Commit Graph

81507 Commits

Author SHA1 Message Date
Peter Steinberger 877ab6b0b2 perf(gateway): bound health recent-session projection (#127744)
Amp-Thread-ID: https://ampcode.com/threads/T-01a02525-2a28-740a-b408-ee5382998a8c

Co-authored-by: Amp <amp@ampcode.com>
2026-08-21 19:04:24 -07:00
Peter Steinberger 62ccf026ca fix(config): match the config directory through symlinks when diagnosing permissions (#127734)
The permission diagnosis added in #127703 compared Node's reported errno
path against the configured directory as raw strings. Node reports the
canonical path, so a config directory reached through a symlink never
matched and the operator fell back to the raw EACCES the change existed to
replace. macOS /var -> /private/var makes this ordinary, not exotic.

Resolve the directory only when the raw comparison fails, so successful
config writes gain no syscall. The narrow path check stays: an unrelated
permission error from the caller's own mutation must keep propagating.
2026-08-21 18:57:18 -07:00
Peter Steinberger 557a5c131b fix(ui): validate empty protected secrets locally (#127740)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b

Co-authored-by: Amp <amp@ampcode.com>
2026-08-21 18:51:06 -07:00
Peter Steinberger 611b3f1753 fix(agents): preserve authoritative child completion results (#127739)
* fix(agents): preserve authoritative child completion results

* fix(agents): decouple child completion result types
2026-08-21 18:47:47 -07:00
Peter Steinberger f048a4370d fix: deliver current-source media before acknowledging (#127737) 2026-08-21 18:47:26 -07:00
Josh Avant 67c06ed54f fix(memory): respect provenance in automatic context (#127469)
* fix: enforce memory provenance for automatic context

* fix: preserve memory provenance compatibility

* fix: repair legacy memory provenance before recall

* fix: fail closed for unsupported memory runtimes

* fix: record command memory exclusions

* docs: clarify memory provenance injection

* docs(memory): clarify bootstrap without a runtime
2026-08-21 18:44:40 -07:00
Peter Steinberger c8b6ec5b33 refactor(browser): remove test route bypass (#127727) 2026-08-21 18:34:01 -07:00
Peter Steinberger 30a9470fca fix(telegram): preserve exact inline callback action values (#127735) 2026-08-21 18:29:03 -07:00
Peter Steinberger 6ced650a50 fix(cli): render models list JSON failures (#127726) 2026-08-21 18:25:51 -07:00
ClawSweeper 249e1bfb00 fix(ui): align narrow chat composer spacing (#127717)
* fix(ui): align narrow chat composer spacing

* test(ui): cover short-landscape composer spacing

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-21 18:20:41 -07:00
Dallin Romney fc5cb9e304 fix(ci): preserve current Kova gate failures (#126034) 2026-08-21 18:18:26 -07:00
Peter Steinberger a90800474d fix(cron): restore failure alerts after clock rollback (#127731) 2026-08-21 18:18:23 -07:00
Peter Steinberger 8b5a02cbf6 fix(mac): serialize persistent node service lifecycle operations (#127732) 2026-08-21 18:17:30 -07:00
Dallin Romney fc425351d6 fix(plugins): restore shipped channel compatibility (#126003)
* fix(plugins): restore shipped channel compatibility

* fix(plugins): align shipped compatibility guardrails

* style(plugins): align legacy setup formatting

* fix(plugins): gate channel compat removal on readers

* fix(channels): scope legacy allowlist updates

* chore(plugins): align rebased SDK budgets
2026-08-21 18:17:04 -07:00
Shakker b28a687830 fix: scope terminal cleanup by run (#127646) 2026-08-22 02:05:56 +01:00
Shakker 8ce4a8a07d fix: remount post-steer stream rows 2026-08-22 02:05:56 +01:00
Shakker 7f5ae9249f fix: preserve steering stream boundaries 2026-08-22 02:05:56 +01:00
Shakker df8898fe26 fix: settle terminal transcript projections 2026-08-22 02:05:55 +01:00
Peter Steinberger 0d29baae01 fix(cli): render status timeout JSON failures (#127721) 2026-08-21 18:04:25 -07:00
Peter Steinberger 992948356f fix(secrets): fail closed for configured references (#127669)
* fix(secrets): fail closed for configured references

Keep explicit SecretRefs authoritative across Gateway auth, onboarding, probes, channel credentials, outbound sends, and GitHub Copilot discovery/embeddings. Ambient credentials remain available only when no reference owns the surface.

* test(secrets): align gateway fallback expectations

* test(providers): remove load-sensitive stream timing

* test(xai): normalize stream capture failures

* fix(copilot): preserve direct auth precedence

* test(ollama): keep progressing streams alive

* test(models): mark resolved config fixtures

* fix(models): drop stale probe import
2026-08-21 18:00:28 -07:00
Peter Steinberger 51649aa1fa fix(mac): keep local gateway failures on their active route (#127723) 2026-08-21 17:59:35 -07:00
Peter Steinberger 14b85b2d82 fix(ui): keep usage results aligned with filters (#127720)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b

Co-authored-by: Amp <amp@ampcode.com>
2026-08-21 17:59:25 -07:00
Peter Steinberger 0382ca218a perf(telegram): reuse prepared rich message plan (#127719)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-21 17:56:22 -07:00
Peter Steinberger f6b42ea223 test: trim duplicate core assertions (#127708) 2026-08-21 17:47:23 -07:00
Peter Steinberger 9c85319792 fix(agents): stop recommending unavailable session tools (#127648)
* fix(agents): stop recommending unavailable session tools

* fix(agents): preserve authorized tool guidance placement

* fix(agents): keep spawn recovery guidance executable
2026-08-21 17:47:17 -07:00
Vito Cappello eee905934a fix(state): keep divergent retired device identity from blocking gateway readiness (#126748)
* fix(state): keep divergent retired device identity from blocking gateway readiness

Classify a divergent retired identity file as a startup notice when the canonical SQLite identity remains valid and authoritative under #120610. Preserve the fatal warning for missing or invalid canonical state, so the readiness gate itself remains unchanged.

Fixes #117270.

Release note: prevents gateway crash loops caused by a recreated retired device identity JSON after a verified SQLite migration.

* fix(state): preserve device identity migration receipt integrity

Reuse canonical SQLite identity validation and retain incomplete receipts for preserved divergent claims.

Co-authored-by: Vito Cappello <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-08-21 17:47:11 -07:00
Peter Steinberger 89bb601b91 fix(qa): replace Linux-only /proc probes in the Telegram proof harness (#127718)
The Mantis lane and the Telegram user driver reached for /proc to enforce
media containment and to prove a pid was still alive. Off Linux those paths
do not exist, so the containment check compared a literal "/proc/self/fd/N"
string against the output root and refused every file, while both liveness
probes silently reported "gone": the lane stole a held harness lock and the
driver deleted the observer pid file without ever signalling the process.

Containment now uses each runtime's strongest portable construct. Python
descends the media path one component at a time from an open directory
descriptor (O_DIRECTORY|O_NOFOLLOW, dir_fd), which is race-free and also
covers the intermediate directories the old leaf-only O_NOFOLLOW did not.
Node has no openat(2), so publicRelativePath re-walks the resolved
components after the descriptor is open and refuses any that became a
symlink. Liveness moves to process.kill(pid, 0) and to ps state/args, which
keeps the pid-reuse and zombie handling the /proc reads provided.

The compound-command approval binding test asserted an operand count that
only held where the host interpreters live in a root-owned prefix; a
Homebrew python3 is writable, so it correctly binds as a third executable
operand. Assert the script operands by path instead.
2026-08-21 17:45:12 -07:00
Peter Steinberger 0a704810e4 fix(onboard): preserve named-agent profiles during config resets (#127716) 2026-08-21 17:42:40 -07:00
Peter Steinberger 01cd0a48db fix(qa): retain failed isolated scenarios in fail-fast results (#127715) 2026-08-21 17:41:37 -07:00
Peter Steinberger 99e337190e fix(daemon): preserve the Gateway when stopping or restarting a Mac node (#127707)
* fix(daemon): skip gateway port-release assertion when stopping a node-host LaunchAgent

The generic LaunchAgent stop path (assertGatewayPortReleasedAfterStop)
resolves a gateway-relative port from the stopped service's own
program arguments/env and then asserts that port is no longer bound
after stop. `resolveNodeService()` reuses this exact same stop path
for the node-host service, but a node-host's "--port" argument is the
Gateway port it connects to *outward as a client* -- it never binds
that port itself.

On a host where the node-host and Gateway are co-located (a common,
documented topology), this made `openclaw node stop`/`restart` fail
with a false-positive "gateway port NNNN is still busy after
LaunchAgent stop" error, because the assertion was inadvertently
checking whether the co-located Gateway's own (legitimately still
open) port had been released -- something the node-host stop has no
business asserting.

Skip the port-release assertion entirely when OPENCLAW_SERVICE_KIND
indicates the node-host service, using the existing service-kind
env marker already used elsewhere in the daemon lifecycle code for
this exact gateway-vs-node distinction.

Fixes openclaw/openclaw#124296 (secondary bug: node stop/restart
false-positive port-collision guard when co-located with Gateway).

* fix(daemon): apply node-vs-gateway port guard exemption to LaunchAgent restart

The stop path (assertGatewayPortReleasedAfterStop in launchd-stop.ts) was
previously patched to skip the gateway-port-released check when
OPENCLAW_SERVICE_KIND is "node", but restartLaunchAgent in
launchd-lifecycle.ts had its own independent busy-port ownership guard
that was not touched, so `openclaw node restart` still failed for
co-located node-host + Gateway topologies.

Extract the OPENCLAW_SERVICE_KIND-based decision into a single shared
helper, shouldSkipGatewayPortOwnershipCheck (new module
launchd-node-gateway-guard.ts), and use it from both the stop and
restart guards so the two lifecycle paths can no longer diverge.

Add a regression test for co-located restart succeeding, mirroring the
existing stop regression test.

Refs openclaw/openclaw#124296

* test(daemon): add real-launchctl proof for co-located node/gateway port guard (#124296)

Adds an e2e integration test that drives real launchctl (no mocked
launchctl or port-inspection calls): a real "gateway" LaunchAgent that
genuinely binds a scratch TCP port, and a real "node-host" LaunchAgent
(OPENCLAW_SERVICE_KIND=node) targeting that same port. Verifies both
stopLaunchAgent and restartLaunchAgent succeed against the real busy
co-located port, and that the co-located Gateway LaunchAgent stays
running throughout.

Run against the pre-fix commit (2a7d735), this reproduces the exact
reported false-positive:

  Error: gateway port <port> is busy but is not verifiably owned by
  LaunchAgent ai.openclaw.launchd-int-node-<id>

Run against this branch, all 8 launchd integration tests pass.

* test(daemon): probe real port busy-ness before exercising node lifecycle

Addresses ClawSweeper P2 ask: the real-launchctl e2e proof only relied on
the LaunchAgent runtime status reporting 'running' for the gateway, which
doesn't guarantee the listener has actually bound the scratch TCP port yet
(status vs. socket bind can race). Add explicit probePortUsage() calls
(the same real, unmocked TCP probe used in production code) immediately
before both the stop and restart assertions, so the test proves the port
is genuinely busy at the moment the guard is exercised, not just inferred
from launchd state.

* refactor(daemon): resolve gateway ownership at launchd context boundary

Co-authored-by: Anis Khan <2815766+aniskhan001@users.noreply.github.com>

---------

Co-authored-by: Anis Khan <2815766+aniskhan001@users.noreply.github.com>
2026-08-21 17:38:44 -07:00
Peter Steinberger 980e67e2ae fix(sessions): retain assigned owners during doctor and startup repairs (#127706) 2026-08-21 17:33:49 -07:00
Peter Steinberger 7e84b2c722 fix(config): diagnose an unwritable config directory instead of leaking EACCES (#127703)
Every config write failed with a bare Node errno naming openclaw.json.lock
when the config directory was not writable. The lock file is an internal
artifact; the directory permissions are the actual problem, so operators
were sent to investigate the wrong thing.

withConfigMutationLock is the choke point for all config writes, so the
diagnosis lands there once and every writer benefits. Only EACCES, EPERM,
and EROFS whose reported path sits directly in the config directory are
relabelled; the caller's mutation runs inside the same scope, so an
unrelated permission error from its own work must keep propagating.
2026-08-21 17:32:51 -07:00
Peter Steinberger 0e8136b554 fix(macos): prevent duplicate New Chat sessions and stale navigation (#127693)
* fix(macos): fence new chat creation

* chore(i18n): refresh native source inventory
2026-08-21 17:31:58 -07:00
Peter Steinberger 12f72dac81 fix(gateway): fail streaming responses when agent runs fail (#127662)
* fix(gateway): fail streaming responses when agent runs fail

* test(gateway): preserve typed streaming failure fixtures
2026-08-21 17:28:01 -07:00
Peter Steinberger eaef2c1be7 fix(ui): re-arm Model Setup detection when stale route data settles after mount (#127695)
The Model Setup page could sit at "Checking this Gateway for available AI
access…" forever on fresh clients: the route loader ran before the Gateway
websocket connected and returned a loading state with a null-client
connection, the lazy page module finished importing after hello, and the
page mounted with routeData undefined under an already-connected Gateway.
When the stale loader result settled a microtask later, willUpdate
correctly discarded it, but synchronizeGateway hit the identity-equality
early return and nothing ever armed detectTask again - a silent dead-end
(fresh headless clients hit it ~100%; warm tabs recovered only because
their cached module mounted before hello).

Replace the mount-branch routeData-connection comparison with a single
self-healing invariant, ensureRouteSettledDetection(), also called from
the identity-equality early return: once route data has settled, a page
still holding phase "loading" with an idle detect task and a connected,
capable Gateway starts detection itself. Guards keep the normal path
duplicate-free: undefined routeData means the loader's own detect is
still in flight, and hasUpdated defers to willUpdate's seeding since
subscriptions fire before the first render.

Regression test mounts the page without routeData under a connected
Gateway, then delivers the stale pre-connect loader result and asserts
exactly one openclaw.setup.detect and a rendered result; it fails on the
pre-fix code with zero detect calls. Live-verified with a headless
Playwright client against a dev gateway: pre-fix stalls past 45s, fixed
build reaches ready in ~5s with a single detect request.
2026-08-21 17:26:37 -07:00
Peter Steinberger 5f6de37e20 fix(secrets): preserve authored env shorthand provenance (#127685)
* fix(secrets): preserve authored env shorthand provenance

Fixes #127684

* fix(gateway): keep provenance scope narrow

* fix(gateway): carry provenance through auth reads
2026-08-21 17:25:46 -07:00
Peter Steinberger 66c0a23a06 fix(onboard): stop printing two contradictory Fix lines for one failure (#127698)
Non-interactive onboarding's gateway-health failure emitted the generic
classification hint and the caller's phase-specific hint together, so the
first and most prominent Fix told operators to restart a managed gateway
while the next line said no daemon had been installed.

logNonInteractiveOnboardingFailure now suppresses the classification hint
when the caller already supplied one; the caller knows whether
--install-daemon was requested and the classifier does not. Callers that
pass no hints are unchanged.
2026-08-21 17:13:02 -07:00
Peter Steinberger 9acf1180a6 fix(talk): keep unused speech secrets from blocking startup (#127687)
* fix(talk): isolate selected speech secrets

* test(talk): use provider-scoped secret fixtures
2026-08-21 17:03:23 -07:00
Vincent Koc 7dfe406d20 perf(ci): parallelize installer smoke validation (#127138)
* fix(ci): parallelize installer smoke groups

* fix(ci): bind installer smoke artifacts

* fix(ci): isolate installer smoke candidate payload

* fix(ci): restore trusted install harness

* fix(ci): run Bun smoke from trusted harness
2026-08-21 17:02:11 -07:00
Peter Steinberger 89e38cfef9 fix(tui): stop local shell descendants on exit (#127652)
* fix(tui): own local shell process scopes

Keep local shell root results independent from authoritative process-scope
extinction, and make TUI shutdown cancel and join its ProcessSupervisor scope.
On Windows, create commands atomically inside a retained non-breakaway Job
Object and prove extinction from exact Job accounting.

Fixes #127488

* fix(process): preserve optional extinction waits
2026-08-21 17:01:09 -07:00
ClawSweeper 7c8e94804c fix(ui): align activity sessions across viewports (#127686)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-21 16:58:09 -07:00
Peter Steinberger 4e7bf407d1 test: remove redundant extension test seams (#127688) 2026-08-21 16:55:33 -07:00
Peter Steinberger b765944a9f fix(ui): explain blocked Talk microphone (#127673)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b

Co-authored-by: Amp <amp@ampcode.com>
2026-08-21 16:51:58 -07:00
Peter Steinberger 20b0ed4da3 refactor(telegram): remove obsolete action runtime override (#127683) 2026-08-21 16:44:51 -07:00
Peter Steinberger 7469b54272 fix(cli): render plugin search JSON failures (#127679) 2026-08-21 16:35:17 -07:00
Peter Steinberger 1d5d5cf462 perf(slack): reuse prepared payload without identity (#127678)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f5-984a-7628-a30c-491c166ff247

Co-authored-by: Amp <amp@ampcode.com>
2026-08-21 16:30:00 -07:00
Peter Steinberger 79c8251245 perf(onboarding): avoid broad provider-auth runtime imports (#127680) 2026-08-21 16:26:26 -07:00
ClawSweeper 7dca0a099a fix(ui): preserve owner filters across gateway reconnects (#127676)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-21 16:20:06 -07:00
Peter Steinberger fb95562e96 fix(ui): add brand icons for all provider auth choices (#127668)
The provider picker enumerates every plugin's providerAuthChoices (63
provider ids), but the bundled icon set only covered CodexBar's 52 marks,
so Arcee, Baseten, BytePlus, Cerebras, Cohere, DeepInfra, Featherless,
Fireworks, Hugging Face, Meta, NVIDIA, Together, and many more rendered
as lettered fallback badges.

Adds 24 monochrome marks from @lobehub/icons-static-svg v1.94.0 (MIT,
metadata-cleaned; mapping documented in ATTRIBUTION.md) and aliases
variant provider ids (kilocode, kimi-coding, xiaomi, ollama-cloud,
tencent-tokenhub, vercel-ai-gateway, ...) onto existing marks. GMI Cloud,
SGLang, and Vydra keep the lettered fallback: no vector mark exists
upstream.
2026-08-21 16:09:03 -07:00
Peter Steinberger ef447abdee fix(channels): degrade unavailable credential files (#127539)
* fix(channels): degrade unavailable credential files

* fix(msteams): gate unavailable credential actions
2026-08-21 16:08:45 -07:00