docs(website): Rspress docsite audit — every P1/P2 from #590 plus cheap P3s - #599
Conversation
…ocsite; pin docs.yml actions; Dependabot scans composite actions (#590 lane E) website/scripts (plain Node >= 22, no dependencies), wired into the website `check` script that `pnpm docs:site:build` and docs.yml run: - check-locale-drift.mjs: every authored en/ page needs a zh/ twin with the same fenced-code count, the same code per fence (comments stripped in sh/bash/ts/tsx/js/json fences, trailing `# note` in text tree listings), the same ABnnnn code set, the same table-row count, and an h2/h3 count within 2; _meta.json/_nav.json must match in entries, order, and link targets modulo the /zh prefix. Rspress's languageParity compares only the set of page paths. - check-built-links.mjs: post-build walk of doc_build/**/*.html (+ sitemap <loc>s) resolving every site-internal href/src/og:url honouring cleanUrls and requiring each #fragment to name an id in the target. Rspress's own checks see only mdast links, so frontmatter hero/feature links, _nav.json, raw <a href>, and every generated page were unchecked, and a warm persistent cache let dead anchors into unchanged pages pass. - check-diagnostics-coverage.mjs: every ABnnnn cited in website/docs {en,zh}/**/*.mdx and (strict, `--no-src` to skip) every ABnnnn literal in packages/agent-bundle/src must have an explicit row, range row, or code heading in docs/diagnostics.md; family catch-all rows do not count. website `check` builds with RSPRESS_PERSISTENT_CACHE=false (the variable @rspress/core reads to disable Rsbuild buildCache) so the anchor checks run against a cold compile. Drops the two website devDependencies nothing imports (@types/react-dom, agent-bundle); lockfile regenerated with `pnpm install --lockfile-only`. The root `typecheck` now also runs the website tsconfig (config, plugins, theme), which only `docs:site:build` compiled before. docs.yml pins actions/checkout, upload-pages-artifact, configure-pages, and deploy-pages to full commit SHAs (job name unchanged; it is a required check). dependabot.yml scans /.github/actions/* so the composite setup-workspace action's pnpm/setup pin is updated too.
…r, sidebar/nav tidy-ups (#590 lane A2) - rspress.config.ts reads `compilerOptions.paths` from tsconfig.typedoc.json (JSONC, via ts.readConfigFile), makes the targets absolute, and merges them with the four `agent-bundle*` entries for pluginTwoslash, so `@agent-bundle/runtime*` and `rsc-markdown-stream` resolve to workspace sources without `pnpm build`. The 12 `: any` hovers on guide/development/testing (en + zh) are gone; the tsconfig comment now states that this file is the single source of the map. - ssg.experimentalWorker: true; builderConfig.performance.printFileSize.detail: false. - head: static theme-color meta. Per-route canonical/og:url functions are left out: renderPages passes config.head to the SSG worker threads through workerData, and a function fails structured cloning (DataCloneError). - themeConfig.footer: Apache-2.0 message (home layout). - Remove transformerNotationDiff/Focus (no [!code ++/--/focus] in docs) and search.codeBlocks (restates the default); TypeDoc index title template drops the empty {version} placeholder. - api/_meta.json: collapsed: true on the six dir groups, both locales. - _nav.json: "Type API" links to the hand-written /reference/api overview; activeMatch covers /api/ and /reference/api, both locales. - mirror-api-locale: per-target `notice`, inserted as an :::info container directly under the title of every mirrored zh/api page. - docs/public/robots.txt with the sitemap URL.
Add explicit rows for the 103 emitted codes in AB3000–AB4716 that were covered only by a family catch-all (AB30xx, AB40xx–AB46xx, AB470x/AB471x), plus dedicated sections for AB4500 and AB5000, whose only mention was the Code families summary row. New sections sit after the Code families table. Adds the missing AB4204 and AB5000 rows; gives AB4716 a table row in its Declaration generation section; folds the AB4834 recovery text into its Trigger cell so the row matches its three-column header (GFM was dropping the fourth cell). Every emitted code in AB0000–AB5999 now has an explicit row; no ragged table rows remain in the file. Refs #590
(lane C) - reference/cli: exit-code rows 1/2 state which option validators throw Commander InvalidArgumentError (exit 2) versus a plain TypeError reported as one AB5000 diagnostic (exit 1), per src/cli.ts and runCli. - guide/authoring/hooks: result-contract table and per-event bullets match hook-handler.ts / hook-contract.ts — no event admits outcome 'stop', Cursor alone tolerates a denying agentStart, only Claude carries additionalContext from agentStop. - reference/configuration: targets defaults to ['portable'], marketplace to false; evals and routes ride the AgentBundleConfig index signature, evals rules fire as EVAL_* errors when an eval or the Workbench loads the config. - Tighten 13 en frontmatter descriptions to <=160 code points. - Reflow every fenced code line over 90 columns in en (36 -> 0) and mirror the identical reflow in the zh twin fences (28 -> 0); zh prose untouched.
…sult contract, config defaults and untyped evals/routes Chinese twins of the lane-C English corrections for the docsite audit: - reference/cli.mdx: exit code 2 is only a Commander error (unknown option, missing argument, InvalidArgumentError from --profile/--allow/doctor --host); the install <host>/--scope/--mode/--port/--trials validators throw a plain TypeError that runCli reports as one AB5000 diagnostic with exit 1. - guide/authoring/hooks.mdx: outcome is continue or deny (no event accepts stop); agentStop additionalContext is rejected on Codex and Cursor, only Claude Code carries it; the typed contract rejects an agentStart denial while Cursor's wrapper tolerates one with a reason. - reference/configuration.mdx: targets defaults to ['portable'] (--target overrides), marketplace defaults to false; evals and routes ride the index signature so tsc does not check them — evals rules fire at eval time (EVAL_CONFIG_INVALID), routes overrides are validated during route discovery and reported through validateSource. Prose only; no fenced code block, heading, table row, or AB code set changed.
…ises regex alternatives
…ane B2) Add explicit rows or explicit ranges for the 121 agent-bundle codes in AB6000–AB9999 that only a family row covered: built-artifact validation (AB6000–AB6004, AB6006–AB6018, AB6023–AB6025), Workbench artifact inspection (AB6200–AB6202), install/uninstall and project-preparation codes (AB7000–AB7004), the AB7103 package-build warning, the whole AB80xx development-server surface grouped by route module, the route-manifest client code AB8123, and the eval API refusals AB9001–AB9005/AB9007–AB9011. Refine the AB6xxx–AB9xxx family rows. AB6005 is left untouched for PR #588.
…rch indexing (#590) LocalProvider.init() fired addAsync() for every document without awaiting, so SearchPanel flipped initStatus to 'inited' while FlexSearch was still indexing and an early query rendered 'No matching results' for documents that had not been added yet (8/8 trials with a late-indexed query on the 971-document en index). Collect the three addAsync promises per item and await them before init() resolves; PageSearcher hard-codes the provider, so a pnpm patch is the smallest fix. Upstream main still has the bug.
…th in the docsite theme (#590) - EditLink: return null on TypeDoc pages (<lang>/api/**), point the generated reference pages at their sources (capabilities JSON directory for hosts/events/notices, docs/diagnostics.md for diagnostics), and defer to the original everywhere else. The patterns track .gitignore lines 20-27. - LlmsCopyRow / LlmsOpenRow / LlmsHint: render nothing when the route path includes /api/, mirroring the pluginLlms exclude, so the outline no longer offers Copy Markdown / Open in chat for the 1,832 routes that have no Markdown twin. - NotFoundLayout: cleanUrls emits quick-start.html, so a trailing-slash URL is a 404 on GitHub Pages; retry without the slash (query and hash kept). - Desktop layout tokens (>= 1280px): sidebar 320 -> 280, outline 268 -> 240, content padding 80 -> 48. At 1440x900 the code scroller grows from 686 to 818 px, so 92 monospace columns fit (was 76 once Shiki's line padding is paid) and a 90-column line no longer scrolls; overflowing fences on the 33 authored en pages drop from 59/169 to 23/169, all of them >= 93 columns.
…ed code has a row
🦋 Changeset detectedLatest commit: 9f7d238 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
…ce fits 90 columns
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
… says recovery where the diagnostic carries one
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f1466396d7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -0,0 +1,5 @@ | |||
| --- | |||
| "agent-bundle": patch | |||
There was a problem hiding this comment.
Remove the package bump from this docs-only change
This commit does not modify any shipped file under the four publishable packages, but this entry causes the next Version Packages run to bump agent-bundle and add a changelog entry anyway. The repository explicitly treats website as private and requires changesets only for changes to publishable packages, so this documentation/CI-only change should not carry an agent-bundle changeset.
AGENTS.md reference: AGENTS.md:L138-L143
Useful? React with 👍 / 👎.
| } | ||
| comparePages(relative, analyzePage(fs.readFileSync(path.join(enRoot, relative), 'utf8')), analyzePage(fs.readFileSync(twin, 'utf8')), failures); | ||
| } | ||
| const metaFiles = walk(enRoot, isMetaFile); |
There was a problem hiding this comment.
Check locale metadata in both directions
When a _meta.json or _nav.json is added only under an existing zh/ directory, this loop never sees it because it enumerates metadata exclusively from enRoot. Rspress language parity covers Markdown page paths rather than these JSON files, so such Chinese-only navigation/sidebar drift passes pnpm docs:site:build; enumerating the union of metadata paths from both locale roots would close the gap.
Useful? React with 👍 / 👎.
… AB4100 lists the four hosts, AB6023/AB6024 and AB7001 describe the one root
…ections; remove the plugin target (#555 W1) (#578) * feat(targets): remove the plugin target from the public target model (#555 S1) - config/normalize.ts no longer synthesizes a plugin lowering target or a shared plugin skill document; loweringHosts is a pure isSkillHost filter. - adapters/registry.ts registers portable, codex, claude, cursor only; adapters/plugin.ts is deleted together with the composite-only capability helpers (intersect/union/mergeCapabilityEvidence, capabilityBooleanView). - targets: ['plugin'] and --target plugin fail with the existing AB4100. - plugin branches removed from api.ts, pack-inventory, package-build, entry-shell, events/projection, lifecycle replay, install/surface, install/install, create-agent-bundle options/scaffold, capability JSON, and the CLI help text. - Tests: plugin-bundle.test.ts deleted; plugin rows dropped from the adapter, install-surface, normalization and lifecycle suites; acceptance 3 covered by normalization.test.ts and cli.test.ts. * feat(build): plan the selected projections into one composite root (#555 S2) build/build.ts stages every selected host projection into one root at artifactRoot; build/compose.ts merges byte-identical entries once, fails same-path collisions with AB4103 in host-name/path order, and refuses host-scoped components another selected host would discover conventionally with AB4105. Codex and Cursor hook/MCP documents move beside their manifests; shared hooks compile to hooks/<name>.<host>.mjs; compiled surfaces are attributed to the sorted composite identity; the artifact manifest records only the selected projections. Install, doctor, dev services, eval harnesses, Workbench, examples, and tests follow the composite root. * feat(build): AB4106 for mixed advanced-registry selections; validate/inspect judge the composite root; port #569 consumer and docs fixes - config/validate.ts: AB4106 when an adapter registered on an advanced TargetRegistry is selected beside any other target; the built-in host list moves to adapters/composite-layout.ts and install/surface.ts imports it. - build/compose.ts: planComposite returns the plan beside its diagnostics; dev/project-service.ts prepare uses it so validate, inspect, dev report AB4103/AB4105 exactly where build refuses (caught by the composite-rules parity test ported from #569). - Ported from #569 (superseded): tests/support/mcp-conformance.ts pluginRoot, tests/skill-document-service.test.ts decoy, examples/audiobook-curator and examples/hooks-and-scripts READMEs, scripts/measure-hook-cold-start.mjs. - tests/composite-rules.test.ts: layout-independent rules from #569 (four-host root, commands/ dialect collision, INSTALL.md sections, validate parity). - Stale per-host wording: Cursor capability evidence, doctor/types/cursor comments, create-agent-bundle README, docs/diagnostics.md, canvas sample. * test(packed): read the composite root's bin/ and single mcp/ entry in the packed pool * fix(inspect): describe the same event allowed-targets set the build bakes into a generated-route server; AB4105 trigger names skills * build: carry #585's MCP App compile diagnostics through the composite root; mcp-apps-compile test selects the portable projection * test(cli): MCP App compile report attributes the view to the composite selection identity (codex+portable), matching planCompiledMcpApps after the #585 merge * build: identify the event runtime by the artifact alone; port #569's nested-root and shared-root tests (#592 boundary) The generated MCP entry and every hook wrapper derived the event runtime's endpoint id from `<epoch>:<selection identity>:<root>`, so the composite selection (`claude+codex`) had become runtime identity, and the runtime took `events.target` as the tool-call lineage host fallback, reading the selection as a host. Both are projection selection leaking into runtime identity (#592 §2). The endpoint is now `<epoch>:<root>` on both sides (entry-shell, hook-contract, `agent-bundle/test` installed harness), the `target` field leaves `GeneratedRouteMcpEntryOptions` and `GeneratedEventRuntimeBinding`, and the lineage fallback is the one host a single-projection root serves, or none for a composite root; `entries.ts` requires the selection instead of defaulting it from the composite name. `AB4105` never fired for a skill: normalization gives every skill every selected target and per-host frontmatter extensions collide as `AB4103` instead, so the dead skill branch leaves `compose.ts` and the diagnostics, reference, and framework-mode prose say so. `AGENT_BUNDLE_HOOK_HOST` leaves the runtime-environment reference (en/zh) and the test env fixtures; `api.ts` reuses `isBuiltInHost`; `compose.ts` reuses `sortedProjections`; stale `<target>/…` doc comments in `test/packed.ts` and `routes/graph.ts` name the root layout. Ports from #569: install refuses `--from` naming a directory above the plugin root for all three hosts (`AB7001`, no host CLI runs), doctor lists Claude plugins from the root `--from` names and never from a nested `claude/`, and the Codex validator judges only `.codex-plugin/*` in a root shared with Claude's `.mcp.json` and `hooks/hooks.json`. Lane C's docs parity pass: tree drawings gain `commands/` and `rules/`, the folder-discovery shield names all three guarded paths, over-wide code samples re-padded to 90 columns, `AB4808`/`AB4809` prose and the rsc-agent-runtime README describe one composite root. * test(prepack): #588's prebuilt payload lands in the composite root (host-packs/runtime/…), not under a target partition * changeset: the event runtime endpoint is the artifact's alone (#592 boundary) * review: lineage fallback is the one host whose MCP document lists the server; document AB7001's composite-root trigger Self-review pass 1 read the fallback as inferring the root's cardinality from `allowedTargets`. It is `server.targets ∩ selected` — the hosts whose MCP documents list the server, so the hosts that can have spawned it — and a Claude-only server in a Claude+Codex root is correctly assumed to be Claude's. The comment and the two test names now say so. `docs/diagnostics.md` names `AB7001` in the `AB700x` family row: the host manifest sits directly under `--from`, never under `<from>/<host>`. * build: host the composite root's event runtime per selected host's first generated server; judge built-in hosts by adapter identity for the install surface (#578 review) - planMcpEntriesSurface no longer attaches every event route to the first generated-route server: eventRuntimeHosting hosts the runtime in the first generated server each selected host's MCP document lists (one process when they agree, one per host otherwise) and every hosting server accepts the same allowed set; a Claude-only server in a Claude+Codex root no longer refuses Codex wrappers while Codex's own server hosts nothing. - The generated entry carries `hosts` (the selected hosts whose documents list the server) separately from `allowedTargets`; the lineage fallback reads `hosts`, so a Claude-only server hosting a two-host runtime still assumes Claude for an anonymous MCP client (#592). - TargetRegistry.builtInHost()/builtInHosts() judge the four shipped adapters by identity; compose and artifact validation use it for INSTALL.md and install.mjs, so an advanced registry's adapter named `portable` earns no install surface it never asked for. The pack inventory (manifest names only) keeps the name-based requirement it had on main. * test(browser): mount each MCP App as one host of the composite selection, never as the selection identity The browser pool compiles every app once for the project's whole selection (as the build stages it, #555) but the registry's `target` — the preview profile and the binding's `target` the page sees — is the host the app mounts as: the override, or the app's first declared target the project selects, as before. `claude+codex+portable` had leaked into the binding (#592) and failed examples/mcp-app's browser-app suite in CI. * docs: fold #599's per-code diagnostics rows into the composite root — AB4100 lists the four hosts, AB6023/AB6024 and AB7001 describe the one root * review: judge built-in hosts by adapter identity in AB4106 and --host-validation; the pack inventory expects exactly the manifested files - NormalizationTargetRegistry.builtInHost? lets config/validate.ts refuse a custom adapter registered under a built-in host's name beside other targets (AB4106) the way compose and validate-artifact already judge it; registries that cannot tell still judge by name. - validate --host-validation and build --host-validation select the shipped validators through registry.builtInHosts(), so a custom `claude` or `portable` adapter is held to no shipped host's contract. - pack-inventory.ts no longer re-derives the install surface from manifest target names: every emitted file is manifested and AB6023/AB6024 already judged the surface by identity, so the pack expects what the manifest lists. - Changeset names the browser pool's `target` option semantics. * docs: AB4106 judges the shipped adapters by identity * test: exercise host validation by adapter identity through validate --artifact and build --host-validation The identity test validated the project root, which never enters host validation; validate the built custom root as an artifact instead, and build a custom adapter named claude with a runner spy that must not be spawned. AB6024's row names the shipped cursor/portable adapters by identity, as the validator judges. * test: validate --artifact takes the project root too * test: a custom adapter under the portable name owes no install surface (AB6023/AB6024 by identity)
…rs read the composite root through the manifest (#592 step 3, #555 W2/S3) (#604) * feat(targets): remove the plugin target from the public target model (#555 S1) - config/normalize.ts no longer synthesizes a plugin lowering target or a shared plugin skill document; loweringHosts is a pure isSkillHost filter. - adapters/registry.ts registers portable, codex, claude, cursor only; adapters/plugin.ts is deleted together with the composite-only capability helpers (intersect/union/mergeCapabilityEvidence, capabilityBooleanView). - targets: ['plugin'] and --target plugin fail with the existing AB4100. - plugin branches removed from api.ts, pack-inventory, package-build, entry-shell, events/projection, lifecycle replay, install/surface, install/install, create-agent-bundle options/scaffold, capability JSON, and the CLI help text. - Tests: plugin-bundle.test.ts deleted; plugin rows dropped from the adapter, install-surface, normalization and lifecycle suites; acceptance 3 covered by normalization.test.ts and cli.test.ts. * feat(build): plan the selected projections into one composite root (#555 S2) build/build.ts stages every selected host projection into one root at artifactRoot; build/compose.ts merges byte-identical entries once, fails same-path collisions with AB4103 in host-name/path order, and refuses host-scoped components another selected host would discover conventionally with AB4105. Codex and Cursor hook/MCP documents move beside their manifests; shared hooks compile to hooks/<name>.<host>.mjs; compiled surfaces are attributed to the sorted composite identity; the artifact manifest records only the selected projections. Install, doctor, dev services, eval harnesses, Workbench, examples, and tests follow the composite root. * feat(build): AB4106 for mixed advanced-registry selections; validate/inspect judge the composite root; port #569 consumer and docs fixes - config/validate.ts: AB4106 when an adapter registered on an advanced TargetRegistry is selected beside any other target; the built-in host list moves to adapters/composite-layout.ts and install/surface.ts imports it. - build/compose.ts: planComposite returns the plan beside its diagnostics; dev/project-service.ts prepare uses it so validate, inspect, dev report AB4103/AB4105 exactly where build refuses (caught by the composite-rules parity test ported from #569). - Ported from #569 (superseded): tests/support/mcp-conformance.ts pluginRoot, tests/skill-document-service.test.ts decoy, examples/audiobook-curator and examples/hooks-and-scripts READMEs, scripts/measure-hook-cold-start.mjs. - tests/composite-rules.test.ts: layout-independent rules from #569 (four-host root, commands/ dialect collision, INSTALL.md sections, validate parity). - Stale per-host wording: Cursor capability evidence, doctor/types/cursor comments, create-agent-bundle README, docs/diagnostics.md, canvas sample. * test(packed): read the composite root's bin/ and single mcp/ entry in the packed pool * fix(inspect): describe the same event allowed-targets set the build bakes into a generated-route server; AB4105 trigger names skills * build: carry #585's MCP App compile diagnostics through the composite root; mcp-apps-compile test selects the portable projection * test(cli): MCP App compile report attributes the view to the composite selection identity (codex+portable), matching planCompiledMcpApps after the #585 merge * build: identify the event runtime by the artifact alone; port #569's nested-root and shared-root tests (#592 boundary) The generated MCP entry and every hook wrapper derived the event runtime's endpoint id from `<epoch>:<selection identity>:<root>`, so the composite selection (`claude+codex`) had become runtime identity, and the runtime took `events.target` as the tool-call lineage host fallback, reading the selection as a host. Both are projection selection leaking into runtime identity (#592 §2). The endpoint is now `<epoch>:<root>` on both sides (entry-shell, hook-contract, `agent-bundle/test` installed harness), the `target` field leaves `GeneratedRouteMcpEntryOptions` and `GeneratedEventRuntimeBinding`, and the lineage fallback is the one host a single-projection root serves, or none for a composite root; `entries.ts` requires the selection instead of defaulting it from the composite name. `AB4105` never fired for a skill: normalization gives every skill every selected target and per-host frontmatter extensions collide as `AB4103` instead, so the dead skill branch leaves `compose.ts` and the diagnostics, reference, and framework-mode prose say so. `AGENT_BUNDLE_HOOK_HOST` leaves the runtime-environment reference (en/zh) and the test env fixtures; `api.ts` reuses `isBuiltInHost`; `compose.ts` reuses `sortedProjections`; stale `<target>/…` doc comments in `test/packed.ts` and `routes/graph.ts` name the root layout. Ports from #569: install refuses `--from` naming a directory above the plugin root for all three hosts (`AB7001`, no host CLI runs), doctor lists Claude plugins from the root `--from` names and never from a nested `claude/`, and the Codex validator judges only `.codex-plugin/*` in a root shared with Claude's `.mcp.json` and `hooks/hooks.json`. Lane C's docs parity pass: tree drawings gain `commands/` and `rules/`, the folder-discovery shield names all three guarded paths, over-wide code samples re-padded to 90 columns, `AB4808`/`AB4809` prose and the rsc-agent-runtime README describe one composite root. * test(prepack): #588's prebuilt payload lands in the composite root (host-packs/runtime/…), not under a target partition * changeset: the event runtime endpoint is the artifact's alone (#592 boundary) * review: lineage fallback is the one host whose MCP document lists the server; document AB7001's composite-root trigger Self-review pass 1 read the fallback as inferring the root's cardinality from `allowedTargets`. It is `server.targets ∩ selected` — the hosts whose MCP documents list the server, so the hosts that can have spawned it — and a Claude-only server in a Claude+Codex root is correctly assumed to be Claude's. The comment and the two test names now say so. `docs/diagnostics.md` names `AB7001` in the `AB700x` family row: the host manifest sits directly under `--from`, never under `<from>/<host>`. * build: host the composite root's event runtime per selected host's first generated server; judge built-in hosts by adapter identity for the install surface (#578 review) - planMcpEntriesSurface no longer attaches every event route to the first generated-route server: eventRuntimeHosting hosts the runtime in the first generated server each selected host's MCP document lists (one process when they agree, one per host otherwise) and every hosting server accepts the same allowed set; a Claude-only server in a Claude+Codex root no longer refuses Codex wrappers while Codex's own server hosts nothing. - The generated entry carries `hosts` (the selected hosts whose documents list the server) separately from `allowedTargets`; the lineage fallback reads `hosts`, so a Claude-only server hosting a two-host runtime still assumes Claude for an anonymous MCP client (#592). - TargetRegistry.builtInHost()/builtInHosts() judge the four shipped adapters by identity; compose and artifact validation use it for INSTALL.md and install.mjs, so an advanced registry's adapter named `portable` earns no install surface it never asked for. The pack inventory (manifest names only) keeps the name-based requirement it had on main. * wip(manifest): artifact manifest v2 — projections, routes, executables, distribution; hook index folded into executables.hooks (#592 step 3) * test(browser): mount each MCP App as one host of the composite selection, never as the selection identity The browser pool compiles every app once for the project's whole selection (as the build stages it, #555) but the registry's `target` — the preview profile and the binding's `target` the page sees — is the host the app mounts as: the override, or the app's first declared target the project selects, as before. `claude+codex+portable` had leaked into the binding (#592) and failed examples/mcp-app's browser-app suite in CI. * test(manifest): retarget hook and MCP suites at the v2 artifact manifest The hook-index sidecar is gone; these tests now assert executables.hooks on agent-bundle.manifest.json and pass the required route graph into build(). * test: migrate manifest coverage to v2 * refactor: read install identity from artifact manifest * feat: inspect authoritative artifact manifest * docs: fold #599's per-code diagnostics rows into the composite root — AB4100 lists the four hosts, AB6023/AB6024 and AB7001 describe the one root * feat(cli): resolve MCP --target from the artifact manifest serve-app and mcp list|invoke|run default to the only projection that runs the named server, and inspect reports a built-manifest summary when one exists at the project's artifact output. * manifest: routes.cli.routes may hold projected MCP tool routes (routes.mcpCommands) * test(build-compose): TargetRegistry is constructed, keep the value import * review: judge built-in hosts by adapter identity in AB4106 and --host-validation; the pack inventory expects exactly the manifested files - NormalizationTargetRegistry.builtInHost? lets config/validate.ts refuse a custom adapter registered under a built-in host's name beside other targets (AB4106) the way compose and validate-artifact already judge it; registries that cannot tell still judge by name. - validate --host-validation and build --host-validation select the shipped validators through registry.builtInHosts(), so a custom `claude` or `portable` adapter is held to no shipped host's contract. - pack-inventory.ts no longer re-derives the install surface from manifest target names: every emitted file is manifested and AB6023/AB6024 already judged the surface by identity, so the pack expects what the manifest lists. - Changeset names the browser pool's `target` option semantics. * docs: AB4106 judges the shipped adapters by identity * manifest: hooks[].routeId for event-route wrappers; cross-check CLI command route ids; inspect reads the CLI build root; drop unused imports * workbench: hook playground rows are manifest hook rows (host, kind, routeId) * test(workbench): hook client fixture carries manifest hook rows * docs(manifest): agent-bundle.manifest.json v2 reference; consumers read the composite root through the manifest (#592 step 3, #555 W2/S3) - New reference page website/docs/{en,zh}/reference/artifact-manifest.mdx (+ _meta.json): every section and field of the v2 manifest, who writes it, who reads it, the shipped JSON Schema and public reader exports, reserved keys not yet emitted, the versioning rule, one abbreviated example. - install / uninstall / doctor: --from is the composite root; identity and the host plugin document come from application + projections[host]; AB7001 reworded (cli.mdx, installation.mdx, package README). - serve-app / mcp: --target optional, ambiguity names the choices; inspect --json gains output.manifest (cli.mdx, mcp.mdx). - docs/diagnostics.md: AB7001 and AB60xx family rows; new "Artifact manifest coherence (AB6039–AB6040)" section; AB6018 reads executables.hooks[]. - Stale statements: agent-bundle.hooks.json sidecar removed from artifact trees and prose (index, project-structure, targets-artifacts, hooks, entry-conventions); targets rows -> projection rows. - Changeset .changeset/592-authoritative-manifest.md (agent-bundle minor). * feat(validate): AB6039/AB6040 manifest coherence lane over the v2 artifact manifest (#592 step 3) New `src/build/validate-artifact-manifest.ts`, wired into `validateArtifact` beside the hook and MCP coherence validators and gated on a parsed manifest whose file table verified (no AB6004), so neither code fires on top of AB6000/AB6001/AB6004 noise. AB6039 (error) — manifest section coherence, what the parser cannot know without the adapter registry or the tree: - executables.bins[].path|worker, scripts[].path|worker, mcpServers[].entry.path|worker, mcpServers[].apps[].path must be direct files of the row's host layout (cliBin, scripts, mcpEntries, mcpApps); hooks[] stays with AB6018, which already holds it to hookWrappers. - a route-generated server (routes.servers[] mode 'generated' with routes) whose executables.mcpServers[] row is not 'compiled' or carries another name. - projections[host].documents.mcp / .hooks must name the document the host's runtime / hook contract reads; a row listing a host without an MCP runtime or without an MCP document. - the host MCP document and the rows listing that host declare the same server names, each with the transport its row records. AB6040 (error) — host document disagrees with the manifest identity: - documents.plugin name/version vs application.name/version. - documents.marketplace name vs projections[host].marketplace.name; a marketplace document the projection does not record (the parser already refuses the reverse). - a host document that is not a strict JSON object cannot be proven. Both are error severity because a consumer acting on the manifest would install or launch something the tree does not contain. Tests: tests/artifact-manifest-coherence.test.ts builds one composite root (claude, codex, cursor, portable; compiled + command + remote MCP servers; three marketplaces) and forges one disagreement per case with the manifest re-serialized and the file table re-hashed, asserting exactly one code. * fix: resolve MCP documents from artifact manifest * docs(manifest): hooks[].routeId and projected CLI tool routes (en, zh) * test: exercise host validation by adapter identity through validate --artifact and build --host-validation The identity test validated the project root, which never enters host validation; validate the built custom root as an artifact instead, and build a custom adapter named claude with a runner spy that must not be spawned. AB6024's row names the shipped cursor/portable adapters by identity, as the validator judges. * Ship a JSON Schema for agent-bundle.manifest.json (#592 step 3) Add schemas/agent-bundle.manifest.schema.json (draft 2020-12, closed keys at every level, $defs per manifest shape, "present exactly when" rules as if/then/else) and publish it through package.json `files` and the `./schemas/agent-bundle.manifest.schema.json` export. src/build/manifest-schema.ts imports the JSON, deep-freezes it as `artifactManifestSchema`, and compiles it once with Ajv 2020 strict mode (strictRequired relaxed for the conditionals) behind `validateArtifactManifestSchema(value): readonly string[]`; both are exported from src/api.ts and src/index.ts. The Rslib bundle inlines the JSON, so dist needs nothing from the packed schemas directory. src/schemas/ajv-issues.ts now installs ajv-formats, accepts Ajv options, and owns the shared `compareSchemaIssues` comparator (lifted from agent-skills/contract.ts) plus `formatSchemaIssue`. scripts/dist-freshness.mjs counts the schemas directory as an agent-bundle build input, since the JSON is compiled into dist. tests/manifest-schema.test.ts checks a populated and a minimal hand-built manifest against both validators, sweeps every object for delete / unknown-key / retype mutations asserting parser-schema agreement with a two-entry documented allowlist, pins the parser-only rules (sorted arrays, cross-references, digests, runtime floor, npm name and semver validity) as accepted-by-schema, pins the schema-encoded rules as rejected by both, and asserts $id, $schema, manifestVersion const, freezing, and the package.json wiring. * test: validate --artifact takes the project root too * validate: manifest coherence judges MCP rows against the MCP lane's single document read; fixtures follow host layouts * schema: hooks[].routeId, projected CLI tool routes; writer output validates against the shipped schema; changeset names #604 * doctor: AB7306 recovery names the composite root and manifest projection * review fixes: reciprocal contract binding, ENOENT-only missing manifest, marketplace pointer existence, projection document pointers judged by the host contract, doctor proof over the built root, stale AB6018/AB7001 prose * validator: judge document→row MCP coherence by built-in host identity; integration expectations for AB6039/AB6040 and the mcp run refusal * manifest: projections[].builtInHost records the shipped adapter identity; install/doctor and the installed harness key on it, the validator cross-checks it (AB6039), inspect reports it * test: mcp-probe fixture records the claude adapter identity * fixtures record built-in identity; advanced-adapter MCP documents own servers the manifest never rowed; inspection projections in the workbench proof * validator: the coherence lane reuses the contracts the target-contract lane fetched; no registry re-entry after evidence snapshots * docs: architecture page describes manifest v2 (#597 follow-up); export ArtifactManifestRouteContract types; cli test imports at top * feat(workbench): project manifest application explorer * Prove artifact-manifest paths stay relocatable when the composite root moves. The writer already emitted root-relative POSIX paths; the parser now also rejects a Windows drive-letter prefix, and a real build proves the bytes never encode the machine and every reader still works after rename. * paths: one relocatable-path rule (core/paths isRelocatablePosixPath) shared by the manifest parser and the writer * refactor(build): serialize manifest from compiler plans * docs: describe authoritative manifest generation * manifest: split operational compiler facts into compiler.recordVersion 1 Keep timings, cache keys, adapter revisions, source-input hashes, and other run metadata out of the public artifact contract so a compiler refactor never forces a manifestVersion bump. * readers: consume manifest.compiler for operational facts Move validator, pack inventory, eval, inspection, and the installed harness onto compiler.project / provenance / adapters / agentSkills so consumer surfaces keep reading only the public contract. * docs: document the public contract vs compiler record Restructure the artifact-manifest pages and the targets outline around manifestVersion and compiler.recordVersion, and mention routes.contracts[] in the authoritative-manifest changeset. * test: read provenance and compiler.project after the manifest split Leftover fixture helpers still typed adapter facts onto projections and asserted files[].sourceInputs / manifest.project on the public contract. * docs(architecture): no separate coherence pass; AB6010 carries adapter identity * test: explorer fixture follows the compiler record split * rstest: drop the deleted coherence test from the integration list * docs(architecture): public contract vs compiler record; explorer projection * Add inspect --artifact so a copied composite root is read through the manifest alone. * fix: trust manifest inventory for installs * docs: describe authoritative install inventory * manifest: MCP/hooks pointers come from the adapter runtime and hook contracts; explorer tolerates route-less servers; tests follow the compiler split * deslop: reuse errorMessage from core/errors, drop dead projectionFor export, fix orphaned doc comment - manifest-file.ts: replace private describe helper with the existing errorMessage from core/errors.ts (helper-before-writing rule) - manifest.ts: delete projectionFor, exported with no importer anywhere (the coherence test defines its own throwing variant) - manifest-routes.ts: move the artifactRoutesFor doc comment off artifactRouteContractFor, where it was stranded as a second docblock Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com> * fix: reindex derived artifact variants * docs: explain variant manifest reindexing * deslop: drop type-bypassing casts, restating comments, and repetitive changeset prose * manifest: carry the web section through v2 — schema, referenced-path rule, doctor reads it from the parsed manifest * tests: preflight artifact graph reads hook rows from the manifest, not the removed sidecar * tests: compiler-evidence fixture supplies the route graph the manifest writer requires * review: doctor --from keeps AB7001 from the identity reader; mcp run launches the host document's own line, cross-checked against the manifest entry; relocatable proof covers web.apps[].entry * tests(packed): provenance lives on compiler.provenance; the packed MCP fixture declares its portable projection identity and server row * Address second self-review: keep AB7001 in doctor, launch host MCP lines verbatim, reject drive paths in schema, cover web entries in relocation proof * feat(manifest): serialize definePrebuilt payloads as distribution.payloads[] (#630 absorbed) * chore: deslop merge delta (gpt-5.6-sol-medium, 1 edit) * Address merge-delta review: payload host-filtering proof, transport on inspection MCP rows, index-based payload location, diagnostics prose * web-host: read declared projections from manifest v2 projections[].host (dev /web route 404 after #628 merge) * feat(manifest): record event route execution * Pin a strict closed-key inventory for manifest v2 and surface payload runtimeDependencies on inspect. An old closed reader rejects any unknown key, so adding an optional public field is not compatible — the inventory fixture fails until the version bumps, and artifact-only consumers read packages from distribution.payloads[].runtimeDependencies. * test: add combined manifest proof * manifest-key-inventory: merge narrowed row properties over the shared $def; regenerate v2 inventory with routes.events[].execution * combined proof: assert routes.events[].execution from the built manifest * docs: readers refuse any other manifestVersion in either direction * manifest: one launch record for compiled MCP servers `executables.mcpServers[]` rows of kind `compiled` carry `launch` ({ args, entry, env, worker? }) in place of `entry`; `args[]` records the author's declaration as `artifact` root-relative paths (plugin-root-anchored) or `literal` values whose tokens the launcher expands. `web.apps[]` drops its copied `entry`/`args`/`env` and names the compiled server instead; the parser cross-checks the reference, the files[] rows, and artifact arguments. The launch types live in `web-host/manifest.ts` (bundled into every plugin bin) and `build/manifest.ts` imports them; `readWebManifestDocument` returns `{ hosts, launches, web? }` so `<plugin> web` resolves the App's launch through the record. Schema, docs (en+zh), changeset clause, and the packed, relocatable, and unit proofs follow. * combined proof: assert executables.mcpServers[].launch; bare plugin-data token * manifest: prebuilt MCP servers carry the same launch record (kind 'prebuilt'), so web Apps on definePrebuilt servers keep working through one record * deslop: 5 edits * Honor manifest launch records in mcp run fallback; web reader requires manifestVersion 2; pin proof wording; prebuilt args/env launch coverage * Rewire the read-only state-root proof to the manifest launch record * Remove the prebuilt launch test's temporary home * Anchor the manifest-only mcp run fallback on the durable plugin root; document the lean web reader and optional web key * Document the lean web reader as the one non-parser consumer * Locate the declared state root through the installed manifest's MCP pointer; admit the compile evidence record * Deslop the state-root rewire; state the inherited state-root fallback * fix(manifest): lean web reader rejects unsupported versions, duplicate server identities, malformed launch and projection rows; reindex refuses compiled files and compile evidence * test(workbench): avoid terminal close locator race * test(manifest): combined proof checks compile evidence survives reindex and install * chore: deslop pass over the reader/reindex delta * fix(manifest): launch records name indexed bytes only in both readers; copies re-measure to the verified inventory * test(manifest): match server-name diagnostics * fix(manifest): the runtime-owned state root is reserved everywhere — AB4741 for payloads, files[] parser and schema, installers * fix(manifest): one files[] path rule for both readers — never the manifest, the runtime state root, or the install receipt entry * chore: deslop the post-review reader/evidence delta --------- Co-authored-by: Ubuntu <zack@ubuntu-main.local> Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
Fixes the Rspress docsite audit in #590: every P1 and P2 except the TypeDoc router change (its own PR,
docs/590-typedoc-module-router, after this merges), plus the cheap P3s. Docs, config, theme, CI, anddocs/diagnostics.mdonly — no runtime code inpackages/agent-bundle/srcchanges.P1
docs/diagnostics.mdAB4834row had four cells under a three-column header, so GFM dropped the recovery hint. Rewritten to three cells.ABcode documented" is now true: 224 codes that were covered only by a family row (AB42xx,AB60xx,AB80xx, …) each have an explicit row with severity, trigger message, and recovery read from the emitting site — including the four the guides cite with specific semantics (AB4204,AB8003,AB8004, andAB6005, whose row restates what feat(build): hold the package build's dist bundles to AB6005 #588 wrote in the family row).website/scripts/check-diagnostics-coverage.mjsfails the build when a code cited inwebsite/docs/{en,zh}/**/*.mdxor a code literal inpackages/agent-bundle/srchas no explicit row or explicit range (family wildcards do not count). Coverage: 422/422 source codes, 107/107 cited codes.reference/cli.mdxexit codes describe whatcli.tsdoes:InvalidArgumentErrorvalidators (serve-app --profile,--allow,doctor --host) reach the parser and exit 2; theTypeErrorvalidators (--port,--trials,dev --install-host,install/uninstall --scope/--mode, malformed--input) surface as oneAB5000diagnostic and exit 1. Whether the code should change is cli: five option validators throw TypeError (AB5000, exit 1) where Commander's InvalidArgumentError (exit 2) is used elsewhere #598 (not widened into this PR).guide/authoring/hooks.mdx:outcomeiscontinueordeny('stop'is rejected byHookHandler<E>and every generated wrapper);agentStopadditionalContextis carried by Claude Code only — Codex and Cursor reject it, and the typed contract excludes it everywhere; the Cursor wrapper alone tolerates a denyingagentStartwith a reason.: anyhovers:rspress.config.tsnow readscompilerOptions.pathsfromwebsite/tsconfig.typedoc.json(the single source of the map) and feeds them topluginTwoslash, so@agent-bundle/runtime*andrsc-markdown-streamresolve to workspace sources. Measured at 1440×900 over the sixguide/development/*pages (en+zh): 26 → 16 popups containing: any; the 16 that remain are TypeScript lib signatures (JSON.parse(): any,Array.isArray(arg: any),console.log(...data: any[])) and oneArray.isArraynarrowing ofunknowntoany[]— real types, not resolution failures. Theguide/development/testingpage went 12 → 0.LocalProvider.initreturns before FlexSearchaddAsyncsettles → "No matching results" on the first query): apnpm patchon@rspress/core@2.0.21awaits the adds (patches/@rspress__core@2.0.21.patch, declared inpnpm-workspace.yaml). Upstream: [Bug]: LocalProvider.init() does not await FlexSearch addAsync, so the first search query can report "No matching results" web-infra-dev/rspress#3658. Verified: a query typed immediately after opening the panel returns results./api/**pages:website/theme/index.tsxre-exportsLlmsCopyRow,LlmsOpenRow, andLlmsHintguarded by the same/api/exclusionpluginLlmsuses, so the rows render only where a Markdown twin exists. (The agent hint the runtime injects fromtheme-originalbypasses theme overrides; only theme and MDX consumers get the guarded version.)P2
EditLinkoverride hides the link on TypeDoc pages and pointsreference/{hosts,events,notices}atsrc/adapters/capabilities/andreference/diagnosticsatdocs/diagnostics.md(patterns track the.gitignoreentries).ssg.experimentalWorker: true: cold build on this machine (RSPRESS_PERSISTENT_CACHE=false, load ≈ 8) 161 s → 95 s; output byte-identical in shape — 1,945 HTML + 1,954 JS files both sides, apparent size 651.3 MB → 650.2 MB (the delta is the HTML changes below).website/styles/index.csstrims--rp-sidebar-width/--rp-outline-width/--rp-content-padding-xat ≥ 1280 px so the code scroller is 686 → 818 px, ~81 → ~97 columns. Authored fences overflowing at 1440×900 (en+zh, hover popups excluded): 116/274 blocks on 35/74 pages → 0/274 after the one 104-char JSON placeholder indocs/diagnostics.mdwas shortened (2/274 before that line was fixed). AGENTS.md's 90-column rule now fits.check-locale-drift.mjs): every authoreden/page needs azh/twin with the same fence count and code per fence (comments stripped), the sameABcode set, the same table-row count, and an h2/h3 count within 2;_meta.json/_nav.jsonmust match in entries, order, and link targets modulo/zh(per regex alternative inactiveMatch). Fixed the drift it found across C/D's changes; currently 0 failures over 33 page pairs and 9 meta files.check-built-links.mjs): walksdoc_build/**/*.html+sitemap.xml, resolves every site-internalhref/src/og:urlhonouringcleanUrls, and requires each#fragmentto name anidin the target — covering frontmatter hero/feature links,_nav.json, raw<a href>, and every generated page, which Rspress's mdast-only checks miss. The websitecheckscript builds withRSPRESS_PERSISTENT_CACHE=falseso anchors are checked against a cold compile ('false' !== process.env.RSPRESS_PERSISTENT_CACHEis the exact test@rspress/coremakes).reference/configuration.mdx:targetsdefaults to['portable'](the only adapter registered{ default: true };--targetoverrides both the default and a declared list);marketplacedefaults tofalse;evals/routesare read through the index signature and are not checked byvalidateSource— described as the code behaves.api/directory groups arecollapsed: truein both locales.P3 landed
docs/public/robots.txt(with sitemap URL) · trailing-slash 404s redirect client-side from theNotFoundLayoutoverride (…/quick-start/→…/quick-start; genuine 404s stay) · zh API mirror pages carry an:::infonotice that the reference is English-only · TypeDoc index title drops the empty{version}· "Type API" nav lands on the hand-written/reference/apioverview (activeMatchcovers/api/and/reference/api; the Reference matcher excludes that page so only one item highlights) ·headtheme-color·themeConfig.footerApache-2.0 line · removedtransformerNotationDiff/Focusand the redundantsearch.codeBlocks·printFileSize.detail: false(build log 4,007 → 22 lines) · 13 en descriptions ≤ 160 chars ·docs.ymlactions pinned to commit SHAs · Dependabot scans.github/actions/*· roottypecheckincludes the website tsconfig · dropped the two unused website devDependencies.Deferred (listed on #590)
router: 'module'→ PR 2.docs.ymljob nameDocs site (Node 22.19)is a required status context onmain; renaming needs the branch-protection edit in the same step — do it with the next Node bump.lastmod= file mtime: a correct value needs full git history in CI (fetch-depth: 0) plus a post-build rewrite; not cheap. Recipe in the Rspress docsite deep-dive audit: 7 P1s (reference drift, twoslashanyhovers, search race, llmsUI 404s), SSG/TypeDoc levers for a 186 s build, 20 % sentence drift #590 comment.canonical/og:urlheadfunctions cannot crossworkerDatato the SSG workers (DataCloneError), so they are incompatible withexperimentalWorker; statictheme-coloronly.generated-reference.tsshape re-declaration (needs a package export), shared-snippet dedup, non-deterministic entry hash (upstream),rspress previewdotted-route behaviour (preview only).AB6005prose beyond the explicit row (feat(build): hold the package build's dist bundles to AB6005 #588 owns it; row restates its text);plugin-target sentences (AB6023,AB6024,AB7001rows describe currentmain; feat(build): emit one composite plugin root; targets select host projections; remove the plugin target (#555 W1) #578/Emit one composite plugin artifact; use targets to select the host projections inside it #555 will rewrite them).Gates
pnpm build && pnpm typecheck && pnpm lint && pnpm test:unit(3,904 passed) andpnpm docs:site:build(typecheck → drift → diagnostics coverage → cold build → built-link walk) — see the checks. Changeset: onepatchforagent-bundlenaming the codes whose rows changed.Self-review
Reviewer:
change-risk-reviewerongpt-5.6-sol-medium(tracedecay daemon intentionally down → plain git/grep fallback), diff vsorigin/main.Round 1 — three findings:
docs/diagnostics.mdAB4300–AB4339,AB4400–AB4408,AB4600–AB4602tables have no Recovery column (52 codes). Dismissed as a table change, fixed in the changeset: those families are emitted throughsourceDiagnostic(code, message, sourcePath)inconfig/validate.ts,core/mcp-transport.ts, andbuild/mcp-apps.tswith norecoveryfield (onlyAB4340carries one), andmainalready documents eight such families in 3-columnCode | Severity | Triggertables. Inventing recovery prose would break "state what the code does"; the changeset now says "recovery where the diagnostic carries one".descriptionshortening (the ≤160-char P3); zh descriptions are independent translations and are all ≤160 already. Every content change (includingreference/cli.mdxexit codes) has its zh twin in this PR;check-locale-drift.mjsreports 0 failures.check-built-links.mjsaccepted a target that escapesdoc_build(/agent-bundle/../package.jsonresolved towebsite/package.json). Fixed: candidates arepath.resolved and must stay insidedoc_build; verified with a traversal probe (flagged) against the real build (still 0 broken).Clean per the reviewer: theme overrides (hook order, SSR, redirect-loop safety), SSG config, the
@rspress/corepatch and lockfile, changeset format, generated-API policy, sampled diagnostic rows vs source, workflow SHA pins.Round 2 (after 9f7d238) — no findings; both dismissals accepted after the reviewer verified them against the source and re-ran the built-link check on the real build.