Commit Graph

4301 Commits

Author SHA1 Message Date
Peter Steinberger 41069d9747 fix(skills): reject an unknown --agent instead of inventing one (#126954)
`openclaw skills check --agent nope-agent` exited 0 and printed a full report
headed "Agent: nope-agent" with 53 skills / 44 eligible, while the install's only
real agent reported 57 / 48. It did not fall back to the default -- it fabricated
an agent and produced confident, different numbers for it. `skills list` behaved
the same way.

Every sibling --agent surface already rejects an unknown id: `models auth list`,
`models list`, `models status`, `memory status`, and `sessions list` all exit 1
with "Unknown agent id". Skills was the only holdout, and the canonical helper
for it already exists -- `resolveConfiguredAgentId`, added for this exact class
when `memory --agent` had the same hole.

`resolveSkillsWorkspace` took the explicit --agent value verbatim while both the
workspace-inferred and default paths were validated. Route the explicit value
through `resolveConfiguredAgentId` so the message and behavior match the
siblings, including the profile-aware hint, and reject a blank --agent the way
memory does. Workspace inference and default resolution are unchanged.

Production +9 LOC.
2026-08-20 19:54:24 -07:00
Peter Steinberger da8196c40b fix(onboard): keep gateway credentials out of plaintext in ref mode (#126928)
* fix(onboard): keep gateway credentials out of plaintext in ref mode

* test(onboard): preserve credential table tuple types
2026-08-20 18:48:11 -07:00
Peter Steinberger afb430d10f fix(cli): render sandbox JSON failures (#126915) 2026-08-20 17:56:20 -07:00
Peter Steinberger a73166b49d fix(cli): render QR JSON failures (#126884) 2026-08-20 17:02:59 -07:00
Peter Steinberger 21bab3a8ac fix(gateway): honor local port for usage and stability queries (#126832) 2026-08-20 13:51:36 -07:00
Peter Steinberger a2051c9bb2 fix(onboard): support password-authenticated remote gateways (#126768)
* fix(onboard): support password-authenticated remote gateways

* fix(onboard): parse remote password without type assertions
2026-08-20 11:02:25 -07:00
Peter Steinberger cbe070071a perf(test): trigger restart probe timeout deterministically (#126664) 2026-08-20 05:42:43 -07:00
Peter Steinberger a59abcf4a8 fix(gateway): preserve restart health errors (#126645) 2026-08-20 04:29:02 -07:00
Peter Steinberger 015913306f fix(nodes): preserve node inventory failures (#126609) 2026-08-20 02:06:09 -07:00
Koduri Mahesh Bhushan Chowdary bb134fef12 fix(cli): clarify cron channel plugin ids (#124655)
Keep cron delivery help and automation docs explicit that --channel selects a channel plugin, not a per-conversation channel identifier.

Fixes #124646

Punchcard-Session: clear-timber-orchard-n1
2026-08-20 01:45:01 -07:00
Peter Steinberger 10e707435a fix(mcp): repair channel lifecycle ownership (#126592)
Restore persisted channel media, cancellation cleanup, retryable permission delivery, bounded-event gap recovery, complete shutdown, and actionable Gateway startup diagnostics.
2026-08-20 01:14:43 -07:00
Peter Steinberger 980b07f4a2 refactor(agents): replace tool-failure warning heuristics with a two-rule policy (#126542)
* refactor(agents): reduce tool failure warnings to two rules

* test(agents): remove obsolete tool recovery receipt proof

* refactor(agents): drop unused meta param from buildToolMutationState

* test(agents): remove stale tool warning assertions

* test: export runtime source snapshot from closed runtime-snapshot mocks

Heal the main breakage introduced by 9441e3fe6e / #126531, which added a runtime source-snapshot read to provider model route resolution. Closed Vitest factories now return null for that source snapshot, preserving their pre-projection behavior.

* test(gateway): make compaction read-error faults order-immune

Generation-2 CI failure in run 32342180898, job 96343444772 showed that the mock factory initialized while shared gateway-server importers remained bound to the real transcript reader.

The dedicated isolated project fixes normal shards. Complete its ownership by adding it to the root project matrix and excluding the test from the non-isolated OPENCLAW_GATEWAY_PROJECT_SHARDS=0 fallback.
2026-08-20 01:11:05 -07:00
Peter Steinberger 147edf47f3 fix(auth): keep a retired auth JSON from stranding a migrated store (#126562)
* fix(auth): keep a retired auth JSON from stranding a migrated store

Runtime failed closed with AUTH_PROFILE_MIGRATION_REQUIRED whenever a retired
credential file was present, even when the canonical SQLite store already held
the agent's profiles. One leftover auth.json therefore made a fully migrated
install unusable, and the gateway lifecycle preflight refused start/restart on
top of it, so every channel and provider stayed offline until Doctor ran.

A legacy file is now only fatal when the canonical store cannot serve
credentials. Doctor's importer never overwrites a usable stored credential, so
a file sitting beside a populated store is unarchived bytes, not pending
migration: runtime logs a one-time warning and keeps serving. An empty store
with a credential file still fails closed and never falls through to
environment auth. Startup degrades that owner to configured-unavailable
instead of refusing to boot, which lets the lifecycle preflight go away.

* refactor(secrets): retire the auth-profiles.json vocabulary

Auth profiles moved to SQLite, but operator-facing surfaces still named the
retired JSON file. The duplicate-agentDir error told operators to copy
auth-profiles.json to share credentials, which does nothing and lands the
second agent in a migration-required state; `openclaw migrate plan codex`
reported a target file that is never created; and the secrets picker labelled
candidates with a filename that no longer exists.

Renames the SecretTargetConfigFile discriminator to "auth-profile-store" and
corrects the operator-facing text, the migrate plan target, and the docs that
described the file as a live target. Genuine legacy-filename uses in doctor,
the security fixer, and migration fixtures are unchanged.

Also deletes resolveSecretPlanTargetByPath and ResolvedSecretPlanTarget from
the plugin SDK. They have no callers in core, plugins, or tests, and the
symbols are absent from the latest stable tag, so they carry no compatibility
obligation and are removed rather than deprecated. Their inline parameter type
was the only thing putting the retired filename on the public SDK surface.

* improve(wizard): warn about device-code phishing

The device-code prompt only warned against sharing the code, and only when an
expiry was known. Device-code phishing works the other way around: the attacker
starts the login and gets the victim to enter the attacker's code. Codes
delivered over a chat channel are the risky case and carry no expiry hint, so
the warning is now unconditional and covers received codes, matching the Codex
CLI prompt.

Also documents the Codex auth handoff: a subscription profile is installed as
in-memory external auth rather than persisted, and token refresh is inverted
so the refresh token stays in OpenClaw's store.

* fix(test): make transcript read-failure injection order-independent

server.sessions.compaction-read-errors.test.ts injected its failures with
mockRejectedValueOnce, which fails the NEXT call to loadTranscriptEvents
globally. Under --isolate=false a shard shares one worker, so any sibling
transcript read could consume the one-shot rejection before the compaction RPC
issued its own; compaction then ran against the real reader and returned ok,
failing three assertions. This shard was already red on main; a prior repair
fixed the mock's initialization order but left the call-order dependency.

Key the injection on the seeded sessionId instead, so unrelated readers cannot
consume it and the re-read case counts only its own session's reads.

Also updates two expectations invalidated by this branch: the duplicate-agentDir
remediation text, and the plugin SDK export ratchet, shrunk by the two retired
secret-plan exports.
2026-08-20 00:42:41 -07:00
Peter Steinberger 75fcb1fbb9 fix(memory): reject unknown --agent ids and keep the hint runnable (#126570)
The memory CLI resolved --agent by returning the caller's string verbatim,
so an id that is not configured produced a confident empty result:
`memory status` rendered a panel for it, `memory index` fabricated a
workspace-<id> path, and `memory search` reported No matches. A typo read
as an empty memory rather than a nonexistent agent, while hooks, status
--usage, capability, migrate, and session targets already rejected unknown
ids.

Consolidate that duplicated check into resolveConfiguredAgentId beside the
agent roster owner, reuse it at the matching core sites, and route memory
to it through the existing memory-core host-runtime facade so no new
plugin SDK surface is added.

The canonical hint uses formatCliCommand rather than a literal: under a
profile or container the bare command is wrong, so consolidating on a
literal would have regressed the hooks and migrate hints and left the
status, capability, and session-target hints unrunnable.
2026-08-20 00:32:59 -07:00
Omar Shahine 641ccba793 fix(cli): allow agent selection for direct inference (#125143)
* fix(cli): inherit inference agent options

* fix(cli): route inference model auth agents

* fix(cli): route video describe agent

* fix(cli): route audio transcription agent

* fix(cli): preserve inherited agent selectors

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-08-19 21:27:09 -07:00
Jacqueline Henriksen eed64163b6 refactor(cli): make multi-agent operations agent-owned (#123871)
* refactor(cli): make multi-agent operations agent-owned

* fix(cli): keep provider setup on agent target

* fix(cli): preserve legacy operation ownership

* fix(cli): align capability target calls with current resolver

* fix(cli): preserve operation-specific agent errors

* fix(cli): keep allowlist selection agent-scoped

* fix(cli): preserve agent-owned model operations

* fix(cli): preserve list-form agent rosters

---------

Co-authored-by: Josh Lehman <550978+jalehman@users.noreply.github.com>
2026-08-19 19:54:00 -07:00
Peter Steinberger 19316660e4 fix(agents): consolidate ambient owner resolution (#126504) 2026-08-19 18:54:32 -07:00
Peter Steinberger bfc6bd3da5 fix(cli): honor inherited tasks options (#117528)
* fix(cli): honor inherited tasks options

* test(cli): classify task flow JSON support
2026-08-19 18:24:11 -07:00
Peter Steinberger 7769cb6466 fix(cli): accept daemon --json before subcommands (#126447)
* fix(cli): accept daemon json before subcommands

* test(cli): update doctor public-surface fixture

* test(cli): classify daemon parent JSON output
2026-08-19 15:17:21 -07:00
Peter Steinberger 1ef2ebf114 fix(cli): CLI commands crash on multi-agent rosters without --agent (#126418)
* fix(cli): route bare startup on configured inference, not a default agent

Bare `openclaw` resolved a single "default" agent to decide whether inference
was configured. On an explicit multi-agent roster (agents.ownership="explicit"
with 2+ entries) that resolution has no answer, so startup threw
AgentSelectionRequiredError instead of launching the TUI or onboarding.

The branch only needs to know whether inference is configured at all, so it now
asks exactly that across the roster and hands off to the TUI, which already
owns agent selection and resolves by workspace path first. Routing ambiguous
rosters to onboarding instead would have dropped a working multi-agent install
back into the setup wizard.

* fix(cli): honor the configured system agent for model read commands

`openclaw models status`, `models list`, `models auth list`, and
`models auth-order get` resolved a deprecated "default" agent when --agent was
omitted, so they threw AgentSelectionRequiredError on an explicit multi-agent
roster. schema.help.core.ts already documents agents.defaults.systemAgent.agentId
as the owner for these unscoped reads, and the Gateway twins
(models.ts, models-auth-status.ts) already honored it; only the local CLI paths
did not.

resolveModelsTargetAgent now takes a closed read/mutation mode. Reads resolve
explicit --agent, then the configured system agent, then a sole agent.
Credential mutations still require an explicit owner rather than guessing which
agent to write into, and say so with a flag that exists on those commands.

The deprecated resolver is gone from this owner. Help text for the two commands
whose default changed now names the system agent.
2026-08-19 13:02:19 -07:00
Peter Steinberger 615ff6ac94 fix: queued deliveries never recover at startup in multi-agent fleets (#126377)
* fix(outbound): resolve ambient delivery owner through the system-agent chain

Agent-less outbound channel bootstrap resolved its owner via the deprecated
throwing resolver, so multi-agent explicit-ownership configs with only
agents.defaults.systemAgent.agentId set threw AgentSelectionRequiredError from
inside gateway delivery recovery, aborting the whole drain ("Delivery recovery
failed") for every queued entry.

Bootstrap now follows the same ambient owner chain heartbeats and cron use
(legacy default, then systemAgent, then sole agent), consolidated into one
canonical tryResolveAmbientOwnerAgentId in agent-scope-config; the duplicated
chain in cron/agent-id.ts is deleted and heartbeat resolution reuses the
helper. Truly ownerless fleets no longer throw either: bootstrap proceeds with
global-scope plugin discovery only, never selecting an agent workspace, so
per-entry delivery outcomes stay recorded instead of one entry starving the
recovery loop.

Regression tests fail pre-fix: agent-less bootstrap routes through the
configured system-agent owner, and ownerless fleets bootstrap without
throwing.

* refactor(agents): route ambient owner resolution through one canonical chain

The idiom `tryResolveLegacyCompatibilityAgentId(cfg) ?? resolveDefaultAgentId(cfg)`
was copied across nine ambient surfaces. It reads like a fallback but is not: when
the first call returns undefined, resolveDefaultAgentId reduces to resolveSoleAgentId
and throws, so the second leg only ever throws — and neither leg consults
agents.defaults.systemAgent.agentId. Every one of those surfaces raised
AgentSelectionRequiredError in explicit fleets that own ambient work through a
system agent.

Promote the chain to one owner in agent-scope-config: tryResolveAmbientOwnerAgentId
(undefined when ownerless) and resolveAmbientOwnerAgentId (throws with the caller's
existing selection context). The throwing variant is a drop-in for every former
composite: identical message when a fleet has no owner, but the system-agent leg
now resolves.

Converted: resolveDefaultAgentDir (the shared producer behind auth, model catalog,
doctor, wizard, and Plugin SDK helpers), config identity-avatar validation, prepared
model catalog and registry, session reset, Talk target, main-session routing and its
routing-contract fingerprint, session store targets, hooks CLI, plugin LLM
completion, and first-run onboarding.

resolveDefaultAgentId keeps backing explicit-selection surfaces where 'pass --agent'
is the right answer; its deprecation note now sends ambient callers to the new
helper.

* fix(sessions,hooks): keep agent-narrowing surfaces on explicit selection

CI caught the over-reach: session-store listing and hooks status reporting are
deliberately explicit-selection surfaces, not ambient system work. Both narrow
output to one agent, so adopting agents.defaults.systemAgent.agentId would hide
the other agents' sessions/hooks instead of failing with the escape hatches the
operator needs. sessions.default-agent-store.test.ts pins that contract by
configuring a system agent and still expecting the --agent/--all-agents error.

Restore the prior behavior at both sites, spelled honestly as
tryResolveLegacyCompatibilityAgentId ?? resolveSoleAgentId — provably identical
to the old composite, since the composite's second leg could only ever throw —
with a comment recording why these two resist the ambient chain.

* test: declare the ambient owner binding in agent-scope mock factories

Explicit vi.mock factories enumerate exports, so production calling
resolveAmbientOwnerAgentId broke prepared-model-catalog, prepared-model-registry,
and channel-resolution with 'No "resolveAmbientOwnerAgentId" export is defined on
the ... mock'. Declare it in the four factories; channel-resolution now drives the
non-throwing variant the bootstrap actually calls.

Also restore session-store targets and hooks status to their exact previous code.
Both stay out of the ambient chain by design, so the smallest correct diff at an
out-of-scope site is none: they now differ from main only by the comment recording
why they resist it.

* fix(models): resolve the model-config workspace through the ambient owner

ClawSweeper P1: prepareModelsConfigContext resolved agentDir through
resolveDefaultAgentDir (ambient chain) but its workspace through
resolveDefaultAgentId (deprecated throwing chain), so explicit fleets owned by a
system agent still failed model preparation on the workspace lookup — a one-sided
fix inside a single function.

Both halves now resolve the same ambient owner.

* docs(agents): describe the widened ambient system-agent ownership

config-agents.md claimed 'Other agent-scoped methods do not use this setting as
a general default', which this branch makes false: systemAgent.agentId is now
the ambient owner for agent dir/workspace resolution, outbound bootstrap and
delivery recovery, main-session routing, Talk, and onboarding.

Record the widened set, the two surfaces that deliberately still demand explicit
selection (sessions, hooks), and delivery recovery's per-entry degradation.
2026-08-19 12:24:25 -07:00
Peter Steinberger 38a45c2220 fix(status): bound macOS gateway status probes (#126394) 2026-08-19 11:28:23 -07:00
Peter Steinberger 4994f7bacf fix(cli): resolve infer command owners via --agent and systemAgent fallback (#126234)
* fix(cli): resolve infer command owners via --agent and systemAgent fallback

Multi-agent rosters (agents.ownership=explicit) dead-ended every infer
runner command: resolveDefaultAgentId threw AgentSelectionRequiredError
telling callers to pass --agent, a flag none of the commands registered,
and agents.defaults.systemAgent.agentId was ignored.

Route model run, image generate/edit/describe/describe-many, video
generate, embedding create, and model auth logout through the existing
resolveCapabilityProviderAgentId chain (explicit --agent, then
agents.defaults.systemAgent.agentId, then the sole agent) with
per-command error surfaces, and register --agent on each command.

* docs(config): scope systemAgent infer fallback help to agent-owned commands
2026-08-19 08:44:52 -07:00
Peter Steinberger ae55a4090c refactor(canvas): make the panel a widget presenter (#126030)
* refactor(canvas): retire legacy host and commands

* refactor(apple): narrow shared Canvas contracts

* refactor(macos): keep Canvas as widget presenter

* refactor(ios): remove Canvas client

* refactor(android): remove Canvas client

* refactor(linux): remove Canvas client

* fix(ci): isolate native locale artifacts

* fix(linux): regenerate companion lockfile

* fix(canvas): refresh native tool display metadata

* test(canvas): align coverage with presenter surface

* test(canvas): remove obsolete asset root seam

* test(canvas): stabilize retirement CI coverage

* refactor(swift): remove orphaned resource wrapper

* test(ios): remove retired canvas layout assertion

* fix(macos): reserve retired canvas command namespace

* refactor(macos): isolate canvas command policy

* fix(canvas): select only eligible macOS panels

* fix(canvas): keep panel selection plugin-owned
2026-08-19 08:21:07 -07:00
Peter Steinberger 94eb34fa78 fix(skills): require re-review when proposals change (#126156)
* fix(skills): bind workshop decisions to reviewed revisions

* chore(i18n): refresh native source inventory

* test(skills): align revision proof with inspect projection

* test: align skill workshop regression fixtures

* fix(ui): align workshop revision admission proof

* fix(ui): keep revision errors out of startup
2026-08-19 01:52:11 -07:00
Peter Steinberger 2bcc06cc22 fix(cron): required delivery failures no longer report success (#126164)
* fix(cron): preserve required delivery completion

Record durable completion independently from payload execution so required delivery failure cannot delete one-shots or report successful waits.\n\nCloses #126163

* fix(cron): keep completion contracts acyclic

* fix(cron): keep delivery predicate private
2026-08-18 22:44:33 -07:00
Peter Steinberger 2456c77459 improve(gateway): avoid repeated logging and delivery scans (#126147)
* perf(gateway): remove repeated logging and delivery scans

Exact session-delivery retries no longer scan the full queue. Logging and diagnostics reuse lifecycle-owned settings and listener interest so uninterested projections are skipped, while outbound WebSocket summaries are built only after recipient admission.

* fix(infra): break diagnostic listener import cycle

Keep event-type validation at the diagnostic dispatcher while the process-wide listener presence counter remains a leaf module.

* test(cli): use logging override owner

Exercise late one-shot JSON diagnostics through the canonical logger override setter so lifecycle-cached console settings are invalidated as they are in production.

* test(auth): use logging override owner

Configure the locked-update warning test through the canonical logger override setter so lifecycle-cached console settings are invalidated before assertion.

* test(gateway): normalize redacted media fixture

Compare durable inbound media facts against the public redaction contract so random identifiers that resemble sensitive text do not make the Gateway suite flaky.
2026-08-18 22:13:22 -07:00
Jason (Json) d16c2858bf improve(update): make managed finalization timing auditable (#126107)
* improve(update): report finalizer phase timings

* test(update): return completion cache outcome

* refactor(update): isolate finalize command

* chore(update): document finalize config assertion

* test(update): isolate finalizer capability fixtures
2026-08-18 22:34:22 -06:00
Peter Steinberger b4a720ff1e fix(worktrees): preserve active removal authority (#126174) 2026-08-18 21:21:25 -07:00
Peter Steinberger 7bc994aee8 fix(install): avoid success after incomplete lifecycle changes (#125992)
* fix(install): make lifecycle mutations transactional

Standalone installers now apply npm-version-aware lifecycle approval. Updates verify and repair the installation before reporting success and preserve the prior install owner during method switches. Uninstall now exits nonzero when requested cleanup is only partially completed. Plugin update behavior is unchanged.

Closes #125925

* test(uninstall): assert aggregated live-owner failure

* fix(install): satisfy standalone shell checks

* fix(update): scan PATH for prior Git wrapper

* test(hooks): await Gmail watcher descendant exit

* fix(install): verify Windows npm candidate

* fix(ci): normalize package acceptance version

* fix(update): preserve staged local package links

* test(update): fold staged symlink coverage

* fix(update): retire every legacy Git wrapper

* test(docs): align consolidated ownership checks
2026-08-18 20:50:15 -07:00
Peter Steinberger 0718aedb9d test(cli): remove stale update sidecar fixture (#126126) 2026-08-18 19:13:09 -07:00
Josh Avant 8d6cbee1b5 fix(gateway): avoid Tailscale crash loops after upgrades (#126069)
* fix(gateway): migrate legacy Tailscale routes on upgrade

* fix(gateway): preserve unattributable Tailscale routes
2026-08-18 17:14:49 -07:00
Peter Steinberger 9924e2d7a7 feat(cli): prepare session-host onboarding (#125879)
* feat(cli): prepare session-host onboarding

* fix(cli): gate session-host installer capability
2026-08-18 16:08:48 -07:00
Peter Steinberger e8312171c1 fix: direct Gateway stops wait for active work (#126024)
* fix(gateway): drain active work on direct stop

* test(ui): isolate widget fetch retry mock
2026-08-18 15:29:52 -07:00
Peter Steinberger f97a133254 fix(config): fail config unset on a missing path again (#125958)
runConfigUnset scoped its missing-path error to --dry-run, so the real
invocation printed "No change" and exited 0 while --dry-run on the same
input exited 1 with a specific message. Dry-run exists to predict the
real run, and a typo'd unset in a script reported success.

Restore the failure for both modes, keeping the strict-config assertion
introduced alongside the regression and the JSON5 byte preservation it
was added to guarantee.
2026-08-18 13:45:57 -07:00
Peter Steinberger f59392fdf5 fix(channels): redact logs and reject unknown filters (#125939)
* fix(channels): redact and validate log filters

* fix(logging): preserve filtered redacted channel tails

* fix(channels): match log filters on exact boundaries

* fix(logging): honor redaction off mode
2026-08-18 13:37:17 -07:00
Peter Steinberger bb92dc61c8 fix: stop --tag main from failing during npm pack (#125949)
* fix: refuse unsupported OpenClaw source package updates

* refactor: narrow main update refusal
2026-08-18 12:22:45 -07:00
Peter Steinberger 7ae9cbf3bc fix(cli): stop claiming a write when approvals mutations are no-ops (#125960)
`openclaw approvals allowlist add|remove` printed "Writing local approvals."
from the shared target-resolution helper, before the mutation decision was
made. Both idempotent paths ("Already allowlisted.", "Pattern not found.")
returned without saving, so the CLI announced a write that never happened.
`approvals set` had the same problem: it announced the write and then rejected
unparseable input.

Move the announcement from `loadWritableSnapshotTarget` into the local branch
of `saveSnapshotTargeted`, the function that owns the write. Every caller of
the shared seam is fixed at once and exit codes are unchanged: idempotent add
and remove still leave the requested end state satisfied and exit 0.
2026-08-18 12:12:37 -07:00
Peter Steinberger 153ad5ec27 fix(cli): preserve migration agent ownership (#125948) 2026-08-18 12:10:09 -07:00
Peter Steinberger 91cc7d512b fix(cli): report broadcast delivery failures (#125915)
* fix(cli): report broadcast delivery failures

* test(qa): wait for descendant process exit
2026-08-18 11:28:13 -07:00
Peter Steinberger d8c1d90edb perf(test): consolidate shutdown watchdog proof (#125890) 2026-08-18 09:27:35 -07:00
Peter Steinberger e68e973c05 fix: report unknown gateway service state when inspection fails (#125734)
* fix(daemon): preserve unknown service load state

* test(daemon): update service load-state fixtures

* fix(onboard): preserve loaded service diagnostic

* fix(daemon): preserve unknown lifecycle state

* fix(status): preserve loaded JSON fields

* fix(daemon): fail restart on unknown service state

* fix(daemon): fence unknown service state
2026-08-18 09:20:02 -07:00
Peter Steinberger 13e3d4535b fix(agents): finalize guided creation safely (#125768)
* fix(agents): finalize guided creation safely

Run channel post-write hooks only after config publication, defer portable auth copying until agent creation succeeds without overwriting newer credentials, and provision existing workspaces before publishing updates.

Keep JSON-only guided creation interactive while routing wizard output to stderr so stdout remains one machine-readable summary.

* fix(terminal): preserve note call signature

* fix(agents): pass committed config to setup hooks

* ci: split heavy codex changed-test shards

Cap non-isolated Codex extension processes at 20 files so 4-vCPU changed-target jobs do not starve real-time watches or hit the no-output watchdog.

* test(ci): align codex shard cap fixture

* docs(cli): clarify agents add JSON mode
2026-08-18 08:50:01 -07:00
Peter Steinberger 8dd0434f86 fix(config): redact plugin secrets and preserve safe mutations (#125753)
* fix(config): secure CLI reads and mutations

Use exact plugin metadata for config get redaction, reject impossible SecretRef provider bindings in canonical validation, preserve include CAS provenance, and skip destructive authored no-op rewrites.

* fix(config): preserve inactive SecretRef startup

Keep normal Gateway validation scoped to active secret owners while strict config validation and write paths reject impossible provider/source bindings, including authored no-ops.

* fix(gateway): preserve config patch no-op

Keep unchanged Gateway config.patch requests on the existing no-op path; strict validation remains owned by actual config writes and the config CLI mutation surfaces.
2026-08-18 08:37:21 -07:00
Peter Steinberger 07a0b51703 fix(gateway): enforce shutdown deadline during event-loop stalls (#125863)
Use an off-main-thread watchdog for the process-owning Gateway runner so a CPU-bound shutdown cannot outlive the managed restart deadline. Bound agent-harness disposal so listener teardown can continue.

Release note: Managed Gateway restarts now recover when shutdown work stalls the event loop while preserving graceful cleanup first.

Closes #125840
2026-08-18 08:14:30 -07:00
Josh Lehman eeed2c92cf fix(upgrade): repair stable state before gateway startup (#125483) 2026-08-18 07:40:01 -07:00
Peter Steinberger fc6338c5d0 test(cli): canonicalize update fixture roots (#125846) 2026-08-18 07:39:31 -07:00
Peter Steinberger d92ebbaf72 feat(gateway): reach a Gateway behind an identity-aware proxy from the CLI (#125700)
* feat(gateway): reach a Gateway behind an identity-aware proxy from the CLI

Operator CLI surfaces (tui, attach, call, probe, onboarding, and configure) can present configured gateway.remote.edgeAuth headers to an identity-aware proxy. Headers are origin-bound, WSS-only, never follow redirects, cannot set transport-owned headers, and are redacted. Identity-proxy upgrade rejections are classified and remediated instead of being reported as an unreachable gateway.

* test(gateway): cover config-aware probe calls

Keep status probe expectations aligned with the resolved configuration forwarded for origin-bound edge-auth resolution.

* fix(gateway): preserve edge auth across wizard saves and enforce wss before secret resolution

Preserve gateway.remote.edgeAuth only when the configured Gateway scope is unchanged, and reject non-WSS targets before resolving any edge-auth SecretInput.
2026-08-18 03:29:56 -07:00
Peter Steinberger f0dd7eecaa fix: preserve plugin update recovery after commit (#125739) 2026-08-18 02:08:56 -07:00
Peter Steinberger 2eec047065 fix(mcp): explain an empty probe instead of printing a bare header (#125611)
With no servers configured, mcp probe emitted only its header line and exited
0, while mcp list and mcp doctor both name the condition and the command that
fixes it. Short-circuit the human path with the same guidance and skip building
a runtime for zero servers; JSON output keeps its existing empty envelope.
2026-08-17 22:15:44 -07:00