fix(plugins): generate valid package names for scoped plugin scaffolds
The plugin scaffold put its openclaw-plugin- prefix in front of the whole name, so a scoped name like @scope/pkg became openclaw-plugin-@scope/pkg, which npm rejects. Scoped names now keep their scope, giving @scope/openclaw-plugin-pkg. Unscoped names are unchanged.
Evidence: built CLI on Node 24.22.1 with tool and provider scaffolds and scoped and unscoped names (16 scaffolds, each checked with an offline npm publish dry run). Main generated openclaw-plugin-@scope/pkg, which npm rejected (twice); with this change it generated @scope/openclaw-plugin-pkg, which npm accepted (twice). Unscoped names are unchanged and accepted on both refs. Plugin IDs, output paths and install metadata were checked, and nothing was published. Details: https://github.com/openclaw/openclaw/pull/186901#issuecomment-6475755167.
Thanks @Alix-007.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* refactor: rename Claws feature to Templates
* docs: repair historical Templates guide links
* fix(templates): preserve state upgrades and published artifacts
* test(templates): preserve fresh identity in additive repair fixture
* fix(templates): complete migration consumers and wrapper closure
* test(templates): allocate explicit safety regression budget
CI e447f0bf (73fa01a3 merged into f38f7e73) counts 6,301,355 test lines against a 6,299,646 ceiling: +1,709. Its actual main base already contains 6,300,241 lines (+595 debt); this PR contributes +1,114 net lines.
Retain independent shared-state upgrade/data/rollback, real plural-lease revocation, immutable-archive authoring-boundary and cold extracted-wrapper regressions. They are already parameterized/shared where their contracts match. Removing 1,709 lines would exceed all PR net growth and force unrelated cleanup or weaker coverage. Allocate exactly the measured total, with no slack or counting/gating changes; account separately for the 2,715 upstream ceiling advance over source 73fa01a3.
* docs(templates): preserve frozen release history and mirror
Restore the historical2026.9.5 Claw-package link to its baseline bytes and regenerate the owned mirror through changelog:from-docs. Normal PR release-artifact scope is now empty; no release-automation override or native prep metadata change.
The unchanged global docs route audit separately reports the frozen /cli/claws historical link as missing. Preserve that concrete failure for the owner policy decision; do not add an alias, redirect or audit exception.
* docs(templates): retain published Claws documentation URL
Keep the verified published2026.9.5 documentation URL through one existing docs-host redirect from /cli/claws to canonical /cli/templates. Frozen release source and mirror remain baseline-exact. This is not a CLI, Gateway/API or Control UI alias, and does not add a runtime handler or audit exception.
* test(templates): reserve bounded regression budget headroom
CI40663216626 measured6,301,549 lines against6,301,539, over by ten upstream lines while PR net remained+1,114. Round to the next1,000 at the owner-approved fixed6,302,000 ceiling:451 reserve lines (0.0072%) for ordinary main advancement during exact-head CI and required regression maintenance.
Actual CI base already contains789 debt lines against6,299,646. The total manual allocation is2,354=789 existing debt+1,114 required PR lines+451 bounded reserve. Latest inspected main5eeafd8d merges at6,301,531 after18 lines of upstream shrink, leaving469; no extra ceiling was added for it. Cases, assertions, counting/gating logic, all runtime/source/prep metadata and permission guards are unchanged.
* test(ui): await responsive appearance grid geometry
Viewport resize schedules shell invalidation and async rendering, followed by the existing grid-track transition. Poll actual geometry within the unchanged100ms/15000ms expect.poll budget, then reread and retain the original3/1 column and minimum150px assertions plus every heading, accent, focus and color-mode check.
Parent-qualified normal secretless native Mac browser at exactCImerge c876: original3a30c3fd red outer1/26.873s expected3 got1; exact staged test blob9db27bab green outer0/19.779s, full case1143ms. Host performed static checks only. No runtime CSS/code, expected values, sleeps, timeouts, skips or guards changed.
fix(cli): route remaining CLI reports through the terminal-text owner
After #185927 added one owner for escaping untrusted values in CLI output, contributors kept opening one PR per command to escape the next report. This moves the remaining human-readable reports in the plugins, secrets, sessions, memory and memory-wiki, workboard, backup, pairing, oc-path, config and setup commands onto `terminalText` / `displayPath`, and extends the owner to neutralize bidirectional control characters. JSON output, persisted identities, raw exports and the CLI's own colors are unchanged, and the trusted styling of `renderTable` is untouched.
This absorbs the per-site fixes from @Leon-SK668 (#184454, #184379, #185374, #186449, #184396, #184788, #184813, #184394), @huwei-xydt (#185895, #185719), @wangmiao0668000666 (#175600, #175181, #175179), @SunnyShu0925 (#184747), @KrasimirKralev (#184597) and @arpe1618 (#150599), whose original commits are kept. Families no PR touched (update, Doctor, install-trust producers and others) are listed under "Not fixed here".
Evidence: 85 built-CLI invocations per ref with crafted control and bidi characters in the reported values, captured as raw stdout bytes. Main printed the raw sequences; this change printed them neutralized, with identical normal colors and unchanged JSON. Details: https://github.com/openclaw/openclaw/pull/186502#issuecomment-6460632667.
Co-authored-by: 胡伟0668000622 <hu.wei94@xydigit.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Leon-SK668 <0668001470@xydigit.com>
Co-authored-by: wangmiao0668000666 <wangmiao0668000666@users.noreply.github.com>
Co-authored-by: SunnyShu <0668000539@local>
Co-authored-by: Krasimir Kralev <263465593+KrasimirKralev@users.noreply.github.com>
Co-authored-by: arpe1618 <razark2978@naver.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* feat(plugins): hand running turns to a reloaded plugin at step boundaries
A reload that reserves a plugin now tells work holding it. A running turn
on a plugin that hands over stops at its next model step through the
existing plugin-runtime refresh and continues on the new generation;
whole-run leases yield their work count. The refresh continuation waits
out pending publication instead of failing after three gates.
* feat(plugins): opt in to turn handover with manifest reload.turnHandover
openclaw-a71.5: a plugin declares reload: { turnHandover: true } in
openclaw.plugin.json; the retiring generation's record decides whether a
reload hands running turns to the new generation. Plugins without the
field keep today's wait for the turn. Replaces the prototype env var.
* feat(plugins): explain what a plugin reload waits for during turn handover
openclaw-a71.6: reload status says when running turns continue on the new
version at their next step, and names plugins that keep whole turns because
they do not declare reload.turnHandover. Documents why a refresh
continuation waits through back-to-back reloads and covers it with a test.
* fix(agents): tell a handed-over turn a plugin reloaded instead of asking it to verify a change
openclaw-a71.7: the refresh records whether the run's own plugins tool or an
outside reload requested it; a reload-driven continuation no longer tells the
model to verify a change it never asked for.
* fix(agents): end a refresh continuation's reload wait when a gate never gives way
Autoreview: an unbounded wait for back-to-back reloads still needs each
settled gate to clear, so a stuck gate fails the continuation instead of
spinning.
* fix(plugins): hand a turn over only when every reloaded plugin can, and finish it as one turn
ClawSweeper on #185315:
- decide after the reload reserves all of its plugins; one undeclared plugin
keeps the whole turn waiting, so parking can't deadlock on a retained hold
- context-engine owners keep the default wait until logical-turn custody can
move with the turn
- agent_end and llm_output fire once, from the attempt that ends the turn
- a refresh continuation doesn't redeliver next-turn injections or rerun
agent_turn_prepare, and prompt hooks see the user's prompt
* test(plugins): prove turn handover on a real Gateway with declared, undeclared and mixed reloads
* docs(plugins): document reload.turnHandover and encourage reload-safe plugins
* fix(agents): let a reload hand a turn over only at a real step boundary
Autoreview: a reload can land during the final, tool-free model step or be
cancelled before the next step. The step boundary now rechecks that the
reload is still pending, and a reload-sourced refresh continues the turn
(and defers completion hooks) only when the attempt actually stopped there.
* fix(plugins): list the replacement watchers in the PR wrapper inventory
* fix(knowledge): give the bundled Knowledge plugin its memory category
Every bundled plugin needs exactly one purpose category. Knowledge was
bundled without one; the check only runs when manifest code changes.
* fix(agents): let admitted calls finish while a reload waits for the step boundary
A reload's handover request no longer fences tool calls: the reloading
plugin keeps serving this generation until the turn reaches its step
boundary. Only the run's own plugins-tool refresh invalidates the catalog.
* fix(gateway): report effective turn handover in reload status
Reload status now uses the same eligibility decision as the handover, so a
context-engine plugin that declares reload.turnHandover is reported as
waiting for whole turns.
* fix(agents): show authorized prompt hooks the user's request on a reload continuation
Authorized prompt enrichment such as memory recall received the synthetic
continuation prompt. Both prompt-build phases now share one event carrying
the user's request; the model still gets the continuation prompt.
* fix(plugins): identify Gateway preparation lease owners
Attribute preparation references to the run and Gateway turn service through the existing diagnostic frame. Keep active work and disposal semantics intact; retain log owner redaction. The completed-run leak did not reproduce in the isolated Gateway fixture, so this change repairs attribution only.
* test(plugins): isolate preparation ownership observations
Use the exact test-local owner observations instead of asserting a cumulative mock call count shared with earlier agent handler tests. The full 412-test agent handler file passes.
Show recorded plugin provenance in the compact plugins list and share the trust formatter with verbose output. Keep listing metadata-only and state that provenance is not a safety guarantee.
The verbose and narrow-terminal regressions fail on the base and pass on the reviewed head. Exact-head CI is green; inspected synthetic before/after images are in the PR. An installed CLI/Gateway run was not performed because it required a full build.
Co-authored-by: SunnyShu <265248434+SunnyShu0925@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
## What Problem This Solves
Fixes plugin metadata builds and validation hanging when `package.json` or `openclaw.plugin.json` is a FIFO with no writer.
## User Impact
Authoring commands reject pipes and special files promptly without rewriting project metadata. Regular files, supported symlinks, valid Unicode, and malformed-JSON diagnostics retain their existing behavior.
## Why This Change Was Made
The shared authoring reader resolves symlinks and delegates admission to `readRegularFileSync`. It also uses `decodeUtf8Input` for the existing strict UTF-8 requirement, removing the duplicate byte check and the proposed custom descriptor-management code.
Thanks to @Leon-SK668 for the original fix and Linux CLI reproduction.
## Evidence
- Red on the unchanged main reader: the special-device package regression reached JSON parsing instead of rejecting the nonregular input. Green with the fix.
- Real-filesystem FIFO regressions cover both metadata files, without I/O mocks, and verify that the pipe and sibling metadata remain unchanged.
- `node scripts/run-vitest.mjs src/cli/plugins-authoring-command.utf8.test.ts --maxWorkers=1`: all 7 tests pass, including existing malformed UTF-8 refusal, metadata preservation, and valid Unicode controls. Wrapper wall time 25.37 s; Vitest duration 13.10 s. These tests import a synthetic plugin through the production build/validation owners.
- Production +5/-6 (net -1), tests +33, documentation +3.
The contributor's built Linux CLI evidence at `c023e6b5c3a04c8dddb7a2c042ba5d158ea42b62` reports baseline timeouts, prompt FIFO refusals after the fix, successful regular-file builds, and validation through a linked package file. This revision was exercised through real filesystem/build/validation owners; the built CLI and live Gateway were not rerun because they require a separate full build, and this path does not use a model or channel.
Targeted oxlint, oxfmt, and diff checks passed. Independent P0–P2 review found no actionable defects. Additional authoring controls passed for stable JSON and malformed JSON. The symlink-root permission control fails identically with the unchanged reader and this change on macOS: directory mode is `01770`, expected `03770` (`plugins-authoring-command.test.ts:564`). This reader does not change directory permissions; the failure is retained as baseline evidence rather than weakened.
After merging current main, the final diff remained byte-identical to the reviewed candidate. All 7 encoding and special-file tests passed again (21.09 s wrapper wall time; 12.14 s Vitest duration).
Known diagnostic limitation: the canonical reader's nonregular-file error does not name which metadata file was rejected. The P3 suggestion to add authoring-specific error wrapping is left as a follow-up to keep this fix at the shared admission boundary; FIFO refusal and file preservation are covered above. Fresh built-CLI proof remains unrun as noted above.
Co-authored-by: Leon-SK668 <0668001470@xydigit.com>
Fixes#169842. When held files (Windows EPERM) block a plugin package swap, the transaction now restores missing files, preserves surviving ones, and keeps a named recovery backup if restoration cannot finish; it retires the displaced directory identity so inode reuse cannot erase recovery details. Resolved-version and pin guidance unchanged. Supersedes #170993, thanks @libaojiang.
Co-authored-by: libaojiang <2461443384@qq.com>
* fix(status): show plugin reloads that block new agent runs
A parked `openclaw plugins reload --wait` holds the plugin replacement gate,
so new agent runs wait, but status and status --json reported nothing.
Project the Gateway's existing plugin reload record into the status RPC with
its start time and whether new runs are blocked, and show it in the overview.
* fix(plugins): bound reload waits and report blocked work
Limit --wait to the existing ten-minute plugin lifecycle wait budget, preserve admitted work through rollback, and project owner reload status into CLI status. Consolidate regression coverage in existing fake-clock and Gateway reader fixtures.
Co-authored-by: yxshee <84263676+yxshee@users.noreply.github.com>
* test(status): isolate plugin reload overview coverage
* docs(status): clarify reload rollback visibility
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: yxshee <84263676+yxshee@users.noreply.github.com>
* feat(plugins): default unprefixed packages to ClawHub
Use the shared source planner for CLI, chat, and assistant installs. Keep explicit npm and local sources, preserve canonical built-in shortcuts, and retain the selected registry in update and repair records.
Autoreview findings addressed:
- [P2] Preserve ClawHub provenance in search hints that match aliases
Route scoped packages through ClawHub and add @latest to ambiguous unscoped search hints.
- [P2] Preserve usable search hints for scoped names with file suffixes
Treat file-suffixed package names as registry specs, migrate source-selection tests, and retain npm in retry guidance.
- [P2] Update the remaining source-selection test expectations
Treat file-suffixed package names as registry specs, migrate source-selection tests, and retain npm in retry guidance.
- [P2] Keep npm prerelease retry hints on npm
Treat file-suffixed package names as registry specs, migrate source-selection tests, and retain npm in retry guidance.
- [P2] Restrict catalog shortcuts to canonical plugin IDs
Restrict bare shortcuts to canonical IDs and retain npm in shared hook-pack prerelease guidance.
- [P2] Preserve npm in hook-pack prerelease guidance
Restrict bare shortcuts to canonical IDs and retain npm in shared hook-pack prerelease guidance.
* docs(plugins): show ClawHub as the default install source
Update setup examples and generated inventory instructions to omit the ClawHub prefix. Document explicit npm selection and canonical plugin-ID shortcuts.
* fix(plugins): keep recovery tied to the selected source
* test(plugins): cover search commands and saved registry choices
* test(plugins): align pre-action recovery with selected sources
* test(plugins): prove source-bound recovery through the CLI
* fix(plugins): retain official identity during config recovery
A plugin selected through plugins.load.paths has no install owner, so
plugins update resolved it with resolveLifecycle, recorded an ownership
rejection, and aborted the whole --all run with refresh-registry advice.
Use the ownership resolver's resolveUpdate like openclaw update already
does. Operator-managed plugins are reported with the shared
plugin-operator-managed warning and skipped, so remaining plugins still
update and a named update no longer fails.
* fix: hand off plugin reloads after agent turn cleanup
Co-authored-by: jacobtomlinson <1610850+jacobtomlinson@users.noreply.github.com>
* fix(tooling): include session display dependencies in PR wrapper
Restore the materialized wrapper runtime closure after session previews began importing the chat media display helper. Include the five existing runtime files reached through that helper.
Proof: all three affected inventory/extraction assertions fail on main and pass with this inventory-only repair. Focused closure checks: 4 passed in 22.37s; extracted dependency check: 1 passed in 16.21s. Independent isolated review found no actionable issues.
Co-authored-by: jacobtomlinson <1610850+jacobtomlinson@users.noreply.github.com>
* test: prepare session creation before loopback RPC deadlines
Prepare the real sessions-create handler alongside chat before request deadlines begin. Cold handler import consumed 6.3 seconds in the pinned baseline fixture; preparation keeps the lifecycle reply assertion from depending on module-load speed without increasing RPC timeouts or changing production behavior.
Co-authored-by: jacobtomlinson <1610850+jacobtomlinson@users.noreply.github.com>
* fix(tooling): use the upstream wrapper inventory at merge
The current-main merge already contains the session display inventory repair. Carrying the older insertion independently duplicates chat-display-projection.helpers.ts when Git combines its moved context. Remove the redundant carry-forward so current main remains the sole inventory source; no handoff implementation changes.
Co-authored-by: jacobtomlinson <1610850+jacobtomlinson@users.noreply.github.com>
---------
Co-authored-by: jacobtomlinson <1610850+jacobtomlinson@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
A partial update could leave @openclaw/codex 2026.9.5 installed on a newer host; its open-ended pluginApi range admitted it and every turn failed on the removed agent-harness-task-runtime SDK subpath. Version-bound official runtimes below a published compatibility floor (codex 2026.9.7) are now unavailable at admission with update repair / plugins update guidance; compatible older versions keep loading while update and repair converge them to the host cohort. plugins update now prints failure reasons. Fixes#168748, #168749. Refs #168498.
Guard local plugin install and hook fallback, uninstall, enable/disable, registry repair, updates, marketplace snapshot writes, and hook configuration writes with the existing local-state owner. Preserve existing Gateway lifecycle RPC routes and offline behavior; refuse local writes while the Gateway owns state with stop-and-rerun guidance.
Reuse effect-time ownership checks without adding cancellation settlement, compensation, fencing, or a new lease protocol. A Gateway starting mid-command is covered by the existing guard at the effect.
Supersedes #168420. Focused remote tests cover the command boundaries and existing migration behavior.
After an upgrade Doctor keeps an old registry install record but selects the bundled copy of a plugin; openclaw plugins reload then routed through package-owner validation and refused with 'no authoritative package-owner metadata', so a config change needed a full Gateway restart. Reload now follows the selected bundled plugin; any record whose path or owner claims that root still requires strict package validation. Closes#161193. Reported by @mbelinky.
Stable official ClawHub installs (catalog and plugins.install source=official) resolved ClawHub's newest release, so after 2026.9.9 shipped a 2026.9.7 host received @openclaw/perplexity-plugin@2026.9.9 (pluginApiRange >=2026.9.9) and refused it. Managed installs now opt into the existing release-channel resolver's same-version selection for official stable installs and fall back to the default spec only when that build is not published; plugin updates and drift detection keep their registry target. Incompatible refusals now tell the operator to upgrade OpenClaw or choose an explicit plugin version. Beta and extended-stable behavior unchanged; operator pins stay strict. Closes#167382. Reported by @charlesBerg-ux.
* perf(gateway): refresh derived plugin metadata after readiness
Serve validated startup metadata without persisting its optional cold registry cache first. Reuse the existing post-ready lifecycle and registry refresh owner, retaining synchronous config recovery and database compatibility checks.
* fix(plugins): preserve leased registry refresh across workers
Refresh derived registry metadata through the existing shared-state worker
without delaying Gateway readiness or replacing its active plugin snapshot.
Retain the lifecycle lease through transaction and commit, preserve pinned
install roots and candidate ownership, and exclude Doctor callbacks from the
worker payload. Keep process-bound crash reclamation for startup maintenance.
Remove the unused synchronous writer export and cover real worker transport,
Doctor repair, cancellation, and admitted source preservation.
* test(startup): preserve recovery and lease custody coverage
Use real backup recovery to acquire the startup lease before racing an
active-config change. Keep refusal, file-preservation, and cleanup checks.
Allow the refresh owner to wrap assertCurrent while retaining the original
lease fields in plugin update custody assertions.
* fix(plugins): preserve registry refresh worker contracts
Send Windows environment entries across the worker boundary and restore
case-insensitive semantics at the consumer without changing lease fencing.
Prepare the deferred commit-failure fixture once, and cover read failures at
the shared persistence kernel used by workers and install transactions.
Proof: Blacksmith Testbox tbx_01m4bv9q8rzrttx7ytw5a8288t; 206 registry,
Doctor, and environment tests plus 59 worker error tests. Selected changed
gates and final lint replay passed. Independent review through P2 is clean.
Reconcile unchanged config observations through the config owner after retained
work drains, before testing replacement authority. Busy forced installs now
apply their own replacement while newer config still supersedes stale work.
Cover retained work, active calls, and consumers with the real config reload
owner. Keep the synchronous publication check and consolidate repeated checks.
## What Problem This Solves
Plugins whose manifest ID contains uppercase letters (for example `MiXeD-demo`) behaved inconsistently across the plugin lifecycle, because some code paths looked them up by their case-preserved manifest ID in maps keyed by the canonical lowercase policy ID:
- Offline `openclaw plugins disable/enable` failed with "Plugin not found".
- Uninstall succeeded but left a conflicting enabled policy entry behind.
- Enabling the plugin reported success, but its runtime methods were never registered ("unknown method"), both on live enable and on cold start.
- Invalid plugin settings (for example a number in a string field) validated as `valid: true`.
- Per-plugin LLM overrides/allowlists and memory-slot enablement settings were not applied to such plugins.
## Why This Change Was Made
Since `f94a7dc183`, plugin policy entries are keyed by a canonical lowercase identity while manifests keep their original casing; several consumers kept indexing with the raw manifest ID. This change routes every one of those lookups through the existing canonical metadata identity resolver (one shared policy-key helper), while preserving the exact case-sensitive runtime and package IDs:
- offline toggles (`src/plugins/management-mutations.ts`)
- uninstall policy cleanup (`src/plugins/uninstall-package-config.ts`, `uninstall-package-plan.ts`)
- Gateway startup/activation policy (`src/plugins/config-normalization-shared.ts` and consumers)
- settings validation (`src/config/validation-plugin-config.ts`)
- LLM policy lookup (`src/plugins/runtime/runtime-llm.runtime.ts`)
- memory slot policy (`src/plugins/memory-runtime.ts`)
## User Impact
Plugins with mixed-case IDs now toggle, uninstall, activate, validate, and receive their configured LLM and memory settings exactly like lowercase-ID plugins.
## Evidence
- Each site has a regression with a mixed-case plugin ID that fails before and passes after (toggles, uninstall, live and cold-start activation including disabled/denied plugins staying unavailable, eight validation cases, LLM overrides/allowlists, memory slot enablement).
- Final head: 540 tests across 27 related files, core typecheck, all 27 test TypeScript graphs, formatting, and oxlint pass on Blacksmith Testbox; earlier: full build, 503 unit, 124 Gateway, and 46 browser E2E tests, plus live CLI install/update/uninstall flows across copy/link/archive/git/npm/bundled sources.
- Full `check-changed` was cancelled by the Testbox provider during its last phase; exact-head CI is the final gate.
- Production +165/-114 LOC (mostly moving lookups onto the shared resolver); tests +386/-74.
Not changed here: a concurrent enable/disable pair can surface only a generic "The CLI command failed" message (`src/cli/failure-output.ts`); improving that copy is a separate product change.
Bundled plugins only shared the host loader when their entry was compiled
JavaScript, so a source checkout captured all 87 bundled packages (copy, hash,
and dependency materialization) on every prepared model runtime publication:
79.5 s of plugin discovery per agent turn, which exceeded the 120 s budget on
a loaded host. Bundled plugins now take the shared host loader regardless of
entry extension, the edited-code warning keys on the canonical export so it
survives loader interop wrappers, and the docs describe source and compiled
bundled identity together.
Discovery for the live embedded-runner case fell from 79.5 s to 12-13 s and the
case from ~100 s to ~25 s on the same host. Editing a bundled plugin's
TypeScript source now needs a Gateway restart, matching compiled bundled code;
installed, external, workspace-path, and standalone plugins keep captured
source reload semantics.
The v13 wide-row state migration conflated a missing installed_plugin_index row with a row whose JSON was unparseable or shape-drifted, and dropped the table in both cases. An invalid row is now preserved in full in the existing diagnostic_events quarantine with repair guidance recorded, valid install records are retained independently of damaged metadata, and a preservation failure rolls the step back to v12. No schema change.
Closes#161329.
Landed under the pre-existing-red rule: the remaining CI failures were current main reds at this base (Codex app-server settlement fixture drift, fixed on main by 52e60fb42b; the subagent kill-tombstone / descendant-cancellation intermittent first seen on main hourly 36619831492).
* fix: migrate retained plugin settings before update activation
Complete selected plugin-owned config repairs through the existing update and replacement-install lifecycle before activation. Preserve pending obligations with actual config rollback, retain published package generations when rollback is unconfirmed, and refuse unresolved active inputs without suppressing committed partial updates.
* test: align replacement-install warning fixture snapshots
* fix(startup): keep legacy state repair in doctor
Separate current-state startup readiness from explicit Doctor migrations.
Preserve current config recovery, quarantine, device identity checks,
lease fencing and updater completion ownership.
Remove automatic startup migration/checkpoint and node-host import paths.
Keep shipped read-only context and roster projections unchanged.
* test(doctor): align proof callers with repair ownership
Keep survivor fixture setup in caller order and select the shared Doctor
flow separately from the channel-specific proof. Include the complete
isolated diagnostics dependency closure.
Prove ordinary startup preserves legacy directories before explicit
Doctor repair, and await SQLite worker closure before test cleanup.
* test(startup): verify index repair through gateway maintenance
* test(doctor): align cutover fixtures with state owners
Reacquire the database after Doctor retires its generation, retain real session history for startup refusal, and keep pending reads at their actual owners. Distinguish the reused readonly reader from independent snapshot-token children and verify every child settles.
* fix(doctor): preserve image activation and published migration receipts
Run the shared noninteractive Doctor owner before default and Compose Gateway
activation so retained Docker volumes keep their published upgrade path while
ordinary Gateway startup stays readiness-only. Preserve root selectors and
settle interrupted repair before executing the original command.
Retain the path-wide tombstones emitted by the published restart-sentinel
importer, including consumed notices, and validate completed source decisions
before retiring recreated inputs. Add the root-image activation lane and causal
receipt coverage without introducing a schema, option, or second importer.
* test(docker): preserve release state pairs in upgrade proof
Use the existing synthetic v2026.9.2 corpus instead of combining a July shared database with a later agent schema. Preserve its deletion journal, registry, both transcript payloads, paired backups, and unsafe-state controls. Register the two shell-launched helpers with Knip.
* test(docker): normalize persisted schema snapshot rows
Compare node:sqlite schema rows using the same plain-object representation as the saved JSON preimage. Keep strict schema, row, and value-type assertions intact.
* fix(models): retain discovered models after refresh failures
Record successful legacy catalog results at the producer boundary so unavailable refreshes retain the accepted inventory. Preserve explicit outcomes, advisory SDK fallback behavior, and first-discovery starter policy.
* fix(models): preserve skipped catalog outcome semantics
Mark bundled static, configured, and advisory catalog projections with
explicit empty outcomes so legacy success inference cannot promote them
to observed account inventory. Preserve live outcomes and helper types.
Keep exact auth provenance histories and move existing fixture/policy
code into focused owners where required by the line-cap ratchet.
Validation: 447 producer and sibling cases, 56 shared self-hosted cases,
95 auth/policy cases, causal missing-outcome failures, maintained checks,
and independent review.
* test(plugin-sdk): keep discovery loader types acyclic
Move the shared loader type into a leaf consumed by both discovery
contract helpers. Preserve its public provider-test-contracts export
without a child-to-parent type import cycle.
Validation: maintained Madge check reports zero cycles; core, all core
test graphs, extension test types, lint, formatting and independent
review pass. Runtime behavior and previous catalog proof are unchanged.
* fix(plugin-sdk): mark generated static catalogs explicitly
Keep the generated non-live, non-strict catalog adapter from claiming
successful acquisition for manifest or configured rows. Preserve null,
errors, strict and custom callbacks, static catalogs, and public types.
Validation: three existing controls fail before the correction; all49
owner and sibling cases pass afterward, with types, lint, line caps and
fresh independent review clean.
* test(gateway): cover restart import during state retirement
Exercise canonical database close while a legacy notice read is paused. Verify admission rejection, retained canonical and source bytes, no migration receipt, and joined maintenance custody without changing the accepted sidecar-stop drain contract.
* fix(test): drain sharing fixtures before removing state
* test: bind retirement regression to its own worker
* docs(docker): clarify automatic Doctor activation
* test(doctor): keep readiness fixture runtime private
* test: stabilize shared skill watcher fixture roots
(cherry picked from commit 15606be10ed61be99931fcf3bb300ebdb475ad89)
* perf(tooling): share indexed scope parsing for artifact scans
(cherry picked from commit 6e6eef9f5b556e0005b16363169e6a85cd310ad0)
* fix(team-reports): use source owners in scheduler tests
The source barrel retired in #157819, but the scheduler tests still imported
it, breaking the extension test typecheck on main. Import the Discord and
GitHub owners directly, matching the production caller.
Validated the original TS2307/TS7006 failure, the corrected extension type
graph, all 36 scheduler tests, changed checks, and independent P2 review.
(cherry picked from commit 7c4866c73b)
* test(install): isolate global npm configuration in version fixtures
Use a controlled absent global config inside the fixture home so the
release helper does not query the deliberately narrow npm stub. Keep
predecessor selection, fresh-install behavior, and expected exits intact.
(cherry picked from commit 0a9eefc76c82d81bd134add3ac3d269ae1b607bd)
* test(docker): verify the complete image activation entrypoint
Include registered archive installs in the existing host-link repair owner so Doctor and post-update convergence can recover stale or dangling SDK links without the original archive. Preserve canonical install-root, path ownership, and lifecycle authority checks.
Reserve busy plugin replacements before gating new agent work, then let
admitted runs finish on their original instance before teardown. Report
queued retained work and completed publication through existing diagnostics.
Preserve the 60-second pre-stop budget, timeout recovery, and shared-resource
cleanup before replacement registration. Cover overlapping runs, installed
version publication, and retained cleanup without introducing configuration.
* refactor: remove TypeScript 6 from plugin runtime and tooling
Keep source plugin loading on Jiti and native module transforms, move development analysis and declaration builds to TypeScript 7, and preserve captured loader and input ownership contracts. Scaffolds compile to the same entry path without shipping a compiler in production.
* refactor: use native checker for restart preflight detection
* fix: keep test-directory docs out of native helper scans
* fix: preserve native compiler tooling across CI runtimes
Keep compiler-backed tests on the supported Node transport, preserve declared Windows aliases and partial-source analysis, and bind relocated SDK reports to their installed compiler. Retain strict package input admission and the existing fixture assertions.
* test: compare messaging guard diagnostics without sorting
* fix: bound native tooling memory and preserve bootstrap loading
* fix: bound native declaration builds with tsdown scheduling
* fix: retire compiler-only helpers from installed packages
* test: migrate routing import scan to native parser
* test(ui): wait for recovered model catalog receipt
* fix(plugins): show the selected entry after reload
Expose the loader-owned selectedEntries map in runtime receipts. Add bounded CLI and tool guidance to rebuild compiled output after source edits while preserving success and restart outcomes.
* fix(protocol): sync generated plugin reload receipt
Regenerate the protocol outputs for optional selectedEntries. The Swift model gains the field, default-nil initializer argument, and wire coding key; Kotlin outputs remain unchanged.