Commit Graph

1374 Commits

Author SHA1 Message Date
Jason (Json) bccbb8a0c7 fix(memory): make persistence promises receipt-backed (#120989)
* fix: require memory persistence receipts

* fix(memory): bind persistence failures to tool owners

* fix(memory): preserve Codex persistence ownership

* test(plugin-sdk): account for owner metadata export

* test(codex): split owner timeout regression

* fix(memory): cover durable deletes across runtimes

* test(codex): type dynamic mutation fixtures

* fix(agents): fail closed ambiguous side-effect owners

* fix(memory): fail zero-row delete receipts
2026-08-16 00:50:10 -06:00
Peter Steinberger 191d2313a8 test(codex): split the session-catalog suite along module seams (#124397)
* test(codex): split the session-catalog suite along module seams

Replace the 4.8k-line grandfathered session-catalog.test.ts with seven
seam-anchored suites plus shared fixtures, and remove its max-lines
suppression and baseline entry. The broad openclaw/plugin-sdk/node-host
vi.mock becomes a narrow session-catalog-pty.runtime.ts boundary so the
non-isolated extension-codex worker no longer re-instantiates the
plugin-sdk graph once per split file (the crash PR #124178 measured).
Test bodies are verbatim; AST parity across the split checked out
96/96 identical.

AI-assisted (Codex worker under maintainer review).

* test(codex): carry caller origin in the cron-authority capability fixture

PR #118579 widened the in-process CronCreatorAuthorityCapability run
scope with a contractually required callerOrigin, and the new transcript
tool wiring reads it during turn startup. The hand-built fixture in
run-attempt.configured-mcp.test.ts predated the field, so
bindActiveOperatorTurnAuthority threw and runCodexAppServerAttempt
rejected while five tests awaited turn/start - 120s timeouts, then a
worker teardown crash. #118579's CI never ran the extension-codex lane
(cross-lane classification gap), so main's codex lane was latently red.
Bisected to 8668aeb9698; fixture now mints the local-operator origin the
helper's name promises.

AI-assisted (maintainer-diagnosed, Codex-era fixture repair).

* test(codex): keep catalog fixture internals private
2026-08-15 21:26:13 -07:00
Peter Steinberger 7862a5da15 refactor(session-catalog): split codex catalog modules and unify adoption coordination (#124178)
* refactor(session-catalog): unify adoption coordination

* refactor(codex): split session catalog modules

* fix(anthropic): narrow adopted history for import

The coordinator migration hoisted history to an optional outer binding;
afterCreate needs the definite array from the create scope.

Also drop the retired session-catalog max-lines ratchet entry.
2026-08-15 06:40:40 -07:00
Peter Steinberger da11168959 fix(codex): preserve paired-node agent ownership (#124172) 2026-08-15 06:06:12 -07:00
WhatsSkiLL 632581477f fix(session-catalog): preserve explicit agent ownership across UI and CLI (#123899)
* fix(session-catalog): preserve explicit agent ownership across UI and CLI

* fix(session-catalog): repair owner routing regressions

* Fix-session-catalog-CI-checks

* test(ui): split chat catalog pane coverage

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>

* refactor(session-catalog): bind Codex homes per request

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>

* refactor(session-catalog): centralize owner resolution

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>

* fix(codex): resolve session fork against the adopted home

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>

* refactor(ui): extract chat session discussion

* test(sessions): stabilize archive worker responsiveness check

---------

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-15 04:47:28 -07:00
Peter Steinberger 20e81a724d test(codex): trim duplicate app-server regressions (#124141) 2026-08-15 02:56:05 -07:00
Jason (Json) 40866f3330 fix(codex): honor managed binary owner root (#124124) 2026-08-15 03:18:54 -06:00
Peter Steinberger 5d601233df refactor(types): remove chained type assertions in extensions (#124079)
* refactor(types): remove chained assertions in extensions

* fix(codex): preserve canonical binding identity
2026-08-15 01:39:26 -07:00
Peter Steinberger 28f10c00b4 fix(codex): keep yolo approvals disabled (#124069)
Keep routine Codex commands from pausing for approval in default and team YOLO sessions. The default exec policy omitted its full mode, so a generic tool hook could promote approvalPolicy from never to untrusted.
2026-08-14 23:57:49 -07:00
Ayaan Zaidi 2e806ef0e2 fix(codex): keep the real answer when a trailing coda follows (#123993)
* fix(codex): keep prior finals when a coda follows without tool work

Live persist last-won a single assistant slot, so a trailing final_answer
replaced the real summary. Keep explicit finals after the last native tool;
phase-less coordination text stays last-wins.

* fix(codex): record the native-work barrier from item notifications

turn/completed.items is a last_agent_message Summary, so result-time
tool scans cannot see intervening work. Invalidate persistable finals
when native tools arrive, drop trailing silent tokens, and let a later
unphased message replace earlier finals.

* fix(codex): make the persistable-text barrier once-per-handoff

Delayed native completions must not move the barrier past an answer that
arrived while that tool was already active. Dynamic tool calls are the
same handoff. If no audible text exists after the barrier, recover the
last persistable answer instead of dropping it.

* fix(codex): keep a post-handoff silent final authoritative

A tool after an audible final starts a new answer segment. If that
segment is NO_REPLY, do not revive the pre-tool text. Recover a prior
answer only when the post-handoff segment is empty.

* fix(codex): classify silent finals with the delivery payload predicate

Token-only matching missed JSON and reasoning-wrapped NO_REPLY
payloads, so a trailing control envelope could join into the visible
answer. Use the shared payload-level predicate.

* fix(codex): honor unphased replacement and sleep handoffs

A later unphased item must invalidate older finals even when a later
final skips it, and sleep is a native answer barrier.
2026-08-15 11:36:33 +05:30
Bek 5a5bf4d524 fix(codex): preserve native child continuation on yield (#124004) 2026-08-15 01:13:09 -04:00
Jason (Json) e382fa7979 fix(codex): keep task lists active across compaction (#123921)
* fix(codex): restore plan state after compaction

* fix(codex): bound restored plan context
2026-08-14 21:27:42 -06:00
Peter Steinberger 0a6b95a3df feat: cloud workers for the codex runtime (remote-exec placements) (#123743)
* feat(gateway): add remote-exec cloud placements

* feat(codex): run cloud turns through remote exec

* fix(sandbox): quote ssh_config path directives containing whitespace

Crabbox lease keys default to ~/Library/Application Support/... on macOS;
unquoted IdentityFile/UserKnownHostsFile/CertificateFile arguments tokenize
on the space and fail as 'extra arguments'. Found via live remote-exec
cloud-worker proof.

* test: consolidate gateway maintenance schedule coverage

* fix(ci): invalidate plugin sdk declarations on state changes
2026-08-14 16:46:56 -07:00
Peter Steinberger 17eb646bb3 refactor(ai): consolidate Responses replay paths (#123762)
* refactor(ai): consolidate Responses replay ownership

* refactor(codex): consolidate completion plumbing

* refactor(agents): centralize replay pairing repair

* refactor: preserve replay static contracts
2026-08-14 11:20:57 -07:00
Peter Steinberger 8885be4756 fix(codex): refresh session meters after /codex compact (#123640)
* fix(codex): route compact through session pipeline

Route /codex compact through host-owned manual compaction so native completion and token snapshots update session meters, and report the terminal outcome to the user.

* test(codex): cover unavailable compact outcome

* fix(plugins): fence command compaction capability

Bind compactCurrent to one command invocation and captured session generation so retained or stale callbacks fail closed without running compaction.

* fix(plugins): lazy-load command session revalidation

Keep compaction session freshness checks at the auto-reply owner without pulling the session accessor into generic plugin command module initialization.

* fix(plugins): keep session revalidation lazy

Avoid loading the session accessor through generic plugin command initialization while preserving pre-compaction session-generation checks.

* fix(compaction): fence session lifecycle admission

Revalidate the exact session id and lifecycle revision immediately before native compaction and again before accounting so resets and rebinds fail closed across awaited work.

* fix(commands): fence plugin compaction authority

* fix(compaction): require accounting commit

* test(compaction): keep regression under lint cap

* fix(codex): preserve compact admission

* fix(codex): preserve compaction target identity

* fix(compaction): bind admitted target

* fix(compaction): fence accounting commit
2026-08-14 09:47:43 -07:00
Peter Steinberger 129c06d811 fix: bind steering authority to model route 2026-08-13 23:28:53 -07:00
Peter Steinberger d183d06738 fix(codex): deny native tool feature pins 2026-08-13 23:28:53 -07:00
Peter Steinberger 54cf346abb fix: preserve pending input across authority changes 2026-08-13 23:28:53 -07:00
Peter Steinberger 1bb20fb16a fix(codex): bind steering to tool authority 2026-08-13 23:28:53 -07:00
Peter Steinberger b5809f5f44 fix: enforce native tool policy across harness lifecycles 2026-08-13 23:28:53 -07:00
Peter Steinberger db4379bd2f fix(codex): refresh token snapshot after compaction (#123478) 2026-08-13 22:38:04 -07:00
Peter Steinberger 7c5eaede1e feat(codex): pass explicit skill selections as structured turn input (#123441)
* feat(codex): pass explicit skill selections as structured turn input

Thread OpenClaw-resolved explicit $skill selections through the reply
pipeline to the Codex app-server harness and emit them as structured
UserInput::Skill turn items when the Codex catalog (skills/list) knows the
same SKILL.md path. Codex then injects the skill natively and blocks its
text scanner from double-selecting the same name, while unmatched names
stay scannable for Codex-native-only skills and the prompt instruction
block keeps owning skills Codex cannot see. Catalog misses and RPC errors
fail open to the instruction path; the turn never fails on skill lookup.

Part of #123367

* fix(plugins): defer llama-cpp ssrf-runtime load out of the setup closure

The doctor-contract closure guard forbids the SSRF barrel in the
doctor/legacy-setup closure (cold-loads DNS, proxy state, logging); the
static import landed with the managed llama-server switch (#123105) and
first fails when a PR selects the guard lane. Defer to a dynamic import at
download time per the guard's stated remedy.
2026-08-13 20:37:47 -07:00
Bek eb1035e861 fix(codex): retain direct-child hook policy after parent yield (#122503) 2026-08-13 22:51:34 -04:00
Vito Cappello e43015146e fix(codex): preserve quiet native tool results (#119835)
* fix(codex): preserve quiet native tool results

* test(qa): cover quiet native tool result topic isolation

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-13 18:05:36 -07:00
Peter Steinberger e04dfd26e2 fix(codex): stop quoted context from triggering explicit skill mentions (#123345)
Codex byte-scans every turn text input for $name skill mentions and
[@name](plugin://...) links (codex-rs/skills/src/mentions.rs), so historical
$skill tokens inside OpenClaw's projected <conversation_context> block and
inbound quoted-reply/room-backlog context counted as current explicit
invocations and injected skill bodies the user never requested.

Neutralize mention sigils with same-length fullwidth lookalikes (the
escapeCodexChatText technique) in projected history and inbound context;
only the raw current request stays selectable.

Fixes #122812
2026-08-13 15:33:23 -07:00
Peter Steinberger eefe8bdc16 fix(codex): preserve explicit migration ownership (#123331)
Discover legacy shared session roots without requiring an implicit default agent. Preserve ambiguous bindings while keeping agent-scoped owners exact.

Closes #123326
2026-08-13 15:14:33 -07:00
Vincent Koc 033247ab42 fix(codex): resume parent after terminal subagent fan-out (#123124)
* fix(codex): settle terminal tool releases immediately

Punchcard-Session: quiet-workshop-river-e5

* fix(agents): materialize requester ownership at launch

Punchcard-Session: quiet-workshop-river-e5
2026-08-13 19:15:58 +08:00
Peter Steinberger b54034d5c2 fix: isolated gateways list and open the operator's HOME Claude/Codex/OpenCode/Pi sessions (#122983)
* fix(sessions): isolated gateways no longer inherit HOME external session catalogs

A gateway on isolated state (custom OPENCLAW_STATE_DIR/CONFIG_PATH/OPENCLAW_HOME,
relocated home, or any named profile) listed, read, continued, archived, and
reopened the operator's real Claude Code/Codex/OpenCode/Pi sessions from the
process HOME. External catalogs now require the default install identity for
process-HOME scans: every catalog verb receives the isolation policy and rejects
HOME-fallback local targets, unknown providers fail closed unless they declare
supportsProcessHomeIsolation, and one structured warning records the skip.
Paired-node hosts and explicitly rooted stores (CLAUDE_CONFIG_DIR, CODEX_HOME,
OPENCODE_DB, Pi session dirs) keep working; default-identity gateways are
unchanged.

* fix(sessions): inject catalog HOME-isolation fact at registry construction

* chore(sdk): regenerate plugin API baselines after rebase

* chore(sdk): regenerate plugin API baselines after rebase
2026-08-13 01:12:03 -07:00
Ayaan Zaidi 0b9842d138 fix(agent): finish turns when providers fail after tools complete (#123005)
Safely finalize settled Codex turns when an overload arrives after tool completion. Keep other provider failures fail-closed and preserve channel delivery.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-13 12:17:28 +05:30
Peter Steinberger 469be48967 fix(codex): keep sessionless mirror warnings out of onboarding (#122831)
* fix(codex): skip mirrors for sessionless runs

* fix(codex): restore openai model provider on media understanding turns

PR #122163 made thread/start modelProvider caller-supplied and updated the
web-search caller but missed media understanding, breaking its tests on main
full runs (cross-lane gap). Pass the provider explicitly and export the
retire binding prod now touches from the shared-client test mock.

* test(codex): align prompt assertions with reworded guidance

PR #121522 reworded the Skill Workshop guidance and cd7b7f639d reworded
the message-tool final-reply text; both updated core tests but missed
these codex mirror assertions (cross-lane gap breaking main full runs).

* test(codex): scope agent-projection fixture session to its agent

PR #114388 made multi-agent session ownership explicit; the atlas-scoped
projection test still used the shared main-scoped session key and now
trips AgentSelectionRequiredError (fourth cross-lane escape on main).
2026-08-12 18:13:16 -07:00
Peter Steinberger e4acf43813 test(agents): scope extension fixtures to explicit owners (#122883) 2026-08-12 17:52:03 -07:00
Peter Steinberger 5c2e099374 fix(codex): restore promoted approval regression coverage (#122861)
* test(codex): align projector fixtures with verbose policy

* test(codex): supply admitted host context to hook relay fixtures
2026-08-12 16:30:30 -07:00
Kimi Yu e1b8150a06 fix(codex): let owners install plugins from discovered marketplaces (#122389)
* fix(codex): allow owner-approved marketplace plugins

* fix(codex): preserve marketplace validation and remove unused exports

* docs(codex): clarify already-installed plugin authorization
2026-08-12 20:29:40 +00:00
Peter Steinberger 9da43d67e1 refactor: remove residual normalization adapters (#122771) 2026-08-12 11:51:45 -07:00
Peter Steinberger e689231e42 fix: make Codex onboarding survive inherited Node loader paths (#122731)
* fix(codex): sanitize inherited runtime loader paths

* fix(onboard): preserve candidate failure details
2026-08-12 10:42:34 -07:00
Peter Steinberger c23d66e3b5 refactor: consolidate coercion ownership (#122692)
* refactor: consolidate coercion ownership

* test: align shard check with weighted planning

* chore: refresh plugin SDK API baseline
2026-08-12 09:25:28 -07:00
Peter Steinberger b080dd1e76 refactor: consolidate coercion contracts (#122458)
* refactor: consolidate coercion contracts

Centralize exact string, record, numeric, date, Boolean, argument, and structured-error coercions while preserving call-site semantics.

Migrate canonical-name collisions and deprecated internal SDK bypasses, deleting 55 net production/tooling lines. Expand declaration ownership enforcement to 101 allowed helpers and add a narrow export-completeness audit.

* fix: preserve standalone script coercions

Keep copied Control UI tooling self-contained and retain the trusted release harness module-relative source seam when the harness runs against an old target cwd.
2026-08-11 23:26:37 -07:00
keshavbotagent 3807eb9c58 fix(codex): preserve allowed tools under channel policy (#122282)
Preserve Codex native tools when conversation policies deny only audited OpenClaw capabilities. Fail closed for computer-control denies and retain structured plan progress.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Co-authored-by: Kelaw - Keshav's Agent <keshavbotagent@gmail.com>
2026-08-12 05:27:08 +00:00
Ayaan Zaidi ec4ae78b75 fix(agents): generate session titles with runtime-owned auth (#122163)
Use the selected harness for isolated title generation, including native Codex auth.
Retry failed dashboard titles from the first user message without overriding manual names.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-12 09:42:16 +05:30
Peter Steinberger a5420dfd91 fix(windows): launch npm-installed native session CLIs (#122334)
* fix(windows): resolve runnable npm launchers

* fix(windows): preserve npm shim argv in terminal sessions
2026-08-11 18:41:35 -07:00
Peter Steinberger 964c8c84c1 refactor: consolidate coercion ownership (#122299)
* refactor: consolidate coercion ownership

Centralize four canonical coercion helpers, migrate exact core and plugin duplicates through narrow Plugin SDK facades, and enforce declaration and plugin-normalization ownership boundaries.

The sweep adds eight focused SDK exports while deleting more production and tooling code than it adds. User-visible behavior is unchanged except for safer equivalent object and UI parsing at existing boundaries.

* fix: guard integer option ownership

Register resolveIntegerOption with the canonical function owner and extend the declaration-guard fixture so future local duplicates fail validation.

* fix: keep integer helpers on numeric facade

Remove the unshipped duplicate string-coerce exports and route every affected plugin consumer through the existing number-runtime contract.

* fix: point numeric coercion to number runtime

Make boundary and declaration diagnostics recommend the canonical numeric facade, with failing-before coverage for both guidance paths.
2026-08-11 17:14:53 -07:00
Ayaan Zaidi 6a4a546593 feat(mcp): per-requester OAuth for MCP servers (#122166)
Per-requester OAuth for HTTP MCP servers: in shared channels each trusted sender connects their own account. New config: mcp.servers.<name>.oauth.identity ("shared" default, byte-identical behavior) and gateway.publicOrigin (HTTPS except loopback) for the new GET /oauth/mcp/callback served on the Gateway HTTP server. Requester tokens are isolated per (channel, account, sender) in mcp_oauth_stores rows (no schema bump); callbacks correlate through a durable state-keyed one-time index with a 10-minute TTL; per-requester servers are fail-closed out of static/scheduled runtimes; unauthenticated senders get a sign-in link with a portable URL button; MCP config mutations clear requester credentials at the canonical owner. mcp status --json keeps the legacy authStatus fields additively. Proven by a two-user self-hosted-Executor E2E through the real gateway callback. Part of #122034.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-11 20:58:51 +00:00
Peter Steinberger cad77fb39c refactor: consolidate remaining coercion helpers (#122020) 2026-08-11 10:22:01 -07:00
joshavant c913d6e126 refactor(codex): use shared coercion helpers 2026-08-11 04:47:10 -05:00
joshavant bb873c8806 fix(cron): preserve Codex app authority 2026-08-11 04:47:10 -05:00
Peter Steinberger e6b356f35a fix(tasks): stream Codex subagent activity (#121899)
* fix(tasks): stream Codex subagent activity

* fix(tasks): honor registry access boundary
2026-08-11 00:32:08 -07:00
Peter Steinberger 46bdbe585f fix(openai): restore Sol thinking levels (#121865)
Co-authored-by: Amp <amp@ampcode.com>
2026-08-11 00:28:21 -07:00
Peter Steinberger fa03d9b913 refactor: consolidate coercion helpers (#121366)
* refactor: consolidate coercion helpers

* fix: remove duplicate coercion imports

* fix: preserve serialized coercion guard

* chore: ratchet coercion helper carve-outs

* fix(test): keep gauntlet subprocess startup lean

* fix: preserve imported session timestamp semantics

* fix: preserve catalog timestamp string semantics

* chore: align plugin SDK surface ratchet

* fix: preserve trajectory and SDK string contracts

* fix(test): preserve QA record assertion semantics

* fix: complete standalone record guard rename

* refactor(cron): use canonical string coercion

* fix(acpx): preserve Pi timestamp parsing

* test(channels): adapt custody test harnesses

* test(telegram): classify media harness as test support

* test(acpx): split timestamp contract coverage

* test(channels): support generated custody contracts

* chore: ban the full coercion helper name set

Extends the declaration guard to all eleven consolidated helper names and
renames the cron schedule-identity readNumber wrapper to readScheduleInteger
so the banned generic name cannot regrow.

* fix(scripts): repair release-validation guard drift and lint cause

Restores the renamed isJsonRecord guard in assertTrustedWorkflowHarness after
main added isRecord call sites in parallel, and attaches the caught YAML error
as the thrown error cause (preserve-caught-error was red on main).

* fix: preserve Claude timestamp string semantics

* fix: preserve persisted timestamp string semantics

* fix: preserve date-first timestamp contracts

* fix(openai): harden delegation failure formatting

* chore: close coercion helper guard gaps

* test(openai): model non-error delegation rejection

* chore: refresh plugin SDK API contract

* fix(tasks): use canonical string field reader

* fix(ai): use canonical provider error field coercion

* fix(browser): migrate native bootstrap coercion

* docs(plugin-sdk): clarify text record export compatibility

* fix(gateway): normalize approval execution identity

* test(outbound): isolate message action poll harness
2026-08-11 00:02:18 -07:00
Josh Avant 73a9eed95b refactor(audit): add canonical admitted-run context (#120534)
* feat(audit): carry canonical admitted execution context

* fix(agents): preserve admitted context across retries

* fix(worker): fence legacy launch dialect

* test(gateway): track approval temp dirs

* fix(plugin-sdk): preserve harness attempt compatibility

* fix: close delegated run authority at owner boundaries

* fix: internalize delegated authority validators

* refactor: split delegated authority proof surfaces

* refactor: centralize command admission identity

* test: claim runtime tool authority

* fix(gateway): keep lifecycle cleanup within static budgets

* fix(agents): revalidate harness policy authority

* fix(agents): fence awaited approval capability results

* test(copilot): supply required harness capability fixtures

* fix(agent): preserve scoped embedded run admission

* fix(agent): preserve keyless and worker authority

* test(agent): bind incomplete-turn authority

* docs: preserve execution authority invariants

* chore(plugin-sdk): regenerate API baseline

* fix(gateway): notify pending claim closure

* fix(gateway): revalidate delegated tool authority

* fix(plugin-sdk): keep source guard internal

* fix: close delegated authority races

* fix: revalidate delegated side effects

* fix: close harness authority projection gaps

* fix: align authority integration types

* fix: isolate settled harness finalization

* fix: fence recovery identity finalization

* fix: preserve committed session worktrees

* fix: preserve worker placement agent identity

* fix: fence active harness tool work

* fix(plugins): restore embedded run admission owner

* chore(plugin-sdk): compose integrated surface budgets

* fix(copilot): keep finalization attempt type internal

* fix(plugins): complete admission owner type imports

* test(harness): use settled finalization attempt shape

* fix(security): retain exact side-run and approval authority

* fix(security): preserve protected authority through terminal sweep

* fix(agents): follow moved recovery store owner

* fix(ci): align integrated authority owners with gates

* fix(plugins): distinguish embedded agent adapter export

* chore(plugin-sdk): regenerate API baseline after rolling integration

* refactor(gateway): keep session authority within owner budgets

* fix(gateway): keep session helpers private

* docs(plugin-sdk): name the V2 parameter subpath

* chore(integration): reconcile worker and SDK surfaces

* docs(plugin-sdk): require the V2 host API floor

* chore(plugin-sdk): regenerate after proxy-auth integration
2026-08-10 23:15:20 -05:00
Peter Steinberger 59492c51a5 feat(agents): rename spawn_task tool to suggest_task (#121694)
* feat(agents): rename spawn_task tool to suggest_task

Models across vendors read the name spawn_task as 'starts background
work' and refuse to call it when the user has not asked to start
anything (Claude Sonnet 5, verbatim: 'spawn_task (which actively starts
background work)... Since you didn't ask me to start work, I'm flagging
this as a follow-up instead'). The tool only records a suggestion card,
so the name defeated the feature.

Rename the model-facing tool to suggest_task everywhere (catalog,
descriptors, presets, display config, OpenClawKit tool-display, docs)
and migrate persisted operator state via doctor: config tool policies
and cron SQLite toolsAllow entries that reference spawn_task are
rewritten to suggest_task. No runtime alias remains; runtime exposes
only the canonical name.

Live clean-room matrix on a dev gateway (virgin session per cell):
suggested-task-card phrasing now yields exactly one card on
anthropic/claude-sonnet-5, claude-haiku-4-5, openai/gpt-5.6-sol,
gpt-5.6-luna, and google/gemini-3.1-pro; pre-rename the same bait
produced prose-only follow-ups.

* chore(doctor): keep legacy tool-name predicate module-local

isLegacyTaskSuggestionToolName has no external consumers; the exported
form tripped the knip unused-export gate (deadcode:exports).

* fix(doctor): keep tool-name migration out of plugin-owned config

The rename migration traversed the whole raw config, so any object
carrying a toolsAllow key was rewritten - including opaque
plugins.entries.*.config, which core must not mutate. Scope the apply
pass to the typed core roots (tools, agents, channels, gateway) and pin
plugin config preservation in the test. Plugin-owned tool lists migrate
via the owning plugin's doctor contract instead.

* fix(ci): heal main deadcode and stale Swift protocol mirror

Unrelated main breakage blocking this PR's merge gate, healed here per
landing policy:

- #121653 left dead exports in src/skills/workshop: make
  removeSkillCollectionDirectory and SkillCollectionRestoreResult
  module-local; register collection-review.ts under the documented knip
  ignoreIssues test-only-export convention (production runs it via the
  scheduled maintenance loop).
- #121673 added ApprovalResolveParams.reviewer without regenerating the
  Swift mirror; regenerate GatewayModels.swift (additive only).

* fix(ci): satisfy generic approval-runtime request signature in resolver test

Third main-heal carried by this PR: #121673 (9935ca3b30) left the
scoped-request mock's concrete inferred type unassignable to the generic
GatewayNativeApprovalRuntime request signature, breaking check-test-types
on main. Cast the mock at the runtime literal; assertions keep the Mock.

* chore(ci): drop approval-test cast superseded by main's typed mock rewrite

* chore(ci): drop duplicate knip entry superseded by main's heal
2026-08-10 16:41:39 -07:00