Skip to content

Automation: Karabiner import · perf: resource audit fixes (ported from the Codex session) - #95

Merged
jiunbae merged 5 commits into
mainfrom
feat/codex-automation-perf
Oct 11, 2026
Merged

jiunbae merged 5 commits into
mainfrom
feat/codex-automation-perf

Conversation

@jiunbae

@jiunbae jiunbae commented Oct 11, 2026

Copy link
Copy Markdown
Member

Work done in a parallel Codex session on the main checkout while R15 was in progress, ported onto main after #94 merged.

What

  • Automation (0ca81b8): Import Settings takes Hammerspoon Lua, Karabiner-Elements JSON, or JavaScript. Karabiner's key-to-key mappings become native remaps on the event tap (no JavaScript per key event); unsupported Karabiner features are reported before importing. Display/AX queries batched; held keys survive watchdog checks.
  • Resource audit fixes (a9d3c14): bounded script/exec runtimes (shared pipe deadline, stdout/stderr/event-queue/timer limits), stale native refresh results rejected across reload/remove/disable, cache pruning and commit-after-write, coalesced memory/disk sampling (MetricSampleCache), fewer menu bar rebuilds, thumbnail/remote image retry and caching, directory watcher cleanup, and a bounded expiring Dock icon cache (DockFilePresentationCache, replacing the unbounded one from feat(dock): BarShelf Dock — widgets, launchers, profiles, Apple Dock layouts (R15) #94).
  • 83e0f1b: the last compiler warning (implicit strong capture in the builder sheet).

How it was ported

Verified

  • swift build: no errors, no warnings; the first commit builds on its own.
  • swift test: all green (Core 607, App 327, CLI), including Codex's new tests (Karabiner import, native refresh gate, exec pipe deadlines, metric sampling, registry network, storage lifecycle, thumbnails).
  • scripts/sync-strings.sh --check: ok.

🤖 Generated with Claude Code

jiunbae and others added 5 commits October 11, 2026 14:50
Import Settings now takes Hammerspoon Lua, Karabiner JSON, or a
JavaScript extension. Karabiner's basic key-to-key mappings (with
mandatory/optional modifiers, up to 128) become native remaps applied
on the event tap, so no JavaScript runs per key event; unsupported
Karabiner features (conditions, macros, hyper) are reported before
importing. Display queries are batched and held keys survive the
watchdog's checks. The dock's ⌃⌥ profile keys are still claimed
through InAppHotkeys before Automation registers.

Written in a parallel Codex session on the main checkout and ported
onto main after R15 (#94) merged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
From a resource audit of the app (143 source files, 30 bundled widgets):
- Script and exec runtimes: pipe readers share one deadline; stdout
  lines are bounded (newline-terminated ones too), stderr at 64 KiB,
  the stdout event queue at 128, timers at 128 per widget.
- Native refresh generations reject results that came back after a
  reload, remove, or disable, keeping refresh ownership straight.
- Caches drop removed entries, late loads cannot re-cache them, and
  commit only after a successful disk write; failed chart saves stay
  retryable. Memory/disk sampling is coalesced on a sleep-aware
  monotonic clock (MetricSampleCache).
- Menu bar entries rebuild only on changes they show; unused
  maintenance timers stop. Thumbnails and remote images retry and
  cache more carefully; directory watchers clean up.
- Dock: icons and names cached per path for a minute, at most 256
  (DockFilePresentationCache), replacing the unbounded cache.

Written in a parallel Codex session on the main checkout and ported
onto main after R15 (#94) merged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Swift 6.4 warns that the outer closure captured runtime strongly while
the inner one asked for weak; both are weak now. No compiler warnings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Both failed now and then (CI, and 2 in 5 runs locally): the service
calls back as soon as it cancels, but the URL protocol hears of the
cancel on its own thread a moment later, so stoppedRequests was still
0 when checked. They now wait for it. The stalled-download test also
held the healthy image to a 0.15 s deadline, which a loaded runner
missed; 1 s still shows the stall being cut off. 0 failures in 15
runs of the suite and 3 runs of everything.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ts, refresh churn, sampling, exec timeout

From a review of #95:
- Key remaps from arrows, Home/End, Page Up/Down, Forward Delete and F
  keys never fired: macOS sets fn on those events, so control+left_arrow
  arrived as control|fn. fn is left out of matching there, and requiring
  fn on such a key is refused (it cannot be told apart).
- Karabiner import accepts what current Karabiner writes on its own
  (keyboard_type_v2, the device-open delay, basic.* timeouts, device
  entries, machine_specific, rule 'enabled'; disabled rules stay off;
  media-only fn_function_keys are left to macOS and said so). Remaps,
  ignored keyboards and F keys sent as other keys are still refused.
- Only real chains are refused: an output some rule takes with no
  modifier, or a rule mapping a key to itself.
- Script stdout waiting for the host is bounded by size (8 MB), not by
  count: 200 log lines in one write no longer kill a healthy script.
  Complete lines ahead of an oversized one are still delivered.
- A widget reload outdates in-flight refreshes only for widgets whose
  manifest or folder changed; every reload used to discard each running
  result and run its command again.
- Disk/memory samples lock per key, so a hung volume no longer stalls
  every other widget's samples.
- An exec that exits just inside its timeout is not reported as timed
  out while its output is still being read.
- Karabiner and key-remap messages are localized (ko).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@jiunbae
jiunbae merged commit 6aa08b8 into main Oct 11, 2026
1 check passed
@jiunbae
jiunbae deleted the feat/codex-automation-perf branch October 11, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant