Skip to content

OMC 5.5

Latest

Choose a tag to compare

@abra-code abra-code released this 08 Nov 19:08
· 14 commits to master since this release

OMC 5 requires macOS 14.6 or later. For older macOS versions, use OMC 4.x.

OMC 5.5 is built against ActionUI 0.9.10. It adds integration tests that drive a real, running applet, fixes two long-standing engine bugs (a hang on large standard input and a stale dialog value in the next command), stops closed ActionUI windows from staying in memory, and fixes a set of leaks. The embedded Python stays at 3.15.2.

Rebuild your applets with AppletBuilder 5.5. The engine fixes, the window memory fix and the ActionUI changes arrive only when an applet is rebuilt. Integration tests need an applet built with the 5.5 engine.

Integration tests against the real applet

omctest tests a handler script on its own, with a fake engine around it. 5.5 adds integration tests, which launch the applet itself and drive it the way a person would: run a command, click a control, wait until the applet is idle, then read a window's values.

  • Put *.itest.sh files beside the applet and run appletbuilder itest MyApp.app, or press the new Integration Test button in the Build & Run pane (the buttons are now Build | Run | Test | Integration Test, then Show).
  • A test file uses omctest's section and check words plus itest_run, itest_wait_idle, itest_click, itest_value, itest_close and friends. itest_run --window runs a command as a given window's subcommand, so menu bar commands and unnamed menu items can be tested too.
  • Each test file gets a fresh launch with its own $HOME, its own temporary folder and its own pasteboards, so a test does not touch the user's preferences, clipboard or Open Recent list. PASTE_AFTER_EXECUTION sends no keystrokes in a test.
  • Save and open panels, alerts (the WARNING confirmation, version warnings, error alerts) and the alert and notify tools do not wait for a person: the test queues the answers (itest_answer_save, itest_answer_open, itest_answer_cancel, itest_answer_alert), and every panel, alert and notice is recorded for the test to check.
  • A failing test file keeps its folder and prints its path; applet.log there holds the applet's own output.
  • If a copy of the applet is already running, the Integration Test button asks to quit it first, because the copy would share its preferences and files with the test.

Only a build signed for local use can be driven this way: ad hoc, self-signed, or an Apple Development certificate. Developer ID, Mac App Store, TestFlight and other distribution signatures never serve the test interface, so a shipped applet cannot be driven by a test launch. An applet that refuses a test launch exits with status 78 and says why.

The full guide is omcitest_guide.md in AppletBuilder's documentation, and the OMC agent skill has a short integration-test section.

Engine fixes

  • A large STANDARD_INPUT_PIPE no longer hangs the applet. Input larger than the pipe buffer, fed to a script that writes output while it reads (cat, sed, a Python filter), deadlocked the applet with no error. This was in every release since 4.0.
  • The next command sees the dialog values the previous script set. When a script set a dialog value with omc_dialog_control and exited, the NEXT_COMMAND_ID command could start before the change was applied and read the old value. This was in every release since 4.0.1.
  • WAIT_FOR_TASK_COMPLETION no longer keeps a CPU core busy while it waits. Python bridge calls, PROGRESS windows with DELAY and other commands' output keep working during the wait.
  • Closed ActionUI windows are released. Every ActionUI window an applet showed stayed in memory until the applet quit. A window's model now goes once the window has closed and the last command started for it has ended, so an end command can still read the closed window through the ActionUI remote bridge.
  • INVOKE accepts point, size and rect arguments. Messages such as setFrame:display:, setFrameOrigin: and setContentSize: were refused as an unsupported structure on 64-bit macOS. omc_dialog_control --help now describes the structure argument format.
  • PROGRESS output made of nothing but line breaks no longer drops the partial line that came before it.
  • An alert the system could not show no longer counts as a click on its default button.
  • Leaks: a subcommand run with its parent's context leaked its whole runtime data, and a few smaller objects leaked in INVOKE structure arguments, plister and file checks. A leaks run over the whole test suite now finds none.

ActionUI 0.9.10

  • HostSurface is registered in OMC dialogs, so a document that uses it loads. A HostSurface is drawn by code in the app's own process, and OMC handlers are separate processes, so in an OMC applet the element is an empty rectangle.
  • Image: the deprecated scaleMode alias is removed. Use contentMode; an Image with only scaleMode now shows at its own size.
  • Map: annotations are red pins with the title and subtitle under them. The annotation's content is no longer used as its title, and an annotation with no text still shows a pin.
  • Chart: the AxisMarks stride units quarter and weekOfMonth used to stop the applet; they are now refused with a warning and the automatic marks are kept.
  • Diff: the 4 MB limit now also holds for a file reached through a symbolic link, and a negative maxRenderedLines no longer crashes (DiffView 0.2.0).
  • Images: an image that declares too large a size is refused instead of crashing the applet (AsyncImageCache 0.2.3, RichText 0.4.0, ChatView 0.6.5).
  • A document that does not parse again shows a readable error instead of "ActionUI.JSONParseError error 1".
  • The Python and shell remote clients bundled in AppletBuilder gain perform_action and actionui_perform_action, which the integration tests use.

Documentation

  • $OMC_OBJ_TEXT carries text only when the run brought some (a URL's text, a service's selection, a command run with text context) or the command declares it (__OBJ_TEXT__ in COMMAND or INPUT_PIPE, or OMC_OBJ_TEXT in ENVIRONMENT_VARIABLES). Only then does the engine read the selection or the clipboard. The behavior is unchanged; the runtime context reference now says so.
  • The output window shows standard output only, not standard error. To see errors there, use exec 2>&1 in a shell handler, 2>&1 on one command, or sys.stderr = sys.stdout in Python.
  • Do not use the Python bridge in a WAIT_FOR_TASK_COMPLETION handler started by a value change in an ActionUI window (a picker, toggle, slider, field edit or row selection). Those actions arrive on the main queue, so each bridge call stalls the applet for 10 seconds and then fails with error 1005.

Compatibility notes

  • plister writes JSON with sorted keys. JSON now goes through OMC's own writer, which puts keys in a fixed order, so the first time plister saves an existing JSON file it may reorder its keys once. The content is unchanged. Property list formats are not affected.
  • Image scaleMode is gone; see the ActionUI section.
  • OMCTEST_API_VERSION is unchanged at 7. Suites written for 5.4 run as they are.

In this distribution

  • AppletBuilder.app - OMC applet development studio.
  • OnMyCommandCM.plugin - contextual menu plugin for use with Shortcuts.app; commands load from ~/Library/Preferences/com.abracode.OnMyCommandCMPrefs.plist.
  • OMCService.service - macOS service template for standalone OMC-based system services.
  • Skill/ - the OMC AI agent skill (three flavors) plus its installer.
  • Scripts/ - codesign_applet.sh, install_contextual_menu_plugin.sh, thin_distribution.sh, OMCApplet.entitlements, and the example com.abracode.OnMyCommandCMPrefs.plist.

See the main OMC README at https://github.com/abra-code/OMC/ for full documentation on commands, runtime context, dialogs, and services.