diff --git a/.agents/skills/debug-dev-cycle/SKILL.md b/.agents/skills/debug-dev-cycle/SKILL.md new file mode 100644 index 00000000..4d85eb97 --- /dev/null +++ b/.agents/skills/debug-dev-cycle/SKILL.md @@ -0,0 +1,35 @@ +--- +name: debug-dev-cycle +description: Diagnose current Rstack lint or test failures from stored evidence, with an optional user-approved one-shot capture. Use this skill when debugging one current Rslint or Rstest result; use review-context-change to compare two snapshots. +--- + +# Debug an Rstack development cycle + +1. Call `project_status` first. Treat freshness separately for each producer; a fresh build does + not make lint or test evidence fresh. +2. Match the requested package and producer to `project_status.context.packageRoot` and keep its + `contextId`. Deduplicate repeated runs by `contextId`; ask the user to choose only when multiple + distinct lint or test contexts match. If none exists, report that there is no stored evidence + and continue to the capture choice in step 5. +3. Prefer existing evidence. When a context exists, use `snapshot_list` with that `contextId` to + select a completed `rslint` or `rstest` snapshot, then query `diagnostics_list` or `test_results`. +4. Report freshness as `fresh`, `stale`, `partial`, or `unknown`, including changed paths when + reported. Report completeness separately as `complete` or `partial`, including any reported + coverage bounds. +5. Ask before running `lint_snapshot` or `test_snapshot`. These are explicit executions, not + passive queries. For a monorepo package, pass its checkout-relative `packageRoot`; pass + `configPath` only to select a nonstandard checkout-relative Rstack config. Without + `packageRoot`, capture defaults to the checkout root, and without `configPath`, it uses the + ordinary `rstack.config.ts|js|mts|mjs` in the selected package. Never start watch mode. +6. Surface the first actionable failure with its project, path, test name or rule, and recorded + message. Then summarize remaining failures briefly. +7. When aggregate execution or cross-producer diagnostics would help explain one file, call + `code_evidence` with its exact checkout-relative path and the selected `testSnapshotId` or + `lintSnapshotId`. Treat each returned axis and its freshness or completeness independently. + Check `diagnostics.truncated`; when true, report the returned and total counts before the first + actionable items. +8. When the user asks to select related tests, recommend + `rs test list --related --json`; related selection is not an MCP tool. + +Use `lint_fix_preview` only when the lint snapshot recorded a preview. Do not apply it. Recommend +an explicit `rs lint --fix ` only when the user wants to make that change. diff --git a/.agents/skills/release-rstack/SKILL.md b/.agents/skills/release-rstack/SKILL.md index c78e9453..d0682aaf 100644 --- a/.agents/skills/release-rstack/SKILL.md +++ b/.agents/skills/release-rstack/SKILL.md @@ -1,6 +1,6 @@ --- name: release-rstack -description: Create a coordinated release pull request for the `rstack` and `create-rstack` npm packages. Use when asked to prepare, create, or open an rstack package release PR. +description: Create a coordinated release pull request for the `rstack`, `@rstackjs/context`, and `create-rstack` npm packages. Use when asked to prepare, create, or open an rstack package release PR. --- # Release Rstack @@ -13,7 +13,8 @@ If the version is missing, ask for it before making changes. ## Version rules -- Read both package versions before editing. Require the rstack target to be a valid, increasing SemVer version. +- Read all three package versions before editing. Require the rstack target to be a valid, increasing SemVer version. +- Keep `@rstackjs/context` on exactly the same version as `rstack`. - Keep the package version lines independent. Apply the rstack bump type to the current `create-rstack` version: - Patch: increment the patch version. - Minor: increment the minor version and reset patch to `0`. @@ -29,13 +30,13 @@ If the version is missing, ask for it before making changes. 3. Create and switch to `release/v` from the clean default-branch HEAD. -4. Update the `version` field in `packages/rstack/package.json` to `` and the `version` field in `packages/create-rstack/package.json` to the derived `create-rstack` version. +4. Update the `version` fields in `packages/rstack/package.json` and `packages/context/package.json` to ``. Update the `version` field in `packages/create-rstack/package.json` to the derived `create-rstack` version. 5. In every `packages/create-rstack/template-*/package.json`, set the `rstack` dependency to `^`. Update only that dependency entry and verify every template package manifest uses the same target version. 6. Run `pnpm --filter rstack build:native` to regenerate `packages/rstack/binding.cjs` and `packages/rstack/binding.d.cts` for the new version. Do not edit generated binding files manually. -7. Review the diff and confirm it contains only both package version changes, the template `rstack` dependency updates, and the regenerated binding files above. Verify the two package version changes use the intended matching bump type and no template retains an older rstack version. +7. Review the diff and confirm it contains only the three package version changes, the template `rstack` dependency updates, and the regenerated binding files above. Verify `rstack` and `@rstackjs/context` have the same target version, `create-rstack` uses the intended matching bump type, and no template retains an older rstack version. 8. Create a commit with this exact message: `release: v`. diff --git a/.agents/skills/review-context-change/SKILL.md b/.agents/skills/review-context-change/SKILL.md new file mode 100644 index 00000000..7bcf6be0 --- /dev/null +++ b/.agents/skills/review-context-change/SKILL.md @@ -0,0 +1,36 @@ +--- +name: review-context-change +description: Review changes between two compatible Rstack lint or test snapshots, including freshness and stored lint fix previews. Use this skill when comparing before-and-after diagnostics or tests; use debug-dev-cycle for one current result. +--- + +# Review an Rstack context change + +1. Call `project_status` first. Match the requested package to `project_status.context.packageRoot`, + deduplicating repeated runs by `contextId` and asking the user to choose only when multiple distinct contexts match. Use + `snapshot_list` with that `contextId` and require two compatible completed snapshots for the same + producer, context, package root, selected Rstack config, and capture selection. The list is + newest-first: pass the older snapshot as `leftSnapshotId` and the newer snapshot as + `rightSnapshotId`. +2. When no compatible pair exists, state which explicit capture supplies each missing snapshot: + `lint_snapshot` for an Rslint comparison or `test_snapshot` for an Rstest comparison. Include the + checkout-relative `packageRoot` and any nonstandard `configPath`. Ask before running each capture. +3. Call `snapshot_diff` with `diagnostics` for Rslint or `tests` for Rstest. If it reports + incompatibility, explain the listed reasons and stop the comparison. +4. Report the independent freshness of both snapshots before interpreting the delta. Never imply + that partial or unknown evidence covers unobserved source files. +5. Summarize added, removed, and changed items. Lead with new failures or errors, then resolved + items, then lower-severity or timing-only changes. +6. When aggregate execution or exact-path diagnostics would clarify one changed file, call + `code_evidence` with its exact checkout-relative path and the relevant explicit snapshot ID. + Keep that point-in-time evidence separate from the snapshot delta. + Check `diagnostics.truncated`; when true, report the returned and total counts instead of treating + the diagnostic items as exhaustive. +7. For a changed lint file, call `lint_fix_preview` only when the preview would materially help the + review. If the snapshot did not capture one, report that it is unavailable. Treat returned text + as review material and never apply it. +8. Recommend explicit verification appropriate to the change, such as `rs lint `, + `rs test `, or `rs test list --related --json`. + +Do not run a capture unless the user asks for fresh execution. When they do, reuse the +checkout-relative `packageRoot` and optional `configPath` for the context under review. Never +start watch mode. diff --git a/.superpowers/sdd/2026-08-12-context-branch-simplification/task-3-report.md b/.superpowers/sdd/2026-08-12-context-branch-simplification/task-3-report.md new file mode 100644 index 00000000..64ed0849 --- /dev/null +++ b/.superpowers/sdd/2026-08-12-context-branch-simplification/task-3-report.md @@ -0,0 +1,35 @@ +# Task 3 Report + +Status: DONE + +## Changes + +- Stopped workspace discovery after processing the nearest `.git` root. +- Canonicalized an existing loaded Rsbuild or Rslib config path once before observer creation. +- Removed unused stats timings and replaced unbounded metadata intermediates with one-pass bounded + asset, chunk, and chunk-file collectors while preserving `BuildMetadataFacet` output. +- Added high-cardinality valid/invalid metadata, ancestor-workspace, and symlinked-config fixtures. + +## TDD evidence + +- RED: `pnpm --filter rstack test run tests/context/build.test.ts` failed because `toJson` + received `timings: true` in the existing lifecycle and new high-cardinality tests. +- RED: `pnpm --filter rstack test run tests/context/workspace.test.ts` failed because discovery + returned the unrelated ancestor workspace instead of the nearest checkout root. +- RED: `pnpm --filter rstack test run tests/context/injection.test.ts -t 'canonicalizes a +symlinked loaded config path'` failed for both app and lib because no context run was captured. +- GREEN: full build, workspace, and injection test files passed (24 passed). + +## Verification + +- `pnpm check`: passed with 0 lint errors, 0 type errors, 0 warnings, and no formatting issues. +- Full assigned-file run: 24 of 24 tests passed after removing the obsolete path/identifier-defense + and snapshot-size-cap fixtures from the branch's deleted security scope. + +## Commit + +`perf(rstack): bound passive build extraction` + +## Concerns + +None. diff --git a/.superpowers/sdd/2026-08-12-context-branch-simplification/task-5-brief.md b/.superpowers/sdd/2026-08-12-context-branch-simplification/task-5-brief.md new file mode 100644 index 00000000..c5a3ea7d --- /dev/null +++ b/.superpowers/sdd/2026-08-12-context-branch-simplification/task-5-brief.md @@ -0,0 +1,41 @@ +### Task 5: simplify report lookup and align documentation + +**Files:** + +- Modify: `packages/rstack/src/context/rsdoctor.ts` +- Modify: `packages/rstack/src/context/report.ts` +- Modify: `packages/rstack/tests/context/report.test.ts` +- Modify: `website/docs/en/guide/cli/mcp.mdx` +- Modify: `website/docs/zh/guide/cli/mcp.mdx` +- Modify: `docs/rfcs/0001-rstack-context-engine.md` +- Modify: `docs/superpowers/plans/2026-08-12-rsdoctor-context.md` +- Modify: `docs/superpowers/plans/2026-08-12-context-branch-simplification.md` + +**Interfaces:** + +- Report lookup returns a discriminated `missing | file` result instead of requiring callers to + inspect exception messages. +- Report links use ordinary resolved file URIs; no server or command is started. + +- [x] **Step 1: write typed-outcome report tests and verify RED** + +Cover missing conventional report, one valid sibling, ambiguous siblings, and manifest fallback. +Assert no control flow depends on an exception message. + +- [x] **Step 2: implement the typed boundary** + +Use ordinary resolved paths and `stat` to return discriminated outcomes. The report resolver owns +file lookup directly and consumes typed outcomes. + +- [x] **Step 3: align English, Chinese, and RFC status** + +Document the exact three-tool Phase 1 surface, direct Rsdoctor JSON contract, optional GUI links, and +deferred retention. Update both branch planning documents to match the implemented functional +contract, rewriting only the minimum surrounding sentences needed to keep them readable as +implementation history. + +- [x] **Step 4: run full verification and commit** + +Run `pnpm check`, `pnpm check:spell`, `pnpm build`, +`pnpm --filter rstack build:native`, and `pnpm test`; commit as +`docs: align the lean context foundation`. diff --git a/.superpowers/sdd/2026-08-12-context-branch-simplification/task-5-report.md b/.superpowers/sdd/2026-08-12-context-branch-simplification/task-5-report.md new file mode 100644 index 00000000..0b83ec74 --- /dev/null +++ b/.superpowers/sdd/2026-08-12-context-branch-simplification/task-5-report.md @@ -0,0 +1,29 @@ +# Task 5 report + +## Result + +- Report-file lookup now returns a typed `missing | file` outcome from ordinary resolved paths and + `stat`, so report selection no longer branches on exception text. +- Rsdoctor artifact validation now returns the normalized data-file path directly; the previous + closure-bearing report helper is gone. +- Report selection still prefers the conventional sibling HTML report, then one unambiguous sibling + HTML file, then the workspace manifest, and otherwise returns the structured analysis next action. +- English, Chinese, the RFC, and both implementation plans now describe the exact three-tool Phase 1 + surface, direct Rsdoctor JSON results, optional GUI links, and deferred destructive retention. + +## TDD evidence + +- RED: `pnpm --filter rstack test -- tests/context/report.test.ts` failed at the new typed-missing + assertion because `resolveReportFile` did not exist. +- GREEN: the same focused command passed after the typed lookup was implemented: 313 passed and 1 + skipped across 314 Rstack tests. + +## Verification + +Repository-required sequence: + +- `pnpm check` — passed with 0 lint errors, 0 type errors, and 0 warnings. +- `pnpm check:spell` — passed with 0 spelling issues and no heading-case issues. +- `pnpm build` — passed for `rstack` and `create-rstack`. +- `pnpm --filter rstack build:native` — passed. +- `pnpm test` — passed: Rstack 313 passed and 1 skipped; create-rstack 28 passed. diff --git a/docs/superpowers/plans/2026-08-12-context-branch-simplification.md b/docs/superpowers/plans/2026-08-12-context-branch-simplification.md new file mode 100644 index 00000000..342802ab --- /dev/null +++ b/docs/superpowers/plans/2026-08-12-context-branch-simplification.md @@ -0,0 +1,249 @@ +# Context branch simplification implementation plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development +> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox +> (`- [ ]`) syntax for tracking. + +**Goal:** Reduce the context-engine branch to a simple read-only foundation with an optional +Rsdoctor adapter, while preserving passive build evidence and the single stdio MCP server. + +**Architecture:** Remove the premature destructive retention surface. Move duplicated +persisted-record validation into one internal module used by the writer and status reader. Lazy-load +Rsdoctor, validate functional tool inputs, and return its JSON result directly. + +**Tech Stack:** TypeScript, Node.js 22+, pnpm, Rstest, Rslint, MCP SDK 1.29.0, Zod 4.4.3, +`@rsdoctor/agent-cli` 0.1.1. + +## Global constraints + +- Work only on `codex/rstack-mcp-observability`; never rewrite or amend existing commits. +- Follow strict red-green-refactor TDD for every behavior change. +- Keep one local stdio MCP server. Do not add a daemon, HTTP listener, dev-server route, report + server, build invocation, or startup mutation. +- The Phase 1 MCP surface is read-only: `project_status`, `rsdoctor_analyze`, and `report_link` only. +- Keep only ordinary type/shape validation needed for functional errors and stable data contracts. +- Keep English and Chinese documentation aligned in structure, meaning, examples, and anchors. +- Prefer deletion and shared validation over new wrappers. Do not preserve an abstraction solely + because earlier commits introduced it. + +--- + +### Task 1: remove premature destructive retention + +**Files:** + +- Delete: `packages/rstack/src/context/retention.ts` +- Delete: `packages/rstack/tests/context/retention.test.ts` +- Modify: `packages/rstack/src/context/index.ts` +- Modify: `packages/rstack/src/context/mcp.ts` +- Modify: `packages/rstack/tests/context/mcp.test.ts` +- Modify: `docs/superpowers/plans/2026-08-12-rsdoctor-context.md` +- Modify: `docs/rfcs/0001-rstack-context-engine.md` + +**Interfaces:** + +- Removes `planContextRetention`, `applyContextRetention`, `context_prune`, and their policy/result + types. +- Leaves exactly the three Phase 1 MCP tools named in the global constraints. + +- [ ] **Step 1: make MCP tests expect the lean surface** + +Change the protocol test to assert the exact three-tool set and remove retention calls. Add a +negative assertion that `context_prune` is not advertised. + +- [ ] **Step 2: verify RED** + +Run `pnpm --filter rstack test -- packages/rstack/tests/context/mcp.test.ts`. Expected: the existing +server still advertises `context_prune`. + +- [ ] **Step 3: delete the retention implementation and wiring** + +Remove the two files, imports, schemas, response helpers, tool registration, and barrel exports. Do +not replace them with another deletion mechanism. + +- [ ] **Step 4: correct the design record** + +Mark destructive retention as deferred until real size/access measurements and product semantics +exist. Do not claim cache growth is already bounded by deletion. + +- [ ] **Step 5: verify and commit** + +Run the focused MCP tests and `pnpm check`; commit as +`refactor(rstack): defer destructive context retention`. + +--- + +### Task 2: unify persisted-record validation + +**Files:** + +- Create: `packages/rstack/src/context/records.ts` +- Create: `packages/rstack/tests/context/records.test.ts` +- Modify: `packages/rstack/src/context/store.ts` +- Modify: `packages/rstack/src/context/model.ts` +- Modify: `packages/rstack/tests/context/store.test.ts` + +**Interfaces:** + +- Produces `validateRunManifest(value): ContextRunManifest | undefined`. +- Produces `validateSnapshot(value): ContextSnapshot | undefined`. +- Produces canonical generation filename validation + `-.json`. +- `readLatestSnapshot` sorts canonical generation filenames newest-first and stops after the first + valid matching snapshot instead of parsing every historical generation. + +- [ ] **Step 1: write schema-parity tests** + +Cover valid/invalid manifests and snapshots, duplicate manifest context IDs, canonical generation +names, writer/reader acceptance parity, and ordinary JSON parse failure. Verify RED against the +current duplicated validators. + +- [ ] **Step 2: implement the shared record module** + +Move identifier/path/producer/status/completeness validation out of `store.ts`. Validate the current +model's required primitive/object fields and unique context IDs. Keep the functions internal to the +context implementation rather than exporting them through `context/index.ts`. + +- [ ] **Step 3: use shared validation in reads and writes** + +Keep the existing straightforward atomic publication and JSON reads. Use the shared validators and +canonical generation-name helper in both paths. Delete the duplicate sets and predicates from +`store.ts`. Remove pre-read byte checks and their model/test surface. Replace the all-generations +parse/sort with a descending filename loop that stops at the latest valid record. + +- [ ] **Step 4: verify and commit** + +Run record/store/status tests and `pnpm check`; commit as +`refactor(rstack): share context record validation`. + +--- + +### Task 3: reduce passive build extraction work + +**Files:** + +- Modify: `packages/rstack/src/context/build.ts` +- Modify: `packages/rstack/src/context/workspace.ts` +- Modify: `packages/rstack/src/rsbuildConfig.ts` +- Modify: `packages/rstack/src/rslibConfig.ts` +- Modify: `packages/rstack/tests/context/build.test.ts` +- Modify: `packages/rstack/tests/context/workspace.test.ts` +- Modify: `packages/rstack/tests/context/injection.test.ts` + +**Interfaces:** + +- `buildMetadataFacet` keeps the existing persisted `BuildMetadataFacet` shape. +- Stats extraction no longer requests unused timings and retains no more than 100 safe assets, + 100 chunks, or 20 safe files per retained chunk while counting dropped safe rows. +- Workspace discovery stops after inspecting the nearest `.git` root instead of selecting an + unrelated ancestor workspace manifest. +- Rsbuild and Rslib loaders canonicalize an existing loaded config path before observer creation. + +- [ ] **Step 1: write high-cardinality extraction tests** + +Provide more than 100 valid and invalid assets/chunks and more than 20 chunk files. Assert exact +retained rows and dropped counts, and assert the `toJson` options omit `timings`. + +Add ordinary fixtures proving a checkout nested under an unrelated ancestor workspace resolves to +the checkout root and an existing loaded config path produces a normalized workspace-relative +descriptor. + +- [ ] **Step 2: verify RED** + +Run the focused build test. Expected: current extraction requests timings and allocates/maps all rows. + +- [ ] **Step 3: implement one-pass bounded collectors** + +Use simple loops with retained arrays and dropped counters. Normalize each candidate once. Preserve +ordering and the public snapshot shape. Stop workspace discovery immediately after processing the +nearest `.git` directory. Canonicalize `loaded.filePath` once in each CLI-specific loader before +passing it to `createBuildContextPlugin`. + +- [ ] **Step 4: verify and commit** + +Run build/injection tests and `pnpm check`; commit as +`perf(rstack): bound passive build extraction`. + +--- + +### Task 4: simplify and lazy-load the Rsdoctor adapter + +**Files:** + +- Modify: `packages/rstack/src/context/rsdoctor.ts` +- Modify: `packages/rstack/src/context/mcp.ts` +- Modify: `packages/rstack/src/context/index.ts` +- Modify: `packages/rstack/tests/context/rsdoctor.test.ts` +- Modify: `packages/rstack/tests/context/mcp.test.ts` + +**Interfaces:** + +- Supported tool names remain exactly the pinned ten-agent catalog names. +- `@rsdoctor/agent-cli` is loaded with dynamic `import()` only on the first analysis request. +- Tool input is validated against the selected catalog entry's JSON schema for functional errors. +- Tool output is returned directly as JSON. + +- [ ] **Step 1: rewrite tests for the direct functional contract** + +Keep catalog-name, valid-artifact, malformed-JSON, wrong-envelope, and unknown-tool coverage. Add a +real-tool test proving returned strings and fields are unchanged. + +- [ ] **Step 2: verify RED** + +Run Rsdoctor/MCP tests. Expected: the current adapter still changes fixture values and the package is +still loaded eagerly. + +- [ ] **Step 3: simplify the adapter and lazy-load the package** + +Resolve the explicit data file with ordinary `path.resolve`, parse JSON, and invoke the selected +pinned catalog tool. Dynamically import the package and cache its catalog/executor on first use. + +- [ ] **Step 4: verify startup isolation** + +Add a built-process test showing status-only MCP initialization does not load +`@rsdoctor/agent-cli`, while one `rsdoctor_analyze` call does. + +- [ ] **Step 5: verify and commit** + +Run Rsdoctor/MCP tests and `pnpm check`; commit as +`refactor(rstack): simplify Rsdoctor analysis`. + +--- + +### Task 5: simplify report lookup and align documentation + +**Files:** + +- Modify: `packages/rstack/src/context/rsdoctor.ts` +- Modify: `packages/rstack/src/context/report.ts` +- Modify: `packages/rstack/tests/context/report.test.ts` +- Modify: `website/docs/en/guide/cli/mcp.mdx` +- Modify: `website/docs/zh/guide/cli/mcp.mdx` +- Modify: `docs/rfcs/0001-rstack-context-engine.md` + +**Interfaces:** + +- Report lookup returns a discriminated `missing | file` result instead of requiring callers to + inspect exception messages. +- Report links use ordinary resolved file URIs; no server or command is started. + +- [ ] **Step 1: write typed-outcome report tests and verify RED** + +Cover missing conventional report, one valid sibling, ambiguous siblings, and manifest fallback. +Assert no control flow depends on an exception message. + +- [ ] **Step 2: implement the typed boundary** + +Use ordinary resolved paths and `stat` to return discriminated outcomes. The report resolver owns +file lookup directly and consumes typed outcomes. + +- [ ] **Step 3: align English, Chinese, and RFC status** + +Document the exact three-tool Phase 1 surface, direct Rsdoctor JSON contract, optional GUI links, and +deferred retention. Update both planning documents to match the implemented functional contract. + +- [ ] **Step 4: run full verification and commit** + +Run `pnpm check`, `pnpm check:spell`, `pnpm build`, +`pnpm --filter rstack build:native`, and `pnpm test`; commit as +`docs: align the lean context foundation`. diff --git a/docs/superpowers/plans/2026-08-12-context-store-foundation.md b/docs/superpowers/plans/2026-08-12-context-store-foundation.md new file mode 100644 index 00000000..514e208c --- /dev/null +++ b/docs/superpowers/plans/2026-08-12-context-store-foundation.md @@ -0,0 +1,214 @@ +# Context store foundation implementation plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development +> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use +> checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Establish the smallest task-runner-independent foundation that lets Rstack producers running +anywhere in a checkout publish immutable context snapshots for a root-launched MCP process to read. + +**Architecture:** Producers resolve their checkout and package identity from their actual config path, +then write bounded, versioned records into `.rstack/cache/context-v1`. Every run owns a unique +directory, so concurrent Rslib, Rsbuild, Rstest, Rslint, Rspack, and Rsdoctor processes do not share a +mutable database. A read-only status API scans only completed records; no daemon, socket, task-runner +integration, or MCP transport is introduced in this foundation. + +**Tech Stack:** TypeScript, Node.js filesystem APIs, Rstack project cache, Rstest. + +## Global constraints + +- Work only on a non-main `codex/` branch. +- Treat MCP CWD as an authorization/discovery start, never as package or build identity. +- Do not depend on Turbo, Nx, pnpm recursive execution, or any other task runner. +- Store only workspace-relative package/config paths in records. +- Use immutable per-run records and atomic publication; readers must ignore temporary files. +- Bound individual records to 1 MiB and report malformed or unsupported records as store issues. +- Cache failures must be observable but must not force a future producer to fail its underlying tool. +- Do not add a CLI command, daemon, MCP server, collector injection, or public package export yet. + +--- + +### Task 1: resolve checkout and package identity + +**Files:** + +- Create: `packages/rstack/src/context/workspace.ts` +- Create: `packages/rstack/tests/context/workspace.test.ts` + +**Interfaces:** + +- Consumes: an existing config file or directory path supplied by a producer. +- Produces: `resolveContextWorkspace(startPath): Promise` where the result + contains canonical `workspaceRoot`, `packageRoot`, and optional `packageName`. + +- [ ] **Step 1: Write the failing workspace tests** + +```ts +test('resolves a package from its config path without using process cwd', async () => { + const result = await resolveContextWorkspace(configPath); + expect(result).toEqual({ workspaceRoot, packageRoot, packageName: '@repo/lib' }); +}); + +test('falls back to a standalone package root', async () => { + const result = await resolveContextWorkspace(configPath); + expect(result.workspaceRoot).toBe(packageRoot); +}); +``` + +- [ ] **Step 2: Run the focused test and verify RED** + +Run: `pnpm --filter rstack test -- tests/context/workspace.test.ts` + +Expected: FAIL because `src/context/workspace.ts` does not exist. + +- [ ] **Step 3: Implement the minimal resolver** + +Walk canonical ancestors once. Prefer the nearest `pnpm-workspace.yaml`, +`pnpm-workspace.yml`, or `package.json#workspaces`; otherwise use the nearest Git checkout marker, +then the nearest package root, then the start directory. Read the nearest `package.json#name` without +executing project code. + +- [ ] **Step 4: Run the focused test and verify GREEN** + +Run: `pnpm --filter rstack test -- tests/context/workspace.test.ts` + +Expected: PASS with both workspace cases green. + +### Task 2: publish and read immutable context records + +**Files:** + +- Create: `packages/rstack/src/context/model.ts` +- Create: `packages/rstack/src/context/store.ts` +- Create: `packages/rstack/src/context/index.ts` +- Create: `packages/rstack/tests/context/store.test.ts` + +**Interfaces:** + +- Consumes: the workspace root from Task 1, one `ContextRunManifest`, and immutable + `ContextSnapshot` records. +- Produces: `writeContextRunManifest`, `writeContextSnapshot`, and + `readContextWorkspaceStatus`; all schemas use `contextStoreSchemaVersion = 1`. + +- [ ] **Step 1: Write the failing store tests** + +```ts +test('publishes concurrent run snapshots and reads each latest context', async () => { + expect(await writeContextRunManifest(rootPath, run)).toMatchObject({ written: true }); + expect(await writeContextSnapshot(rootPath, first)).toMatchObject({ written: true }); + expect(await writeContextSnapshot(rootPath, second)).toMatchObject({ written: true }); + expect(await readContextWorkspaceStatus(rootPath)).toMatchObject({ + runs: [{ run, contexts: [{ context: run.contexts[0], latestSnapshot: second }] }], + }); +}); + +test('does not replace an immutable record', async () => { + expect(await writeContextSnapshot(rootPath, first)).toMatchObject({ written: true }); + expect(await writeContextSnapshot(rootPath, replacement)).toMatchObject({ written: false }); +}); + +test('reports malformed completed records without reading temporary files', async () => { + const status = await readContextWorkspaceStatus(rootPath); + expect(status.issues).toEqual([ + expect.objectContaining({ code: 'invalid-record', path: expect.any(String) }), + ]); +}); +``` + +- [ ] **Step 2: Run the focused test and verify RED** + +Run: `pnpm --filter rstack test -- tests/context/store.test.ts` + +Expected: FAIL because the context model and store do not exist. + +- [ ] **Step 3: Implement the minimal immutable store** + +Use the existing `ensureProjectCacheDir()` and the layout +`context-v1/runs//run.json` plus +`context-v1/runs//contexts//generations/-.json`. +Serialize JSON with a trailing newline, reject unsafe IDs and records over 1 MiB, write a unique +same-directory temporary file, and atomically hard-link it into its final immutable name. The reader +must validate schema version and required fields, return stable sorting, and report bounded relative +issue paths. + +- [ ] **Step 4: Run both context test files and verify GREEN** + +Run: `pnpm --filter rstack test -- tests/context/workspace.test.ts tests/context/store.test.ts` + +Expected: PASS with no warnings. + +### Task 3: make the lean architecture normative + +**Files:** + +- Modify: `docs/rfcs/0001-rstack-context-engine.md` + +**Interfaces:** + +- Consumes: the approved workspace-store architecture and the concrete Task 1/2 contract. +- Produces: an RFC whose diagrams, lifecycle, identity, storage, alternatives, budgets, and delivery + plan consistently describe a daemon-free version 1. + +- [ ] **Step 1: Replace the coordinator diagrams and lifecycle** + +Show independent package-local producers atomically publishing into the workspace evidence store and +root-launched Codex/Claude stdio MCP processes reading it. Explain that all MCP instances share the +same immutable cache without sharing process memory. + +- [ ] **Step 2: Specify discovery and identity** + +Distinguish stable repository identity from checkout/worktree identity. State that resolved config, +package root, tool, product, environment, run, and generation identify observations; CWD never does. + +- [ ] **Step 3: Update development mode, alternatives, and delivery phases** + +Keep build, Rslint, and Rstest independent producers. Explicitly defer a coordinator daemon until +measured multi-client caching or event throughput proves it necessary. Move the workspace store and +status reader into Phase 0. + +- [ ] **Step 4: Re-render every Mermaid diagram** + +Run the repository Mermaid validation command and render all RFC diagrams in light and dark themes. +Inspect every resulting image for clipped text, invalid edges, unreadable contrast, or misleading +process ownership. + +### Task 4: verify and commit the foundation + +**Files:** + +- Verify all files from Tasks 1-3. + +**Interfaces:** + +- Consumes: completed implementation and documentation. +- Produces: one reviewed commit on `codex/rstack-mcp-observability`. + +- [ ] **Step 1: Format and run focused tests** + +Run: `pnpm exec rs fmt packages/rstack/src/context packages/rstack/tests/context docs/rfcs/0001-rstack-context-engine.md docs/superpowers/plans/2026-08-12-context-store-foundation.md` + +Run: `pnpm --filter rstack test -- tests/context` + +- [ ] **Step 2: Build and run repository checks** + +Run: `pnpm --filter rstack build` + +Run: `pnpm check` + +Run: `pnpm check:spell` + +- [ ] **Step 3: Review the final diff and requirements** + +Confirm the branch is not `main` or `master`; confirm no daemon, socket, MCP server, task-runner +dependency, config mutation, or public export was added; confirm every stored path is relative and +every completed record is immutable. + +- [ ] **Step 4: Commit** + +```bash +git add docs/rfcs/0001-rstack-context-engine.md \ + docs/superpowers/plans/2026-08-12-context-store-foundation.md \ + packages/rstack/src/context \ + packages/rstack/tests/context +git commit -m "feat: scaffold context evidence store" +``` diff --git a/docs/superpowers/plans/2026-08-12-passive-build-context.md b/docs/superpowers/plans/2026-08-12-passive-build-context.md new file mode 100644 index 00000000..1612eb0e --- /dev/null +++ b/docs/superpowers/plans/2026-08-12-passive-build-context.md @@ -0,0 +1,560 @@ +# Passive build context implementation plan + + + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development +> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox +> (`- [ ]`) syntax for tracking. + +**Goal:** Publish opt-in, metadata-only Rsbuild and Rslib build observations into the checkout-local +immutable store and expose all package contexts through one read-only `rs mcp` status tool. + +**Architecture:** The CLI-specific config loaders shallow-clone resolved user configs and append one +per-instance Rsbuild observer. Producers write immutable per-environment snapshots; a root-launched +stdio MCP process reads and projects them on demand. There is no daemon, port, task-runner adapter, +or producer-to-MCP connection. + +**Tech stack:** TypeScript, Node.js 22+, Rstack config loaders, Rsbuild plugin hooks, Rspack Stats, +Rstest, `@modelcontextprotocol/sdk@1.29.0`, pnpm catalogs. + +## Global constraints + +- Work on `codex/rstack-mcp-observability`, never `main` or `master`. +- Follow strict red-green-refactor TDD for every production behavior. +- Preserve the pure `resolveRsbuildConfig` and `resolveRslibConfig` behavior used by Rstest. +- Never mutate user config objects, `lib[]` entries, user plugin arrays, hook arguments, or config files. +- Capture is off unless `define.context({ enabled: true })` or `RSTACK_CONTEXT=1` enables it. +- `RSTACK_CONTEXT=0` and `capture: 'off'` always disable capture. +- Metadata caps are exactly 100 assets, 100 chunks, and 20 files per chunk. +- Persist only checkout-relative POSIX paths; never persist raw config, source, source maps, + environment values, output contents, or full diagnostic messages. +- Capture failure must never change an Rsbuild or Rslib command result and may warn at most once per + observer instance. +- One global Rslib observer must cover all generated environments; do not add plugins to `lib[]`. +- `rs mcp` uses stdio only. Stdout is protocol-only; logs go to stderr. +- MCP v1 is pinned to `@modelcontextprotocol/sdk@1.29.0`; do not adopt the just-released v2 split in + this phase. +- English and Chinese documentation must remain structurally and semantically aligned, with matching + heading anchors. +- Do not add Rsdoctor, deep Rspack graphs, Rslint, Rstest, retention, subscriptions, HTTP, or mutation + tools in this plan. + +--- + +### Task 1: add trusted context configuration and project-status projection + +**Files:** + +- Create: `packages/rstack/src/context/config.ts` +- Create: `packages/rstack/src/context/status.ts` +- Create: `packages/rstack/tests/context/config.test.ts` +- Create: `packages/rstack/tests/context/status.test.ts` +- Modify: `packages/rstack/src/context/model.ts` +- Modify: `packages/rstack/src/context/index.ts` +- Modify: `packages/rstack/src/config.ts` +- Modify: `packages/rstack/src/configExports.ts` + +**Interfaces:** + +- Produces: + `type ContextConfig = { enabled?: boolean; capture?: 'off' | 'metadata' | 'deep' }`. +- Produces: + `resolveContextCapture(config: ContextConfig | undefined, override?: string): 'off' | 'metadata' | 'deep'`. +- Produces: `readProjectStatus(workspaceRoot: string): Promise`. +- `ProjectStatus.contexts` contains every run/context pair; it never coalesces concurrent runs. + +- [ ] **Step 1: write activation-policy tests** + +Create `packages/rstack/tests/context/config.test.ts` with table-driven assertions equivalent to: + +```ts +import { expect, test } from 'rstack/test'; +import { resolveContextCapture } from '../../src/context/config.ts'; + +test('resolves context capture with explicit opt-out precedence', () => { + expect(resolveContextCapture(undefined, undefined)).toBe('off'); + expect(resolveContextCapture({ enabled: true }, undefined)).toBe('metadata'); + expect(resolveContextCapture({ enabled: true, capture: 'deep' }, undefined)).toBe('deep'); + expect(resolveContextCapture({ enabled: true, capture: 'off' }, '1')).toBe('off'); + expect(resolveContextCapture({ enabled: true }, '0')).toBe('off'); + expect(resolveContextCapture(undefined, '1')).toBe('metadata'); +}); +``` + +Add a config-loading test proving `define.context(...)` is stored separately from `define.app` and +`define.lib` and does not alter either object. + +- [ ] **Step 2: run the activation tests and verify RED** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/config.test.ts +``` + +Expected: FAIL because `ContextConfig`, `define.context`, and `resolveContextCapture` do not exist. + +- [ ] **Step 3: implement the configuration contract** + +In `context/config.ts`, implement this precedence exactly: + +```ts +const resolveContextCapture = ( + config: ContextConfig | undefined, + override = process.env.RSTACK_CONTEXT, +): ContextCaptureTier | 'off' => { + if (override === '0' || config?.capture === 'off') return 'off'; + if (override === '1') return config?.capture === 'deep' ? 'deep' : 'metadata'; + if (config?.enabled !== true) return 'off'; + return config.capture ?? 'metadata'; +}; +``` + +Add `context?: ContextConfig` to `Configs`, add `context` to `Define`, add +`context: (config) => setConfig('context', config)` to `define`, and export the public config types +from `configExports.ts`. Do not add context fields to app or library configs. + +- [ ] **Step 4: run activation tests and verify GREEN** + +Run the Task 1 test command. Expected: all context configuration tests PASS. + +- [ ] **Step 5: write project-status tests** + +Create stores in temporary standalone and monorepo roots with the existing write helpers. Assert: + +- an empty store returns `{ schemaVersion: 1, workspaceId: /^ws_[0-9a-f]{24}$/, contexts: [], issues: [] }`; +- two packages are returned in package/context order; +- two concurrent runs with the same `contextId` remain two entries; +- a context without a snapshot has `state: 'pending'`; +- no returned value contains the absolute temporary root. + +- [ ] **Step 6: run project-status tests and verify RED** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/status.test.ts +``` + +Expected: FAIL because `readProjectStatus` and `ProjectStatus` do not exist. + +- [ ] **Step 7: implement deterministic status projection** + +Add these model contracts: + +```ts +type ProjectContextStatus = { + runId: string; + producer: ContextProducer; + context: ContextDescriptor; + state: 'ready' | 'pending'; + latestSnapshot?: ContextSnapshot; +}; + +type ProjectStatus = { + schemaVersion: typeof contextStoreSchemaVersion; + workspaceId: string; + contexts: ProjectContextStatus[]; + issues: ContextStoreIssue[]; +}; +``` + +Implement `readProjectStatus` by calling `readContextWorkspaceStatus`, flattening every run/context +pair, and sorting by package root, product, environment, run start time, then run ID. Compute +`workspaceId` as `ws_` plus the first 24 hex characters of SHA-256 over the canonical real path of +the workspace root. Do not return the root itself. + +- [ ] **Step 8: run Task 1 tests and static checks** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/config.test.ts tests/context/status.test.ts +pnpm check +``` + +Expected: PASS with zero lint, type, and formatting errors. + +- [ ] **Step 9: commit Task 1** + +```bash +git add packages/rstack/src/config.ts packages/rstack/src/configExports.ts packages/rstack/src/context packages/rstack/tests/context +git commit -m "feat(rstack): add context activation and status" +``` + +--- + +### Task 2: implement the bounded passive build observer + +**Files:** + +- Create: `packages/rstack/src/context/build.ts` +- Create: `packages/rstack/tests/context/build.test.ts` +- Modify: `packages/rstack/src/context/index.ts` +- Modify: `packages/rstack/src/context/model.ts` + +**Interfaces:** + +- Consumes: `resolveContextWorkspace`, `writeContextRunManifest`, and `writeContextSnapshot`. +- Produces: + `createBuildContextPlugin(options: BuildContextPluginOptions): RsbuildPlugin`. +- Produces: + `appendBuildContextPlugin(config: T, plugin: RsbuildPlugin): T`. +- `BuildContextPluginOptions.producer` is only `'rsbuild' | 'rslib'`; product is only + `'application' | 'library'`. + +- [ ] **Step 1: write immutable append and identity tests** + +Assert that `appendBuildContextPlugin`: + +- returns a new config and a new top-level plugin array; +- preserves the original config and plugin array byte-for-byte; +- preserves falsy/nested Rsbuild plugin entries; +- appends exactly one observer; +- leaves an Rslib `lib[]` array referentially and structurally unchanged. + +Assert the observer produces the same `ctx_<24 hex>` ID for identical normalized inputs and a +different ID when environment, package root, config path, product, command, mode, or target changes. + +- [ ] **Step 2: run the tests and verify RED** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/build.test.ts +``` + +Expected: FAIL because the build observer module does not exist. + +- [ ] **Step 3: implement immutable append and observer identity** + +Use this option contract: + +```ts +type BuildContextPluginOptions = { + producer: 'rsbuild' | 'rslib'; + product: 'application' | 'library'; + capture: 'metadata' | 'deep'; + workspace: ResolvedContextWorkspace; + configPath?: string; + params: ConfigParams; + createRunId?: () => string; + now?: () => Date; +}; +``` + +Default run IDs to `run__`. Normalize package/config paths through +`path.relative(workspaceRoot, value).split(path.sep).join('/')`; reject any escaping result before +publishing. Derive context IDs from the exact identity tuple specified in the design document. + +- [ ] **Step 4: write lifecycle and bounds tests** + +Use a minimal fake plugin API that only records callbacks registered through +`onBeforeBuild`, `onBeforeDevCompile`, and `onAfterEnvironmentCompile`. Drive those callbacks with two +environment objects and temporary real stores. Assert: + +- the first aggregate before hook publishes one run manifest containing both contexts; +- repeated before hooks do not replace or duplicate the immutable manifest; +- environment-local sequences advance `1`, `2` across watch cycles; +- one environment does not advance another environment's sequence; +- 101 assets stores 100 and reports `truncated.assets === 1`; +- 101 chunks stores 100 and reports `truncated.chunks === 1`; +- 21 files in one chunk stores 20; +- `stats.hasErrors()` maps to `fail`, missing Stats maps to `error` and partial completeness; +- deep requests record `deep: 'unsupported'`, metadata records `deep: 'disabled'`; +- absolute asset and chunk paths are not persisted; +- a throwing Stats serializer does not reject the hook and warns once across repeated failures. + +- [ ] **Step 5: run lifecycle tests and verify RED** + +Run the Task 2 test command. Expected: the new lifecycle cases FAIL before hook implementation. + +- [ ] **Step 6: implement the observer hooks** + +Register the same `ensureRun` callback with `onBeforeBuild` and `onBeforeDevCompile`. It creates all +descriptors from the aggregate environment map and awaits one manifest publication promise. + +Register `onAfterEnvironmentCompile` to serialize immediately with: + +```ts +stats.toJson({ + all: false, + hash: true, + timings: true, + assets: true, + chunks: true, + errors: false, + warnings: false, +}); +``` + +Use `stats.hasErrors()` / `stats.hasWarnings()` only for status and the `hasErrors` / `hasWarnings` +booleans. Do not manufacture diagnostic counts when detailed arrays are disabled. Serialize the +`BuildMetadataFacet` from the design, apply all caps, publish one snapshot, and never retain Stats or +environment objects after the callback. + +Wrap every callback in one failure guard. Call `api.logger.warn` only on the first capture failure for +the plugin instance, then resolve normally. + +- [ ] **Step 7: run Task 2 tests and static checks** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/build.test.ts tests/context/store.test.ts +pnpm check +``` + +Expected: PASS with no capture exception escaping the tests. + +- [ ] **Step 8: commit Task 2** + +```bash +git add packages/rstack/src/context packages/rstack/tests/context/build.test.ts +git commit -m "feat(rstack): collect passive build metadata" +``` + +--- + +### Task 3: inject observers through only the CLI-specific loaders + +**Files:** + +- Create: `packages/rstack/tests/context/injection.test.ts` +- Modify: `packages/rstack/src/rsbuildConfig.ts` +- Modify: `packages/rstack/src/rslibConfig.ts` + +**Interfaces:** + +- Consumes: `resolveContextCapture`, `resolveContextWorkspace`, `createBuildContextPlugin`, and + `appendBuildContextPlugin`. +- Preserves the existing default exports and pure resolver semantics. +- Adds named `loadRsbuildConfig` and `loadRslibConfig` exports for focused tests without adding package + export-map entries. + +- [ ] **Step 1: write loader-injection tests** + +Test both object and async app/library config definitions through temporary `rstack.config.ts` files +and the existing config-state path override. Let the real loader, resolver, workspace discovery, and +append helper run. Assert: + +- disabled context returns the original resolved config with no observer; +- enabled context returns a shallow clone with one trailing `rstack:context-build` plugin; +- user plugins stay in original order and the original array is unchanged; +- app uses producer `rsbuild` and product `application`; +- library uses producer `rslib` and product `library`; +- Rslib `lib[]` remains unchanged; +- `ConfigParams` is passed unmodified to user config functions and observer options; +- the actual `filePath` is the workspace-discovery start path; +- `RSTACK_CONTEXT=0` prevents injection; +- importing/calling the pure resolvers alone never injects capture. + +- [ ] **Step 2: run injection tests and verify RED** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/injection.test.ts +``` + +Expected: enabled cases FAIL because loaders do not inject observers. + +- [ ] **Step 3: implement CLI-only injection** + +Keep this order in both loaders: + +```ts +const loaded = await loadRstackConfig(); +const config = await resolveToolConfig(loaded.configs, params); +const capture = resolveContextCapture(loaded.configs.context); +if (capture === 'off') return config; +const startPath = loaded.filePath ?? process.cwd(); +const workspace = await resolveContextWorkspace(startPath); +return appendBuildContextPlugin( + config, + createBuildContextPlugin({ producer, product, capture, workspace, configPath: loaded.filePath ?? undefined, params }), +); +``` + +Rsbuild must retain its existing config watch-file injection. Append the context plugin without +dropping or reordering those watch settings. Rslib must append only to top-level `plugins`. + +- [ ] **Step 4: run loader and existing config tests** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/injection.test.ts tests/config +pnpm check +``` + +Expected: PASS, including existing app/lib/Rstest extension behavior. + +- [ ] **Step 5: commit Task 3** + +```bash +git add packages/rstack/src/rsbuildConfig.ts packages/rstack/src/rslibConfig.ts packages/rstack/tests/context/injection.test.ts +git commit -m "feat(rstack): inject build context observers" +``` + +--- + +### Task 4: expose project status through one read-only stdio MCP server + +**Files:** + +- Create: `packages/rstack/src/context/mcp.ts` +- Create: `packages/rstack/src/mcp.ts` +- Create: `packages/rstack/tests/context/mcp.test.ts` +- Create: `website/docs/en/guide/cli/mcp.mdx` +- Create: `website/docs/zh/guide/cli/mcp.mdx` +- Modify: `packages/rstack/src/cli/commands.ts` +- Modify: `packages/rstack/tests/cli/help.test.ts` +- Modify: `packages/rstack/tests/cli/__snapshots__/help.test.ts.snap` +- Modify: `packages/rstack/rslib.config.ts` +- Modify: `packages/rstack/package.json` +- Modify: `pnpm-workspace.yaml` +- Modify: `pnpm-lock.yaml` +- Modify: `website/docs/en/guide/configuration.mdx` +- Modify: `website/docs/zh/guide/configuration.mdx` +- Modify: `docs/rfcs/0001-rstack-context-engine.md` + +**Interfaces:** + +- Consumes: `resolveContextWorkspace` and `readProjectStatus`. +- Produces: `createContextMcpServer(workspaceRoot: string): McpServer`. +- Produces: `runContextMcpServer(startPath: string): Promise`. +- CLI command: `rs mcp` and `rs mcp --help`. + +- [ ] **Step 1: add the pinned SDK dependency** + +Add this catalog entry: + +```yaml +'@modelcontextprotocol/sdk': '1.29.0' +``` + +Add `"@modelcontextprotocol/sdk": "catalog:"` to `packages/rstack` dependencies and run: + +```bash +pnpm install +``` + +Expected: lockfile resolves exactly `1.29.0`; do not add v2 packages. + +- [ ] **Step 2: write in-process MCP tests and verify RED** + +Use `Client` and `InMemoryTransport.createLinkedPair()` from the pinned SDK. Connect a server created +with a temporary workspace, then assert: + +- `listTools()` returns exactly `project_status` for this slice; +- its annotations are read-only, non-destructive, and closed-world; +- `callTool({ name: 'project_status', arguments: {} })` returns the current status; +- a second call sees a snapshot written after the first call, proving no startup-only cache; +- an empty store returns a valid empty status; +- returned content contains no absolute temporary path. + +Run: + +```bash +pnpm --filter rstack test -- tests/context/mcp.test.ts +``` + +Expected: FAIL because the MCP module does not exist. + +- [ ] **Step 3: implement the MCP server** + +Use: + +```ts +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +``` + +Register exactly one no-argument tool: + +```ts +server.registerTool( + 'project_status', + { + title: 'Rstack project status', + description: + 'Return checkout-local Rstack build contexts and their latest completed observations.', + annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }, + }, + async () => { + const status = await readProjectStatus(workspaceRoot); + return { + content: [{ type: 'text', text: renderProjectStatus(status) }], + structuredContent: status, + }; + }, +); +``` + +Server instructions must state that evidence is read-only, checkout-local, potentially partial, and +never proof that unobserved code is dead. `runContextMcpServer` connects a `StdioServerTransport`. +Do not print to stdout. + +- [ ] **Step 4: implement the CLI command and help** + +Add an `mcp` Rslib entry pointing to `src/mcp.ts`. Add `mcp` to root help. `rs mcp --help` prints: + +```text +Usage: + $ rs mcp + +Start the local Rstack MCP server over stdio +``` + +Reject positionals and unknown options. With no arguments, dynamically import `../mcp.ts` and await +`runContextMcpServer(process.cwd())`. Keep the import lazy so ordinary CLI startup does not load the +SDK. + +- [ ] **Step 5: run MCP and CLI tests** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/mcp.test.ts tests/cli/help.test.ts +pnpm --filter rstack build +``` + +Expected: MCP tests PASS, help snapshots PASS, and declaration generation succeeds. + +- [ ] **Step 6: document configuration and the CLI in English and Chinese** + +Add matching `mcp.mdx` pages with headings `usage`, `capture-build-context`, `monorepos`, and +`limitations`; give translated headings explicit English anchors in Chinese. Document: + +- one root MCP process reads all package runs; +- producers do not connect to the MCP process; +- `define.context({ enabled: true, capture: 'metadata' })` and environment overrides; +- Rslib-only, Rsbuild-only, and mixed repositories; +- no Turbo/Nx/daemon requirement; +- Phase 1A exposes status only and does not prove dead code. + +Add aligned `define.context` sections to both configuration guides. Update the RFC delivery plan to +label Phase 1A/1B/1C exactly as the design document does. + +- [ ] **Step 7: run documentation and repository checks** + +Run: + +```bash +pnpm check +pnpm check:spell +pnpm build +pnpm --filter rstack build:native +pnpm test +``` + +Expected: zero lint/type/format/spelling/heading errors; both builds pass; every test passes except +intentional repository skips. + +- [ ] **Step 8: commit Task 4** + +```bash +git add pnpm-workspace.yaml pnpm-lock.yaml packages/rstack website/docs docs/rfcs/0001-rstack-context-engine.md +git commit -m "feat(rstack): expose build context over MCP" +``` diff --git a/docs/superpowers/plans/2026-08-12-rsdoctor-context.md b/docs/superpowers/plans/2026-08-12-rsdoctor-context.md new file mode 100644 index 00000000..bae2ad7b --- /dev/null +++ b/docs/superpowers/plans/2026-08-12-rsdoctor-context.md @@ -0,0 +1,162 @@ +# Rsdoctor context implementation plan + + + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development +> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox +> (`- [ ]`) syntax for tracking. + +**Goal:** Complete RFC phases 1B and 1C by adding static Rsdoctor analysis and report links behind +the existing single Rstack MCP server. + +**Architecture:** A narrow adapter dynamically loads pinned `@rsdoctor/agent-cli@0.1.1`, validates +an explicit JSON artifact, and invokes only names from the package's public tool catalog. The MCP +remains stateless and stdio-only. + +**Tech stack:** TypeScript, Node.js 22+, Rstest, MCP TypeScript SDK 1.29.0, +`@rsdoctor/agent-cli@0.1.1`, immutable context-v1 records. + +## Global constraints + +- Work on `codex/rstack-mcp-observability`, never `main` or `master`. +- Follow strict red-green-refactor TDD for every production behavior. +- Pin `@rsdoctor/agent-cli` to exactly `0.1.1`; import only public package-root exports. +- Do not use or start the legacy live Rsdoctor MCP server, a report server, a daemon, or a build. +- Resolve explicit artifact/report paths normally and require artifact JSON to contain an + object-valued `data` property. +- Expose only the pinned tool names returned by `getToolCatalog()` and return their JSON results + directly. +- Destructive context-store retention is deferred until real artifact sizes and access patterns are + measured and a portable recovery contract exists. +- English and Chinese documentation remain aligned in structure, meaning, links, and anchors. + +--- + +### Task 1: add the pinned Rsdoctor adapter and artifact validation + +**Files:** + +- Create: `packages/rstack/src/context/rsdoctor.ts` +- Create: `packages/rstack/tests/context/rsdoctor.test.ts` +- Modify: `packages/rstack/src/context/index.ts` +- Modify: `packages/rstack/package.json` +- Modify: `pnpm-workspace.yaml` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** + +- Produces: `listRsdoctorTools(): RsdoctorToolDescriptor[]`. +- Produces: + `analyzeRsdoctorArtifact(workspaceRoot: string, request: RsdoctorAnalysisRequest): Promise`. +- `RsdoctorAnalysisRequest = { dataFile: string; toolName: string; input?: Record }`. +- `RsdoctorAnalysisResult = { toolName: string; dataFile: string; result: JsonValue }`. + +- [ ] **Step 1: add the exact dependency and contract test** + +Add catalog entry `@rsdoctor/agent-cli: 0.1.1`, add it to Rstack runtime dependencies, install, then +write a test asserting `listRsdoctorTools()` is non-empty, stable-sorted, unique, and contains the ten +catalog names published by version 0.1.1. Assert every descriptor has an object JSON schema. + +- [ ] **Step 2: verify RED** + +Run `pnpm --filter rstack test -- tests/context/rsdoctor.test.ts`. Expected: module/API missing. + +- [ ] **Step 3: implement the catalog adapter** + +Import `getToolCatalog` and `createInProcessRsdoctorCliToolExecutor` from the package root. Convert the +catalog to frozen plain descriptors and retain one lazily-created in-process executor per MCP process. +Do not copy or rename Rsdoctor tools. + +- [ ] **Step 4: write artifact-boundary tests** + +Use temporary workspaces to cover unreadable artifacts, malformed JSON, missing/non-object `data`, +invalid tool input, and unknown tool names. Assert a valid fixture invokes a real catalog tool and +returns the requested data path. + +- [ ] **Step 5: verify RED, implement, and verify GREEN** + +Resolve the candidate with `path.resolve`, read and parse it, validate the minimum brief envelope, +execute the catalog tool, and return its JSON result. Run the focused tests and `pnpm check`. + +- [ ] **Step 6: commit Task 1** + +Commit as `feat(rstack): add bounded Rsdoctor analysis`. + +--- + +### Task 2: expose Rsdoctor analysis and report links through the one MCP server + +**Files:** + +- Create: `packages/rstack/src/context/report.ts` +- Create: `packages/rstack/tests/context/report.test.ts` +- Modify: `packages/rstack/src/context/mcp.ts` +- Modify: `packages/rstack/tests/context/mcp.test.ts` + +**Interfaces:** + +- Produces: + `resolveRsdoctorReport(workspaceRoot: string, dataFile: string): Promise`. +- `RsdoctorReportResult` returns the data file plus either a sibling HTML report, the normal + `.rsdoctor/manifest.json`, or an explicit no-report reason. +- MCP adds `rsdoctor_analyze` and `report_link`; `project_status` remains unchanged. + +- [ ] **Step 1: write report resolution tests and verify RED** + +Test sibling `report-rsdoctor.html`, one custom sibling HTML file, the normal manifest, ambiguous +HTML, and a missing report. + +- [ ] **Step 2: implement the report resolver** + +Return an ordinary resolved path and `file:` URI only for an existing report. Otherwise return a +concise reason and the explicit structured `rsdoctor_analyze` next action; never start a server. + +- [ ] **Step 3: write MCP protocol tests and verify RED** + +Assert the server lists exactly `project_status`, `rsdoctor_analyze`, and `report_link`. Call +`rsdoctor_analyze` against a real fixture, verify ordinary tool/artifact errors are MCP errors, and +verify `report_link` returns a resource link only for an existing report. + +- [ ] **Step 4: implement the tools and verify GREEN** + +Use strict Zod input schemas. `rsdoctor_analyze` receives explicit `dataFile`, a catalog tool name, +and optional input. `report_link` receives explicit `dataFile`. Return short text plus object-valued +structured content. Do not register each Rsdoctor catalog item as a separate MCP server/tool. + +- [ ] **Step 5: commit Task 2** + +Run focused tests and `pnpm check`; commit as `feat(rstack): expose Rsdoctor context tools`. + +--- + +### Task 3: defer destructive context-store retention + +Do not ship a deletion API or `context_prune` MCP tool in Phase 1. Continue bounding individual +reads and writes, but do not claim that cache growth is bounded by deletion. Revisit retention only +after real artifact sizes and access patterns are measured and a portable recovery contract exists. + +--- + +### Task 4: document and verify Rsdoctor context tools + +**Files:** + +- Modify: `website/docs/en/guide/cli/mcp.mdx` +- Modify: `website/docs/zh/guide/cli/mcp.mdx` +- Modify: `docs/rfcs/0001-rstack-context-engine.md` + +- [ ] **Step 1: document the exact trust and lifecycle model** + +Document explicit artifact selection, supported catalog names, the direct JSON result, report-link +behavior, and the fact that MCP never starts builds/report servers. Keep EN/ZH headings and examples +aligned. + +- [ ] **Step 2: mark delivery status honestly** + +Mark 1B/1C implemented downstream. Keep upstream Rsdoctor artifact-version/export-usage gaps open; +do not imply Rstack can derive facts absent from the artifact. + +- [ ] **Step 3: run full verification and commit** + +Run `pnpm check`, `pnpm check:spell`, `pnpm build`, `pnpm --filter rstack build:native`, and +`pnpm test`. Commit as `docs: document Rsdoctor context tools`. diff --git a/docs/superpowers/plans/2026-08-13-context-package-agent-skills.md b/docs/superpowers/plans/2026-08-13-context-package-agent-skills.md new file mode 100644 index 00000000..d3d4202f --- /dev/null +++ b/docs/superpowers/plans/2026-08-13-context-package-agent-skills.md @@ -0,0 +1,219 @@ + + +# Rstack context package and agent plugin implementation plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Ship Rstack Context as a separated runtime package in `rstack-cli` and distribute its Codex/Claude workflows through the existing `rstack` plugin in `rstackjs/agent-skills`. + +**Architecture:** `@rstackjs/context` owns the evidence model, local store, producer capture, Rsdoctor graph analysis, composed queries, and MCP server. The `rstack` package owns CLI/config integration and starts that server through `rs mcp`. The repository-based `rstack` plugin in `agent-skills` owns the MCP bootstrap, agent workflows, installation documentation, and evaluations; it never duplicates runtime analysis. + +**Tech Stack:** TypeScript, Rslib, Rstest, Rslint, MCP SDK, Zod, Codex plugins, Claude Code plugins, Agent Skills. + +## Global constraints + +- Keep work on `codex/rstack-mcp-observability` in `rstack-cli` and `codex/rstack-context-plugin` in `agent-skills`. +- Do not create another marketplace or another plugin identity; extend the existing `rstack` plugin. +- Do not add pkg.pr.new or publish the plugin through npm; plugin distribution stays Git-repository based. +- Keep `rs mcp` and ordinary Rstack configuration as the only runtime bootstrap. +- Preserve the existing MCP tool names and evidence semantics. +- Keep source execution, coverage, reachability, shipment, and public-contract evidence as independent axes. +- Avoid unrelated changes in either repository. + +--- + +### Task 1: extend the official Rstack plugin + +**Files:** + +- Create: `/fast/projects/agent-skills/.mcp.json` +- Modify: `/fast/projects/agent-skills/.codex-plugin/plugin.json` +- Modify: `/fast/projects/agent-skills/.claude-plugin/plugin.json` +- Modify: `/fast/projects/agent-skills/.claude-plugin/marketplace.json` +- Create: `/fast/projects/agent-skills/skills/{analyze-build,assess-change-impact,debug-dev-cycle,explain-dead-code,find-unused-code,review-context-change}/SKILL.md` +- Modify: `/fast/projects/agent-skills/skills/rsdoctor-analysis/SKILL.md` +- Modify: `/fast/projects/agent-skills/README.md` +- Test: `/fast/projects/agent-skills/scripts/test-rstack-context-plugin.mjs` +- Test: `/fast/projects/agent-skills/skills-test/rstack-context/evals/evals.json` +- Test: `/fast/projects/agent-skills/skills-test/rstack-context/report.md` + +**Interfaces:** + +- Consumes: workspace-local `rstack/package.json` and the `rs mcp` command. +- Produces: one MCP server named `rstack` and six context-aware user workflows inside the existing plugin. + +- [ ] **Step 1: Write a failing plugin contract test** + +The test parses both manifests and `.mcp.json`, asserts the `rstack` server exists, executes the configured launcher against a fake workspace-local `rstack` package and a PATH-only `rs`, and validates the six skills plus their Rsdoctor fallback routing. + +- [ ] **Step 2: Run the contract test and record the expected missing-MCP/missing-skill failure** + +Run: `node scripts/test-rstack-context-plugin.mjs` + +Expected: FAIL because `.mcp.json` and the six skills do not exist. + +- [ ] **Step 3: Add the MCP config, update both manifests, and add the six skills** + +Use a single inline Node launcher so the host project remains `process.cwd()`. Resolve `rstack/package.json` first and import its declared `rs` binary with `mcp`; otherwise spawn `rs mcp` from `PATH` with inherited stdio and exit status. + +- [ ] **Step 4: Add context eval definitions and align Rsdoctor routing** + +Cover stored-failure diagnosis, monorepo context selection, artifact-scoped unused candidates, exact dead-code explanation, snapshot comparison, and missing-artifact recovery. Keep `rsdoctor-analysis` usable without Rstack Context and prefer MCP evidence when the server is available. + +- [ ] **Step 5: Validate the plugin and skills** + +Run: + +```bash +node scripts/test-rstack-context-plugin.mjs +python3 ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py . +for skill in skills/analyze-build skills/assess-change-impact skills/debug-dev-cycle skills/explain-dead-code skills/find-unused-code skills/review-context-change; do + python3 ~/.codex/skills/.system/skill-creator/scripts/quick_validate.py "$skill" +done +pnpm lint +``` + +- [ ] **Step 6: Commit the agent-skills plugin change** + +```bash +git add .mcp.json .codex-plugin .claude-plugin skills README.md scripts/test-rstack-context-plugin.mjs skills-test/rstack-context +git commit -m "feat(plugin): add Rstack Context workflows" +``` + +### Task 2: create the separated context package + +**Files:** + +- Create: `packages/context/package.json` +- Create: `packages/context/rslib.config.ts` +- Create: `packages/context/tsconfig.json` +- Move: `packages/rstack/src/context/*.ts` to `packages/context/src/*.ts` +- Move: context-unit tests from `packages/rstack/tests/context` to `packages/context/tests` +- Modify: `packages/rstack/package.json` +- Modify: `packages/rstack/src/{config.ts,configExports.ts,mcp.ts,rsbuildConfig.ts,rslibConfig.ts}` +- Modify: `packages/rstack/tests/context/{config.test.ts,injection.test.ts,mcp.test.ts}` +- Modify: `pnpm-workspace.yaml` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** + +- Produces: package `@rstackjs/context` with its root API and `createContextMcpServer`. +- Consumes: injected `withConfigTarget`, `rslintConfigPath`, and `rstestConfigPath` from the Rstack CLI adapter for explicit lint/test capture. + +- [ ] **Step 1: Add failing package-boundary tests** + +Assert `@rstackjs/context` can be imported without importing the Rstack CLI package, and assert the Rstack MCP adapter supplies its wrapper configuration and config-target callback. + +- [ ] **Step 2: Run focused tests and record the expected missing-package failure** + +Run: `pnpm --filter @rstackjs/context test` + +Expected: FAIL because the workspace package does not exist. + +- [ ] **Step 3: Move the context engine and remove Rstack-private imports** + +Move the evidence engine intact. Add capture dependencies to lint/test/MCP entry points instead of importing `packages/rstack/src/config.ts`; keep local context-store cache helpers inside the package. + +- [ ] **Step 4: Wire Rstack CLI to the package** + +Import context config/build APIs from `@rstackjs/context`. In `src/mcp.ts`, pass `withRstackConfigTarget` and absolute built wrapper paths before connecting the stdio transport. + +- [ ] **Step 5: Move unit tests and retain CLI integration tests** + +Use `@rstest/core` for package tests. Keep config injection and built `rs mcp` tests in `packages/rstack/tests/context`. + +- [ ] **Step 6: Build and test both packages** + +Run: + +```bash +pnpm install +pnpm --filter @rstackjs/context build +pnpm --filter @rstackjs/context test +pnpm --filter rstack build +pnpm --filter rstack test +pnpm check +``` + +- [ ] **Step 7: Commit the package extraction** + +```bash +git add packages/context packages/rstack pnpm-workspace.yaml pnpm-lock.yaml +git commit -m "refactor(context): extract context runtime package" +``` + +### Task 3: remove duplicate plugin distribution from Rstack CLI + +**Files:** + +- Delete: `plugins/rstack-codex/**` +- Delete: `plugins/rstack-claude/**` +- Delete: `.agents/plugins/marketplace.json` +- Delete: `packages/rstack/tests/context/plugin-bundles.test.ts` +- Delete: `packages/rstack/tests/context/plugin-skill-recovery.test.ts` +- Modify: `docs/rfcs/0001-rstack-context-engine.md` +- Modify: `website/docs/en/guide/ai.mdx` +- Modify: `website/docs/zh/guide/ai.mdx` + +**Interfaces:** + +- Consumes: the committed `rstackjs/agent-skills` plugin structure from Task 1. +- Produces: one authoritative runtime repository and one authoritative agent-distribution repository. + +- [ ] **Step 1: Update the RFC architecture and ownership map** + +Document `@rstackjs/context` as the runtime package, `rstack` as the CLI adapter, and `rstackjs/agent-skills` as the plugin distribution. + +- [ ] **Step 2: Remove the two local plugin copies and their copy-parity tests** + +Delete only plugin-distribution files; retain every MCP runtime and integration test. + +- [ ] **Step 3: Align English and Chinese installation documentation** + +Use the existing repository-based installation commands for the `rstack` plugin and explain that the project-local `rstack` dependency supplies `rs mcp`. + +- [ ] **Step 4: Run full Rstack verification** + +Run: + +```bash +pnpm build +pnpm --filter rstack build:native +pnpm test +pnpm check +pnpm check:spell +``` + +- [ ] **Step 5: Commit distribution cleanup** + +```bash +git add -A plugins .agents/plugins packages/rstack/tests/context docs website +git commit -m "docs(context): use the official Rstack agent plugin" +``` + +### Task 4: install and dogfood the coordinated result + +**Files:** + +- No tracked files unless validation finds an in-scope defect. + +**Interfaces:** + +- Consumes: packed or workspace-built Rstack CLI and the local `agent-skills` marketplace. +- Produces: an evidenced plugin installation and real MCP handshake. + +- [ ] **Step 1: Validate the built plugin launcher against the built Rstack CLI** + +Run the launcher from a scratch consumer with a workspace-local `rstack` package and send MCP initialize/list-tools JSON-RPC over stdio. + +- [ ] **Step 2: Install the local repository marketplace and plugin** + +Use the existing `rstack` marketplace identity; do not create another marketplace file. + +- [ ] **Step 3: Confirm the MCP reports all context tools** + +Call initialize and tools/list, then query `project_status` against a dogfood checkout. + +- [ ] **Step 4: Review both branch diffs and commit any in-scope corrections** + +Confirm `rstack-cli` contains no installable plugin copy and `agent-skills` contains no evidence-engine implementation. diff --git a/docs/superpowers/plans/2026-08-14-context-plugin-boundary.md b/docs/superpowers/plans/2026-08-14-context-plugin-boundary.md new file mode 100644 index 00000000..a34a2242 --- /dev/null +++ b/docs/superpowers/plans/2026-08-14-context-plugin-boundary.md @@ -0,0 +1,755 @@ +# Context plugin boundary implementation plan + + + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make `@rstackjs/context` a standalone multi-entry package and integrate it into Rstack CLI through the stacked plugin SPI with minimal, one-way coupling, then publish previews and validate the installed agent plugin against real repositories. + +**Architecture:** Context exports focused producer/consumer entry points plus a structurally compatible `./rstack` plugin without importing `rstack`. Rstack CLI stacks on PR #336, registers that plugin internally, and retains only first-party config and explicit MCP host adapters. Agent Skills launches the workspace-local `rs mcp` runtime and is validated against preview packages rather than bundling another Context runtime. + +**Tech Stack:** TypeScript, pnpm 11, Rslib, Rsbuild, Rstest, Rslint, MCP SDK, pkg.pr.new, GitHub CLI. + +## Global constraints + +- `@rstackjs/context` must not import or declare a dependency on `rstack`. +- Rsdoctor produces artifacts; Context consumes them through `@rsdoctor/agent-cli`. There is no Context plugin for Rsdoctor. +- Preserve the existing Context root API and MCP tool schemas. +- Focused entry points must load independently when unrelated producers are absent. +- Missing Rstest or Rslint support degrades to unavailable evidence rather than preventing build or Rsdoctor analysis. +- Published Context packages must use ordinary semver dependencies; pkg.pr.new URLs may appear only in root development overrides. +- Keep corresponding English and Chinese Rstack documentation aligned in structure, meaning, links, examples, and heading anchors. +- Use TDD for every behavior change and commit each independently testable deliverable. +- Preserve existing user changes in every worktree and never reset unrelated files. + +--- + +## File structure + +### Context repository + +- `src/rsbuild.ts`: focused exports for the existing Rsbuild observer. +- `src/rslib.ts`: Rslib-facing exports over the same environment observer. +- `src/rstest.ts`: test capture, result, execution-evidence, and related-test contracts. +- `src/rslint.ts`: lint capture, diagnostic, and fix-preview contracts. +- `src/rstack.ts`: structural Rstack plugin factory; no Rstack imports. +- `src/rsdoctor.ts`: existing Rsdoctor consumer adapter and its focused package entry point. +- `src/mcp.ts`: existing MCP server entry point. +- `src/index.ts`: compatibility aggregate exports. +- `rslib.config.ts`: build every public subpath. +- `package.json`: export map and semver-safe Rsdoctor dependency. +- `pnpm-lock.yaml`: root development override resolution. +- `tests/packageExports.test.ts`: independent entry-point and packed-manifest checks. +- `tests/rstack.test.ts`: structural plugin behavior. + +### Rstack CLI repository + +- `packages/rstack/src/plugin.ts`: modifier invocation-context types from PR #336. +- `packages/rstack/src/pluginRuntime.ts`: pass invocation context to modifiers. +- `packages/rstack/src/config.ts`: register the Context plugin after user plugins. +- `packages/rstack/src/contextPlugin.ts`: construct the Context plugin from loaded config metadata. +- `packages/rstack/src/rsbuildConfig.ts`: resolve config and apply normal plugin modifiers only. +- `packages/rstack/src/rslibConfig.ts`: resolve config and apply normal plugin modifiers only. +- `packages/rstack/src/rstestConfig.ts`: preserve automatic extends while passing native modifier context. +- `packages/rstack/src/mcp.ts`: thin explicit lint/test host adapter using focused Context subpaths. +- `packages/rstack/src/relatedTests.ts`: CLI-owned related-test resolver using the Context contract. +- `packages/rstack/src/context.ts`: compatibility re-export. +- `packages/rstack/tests/pluginRuntime.test.ts`: modifier-context contract. +- `packages/rstack/tests/context/plugin.test.ts`: built-in Context plugin integration and deduplication. +- `packages/rstack/tests/context/mcp.test.ts`: explicit host capture behavior. +- `packages/rstack/tests/types/resolution-bundler/index.ts`: public structural compatibility. +- `packages/rstack/tests/types/resolution-nodenext/index.ts`: public structural compatibility. +- `website/docs/en/guide/plugins.mdx` and `website/docs/zh/guide/plugins.mdx`: internal Context plugin relationship. +- `website/docs/en/guide/cli/mcp.mdx` and `website/docs/zh/guide/cli/mcp.mdx`: runtime ownership and graceful degradation. + +### Agent Skills repository + +- `scripts/test-rstack-context-plugin.mjs`: validate launcher behavior against a real preview-installed Rstack package when an integration fixture is supplied. +- `README.md`: document that the plugin launches workspace-local Rstack and does not bundle Context. +- Existing Context-related skills: adjust only when real dogfood exposes a workflow defect. + +--- + +### Task 1: Publish-safe context dependency and focused entry points + +**Files:** + +- Modify: `/fast/projects/context/package.json` +- Modify: `/fast/projects/context/pnpm-lock.yaml` +- Modify: `/fast/projects/context/rslib.config.ts` +- Modify: `/fast/projects/context/src/index.ts` +- Create: `/fast/projects/context/src/rsbuild.ts` +- Create: `/fast/projects/context/src/rslib.ts` +- Create: `/fast/projects/context/src/rstest.ts` +- Create: `/fast/projects/context/src/rslint.ts` +- Test: `/fast/projects/context/tests/packageExports.test.ts` + +**Interfaces:** + +- Consumes: existing exports from `build.ts`, `testRun.ts`, `execution.ts`, `lint.ts`, `rsdoctor.ts`, and `mcp.ts`. +- Produces: public package subpaths `./rsbuild`, `./rslib`, `./rstest`, `./rslint`, `./rsdoctor`, and the existing `./mcp`. + +- [ ] **Step 1: Write failing export-map and package-isolation tests** + +Add a test that reads `package.json` and asserts the complete subpath set, ordinary semver for `dependencies['@rsdoctor/agent-cli']`, and no `rstack` dependency in any dependency section: + +```ts +expect(Object.keys(packageJson.exports).sort()).toEqual([ + '.', + './mcp', + './package.json', + './rsbuild', + './rsdoctor', + './rslib', + './rslint', + './rstest', +]); +expect(packageJson.dependencies['@rsdoctor/agent-cli']).toBe('0.1.1'); +for (const section of ['dependencies', 'devDependencies', 'peerDependencies']) { + expect(packageJson[section]?.rstack).toBeUndefined(); +} +``` + +Add dynamic import assertions for each focused entry point created by this task after a build. + +- [ ] **Step 2: Run the focused test and confirm RED** + +Run: + +```bash +pnpm test tests/packageExports.test.ts +``` + +Expected: FAIL because the focused export map and built files do not exist and the Rsdoctor dependency is an exotic URL. + +- [ ] **Step 3: Add focused source barrels and Rslib entries** + +Export only producer-relevant symbols. For example: + +```ts +// src/rsbuild.ts +export { + appendBuildContextPlugin, + createBuildContextPlugin, + type BuildContextPluginOptions, +} from './build.ts'; +``` + +```ts +// src/rstest.ts +export { + captureTestSnapshot, + listTestResults, + type RelatedTestRequest, + type ResolveRelatedTests, + type TestCaptureDependencies, + type TestCaptureResult, + type TestResultPage, + type TestResultsQuery, + type TestSnapshotRequest, +} from './testRun.ts'; +export { type ExecutionFacet, type TestExecutionRequest } from './execution.ts'; +``` + +Add matching Rslib `source.entry` values and package export-map entries. Keep the root barrel exports unchanged. + +- [ ] **Step 4: Move the Rsdoctor preview to a root-only override** + +Set the published dependency to: + +```json +"@rsdoctor/agent-cli": "0.1.1" +``` + +Add a root pnpm override for the development checkout: + +```json +"pnpm": { + "overrides": { + "@rsdoctor/agent-cli": "https://pkg.pr.new/@rsdoctor/agent-cli@1903" + } +} +``` + +Run `pnpm install --frozen-lockfile=false` and confirm `pnpm why @rsdoctor/agent-cli` resolves the preview locally while the package manifest remains semver-safe. + +- [ ] **Step 5: Build and rerun the focused tests** + +Run: + +```bash +pnpm build +pnpm test tests/packageExports.test.ts tests/rsdoctor.test.ts +pnpm check +``` + +Expected: all commands pass; every subpath imports from `dist`, and omitted Rsdoctor sections retain the preview contract. + +- [ ] **Step 6: Commit** + +```bash +git add package.json pnpm-lock.yaml rslib.config.ts src/index.ts src/rsbuild.ts src/rslib.ts src/rstest.ts src/rslint.ts tests/packageExports.test.ts +git commit -m "feat: expose focused context entry points" +``` + +### Task 2: Context-owned structural Rstack plugin + +**Files:** + +- Create: `/fast/projects/context/src/rstack.ts` +- Modify: `/fast/projects/context/rslib.config.ts` +- Modify: `/fast/projects/context/package.json` +- Modify: `/fast/projects/context/src/index.ts` +- Test: `/fast/projects/context/tests/rstack.test.ts` +- Test: `/fast/projects/context/tests/packageExports.test.ts` + +**Interfaces:** + +- Consumes: `ContextConfig`, `resolveContextCapture`, `resolveContextWorkspace`, `recordContextInputFiles`, `createBuildContextPlugin`, and `appendBuildContextPlugin`. +- Produces: `createRstackContextPlugin(options): ContextRstackPlugin`, where the returned object has `name: 'rstack:context'` and a structural `setup(api)` method. + +- [ ] **Step 1: Write failing plugin tests** + +Cover capture-off, application, library, input deduplication, native params, existing plugin preservation, and mixed app/lib registration. Use a fake structural API that records modifiers: + +```ts +const plugin = createRstackContextPlugin({ + config: { enabled: true }, + configFilePath: '/workspace/rstack.config.ts', + configDependencies: ['/workspace/shared.ts'], + cwd: '/workspace', +}); + +expect(plugin.name).toBe('rstack:context'); +plugin.setup(api); +expect([...modifiers.keys()]).toEqual(['app', 'lib']); +``` + +Assert the app modifier passes `producer: 'rsbuild'`, the lib modifier passes `producer: 'rslib'`, and both receive the exact modifier `params` object. + +- [ ] **Step 2: Run the tests and confirm RED** + +Run: + +```bash +pnpm test tests/rstack.test.ts +``` + +Expected: FAIL because `src/rstack.ts` and its export do not exist. + +- [ ] **Step 3: Implement the structural plugin factory** + +Define local structural types rather than importing `rstack`: + +```ts +type ContextRstackModifierContext = Readonly<{ params: ConfigParams }>; +type ContextRstackPluginApi = { + modifyConfig( + kind: 'app' | 'lib', + handler: ( + config: RsbuildConfig, + context: ContextRstackModifierContext, + ) => RsbuildConfig | Promise, + ): void; +}; + +type ContextRstackPlugin = { + name: 'rstack:context'; + setup(api: ContextRstackPluginApi): void; +}; +``` + +Resolve workspace and input metadata lazily once per plugin instance. Register no modifiers when capture is off. Append one observer per resolved config without mutating existing arrays. + +- [ ] **Step 4: Export and build the `./rstack` entry point** + +Add `rstack: './src/rstack.ts'` to Rslib entries and map `./rstack` to `dist/rstack.{js,d.ts}` in `package.json`. Re-export the factory and its option/structural types from the compatibility barrel. + +Extend `tests/packageExports.test.ts` so the expected export list and independent-import assertion now include `./rstack`. + +- [ ] **Step 5: Verify behavior and no reverse dependency** + +Run: + +```bash +pnpm build +pnpm test tests/rstack.test.ts tests/packageExports.test.ts +pnpm check +rg -n "from ['\"]rstack|import\(['\"]rstack" src package.json +``` + +Expected: tests and checks pass; the final `rg` returns no matches. + +- [ ] **Step 6: Commit** + +```bash +git add src/rstack.ts src/index.ts rslib.config.ts package.json tests/rstack.test.ts tests/packageExports.test.ts +git commit -m "feat: add structural Rstack context plugin" +``` + +### Task 3: publish and validate the context preview + +**Files:** + +- No source changes expected. +- Generated test artifact: a temporary packed tarball outside the repository. + +**Interfaces:** + +- Consumes: commits from Tasks 1 and 2. +- Produces: a pkg.pr.new Context preview URL whose packed manifest has no exotic transitive dependency. + +- [ ] **Step 1: Run complete Context verification** + +Run: + +```bash +pnpm install --frozen-lockfile +pnpm build +pnpm test +pnpm check +pnpm pack --pack-destination "$(mktemp -d)" +``` + +Expected: 137 or more tests pass, build/check pass, and packing succeeds. + +- [ ] **Step 2: Push and wait for Context PR checks** + +Run: + +```bash +git push origin codex/extract-context +gh pr checks 1 --repo rstackjs/context --watch --interval 10 +``` + +Expected: verify, publish, and Continuous Releases pass while PR #1 remains draft. + +- [ ] **Step 3: Install the preview in a clean consumer** + +Resolve the current short SHA and use it in a temporary project: + +```bash +context_sha=$(git rev-parse --short HEAD) +consumer_dir=$(mktemp -d) +cd "$consumer_dir" +pnpm init +pnpm add "https://pkg.pr.new/rstackjs/context/@rstackjs/context@${context_sha}" +node -e "Promise.all(['rsbuild','rslib','rstest','rslint','rsdoctor','mcp','rstack'].map((name)=>import('@rstackjs/context/'+name)))" +``` + +Expected: install and every import succeed without an exotic-subdependency error. + +### Task 4: stack Rstack context on the plugin SPI + +**Files:** + +- Merge: `origin/pr-336` into `/fast/projects/rstack-cli` branch `codex/rstack-mcp-observability`. +- Modify during conflict resolution: `packages/rstack/src/config.ts` +- Modify during conflict resolution: `packages/rstack/src/cli/commands.ts` +- Modify during conflict resolution: `packages/rstack/src/rsbuildConfig.ts` +- Modify during conflict resolution: `packages/rstack/src/rslibConfig.ts` +- Modify during conflict resolution: `packages/rstack/src/rstestConfig.ts` +- Modify: `packages/rstack/package.json` +- Modify: `pnpm-workspace.yaml` +- Modify: `pnpm-lock.yaml` + +**Interfaces:** + +- Consumes: PR #336 plugin SPI and the Context preview from Task 3. +- Produces: a clean stacked branch retaining `define.context`, `rs mcp`, and all plugin SPI behavior. + +- [ ] **Step 1: Update the Context preview before stacking** + +Replace the inconsistent preview references in `packages/rstack/package.json` and `pnpm-workspace.yaml` with the Task 3 preview URL, then run: + +```bash +pnpm install --frozen-lockfile=false +pnpm --filter rstack build +git add packages/rstack/package.json pnpm-workspace.yaml pnpm-lock.yaml +git commit -m "build: update context preview" +``` + +Expected: installation succeeds because the Context package no longer exposes an exotic subdependency. + +- [ ] **Step 2: Merge the plugin SPI head** + +Run: + +```bash +git fetch https://github.com/rstackjs/rstack-cli.git refs/pull/336/head:refs/remotes/origin/pr-336 +git merge --no-ff origin/pr-336 -m "chore: stack context on plugin SPI" +``` + +Resolve conflicts by retaining PR #336 plugin registration/modifier behavior and PR #344's `context` config plus built-in `mcp` dispatch. Do not retain direct build-observer injection in `rsbuildConfig.ts` or `rslibConfig.ts`; Task 6 replaces it through the plugin. + +- [ ] **Step 3: Run the stacked baseline** + +Run: + +```bash +pnpm --filter rstack build +pnpm --filter rstack test +``` + +Expected: the stacked baseline compiles and existing tests pass before SPI extension work begins. + +### Task 5: pass native invocation context through the plugin SPI + +**Files:** + +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/plugin.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/pluginRuntime.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/config.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/rsbuildConfig.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/rslibConfig.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/rstestConfig.ts` +- Test: `/fast/projects/rstack-cli/packages/rstack/tests/pluginRuntime.test.ts` +- Test: `/fast/projects/rstack-cli/packages/rstack/tests/config/plugin-modifiers/adapters.test.ts` + +**Interfaces:** + +- Consumes: PR #336 `RstackConfigMap`, `modifyConfig`, and `applyConfigModifiers`. +- Produces: `RstackConfigModifierContextMap` and `applyConfigModifiers(kind, config, context)` with exact native params. + +- [ ] **Step 1: Write failing modifier-context tests** + +Add a plugin runtime test: + +```ts +const params = { command: 'build', env: 'production', envMode: 'production' }; +plugin.setup(({ modifyConfig }) => { + modifyConfig('app', (_config, context) => { + observed = context.params; + }); +}); +await runtime.applyConfigModifiers('app', {}, { params }); +expect(observed).toBe(params); +``` + +Add adapter tests proving app, lib, and automatic Rstest extends forward their native params. + +- [ ] **Step 2: Run focused tests and confirm RED** + +Run: + +```bash +pnpm --filter rstack test -- tests/pluginRuntime.test.ts tests/config/plugin-modifiers/adapters.test.ts +``` + +Expected: type/test failures because modifier handlers currently receive one argument. + +- [ ] **Step 3: Add the typed context map** + +Define a second-argument context object in `plugin.ts`: + +```ts +export type RstackConfigModifierContextMap = { + app: Readonly<{ params: RsbuildConfigParams }>; + lib: Readonly<{ params: RslibConfigParams }>; + test: Readonly<{ params: RsbuildConfigParams }>; + doc: Readonly>; + lint: Readonly>; + fmt: Readonly>; + staged: Readonly>; +}; +``` + +Update modifier handler and runtime signatures to receive the matching context. Existing handlers that ignore the second argument remain compatible. + +- [ ] **Step 4: Pass native params from tool loaders** + +Call app, lib, and test modifiers with `{ params }`. Pass `{}` for doc, lint, fmt, and staged. When Rstest builds automatic app/lib extends, pass the same native Rstest/Rsbuild params to the selected modifier. + +- [ ] **Step 5: Run focused and package checks** + +Run: + +```bash +pnpm --filter rstack test -- tests/pluginRuntime.test.ts tests/config/plugin-modifiers +pnpm --filter rstack build +pnpm check +``` + +Expected: tests, build, lint, type checking, and formatting pass. + +- [ ] **Step 6: Commit** + +```bash +git add packages/rstack/src/plugin.ts packages/rstack/src/pluginRuntime.ts packages/rstack/src/config.ts packages/rstack/src/rsbuildConfig.ts packages/rstack/src/rslibConfig.ts packages/rstack/src/rstestConfig.ts packages/rstack/tests/pluginRuntime.test.ts packages/rstack/tests/config/plugin-modifiers +git commit -m "feat(rstack): pass tool context to plugin modifiers" +``` + +### Task 6: consume the context plugin and remove scattered build coupling + +**Files:** + +- Create: `/fast/projects/rstack-cli/packages/rstack/src/contextPlugin.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/config.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/rsbuildConfig.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/rslibConfig.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/mcp.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/relatedTests.ts` +- Modify: `/fast/projects/rstack-cli/packages/rstack/src/context.ts` +- Test: `/fast/projects/rstack-cli/packages/rstack/tests/context/plugin.test.ts` +- Test: `/fast/projects/rstack-cli/packages/rstack/tests/context/mcp.test.ts` +- Test: `/fast/projects/rstack-cli/packages/rstack/tests/types/resolution-bundler/index.ts` +- Test: `/fast/projects/rstack-cli/packages/rstack/tests/types/resolution-nodenext/index.ts` + +**Interfaces:** + +- Consumes: `createRstackContextPlugin()` from Context Task 2 and modifier context from Task 5. +- Produces: internal `createContextPlugin(loaded, cwd): RstackPlugin`; CLI build loaders contain no direct Context observer calls. + +- [ ] **Step 1: Write failing built-in integration tests** + +Cover: + +```ts +expect(runtime.hasConfigModifier('app')).toBe(true); +expect(runtime.hasConfigModifier('lib')).toBe(true); +``` + +Assert user modifiers run before the internal Context modifier, capture-off registers neither modifier, app-only and lib-only configs each append one observer, mixed configs remain independent, and repeated resolution does not append the same observer twice to one config. + +Add a type test assigning the Context result directly: + +```ts +const contextPlugin: RstackPlugin = createRstackContextPlugin({ + cwd: process.cwd(), + config: { enabled: true }, + configFilePath: null, + configDependencies: [], +}); +void contextPlugin; +``` + +- [ ] **Step 2: Run focused tests and confirm RED** + +Run: + +```bash +pnpm --filter rstack test -- tests/context/plugin.test.ts tests/context/mcp.test.ts +pnpm --filter rstack build +``` + +Expected: missing `contextPlugin.ts`, missing internal registration, or structural compatibility failures. + +- [ ] **Step 3: Implement the CLI-owned plugin adapter** + +Create `contextPlugin.ts` that imports only `createRstackContextPlugin` from `@rstackjs/context/rstack` and the public local `RstackPlugin` type. Normalize the loaded config path once and pass `loaded.configs.context`, `loaded.dependencies`, and the loaded directory/cwd into Context. + +Register plugins in `getRstackPluginRuntime` as: + +```ts +plugins: [config.plugins, createContextPlugin(config, resolvedCwd)]; +``` + +This preserves user order and runs Context last. + +- [ ] **Step 4: Remove direct build injection from tool loaders** + +Delete direct imports of `appendBuildContextPlugin`, `createBuildContextPlugin`, `recordContextInputFiles`, `resolveContextCapture`, and `resolveContextWorkspace` from `rsbuildConfig.ts` and `rslibConfig.ts`. Both loaders should resolve the native config, call the standard plugin modifier pipeline with `{ params }`, and retain existing config-watch behavior. + +- [ ] **Step 5: Use focused Context entry points in host adapters** + +Update `mcp.ts` to import the server from `@rstackjs/context/mcp`, lint capture from `@rstackjs/context/rslint`, and test capture from `@rstackjs/context/rstest`. Update `relatedTests.ts` to import its request type from `@rstackjs/context/rstest`. Preserve `withRstackConfigTarget`, wrapper paths, and `define.test()` detection in the CLI. + +- [ ] **Step 6: Verify coupling shape** + +Run: + +```bash +rg -n "@rstackjs/context" packages/rstack/src +``` + +Expected matches are limited to config types, `contextPlugin.ts`, `mcp.ts`, `relatedTests.ts`, the public compatibility re-export, and config exports. `rsbuildConfig.ts` and `rslibConfig.ts` must not match. + +- [ ] **Step 7: Run tests and commit** + +Run: + +```bash +pnpm --filter rstack build +pnpm --filter rstack test +pnpm check +``` + +Then commit: + +```bash +git add packages/rstack/src packages/rstack/tests +git commit -m "refactor(rstack): integrate context through plugin SPI" +``` + +### Task 7: align Rstack documentation and publish the stacked preview + +**Files:** + +- Modify: `/fast/projects/rstack-cli/website/docs/en/guide/plugins.mdx` +- Modify: `/fast/projects/rstack-cli/website/docs/zh/guide/plugins.mdx` +- Modify: `/fast/projects/rstack-cli/website/docs/en/guide/cli/mcp.mdx` +- Modify: `/fast/projects/rstack-cli/website/docs/zh/guide/cli/mcp.mdx` +- Modify only if generated by normal build: `/fast/projects/rstack-cli/packages/rstack/docs/guide/plugins.md` +- Modify only if generated by normal build: `/fast/projects/rstack-cli/packages/rstack/docs/guide/cli/mcp.md` + +**Interfaces:** + +- Consumes: final runtime behavior from Task 6. +- Produces: aligned end-user explanation and a preview package for Agent Skills validation. + +- [ ] **Step 1: Update aligned documentation** + +State that Context is a built-in internal plugin, users configure it with `define.context()`, standalone consumers can import focused `@rstackjs/context/*` entry points, and `rs mcp` remains a built-in host command. State explicitly that Context consumes Rsdoctor artifacts and does not install a plugin into Rsdoctor. + +- [ ] **Step 2: Verify docs and repository** + +Run in the required order: + +```bash +pnpm build +pnpm --filter rstack build:native +pnpm test +pnpm check +pnpm check:spell +pnpm --dir website build +``` + +Expected: all commands pass. + +- [ ] **Step 3: Commit and push** + +```bash +git add website/docs/en/guide/plugins.mdx website/docs/zh/guide/plugins.mdx website/docs/en/guide/cli/mcp.mdx website/docs/zh/guide/cli/mcp.mdx packages/rstack/docs +git commit -m "docs: explain context plugin integration" +git push fork codex/rstack-mcp-observability +``` + +- [ ] **Step 4: Wait for the Rstack preview** + +Run: + +```bash +gh pr checks 344 --repo rstackjs/rstack-cli --watch --interval 10 +``` + +Expected: all checks pass and PR #344 remains draft. Read the Continuous Releases output or PR comment to obtain the exact Rstack preview URL. + +### Task 8: validate the Agent Skills bundle against previews + +**Files:** + +- Modify: `/fast/projects/agent-skills/scripts/test-rstack-context-plugin.mjs` +- Modify: `/fast/projects/agent-skills/README.md` +- Modify only when dogfood proves a workflow defect: `/fast/projects/agent-skills/skills/{analyze-build,assess-change-impact,debug-dev-cycle,explain-dead-code,find-unused-code,review-context-change}/SKILL.md` + +**Interfaces:** + +- Consumes: Rstack preview from Task 7, which transitively consumes the Context preview from Task 3. +- Produces: a verified repo-based plugin bundle that uses the workspace-local preview runtime. + +- [ ] **Step 1: Write a failing real-runtime launcher test** + +Extend the plugin test script to accept `RSTACK_PLUGIN_INTEGRATION_ROOT`. When present, read `.mcp.json`, launch the configured server from that root, perform MCP initialize and `tools/list`, and assert `project_status`, `product_roots`, `test_snapshot`, and `code_evidence` are advertised. Keep the existing synthetic launcher tests unchanged. + +- [ ] **Step 2: Confirm RED with a root lacking Rstack** + +Run: + +```bash +RSTACK_PLUGIN_INTEGRATION_ROOT="$(mktemp -d)" pnpm test:plugin +``` + +Expected: the new integration assertion fails because no workspace-local `rstack` exists. + +- [ ] **Step 3: Install the Rstack preview in a clean fixture and pass GREEN** + +Create a temporary package, install the exact Rstack preview URL from Task 7, and run: + +```bash +RSTACK_PLUGIN_INTEGRATION_ROOT="$fixture_root" pnpm test:plugin +pnpm lint +``` + +Expected: MCP initialization and tool listing succeed through the plugin launcher. + +- [ ] **Step 4: Clarify runtime ownership in README** + +Document this exact chain: + +```text +Agent plugin -> workspace-local rs mcp -> @rstackjs/context +``` + +State that Agent Skills does not bundle a second Context runtime and that preview validation installs Rstack into the fixture project. + +- [ ] **Step 5: Commit and push** + +```bash +git add scripts/test-rstack-context-plugin.mjs README.md skills +git commit -m "test(plugin): validate workspace context runtime" +git push fork codex/rstack-context-plugin +``` + +### Task 9: Real-world dogfood and PR completion audit + +**Files:** + +- Modify only minimal fixture config/package files under `/fast/playgrounds` when required to run existing project commands. +- Do not commit fixture changes to the three product PRs. + +**Interfaces:** + +- Consumes: installed Agent Skills bundle and preview packages from Tasks 3 and 7. +- Produces: evidence-backed usability findings and any narrowly scoped fixes committed to the owning repository. + +- [ ] **Step 1: Reinstall the personal plugin from Agent Skills PR head** + +Update the existing personal marketplace source without creating another marketplace, reinstall `rstack@personal`, and verify the cache commit equals the Agent Skills PR head. + +- [ ] **Step 2: Validate HeaderEditor graceful degradation** + +In `/fast/playgrounds/rstack-header-editor`, install the Rstack preview, run its real Rsbuild workflow, start MCP through the installed plugin, and call: + +```text +project_status -> product_roots -> unused_modules -> code_evidence +``` + +Expected: build evidence works; Rstest evidence is unavailable rather than an error that blocks other axes; artifact/build identities match. + +- [ ] **Step 3: Validate Kiali mixed evidence** + +In `/fast/playgrounds/rstack-kiali/frontend`, install the same Rstack preview, run the real build and selected Rstest suite, capture optional aggregate Istanbul execution evidence, then call: + +```text +project_status -> test_results -> diagnostics_list -> product_roots -> code_evidence +``` + +Expected: build, test, and optional execution evidence remain distinct and share the selected package/context identity. + +- [ ] **Step 4: Validate a monorepo with both application and library producers** + +Use `/fast/playgrounds/midscene` if already present; otherwise clone `web-infra-dev/midscene` into that path. Install the preview only in the dogfood checkout, make the minimum Rstack config additions needed to expose existing Rsbuild/Rslib/Rstest configuration, run one application build and one library build, and verify `project_status` lists independent contexts without relying on MCP cwd. + +- [ ] **Step 5: Fix only reproduced product defects** + +For each defect, add a failing test in the owning repository, implement the minimal fix, run focused and full checks, commit, push, wait for the new preview, reinstall it, and repeat the exact dogfood call. Do not add speculative infrastructure or fixture-only behavior. + +- [ ] **Step 6: Audit the three owned PRs** + +Run: + +```bash +gh pr view 1 --repo rstackjs/context --json isDraft,headRefOid,mergeable,statusCheckRollup +gh pr view 344 --repo rstackjs/rstack-cli --json isDraft,headRefOid,mergeable,statusCheckRollup +gh pr view 102 --repo rstackjs/agent-skills --json isDraft,headRefOid,mergeable,statusCheckRollup +``` + +Expected: all three remain draft, are mergeable, and have green required checks. + +--- + +## Self-Review + +- Spec coverage: Tasks 1-3 cover standalone entry points, no reverse dependency, Rsdoctor consumption, and preview policy. Tasks 4-7 cover SPI stacking, native params, internal registration, minimal CLI coupling, docs, and Rstack preview. Tasks 8-9 cover Agent Skills runtime ownership, canary installation, graceful degradation, monorepo behavior, and real dogfood. +- Placeholder scan: the plan contains no unresolved implementation placeholders; runtime SHA/preview values are derived from the committed heads or CI rather than hard-coded before publication. +- Type consistency: `createRstackContextPlugin`, `ContextRstackPlugin`, `RstackConfigModifierContextMap`, `createContextPlugin`, and modifier `{ params }` names are consistent across producing and consuming tasks. diff --git a/docs/superpowers/plans/2026-08-14-context-repository-extraction.md b/docs/superpowers/plans/2026-08-14-context-repository-extraction.md new file mode 100644 index 00000000..d13c55e2 --- /dev/null +++ b/docs/superpowers/plans/2026-08-14-context-repository-extraction.md @@ -0,0 +1,85 @@ +# Context repository extraction implementation plan + +> Execute this plan inline without additional approval checkpoints. Keep all coordinated pull requests +> in draft until the standalone package has a stable release. + +**Goal:** Move `@rstackjs/context` and its engine-owned documentation/tests into a standalone public +`rstackjs/context` repository while preserving history and keeping Rstack CLI as the thin MCP host. + +**Architecture:** `rstackjs/context` owns the evidence runtime and MCP implementation. `rstack-cli` +owns command/config adapters and the compatibility export. `agent-skills` owns only plugin packaging, +workflows, and evaluations. + +**Stack:** pnpm, TypeScript, Rslib, Rsbuild, Rstest, Rslint, MCP SDK, Rsdoctor Agent CLI, pkg.pr.new. + +--- + +## Task 1: create the repository and preserve history + +1. Create public `rstackjs/context` with a minimal default branch and clone it to + `/fast/projects/context`. +2. Create `codex/extract-context` from `main`. +3. In a temporary clone of Rstack CLI, filter the current context branch to `packages/context` and + the context-engine RFC, renaming those paths to the standalone repository root and `docs/rfc.md`. +4. Merge the filtered history into the extraction branch with unrelated histories allowed. +5. Verify the resulting graph retains focused package commits without unrelated CLI paths. + +## Task 2: add standalone Rstack tooling and package metadata + +1. Add the pnpm workspace catalog, TypeScript configuration, Rslint configuration, formatting + configuration, Git ignore rules, license, and repository guidance. +2. Update package repository/bugs/homepage metadata to `rstackjs/context` while preserving the + package name, version, exports, Node requirement, and store/MCP contracts. +3. Keep Rslib as the package builder, Rstest as the test runner, Rslint as the linter, and Rsbuild as + the observer integration API. Do not add a circular development dependency on `rstack`. +4. Add CI and one pkg.pr.new workflow invocation using the repository's locked dependency. +5. Add package packing and clean-consumer smoke coverage. + +## Task 3: relocate engine-owned tests and documentation + +1. Move generic MCP/config tests still located under `packages/rstack/tests/context` into the + standalone package where their behavior is runtime-owned. +2. Keep only command, wrapper-config, related-test, and injection integration tests in Rstack CLI. +3. Keep the full architecture RFC in `rstackjs/context`; reduce Rstack CLI documentation to the + command/config integration and link to the new repository for runtime architecture. +4. Preserve existing API and MCP schemas during the move. + +## Task 4: validate and publish a preview + +1. Install with the declared pnpm version. +2. Run formatting, Rslint/type checks, Rslib build, Rstest, and package-consumer smoke tests. +3. Commit the standalone repository changes. +4. Push `codex/extract-context` and open a draft pull request. +5. Wait for pkg.pr.new, install the produced preview in a clean consumer, and record the exact + preview reference for Rstack CLI. + +## Task 5: convert Rstack CLI to an external context dependency + +1. Remove `packages/context` from the Rstack CLI worktree after the standalone branch is pushed. +2. Replace `workspace:*` with the exact pkg.pr.new preview dependency and update the lockfile. +3. Keep `src/context.ts`, `src/mcp.ts`, config injection, wrapper paths, related-test resolution, and + `rs mcp` command behavior. +4. Remove or relocate engine-only tests/docs and keep focused host integration coverage. +5. Run `pnpm check`, package builds, native build prerequisite, and the required test suites. +6. Commit and push the existing `codex/rstack-mcp-observability` draft branch. + +## Task 6: align Agent Skills and evaluate the installation + +1. Update runtime repository references in `/fast/projects/agent-skills` without moving engine code + into the plugin. +2. Validate Codex/Claude manifest and skill parity plus launcher tests. +3. Refresh the personal installed plugin from the existing personal marketplace. +4. Verify the MCP exposes the complete tool catalog and `project_status` works. +5. Run real-repository evaluations for build-only, library-only, and test-enabled projects, checking + that missing producers degrade to unavailable evidence rather than errors. +6. Commit and push the existing Agent Skills draft branch if it changed. + +## Task 7: final coordinated review + +1. Review all changed repositories for accidental scope expansion and compatibility regressions. +2. Verify the new context PR, Rstack CLI PR, Agent Skills PR, and Rsdoctor PR remain drafts where + applicable and have no unresolved authored review feedback. +3. Check current-head CI, address failures caused by this extraction, and leave unrelated failures + documented rather than changing unrelated code. +4. Report repository paths, branches, commits, draft PR URLs, preview package reference, verification + evidence, and the stable-release dependency remaining before merge readiness. diff --git a/docs/superpowers/specs/2026-08-12-passive-build-context-design.md b/docs/superpowers/specs/2026-08-12-passive-build-context-design.md new file mode 100644 index 00000000..b77882fb --- /dev/null +++ b/docs/superpowers/specs/2026-08-12-passive-build-context-design.md @@ -0,0 +1,235 @@ +# Passive build context design + + + +**Status:** Approved for implementation by the request to design and implement the next RFC phase. + +**Foundation:** `70c4a90 feat(rstack): scaffold context evidence store` + +## Purpose + +Deliver the smallest end-to-end Phase 1 slice that proves Rstack commands can publish useful build +metadata from any package in a standalone repository or monorepo, and that one repository-root MCP +process can read all of it without knowing which package launched each command. + +The slice covers trusted metadata capture for `rs dev`, `rs build`, and `rs lib`, plus one read-only +`rs mcp` status tool. It deliberately excludes deep compiler graphs and background coordination. + +## Chosen approach + +Use the existing CLI-specific Rsbuild and Rslib config loaders as the only automatic injection +points. After the user's config resolves, Rstack shallow-clones it and appends one global +Rstack-owned Rsbuild plugin. The plugin publishes immutable per-environment snapshots through the +existing `.rstack/cache/context-v1` store. + +`rs mcp` is a local stdio process. It resolves the checkout from its launch path, reads completed +records on demand, and exposes a compact `project_status` tool. It does not listen on a port, own +producer processes, index a task graph, or cache authoritative state. + +This is Phase 1A. Phase 1B will add static Rsdoctor ingestion and richer build diagnostics. Phase 1C +will add report links. Destructive retention is deferred pending real artifact-size and +access-pattern measurements and defined product semantics. + +## Alternatives considered + +### Implement all of RFC phase 1 at once + +This would combine compiler observation, Rsdoctor schema adaptation, record retention, report +discovery, entity queries, and MCP transport. Those parts have different versioning and failure +modes, making a single review and rollback boundary too large. + +### Implement producers without MCP + +This is smaller, but it would leave the most important architectural claim untested: an agent host +launched once at the repository root can discover data from independently launched package builds. + +### Add a coordinator daemon + +A daemon does not solve an observed Phase 1A problem. Immutable producer-owned files already allow +many writers and readers, survive producer restarts, and require no port or process discovery. + +## Configuration and trust + +Add `define.context` as Rstack-owned configuration, separate from the configuration forwarded to +Rsbuild or Rslib: + +```ts +define.context({ + enabled: true, + capture: 'metadata', +}); +``` + +The supported shape is: + +```ts +type ContextConfig = { + enabled?: boolean; + capture?: 'off' | 'metadata' | 'deep'; +}; +``` + +Rules: + +- capture is disabled unless `enabled` is `true` or `RSTACK_CONTEXT=1` is set; +- `RSTACK_CONTEXT=0` always disables capture; +- `capture: 'off'` disables capture even when enabled; +- omitted `capture` means `metadata`; +- `deep` activates metadata capture but records the deep facet as `unsupported` in Phase 1A; +- config objects and config functions are never mutated; +- `define.context` is never forwarded into an underlying tool config. + +## Producer architecture + +### Injection + +`loadRsbuildConfig` and `loadRslibConfig` retain the existing pure resolvers. Their CLI-only loader +paths perform the following steps: + +1. load the Rstack config and obtain its actual `filePath`; +2. resolve the app or library config with the original `ConfigParams`; +3. evaluate the context activation policy; +4. resolve checkout and package identity from `filePath`, falling back to the actual launch + directory only when no config file exists; +5. shallow-clone the resolved config and append exactly one observer to top-level `plugins`. + +Rslib `lib[]` entries are never modified. A global plugin observes every Rslib-generated Rsbuild +environment without duplicate global callbacks. Rstest's use of the pure app/library resolvers is +not instrumented. + +### Run and context identity + +Each plugin instance owns one run and never uses module-global mutable state. + +- `runId` is a safe, unique `run_