Skip to content

OMC version 5.2

Choose a tag to compare

@abra-code abra-code released this 26 Aug 06:12
· 40 commits to master since this release

OMC 5.2

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

OMC 5.2 is a testing and tooling release. Its centerpiece is omctest, a headless test harness that runs an applet's handlers against a mock OMC environment, wired into AppletBuilder as a Test button and an appletbuilder test subcommand. Around it, the command-line plister tool got three rounds of crash and data-loss fixes plus content-based format sniffing, codesign_applet.sh learned to preserve entitlements on nested code, applets launch faster and ship smaller, and includes latest ActionUI with add-ons.

Highlights

omctest: a headless test harness for applet handlers

Applet handlers can now be tested without a GUI and without a human clicking through dialogs. omctest runs a suite of shell or Python tests against a mock OMC environment: recording stubs for omc_dialog_control, plister and pasteboard, simulated alerts and command chains, input simulation, a check vocabulary, and virtual-window readback.

  • The harness ships as Agents/omctest.sh inside AppletBuilder.app, with a full test-author reference at Documentation/omctest_guide.md (API tables, verb replay table, seam contract, fixtures, troubleshooting).
  • omc_control_defaults <document> resets a window to the values its ActionUI document actually declares, rather than to a blank state. This matters because many applets ship non-default toggle states, and a blank reset silently tests the wrong thing.
  • chains_reset resets chain state between tests, ui_declare_ids declares runtime-minted view ids, and omctest_isolation_lint warns about $HOME and defaults paths the harness cannot intercept.
  • $HOME is isolated per test file, so a test that saves settings no longer writes into your real ~/Library/Application Support.
  • Named pasteboards are emulated as files in the per-run scratch directory instead of being proxied to the per-login pasteboard server. That removes the last Mach-service dependency and makes suites runnable under the App Sandbox.
  • A test file that runs zero assertions is now a failure, and a suite reports CRASH and INCOMPLETE distinctly instead of collapsing both into a generic failure.

OMCTEST_API_VERSION is currently 6. Assert a minimum in your suite if you rely on something recent: 2 added omc_control_defaults, 3 isolates $HOME, 4 isolates named pasteboards, 5 exports OMC_APP_PROCESS_ID, 6 makes named pasteboards files and drops OMCTEST_PB_PREFIX.

AppletBuilder runs the suite for you

  • A Test button joins Build and Run in the Build & Run pane, streaming the suite's transcript into the same log.
  • The pane gained a status row: an indeterminate spinner while a Build or Test runs, then a one-line colored verdict with the tally, for example "Tests failed - 649 passed, 1 failed, 8 files". Orange calls out the case where nothing ran at all, which otherwise reads as success.
  • appletbuilder build --test runs the suite after the runtime refresh and before signing, and halts the build if it fails. This is deliberately opt-in rather than folded into a plain build.
  • appletbuilder validate now emits an informational note when an applet has no Tests/ directory.

validate cross-checks ActionUI action ids against the command list

command_verifier now resolves every ActionUI actionID and *ActionID value against the applet's command list. It warns when a control's action id resolves to no command, and separately flags a case-only mismatch, which the engine treats as a dead control because dispatch is case-sensitive. This turns a manual by-eye step into an automated one. It was validated across 25 applets plus AppletBuilder itself, roughly 460 action ids, with no false positives.

plister: crash and data-loss fixes, and format sniffing

plister is the plist and JSON manipulation tool handlers lean on, and it went through three review rounds:

  • Format sniffing. When a file's extension does not identify the format, plister now determines it from the content, trying JSON first and falling back to the plist parser. Custom project extensions work without a format flag.
  • append dict and append array now work; previously only scalars could be appended.
  • The on-disk format is preserved on write. A binary plist stays binary instead of being normalized to XML on every modification.
  • Six crashes on non-UTF-8 bytes and missing arguments are fixed, across integer, real, boolean and date argument parsing, file paths, property paths, and insert keys.
  • A failed save no longer reports success. plister returned exit 0 after a write that did not happen; so did iterate after a failed modifying subcommand.
  • A file that does not parse is no longer destroyed. plister set dict <file> / previously overwrote an unparsable file with an empty container.
  • A . or .. component in a property path no longer hangs; it was allocating about 2 GB in 4 seconds.

New features

OMC_APP_PROCESS_ID

A new always-exported variable, $OMC_APP_PROCESS_ID (template form __APP_PROCESS_ID__), resolves to the process id of the OMC host process itself: the applet, OMCService, the Shortcuts observer, OMCEdit, or AppletBuilder. No ENVIRONMENT_VARIABLES declaration is needed.

This is distinct from the existing $OMC_FRONT_PROCESS_ID, which is the frontmost application and may be unrelated to the applet. Use $OMC_APP_PROCESS_ID when a handler needs to know whether the instance that owns some state is still alive, for example to avoid orphaning a spawned server process.

New ActionUI navigation elements

NavigationSplitView and NavigationStack are now available and documented for OMC dialogs, giving multi-pane sidebar and detail layouts and push-style navigation stacks. Each has two forms: static panes, or selection-driven destination switching via destinationViewId.

codesign_applet.sh: entitlements carried forward, plus two new flags

  • Existing entitlements are preserved on re-signed nested code. Frameworks, helpers and XPC services previously had their entitlements silently stripped when re-signed, so a helper that needed something like allow-jit would crash the first time it ran after signing.
  • --list-code prints every path the script would sign, one per line, and exits without touching anything, so a caller can check the same set.
  • --no-entitlements-search uses only the entitlements file passed explicitly, never auto-discovering a stray neighboring .entitlements file.
  • Nested-bundle detection now works by structure as well as by extension, so a structurally-bundled but oddly-named item is signed correctly, versioned frameworks are signed per-version, and resource-only bundles such as SwiftPM privacy manifests are correctly left unsigned.
  • The entitlements cache moved from a hardcoded /tmp to $TMPDIR.

thin_applet_python.py

A new plan and apply tool shrinks an applet's embedded Python by tracing the bundle's own scripts directly, with no hand-written per-applet workload to maintain. Measured on the current applets: Zip 69.5 MB to 42.6 MB, ICEdit 56.5 MB to 38.0 MB, Watchdog 61.0 MB to 38.0 MB, Cadabra 108.2 MB to 89.9 MB, AIChat 47.5 MB to 29.1 MB.

Faster applet launch

The launch-time compileall of an applet's Resources/Scripts is disabled. It could never help, because CPython does not consult a bytecode cache for __main__, and it cost every launch between 24 and 123 ms to save at most 3 ms once. Handlers behave identically; cold launch is measurably faster.

Security

Bundled Chat component: redirects refused on the ACP handshake

The bundled Chat component moved from ChatView 0.2.1 to 0.5.6. As of 0.4.5 its remote ACP WebSocket client refuses redirects on the connection-upgrade handshake. Previously a followed redirect could hand the code-execution bridge credential to whatever host the redirect named, in cleartext over ws://.

The same version arc also fixed a recurring AppKit layout-loop crash that could kill a chat mid-answer, and added composer and conversation-summarizer support.

Compatibility notes

The plister fixes above correct real bugs, but a handler that worked around one of them may need a look:

  • A plist that plister used to rewrite as XML on every modification now keeps its original format. Tooling that assumed "plister always normalizes to XML" no longer holds.
  • A bare true, 42, or null at the root of a file with an unrecognized extension is read as a plist string, not sniffed as JSON.
  • plister set dict <file> /, the documented create-if-missing idiom, now refuses to run against an existing file that fails to parse instead of overwriting it. A handler that relied on the old overwrite behavior will now see a failure.

omctest suites written against API version 2 or lower still run, but tests that read or write real user preferences may behave differently now that $HOME is isolated per test file. That is the intended fix, and it is worth re-reading such tests rather than assuming they still assert what they used to.

Documentation and skill

  • New Documentation/omctest_guide.md, the test-author reference for omctest.
  • New Skill section, "Testing an Applet (omctest)", in the claude and capable flavors.
  • OMC_APP_PROCESS_ID documented in the runtime-context reference, in building_omc_applet.md, and in the Skill.
  • The action id cross-check is documented in appletbuilder_user_guide.md and in the agent troubleshooting checklist.
  • ActionUI schema and documentation refresh for Chat, NavigationSplitView, NavigationStack, CommandMenu, and View, whose hidden semantics are now stated explicitly: a hidden view is laid out but invisible, not collapsed.

Also in this release

  • AppletBuilder's own application icon and several bundled template icons were refreshed.
  • Fixed a hang where appletbuilder build <app> --identity or --thin, with the option as the final argument, spun at 100% CPU forever instead of reporting a usage error.
  • AppletBuilder no longer falls back to /usr/bin/python3 when its embedded interpreter is missing; it fails loudly instead. Multi-line embedded Python inside its shell scripts was extracted into real .py files.

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.