Commit Graph

1649 Commits

Author SHA1 Message Date
Peter Steinberger e0680fdd42 fix(cli): preserve authored config during channel auth (#131117)
* fix(cli): preserve authored channel config during auth

* fix(cli): preserve source config for auth selection

* test(ui): synchronize task panel hover assertions
2026-08-27 14:11:22 -07:00
Peter Steinberger 9be3cefabd feat(configure): surface the trusted-proxy loopback opt-in with its warning (#131132)
* feat(configure): surface the trusted-proxy loopback opt-in with its warning

Ask for explicit consent before enabling same-host trusted-proxy authentication,
and explain the runtime rejection when consent is declined. Preserve existing
loopback consent and unprompted device enrollment policy on same-mode reruns.

Reuse runtime loopback classification, add English and Chinese wizard copy,
and document the consent and preservation behavior.

* test(configure): assert wizard auth through the real builder

Remove the auth-builder mock and replacement factories so gateway prompt tests verify returned configuration across proxy, token, password, and SecretRef flows. Retain all consent regressions while reducing test scaffolding and reusing tracked environment cleanup.
2026-08-27 12:45:23 -07:00
Peter Steinberger 025ae36a72 fix(device-pair): verify retained subscribers before archiving the migration source (#131008)
* fix(device-pair): verify retained subscribers before archiving the migration source

Precheck remaining namespace capacity before importing legacy subscribers. Verify source and pre-existing destination keys in the shared JSON importer before reporting completion or archiving, preserving the source and warning when retention falls short. Keep runtime caps, eviction policy, and registration semantics unchanged.

Prepared for draft PR maintainer review. Review-required: persistent-state retention semantics.

* fix(device-pair): omit absent subscriber migration fields

Keep absent account and thread fields out of normalized legacy subscribers so the strict plugin-state JSON serializer accepts ordinary subscriptions. Preserve numeric zero thread IDs and exercise all optional target combinations through the real migration contract.
2026-08-27 11:52:24 -07:00
Peter Steinberger 80082b2476 fix(configure): preserve unrelated gateway auth policy across reconfiguration (#131035)
* fix(configure): preserve unrelated gateway auth policy across reconfiguration

* test(configure): exercise real auth builder in gateway prompt tests

Replace fake auth factories and builder-call assertions with returned-config checks. Cover password policy preservation, generated-token parity, and SecretRef output without changing production behavior.
2026-08-27 11:38:49 -07:00
Peter Steinberger 19d61d9ada fix: inspect exact hook names before matching key aliases (#131081)
Share name-first, ambiguity-aware hook selection with toggles and carry the selected hook to rendering and exit status. Preserve unique keys, missing-hook output, plugin-managed inspection and mutation policy. Closes #131075.
2026-08-27 11:25:30 -07:00
Peter Steinberger 834368b7d4 fix(browser): cancel downloads after output save failures (#131048) 2026-08-27 10:28:08 -07:00
Peter Steinberger ff3cf3de3b docs(start): correct headless credential handoff to the SQLite auth store (#131024) 2026-08-27 09:40:27 -07:00
Peter Steinberger 8012723c72 fix(channels): keep configured accounts in JSON inventory (#130738)
* fix(channels): keep configured accounts in JSON inventory

Keep metadata-only inventory independent of setup-runtime eligibility, while retaining setup precedence and failure visibility. Let status audits resolve channel capabilities at the audit owner instead of treating inventory metadata as complete adapters.

Fixes https://github.com/openclaw/openclaw/issues/130700

* test(status): align JSON audit owner expectations
2026-08-27 07:38:30 -07:00
Peter Steinberger 11ef173077 fix: preserve native session ownership during cleanup and attachment (#130864)
* fix: preserve native session ownership during cleanup and attachment

Prepare permitted harness owners for offline session deletion. Reject direct
attachment of parent-controlled Codex children before displacing ownership.
Keep deadline and client authority through binding publication, and release
accepted subscriptions when publication fails without a remaining owner.

Unify conversation create/attach and preserve observational child monitoring.
Verified 950 focused/sibling tests, production and test types, independent
Codex review, and the real built offline CLI capacity reproduction.

* test: avoid shadowing the native binding row
2026-08-27 03:37:44 -07:00
Peter Steinberger 1cbcf141ed fix(gmail): keep forwarding alive across watcher restarts (#130853)
* fix(gmail): keep forwarding alive across watcher restarts

* fix(gmail): preserve foreground CLI shutdown ownership
2026-08-27 02:29:33 -07:00
Peter Steinberger d3aa4be83a fix(cli): honor gateway --port on the status leaf (#130847) 2026-08-27 02:24:40 -07:00
Peter Steinberger b5fb4fa938 fix(hooks): load linked hooks and nested packs (#130813)
Resolve explicit extra roots as hooks or declared packs so successful linked installs are discovered and executed. Select only declared pack leaves while preserving collection scanning, source policy, and containment checks.

Fixes #130783.
2026-08-27 01:28:38 -07:00
Peter Steinberger 09d92ff86d fix(status): show healthy channels as OK in deep health (#130794) 2026-08-27 01:03:07 -07:00
Peter Steinberger e4d602c6f3 fix(worker): keep background servers alive after replies (#130733)
* fix(worker): keep background servers alive between turns

Retain the supervised worker environment while background execs are live,
while recreating turn admission, tools, connections, and authorization for
each turn. Keep physical worker ownership separate from bounded turn
receipts so cancellation, restart recovery, and environment retirement
cannot discard a still-running worker.

Preserve process polling across turns, release turn callbacks, join exec
finalization before environment cleanup, and require exact worker stop
confirmation unless a dedicated provider proves the machine is gone.

Fixes #130450.

* fix(worker): fence revoked placements and verify retained lifetimes

Record provider-loss teardown intent before remote stop, prevent pending cleanup
from being recovered as an active placement, and preserve exact physical ownership
until stop is confirmed. Keep draining state when the provider becomes unavailable.

Remove the ownership/lifecycle import cycle and align workspace-retention proof
with physical teardown. Exercise missing-capability rejection and reconnect on
real Gateway/node wire, preserving scenario and cleanup failures in the harness.

* test(worker): verify durable startup revocation cleanup
2026-08-27 00:35:19 -07:00
Peter Steinberger 1ea2640f54 refactor(state): consolidate wide rows, plugin index, workspace attestations, and shared auth singletons at schema v13 (#130466)
* refactor(state): make cron and subagent rows JSON-canonical

* refactor(state): make gateway origin device tokens canonical at v13

The lazy ensure predates the table joining the canonical schema; at the
v13 bump the schema owns creation, so the feature-local DDL, WeakSet
dedupe, and lazy-list entry retire. The legacy-file guard the ensure
carried stays at each call site.

* test: drop obsolete lazy-ensure coverage for origin device tokens

The table is canonical at v13; same-version lazy creation no longer
exists to protect. Origin CRUD, isolation, and rotation coverage remains
in the surviving cases.

* refactor(state): fold installed_plugin_index into config_machine_state

The singleton index row becomes one JSON value under
plugins.installedIndex with its rollback-fencing revision inside the
value; reads, CAS restore, and the lease-held write transactions use
direct Kysely on config_machine_state so the state_leases assertion
stays in-transaction. The v13 migration imports the row and drops the
table; the additive workspace_dir entry folds with it. Doctor guidance,
docker staging, and the e2e probes name the machine-state row.

* refactor(state): merge workspace_attestations into workspace_setup_state

One row per workspace now carries both setup milestones and the
attestation clock: nullable setup columns represent attestation-only
workspaces (replaceWorkspaceAttestation can precede any setup write) and
setupExists derives from a non-null version. The bootstrap-hash FK
repoints to the merged table; migration receipts keep the historical
workspace_attestations discriminator string. The v13 migration grows and
rebuilds the table, merges attestation rows (orphans without a path
alias drop — their hashes re-derive at the next bootstrap attestation),
and the consolidation kind is renamed state-consolidation-v13 to cover
the batch.

* test(state): cover the workspace merge and consolidation fallout

The v12-to-v13 regression seeds merged, attestation-only, and orphan
attestation workspaces; the 13-to-12 downgrade fixture recreates
workspace_attestations and installed_plugin_index from the folded data;
the fold-in migration gates the additive workspace_dir column for
pre-additive rows; the workspace merge now triggers on the setup table's
own shape so stable-era databases without an attestations table still
reshape; the consolidation applied-message covers the batch.

* refactor(state): fold shared auth profile singletons into config_machine_state

The shared-state auth_profile_stores/auth_profile_state rows (fixed key
'shared') become authProfiles.store/authProfiles.state machine-state
values; the agent-DB tables of the same names are untouched. Git-backup
redaction moves from table-drop to the authProfiles. secret prefix with
seeded-secret absence proof; migration receipts keep the historical
table-name discriminators; the shared-auth relocation and receipt
verification project the KV cells back to the receipt-era row shapes so
persisted digests stay byte-compatible. mcp_oauth_stores stays a table —
its multi-key fold is a named follow-up.

* test(state): finish shared-auth fold coverage and annotate boundary casts

Auth seeders and assertions across the e2e/scripts/secrets suites target
the authProfiles machine-state cells; the v12-to-v13 regression proves
payload-byte fidelity, non-shared-row drop, and insert-if-absent
precedence; the downgrade fixture recreates and repopulates both v12
tables. Boundary type assertions in the plugin-index store carry SAFETY
invariants per the ratchet.

* chore: shrink assertion-safety baseline for plugin-index store

* refactor(doctor): delete the dead onboarding-recommendations migration

Its input — the unscoped 'primary' onboarding row — existed only between
9a93a52a8a and 473962b7de, a two-day beta window; no shipped stable
can produce it and the runtime table folded away at v12. The audit
backup list keeps recognizing system-agent.jsonl artifacts because beta
installs that ran that import may still carry its backups.

* docs: sync the 13-to-12 downgrade example with the executable fixture

* style: format the synced downgrade example

* style: drop unused import and duplicate union constituent

* fix(state): keep orphan attestations across the v13 workspace merge

The merged workspace_setup_state required a workspace path, but legacy
orphan hashed-key attestations never recorded one. workspace_path is now
nullable (setup rows still enforce it via CHECK), the v13 migration and
the doctor file import keep orphans with a NULL path that heals on the
next live access, and the 13-to-12 downgrade keeps attestation-owned
hashes. Doctor test seeds move to the folded KV row.

* perf(state): retire unused cron indexes

* fix(state): preserve v13 migration recovery

* fix(state): preserve v12 lazy-table upgrade

* docs(state): document v13 auth relocation

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-27 15:26:14 +08:00
Peter Steinberger 2fd16c2855 fix: share managed Gateway startup readiness across setup (#130682)
* fix: wait for Gateway startup after configure daemon setup

* fix: share managed Gateway startup timing across setup
2026-08-27 00:11:32 -07:00
ruel225 a3eb0692a2 fix(cli): reject --agent for global model refresh (#130448)
* fix(cli): models refresh rejects parent --agent like set/aliases/scan

`models refresh` refreshes the global hosted catalog
(refreshRemoteModelCatalog) and takes no agent, but silently accepted a
parent --agent, implying a per-agent scope it does not deliver. #126864
landed rejectAgentScopedModelCommand for set/set-image/aliases/scan but
left refresh unaddressed (it scoped out only fallbacks/image-fallbacks).
Add "refresh" to GlobalOnlyModelCommandName and switch refresh's action
to the same loadModelsRuntime + reject + runModelsCommand pattern, so
--agent fails fast with the same error instead of a silent global refresh.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(cli): list models refresh among --agent-rejecting commands

`docs/cli/models.md` listed `set`/`set-image`/`scan`/`aliases` as
rejecting `--agent` but omitted `refresh`, so the new guard landed in
the previous commit was not reflected in the docs. Add `refresh` to the
global-only list and note it on the refresh section.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: ruel225 <ruel225@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-27 14:25:44 +08:00
Peter Steinberger 7eebd6d4a6 docs(hooks): clarify setup and execution contracts (#130734) 2026-08-26 23:12:06 -07:00
Eden a0abb23d00 fix(plugins): keep beta installs on gateway release (#127791)
Keep official plugins on the gateway release stream so beta gateways do not silently install stable artifacts. Resolve hosted catalog entries at the shared boundary, stop missing cohorts before hook fallback, and keep recovery notices visible.

Co-authored-by: 許元豪 <146086744+edenfunf@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-27 10:53:47 +05:30
Peter Steinberger 036e635c71 fix: preserve Gateway error reasons in text logs (#130645)
Print the existing formatted and redacted RPC error instead of a generic reachability claim. Preserve JSON output, selected-target details, fallback/recovery, auth and exit behavior. Verified with real loopback rejection and built CLI before/after proof. Closes #130616.
2026-08-26 22:10:26 -07:00
wangyan2026 e00d46b19b fix(plugins): normalize managed npm overrides before peer planning (#124532)
* [AI] fix(plugins): filter pnpm parent-child overrides at managed npm producer

readOpenClawManagedNpmRootOverrides returned host pnpm-workspace overrides
without filtering pnpm-only parent-child selectors (parent>child). Those
selectors are invalid npm override keys and trigger EINVALIDTAGNAME before
the retry-based compatibility path can recover, breaking managed npm plugin
installs and the pre-install peer-sync that runs before the retry loop.

Filter pnpm parent-child selectors once at the shared producer so every
managed npm install/uninstall consumer receives a npm-compatible manifest
up front. The existing retry path stays as a fallback for npm alias
compatibility, which is npm-version-dependent.

Fixes #124426

* fix(plugins): normalize overrides before managed peer planning

Plan peers against the incoming compatible override set so retired selectors cannot silently retain stale pins. Remove duplicate selector retry and synchronization paths while preserving npm alias compatibility.

Co-authored-by: WangYan <wang.yan29@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 20:41:34 -07:00
Peter Steinberger 682ddcb28c fix: preserve Gateway when setup Reinstall is cancelled (#130617)
Keep replacement preparation ahead of service mutation in configure and onboarding. Let platform installers own replacement, and report surviving Gateway reachability independently of failed setup.
2026-08-26 20:07:50 -07:00
Peter Steinberger d3d43eb6cf fix(cli): reject missing repeatable inference inputs (#130608) 2026-08-26 19:55:41 -07:00
cxbAsDev e3c78c3487 fix(agents): keep embedded prompts isolated from ambient files (#110776)
Skip unused SYSTEM.md and APPEND_SYSTEM.md discovery in embedded turns,
compaction, and workers. Preserve bounded workspace context and interpret
Gateway-supplied instructions as literal text rather than local filenames.
Share the existing loader policy and retain standalone loader semantics.

Rewrite the prompt-read repair reported in #110776.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 19:53:59 -07:00
Peter Steinberger 4b287caac3 fix(memory): stop false Copilot index mismatch warnings (#130603)
Share provider-owned canonical model projection across cold identity and creation, keep undiscovered models unknown, and preserve strict initialized identity checks. Consolidate obsolete lookup and table-existence paths.

Co-authored-by: 1052326311 <65798732+1052326311@users.noreply.github.com>
2026-08-26 19:50:15 -07:00
Peter Steinberger 00713ca253 fix(cli): honor selected port when tailing logs (#130513) 2026-08-26 17:34:17 -07:00
Peter Steinberger 5153f25495 fix(memory): prevent forgotten session content from returning (#130451) 2026-08-26 16:26:00 -07:00
Peter Steinberger 86e208310f improve(worker): diagnose admission-deadline failures and widen daemon revalidation budget (#130435)
WorkerAdmissionDeadlineExceededError now carries the terminal diagnosis —
the last connection failure kind and detail, attempt count, and the
redacted endpoint — instead of a bare deadline sentence, and that text
flows through IPC, container stderr, the node launch journal, and the
gateway turn error. Credential material (raw, URL-encoded, JSON-escaped)
is scrubbed before truncation. A LAN partition was misdiagnosed as a
gateway admission wedge for a day because the old text was identical for
never-connected and never-answered (#129979). Container daemon
revalidation gets a 30s budget: a slammed-but-healthy OrbStack daemon
exceeded the old 5s under a 50-container burst; fail-closed semantics
unchanged.
2026-08-26 15:15:10 -07:00
Peter Steinberger 0e05d8205a fix(browser): accept common keyboard aliases (#130401)
* fix(browser): accept common keyboard aliases

* docs(browser): note keyboard alias repair
2026-08-26 15:12:37 -07:00
Peter Steinberger 738e67c880 fix(browser): preserve exact select option values (#130410) 2026-08-26 14:29:08 -07:00
Masato Hoshino df559c3284 fix(agents): stored auth profile order is ignored when resolving CLI runtime aliases (#129165)
* fix(agents): honor the stored auth profile order when resolving CLI runtime aliases

`resolveCliRuntimeFromAuthProfile` built its ordered profile list from
`cfg.auth.order` alone, and `RuntimeAuthAliasParams` carried no auth store at
all, so the order an operator sets through `models auth order set` never
reached CLI runtime alias resolution. The canonical sibling resolver,
`resolveAuthProfileOrderWithMetadata`, already reads the stored order first and
falls back to config, so the two disagreed about the same question.

With no config `auth.order` and two profiles sharing a provider auth key, the
ordered list came out empty and the resolver fell through to its "exactly one
compatible profile" branch, returning undefined. The gateway then reported
model availability and picked the turn's execution backend as if the reorder
had not happened, and no restart cleared it because the store was never read on
this path.

Rather than re-deriving the precedence at the call site, extract it: the
stored-first explicit-order resolution moves out of
`resolveAuthProfileOrderWithMetadata` into `resolveExplicitAuthOrderSelection`,
and alias routing becomes its second consumer. Both now resolve the order
through one implementation, across normalized provider keys, so they cannot
drift apart again. The store is read from the lifecycle-published runtime
snapshot for the requested agent and its declared inherited owner, matching how
prepared model catalog and registry resolve the same pair; no new snapshot API
and no SQLite reopen on request paths.

An authored stored order also owns selection, so it suppresses the
unique-compatible-profile fallback the way the canonical resolver does.

Tests cover stored-order-only selection, stored-over-config precedence,
non-normalized stored keys, inheritance from the main agent, authoritative
empty orders with a control for the fallback that must survive, and the
unchanged config-only path.

* fix(agents): align runtime routing with stored auth selection

Share stored-over-config precedence, preserve stale-profile repair, and route explicitly selected stored credentials without config metadata. Remove unreachable OpenAI order-alias merging.

Co-authored-by: masatohoshino <g515hoshino@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 13:50:02 -07:00
Peter Steinberger 1fc29beba2 refactor(state): fold singleton tables into config_machine_state at schema v12 (#129876)
* refactor(state): fold singleton tables into config_machine_state at schema v11

Eight singleton tables (skill_curator_state, update_check_state,
clawhub_promotions_feed_state, model_catalog_remote, voicewake_triggers,
voicewake_routing_config, voicewake_routing_routes,
onboarding_recommendations) were each one logical JSON value behind a
fixed key; their bespoke schemas, lazy ensures, and per-table accessors
collapse onto the shared config_machine_state KV under namespaced keys.
cron_store_epochs retires outright: it was born write-only in #114388
and no reader ever existed in any language. Durable values (update
check state, voicewake triggers and routing, per-workspace onboarding
answers) migrate insert-if-absent during the v10->v11 migration; cache
class contents rebuild on next use. Deferred with named reasons:
exec_approvals_config (macOS direct-SQL contract), installed_plugin_index
(same-tx lease fence), node_host_config and web_push_vapid_keys
(secret-table git-backup redaction).

# Conflicts:
#	src/skills/workshop/collection-review-state.ts
#	src/skills/workshop/collection-review.gateway-admission.test.ts

* test: register v11 guard carve-outs and suppression pin

The v11 migration module joins the raw-SQLite allowlist (migrations are
the named guardrail exception), the lint-suppression allowlist records
the second type-parameter suppression in config-machine-state, and the
identity module keeps only externally consumed exports.

* test: surface CLI stderr when migration-diagnostic assertion fails

* test: expect migration diagnostics on stderr for models plain commands

The #129037 pending-migration cases asserted that aliases/fallbacks
lists never open the state database, but config-health observation
(observeConfigSnapshot -> readConfigHealthStateFromStore) full-opens it
on any config read whose file exists — reproduced identically on clean
main with a main-built dist. The protected contract is exact stdout;
the diagnostic legitimately lands on stderr for every case.

* test: drop unused defaults import from CLI stdout e2e

* test: split session path derivation out of oversized session-files suite

#130016 pushed session-files.test.ts to 1008 lines, over the 1000-line
lint cap and red for every PR's check-lint. The sessionPathForFile
describe moves to a self-contained sibling following the existing
session-files.*.test.ts split pattern; no assertions change.

* refactor(state): fold four more singleton tables into schema v12

tui_last_sessions (cache-class, regenerates on next session switch),
sidebar_sections (persistent section order, migrated as one JSON array),
node_host_config, and web_push_vapid_keys join the v12 fold-in, taking
the retirement to thirteen tables at the same version. The two secret
singletons were blocked on table-granular git-backup redaction; backups
now exclude config_machine_state rows by secret key prefix (nodeHost.*,
webPush.vapidKeys) with a fail-closed row filter and regression proof,
so STATE_SECRET_TABLE_NAMES sheds both tables. The sidebar fold also
retires its lazy-ensure WeakSet and inline DDL; sidebar edits stay
inside the existing session-group write transaction via direct Kysely.

* fix(node-host): omit absent Cloudflare Access config like the column reader

The KV rewrite returned gateway.cloudflareAccess as an own undefined
property where the retired column reader omitted the key; toStrictEqual
consumers (state-migrations doctor-repair test) caught the shape drift.
Mirror the column reader's conditional spread at both construction
sites.

* fix(backup): disclose redacted machine-state prefixes after restore

The prefix-granular secret redaction recorded omitted key prefixes in
the backup manifest but the restore result exposed only excludedTables,
so a redacted restore looked complete while nodeHost.* and
webPush.vapidKeys configuration were intentionally absent. The restore
result and CLI output now disclose the omitted prefixes (JSON mode
carries them via the result shape), with restore-side regression
coverage.

* fix(tui): compare-and-delete retired session pointers

Doctor cleanup read matching pointer keys then deleted them
unconditionally, so a replacement pointer written between the scan and
the delete was erased. The delete now re-checks the stored value inside
the write transaction and only removes pointers that still name a
retired session; a live replacement survives (regression covered).
Also corrects the stale schema-version line in database-first.md.
2026-08-26 13:32:19 -07:00
Peter Steinberger 6287056d26 docs(secrets): make the credential-request tool discoverable and warn about empty hosts (#130299)
The tool page shipped with the feature but nothing pointed at it: the
tools index still listed only ask_user under human input, and neither the
secrets CLI page nor ask-user mentioned it. Add those three references.

The page also missed the trap the card invites: the allowed-hosts field
is editable, and clearing it stores a secret that can never be
substituted at egress, so the request looks successful and the credential
is unusable. Warn where the operator edits it, say what a skipped or
expired prompt means for the agent, and drop wording left over from when
requests could ask for an env value.
2026-08-26 11:56:12 -07:00
Peter Steinberger 8e39f58365 docs(memory): add memory provenance and deletion concepts page (#130278)
* docs(memory): add memory provenance and deletion concepts page

New concepts/memory-provenance page tells the operator policy story end to end: recorded session lineage through consolidation, the admission policy and its pipeline-only boundary, memory forget guarantees (whole-entry purge, derived-artifact sweep, forgotten tombstones) and reported boundaries (transcripts, curated writes, paraphrased prose), plus the person/source purge workflow. Cross-linked from memory architecture, dreaming, builtin, overview, CLI, and config reference; registered in docs navigation.

* docs(i18n): add glossary terms for the memory provenance page

* docs(memory): distinguish curated entries from missing lineage in the provenance page
2026-08-26 11:36:39 -07:00
Peter Steinberger 9d9dc31275 feat(memory): session provenance, admission policy, and openclaw memory forget (#130151)
* feat(state): add memory entry origins and session tombstone tables with session-aware write provenance

Additive same-version per-agent tables (memory_entry_origins, memory_session_tombstones) declared canonically with lazy idempotent ensure; read-only agent DB access exposed through the SDK; memory-write observers and the session-memory hook record the authoring session; archived narrative transcripts classified by authoritative run identity.

* feat(memory): admission policy, entry provenance, and openclaw memory forget

memoryPolicy.excludeSessions keeps configured sources out of the dreaming pipeline with recorded exclusions; promotion writes are marker-addressable and carry per-session origins through consolidation; memory forget purges whole entries and every derived artifact (corpus lines, diary quotes, index/FTS/vec/cache, short-term state, backups), reports curated agent writes from transcripts, and tombstones purged sessions so ingestion, backfill, and transcript indexing never re-admit them.

* docs(memory): document admission policy, memory forget, and provenance boundaries

* fix(memory): open the vec probe through openNodeSqliteDatabase

Kysely guardrail forbids direct node:sqlite constructors in production; the in-memory extension probe now uses the canonical opener.

* fix(memory): resolve archived and explicit sessions in memory forget

Explicit --session selectors union live session windows, transcript archives, and exact unresolved ids so an operator-named session always purges and tombstones instead of silently no-oping after lifecycle archival; reports carry per-session resolution sources. ClawSweeper P1 on #130151.

* fix(memory): reconcile consolidation origins for every workspace agent

Shared workspaces record entry origins per source agent; consolidation now re-keys and prunes origins in each participating agent's database (membership from the authoritative dreaming workspace mapping), so a non-owner agent's later memory forget still finds the live consolidated entry. ClawSweeper re-review P1 on #130151.
2026-08-26 10:57:04 -07:00
Peter Steinberger c69abc2327 fix(sandbox): restore reliable OpenShell execution and workspace integrity (#130031)
* fix(sandbox): harden OpenShell lifecycle and workspace integrity

Fixes #127441, #127438, #98446, #119270, and #89606.

Co-authored-by: harjoth <harjoth.khara@gmail.com>

Co-authored-by: qingminlong <qing.minlong@xydigit.com>

* fix(agents): reject unresolved memory flush path aliases

* docs: keep OpenShell release notes in pull request

---------

Co-authored-by: qingminlong <qing.minlong@xydigit.com>
2026-08-26 03:10:07 -07:00
sunlit-deng 87b93b5303 fix(browser): bound batch action files (#115882)
* fix(browser): bound batch action files

* fix(browser): preserve legacy file input while bounding batches

Co-authored-by: sunlit-deng <yang.jiajun1@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-26 02:37:42 -07:00
Peter Steinberger 4bd8859126 fix(skills): record skill usage again and retire dead curator tables (#129769)
* fix(scripts): see SAFETY comments after template substitutions

The assertion ratchet scanned each file with a raw ts.createScanner, which
reads the `}` closing a template-literal substitution as a block close. The
scanner desynced there, so every `// SAFETY:` comment after a file's first
`${...}` was invisible and its annotated assertions were counted as bare.

Track substitution brace depth and rescan the closing brace the way the parser
does. The fix uncovers already-annotated assertions in eight files, so the
baseline shrinks accordingly.

* fix(skills): record skill usage again and retire dead curator tables

Skill lifecycle curation shipped in 2026.7.1 with two producers: a trusted
`skill.used` consumer writing `skill_usage`, and a daily sweep aging skills
into `skill_lifecycle`. The weekly collection review (#121653) replaced that
policy and deleted both producers, but left every reader in place. Since then
`skill_usage` has had no writer, so curator status reported `lastUsedAtMs:
null` and `useCount: 0` forever, and `skill_lifecycle` had no writer either, so
pin/unpin/restore either threw "not found" on fresh installs or, worse,
"succeeded" on upgraded ones while gating nothing at all.
`skill_workshop_proposal_origin_runs` was never read in any revision; proposal
provenance is authoritative in `record_json`.

Restore the usage producer at its owner and retire what has no owner:

- `skill.used` events populate `skill_usage` again, registered with the
  collection-review maintenance it belongs beside. Curator status derives
  curated skills from applied Workshop create proposals and reports real usage.
- Weekly review receives bounded `useCount` / `lastUsedDaysAgo` evidence, with
  prompt text stating usage supports keeping a procedure and never alone
  justifies a drop.
- State schema 10 drops `skill_lifecycle` and
  `skill_workshop_proposal_origin_runs`. Previously archived skills return to
  the active collection, where review judges them by content; the migration
  logs how many. Reconcile now clears usage only for skills it actually drops.
- `skills.curator.pin`/`unpin`/`restore` stay registered for existing clients
  but fail with an explicit retirement message instead of silently doing
  nothing.

Retirement code moves to openclaw-state-db-table-retirements.ts to keep the
schema-repair module under max-lines; that split is a pure relocation.

Production delta is +23 raw: about -46 for the change itself, +44 for the file
split, +25 for the ratchet fix in the previous commit.
2026-08-26 01:06:06 -07:00
Peter Steinberger 6a6635abb3 feat(daemon): support Bun 1.4 managed services (#129593)
* feat(daemon): support Bun 1.4 managed runtimes

Amp-Thread-ID: https://ampcode.com/threads/T-01a037b7-66db-71f0-91e7-1578b383afb2

* fix(daemon): enforce Bun SQLite safety

Amp-Thread-ID: https://ampcode.com/threads/T-01a037b7-66db-71f0-91e7-1578b383afb2

* fix(daemon): preserve lightweight Bun startup

Amp-Thread-ID: https://ampcode.com/threads/T-01a037b7-66db-71f0-91e7-1578b383afb2

* docs: show Bun runtime opt-in commands

Amp-Thread-ID: https://ampcode.com/threads/T-01a037b7-66db-71f0-91e7-1578b383afb2

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-26 00:45:43 -07:00
Peter Steinberger 7f7448e96d feat(gateway): identity-conditional forced sandboxing for operator roles (#129926)
One shared agent could not give different people different execution
isolation: sandbox selection saw only the agent's mode and the session key,
never who created the session. Teams that share an agent had to choose
between sandboxing everyone or no one.

Add a closed, optional role axis sandbox?: "inherit" | "required"
(default "inherit", so existing deployments are unchanged). The Gateway
resolves it from the authenticated session creator and stamps it write-once
onto genuinely new session entries; the agents layer reads that immutable
fact and forces a sandbox even when the agent config says mode: "off".

Anchoring on the creator keeps a session's isolation stable for its lifetime:
a maintainer replying inside a guest session cannot un-sandbox it, and a
caller whose role requires a sandbox is refused inside an unstamped session
rather than silently inheriting host execution. Reset, rewind, rollover and
fast-path all carry the requirement forward so a session cannot be reset out
of its sandbox.

Because exec injects the agent's managed GitHub identity only for gateway-host
execution and blanks GH_TOKEN/GITHUB_TOKEN otherwise, a forced-sandbox session
also loses access to the shared agent's credentials — the property that makes
one shared agent safe for untrusted guests.

Session entries are JSON; no SQLite schema, schema-version, or protocol change.
Docs also correct the sandbox backend list, which omitted the first-class
podman backend.
2026-08-26 00:18:50 -07:00
Peter Steinberger 2f17d11e90 fix(backup): preserve configured agent state roots (#129773)
* fix(backup): honor configured agent state roots

Inventory configured agent directories as durable backup owners regardless of layout. Reuse the owner inventory for archive planning, SQLite snapshotting, verification, restore safety, and Git/SQLite backup selection.

Add manifest-first plugin backup resource declarations so regenerable runtime roots stay plugin-owned without provider IDs in core.

Closes #129730

* fix(backup): preserve canonical ownership checks
2026-08-25 21:13:37 -07:00
sashankh 93573e8fdf fix(models): --agent is silently ignored by models aliases and models scan (#126864)
* fix(models): reject --agent on aliases and scan instead of ignoring it

models aliases list/add/remove and models scan never read the parent
--agent option, so an operator scoping one of them to an agent got no
feedback that the flag did nothing, and a typo'd or nonexistent agent id
was never validated. They only read or write agents.defaults.*, so there
is no agent-scoped path for the flag to feed.

Reuse the existing set/set-image guard rather than inventing a new
mechanism: rename it to rejectAgentScopedModelCommand, give each
global-only command an accurate scope phrase, and call it before the
command runs. fallbacks/image-fallbacks are deliberately untouched;
they are tracked separately in #106346.

Fixes #126597

* fix(models): drop release-owned changelog entry

* fix(models): simplify global-only scope message

Review flagged the production LOC delta. Collapse the runtime scope map
into a type-only union and one accurate message covering both the read
(aliases list) and write commands; net production delta is now +20.

* fix(models): state the guard scope accurately for scan

Review finding: the shared message claimed every guarded command 'only
reads or writes global model config', but models scan --no-probe prints
the catalog and returns before any config update (scan.ts:283).

Say what is true of all six instead: they are global and never
agent-scoped. Docs line updated to match.

---------

Co-authored-by: sashankh <saisashankhd@microsoft.com>
2026-08-25 19:24:25 -07:00
Josh Avant 1c37c8cdc7 fix(exec): scope reusable approvals to their working directory (#129636)
* fix(exec): bind durable approvals to working directory

* chore(apps): refresh native string inventory

* test(node-host): preserve prepared working directory

* fix(exec): use shared path safety facade

* fix(exec): revalidate approved directory identity
2026-08-25 18:24:14 -07:00
Peter Steinberger 6f61184d1e fix(telegram): support polls lasting up to seven days (#129461) 2026-08-25 17:36:11 -07:00
Peter Steinberger df962dd559 fix(cli): emit JSON failures when existing config is invalid (#129578)
* fix(cli): preserve invalid-config failures in JSON output

* test(cli): assert structured invalid-config process failures
2026-08-25 17:17:26 -07:00
Peter Steinberger b5864ba1db fix(skills): fail closed for unavailable remote Gateway (#117567)
* fix(cli): respect explicit Gateway ownership

* fix(gateway): fence offline CLI fallbacks

* fix(gateway): restrict local recovery closes

* fix(cli): preserve offline Gateway ownership and log recovery
2026-08-25 16:58:39 -07:00
Peter Steinberger 948ae80ae6 fix(onboard): preserve JSON errors when no terminal is available (#129437) 2026-08-25 16:31:09 -07:00
Leon-SK668 0db1d89d05 fix(backup): preserve full backups with managed runtime symlinks (#124821)
* fix(backup): skip managed runtime symlinks

Keep full backup creation fail-closed for arbitrary symlinks while omitting and reporting regenerable browser, sandbox, plugin-skill, and agent-runtime paths. Verify relative links remain within declared backup assets across create and restore.

Closes #124769

Co-authored-by: Leon-SK668 <0668001470@xydigit.com>

* test(codex): route startup retry coverage

* test(codex): align startup inventory with main

* test(agents): complete plugin metadata snapshot mock

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 15:16:57 -07:00
Josh Avant f9dbda38dc fix(mcp): revoke resource access with app authority (#129550) 2026-08-25 14:04:14 -07:00
Peter Steinberger a6ebad9964 fix(worker): honor full access on paired node sessions (#129537)
* fix(worker): honor full access on paired node sessions

* test(worker): preserve narrowed operator in live proof

* test(vitest): assign Codex startup retry to its owner shard
2026-08-25 14:01:39 -07:00