* fix(cron): cap trigger script tool access
Persist the creator tool cap for any cron job with a trigger script and pass it to the headless trigger runtime. System event and command payloads retain the cap across cron updates.
* fix(cron): persist trigger tool cap for systemEvent and command payloads
The creator tool cap is stamped on systemEvent and command payloads whenever a
cron job carries a trigger script, but the SQLite codec dropped
payload.toolsAllow for those kinds. After a gateway restart the reloaded job
carried no cap and the trigger regained the full coding surface. Persist and
restore toolsAllow through the existing payload_tools_allow_json column for all
payload kinds, and add restart-aware round-trip coverage.
* ci: re-trigger workflows (transient self-hosted runner flake)
* fix(cron): use expectDefined for store test job access
* refactor(cron): hoist cron tool types, payload merge, and wire types into companion modules
Keeps the oversized cron files at or below their baseline line counts for the
changed-file TypeScript LOC ratchet on main. No behavior change.
* fix(cron): retain freshly stamped cap markers
* test(ci): align compact shard count
* fix(cron): make trigger cap updates atomic
* fix(cron): preserve explicit cap provenance
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
* feat(linux): canvas via CLI-node + Tauri app IPC bridge
* refactor: extract gateway helper modules
* build(linux-canvas): register plugin package in lockfile
* fix(linux-canvas): move canvas advertise test out of core, regen docs/protocol/deadcode
* fix(gateway): break node-catalog/registry import cycle via leaf normalize module; add canvas glossary term
* style: oxfmt invoke.ts and runtime.ts after buildNodeEventParams extraction
* fix(linux): load Canvas WebView via dedicated data_directory context
Wry's Linux/WebKitGTK incognito mode discards Tauri's registered
WebContext (wry webkitgtk/mod.rs), so the Canvas window got a fresh
ephemeral context without the openclaw-canvas:// scheme handler — the
bundled A2UI page never committed (stayed about:blank) and every A2UI
command timed out. Use an isolated cache-backed data_directory instead,
which keeps the protocol handler while still isolating Canvas storage
from the dashboard window.
* fix(linux): keep Canvas WebView ephemeral via incognito + data_directory
Autoreview flagged that a dedicated data_directory alone persists Canvas
browser state (cookies, localStorage, IndexedDB, service workers) across
restarts, so an agent that navigates Canvas to a site could leak an
authenticated session into a later session. iOS uses a non-persistent
store; Linux should match.
Add .incognito(true) alongside .data_directory(): the distinct directory
gives Tauri a fresh WebContext key so it still attaches the
openclaw-canvas:// protocol closure, and incognito makes Wry swap in a
fresh *ephemeral* context carrying those protocols. Live-verified on a
Wayland/WebKitGTK box: the bundled page still loads
(location.href=openclaw-canvas://localhost/index.html, openclawA2UI
present, A2UI renders) and the canvas-webview dir holds no persistent
cookie/storage files.
User-facing name is now OpenClaw (the system speaks); internal code name is
system-agent. Gateway methods crestodian.* -> openclaw.chat/openclaw.setup.*,
agent tool -> openclaw, reserved agent ids openclaw + retired crestodian.
openclaw setup routes: onboarding flags -> onboard, -m/--yes -> system agent,
bare configured interactive -> OpenClaw chat, unconfigured -> onboarding.
Hidden crestodian CLI and /crestodian TUI aliases kept; docs moved to
docs/cli/openclaw.md with redirect stub. macOS/Android strings in lockstep.
Refs #107237
aae56539fa set binaryType=nodebuffer but left RawData-typed toString
calls; no-base-to-string fails check-lint repo-wide. Cast to Buffer like
the same commit's realtime-transcription site.
* fix(terminal): harden node PTY relay and terminal session lifecycle
Pin node relay invokes to the authorized node connection (ROUTE_CHANGED
guard), stop node-side input writes to settled/dead PTYs, finalize
sessions on resize failure like write failure, keep surrogate pairs
intact across scrollback and relay prelude truncation, bound the relay
pre-registration output buffer, and buffer Control UI keystrokes typed
while terminal.open/attach is in flight so slow node-relay opens no
longer drop input. Correct the terminal.data seq doc to its real
contract and pin seq monotonicity, seq-gap bounds, input coercion, and
runner event routing with new tests.
* refactor(terminal): extract startup input buffer and fix CI findings
Move Control UI startup input buffering into terminal-startup-input.ts
(LOC budget), drop a stale session-manager comment, remove a map
spread, and fix test typings for event frames and typed mock access.
Catalog session rows (sidebar context menu + click), the built-in viewer
header, and a new "Open Codex/Claude sessions in" preference can launch the
native CLI (codex resume / claude --resume) in the operator terminal on the
machine that owns the session.
- Gateway-local sessions spawn through the existing terminal launch policy
(sandbox/enabled gates preserved) with the resume command in the session cwd.
- Paired-node sessions run through a new seq-ordered node PTY relay: a
duplex node-host command streams PTY output via node.invoke.progress and
receives keystrokes/resize via a new node.invoke.input event, behind the
unchanged terminal.* client protocol (TerminalSessionManager gains a backend
abstraction; node relay reuses the streaming-invoke controller).
- Owner boundary: each plugin owns its resume command and builds argv from a
validated thread id; the gateway routes node opens through the node command
allowlist and plugin invoke policy (no advertisement-only trust), and nodes
re-verify session eligibility before spawning.
- UI setting catalogOpenTarget + canOpenTerminal capability gate every entry
point; capability requires the owning host to actually have the CLI.
Node PATH is normalized before command-availability probes, Windows .cmd/.bat
shims spawn via ComSpec, and catalog terminal opens reattach persisted tabs
before opening the new tab.
* feat(ui): redesign Channels page with guided channel setup wizard
Adds wizard.start flow=channels gateway RPC (additive protocol change) that
drives the shared channel-setup wizard (openclaw channels add) over the
session step protocol. Control UI Channels page becomes a card hub with
plugin-art covers, guided per-channel setup modal (WhatsApp QR pairing via
web.login.*, BotFather/Slack/Discord helper links), and a detail overlay
hosting the full schema config form.
* test(ui): cover channel wizard controller; refresh channels view test props
* chore(mock): use non-token-shaped wizard placeholder
* test(gateway): scanner-safe auth local in channels wizard test
* fix(ui): cancel gateway wizard session on channels page disconnect
* fix(ui): adopt browse-all channel pick and guard dirty config before setup
* fix(ui): cancel gateway session created by a stale wizard.start
* fix(ui): adopt multiselect channel picks; drop redundant String()
* fix(ui): track all wizard-adopted channels so WhatsApp QR runs regardless of pick order
* feat(gateway): report configured channels on terminal channel-wizard result
Replaces the Control UI's channel-adoption heuristic with the authoritative
outcome: the channels flow reports its actual selection after config commit,
the wizard session surfaces it as an additive channels field on the terminal
wizard.next result, and the UI keys WhatsApp QR linking off that.
* refactor(ui): align channels hub with the unified settings design language
Hub becomes settings-language rows (44px art tiles, status dots, uppercase
section headings, hairline groups) instead of a card gallery; the detail
overlay hosts the migrated per-channel settings sections with Run setup in
the header. Wizard dialog and tile/cover styles move to spacing tokens.
* chore(i18n): translate channels hub/setup strings; refresh raw-copy baseline
* refactor: satisfy LOC ratchet and dead-export gates
Split mock-dev channel/plugin fixtures into their own modules, move wizard
runner types/defaults to server-methods/wizard.ts, extract the channels page
wizard host and nostr profile HTTP ops, and unexport internal-only types
(incl. the unused config-form SECTION_META barrel re-export).
* chore(i18n): retranslate channels strings on rebased locale bundles
* fix(test): drop redundant String() in channels wizard e2e
* fix: address channel-wizard review findings
- lock wizard cancellation before durable installs/config writes
- report configured channel accounts on the terminal wizard result and
start WhatsApp QR pairing for that account (web.login accountId)
- forward request options through the browser gateway client so wizard
RPC timeouts apply
- render skipped setup as a no-change completion
- keep detail/advanced config reachable for unconfigured channels
- surface the dirty-config warning inside the detail overlay
- adopt the picked channel for wizard title/links in browse-all flows
* fix(ui): local wizard RPC timeout; translate no-change completion strings