How Does Script Debugger Avoid Modification of Persistent Properties in .scpt Files?

When running AppleScripts from the command line, I generally either use osascript or my own very limited command line utility that calls NSUserScriptTask (which conveniently allows it to run in the system Script Monitor utility; link).

Both of these methods result in functional persistent properties in .scpt files, which has the unfortunate side effect of modifying the original .scpt file. This wreaks havoc with syncing in iCloud, and I frequently find myself with multiple copies of scripts with modifications out of sync. I would like to disable property persistence to prevent these syncing errors.

How does Script Debugger disable property persistence? Is this something trivial that could be handled from Cocoa? I’ve had a look at NSAppleScript as well as NSUserScriptTask (and its subclass NSUserAppleScriptTask) and nothing is jumping out at me.

Thanks for any advice you can offer.


Property persistence is done by the host: when it runs a script, it then checks if any top-level values have changed, and if so, saves the new version. That’s the normal way to run a script.

You can avoid it a couple of ways: ensure there are no changed top-level values, by restoring any properties and globals to their initial values, and putting all code in a handler; or adding a top-level ASObjC value (they can’t be stored, so the saving fails silently).

Thanks Shane! Really appreciate your expertise.

Are you describing the behaviour of NSAppleScript? As in, by default, it does not write changes back into the script?

I’m only really familiar with using NSScriptTask – it runs asynchronously (and appears to call osascript with the undocumented -P option), and from what I can tell it always writes changes back into the script. I haven’t been able to figure out a way to disable that behaviour.

The host is the process running the script — so osascript, or Script Debugger, or FastScripts, or whatever.

1 Like

Got it – thanks! So I’d have to use NSAppleScript, since NSUserAppleScriptTask calls osascript & always tries to persist properties. :weary:

I’ve spent the afternoon playing around with NSAppleScript, but it’s been very difficult figuring out how to unpack the result (which comes packaged as an NSAppleEventDescriptor) for arbitrary return values. The stringValue and coerce(toDescriptorType:) methods don’t work for AppleScript lists, records, dates, etc. All of the example code I could find seems to rely on the script having a known return type, which makes it useless for a “script-runner” type executable.

Do you have any advice on how to handle this? I think I may be out of my depth there.

For posterity, the other solution I’ve come up with is to use a secondary AppleScript to execute the primary AppleScript, so that osascript doesn’t persist the properties of the primary AppleScript.

$ osascript -e 'on run argv' -e 'return run (load script (item 1 of argv as «class furl»))' -e 'end run' /PATH/TO/PRIMARY/SCRIPT.scpt

This obviously has a bit of overhead, but prevents osascript from modifying the primary AppleScript & causing iCloud sync headaches.

There are some open source projects with code for packing and unpacking NSAppleEventDescriptors – you get the descriptorType and unpack accordingly.

One other simple method I forgot to mention: change the permissions of the .scpt file to run-only. That’s what Script Debugger 7 (and Script Editor) do for applets when code-signing, to avoid subsequent modification.

1 Like