Commit Graph

70272 Commits

Author SHA1 Message Date
Peter Steinberger
52d49a69b2 fix(plugin-sdk): refresh config schema API baseline (#110614) 2026-07-18 11:14:41 +01:00
mushuiyu886
42e6972d35 fix(opencode): Zen GPT-5.6 models are missing from discovery (#110405)
* fix(opencode): add Zen GPT-5.6 models

* test(opencode): narrow GPT-5.6 policy fixture

* fix(opencode): align GPT-5.6 thinking levels

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 11:14:05 +01:00
mushuiyu886
04d7462806 fix(plugin-sdk): attached send results report the configured channel (#110069)
* fix(plugin-sdk): keep attached channel authoritative

* refactor(plugin-sdk): simplify channel attachment

Co-authored-by: 杨浩宇0668001029 <yang.haoyu@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 11:10:39 +01:00
snowzlmbot
21bd5a49c3 fix(chat): preserve explicit current-source sends in Control UI history (#106073)
* fix(gateway): retain explicit source replies in history

Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>

* test(infra): update source reply mirror mock

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com>
2026-07-18 11:09:33 +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 Steinberger
bf20509c46 fix: prevent TUI PTY tests from aborting after completion (#110610)
* test(tui): await PTY teardown before worker exit

* test(tui): avoid unbound PTY mock assertion
2026-07-18 11:06:32 +01:00
Peter Steinberger
b3650b7012 fix(tui): exit reliably after quit (#110595) 2026-07-18 11:05:09 +01:00
Peter Steinberger
8c95ec95ca fix(ui): show sidebar connection state only on sustained disconnect (#110567) 2026-07-18 11:02:38 +01:00
Peter Steinberger
7a7c158210 perf(ci): parallelize gateway watch artifact check (#110609) 2026-07-18 11:01:08 +01:00
Peter Steinberger
e7fe47d63f fix(browser): allow one retry after transient failures (#110607)
* fix(browser): soften transient retry guidance

* style(browser): format retry hint test

* chore: keep release note in PR body
2026-07-18 10:58:22 +01:00
Peter Steinberger
a068d38b66 refactor(plugins)!: remove experimental workspaces plugin (#110416)
* refactor(plugins)!: remove experimental workspaces plugin

* fix(doctor): remove retired workspaces plugin state

* refactor(doctor): settle retired-workspaces cleanup before legacy-state detect

* chore(i18n): leave workflow-owned locale artifacts to the locale refresh

* ci: retrigger after GitHub scheduling outage
2026-07-18 10:56:37 +01:00
zengLingbiao
fcdf06ed29 fix(config): ignore inherited keys when restoring env refs (#109463)
* fix(config): use Object.hasOwn in restoreEnvVarRefs to avoid prototype pollution

When key comes from Object.entries(incoming) on user config data,
'key in parsed' traverses the prototype chain. If a config key
collides with an Object.prototype property (e.g. 'toString'),
the check incorrectly returns true and calls restoreEnvVarRefs
with a prototype function instead of a config value.

Replace with Object.hasOwn(parsed, key) to check only own properties.

* test(config): prove inherited env refs are ignored

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 10:49:53 +01:00
Peter Steinberger
7752e33f79 Revert "fix(security): restore fs import lost in bounded manifest-read merge"
This reverts commit 39528edd74.

That push was an accident: the fs-import fix it described had already landed
on main, and a rebase reduced the commit to unrelated in-progress
gateway-protocol schema edits (nodes/session-placement) that were staged in
the pushing worktree and belong to another work stream. Restore the reviewed
main state; the protocol work can land through its own PR.
2026-07-18 02:45:59 -07:00
tzy-17
a941d3ab72 fix(shared): reject HTTP status codes outside the 100-599 range (#110554)
* fix(shared): reject HTTP status codes outside the 100-599 range

extractHttpStatusMatch only checked Number.isFinite, so 3-digit
sequences such as "000", "099", "600", and "999" were accepted as
valid HTTP statuses. Downstream code then surfaced them as "HTTP 0"
in user-visible messages and fed them into retry/classification
branches (e.g. isCloudflareOrHtmlErrorPage checks `code < 500` and
`code < 600`). Restrict the extracted code to the IANA HTTP status
code range (100-599).

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>

* fix(shared): validate all parsed HTTP status prefixes

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:44:31 +01:00
Peter Steinberger
95d632e644 fix(security): bound skill-file audit read via safe reader (restore removed fs dependency) (#110589) 2026-07-18 10:44:01 +01:00
chengzhichao-xydt
fceae4d8aa fix(ui): bound managed outgoing image fetches (#108116)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: chengzhichao-xydt <chengzhichao-xydt@users.noreply.github.com>
2026-07-18 10:42:19 +01:00
Peter Lee
2b04c350a3 fix(config): restore process.env after invalid config rejection (#103786)
* fix(config): restore process.env after invalid config rejection

When config validation fails, env vars from the rejected config
(env.vars in openclaw.json) leaked into process.env and were never
cleaned up. In long-running gateways this meant rejected config
values could persist until process restart.

Add restoreEnvChangesIfUnchanged calls in both sync (loadConfigLocal)
and async (readConfigFileSnapshotInternal) validation-failure paths,
matching the pattern already used by suspicious-config recovery paths.

* fix(config): restore env before observer and on duplicate-agent-dir rejection

- Add restoreEnvChangesIfUnchanged before DuplicateAgentDirError throw
  in the sync loadConfigLocal path so env vars from rejected config
  do not leak when duplicate agent directories are detected.
- Move restoreEnvChangesIfUnchanged before observeLoadConfigSnapshot
  in the sync validation-failure path so config health/audit
  observation does not see rejected env values.
- Add entry-point regression tests exercising sync loadConfig,
  async readConfigFileSnapshot, and duplicate-agent-dir rejection
  paths through createConfigIO with real config files.

* fix(config): restore env after invalid snapshot

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

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:41:44 +01:00
xingzhou
1af6d99658 fix: surface cron errors for empty isolated agent replies (#100229)
* fix(cron): fail empty isolated agent completions

* fix: surface cron errors for empty isolated agent replies

* fix(cron): preserve intentional terminal progress

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 10:41:31 +01:00
tzy-17
b34d0a8bb6 fix(gateway): bound usage.list days parameter to 100 years (#110552)
* fix(gateway): bound usage.list days parameter to 100 years

parseDays accepted any finite number including 1e300, which downstream
resolveTrailingDays would feed into Date arithmetic as a day offset,
overflowing the ECMAScript Date range and surfacing as a misleading
"calendar day does not exist in requested time zone" error. Reject
day counts above 100 years (36600); callers wanting truly unbounded
history should use `range: "all"`.

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>

* fix(gateway): clamp oversized usage day ranges

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:40:05 +01:00
Peter Steinberger
39528edd74 fix(security): restore fs import lost in bounded manifest-read merge
#101773 removed the node:fs/promises import while switching plugin manifest
reads to fs-safe helpers, but getSkillCodeSafetySummary (added later by
#109363) still reads SKILL.md via fs.readFile. Main has been red since the
merge (check-prod-types, check-lint, check-test-types, package-boundary
compile, compact-large-5). Restore the import; skill-file reads keep their
pre-existing unbounded contract.
2026-07-18 02:38:23 -07:00
thomas.szbay
e721508ed3 fix(ui): bound chat avatar fetches (#110010)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 10:38:12 +01:00
Peter Steinberger
f14947d256 fix(codex): persist automatic compaction history (#110587)
* fix(codex): persist automatic compaction counts

* test(codex): stress compaction and restart recovery

* test(codex): bind compaction waves to fresh counts

* chore: keep Codex release note in PR
2026-07-18 10:37:25 +01:00
xingzhou
609e5d2318 fix(gateway): session workspace reveal hangs on foreground opener (#110277)
* fix(gateway): bound session workspace reveal opener

* refactor(gateway): share bounded path opener lifecycle

---------

Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 10:36:35 +01:00
cxbAsDev
35754a63cc fix(plugins): bound marketplace manifest file reads (#101774)
* fix(plugins): bound marketplace manifest file reads

* fix(plugins): distinguish oversized marketplace manifest from other read failures

* fix(plugins): follow symlinked marketplace manifests while bounding reads

* test(plugins): cover oversized symlinked marketplace manifest target
2026-07-18 10:34:00 +01:00
Peter Steinberger
75b1ac12df feat(onboarding): enable lean mode for local models (#110596) 2026-07-18 10:31:58 +01:00
Peter Steinberger
5057fd9e59 fix: keep native question cards out of the public API (#110534)
* 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

* fix: narrow shared question card visibility

* test: update macOS question scope expectations
2026-07-18 10:27:32 +01:00
Peter Steinberger
4b74a7233f test(apple): remove model patch timing flake 2026-07-18 10:26:31 +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 Steinberger
0234cf5f7f fix(security): restore fs import dropped by bounded manifest-read change (#110585)
aa0c92186b (#101773) removed the file-wide node:fs/promises import
while converting the plugin-manifest read to fs-safe helpers, but
getSkillCodeSafetySummary still calls fs.readFile for skill content.
Every main push since fails check-prod-types/lint/test-types and the
security shard (TS2304 + runtime ReferenceError). Restore the import;
migrating the skill read to bounded fs-safe helpers is the PR author's
follow-up.
2026-07-18 10:22:50 +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
tzy-17
f0312bc979 fix(gateway): trim whitespace in audit.list cursor parsing (#110551)
parseAuditCursor in audit.ts did not trim whitespace before running the
digit regex, while the parallel parseCursor in tasks.ts did. A client
passing "  11  " (e.g. URL-decoded from query strings) would get a 400
INVALID_REQUEST instead of the correct page. Trim the cursor before
validation so behavior matches tasks.list and the gateway cursor contract.

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-07-18 10:17:57 +01:00
Peter Steinberger
e1d87e9a9d fix(sessions): preserve parent lifecycle for parallel children (#110541)
* fix(sessions): declare parent lifecycle disposition

Co-authored-by: Luiz Antonio Busnello <lab@generantis.com.br>

* chore: keep release notes in PR body

* fix(sessions): preserve parallel fallback on old gateways

* chore(i18n): refresh native source inventory

---------

Co-authored-by: Luiz Antonio Busnello <lab@generantis.com.br>
2026-07-18 10:16:14 +01:00
Peter Steinberger
08b80224ea feat(ui): logo-scare lobster visits; drop the model-auth-expiring chip (#110466)
* feat(ui): drop the model-auth-expiring sidebar chip

The warning-severity expiring chip nagged for OAuth tokens that roll
continuously; the error-severity expired chip stays and still surfaces
actually broken auth.

* feat(ui): let ledge visits sometimes scare the sidebar logo away

Some idle lobster visits now spook the brand mark: a beat after the crab
settles in, the logo fades out (no stand-in), and it pops back when the
visit ends. Seeded 30% roll per arrival; perch visits, offline summons,
and reduced-motion users are exempt.
2026-07-18 10:12:50 +01:00
cxbAsDev
1e2d0e29b0 refactor(gateway): adopt closedObject in recently added schema files (#106532)
* refactor(gateway): adopt closedObject in recently added schema files

* test(gateway): prove recently closed node and dispatch schemas reject extra fields
2026-07-18 10:12:18 +01:00
cxbAsDev
993c975f57 fix(heartbeat): bound HEARTBEAT.md file read size (#101775)
* fix(heartbeat): bound HEARTBEAT.md file read size

* fix(heartbeat): follow symlinked HEARTBEAT.md while bounding reads

* fix(heartbeat): warn operators when oversized HEARTBEAT.md is skipped
2026-07-18 10:06:31 +01:00
cxbAsDev
94e1cc9a4e fix(daemon): distinguish shared and embedded SQLite in system Node warning (#107990) 2026-07-18 10:02:28 +01:00
Peter Steinberger
222dc58011 feat(linux): native gateway transport for Quick Chat — device identity, TLS pinning, ack-driven sends (#110491)
* feat(gateway): add Linux native auth surface

* feat(linux): persist Gateway device identity

* feat(linux): add native Gateway WebSocket client

* feat(linux): route Quick Chat through Gateway

* feat(cli): expose dashboard transport handoff

* docs(linux): document native Quick Chat transport

* test(linux): placeholder-shaped fixture token in device-auth payload test

* test: placeholder-shaped credential fixtures; reshape device-token rebind

* test: keep auth-method enums verbatim; rename only credential fixtures

* test(gateway): move Linux native admission coverage to a dedicated test file

* style: replace scanner-evasion literals with honest shapes; shared trim helper for auth material

* style(cli): join-built computed keys instead of literal concatenation

* chore: drop release-owned CHANGELOG edit from feature branch
2026-07-18 09:59:10 +01:00
cxbAsDev
aa0c92186b fix(security): bound plugin manifest reads in audit deep scan (#101773) 2026-07-18 09:55:31 +01:00
Peter Steinberger
654560f289 feat(ui): add Apps & extensions page to the Control UI (#110563)
* feat(ui): add Apps & extensions page

* feat(ui): add per-theme app-art card illustrations

* docs: describe the Apps and extensions page in control-ui

* fix(ui): keep icons.ts under max-lines, drop unused export, regen docs map
2026-07-18 09:52:34 +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
Peter Steinberger
d55c91c918 test: add subagent handoff failure diagnostics
Related: #110572
2026-07-18 09:50:33 +01:00
xingzhou
91ded68990 fix(vault): SecretRef resolution no longer hangs on stalled response bodies (#108970)
* fix(vault): keep request deadline through response body

* test(vault): use generic stalled-body fixture

* test(vault): mark fixture token synthetic

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-18 09:46:50 +01:00
Peter Steinberger
ab093bded4 docs(onboarding): finalize phase status and phase 7 decision (#110543)
* docs(onboarding): final phase status and phase 7 decision

* docs(onboarding): remove shipped refresh follow-up

* docs(onboarding): remove shipped browser follow-up
2026-07-18 09:44:20 +01:00
Alix-007
deccdb5e57 fix(ui): bound browser gateway WebSocket opening (#109037)
* fix(ui): bound browser gateway socket opening

* fix(ui): use browser-safe timeout export
2026-07-18 09:38:37 +01:00
Alix-007
bc77ef3398 fix(browser): time out relay WebSocket opening (#109114)
* fix(browser): time out relay WebSocket opening

* test(browser): resolve worker import at runtime

* test(browser): refresh relay worker mocks

Co-authored-by: Alix-007 <li.long15@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-18 09:36:46 +01:00
Alix-007
cc7bd4d95a fix(qa-lab): bound Node binary lookup (#109428) 2026-07-18 09:35:16 +01:00
Peter Steinberger
764999c755 refactor(exec): remove duplicate task session detail (#110566) 2026-07-18 09:35:14 +01:00
Peter Steinberger
bbb45cde9d fix(scripts): keep hosted-gate run queries under the gh relay response cap (#110540) 2026-07-18 09:34:50 +01:00
Alix-007
78b4a4afed fix(qa-lab): bound WhatsApp auth archive extraction (#109501) 2026-07-18 09:33:38 +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