Files
openclaw/apps/macos
Peter Steinberger bc4ed5cf61 feat(macos): native-feel dashboard hosting — instant reopen, preload, frame autosave, ⌘N/⌘K, route memory (#106997)
* feat(macos): native-feel dashboard hosting: instant reopen, preload, frame autosave, ⌘N/⌘K, route memory

The hosted Control UI dashboard now skips SPA reloads when reopening an
unchanged endpoint (auth-equality gated), preloads after launch when a
credentialed local/direct config exists, autosaves its window frame, maps
⌘N/⌘K menu items onto the shipped native web events, filters browser-tell
context-menu items, restores the last committed route via web-side
localStorage memory, and themes the pre-paint background.

* refactor(ui): satisfy TS LOC ratchet: move optional lazy-element helpers out of app-host

app-host.ts is over the 500-line ratchet ceiling and may not grow; move the
self-contained optional custom-element block into lazy-custom-element.ts (its
natural owner) and fold the route-restore decision into native-route-memory's
considerRouteRestore so the shell only replaces-or-persists.

* fix(macos): recover stuck dashboard command queue via deliverability gate

Replace the failure-page-only fast-path check with canDeliverNativeCommands
(live document or in-flight load); a terminally cancelled reload now falls
through to the reload path instead of queueing ⌘N/⌘K forever.

* fix(ui): let in-flight navigation win over native route restore

The one-shot startup restore now checks the rendered/pending match against
the committed bootstrap route; an explicit navigation already in flight
(replayed native new-session, fast click) is no longer clobbered.

* docs(ui): note idempotent collapse of pending native new-session replays

* fix(macos): drop queued dashboard commands on terminal load failure

Queued ⌘N/⌘K are moment-bound; surviving a failure page meant a later
recovery reload replayed stale commands (double palette toggle nets closed,
surprise navigation). Both failure entry points now clear the queue.

* fix(ui): persist native route memory only for settled router states

Mid-navigation emissions still carry the stale committed bootstrap route; an
interrupted restore could overwrite the remembered destination with it.

* fix(macos): coalesce dashboard opens for queued native commands

One in-flight open drains a manager-level queue in press order; a Task per
key press could race window creation (duplicate windows) and reorder ⌘N/⌘K
delivery on the non-immediate remote path.

* fix(macos): correct dashboard placement after frame-autosave restore

setFrameAutosaveName re-applies the stored frame; run ensureOnScreen after
both autosave-name assignments so a frame saved on a disconnected monitor
cannot restore the window off-screen.

* fix(macos): clear dashboard failure state when history restores a real document

Swipe-back/⌘[ off the failure page commits an http(s) document without
passing through load(); the flag previously stayed set and forced a reload
on the next native command.

* fix(macos): keep in-flight dashboard loads instead of restarting them

An open/update during the launch preload previously cancelled and restarted
the same-URL load; in-flight non-failure documents now count as usable in
the reload decision.

* fix(macos,ui): ⌘K legacy fallback + transient search param filtering

Command palette dispatch now sends a cancelable toggle event and falls back
to the shipped open-search event when no handler acknowledges it, so ⌘K
keeps working against older gateway-served bundles. Route memory strips
one-shot action params (?draft=) before persisting; navigation state like
?session= still restores.

* chore(i18n): register dashboard menu strings + drop unused route-memory export

native:i18n:sync inventory + per-locale artifacts for New Session / Command
Palette…; StoredNativeRoute is module-internal after the considerRouteRestore
refactor (deadcode exports gate).

* chore(i18n): rebaseline raw-copy for relocated lazy-element labels

The lazy-custom-element extraction moved three internal load-failure labels
out of app-host.ts; refresh the keyless raw-copy baseline to match (main's
new ui:i18n:verify gate).
2026-07-14 03:33:25 -07:00
..

OpenClaw macOS app (dev + signing)

Quick dev run

# from repo root
scripts/restart-mac.sh

Options:

scripts/restart-mac.sh --no-sign   # fastest dev; ad-hoc signing (TCC permissions do not stick)
scripts/restart-mac.sh --sign      # force code signing (requires cert)

Packaging flow

scripts/package-mac-app.sh

Creates dist/OpenClaw.app and signs it via scripts/codesign-mac-app.sh.

Signing behavior

Auto-selects identity (first match):

  1. Developer ID Application
  2. Apple Distribution
  3. Apple Development
  4. first available identity

If none found:

  • errors by default
  • set ALLOW_ADHOC_SIGNING=1 or SIGN_IDENTITY="-" to ad-hoc sign

Team ID audit (Sparkle mismatch guard)

After signing, we read the app bundle Team ID and compare every Mach-O inside the app. If any embedded binary has a different Team ID, signing fails.

Skip the audit:

SKIP_TEAM_ID_CHECK=1 scripts/package-mac-app.sh

Library validation workaround (dev only)

If Sparkle Team ID mismatch blocks loading (common with Apple Development certs), opt in:

DISABLE_LIBRARY_VALIDATION=1 scripts/package-mac-app.sh

This adds com.apple.security.cs.disable-library-validation to app entitlements. Use for local dev only; keep off for release builds.

Useful env flags

  • SIGN_IDENTITY="Apple Development: Your Name (TEAMID)"
  • ALLOW_ADHOC_SIGNING=1 (ad-hoc, TCC permissions do not persist)
  • CODESIGN_TIMESTAMP=off (offline debug)
  • DISABLE_LIBRARY_VALIDATION=1 (dev-only Sparkle workaround)
  • SKIP_TEAM_ID_CHECK=1 (bypass audit)