* fix(cli): bound node camera URL downloads
* refactor(cli): enforce camera download policy at guard
* refactor(cli): enforce camera download policy at guard
* refactor(cli): enforce camera download policy at guard
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
* fix(doctor): gate cross-state-dir legacy imports behind explicit doctor opt-in
A gateway or CLI command started with OPENCLAW_STATE_DIR pointing at a
non-default directory used to import legacy files FROM the default
~/.openclaw state dir (exec-approvals.json, plugin-binding-approvals.json)
and archive the originals with a .migrated suffix. Any isolated, test, or
staging run on a host with production state silently captured and archived
the production files.
Cross-state-dir imports now run only with the new crossStateDirImports
opt-in: openclaw doctor --fix (or an interactive doctor confirm) performs
the import; the implicit CLI/gateway preflight leaves the default dir
untouched and emits a notice pointing at doctor instead.
* test(doctor): include notices in legacy-state detector mocks
* feat(onboard): guided CLI onboarding with live AI verification and classic fallback
Interactive `openclaw onboard` (and bare `openclaw` on a fresh install) now
runs a guided flow with macOS-app parity: detect existing AI access, live-test
candidates with a real completion before persisting anything, walk down the
ladder on failure with mapped reasons, and offer verified manual API-key entry
from installed provider manifests (masked input). In-flow escapes: classic
wizard, Crestodian chat, skip-AI. Classic wizard gains an optional post-auth
live verification step. `--classic`, `--modern`, and `--non-interactive`
contracts unchanged. Docs corrected for post-#99935 routing.
Closes#101851
* improve(onboard): quiet probe diagnostics in wizard TTY, carry risk ack into classic escape
Candidate live-tests during guided setup are probes: rename their run id and
lane to the existing probe conventions (logging/subsystem.ts console
suppression, command-queue quiet probe lanes) so expected failures stop
leaking raw diagnostics into the Clack UI; file diagnostics unchanged. The
classic-wizard escape now passes the already-collected risk acknowledgement
through instead of re-prompting in the same session.
* fix(onboard): quiet the session-derived setup-inference probe lane too
The live-test run enqueues on two lanes: the explicit probe lane and one
derived from its temp session key. Extend the shared quiet-probe predicate to
cover the derived lane so a failing candidate cannot leak lane-task
diagnostics into the wizard TTY.
* improve(onboard): suppress subsystem console output during wizard live tests
Provider-transport subsystem loggers (model-fetch start/response, transport
errors) carry no run id, so probe suppression cannot catch them and a failing
candidate printed raw log lines into the Clack TTY. Reuse the TUI console
subsystem-filter seam via a finally-safe scoped helper around guided
activation and the classic live-verify; file logging is unchanged and the
gateway (macOS app) surface is unaffected.
* fix(onboard): never auto-replace a configured model when its live check fails
The re-run verification probe executes outside the configured workspace (setup
never runs workspace plugins), so a workspace-backed current model can fail
the check while working fine in the agent. Stop the auto ladder on an
existing-model failure and hand the decision to the manual stage instead of
silently persisting a different candidate as the default. Docs note the
fail-safe and the workspace caveat.
* feat(onboard): two-way switching between Crestodian chat and the menu wizards
From the chat, `open setup wizard`, `open classic wizard`, and `open channel
wizard for <channel>` hand off to the guided flow, the classic wizard, or the
masked `channels add` wizard after the chat TUI tears down (mirrors the
open-tui handoff; gateway surface gets a text pointer instead). The hosted
channel wizard no longer dead-ends at sensitive steps — it offers the switch
and remembers the channel. New read-only `channel info <channel>` operation
and ring-zero action surface label, blurb, configured state, and the real
docs URL from channel-setup discovery so the assistant can explain Slack or
Telegram prerequisites instead of guessing; both prompts instruct it to use
them. `channels add --channel <id>` now preselects the channel. Docs cover
the interchangeable flows.
* fix(onboard): avoid param reassignment in open-setup handoff
* improve(onboard): separate ask-about vs connect intent in channel prompt guidance
Live test showed the agent detouring an explicit connect request through
channel_info because the guidance said to consult it first. Both prompts now
distinguish asking about a channel (channel info + docs link) from asking to
connect (connect right away).
* fix(channels): mark channel token entry as sensitive input
The shared single-token prompt lacked sensitive:true, so terminal wizards
echoed pasted channel tokens and the Crestodian chat bridge (which refuses
plain-text secrets based on this flag) hosted the Telegram token step in
visible chat. Found live-testing the chat-to-wizard switch; pre-existing on
main but load-bearing for the masked-wizard contract this PR documents.
* fix(onboard): restore terminal state around the guided flow's TUI launch
Mirror the classic finalize handoff so the chat TUI never inherits the wizard
prompter's raw/paused terminal state on the default first-run path.
* fix(channels): type the token prompter mock for the sensitive-flag assertion
* fix(gateway): map the TUI-only open-setup action to none for app clients
Engine-side surface gating already prevents open-setup replies on the gateway
surface; this keeps the client-visible action enum stable even if that gate
ever regresses. (Reviewed with the switching round; missed in its commit.)
* docs: regenerate docs map for onboarding page changes
* feat(cron): add headless code-mode driver and trigger-script evaluator
Part A of cron event triggers: runCodeModeScriptHeadless runs a script
to completion (exec/settle/resume, no snapshots, no session), plus the
cron-facing evaluator with per-job tool catalog cache, semaphore, 16KB
state cap, and closed failure taxonomy.
* fix(cron): correct trigger-script bootstrap flags and cache narrowing
* feat(cron): add event triggers (polled condition-watcher scripts)
Part B: trigger field on cron jobs gated by cron.triggers.enabled;
timer evaluates the script each due tick, quiet ticks leave no run
history, fired runs append the script message to the payload; once
semantics, min-interval floor, SQLite columns, RPC/CLI/agent-tool
surfaces, and docs.
* fix(cron): propagate triggerEval through startup catch-up outcomes
* fix(cron): honor cron staggering on quiet trigger ticks; fix trigger test types
* fix(cron): reject with Error reason in trigger-script abort test
* fix(cron): regenerate protocol/docs/snapshot artifacts and break madge cycle for trigger types
CI fixes for #101195: trigger evaluator result types move to the cron
types leaf (madge cycle), cron tool schema inventory gains trigger,
Swift protocol bindings + docs map + Linux prompt snapshots regenerated.
* fix(cron): drop underscore-dangle names in trigger code sync assert
* fix(cron): adopt registerHeadlessToolSearchCatalog after tool-search symbol localization
Upstream #101831 made registerToolSearchCatalog module-private; fold the
headless ref-only catalog registration into one public seam.
* fix(gateway): support native Windows exec approvals
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* chore: defer changelog entry to release
* test: use tracked approvals temp directories
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* feat: add openclaw promos CLI for ClawHub promotional model offers
* fix: harden promos claim auth validation and sanitize remote promo text
* fix: enforce promo window client-side and validate slug contract
* fix: shell-safe model ref contract and explicit --api-key override
* fix: hold promotion aliases to the models alias contract
* docs: document argv-credential contract and env alternative for promos claim
* fix: enforce provider plugin enablement on the credential-reuse claim path
* fix: require plugin install before credential-reuse shortcut in promos claim
* fix: run runtime plugin repair on promo defaults and harden identifier parsing
* fix: distinct message for contract-invalid promo aliases
* fix(cli): validate promotion plugin contracts
* fix(cli): recheck promotion window before claim
* feat(cli): surface ClawHub promotions in models list via the hosted feed
Passive discovery for promotional model offers. A cadence-gated (24h),
fail-silent conditional GET of ClawHub's immutable promotions feed
snapshot (If-None-Match -> 304, short 2.5s timeout, unauthenticated so
CDN caches stay unfragmented) is cached in two new shared-state-DB
tables, fully separate from update_check_state. models list renders an
'Available via promotion' group for live offers whose models are not in
the user's configured set (including the zero-row fresh-install path),
tags claimed models promo / promo ended from provenance recorded at
claim time, and prints a one-time notice per newly seen offer; promos
list and claim mark offers as seen. Machine outputs stay clean, snapshot
sequence is monotonic against stale edges, and claims still revalidate
against the live API so the kill switch always wins.
* style: satisfy lint on promotions feed additions
no-useless-fallback-in-spread on the optional request headers and
no-map-spread in claim-provenance row mapping.
* fix(cli): harden promotions feed cache
* fix(cli): honor live promotion validity
* fix(ports): ignore malformed lsof listener pids
* fix(infra): strictly reject malformed lsof pid tokens
Number.parseInt truncated tokens like "111abc" to 111, silently accepting
a corrupted lsof pid record. Switch to parseStrictPositiveInteger so the
whole token must be a valid positive integer, and restore the deduped
listener test that a prior change had replaced instead of extended.
* fix(cli): strictly reject malformed lsof pid tokens
Harden the force-free lsof parser to reject digit-prefixed garbage like
p111abc instead of truncating it to pid 111, and cover the sibling parser
with a focused regression test.
* fix(infra): strictly parse stale lsof pid tokens
Harden the stale gateway cleanup parser to reject digit-prefixed garbage
like p111abc instead of truncating it to pid 111, and add a focused
regression test without dropping the existing argv verification coverage.
* fix(ports): fail closed on malformed lsof pids
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(gateway): show last error when status probe fails
* fix(gateway): scope status log diagnostics
---------
Co-authored-by: wAngByg <wAngByg@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Tracks per-skill usage from the skill.used diagnostic event (trusted-only
delivery, file-scoped identity), sweeps workshop-created skills daily from
gateway maintenance (active -> stale 30d -> archived 90d, pinned bypass,
restore-only unarchive, files never touched), filters archived skills from
snapshots fail-open, reports workspace-scoped overlap candidates, and adds
openclaw skills curator CLI, additive gateway methods, and a warn-only
doctor finding. Zero new config keys; SQLite/Kysely state only.
* fix(cron): do not set delivery mode to announce when disabling best-effort on payload edits
* fix(cron-cli): update sibling test to expect undefined mode on no-best-effort-deliver
* fix(cron): preserve delivery mode when disabling best effort
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(cron): use direct lookup instead of paginated search in cron edit
* fix(test): update cron-cli tests to mock cron.get and remove obsolete pagination checks
* fix(cron): preserve edit compatibility with older gateways
* fix(cron): preserve legacy lookup error cause
---------
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>