Commit Graph

72367 Commits

Author SHA1 Message Date
Peter Steinberger
eec2c0cc26 refactor(providers): unify lifecycle-safe manifest registration (#114381)
* refactor(providers): canonicalize manifest-driven registration

* fix(zai): eliminate type-only SDK import side effects
2026-07-27 03:20:02 -04:00
Peter Steinberger
65cce37480 fix(codex): keep user-home app-servers on native Codex auth (#114397)
A prepared OpenClaw auth handoff was still resolved for connections that
target the operator's native Codex home, so every turn failed with
"Prepared Codex auth requires an isolated app-server home." once a stored
OpenAI profile produced a prepared model route. User-home mode now keeps
its native account for both subscription and Platform routes, matching the
documented contract; the shared-client guard stays as the backstop.
2026-07-27 03:19:06 -04:00
Peter Steinberger
24e6d5edd7 fix(ui): recover offline-selected locales once the gateway reconnects (#114378)
* fix(ui): retry offline-failed locale loads when the gateway reconnects

* fix(ui): recover offline-failed locale loads via guarded stale-chunk reload

* test(ui): isolate locale retry tests from the i18n singleton cache

* test(ui): move locale manager test factory to test-support
2026-07-27 03:18:02 -04:00
Fede Kamelhar
cc027149e5 security fix(agents): close symlink-then-.. workspace boundary bypass in assertSandboxPath (#113405)
* fix(agents): close symlink-then-.. workspace boundary bypass in assertSandboxPath

resolveSandboxPath builds on path.resolve, which collapses ".." lexically
before any symlink is resolved. When a "<symlink>/.." sequence appears, the
lexical collapse lands on a harmless in-root path while the OS resolves the
same raw string (symlink first, then "..") to a location outside the
workspace, so assertSandboxPath approved inputs whose real resolution escaped
the boundary.

Add assertRawParentWithinRoot: it resolves the raw (non-collapsed) parent
chain via the OS realpath (fs.realpath.native; the JS realpath and
path.resolve both pre-collapse "..") and asserts it stays inside the
workspace root. It runs after assertNoPathAliasEscape so that guard's more
specific messages still win for cases it already catches, adding coverage only
for the residual gap it never sees.

Not currently reachable through shipped tools (read/write/edit route I/O
through fs-safe Root, which opens its own collapsed path; other callers use
the returned .resolved) -- this hardens the validator so the boundary no
longer depends on caller discipline. Regression test included.

* fix(agents): simplify raw sandbox path guard

* fix(agents): preserve symlinked sandbox roots

* fix(agents): validate raw final path aliases

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 03:15:59 -04:00
Peter Steinberger
3e4c57dbeb fix(onepassword): resolve secret refs under Bun by dropping execa buffer encoding (#114346) 2026-07-27 03:15:17 -04:00
Peter Steinberger
3a4f337802 fix(gateway): connect first-boot loopback agents after readiness (#114380)
* fix(gateway): pair local CLI before runtime-token readiness

* docs(gateway): explain first-boot loopback CLI auth

* fix(gateway): keep startup pairing result internal

* chore(gateway): leave release note to release process
2026-07-27 03:15:12 -04:00
Peter Steinberger
1fe66e0fe8 fix(ui): guard empty catalog refresh responses (#114394) 2026-07-27 03:09:25 -04:00
Peter Steinberger
7ad7cf8b0f refactor(sessions): unify canonical SQLite lifecycle and transcript projection (#114369)
* refactor(sessions): unify canonical SQLite lifecycle and transcript projection

* fix(sessions): ratchet eliminated transcript accessor debt
2026-07-27 02:59:08 -04:00
Peter Steinberger
b461ae6de8 test(model-catalog): cover normalization and routing boundaries (#114384) 2026-07-27 02:56:59 -04:00
Peter Steinberger
b34c19632f refactor(daemon): split Windows task scheduler integration (#113783)
* refactor(daemon): split Windows task scheduler integration

* refactor(daemon): keep split helpers private

* refactor(daemon): remove superseded schtasks script module
2026-07-27 02:55:23 -04:00
Pavan Kumar Gondhi
33f44caa5d fix: restrict QQBot quoted context [AI] (#114136)
* fix: restrict qqbot quoted context

* fix: narrow qqbot bot quote exemption

* test: use valid qqbot ingress reasons

* fix: honor narrowed qqbot open dm quotes

* fix: honor narrowed qqbot open group quotes

* test: use valid qqbot blocked ingress decisions

* fix: honor qqbot quote visibility mode

* docs: mention qqbot context visibility

* fix: validate qqbot context visibility config

* fix: hide denied qqbot quote sender

* test: avoid unbound qqbot access mock

* test: allow auth migration isolation to finish

* Revert "test: allow auth migration isolation to finish"

This reverts commit f2b9a4f5e9.
2026-07-27 12:23:21 +05:30
Peter Steinberger
9a0fa8f375 fix(ui): back off unavailable session PR polling (#114266)
* fix(ui): back off unavailable session PR polling

The sidebar PR indicators iterated worktree rows sequentially; each ~68ms
UNAVAILABLE reply immediately advanced to the next row, hammering
controlUi.sessionPullRequests at ~14 calls/second forever (the method is
advertised while its runtime dependency is down, so the advertised-method
gate never stopped it).

Route all callers through GatewayBrowserClient.requestSessionPullRequests:
a non-retryable UNAVAILABLE latches until the next socket hello; retryable
failures back off 30s doubling to 5min, honoring longer server retry hints.
A generation counter keeps concurrent rows from multiplying one outage wave.

* fix(ui): satisfy test-types and knip lanes

Type the PR-indicator request mocks with real signatures instead of bare
vi.fn shells, and keep GatewaySessionPullRequestsParams module-local until a
second consumer exists.

* test(ui): route hydration stubs through the PR latch wrapper

* chore(ui): drop unused ControlUiSessionPullRequests re-export

* test(ui): stub the PR latch wrapper in sidebar and clobber fixtures
2026-07-27 02:49:45 -04:00
Peter Steinberger
dda4883a4c fix(auto-reply): prevent duplicate rewritten-command replies (#114379)
* fix(auto-reply): dedupe settled block finals

* chore: leave release note to release flow
2026-07-27 02:49:23 -04:00
ClawSweeper
5b58d8540d fix(ui): new sessions remember valid workspace and model choices (#113884)
* fix(ui): remember new session selections

* fix(ui): repair stale new session folder preference

* fix(ui): clear node cwd when switching agents

* fix(ui): revalidate remembered model selections

* fix(ui): repair moved workspace preference

* fix(ui): anchor stale folder errno detection

* fix(ui): wait for remembered session choices

* fix(ui): satisfy new session preference contracts

* fix(ui): persist early folder for resolved agent

* fix(ui): anchor stale folder errno detection

* fix(ui): repair rejected workspace worktree preference

* test(ui): narrow new session request params

* fix(ui): keep an unusable remembered worktree from blocking submit

* test(ui): wait for the committed chat route before leaving it

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 02:47:09 -04:00
Pavan Kumar Gondhi
af7b0708aa fix: block unsafe workspace dotenv controls [AI] (#114133)
* fix: block unsafe workspace dotenv controls

* fix: narrow workspace dotenv control blocking

* fix: narrow dotenv token matching

* fix: scope dotenv access control keys

* fix: block bedrock bearer dotenv key

* fix: block bedrock credential dotenv keys

* test: split dotenv blocklist coverage

* fix: block aws sdk dotenv controls

* fix: block aws credential provider dotenv controls

* fix: block aws credential metadata dotenv controls
2026-07-27 12:15:31 +05:30
Peter Steinberger
a731397ea1 refactor: unify doctor repairs and configure setup (#114375) 2026-07-27 02:42:09 -04:00
Peter Steinberger
2242b968b3 fix(tui): prevent duplicate session rollover after stale terminal redraw (#114373)
* test(tui): make real session rollover deterministic

* test(tui): satisfy typed deferred lint
2026-07-27 02:40:43 -04:00
Peter Steinberger
3796a45911 fix(release): keep advisory summaries portable on macOS (#114371) 2026-07-27 02:38:11 -04:00
Peter Steinberger
0f68118176 fix(ci): run Testbox validation when draft PRs become ready (#114372) 2026-07-27 02:36:36 -04:00
Peter Steinberger
054495d16d fix(ci): verify stale bugs before closure (#114365) 2026-07-27 02:25:15 -04:00
Peter Steinberger
fee6db765d fix(openai): prevent onboarding from offering unavailable account models (#114356)
* fix(openai): keep account models and onboarding release proof authoritative

* fix(openai): document configured model catalog authority
2026-07-27 02:23:50 -04:00
Peter Steinberger
604f379203 perf: collapse board.get store reads (#114363) 2026-07-27 02:21:12 -04:00
Peter Steinberger
390f46d042 fix(agents): preserve fallback route provenance (#114360)
Co-authored-by: 1052326311 <65798732+1052326311@users.noreply.github.com>
2026-07-27 02:20:56 -04:00
Peter Steinberger
ab3e9645e7 fix(linux): recover corrupt gateway identity (#114359) 2026-07-27 02:17:08 -04:00
Peter Steinberger
2ce0362f12 perf(gateway): stabilize parallel channel status probes (#114362) 2026-07-27 02:15:56 -04:00
Peter Steinberger
8ad5139d7c refactor(tests): consolidate plugin update fixtures and version cases (#114344) 2026-07-27 02:15:49 -04:00
Peter Steinberger
7b71d5608e perf(gateway): reuse session catalog entry snapshots per request (#114358)
* perf(gateway): reuse session catalog entry snapshots

* chore(gateway): satisfy knip and typed-test lanes for catalog snapshot
2026-07-27 02:14:11 -04:00
Peter Steinberger
2714c60297 refactor: consolidate auto-reply routing regression tests (#114345) 2026-07-27 02:12:13 -04:00
Peter Lee
0406e66369 fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp (#113266)
* fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp

* fix(ui): keep live rows within current turn

* fix(ui): keep current work above queued turns

* fix(ui): keep streamed replies above queued turns

* fix(ui): preserve reconnecting run order

* fix(ui): preserve causal terminal ordering

* fix(ui): bound replay rows to owning turns

* fix(ui): keep question summaries in owning turns

* fix(ui): scope question run ownership to session

* fix(ui): restore reconnecting chat run identity

* fix(ui): remove unused chatItemTimestamp import in chat-thread-build.ts

* fix(ui): correlate question summaries with agent runs

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

* chore(i18n): refresh native source baseline

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

* fix(ui): remove unused chatItemTimestamp export and split tool-stream test file

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 02:08:22 -04:00
Peter Steinberger
be50034bbe refactor(agents): consolidate subscription handler event tests (#114339) 2026-07-27 02:07:53 -04:00
Dallin Romney
ffec7731a4 fix: report unavailable system Node versions accurately (#114325) 2026-07-27 14:06:27 +08:00
Dallin Romney
9310586b09 fix(qa-lab): unify runner control plane (#112838) 2026-07-27 14:05:14 +08:00
Peter Steinberger
aa9eecab1f refactor(config): consolidate configuration write regression fixtures (#114347) 2026-07-27 02:04:34 -04:00
Peter Steinberger
564ba951a7 refactor(ui): consolidate chat lifecycle regression tests (#114335) 2026-07-27 01:59:43 -04:00
Erick Kinnee
0b1ef9017b fix(sessions): gateway becomes unusable when there are many sessions (#113959)
* fix(sessions): add SQLite session entry cache with current-schema support

Rebase PR #113959 cache changes onto current origin/main:
- Replace listSqliteSessionEntries with cached version using
  session_nodes table (was session_entries)
- Add connection-identity token for data_version cross-connection safety
- Add light listing variant with LIMIT/OFFSET pagination
- Add file-stat + data_version coherence guards
- Add cache invalidation on all mutation paths
- Add SessionEntryListScope type with light/limit/offset fields
- Restore store-cache.ts (deleted upstream, re-added with cache layer)

* perf(sessions): project lightweight gateway lists

Replace the request-time session cache and freshness probes with an explicit SQL-side list projection. Keep full entry reads as the default, preserve the post-await sharing authorization refresh, and carry the projection through Gateway, TUI, and embedded-tool list paths.

Co-authored-by: Erick Kinnee <1707617+ekinnee@users.noreply.github.com>

Co-authored-by: gucasbrg <buruguo2000@163.com>

* test(tui): expect lightweight session projection

---------

Co-authored-by: Erick Kinnee <ekinnee@gmail.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: gucasbrg <buruguo2000@163.com>
2026-07-27 01:58:14 -04:00
Peter Steinberger
0642072b70 test(providers): consolidate catalog and realtime contract cases (#114352) 2026-07-27 01:55:20 -04:00
Peter Steinberger
007ed6d8af refactor(cli): consolidate capability and command regression suites (#114349) 2026-07-27 01:51:16 -04:00
Vlad Gaevsky
36f5e61f4e fix(mcp): reconnect a bundled MCP server instead of wedging on it (#113916)
* fix(mcp): reconnect a bundled MCP server instead of wedging on it

A bundled MCP server that dies or stops responding never comes back. Two gaps:

1. `client.onclose` flips `connected`/`disconnectReason` and stops there. The
   dead session stays in `sessions` and the memoized `catalog` stays valid, so
   every later request is a `getCatalog()` cache hit followed by
   `requireConnectedSession` throwing `is disconnected` — indefinitely. The
   reconnect path already exists (the catalog builder retires a disconnected
   session and rebuilds it); it just never runs, because nothing invalidates the
   catalog on close. This mirrors what `listChanged.onChanged` already does.

2. At `BUNDLE_MCP_FAILURE_THRESHOLD`, `recordServerToolFailure` sets
   `retryAfterMs`. That delays the next attempt against the same broken
   transport rather than repairing it, so a server that hangs stays hung.

Recovery therefore depended entirely on idle eviction
(`mcp.sessionIdleTtlMs`), a `configFingerprint` change, or a restart — which
makes the eviction timer a de facto health mechanism and couples "how fast a
broken server recovers" to "how long an idle one is kept". Raising the TTL for
warm-start latency silently makes outages last longer.

Both fixes are narrowed to avoid over-reacting:

- onclose only invalidates for a connection that was ESTABLISHED and lost. A
  transport closing mid-connect is the startup-failure path the catalog builder
  already owns; invalidating there discards the in-flight build on a generation
  mismatch and spins up a respawn loop.
- recycling requires the server to have stopped RESPONDING
  (`ErrorCode.RequestTimeout`, or a session no longer connected). A server
  answering with JSON-RPC errors is healthy and reachable — tearing down its
  transport because a tool got bad arguments would be worse than the bug. The
  existing cooldown still covers that case, as its tests require.
  `serverBackoff.delete` on recycle is deliberate: the replacement must not
  inherit the dead transport's failure count.

Two tests encoded the old behavior and now assert recovery instead, including
that the replacement child has a different pid. The recovery assertion polls: a
request already in flight when the transport closes still fails, and should.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(mcp): recover disconnected bundled servers

Co-authored-by: Vlad Gaevsky <kelstar95@gmail.com>

* test(mcp): tighten recovery validation

Co-authored-by: Vlad Gaevsky <kelstar95@gmail.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 01:48:29 -04:00
Peter Steinberger
256988e068 refactor(ui): consolidate workboard regression fixtures (#114348)
* refactor(ui): consolidate workboard regression fixtures

* test(ui): preserve nullable workboard refresh fixture
2026-07-27 01:48:05 -04:00
Peter Steinberger
927aad98d7 fix(linux): surface manual update results (#114341) 2026-07-27 01:47:37 -04:00
Peter Steinberger
6e2d4cbee0 refactor(cli): consolidate regression test fixtures (#114334) 2026-07-27 01:45:02 -04:00
Peter Steinberger
b5137604ef feat(cron): default agent turns to the current conversation, add /loop, tighten cron tool surface (#114328)
* feat(cron): bind agent turns to current sessions

* feat(commands): add loop chat command

* test(cron): cover session defaults and loop commands

* docs(cron): document current defaults and loops

* fix(commands): scope /loop status and stop by conversation name tag

* fix(commands): widen /loop conversation tag to 48 bits

* fix(commands): include disabled jobs in /loop status and stop

* docs(cron): regenerate docs map

* test(cron): split session-target default tests to satisfy max-lines
2026-07-27 01:44:38 -04:00
Peter Steinberger
e154330a42 perf(ui): parallelize session-switch hydration (#114338)
* perf(ui): parallelize session switch hydration

* test(ui): cover reconnect session hydration

* test(ui): give hydration request mocks real signatures
2026-07-27 01:43:47 -04:00
Peter Steinberger
30ba6bc9de refactor(tests): consolidate plugin planning and provider stream coverage (#114333)
* refactor(tests): consolidate plugin planning and provider stream coverage

* test: keep plugin planning fixtures lint-clean
2026-07-27 01:40:36 -04:00
Peter Steinberger
736a788cb8 build(ui): let control-ui baseline updates take CI-measured bytes (#114340) 2026-07-27 01:39:19 -04:00
Peter Steinberger
8e4b6623e5 test(providers): consolidate streaming and model contract cases (#114336) 2026-07-27 01:36:32 -04:00
Peter Steinberger
d3e043751a refactor(gateway): consolidate chat send and abort regression tests (#114337) 2026-07-27 01:33:41 -04:00
Peter Steinberger
e78310fc23 fix(ui): validate session catalog agent (#114303) 2026-07-27 01:33:08 -04:00
Peter Steinberger
fa28e9be8d fix(plugins): find installed external web-search providers on fresh installs (#114327)
* fix(plugins): stop treating a partial active registry as authoritative for web providers

An active plugin registry with some web providers used to win even when a
manifest-declared candidate (e.g. an npm-installed Brave plugin with
BRAVE_API_KEY set) was absent from it, so env-var auto-detect could never see
installed external search providers. Delegate to the coverage-checked
resolvePluginWebProviders path, which reuses the active registry only when it
covers every declared candidate.

* feat(agents): require explicit overwrite before replacing pre-existing files in the write tool

Blind writes to an existing path silently destroyed user content (observed as
WildClawBench safety-task data loss with weaker models). The write tool now
refuses to replace an existing differing file unless the call passes
overwrite:true or this tool instance already wrote that path, keeping
iterate-loops friction-free while making destructive replacement an explicit
model decision.

* docs(templates): make a concrete first-message task outrank the BOOTSTRAP.md birth sequence

A fresh workspace's birth ritual hijacked substantive first messages: agents
introduced themselves and asked for a name instead of doing the requested
work (worst with weaker models, which follow the ritual literally). State
task precedence explicitly at the top of the template.

* fix(agents): lead the write overwrite guard error with the safe protocol

Weak models retried immediately with overwrite:true when the flag came first
in the message. Order the guidance read -> rename -> overwrite-as-last-resort
so the destructive path requires an explicit judgment call.

* refactor(agents): replace the write overwrite flag with a confirm-by-resend gate

The overwrite:true escape hatch let weak models bulldoze reflexively and grew
the tool schema. The first write to a differing pre-existing file now returns
that file's content (head-clipped) and a resend of the identical write, issued
after the warning, against byte-identical existing content confirms the
replacement. Fingerprints hash raw bytes; oversized files fall back to
size+mtime (named tradeoff); missing metadata fails closed.

* revert(agents): restore plain overwrite semantics in the write tool

The overwrite gate (flag, then confirm-by-resend) was overfit to one
WildClawBench safety rubric: the guarded model still chose to overwrite and
still scored zero, while every real overwrite in normal sessions paid a
round-trip. Write means write; peers (Pi, Hermes) agree.

* test(agents): drop the stale overwrite arg from the write output-contract test
2026-07-27 01:32:04 -04:00
Peter Steinberger
4bc1fd314b refactor(config): consolidate write preparation regression tests (#114332) 2026-07-27 01:31:18 -04:00