Skip to content

ci(host-proofs): run the binary-gated real-host install proofs on every PR with pinned CLIs - #395

Merged
ScriptedAlchemy merged 5 commits into
mainfrom
ci/host-proofs-required
Sep 3, 2026
Merged

ci(host-proofs): run the binary-gated real-host install proofs on every PR with pinned CLIs#395
ScriptedAlchemy merged 5 commits into
mainfrom
ci/host-proofs-required

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

  • The host-install, packed host-install, and packed Claude plugin-validation proofs skip their Claude/Codex legs when the CLIs are absent, which let fix(adapters): third-wave review findings (#346/#350/#352/#354/#357/#358) #364 change the Codex interface.logo emission and break both proofs on main unnoticed (test(install): expect the Codex interface.logo field in the packed host-install proof #367/fix(docs,test): closed-issue audit G4 — stale Claude cwd/preview-peer docs, restore rendered-skill docs, pin the #23 handshake queue #368 repaired them from local runs). This PR makes those proofs run on every PR and main push.
  • Pins live beside the schema provenance. hostCli blocks in src/adapters/schemas/{claude,codex}/PROVENANCE.json pin @anthropic-ai/claude-code@2.1.250 and @openai/codex@0.147.0. scripts/host-cli-pins.mjs refuses a hostCli.version that differs from observedCliVersion, installs the pins (re-running Claude Code's install.cjs when npm 12+ blocks its postinstall), and verify fails closed with one diagnostic line per host when claude/codex --version on PATH is not the pin. pnpm check:host-cli runs the same check locally.
  • New host-install-proofs CI job (Node 22.19, ubuntu-latest): cached global npm prefix keyed by OS/arch/pins → version gate → pnpm buildtest:host-installtest:host-install:packedAGENT_BUNDLE_PACKAGE_PREBUILT=1 test:packed:native. Honors the docs-only skip. No secrets or login: every proof runs against an isolated HOME / CLAUDE_CONFIG_DIR / CODEX_HOME.
  • Less brittle Codex interface proof. One shared pinned snapshot (expectedCodexInterfaceFields) for both proof suites instead of two hand-written copies; the proof now also requires the installed manifest to equal the built artifact byte-for-byte, validates it against the pinned plugin schema, and rejects any interface field outside the adapter's exported codexInterfaceFields.
  • Docs: docs/local-ci.md gains a "Real-host install proofs" section (how CI runs them, how to run them locally, what stays login-gated); README proof-levels paragraph updated; native-host-smoke.yml comment clarifies it now adds only the signed-in evidence.

Evidence

  • Verified locally with the pinned CLIs installed into a throwaway prefix (node scripts/host-cli-pins.mjs install --prefix /tmp/...), HOME pointed at an empty directory, and API-key env vars removed:
    • pnpm test:host-install → 16/16 passed, 0 skipped (Claude and Codex legs ran).
    • pnpm test:host-install:packed → 3/3 passed, 0 skipped.
    • AGENT_BUNDLE_PACKAGE_PREBUILT=1 pnpm test:packed:native → 6 passed, 1 skipped (only the opt-in signed-in Eval smoke).
  • verify against the machine's own claude 2.1.257 produced the single mismatch line and exit 1; against an empty PATH produced the single unmet line per host.
  • pnpm typecheck, pnpm lint, pnpm test:projection green; pnpm test:unit and pnpm test:route-unit each had one unrelated 5 s timeout under load average >90 (native-claude-contract, lifecycle-replay) that passed on isolated rerun.

Test plan

  • Host install proofs (Node 22.19) job runs green on this PR (this is the real test).
  • Cache miss path installs both CLIs and the version gate prints two host-cli pin ok lines.
  • Verify job does not run on docs-only PRs.

@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 618beb7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Patch

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T08:23:21.354280Z 618beb7 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@395
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@395
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@395

commit: 618beb7

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1195041a43

ℹ️ 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".

Comment thread scripts/host-cli-pins.mjs Outdated
process.stdout.write(`npm ${installArguments(pins, prefix).join(' ')}\n`);
await runNpm([...installArguments(pins, prefix)], environment);
const globalRoot = (await runNpm(['root', '-g', ...(prefix === undefined ? [] : ['--prefix', prefix])], environment)).trim();
const binDirectory = join(dirname(dirname(globalRoot)), 'bin');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive the Windows global bin directory correctly

When this installer is run on Windows with --prefix X, npm root -g returns X\node_modules, but npm places global executable shims directly in X, as documented under npm global executables. Taking two parent directories and appending bin therefore probes an unrelated sibling such as C:\tmp\bin; both newly installed CLIs remain invisible, the Claude fallback is triggered unnecessarily, and verification fails unless matching binaries already existed on the original PATH.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 274f888. The installer now asks npm for the global prefix (npm prefix -g [--prefix X]) and derives the executables directory with globalBinDirectory(prefix, platform): <prefix>/bin on POSIX, the prefix itself on win32, per the npm folders doc you linked. npm root -g is still queried, but only to locate install.cjs for the Claude postinstall fallback. Unit test added (host-cli-pins.test.ts: "locates npm global executables in /bin on POSIX and in the prefix itself on Windows"), and the CI step comment notes the ubuntu-only /bin assumption. Verified with a fresh --prefix install locally: both CLIs found and version-gated without the fallback probing a sibling directory.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — on Windows npm root -g is <prefix>\node_modules and shims live directly in <prefix>, so dirname(dirname(root))/bin is wrong there. This PR is still open; owner is ci/host-proofs-required (CI host-proofs lane). Tracked by the late-review sweep; not fixed on main.

Comment thread .github/workflows/ci.yml
uses: actions/cache@v6
with:
path: ${{ runner.temp }}/host-cli
key: host-cli-${{ runner.os }}-${{ runner.arch }}-${{ steps.pins.outputs.pins }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include package names in the host CLI cache key

When a hostCli.package is deliberately changed without changing its CLI version, this key still matches the cache populated for the previous package, so line 219 skips installation and verify accepts the stale binaries because it checks only their reported versions. The newly pinned package is consequently never exercised, including after merge while the old default-branch cache remains available; derive the cache output from each package name as well as its version.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 274f888. The pins output (and therefore the actions/cache key) is now pinsCacheKey(pins), which includes each host's hostCli.package as well as its version, sanitised to [A-Za-z0-9._-]: currently claude-anthropic-ai-claude-code-2.1.250-codex-openai-codex-0.147.0. A package re-pin at the same version therefore misses the cache and installs fresh. Unit test added asserting the key changes when only the package name changes and stays within the cache-key-safe character set; the GITHUB_OUTPUT test now checks the same key.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — the host CLI cache key should include each hostCli.package name as well as its version so a package swap at the same version is not served from the stale cache. This PR is still open; owner is ci/host-proofs-required (CI host-proofs lane). Tracked by the late-review sweep; not fixed on main.

…ry PR with pinned CLIs

The host-install, packed host-install, and packed Claude plugin-validation
proofs skip their Claude/Codex legs when the CLIs are absent, which let #364
break both proofs on main unnoticed (#367/#368 repaired them from local runs).

- Pin @anthropic-ai/claude-code@2.1.250 and @openai/codex@0.147.0 as `hostCli`
  in each adapter's schema PROVENANCE.json; scripts/host-cli-pins.mjs reads
  the pins, refuses a pin that differs from observedCliVersion, installs them
  (re-running Claude's postinstall when npm blocks it), and fails closed with
  one diagnostic line when the CLI on PATH is not the pin.
- Add the host-install-proofs CI job (cached CLI prefix, version gate, build,
  test:host-install, test:host-install:packed, test:packed:native) honoring
  the docs-only skip. No secrets or login are needed.
- Harden the Codex interface proof: one shared pinned snapshot for both proof
  suites, installed manifest must equal the built artifact, validate against
  the pinned plugin schema, and reject fields outside the adapter's exported
  codexInterfaceFields.
- Document the job and the local commands in docs/local-ci.md and README.
…in via prefix

Address the automated review on #395: the actions/cache key now includes each
pinned hostCli.package as well as its version, so a re-pin to a different
package with the same version misses the cache instead of reusing stale
binaries; and the installer derives npm's global bin directory from
`npm prefix -g` (<prefix>/bin on POSIX, the prefix itself on Windows)
instead of walking up from `npm root -g`.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 274f888d48

ℹ️ 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".

Comment thread scripts/host-cli-pins.mjs Outdated
Comment on lines +136 to +139
export const pinsCacheKey = (pins) => hostCliHosts
.flatMap((host) => [host, pins[host].package, pins[host].version])
.map((part) => part.replaceAll(/[^A-Za-z0-9._-]+/gu, '-').replaceAll(/^-+|-+$/gu, ''))
.join('-');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make sanitized package names collision-resistant

When a pin changes between package names that normalize identically, such as @foo/bar and foo-bar, this produces the same cache key, so the workflow can restore the previous package and skip installation; because verification checks only the reported version, the stale binary is accepted whenever both packages use the same version. The new sanitization is fresh evidence beyond the earlier cache-key comment because it shows that including package names still does not uniquely identify them; encode the names reversibly or hash the unsanitized pin data.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1dea8da. pinsCacheKey keeps the readable sanitised prefix for humans but now appends a 16-hex SHA-256 of the exact, unsanitised host=package@version pairs, so @foo/bar and foo-bar (or any other pair that normalises identically) produce different cache keys and the stale binary is never restored. Unit test added: the two collide on the readable prefix and differ on the full key; the existing GITHUB_OUTPUT test asserts the same key is emitted.

Sanitising package names for the actions/cache key can map distinct
packages (`@foo/bar`, `foo-bar`) to the same text; append a 16-hex SHA-256
of the exact `package@version` pairs so any re-pin misses the cache.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1dea8dafc3

ℹ️ 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".

Comment thread scripts/host-cli-pins.mjs Outdated
Comment on lines +220 to +223
const pathWithPrefix = `${binDirectory}${process.platform === 'win32' ? ';' : ':'}${environment.PATH ?? ''}`;
const probeEnvironment = { ...environment, PATH: pathWithPrefix };
const claude = await probeOnPath('claude', probeEnvironment);
if (claude.exitCode !== 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict the postinstall probe to the requested prefix

When npm blocks Claude's postinstall and another claude executable already exists later on the inherited PATH, this probe resolves that existing executable instead of detecting that the requested prefix has no working shim. If the existing executable reports the pinned version, the later verification also succeeds, so install --prefix ... exits successfully while the new prefix remains incomplete; probe the executable inside binDirectory directly, or otherwise prevent fallback to the inherited PATH for this check.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 618beb7. The post-install probe (and the verification that closes install) now runs under installProbeEnvironment(binDirectory, env), whose PATH is exactly [binDirectory, dirname(process.execPath)] (the prefix's shims plus the Node the shebangs need), so nothing from the inherited PATH can satisfy the probe; an incomplete prefix fails install even when a matching claude exists elsewhere. Unit test added asserting the probe PATH contains only those two entries and drops an inherited /opt/other-claude/bin. Verified locally against a fresh --prefix on a machine that has a different claude on PATH: the blocked-postinstall fallback still triggers and both pins verify from the prefix.

Comment thread scripts/host-cli-pins.mjs
Comment on lines +185 to +187
if (argument === '--prefix') {
options.prefix = rest[index + 1];
index += 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject a missing --prefix value

When the command is invoked as install --prefix without an operand, this assigns undefined and silently proceeds as though --prefix was omitted. Instead of reporting malformed input, the helper therefore installs both packages into the user's default global npm prefix, which is an unexpected machine-wide side effect; validate that the following argument is a nonempty value before accepting the option.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 618beb7. parseArgs now rejects --prefix when the operand is missing, empty, or another flag: --prefix requires a directory operand (refusing to fall back to the default global npm prefix), thrown before anything is installed. Unit test added covering all three malformed forms via runHostCliPins({ argv: ['install', '--prefix', …] }).

…re --prefix

The post-install probe now runs with PATH limited to the prefix bin
directory plus the running Node, so a pre-existing claude/codex elsewhere
on the inherited PATH cannot mask an incomplete prefix. `install --prefix`
without a directory operand is rejected instead of silently installing
into the default global npm prefix.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 618beb72a3

ℹ️ 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".

@ScriptedAlchemy
ScriptedAlchemy merged commit 7779cb0 into main Sep 3, 2026
11 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the ci/host-proofs-required branch September 3, 2026 08:25
ScriptedAlchemy added a commit that referenced this pull request Sep 3, 2026
… Pages delivery (#384)

## Summary

Lands the Rspress documentation site (`website/`, private workspace `@agent-bundle/docs`) designed in `docs/superpowers/specs/2026-09-02-agent-bundle-rspress-docsite-design.md` and planned in `docs/superpowers/plans/2026-09-02-agent-bundle-rspress-docsite.md` (both versioned here). Continues the prior `docs/rspress-website` branch (Tasks 1–5, rebased onto main) and completes Tasks 6–7 plus generated reference pages.

- **Site**: Rspress 2.0.21 with `@rspress/plugin-typedoc` (11 public export entry modules, mirrored into `zh/`), `plugin-twoslash` (type hovers on guide samples), `plugin-llms` (`llms.txt`/`llms-full.txt` per locale + per-route Markdown), `plugin-sitemap`; dead-link, dead-anchor, dead-image, and language-parity checks on. Complete English + Simplified Chinese parity for Guide (start/authoring/development/distribution), Reference, Examples, Contributing, and home.
- **Generated reference pages** (new `website/plugins/generated-reference.ts`, run in the `config` hook, gitignored output; the Reference overview links every generated page, so Rspress's dead-link check fails the build if generation is skipped): **Host capability matrix**, **Event and hook matrix**, **Notice delivery matrix** rendered from `packages/agent-bundle/src/adapters/capabilities/*.json`, and **Diagnostics reference** copied from `docs/diagnostics.md`. Source of truth stays in the repo; the docs cannot drift.
- **Content**: documented event routes (`src/events/**`) and the full hook wire (stdin → IPC → warm runtime → projection → stdout, fail-closed semantics), verified against `events/ipc.ts`, `adapters/hook-contract.ts`, `events/projection.ts`; config reference now links every field to its TypeDoc-generated type (the config is a TS contract, not a Zod schema); fixed the hook entry shape (`handler`, not `entry`); family-parity homepage (Introduction / Quick start actions, nine linked feature cards) whose MDX body renders below the feature grid through a `Layout` override on the `afterFeatures` slot (`website/theme/index.tsx`): a write-vs-emit comparison with per-host output trees, a Describe → Develop → Prove → Ship walkthrough, a host table, and start-here links, authored per locale; Examples/Contributing nav entries.
- **CI / delivery**: `.github/workflows/docs.yml` runs `pnpm docs:site:build` (typecheck + build with dead-link/anchor/image and language-parity checks; the standalone `verify-build.mjs` was dropped in favor of the built-in checks) on every PR and push to `main` (no path filter), and deploys `website/doc_build` to GitHub Pages from `main` only (Pages source set to GitHub Actions via API; target `https://scriptedalchemy.github.io/agent-bundle/`). `scripts/classify-docs-only.mjs` now treats `website/**` as docs-only (unit-tested), so website-only PRs skip the heavy `ci.yml` jobs. Root scripts: `docs:site:build`, `docs:site:dev`, `docs:site:preview`. READMEs link to the hosted docs.
- **Accuracy fixes from review and browser acceptance**: host path-token table (Cursor and Codex do not accept `${PLUGIN_DATA}`), `pnpm example:*` prints the Workbench URL (`--open` launches the browser), zh Node-resolution order, zh `技能` → `Skill`, `AB4707`–`AB4709` descriptions, `AGENT_BUNDLE_WORKBENCH_API_PROXY` row, Development/Distribution overview titles no longer repeat their sidebar group, TypeDoc member titles emit unescaped underscores (API sidebar and prev/next labels showed `FOO\_BAR`), and over-wide code samples wrapped.
- **Fix**: Twoslash could not resolve `zod` in package-entry samples on current main; the website package now declares it (`4.5.4`, matching the package).

No package source is changed. The `packages/agent-bundle/README.md` link is a shipped-tarball change, so it carries one `agent-bundle` patch changeset (`.changeset/docs-site-readme-link.md`) per the policy `main` now enforces.

## Since consolidation

- **Final-review corrections** (all verified against source, both locales): `reference/api.mdx` lists all eleven entry points and puts `build`/`validate`/`inspect`/`prepack` under `agent-bundle/api`; the hook `reason` rule follows `nativeHookWrapperSource` (denied `agentStop` requires a reason; `agentStart` cannot deny); `cursor` emits `.cursor-plugin/marketplace.json` when `marketplace: true` and `plugin` emits all three manifests; wrapper names carry a digest of their declaration, not a content hash; the diagnostics index gains `AB48xx`–`AB49xx`; `languageParity` now covers the homepages; `llms-full.txt` is emitted with `mdxToMd` (no raw theme imports/JSX); `docs.yml` lints website-only PRs and deploys on `workflow_dispatch` from `main`; the TypeScript 6 pin the docsite needs for `typedoc@0.28` is recorded in `docs/effect-conventions.md`.
- **Review-thread fixes**: quick start installs only the hosts its configs build; the examples index counts all six examples and links the two advanced references; `dev.contracts` (`fixtures`, `server`, `AB7210`/`AB7211` gating) is in the configuration reference; the security page no longer denies the native eval harnesses; `agent-bundle.manifest.json` sits at the output root in the structure tree; the generated hosts page derives Claude's MCP path-token fields from its plugin path-substitution table; a duplicate changeset was removed.
- **Artifact root**: `agent-bundle build` writes host artifacts to `artifact/` by default (it always runs the package build, which owns `dist/`), so the site now says `artifact/` everywhere it means host artifacts, explains the `artifact/`/`dist/` split in the configuration, CLI, and project-structure pages, and the CLI's `--output` help text no longer claims `default dist`. The Cursor and portable capability tables record the marketplace path and path tokens their adapters emit, so the generated host matrix stops rendering empty cells; the changeset covers both.
- **`AGENTS.md`**: new "Documentation site" section — which user-facing changes must update `website/docs` in both locales, which pages are generated and must not be hand-edited, and `pnpm docs:site:build` as the gate.
- **Merged `main`** (through #405, #395): the lockfile was regenerated on top of `main`'s; the generated diagnostics page now rewrites repo-relative `docs/*.md` links to GitHub URLs, since `docs/diagnostics.md` started linking to `entry-conventions.md`.

## Evidence

- `pnpm docs:site:build` (website typecheck → `rspress build`): green (1424 sitemap pages on the merged head), language parity checked, no warnings.
- `pnpm lint`: 0 errors / 0 warnings (1032 files).
- `pnpm exec rstest --config rstest.unit.config.ts packages/agent-bundle/tests/classify-docs-only.test.ts`: 4/4 pass (new website-only and mixed website+source cases).
- Root `pnpm build`, `pnpm typecheck`, `pnpm test:projection`: pass. `test:unit` (2665/2671) and `test:route-unit` (34/35) each had one timeout while running concurrently with the TypeDoc build; both tests pass in isolation. `test:integration:run` fails only `host-install-proof :: installs through Codex` against the locally installed real Codex CLI (`logo` field in the emitted manifest) — environment-specific and unrelated to this branch, which changes no package source.
- Browser acceptance at 1440×900: crawled all 66 authored routes in both locales plus generated reference and API samples — every page renders with title, sidebar and outline; no raw MDX/JSX, `undefined` leaks, broken images, or non-`pre` overflow; Twoslash hover shows the real `defineConfig` signature; search returns prose and code-block hits; locale switch preserves the route both ways; dark mode clean. Earlier pass (Playwright, `rspress preview`): `/`, `/zh/`, `/reference/hosts`, `/reference/events`, `/guide/authoring/hooks`, `/api/` all render with no loading state and no broken images; nav shows Guide / Reference / Examples / Contributing / Type API + locale switch; LLM "Copy Markdown / Open in chat" actions present; per-route `.md` resolves under `/agent-bundle/`; `llms.txt` links use `https://scriptedalchemy.github.io/agent-bundle/`; `sitemap.xml` uses the same origin + base; Twoslash hover markup present in built HTML.

## Test plan

- [ ] `Docs` workflow green on this PR (`pnpm docs:site:build`)
- [ ] `CI` workflow: website+ci+scripts changes are not docs-only, so the full matrix runs and must be green
- [ ] After merge: `Docs` deploy job publishes to https://scriptedalchemy.github.io/agent-bundle/ (Pages source already set to GitHub Actions)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant