Using $.NSUserNotification within a JXA osascript (Execute Shell Script action)

Not a great problem, because I can use KM notifications, but I was interested to see that this Yosemite Javascript for Applications script, which works in Script Editor, needs to have the call to $.NSUserNotification methods switched off for use in KM with an execute Shell script command line like:

osascript -l JavaScript path to script

Not sure if there is a way around this (analogous to bracketing UI calls with tell "System Events ... end tell in Applescript, perhaps ?

function run() {
	var dct = {
		title: "Append Safari clipboard to end of file",
		ver: "0.2",
		description: "Creates MD header with page title, url & timestamp",
		author: "RobTrew copyright 2014",
		license: "MIT",
		site: "https://github.com/RobTrew/txtquery-tools"
	};

	var dctOptions = {
		clipfile: "$HOME/Library/Application Support/Notational Velocity/Clippings.txt",
		clipheadings: "### ",
		urlprefix: "- ",
		datetimetag: "clipped",
		useNSnotification: false, // turn off for KeyBoard Maestro
		clippedsound: 'Pop',
		problemsound: 'Blow'
	};
	//ALTERNATIVE SOUND NAMES
	//Basso	Frog Hero Pop Submarine
	//Blow Funk	Morse Purr Tink
	//Bottle Glass Ping Sosumi

	// Taskpaper-style datetime stamp yyy-mm-dd HH:MM
	function fmtTP(dte) {
		var strDate = '',
			strDay = '',
			strTime = '';
		strDay = [dte.getFullYear(), ('0' + (dte.getMonth() +
			1)).slice(-2), ('0' + dte.getDate()).slice(-2)].join('-');
		strTime = [('00' + dte.getHours()).slice(-2), ('00' +
			dte.getMinutes()).slice(-2)].join(':');
		if (strTime !== '00:00') strDate = [strDay, strTime].join(' ');
		else strDate = strDay;
		return strDate;
	}

	// single quoting for bash shell
	function shellEscaped(cmd) {
		return '\'' + cmd.replace(/\'/g, "'\\''") + '\'';
	}

	var appSafari = Application("Safari");

	if (!appSafari.windows.length) return 'Safari not running ...';

	//PREPARE FOR ANY NOTIFICATION
	ObjC.import('Cocoa');
	try {
		ObjC.registerSubclass({
			name: 'BriefNotify',
			methods: {
				'userNotificationCenter:shouldPresentNotification:': {
					types: ['bool', ['id', 'id']],
					implementation: function (center, notification) {
						return true;
					}
				}
			}
		});
	} catch (e) {} // already defined

	function postNote(strTitle, txtInfo, strSoundName) {
		var noteFlash = $.NSUserNotification.alloc.init,
			strSound = strSoundName || 'Glass';

		noteFlash.title = strTitle;
		noteFlash.informativeText = txtInfo;
		noteFlash.soundName = strSound;
		$.NSUserNotificationCenter.defaultUserNotificationCenter.deliverNotification(noteFlash);
	}

	var app = Application.currentApplication(),
		oWindow = appSafari.windows[0],
		oTab = oWindow.tabs[0],
		strName = oWindow.name(),
		strHeading, strRefce, strCmd,
		strPrefix = '',
		strQuotedPath = '"' + dctOptions.clipfile + '"',
		oBriefNotify = $.BriefNotify.alloc.init,
		strMsg, strDetail, strSound = '',
		varResult;

	app.includeStandardAdditions = true;

	// Creating heading from web page name and MD link to URL
	strHeading = dctOptions.clipheadings + strName + '  @' +
		dctOptions.datetimetag + "(" + fmtTP(new Date()) + ")";
	strRefce = dctOptions.urlprefix +
		'[' + oWindow.name() + '](' + oTab.url() + ')';
	strPrefix = [strHeading, strRefce, ''].join('\n') + '\n\n';

	// and append heading and clipboard text to the end of the file
	strCMD = 'echo ' + shellEscaped(strPrefix) + ' >> ' + strQuotedPath +
		'; pbpaste >> ' + strQuotedPath + ' ; printf "\n\n" >> ' + strQuotedPath;

	try {
		varResult = app.doShellScript(strCMD);
	} catch (e) {
		varResult = e.message;
	}

	if (!varResult) {
		strMsg = "Appended to " + dctOptions.clipfile;
		strDetail = strPrefix;
		strSound = dctOptions.clippedsound;
	} else {
		strMsg = "NOT clipped ...";
		strDetail = varResult;
		strSound = dctOptions.problemsound;
	}

	if (dctOptions.useNSnotification) {
		$.NSUserNotificationCenter.defaultUserNotificationCenter.delegate = oBriefNotify;
		postNote(strMsg, strDetail, strSound);
	}
	return strDetail;

}

osascript presumably does not have enough of an application bundle/state to have a defaultUserNotificationCenter. Other than creating an applet of some sort, complete with a valid bundle, I’m not sure what to suggest. I have reports the problem to Apple’s bug reporter.

OK, Apple responded and said they don’t plan to change this because you can post notifications using the “display notification” scripting addition. For example:

 app = Application.currentApplication()
 app.includeStandardAdditions = true
 app.displayNotification('Hello world', {
	withTitle:'My Title',
	subtitle:'Subtitle',
	soundName:'Glass'
})

You do get a warning with the above code:

2014-11-21 11:05:34.088 osascript[92388:3135947] warning: failed to get scripting definition from /usr/bin/osascript; it may not be scriptable.

which you will need to ignore, for example in Keyboard Maestro’s Execute Shell Script:

 osascript -l JavaScript <<'EOM' 2>/dev/null
 app = Application.currentApplication()
 app.includeStandardAdditions = true
 app.displayNotification('Hello world', {
	withTitle:'My Title',
	subtitle:'Subtitle',
	soundName:'Glass'
})
EOM

That’s very helpful, and makes good sense.

Thanks Peter