Commit Graph

3657 Commits

Author SHA1 Message Date
Peter Steinberger
62c5a8b888 fix(gateway): make scope errors machine-readable across clients (#111013)
* fix(gateway): consume structured scope errors

* docs(gateway): clarify tools error boundary

* refactor(gateway): unify node admin policy
2026-07-18 17:53:45 -07:00
mushuiyu886
7abcd6c691 fix(skills): distinguish duplicate ClawHub search results by publisher (#110903)
* fix(skills): distinguish duplicate search results by publisher

* test(skills): cover owner-qualified search output

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 17:27:25 -07:00
Peter Steinberger
56eef79989 fix(channels): recover dead-lettered inbound events (#111029)
* feat(channels): add ingress dead-letter recovery

* fix(channels): preserve dead-letter compatibility

* docs: refresh CLI map for channel dead letters
2026-07-19 00:44:23 +01:00
Peter Steinberger
556a2ee276 feat(cron): add per-job dynamic cadence (#110978)
Add optional per-job pacing bounds across the cron API, CLI, tool schema, public output, and SQLite job envelope, requiring at least one bound. Allow only the currently running paced job to record a one-shot next_check proposal and carry it through isolated-run completion.

After successful runs, clamp the proposal to the job bounds and persist an exact one-shot slot marker so maintenance preserves only that timestamp. Clear the marker on runs, edits, and schedule normalization; preserve existing no-proposal, skip, timeout, and error scheduling behavior.
2026-07-18 23:43:39 +01:00
Peter Steinberger
7fbfc2e8ad fix(plugins): allow intentional uninstall size drops (#110991) 2026-07-18 23:28:18 +01:00
cxbAsDev
2295fae731 fix: bound miscellaneous unbounded file reads across 5 modules (#110516)
* fix: bound misc unbounded fs.readFile calls; remove unused fs import

* fix: decode buffer to string before passing to string consumers

readRegularFile and readRegularFileSync return { buffer, stat },
not a string. All 4 new call sites passed the raw object to functions
expecting a string (JSON.parse, RegExp.test, template literals, etc.),
causing TS2345 type errors and runtime failures.

Fix each call by extracting .buffer and calling .toString('utf8')
before passing the result to string consumers.

* style: fix oxfmt formatting in config-set-input.ts

* fix: bound config and trajectory metadata reads

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

* refactor: isolate bounded read ownership

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 23:27:26 +01:00
Peter Steinberger
f1a8c04aea fix(cron): clean up recurring jobs converted to one-shot (#110431)
* fix(cron): default updated one-shots to cleanup

* test(cron): type schedule transition fixtures

* chore: leave cron notes to release generation
2026-07-18 18:16:40 +01:00
Peter Steinberger
98410d986e refactor(state): move device identity into canonical SQLite state (#110392)
* refactor: store device identities in SQLite

* style: satisfy Swift identity lint limits

* test: harden device identity migration fixtures

* fix: harden SQLite device identity recovery

* chore: remove stale identity helper

* refactor: isolate device identity repair

* chore: remove stale migration import

* test: validate migrated identity key types

* fix: harden device identity repair

* style: format device identity assertion

* fix: derive repaired identity key from PEM

* style: remove redundant PEM conversions

* fix: align native identity store with schema v4

* fix(state): satisfy SQLite identity CI gates

* fix(state): coordinate native identity migration

* test(doctor): include native identity claim path

* fix(infra): preserve coordinator release error

* fix(state): clear identity validation gates

* refactor(apple): remove identity test-only APIs

* refactor(apple): remove dead identity error type

* test(apple): use canonical identity test seam

* test(macos): isolate gateway readiness identity
2026-07-18 17:43:56 +01:00
Peter Steinberger
40793e6f8b fix: bound pasted input and provider response bodies (#110627)
* refactor(runtime): centralize bounded I/O handling

* fix(runtime): finalize bounded I/O contracts

* chore(security): drop stale audit import

* docs(changelog): credit bounded I/O fixes

Co-authored-by: Pick-cat <huang.ting3@xydigit.com>

* fix(agents): keep provider HTTP options private

* fix(ai): traverse OpenAI schema maps by value

* fix(runtime): preserve absolute download deadlines

* ci(ui): stabilize compressed CSS budget

* fix(ai): traverse legacy schema applicators

---------

Co-authored-by: Pick-cat <huang.ting3@xydigit.com>
2026-07-18 13:54:56 +01:00
cxbAsDev
05fb8e6e61 fix(cli): bound --message-file reads for agent command (#101442)
* fix(cli): bound --message-file reads for agent command

* fix(cli): preserve symlinked --message-file paths with bounded reads

* fix(cli): preserve FIFO message files with bounded reads, document 4 MiB cap

* fix(cli): accept FIFO --message-file targets via bounded descriptor read

* test(cli): drop duplicate FIFO message-file read test

* docs(cli): note 4 MiB --message-file cap in agent help text

* style(commands): format agent-via-gateway test

* fix(cli): preserve procfs message-file reads

Co-authored-by: 陈宪彪0668000387 <chen.xianbiao@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 12:29:33 +01:00
Peter Steinberger
9d97e10efe refactor: move non-session runtime journals to SQLite (#109427)
* refactor: migrate runtime JSONL state to SQLite

* chore: refresh SQLite migration validation

* fix: preserve safe audit migration order

* fix: sanitize retired audit archives safely

* fix: satisfy SQLite storage architecture gates

* fix: serialize plugin doctor state migrations

* fix: bound memory event SQLite projections

* fix: rotate memory event projections safely

* fix: preserve imported event retention age

* fix: harden memory event export projection

* fix: canonicalize memory event migrations

* fix: harden legacy journal migrations

* fix: report unsafe legacy journal paths

* fix: preserve journal ownership during migration

* fix: keep legacy file imports doctor-only

* fix: align SQLite audit CI coverage

* refactor: keep state helpers module-private

* fix: harden legacy state migration recovery

* fix: reconcile SQLite state audit migration

* test: use neutral audit redaction fixtures

* fix: close SQLite migration recovery gaps

* refactor: split audit migration recovery helpers

* test: prove completed audit pads stay out of backups

* fix: preserve audit record ordinals across blank lines

* fix: align SQLite audit CI contracts

* build: package SQLite audit E2E entries

* fix: preserve audit ordinals in backup snapshots
2026-07-18 11:42:14 +01:00
Peter Steinberger
fab3cdf1d8 refactor(gateway): simplify lifecycle mutation contracts (#110583)
* refactor(gateway): simplify lifecycle mutation contracts

* refactor(cli): unexport internal emitDaemonActionMessage
2026-07-18 11:09:21 +01:00
Peter Lee
c791e2b128 fix(cli): restore terminal state before exit in logs and hooks commands (#105863)
* fix(cli): restore terminal state before exit in logs and hooks commands

* fix(cli): route logs/hooks error exit through canonical defaultRuntime.exit

* fix(cli): route terminal reset to stderr in JSON mode to keep stdout parseable

* fix(cli): centralize stream-aware terminal reset exit

Add optional resetStream parameter to RuntimeEnv.exit so JSON-mode
callers can route the terminal reset to stderr through the shared
defaultRuntime.exit path, keeping structured stdout parseable.

- Extend RuntimeEnv.exit signature with optional resetStream option
- Route JSON-mode logs fatal exit through unified defaultRuntime.exit
  instead of manually pairing restoreTerminalState with process.exit
- Update test mock to exercise real terminal restore during exit

* refactor(cli): tighten terminal exit contract

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:25:13 +01:00
Peter Lee
953ae8163a fix(cli): reject --channel/--to for systemEvent cron jobs with a clear error (#105910)
* fix(cli): reject --channel/--to for systemEvent cron jobs with a clear error

* test(cli): add regression coverage for cron-add delivery-option validation

* fix(cli): fix optionSource reference and add chat-delivery guard to cron edit

- Fix bare optionSource() call in cron-add guard to use cmd.getOptionValueSource()
- Add equivalent resulting-job validation to cron edit: reject --channel/--to/--account/--thread-id when the resolved job is a main-session systemEvent
- Add parity tests covering fast-path reject, existing-job reject, isolated allow, and clear-flag allow cases

* test(cli): return a real CronJob from default cron.get mock

* fix(cli): reject dropped cron delivery targets

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:19:07 +01:00
Peter Steinberger
0d91b07f5b refactor(update): split update-command into focused modules under the line limit (#110550) 2026-07-18 09:51:00 +01:00
Chris Eckert
42be965eac improve(mattermost): restart only the changed account on config reload (#99312)
* improve(gateway): restart only the changed account on channel config reload

When a config change is scoped entirely to one channel account
(channels.{kind}.accounts.{accountId}[.*]), restart just that account
instead of the whole channel. Wholesale channel restarts disconnect every
account on the channel; on gateways running many accounts, each
account-scoped config write (adding an account, changing one account's
settings) briefly dropped every other account's connection.

The reload plan gains a restartChannelAccounts bucket populated only when
all of a channel's changed paths are account-scoped; any channel-global
path falls back to the existing wholesale restart, and a channel scheduled
for wholesale restart drops its per-account entries so each (channel,
account) pair restarts at most once. The executor runs per-account
restarts through the existing stopChannel/startChannel accountId parameter.

* fix(gateway): preserve account reload admission

* fix(gateway): scope surgical reloads to isolated plugins

* test(gateway): avoid preactivating reload snapshot

* docs(channels): define account reload isolation contract

* fix(gateway): preflight scoped account reloads

* fix(gateway): re-drain live scoped reload targets

* docs: refresh generated docs map

* fix(mattermost): align scoped reload with durable ingress

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 09:33:06 +01:00
Peter Steinberger
1710313596 fix(cli): offer config repair after invalid startup (#110533)
* fix(cli): offer doctor recovery for invalid config

* fix(cli): preserve invalid config overrides

* fix(cli): keep invalid config recovery controlled
2026-07-18 09:30:27 +01:00
Peter Steinberger
d7de67ae02 feat: ask_user follow-ups — harness convergence, channel finalization + reactions, native cards, docked web panel (#110372)
* feat(ask-user): follow-up harness slice

* feat(ask-user): follow-up channels slice

* feat(ask-user): follow-up native slice

* feat(ui): dock question panel above composer with stepper and compact stream summaries

* docs: refresh follow-up integration maps

* test(ui): align terminal summary proof

* fix(infra): echo declared option answers in terminal status when free-text is allowed

* fix(infra): keep reaction answering when display labels are formatter-adjusted

* fix(agents): settle plain-text claims only after question registration commits

* fix(agents,apps): commit-ordered claim persistence, claim-aware prompt delivery, non-blocking question refresh

* fix(harness,infra): reaction-appropriate question copy, caller presentations honored

* fix(native,infra,agents): local-expiry eviction, value-addressed reactions, reserve-before-request

* fix(infra,android): dual-mode question resolver for compact callbacks; reset terminal retention on replayed pending

* fix(harness,discord): claim-aware prompt delivery in run helper; escape finalization labels

* fix(macos): merge transient-content visibility with question cards after main sync

* fix: repair ask user follow-up CI

* test: update limited bootstrap scope expectation

* fix: retain shared question card API

* chore: refresh native i18n inventory
2026-07-18 03:32:39 -04:00
Peter Steinberger
6416baef83 fix(gateway): audit managed service starts (#110497)
* fix(gateway): audit managed service starts

* chore: drop changelog edit (release-only per repo policy)

* test(gateway): align start routing mocks
2026-07-18 08:26:45 +01:00
moguangyu5-design
6afba55b2a fix(cli): preserve platform-specific camera defaults and test RPC forwarding (#107942)
* fix(cli): preserve platform-specific camera defaults and test RPC forwarding

* test(cli): cover platform-specific camera help

Co-authored-by: moguangyu5-design <moguangyu5-design@users.noreply.github.com>

---------

Co-authored-by: moguangyu5-design <moguangyu5-design@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 08:24:52 +01:00
Peter Steinberger
13ae897cfb fix(cli): keep config schema stdout parseable (#110496) 2026-07-18 08:02:04 +01:00
Peter Steinberger
4186691885 feat(onboard): extend browser handoff and refresh recommendations (#110484)
* feat(onboard): enable browser handoff cross-platform

* feat(onboard): add recommendations refresh

* test(onboard): keep guided handoff coverage focused
2026-07-18 07:49:09 +01:00
xingzhou
75982be9a3 fix(cli): oversized secrets plans consume unbounded memory (#109652)
* fix(cli): reject oversized secrets plan files

* fix(cli): keep generated secrets plans applyable

* fix(cli): reject special plan files without blocking

* docs(cli): refresh secrets plan documentation map
2026-07-18 07:18:21 +01:00
dwc1997
0d822a3495 test(cli): add unit tests for CLI argument quoting helper (#98567)
* test(cli): add unit tests for CLI argument quoting helper

* ci: trigger re-review

* ci: trigger re-review

* ci: trigger re-review

* ci: retrigger

* fix: correct empty string assertion in quoteCliArg test

* ci: trigger re-review

* ci: trigger re-review

* test(cli): add shell metacharacter tests for quoteCliArg

* test(cli): expand argument quoting coverage

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 07:15:37 +01:00
Peter Lee
8539640abc fix(config,secrets): emit JSON errors and cover dotenv roots (#104340)
* fix(secrets): use resolveStateDir for .env path to cover legacy .clawdbot dir

* fix(secrets): replace override-based legacy .env test with true automatic fallback, add apply-path coverage

* fix(config-cli): emit JSON error on config get --json for missing paths

When  is used with a nonexistent
path, the command emits no JSON on stdout, only a text error on stderr.
This breaks automated consumers that expect machine-readable errors.

Fix: output  JSON to stdout before exit(1) when
opts.json is set. This matches the existing JSON error output pattern
already used by runConfigValidate and handleConfigMutationError.

Also re-throw synthetic exit errors in the catch block so the
--json branch's writeRuntimeJson+exit is not caught and re-emitted
as a text error.

* fix(config-cli): use typed ExitError signal instead of __exit__ string sentinel

* fix(secrets): reuse resolved stateDir for .env path in audit

* fix(secrets): pass resolved stateDir into apply .env scrubbing, add root-switch regression

* test(config-cli): migrate remaining __exit__ sentinel to ExitError

* fix(secrets): cover config and state dotenv roots

* style(secrets): format dotenv path helper

* test(secrets): track temporary directories

* test(config): expect typed exit for missing patch files

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-17 23:14:05 -07:00
Shakker
006d6556b8 refactor: expose selected plugin payload checks 2026-07-18 07:13:45 +01:00
Peter Steinberger
8992f92dab feat(gateway): idempotent start, non-interactive stop guard, unified lifecycle audit (#110323)
* feat: guard gateway lifecycle mutations

* fix: harden gateway lifecycle mutation guards

* fix: harden gateway lifecycle audit safety

* fix(cli): repair gateway lifecycle checks

* fix(cli): satisfy lifecycle CI gates
2026-07-18 07:01:38 +01:00
Peter Lee
cafa7606b7 fix(cli): show clean errors for missing input files (#105874)
* fix(cli): wrap readFileSync ENOENT with user-friendly messages and suppress cause leak

* fix(secrets): type missing plan errors

* style(secrets): format missing plan error branch

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 06:45:58 +01:00
Peter Steinberger
a89f01abf4 perf(sqlite): fast schema gates, background integrity verification, and downgrade protection (#110271)
* perf(sqlite): gate schema version before integrity scans and quarantine terminal open failures

* feat(gateway): refuse incompatible database schemas at boot and verify integrity in the background

* feat(update): refuse installing builds that cannot open the current databases

* docs: add database schema reference with version history and downgrade guidance

* test(update): tolerate optional runner options in git-mutation mocks

* refactor(update): split npm package-target metadata out of update-check

* chore: model verifier internals for knip and regenerate docs map

* chore(i18n): resync stale iOS localization catalog

* chore: allowlist read-only preflight and verifier raw SQLite access
2026-07-18 05:49:39 +01:00
Peter Steinberger
6e695c5e2c fix(cli): avoid macOS system CA exit hang (#110341)
Respawn one-shot macOS commands with Node's OpenSSL-backed CA store when system CA loading is inherited. This avoids an indefinite shutdown join on the Keychain loader worker while preserving system CA for Gateway, interactive, and explicit --use-system-ca processes.
2026-07-18 04:07:17 +01:00
Vito Cappello
cd1ab40632 fix: gateway boots when a configured plugin payload is broken (#110239)
* fix: quarantine broken plugins during gateway startup

* fix(plugins): preserve degraded boot on package read errors

* fix(gateway): emit quarantine diagnostic once

* fix(gateway): refresh plugin quarantine every boot

* fix(gateway): harden plugin payload quarantine

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ci): satisfy plugin quarantine checks

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 03:50:50 +01:00
Peter Steinberger
b440cfb15e fix(gateway): occupied non-gateway ports exit nonzero (#110310)
* fix(gateway): reject unrelated occupied ports

* docs(changelog): defer gateway collision note

* test(gateway): isolate unconfirmed lock collision
2026-07-18 03:23:52 +01:00
DaigoSoup
025cecf1f9 fix: avoid false macOS gateway restart failures (#109955)
* fix: wait through launchd KeepAlive restart throttling

* ci: retrigger checks

* test: make update restart test platform-independent

---------

Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-07-17 17:19:23 -07:00
xingzhou
c6d4559811 fix(mcp): doctor probes no longer start every server at once (#109870)
* fix(mcp): bound doctor server checks

* fix(mcp): defer doctor concurrency helper loading

* fix(mcp): preserve doctor check coverage

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 00:59:10 +01:00
Vito Cappello
748fc04419 fix(update): classify unreadable plugin manifests (#110200)
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-07-17 16:33:04 -07:00
Peter Steinberger
9a93a52a8a feat(onboard): recommendations store with once-semantics and self-naming bootstrap (#110173)
* feat(onboarding): persist app recommendations once

* feat(onboarding): add self-naming birth sequence

* chore(wizard): hoist bootstrap-defer imports to the top of the module

* docs(bootstrap): persist agreed identity into IDENTITY.md and SOUL.md as well

* docs: regenerate docs map after onboarding plan merge

* fix(wizard): reuse a pending stored offer instead of rescanning apps

* fix(onboard): deduplicate bootstrap recommendations
2026-07-17 23:42:01 +01:00
Peter Steinberger
282879b394 fix(cli): write --json payloads to stdout not stderr (#109808)
node identity, promos list, daemon restart, and tasks show emitted their --json result via runtime.log() (console.log), which --json mode redirects to stderr — leaving stdout empty and breaking pipes like `openclaw node identity --json | jq`. Use writeRuntimeJson to write the payload to stdout, matching health/tasks-list/capability. Human output unchanged.
2026-07-17 21:59:30 +01:00
Peter Steinberger
62f9c247ab fix(cli): config file resolves path without initializing state (#109811)
`config file` (print the active config path) called readConfigFileSnapshot(), eagerly creating the state dir + state/openclaw.sqlite — so a --profile typo minted a stray profile tree. Resolve the path via resolveConfigPath() instead; no state initialized.
2026-07-17 21:59:16 +01:00
Peter Steinberger
198e3b37b2 feat(onboard): browser-first guided handoff (#110054)
* feat(onboard): add browser-first guided handoff

* chore: drop release-only CHANGELOG edit from browser-handoff branch

* fix(onboard): make browser handoff reach the gateway on real installs

The presence probe connected as a raw shared-auth client with a possibly
SecretRef-managed token, which the gateway rejects as an unpaired Control UI
client ("device identity required"), so the handoff never fired and always
fell through to the terminal hatch. Read presence as a CLI-mode loopback client
(the trusted path every openclaw command uses) so operator.read is granted, and
share that one auth path between the reachability gate and the wait loop. Also
short-circuit when gateway.controlUi.enabled is false so onboarding does not open
a dead dashboard URL and block for the full timeout.

* fix(onboard): share resolved target between handoff gate and wait

The reachability preflight now resolves the same target (and shared secret) the
wait loop uses, and presents the configured secret to the CLI-mode presence
read. Known remaining limitation: on fresh quickstart gateways whose auth token
is written to config but resolved differently at runtime, the presence read is
rejected with a token mismatch and the handoff falls back to the terminal hatch.
Tracked for follow-up before enabling the browser handoff by default.

* docs(onboarding): mark phase 3 browser handoff as held with diagnosis

* docs(onboarding): phase 3 proven end-to-end; token-mismatch hold was a test artifact

* fix(onboard): satisfy docs-map and test-type gates for the handoff branch

* refactor(onboard): split guided manual stage
2026-07-17 18:57:57 +01:00
Peter Steinberger
5366b6de81 refactor: store gateway restart recovery in SQLite (#110014)
* refactor: move restart sentinel state to sqlite

* fix: satisfy restart sentinel architecture gates

* test: avoid cold startup migration timeout

* fix: bound durable restart notice retries

* test: type restart notice contention mock

* fix: detect legacy restart sentinel before reads

* fix: keep delivery attempt result internal

* fix: narrow restart sentinel preflight guard
2026-07-17 17:43:22 +01:00
Peter Steinberger
da69daeb72 feat(onboarding): recommend plugins and skills from installed apps (#109668)
* feat(onboarding): recommend plugins and skills from installed apps

Scan installed macOS apps during classic onboarding (TCC-free), gather
candidates from official catalogs + ClawHub search, let the configured
model pick genuine matches, and offer an opt-in multiselect install step.
Adds a device.apps node-host command (default-off sharing, Android-parity
envelope) so remote gateways can request a paired Mac's inventory, and a
wizard.appRecommendations kill switch. Custom setup-inference completions
no longer inherit the 32-token verification-probe output cap.

* feat(onboarding): recommend apps in guided flow

* fix(onboarding): harden app recommendations against ClawHub self-promotion

Third-party ClawHub skills are never pre-selected regardless of model tier
(publisher-controlled listing text reaches the matcher prompt and could
promote itself); their labels now say they install third-party code.
Installed-app scans follow symlinked .app bundles. Matcher output stays
bounded by the resolved model's own maxTokens budget (documented invariant).

* fix(onboarding): key official catalog candidates by resolved plugin id

Real catalog entries are package manifests without a top-level id; keying the
candidate map and channel/provider classification by entry.id collapsed the
whole official catalog into one undefined-keyed entry, so no official plugin
or channel was ever recommended. Regression test runs against the bundled
catalogs.

* fix(onboarding): satisfy lint, types, deadcode, and migration gates

Split the guided-onboarding test into a self-contained custodian suite to stay
under max-lines. Narrow app-recommendation exports (drop dead node-payload
normalizer, unexport internal types/helpers, route candidate tests through the
public API), replace map-spread with a helper, unexport device.apps result
types, add installedAppsSharing to node-host migration expectations, cast the
wizard multiselect mock, and regenerate the docs map.

* test(onboarding): register new live test in the shard classifier
2026-07-17 14:07:59 +01:00
Peter Steinberger
f3d1f02dc1 refactor: move MCP OAuth state to SQLite (#109844)
* refactor(mcp): move OAuth state to SQLite

* refactor(mcp): tighten OAuth module boundaries

* chore: refresh PR merge ref

* fix(mcp): align storage docs and merge checks

* fix(mcp): surface OAuth reauthorization status
2026-07-17 12:15:16 +01:00
Peter Steinberger
66aa2eda9d fix(cli): report malformed plugin JSON paths (#109916)
* fix(cli): report malformed plugin JSON paths

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

* test(google-meet): keep CLI test on plugin boundary

---------

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>
2026-07-17 11:53:23 +01:00
wuqxuan
d7056abbc8 fix(cli): reject missing separator after config path brackets (#109580)
* fix(cli): reject missing separator after config path brackets

* fix(cli): simplify bracket path separator validation

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 11:42:58 +01:00
krissding
af469c85cf fix(cli): guard secrets plan JSON.parse against malformed input (#109721)
* fix(cli): guard secrets plan JSON.parse against malformed input

readPlanFile reads a user-specified file and parses it with JSON.parse
without a try-catch. A malformed or corrupted plan file produces a raw
SyntaxError that is not user-actionable.

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

* test: tighten malformed secrets plan proof

Co-authored-by: 丁宇婷0668001435 <ding.yuting@xydigit.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-17 10:00:35 +01:00
Peter Steinberger
0097363c69 fix(secrets): keep gateway alive when web provider refs fail (#109687)
* fix(secrets): isolate unavailable web providers

* fix(secrets): keep web result type internal

* fix(secrets): hide unavailable web selections
2026-07-16 23:48:37 -07:00
Peter Steinberger
9b80f9a8b1 fix(cli): emit resolved config paths in machine output, not abbreviated home (#109361)
`config file`, `config patch --dry-run --json`, and `config unset --json` ran
the config path through shortenHomePath, emitting `~/…` or the literal
`$OPENCLAW_HOME/…` token in machine output — breaking `cat $(openclaw config
file)` and corrupting JSON path fields. `agents list --json` already resolves.
Emit the raw resolved snapshot path at these machine-output sites; human table
rendering keeps the friendly abbreviation.
2026-07-16 21:45:04 -07:00
ooiuuii
7641aa80c2 fix: plugins update rewrites config for install-record-only updates (#98422)
* Avoid config rewrites for plugin index updates

* Preserve config freshness for records-only plugin updates

* Validate records-only plugin update config

* fix(plugins): reload index-only updates

Co-authored-by: luyifan <al3060388206@gmail.com>

* chore(protocol): refresh generated clients

Co-authored-by: luyifan <al3060388206@gmail.com>

* fix(gateway): wire plugin refresh handler

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 21:38:45 -07:00
Erick Kinnee
135aa7a002 fix(config): improve validation error messages with line numbers, bracket paths, and received values (#106526)
* fix(config): improve validation error messages with line numbers, bracket paths, and received values

- Add JSON5-aware path navigator (issue-location.ts) that resolves line
  numbers and received values from raw config text without a full parser
- Add formatConfigIssuePath() for bracket notation (agents.list[3])
- Add appendReceivedValueHint() for safe value display (got: "none")
- Add attachConfigIssueDiagnostics() to enrich issues with location info
- Wire enrichment into runConfigValidate() and loadValidConfig() in config-cli.ts
- Add resolveIssueLocationPrefix() to issue-format.ts for sourceFile:line prefix
- Sensitive paths and secret refs are never leaked in received value hints
- Paths in 'd files gracefully degrade (no line number shown)

Closes #104854

* fix(config): type fixes from tsgo:core validation

- Add sourceFile to ConfigIssueFormatOptions (used in resolveIssueLocationPrefix)
- Fix readKey regex test for undefined raw[c.pos]

* fix(config): satisfy eslint(curly) and formatting for issue-location.ts

- Add braces to all single-line if/while/for statements
- Run oxfmt for consistent formatting

* fix(config): trim issue-location.ts to 500 lines for LOC ratchet

* fix(config): fix formatConfigIssuePath ternary bug from trimming

* fix(config): trim issue-location.ts to 469 lines for LOC ratchet

* fix(config): format issue-location.test.ts

* fix(config): document JSON5 subset and add 20 edge case tests

- Add explicit supported-subset documentation to issue-location.ts header
- Add 20 tests covering hex numbers, leading decimals, Infinity, NaN,
  null/bool, trailing commas, deep nesting, unicode escapes, multi-line
  strings, unicode keys, escaped quotes, numeric separators, block comments,
  mixed quotes, empty objects/arrays, and graceful degradation

* fix(config): address autoreview findings on JSON5 docs and tests

- Remove numeric separator claim (not valid JSON5)
- Remove 'None known' unsupported-syntax claim, document known limitations
- Restructure scalar tests to exercise skipVal (resolve sibling after exotic value)
- Remove numeric separator test

* fix(config): constrain received value diagnostics

* fix(config): preserve JSON5 diagnostic locations

* fix(config): preserve validation path ownership

* fix(config): redact dotted plugin paths

* test(config): avoid diagnostic fixture shadowing

* refactor(config): privatize diagnostic helpers

---------

Co-authored-by: Erick Kinnee <erick@ekinnee.dev>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 21:01:30 -07:00
OfflynAI
def7dd2401 fix(channels): restart gateway when channels.start fails for unloaded plugin (#90779)
* fix(channels): restart gateway when channels.start fails for unloaded plugin

After channels login, the CLI calls channels.start to reconcile the running
gateway. If the channel plugin was installed or enabled after the gateway
started, the plugin is not in the runtime registry and channels.start rejects
with 'invalid channels.start channel'. Detect this error and fall back to
gateway.restart.request so the gateway reloads plugins and starts the channel
automatically.

Fixes #90296

* ci: retrigger checks (update proof section format)

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: retrigger proof check (real behavior evidence)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(channels): narrow unloaded-plugin restart

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 20:21:06 -07:00