From 1934f3578e53211246834f8c701aff1fc4dac8e3 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:15:08 +0200 Subject: [PATCH 01/11] harness(mcp): lock registry-safe publish plan --- .../context-pack.md | 66 +++++++++ .../drift.md | 11 ++ .../plan.md | 139 ++++++++++++++++++ .../research.md | 28 ++++ .../supervisor.md | 22 +++ .../worklog.md | 75 ++++++++++ 6 files changed, 341 insertions(+) create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan.md create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/research.md create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md new file mode 100644 index 000000000..e3eff5468 --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md @@ -0,0 +1,66 @@ +# Context Pack: registry-safe MCP README embedding + +## Run Metadata + +| Field | Value | +| --- | --- | +| Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | +| Branch | `fix/mcp-readme-text-import` | +| Current phase | `plan-eval` | +| Archetype | `6 — CLI / Tooling` | +| Scope overlays | `none` | + +## Current State + +The branch is based cleanly on `origin/main` at `a5adb706`. Research and a four-slice design are locked. No implementation source has changed; PLAN-EVAL is the hard stop. + +## Completed + +- Named skills, harness routing, relevant doctrine, release gates, existing generator, publish surface, and preflight implementation were inspected. +- Research, plan, design checkpoint, supervisor identity, and drift log were created. + +## In Progress + +- Separate-session formal PLAN-EVAL. + +## Next Steps + +1. Obtain PLAN-EVAL `PASS`. +2. Commit/push the plan bootstrap and open the draft PR. +3. Implement generated assets and the publish-surface sweep. + +## Key Decisions + +| Decision | Source | Notes | +| --- | --- | --- | +| Generated constants are the only sanctioned bundled assets. | user + plan D1 | No import attributes in publishable source. | +| Scan actual publish rules. | existing preflight + plan D3 | Avoid test-only false failures. | + +## Files Changed + +| Path | Status | Notes | +| --- | --- | --- | +| `.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/` | new | Harness planning artifacts only. | + +## Gates + +| Gate family | Current status | Evidence | +| --- | --- | --- | +| Plan | pending | formal evaluator not yet run | +| Static | not run | blocked by Plan-Gate | +| Fitness | not run | blocked by Plan-Gate | +| Runtime | N/A | no runtime protocol change planned | +| Consumer | not run | blocked by Plan-Gate | + +## Open Questions + +- None. + +## Drift and Debt + +- Drift: none. +- Debt: none created or deepened. + +## Commits + +- See the draft PR's commit list + per-slice PR comments after the bootstrap commit. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md new file mode 100644 index 000000000..12b883268 --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md @@ -0,0 +1,11 @@ +# Drift Log: registry-safe MCP README embedding + +## 2026-07-17 — Local formal evaluator credential unavailable + +- **What:** The local Claude Code + OpenRouter Qwen canary could not launch, so formal evaluation moved to the canonical OpenHands cloud route with the same approved open model. +- **Source:** `deno task agentic:provider-canary --live --profile claude-openrouter --model qwen/qwen3.7-max --effort high --worktree /home/codex/repos/b10-textimport`. +- **Expected:** Local formal evaluator route available. +- **Actual:** Structured result `status=blocked`, diagnostic `auth_required`, credential `absent`. +- **Severity:** minor +- **Action:** fix — use the lane policy's canonical OpenHands cloud evaluator route. +- **Evidence:** supervisor route table and provider-canary output in the supervisor session. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan.md new file mode 100644 index 000000000..1c4f28b09 --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan.md @@ -0,0 +1,139 @@ +# Plan: registry-safe MCP README embedding and publish preflight + +## Run Metadata + +| Field | Value | +| --- | --- | +| Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | +| Branch | `fix/mcp-readme-text-import` | +| Phase | `plan` | +| Target | `packages/mcp`, publishable package/plugin surfaces, release tooling/docs | +| Archetype | `6 — CLI / Tooling` | +| Scope overlays | `none` | + +## Archetype + +Archetype 6 is the smallest fit because `@netscript/mcp` publishes an executable stdio CLI entrypoint and this hotfix changes its bundled runtime documentation asset. The cross-workspace sweep is release fitness tooling, not a new public runtime abstraction. + +## Current Doctrine Verdict + +The doctrine's current package table predates `@netscript/mcp`; the adjacent `@netscript/cli` verdict is `Restructure`. This hotfix does not broaden that debt and applies A14 at the actual JSR boundary. + +## Axioms in Play + +| Axiom | Why it matters | +| --- | --- | +| A7 | Generated constants use platform file reads only in the maintainer generator, never at published runtime. | +| A8 | Generated assets and their generator each have one clear reason to change. | +| A14 | The release gate must reproduce the registry failure class, including a witnessed negative case. | + +## Goal + +Remove all import attributes from publishable NetScript source, embed MCP README/package assets through reproducible generated constants, and make release preflight reject any future `with { type: ... }` attribute before JSR does. + +## Scope + +- Generate and consume an internal MCP README constant and generated package metadata/constants needed to remove publishable JSON attributes. +- Sweep all publishable `packages/**` and `plugins/**` source selected by each member's publish rules. +- Add regeneration and freshness tasks, with a green run and a seeded stale-output failure. +- Add an import-attribute release-preflight finding, tests, user-facing failure output, and seeded CLI failure proof. +- Correct canonical and mirrored release/JSR-audit guidance; run the sync check. + +## Non-Scope + +- Test-only JSON import attributes excluded from publish tarballs. +- Import-attribute text embedded inside scaffold template string constants; it is userland generated source, not syntax in the published module graph. +- Cutting, publishing, retrying beta.10, merging the PR, or closing issue #808. +- Existing archetype restructuring debt unrelated to the registry hotfix. + +## Hidden Scope + +- Publish-rule-aware scanning must ignore comments/string/template content to avoid false positives in generated asset constants. +- Generated files must be included by each owning package's existing `**/*.ts`/`src/**/*.ts` publish rules. +- Wording in `.agents/skills` and `.claude/skills` must remain synchronized. + +## Locked Decisions + +| ID | Decision | Rationale | +| --- | --- | --- | +| D1 | Generated TypeScript constants are the sole sanctioned bundled-asset form. | JSR registry rejected import attributes despite local dry-run success. | +| D2 | Extend repo maintainer generation with a dedicated publish-assets generator and diff freshness task. | Mirrors the proven `check:assets-barrel` pattern and makes source drift visible. | +| D3 | Preflight rejects every `with { type: ... }` attribute on the publish-rule-filtered source surface. | The registry limitation is attribute-type agnostic from the release policy perspective. | +| D4 | Tests and emitted scaffold strings remain out of the syntax gate. | They are outside the published module graph or are string data, not module syntax. | + +## Open-Decision Sweep + +| Decision | Status | Notes | +| --- | --- | --- | +| Generator/file placement | resolved now | Internal `*.generated.ts` files live inside each owning publishable member. | +| Attribute parser strategy | resolved now | A lexical code-only scan preserves line numbers and rejects syntax without matching strings/comments. | +| Post-publish beta retry | safe to defer | Explicitly outside this PR; release owners fix-forward after merge. | + +## Risk Register + +| Risk | Mitigation | +| --- | --- | +| Sweep misses an included source file. | Reuse existing publish member discovery and include/exclude filtering in `scanPublishSurface`. | +| Gate flags scaffold strings or comments. | Add lexical tests covering actual syntax versus inert text. | +| Generated metadata drifts. | Regeneration-plus-`git diff --exit-code` freshness task and negative seed proof. | +| Release docs remain contradictory. | Update both named skills in canonical/mirrored trees and run `agentic:check-claude`. | +| Local dry-run gives a false sense of registry equivalence. | Record it as static-only evidence and retain the registry failure rationale. | + +## Anti-Patterns to Resolve or Avoid + +| AP | Status | Plan | +| --- | --- | --- | +| AP-11 | risk | Published runtime never reads repo files; generator owns filesystem IO. | +| AP-18 | risk | Freshness compares deterministic generated output; focused behavior tests avoid giant snapshots. | + +## Fitness Gates + +| Gate | Required | Expected evidence | +| --- | --- | --- | +| F-5 public surface | yes | MCP check/tests; no public API change | +| F-6 JSR publishability | yes | MCP `publish:dry-run`, release preflight green and witnessed red | +| F-7 docs | yes | README remains published and embedded byte-for-byte | +| F-9 permissions | reviewed | No runtime permission expansion | +| F-10 test shape | yes | Focused scanner and MCP tests | +| F-19 scoped runners | yes | changed roots/files through repo wrappers where applicable | +| code quality | yes | changed-file `quality:scan` and `arch:check` | + +## Arch-Debt Implications + +| Entry | Action | Notes | +| --- | --- | --- | +| `.llm/harness/debt/arch-debt.md` | none | The known release defect is fixed in scope; no violation is deferred. | + +## Commit Slices + +1. Harness bootstrap and approved design — proven by separate PLAN-EVAL; files under this run directory. +2. Registry-safe generated publish assets and full publish-surface sweep — proven by focused checks/tests, freshness green/red, and zero publish-surface attributes; package/plugin sources, generator, tasks, run artifacts. +3. Release preflight doctrine correction — proven by scanner tests, CLI seeded red, full preflight green, skill sync; release tool/tests and skill mirrors. +4. Final gate/evaluator evidence — proven by required gate table and separate IMPL-EVAL; run artifacts and PR phase trail. + +## Validation Plan + +| Order | Gate | Command or check | Expected result | +| --- | --- | --- | --- | +| 1 | focused MCP | package check and focused tests | exit 0 | +| 2 | generator freshness | new check task | exit 0; seeded drift exits non-zero | +| 3 | release scanner tests | focused Deno test | exit 0 | +| 4 | release preflight | `deno task release:preflight` | exit 0; seeded attribute exits non-zero | +| 5 | MCP JSR static gate | `cd packages/mcp && deno task publish:dry-run` | exit 0 | +| 6 | changed quality | `deno task quality:scan` scoped to changed files | exit 0 | +| 7 | doctrine fitness | `deno task arch:check` | exit 0 | +| 8 | skill mirror | `deno task agentic:check-claude` | exit 0 | +| 9 | IMPL-EVAL | separate formal evaluator session | `PASS` | + +## Dependencies + +- Existing workspace discovery/publish rules and generated-assets conventions. +- No new runtime or registry dependency. + +## Deferred Scope + +- Actual publish retry and `e2e-cli-prod` remain post-merge release operations. + +## Drift Watch + +- Any newly discovered attribute outside test/generated-string exclusions, generator nondeterminism, or gate requiring unrelated source churn is recorded before proceeding. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/research.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/research.md new file mode 100644 index 000000000..0c4199a4a --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/research.md @@ -0,0 +1,28 @@ +# Research — fix-mcp-readme-text-import--beta10-jsr-hotfix + +## Re-baseline + +- Carried-in source: user evidence from `publish.yml` run `29558968037`. +- Re-derived against `origin/main` @ `a5adb706` on 2026-07-17. +- The branch is clean and points at current `origin/main`; no carried implementation exists. + +## Findings + +| # | Finding | How to verify | +| - | ------- | ------------- | +| 1 | `packages/mcp/cli.ts:18` imports `README.md` with `type: 'text'`; the registry rejected this while local dry-run passed. | `rg -n "with \\{ type:" packages/mcp/cli.ts`; publish run 29558968037 | +| 2 | The repo already embeds publish-time assets as generated string constants and protects them with regeneration-plus-diff parity. | `.llm/tools/generate-cli-assets-barrel.ts`; root tasks `gen:assets-barrel` and `check:assets-barrel` | +| 3 | The existing release preflight scans the actual include/exclude-filtered publish surface, but only rejects import-meta filesystem reads and self-imports; its messages recommend text imports. | `.llm/tools/release/preflight-text-imports.ts` | +| 4 | Publishable `with { type: ... }` syntax exists beyond MCP: MCP package metadata, CLI metadata/schema, and plugin package metadata. Test-only attributes and generated string contents are not publishable syntax. | publish rules in affected `deno.json` files plus `rg -n --glob '*.ts' 'with\\s*\\{\\s*type\\s*:' packages plugins` | +| 5 | Release and JSR-audit skills in both `.agents/skills` and `.claude/skills` currently bless import attributes; the publish-workspace comment already records the correct registry behavior. | `rg -n "import attributes|text imports" .agents/skills .claude/skills .llm/tools/release/publish-workspace.ts` | + +## jsr-audit surface scan + +- Surface scanned: `@netscript/mcp` exports `.` and `./cli`, plus every publishable TypeScript file selected by workspace publish rules under `packages/**` and `plugins/**`. +- Static dry-run risk: local `deno publish --dry-run` is known to pass the rejected text attribute, so it is necessary but not sufficient. +- Registry risk: any import attribute (`with { type: ... }`) in publishable source can fail module-graph construction; the only sanctioned bundled-asset pattern is a checked-in generated constant. +- Public API/slow-type risk: no public signature is intentionally changed; generated constants remain internal. + +## Open questions + +- None. The user locked the branch, PR metadata, registry-safe pattern, sweep scope, negative-proof requirements, and gate set. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md new file mode 100644 index 000000000..f28388304 --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md @@ -0,0 +1,22 @@ +# Supervisor Identity — fix-mcp-readme-text-import--beta10-jsr-hotfix + +| Field | Value | +| --- | --- | +| Model | Codex root session (API model identity not exposed) | +| Session | current `/root` session | +| Host | Linux / `/home/codex` | +| Checkout | `/home/codex/repos/b10-textimport` | +| Worktree | `/home/codex/repos/b10-textimport` | +| Branch | `fix/mcp-readme-text-import` | +| Baseline | `a5adb706` (`origin/main`, 2026-07-17) | +| Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | + +## Routes in force + +| Task lane | Provider / model / effort | Role in this run | +| --- | --- | --- | +| `light_implementation` | current Codex root implementation session | Scoped hotfix implementation | +| `formal_evaluation` | OpenHands cloud / OpenRouter Qwen 3.7 Max / xhigh | Separate-session PLAN-EVAL and IMPL-EVAL after local Claude/OpenRouter credential check blocked | +| `review_codex_light` | Claude opposite-family review route | Slice-review gate after automated evidence | + +Reference `.llm/harness/workflow/lane-policy.md`. OpenHands is the canonical cloud formal-evaluator transport; the local transport was unavailable, as recorded in `drift.md`. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md new file mode 100644 index 000000000..1f7f350a2 --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -0,0 +1,75 @@ +# Worklog: registry-safe MCP README embedding + +## Run Metadata + +| Field | Value | +| --- | --- | +| Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | +| Branch | `fix/mcp-readme-text-import` | +| Archetype | `6 — CLI / Tooling` | +| Scope overlays | `none` | + +## Design + +### Public Surface + +- `@netscript/mcp/cli` behavior is unchanged; the default embedded docs corpus still exposes the package README. +- No new package export or CLI command is introduced. + +### Domain Vocabulary + +- `ImportAttributeFinding` — a publishable source location containing registry-unsafe `with { type: ... }` syntax. +- generated publish asset — checked-in TypeScript constant derived from README, schema, or package metadata. + +### Ports + +- None. The generator is maintainer tooling and the runtime consumes plain constants. + +### Constants + +- `MCP_PACKAGE_README` — exact `packages/mcp/README.md` content. +- package release versions — exact owning `deno.json` version values. +- CLI schema constant — exact config schema data needed by scaffold output. + +### Commit Slices + +| # | Slice | Gate | Files | +| - | ----- | ---- | ----- | +| 1 | Harness bootstrap and design | separate PLAN-EVAL | run artifacts | +| 2 | Generated publish assets and surface sweep | freshness green/red; focused package tests/checks | generator, tasks, generated files, consumers | +| 3 | Registry-failing preflight and corrected guidance | scanner tests; preflight green/red; skill sync | release scanner/tests, release + JSR skills | +| 4 | Final evidence and evaluator handoff | required gates; separate IMPL-EVAL | run artifacts and PR comments | + +### Deferred Scope + +- Release retry and production JSR E2E — post-merge release-owner operation. + +### Contributor Path + +Update the source README/schema/package metadata, run the publish-assets generation task, and commit the resulting `*.generated.ts`; the freshness and release-preflight tasks reject drift or import attributes. + +## Progress Log + +| Time | Slice | Step | Notes | +| --- | --- | --- | --- | +| 2026-07-17 | 1 | research/design | Re-baselined at `a5adb706`; implementation remains blocked on PLAN-EVAL. | + +## Decisions + +| Decision | Reason | Source | +| --- | --- | --- | +| Generated constants only | Registry rejects import attributes that local dry-run accepts. | user evidence + publish-workspace comment | + +## Drift + +| Drift | Severity | Logged in drift.md | +| --- | --- | --- | +| none | minor | n/a | + +## Gate Results + +No implementation gates run before PLAN-EVAL. + +## Handoff Notes + +- PLAN-EVAL should spot-check `packages/mcp/cli.ts:18`, the existing generator pattern, and publish-rule filtering in `scanPublishSurface`. From b5568180be3a86573065000f8fb437137704f413 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:22:52 +0200 Subject: [PATCH 02/11] harness(mcp): pass registry hotfix plan gate --- .../context-pack.md | 15 ++++---- .../drift.md | 4 +-- .../plan-eval.md | 36 +++++++++++++++++++ .../supervisor.md | 4 +-- .../worklog.md | 1 + 5 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan-eval.md diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md index e3eff5468..e08b39b42 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md @@ -6,28 +6,29 @@ | --- | --- | | Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | | Branch | `fix/mcp-readme-text-import` | -| Current phase | `plan-eval` | +| Current phase | `implement` | | Archetype | `6 — CLI / Tooling` | | Scope overlays | `none` | ## Current State -The branch is based cleanly on `origin/main` at `a5adb706`. Research and a four-slice design are locked. No implementation source has changed; PLAN-EVAL is the hard stop. +The branch is based on `origin/main` at `a5adb706`. Research and a four-slice design are locked. Separate-session PLAN-EVAL passed; implementation may begin. ## Completed - Named skills, harness routing, relevant doctrine, release gates, existing generator, publish surface, and preflight implementation were inspected. - Research, plan, design checkpoint, supervisor identity, and drift log were created. +- PLAN-EVAL passed in local Qwen session `f03ae1dd-da69-406a-b725-f3bf391255a8`. ## In Progress -- Separate-session formal PLAN-EVAL. +- Slice 2 generated publish assets and publish-surface sweep. ## Next Steps -1. Obtain PLAN-EVAL `PASS`. -2. Commit/push the plan bootstrap and open the draft PR. -3. Implement generated assets and the publish-surface sweep. +1. Implement generated assets and the publish-surface sweep. +2. Run freshness green/red and focused package gates. +3. Commit, push, and comment slice 2. ## Key Decisions @@ -46,7 +47,7 @@ The branch is based cleanly on `origin/main` at `a5adb706`. Research and a four- | Gate family | Current status | Evidence | | --- | --- | --- | -| Plan | pending | formal evaluator not yet run | +| Plan | PASS | `plan-eval.md`; session `f03ae1dd-da69-406a-b725-f3bf391255a8` | | Static | not run | blocked by Plan-Gate | | Fitness | not run | blocked by Plan-Gate | | Runtime | N/A | no runtime protocol change planned | diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md index 12b883268..250391f9d 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md @@ -7,5 +7,5 @@ - **Expected:** Local formal evaluator route available. - **Actual:** Structured result `status=blocked`, diagnostic `auth_required`, credential `absent`. - **Severity:** minor -- **Action:** fix — use the lane policy's canonical OpenHands cloud evaluator route. -- **Evidence:** supervisor route table and provider-canary output in the supervisor session. +- **Action:** fix — load the configured `/home/codex/.config/netscript-agentic/openrouter.env` credential source, re-run the local canary, and use the canonical local evaluator. The interim OpenHands fallback failed before a model turn because its runtime lacked `fastapi` (Actions run `29559553914`); no verdict was produced. +- **Evidence:** local canary then passed with tools/reasoning/streaming supported; PLAN-EVAL session `f03ae1dd-da69-406a-b725-f3bf391255a8` wrote `plan-eval.md` with `PASS`. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan-eval.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan-eval.md new file mode 100644 index 000000000..2cca8cc8d --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/plan-eval.md @@ -0,0 +1,36 @@ +# PLAN-EVAL — fix-mcp-readme-text-import--beta10-jsr-hotfix + +- Plan evaluator session: Claude Code + OpenRouter (open-model qwen3.7-max) / 2026-07-17 +- Run: fix-mcp-readme-text-import--beta10-jsr-hotfix +- Surface / archetype: `@netscript/mcp` + cross-workspace publish surface / Archetype 6 — CLI / Tooling +- Scope overlays: none + +## Checklist results + +| Plan-Gate item | Result | Evidence / location | +| --------------------------------------- | ----------------- | ------------------- | +| Research present and current | PASS | `research.md` exists; re-baselined against `origin/main` @ `a5adb706` on 2026-07-17. Spot-checked: `packages/mcp/cli.ts:18` confirmed `import packageReadme from './README.md' with { type: 'text' }`; `.llm/tools/generate-cli-assets-barrel.ts` exists and follows the described pattern; `gen:assets-barrel` + `check:assets-barrel` tasks confirmed in root `deno.json:80-81`; `preflight-text-imports.ts` confirmed to check `import.meta`-relative reads (not import attributes) with message recommending text imports at line 455. | +| Decisions locked | PASS | `plan.md` D1–D4 stated with rationale. D1 (generated constants) justified by witnessed JSR registry rejection. D2 (extend generation pattern) justified by proven barrel pattern. D3 (preflight rejects all `with { type: }`) justified by registry attribute-type-agnostic limitation. D4 (tests/scaffold excluded) justified by published-module-graph boundary. | +| Open-decision sweep | PASS | Plan lists 3 items: generator/file placement (resolved now), attribute parser strategy (resolved now — lexical scan preserves line numbers), post-publish beta retry (safe to defer — explicitly non-scope). Evaluator own sweep: no additional decisions found that would force rework if deferred. | +| Commit slices (< 30, gate + files each) | PASS | 4 slices, ordered. Each names what it proves, the proving gate, and files/categories: (1) harness bootstrap → PLAN-EVAL → run artifacts; (2) generated assets + sweep → freshness green/red + focused checks/tests → generator, tasks, generated files, consumers; (3) preflight + guidance → scanner tests + preflight green/red + skill sync → release tool/tests + skills; (4) final evidence → required gates + IMPL-EVAL → run artifacts + PR phase trail. | +| Risk register | PASS | 5 risks with mitigations in `plan.md`. Scope miss → reuses `scanPublishSurface` publish-rule filtering. False-positive gate → lexical tests for syntax vs inert text. Metadata drift → regeneration + `git diff --exit-code` + negative seed proof. Docs contradiction → dual-skill update + `agentic:check-claude`. Dry-run false sense → recorded as static-only evidence; registry failure rationale retained. | +| Gate set selected | PASS | Required gates from archetype-gate-matrix for Arch 6: F-5 (public surface), F-6 (JSR publishability), F-7 (doc-score), F-9 (permissions — reviewed, no expansion), F-10 (test shape), F-19 (scoped runners), code quality (check/lint/fmt), `arch:check` (fitness gates incl. F-CLI where applicable), `agentic:check-claude` (skill mirror validation). Validation plan table (9 ordered entries) includes focused MCP checks, generator freshness green/red, release scanner tests, preflight green/red, MCP JSR static gate, quality scan, doctrine fitness, skill mirror, and IMPL-EVAL. | +| Deferred scope explicit | PASS | `plan.md` Non-Scope: test-only JSON import attributes; scaffold template strings (userland-generated, not published module syntax); cutting/publishing/retrying beta.10/merging PR/closing #808; unrelated archetype restructuring debt. Deferred Scope section: actual publish retry and `e2e-cli-prod` remain post-merge release operations. | +| jsr-audit surface scan (pkg/plugin) | PASS | `research.md` "jsr-audit surface scan" section names: `@netscript/mcp` exports (`.` + `./cli`); all publishable TS under `packages/**` and `plugins/**` per each member's publish rules. Risks named: static dry-run is necessary but not sufficient (local passes registry-rejected syntax); registry risk is any import attribute in publishable source; slow-type risk is nil (no public signature change). Plan addresses each risk through generated constants (registry-safe), preflight rejection (attribute-agnostic), and publish:dry-run evidence (static-only). | + +## Open-decision sweep (evaluator-run) + +**Additional sweep performed by evaluator:** The tree contains 18+ non-test, non-generated `with { type: ... }` attributes across publishable source: 3 in `packages/cli` (`public-command-tree.ts`, `jsr-specifiers.ts`, `editor-config.ts`; all `type: 'json'`), 1 in `packages/mcp` (`spawn-command-executor.ts`; `type: 'json'`), 1 + 1 test fixture in `packages/mcp` (`cli.ts`; `type: 'text'`), 2–4 in `plugins/streams` (`main.ts`, `verify-plugin.ts`, `mod.ts`), 1–3 in `plugins/sagas` (`verify-plugin.ts`, `mod.ts`), 1–4 in `plugins/workers` (`verify-plugin.ts`, `init.ts`), 1–3 in `plugins/auth` (`constants.ts`, `verify-plugin.ts`), 1–4 in `plugins/triggers` (`verify-plugin.ts`, `main.ts`), 1–2 in `plugins/ai` (`constants.ts`, `verify-plugin.ts`). The plan's D3 scope ("all publishable source" + each member's publish rules via `scanPublishSurface`) and slice 2 ("full publish-surface sweep") correctly encompass this surface. The worklog Design and worklog Handoff Notes (`worklog.md` line 75) reference the sweep scope. No additional decisions forced open by this surface. + +**None.** All decisions are either resolved in the plan or explicitly safe to defer. + +## Verdict + +`PASS` + +## Notes + +- The worklog Design section is appropriately minimal for this hotfix: it does not enumerate spine abstracts, layer-2 abstracts, vertical-feature catalogs, or extension axes because the run touches no abstract hierarchy or feature structure. The archetype 6 design-checkpoint items that apply (public surface, domain vocabulary, ports, constants, contributor path, slice ordering) are present. +- The evaluator confirmed that `packages/mcp/cli.ts:18` carries the registry-rejected `with { type: 'text' }` attribute and that the existing `.llm/tools/generate-cli-assets-barrel.ts` generator pattern provides a proven structural basis for the plan's D2 extension. +- The evaluator confirmed the risk that local `deno publish --dry-run` passes the rejected attribute syntax (research finding 1). The plan correctly retains the registry failure rationale and treats dry-run as static-only evidence. +- The evaluator verified that `preflight-text-imports.ts` currently scans for `import.meta`-relative file reads only (check `file-url-import-meta`) and does not scan for import attributes — confirming the plan's need for a preflight correction slice (slice 3). diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md index f28388304..579afe1be 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/supervisor.md @@ -16,7 +16,7 @@ | Task lane | Provider / model / effort | Role in this run | | --- | --- | --- | | `light_implementation` | current Codex root implementation session | Scoped hotfix implementation | -| `formal_evaluation` | OpenHands cloud / OpenRouter Qwen 3.7 Max / xhigh | Separate-session PLAN-EVAL and IMPL-EVAL after local Claude/OpenRouter credential check blocked | +| `formal_evaluation` | Claude Code + OpenRouter / Qwen 3.7 Max / high | Separate-session PLAN-EVAL and IMPL-EVAL; PLAN-EVAL session `f03ae1dd-da69-406a-b725-f3bf391255a8` | | `review_codex_light` | Claude opposite-family review route | Slice-review gate after automated evidence | -Reference `.llm/harness/workflow/lane-policy.md`. OpenHands is the canonical cloud formal-evaluator transport; the local transport was unavailable, as recorded in `drift.md`. +Reference `.llm/harness/workflow/lane-policy.md`. The configured OpenRouter environment was loaded for the canonical local formal-evaluator transport. diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md index 1f7f350a2..614381eae 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -53,6 +53,7 @@ Update the source README/schema/package metadata, run the publish-assets generat | Time | Slice | Step | Notes | | --- | --- | --- | --- | | 2026-07-17 | 1 | research/design | Re-baselined at `a5adb706`; implementation remains blocked on PLAN-EVAL. | +| 2026-07-17 | 1 | PLAN-EVAL | Separate local Qwen session `f03ae1dd-da69-406a-b725-f3bf391255a8` returned `PASS`. | ## Decisions From 7c17a6d1ce2c3d62850a747519ef7c0a87247b98 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:32:53 +0200 Subject: [PATCH 03/11] fix(mcp): embed publish assets as generated constants --- .../context-pack.md | 18 +-- .../worklog.md | 22 +++- .llm/tools/generate-publish-assets.ts | 108 ++++++++++++++++++ deno.json | 2 + .../kernel/adapters/scaffold/editor-config.ts | 3 +- .../kernel/assets/publish-assets.generated.ts | 9 ++ .../src/kernel/constants/jsr-specifiers.ts | 4 +- .../features/root/public-command-tree.ts | 4 +- packages/mcp/cli.ts | 4 +- .../infrastructure/spawn-command-executor.ts | 4 +- packages/mcp/src/publish-assets.generated.ts | 9 ++ plugins/ai/src/constants.ts | 4 +- plugins/ai/src/package-metadata.generated.ts | 5 + plugins/auth/src/constants.ts | 4 +- .../auth/src/package-metadata.generated.ts | 5 + plugins/auth/verify-plugin.ts | 4 +- .../sagas/src/package-metadata.generated.ts | 5 + plugins/sagas/src/public/mod.ts | 4 +- plugins/sagas/verify-plugin.ts | 4 +- plugins/streams/services/src/main.ts | 4 +- .../streams/src/package-metadata.generated.ts | 5 + plugins/streams/src/public/mod.ts | 4 +- plugins/triggers/services/src/main.ts | 4 +- plugins/triggers/src/constants.ts | 4 +- .../src/package-metadata.generated.ts | 5 + plugins/workers/services/src/init.ts | 4 +- .../workers/src/package-metadata.generated.ts | 5 + plugins/workers/src/public/mod.ts | 4 +- 28 files changed, 221 insertions(+), 40 deletions(-) create mode 100644 .llm/tools/generate-publish-assets.ts create mode 100644 packages/cli/src/kernel/assets/publish-assets.generated.ts create mode 100644 packages/mcp/src/publish-assets.generated.ts create mode 100644 plugins/ai/src/package-metadata.generated.ts create mode 100644 plugins/auth/src/package-metadata.generated.ts create mode 100644 plugins/sagas/src/package-metadata.generated.ts create mode 100644 plugins/streams/src/package-metadata.generated.ts create mode 100644 plugins/triggers/src/package-metadata.generated.ts create mode 100644 plugins/workers/src/package-metadata.generated.ts diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md index e08b39b42..90f030df7 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md @@ -12,23 +12,25 @@ ## Current State -The branch is based on `origin/main` at `a5adb706`. Research and a four-slice design are locked. Separate-session PLAN-EVAL passed; implementation may begin. +Separate-session PLAN-EVAL passed. Slice 2 is implemented and reviewed: generated constants now carry MCP README, CLI schema/version, and affected plugin versions; publishable consumers no longer use import attributes. ## Completed - Named skills, harness routing, relevant doctrine, release gates, existing generator, publish surface, and preflight implementation were inspected. - Research, plan, design checkpoint, supervisor identity, and drift log were created. - PLAN-EVAL passed in local Qwen session `f03ae1dd-da69-406a-b725-f3bf391255a8`. +- Generated publish assets, all affected consumers, and the regeneration/freshness tasks are implemented. +- MCP (45 tests), CLI, and six plugin checks pass; freshness is witnessed green and red; MCP publish dry-run and changed-file quality scan pass. ## In Progress -- Slice 2 generated publish assets and publish-surface sweep. +- Slice 3 release-preflight and release-guidance correction. ## Next Steps -1. Implement generated assets and the publish-surface sweep. -2. Run freshness green/red and focused package gates. -3. Commit, push, and comment slice 2. +1. Commit, push, and comment slice 2. +2. Finish and review the release-preflight/guidance slice. +3. Run full fixed-tree and seeded-red release evidence. ## Key Decisions @@ -42,14 +44,16 @@ The branch is based on `origin/main` at `a5adb706`. Research and a four-slice de | Path | Status | Notes | | --- | --- | --- | | `.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/` | new | Harness planning artifacts only. | +| `.llm/tools/generate-publish-assets.ts`, `deno.json` | new/changed | Deterministic generation and freshness task. | +| `packages/mcp`, `packages/cli`, `plugins/{ai,auth,sagas,streams,triggers,workers}` | changed | Generated assets and registry-safe consumers. | ## Gates | Gate family | Current status | Evidence | | --- | --- | --- | | Plan | PASS | `plan-eval.md`; session `f03ae1dd-da69-406a-b725-f3bf391255a8` | -| Static | not run | blocked by Plan-Gate | -| Fitness | not run | blocked by Plan-Gate | +| Static | PASS for slice 2 | package checks, focused MCP tests, wrapper fmt/lint evidence | +| Fitness | PASS for slice 2 | freshness green/red, quality scan, MCP dry-run/audit, arch check | | Runtime | N/A | no runtime protocol change planned | | Consumer | not run | blocked by Plan-Gate | diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md index 614381eae..d51f757d3 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -54,6 +54,10 @@ Update the source README/schema/package metadata, run the publish-assets generat | --- | --- | --- | --- | | 2026-07-17 | 1 | research/design | Re-baselined at `a5adb706`; implementation remains blocked on PLAN-EVAL. | | 2026-07-17 | 1 | PLAN-EVAL | Separate local Qwen session `f03ae1dd-da69-406a-b725-f3bf391255a8` returned `PASS`. | +| 2026-07-17 | 2 | implement | Added deterministic publish-asset generation; MCP, CLI, and six plugin surfaces consume generated constants instead of publishable import attributes. | +| 2026-07-17 | 2 | negative proof | Seeded stale plugin metadata made `check:publish-assets` exit 1; regeneration restored a green exit 0. | +| 2026-07-17 | 2 | review | Supervisor reviewed generated source fidelity, consumer import paths, publish include coverage, and excluded test/verifier attributes; no scope gap found. | +| 2026-07-17 | 2 | reconcile | #808 is closed and remains a non-closing `Refs #808`; PR #810 is draft with `status:impl`; no new reviewer comments required adjustment. | ## Decisions @@ -69,8 +73,22 @@ Update the source README/schema/package metadata, run the publish-assets generat ## Gate Results -No implementation gates run before PLAN-EVAL. +### Slice 2 — generated publish assets and sweep + +| Gate | Result | Evidence | +| --- | --- | --- | +| MCP check | PASS | `packages/mcp: deno task check` exit 0; wrapper-parsed log has 0 diagnostics | +| MCP tests | PASS | 45 passed, 0 failed | +| CLI check | PASS | `packages/cli: deno task check` exit 0 | +| plugin checks | PASS | `deno task check` exit 0 for ai/auth/sagas/streams/triggers/workers | +| freshness | PASS | `deno task check:publish-assets` exit 0 | +| freshness negative proof | PASS | seeded `PLUGIN_PACKAGE_VERSION = "seeded-stale-value"` produced exit 1 naming the stale generated file; regenerated tree returned green | +| changed source fmt/lint wrappers | PASS | 20 selected files, 0 failed batches/findings; generated output separately `deno fmt --check` clean | +| changed-file quality scan | PASS | 19 scanned files, 0 findings, 0 allowances | +| JSR audit | PASS with baseline tool note | MCP dry-run OK; helper reported only its known banner false-positive for “Checking for slow types” | +| MCP publish dry-run | PASS | `@netscript/mcp@0.0.1-beta.10` dry-run complete; generated README asset included | +| architecture | PASS | `deno task arch:check` exit 0; baseline warnings only, no failures | ## Handoff Notes -- PLAN-EVAL should spot-check `packages/mcp/cli.ts:18`, the existing generator pattern, and publish-rule filtering in `scanPublishSurface`. +- Evaluator should compare `MCP_PACKAGE_README` to `packages/mcp/README.md`, inspect generator check mode, and confirm remaining raw attributes are excluded tests/verifiers rather than publishable files. diff --git a/.llm/tools/generate-publish-assets.ts b/.llm/tools/generate-publish-assets.ts new file mode 100644 index 000000000..d4288e8dd --- /dev/null +++ b/.llm/tools/generate-publish-assets.ts @@ -0,0 +1,108 @@ +/** Generates registry-safe TypeScript constants for publish-time package assets. */ + +interface PackageConfig { + readonly version?: unknown; +} + +const ROOT = new URL('../../', import.meta.url); +const CHECK = Deno.args.includes('--check'); +const stalePaths: string[] = []; + +async function readVersion(path: string): Promise { + const config = JSON.parse(await Deno.readTextFile(new URL(path, ROOT))) as PackageConfig; + if (typeof config.version !== 'string' || !config.version.trim()) { + throw new Error(`${path} requires a non-empty version`); + } + return config.version; +} + +function header(): string { + return `// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run \`deno task gen:publish-assets\`. + +`; +} + +async function formatTypeScript(source: string): Promise { + const command = new Deno.Command('deno', { + args: ['fmt', '--ext', 'ts', '-'], + cwd: ROOT, + stdin: 'piped', + stdout: 'piped', + stderr: 'piped', + }).spawn(); + const writer = command.stdin.getWriter(); + await writer.write(new TextEncoder().encode(source)); + await writer.close(); + const { code, stdout, stderr } = await command.output(); + if (code !== 0) { + throw new Error(`deno fmt failed: ${new TextDecoder().decode(stderr)}`); + } + return new TextDecoder().decode(stdout); +} + +async function write(path: string, source: string): Promise { + const expected = await formatTypeScript(`${header()}${source}`); + const url = new URL(path, ROOT); + if (CHECK) { + const actual = await Deno.readTextFile(url).catch(() => ''); + if (actual !== expected) stalePaths.push(path); + return; + } + await Deno.writeTextFile(url, expected); +} + +async function generateMcpAssets(): Promise { + const version = await readVersion('packages/mcp/deno.json'); + const readme = await Deno.readTextFile(new URL('packages/mcp/README.md', ROOT)); + await write( + 'packages/mcp/src/publish-assets.generated.ts', + `/** Version of the published MCP package. */ +export const MCP_PACKAGE_VERSION: string = ${JSON.stringify(version)}; + +/** Published MCP README embedded as the default documentation corpus. */ +export const MCP_PACKAGE_README: string = ${JSON.stringify(readme)}; +`, + ); +} + +async function generateCliAssets(): Promise { + const version = await readVersion('packages/cli/deno.json'); + const schema = await Deno.readTextFile( + new URL('packages/cli/assets/schema/config-file.v1.json', ROOT), + ); + await write( + 'packages/cli/src/kernel/assets/publish-assets.generated.ts', + `/** Version of the published CLI package. */ +export const CLI_PACKAGE_VERSION: string = ${JSON.stringify(version)}; + +/** Serialized Deno configuration schema copied into generated workspaces. */ +export const DENO_CONFIG_SCHEMA_JSON: string = ${JSON.stringify(schema)}; +`, + ); +} + +async function generatePluginMetadata(): Promise { + for (const plugin of ['ai', 'auth', 'sagas', 'streams', 'triggers', 'workers']) { + const version = await readVersion(`plugins/${plugin}/deno.json`); + await write( + `plugins/${plugin}/src/package-metadata.generated.ts`, + `/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = ${JSON.stringify(version)}; +`, + ); + } +} + +if (import.meta.main) { + const unknownArgs = Deno.args.filter((arg) => arg !== '--check'); + if (unknownArgs.length > 0) throw new Error(`Unknown argument: ${unknownArgs[0]}`); + await Promise.all([generateMcpAssets(), generateCliAssets(), generatePluginMetadata()]); + if (stalePaths.length > 0) { + throw new Error( + `publish assets are stale: ${ + stalePaths.sort().join(', ') + }. Run deno task gen:publish-assets.`, + ); + } +} diff --git a/deno.json b/deno.json index 349908dfa..c7fbbe121 100644 --- a/deno.json +++ b/deno.json @@ -79,6 +79,8 @@ "agentic:opencode-web": "deno run --no-lock --allow-read --allow-run --allow-env .llm/tools/agentic/opencode/opencode-web.ts", "gen:assets-barrel": "deno run --no-lock --allow-read --allow-write --allow-run=deno .llm/tools/generate-cli-assets-barrel.ts", "check:assets-barrel": "deno task gen:assets-barrel && git diff --exit-code -- packages/cli/src/kernel/assets/embedded.generated.ts packages/plugin/src/kernel/assets/embedded.generated.ts packages/fresh-ui/registry.generated.ts packages/service/src/primitives/scalar.generated.ts", + "gen:publish-assets": "deno run --no-lock --allow-read --allow-write --allow-run=deno .llm/tools/generate-publish-assets.ts", + "check:publish-assets": "deno task gen:publish-assets --check", "check:scaffold-versions": "deno run .llm/tools/validation/check-scaffold-versions.ts --pretty", "check:netscript-jsr-specifiers": "deno run --allow-read .llm/tools/validation/check-netscript-jsr-specifiers.ts --pretty", "release:preflight": "deno run --allow-read .llm/tools/release/preflight-text-imports.ts", diff --git a/packages/cli/src/kernel/adapters/scaffold/editor-config.ts b/packages/cli/src/kernel/adapters/scaffold/editor-config.ts index be0550e1e..a062b4ef8 100644 --- a/packages/cli/src/kernel/adapters/scaffold/editor-config.ts +++ b/packages/cli/src/kernel/adapters/scaffold/editor-config.ts @@ -6,10 +6,11 @@ * immediately usable in the chosen editor without repo-specific assumptions. */ -import denoConfigSchema from '../../../../assets/schema/config-file.v1.json' with { type: 'json' }; +import { DENO_CONFIG_SCHEMA_JSON } from '../../assets/publish-assets.generated.ts'; import type { EditorChoice } from '../../domain/scaffold/workspace-config.ts'; const DENO_CONFIG_SCHEMA_TARGET = '.netscript/schema/config-file.v1.json'; +const denoConfigSchema: unknown = JSON.parse(DENO_CONFIG_SCHEMA_JSON); /** A single editor config file to be written relative to the workspace root. */ export interface EditorConfigFile { diff --git a/packages/cli/src/kernel/assets/publish-assets.generated.ts b/packages/cli/src/kernel/assets/publish-assets.generated.ts new file mode 100644 index 000000000..04e4ddc24 --- /dev/null +++ b/packages/cli/src/kernel/assets/publish-assets.generated.ts @@ -0,0 +1,9 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published CLI package. */ +export const CLI_PACKAGE_VERSION: string = '0.0.1-beta.10'; + +/** Serialized Deno configuration schema copied into generated workspaces. */ +export const DENO_CONFIG_SCHEMA_JSON: string = + '{\n "$id": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",\n "$schema": "https://json-schema.org/draft/2020-12/schema",\n "title": "Deno configuration file Schema",\n "description": "A JSON representation of a Deno configuration file.",\n "type": "object",\n "required": [],\n "$defs": {\n "permissionConfigValue": {\n "oneOf": [{\n "type": "boolean",\n "description": "Allow or deny the permission."\n }, {\n "type": "array",\n "description": "Subset of items to allow or deny depending on the context.",\n "items": { "type": "string" }\n }]\n },\n "allowDenyIgnorePermissionConfig": {\n "type": "object",\n "description": "Object form to allow, deny, and/or ignore permissions.",\n "additionalProperties": false,\n "properties": {\n "allow": { "$ref": "#/$defs/permissionConfigValue" },\n "deny": { "$ref": "#/$defs/permissionConfigValue" },\n "ignore": { "$ref": "#/$defs/permissionConfigValue" }\n }\n },\n "allowDenyIgnorePermissionConfigValue": {\n "oneOf": [{\n "$ref": "#/$defs/permissionConfigValue"\n }, {\n "$ref": "#/$defs/allowDenyIgnorePermissionConfig"\n }]\n },\n "allowDenyPermissionConfig": {\n "type": "object",\n "description": "Object form to allow and/or deny permissions.",\n "additionalProperties": false,\n "properties": {\n "allow": { "$ref": "#/$defs/permissionConfigValue" },\n "deny": { "$ref": "#/$defs/permissionConfigValue" }\n }\n },\n "allowDenyPermissionConfigValue": {\n "oneOf": [{\n "$ref": "#/$defs/permissionConfigValue"\n }, {\n "$ref": "#/$defs/allowDenyPermissionConfig"\n }]\n },\n "allowScriptsList": {\n "type": "array",\n "description": "List of npm package constraints to allow or deny for lifecycle scripts.",\n "items": {\n "type": "string",\n "pattern": "^(?:npm:).+"\n }\n },\n "permissionSet": {\n "type": "object",\n "description": "Collection of permissions.",\n "additionalProperties": false,\n "properties": {\n "all": {\n "type": "boolean",\n "description": "Allow all permissions for the program to run unrestricted."\n },\n "read": { "$ref": "#/$defs/allowDenyIgnorePermissionConfigValue" },\n "write": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },\n "import": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },\n "env": { "$ref": "#/$defs/allowDenyIgnorePermissionConfigValue" },\n "net": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },\n "run": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },\n "ffi": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },\n "sys": { "$ref": "#/$defs/allowDenyPermissionConfigValue" }\n }\n },\n "permissionNameOrSet": {\n "description": "A permission set name to use or inline permission set.",\n "anyOf": [{\n "type": "string",\n "description": "Permission name."\n }, {\n "$ref": "#/$defs/permissionSet"\n }]\n },\n "minimumDependencyAgeDate": {\n "oneOf": [{\n "description": "(Unstable) The age in minutes, ISO-8601 duration or RFC3339 absolute timestamp (e.g. \'120\' for two hours, \'P2D\' for two days, \'2025-09-16\' for cutoff date, \'2025-09-16T12:00:00+00:00\' for cutoff time, \'0\' to disable).",\n "type": "string"\n }, {\n "description": "(Unstable) The age in minutes.",\n "type": "number"\n }]\n }\n },\n "properties": {\n "allowScripts": {\n "oneOf": [{\n "description": "Whether to allow npm lifecycle scripts.",\n "type": "boolean"\n }, {\n "$ref": "#/$defs/allowScriptsList"\n }, {\n "type": "object",\n "description": "Allow or deny config for lifecycle scripts.",\n "additionalProperties": false,\n "properties": {\n "allow": {\n "oneOf": [{\n "description": "Whether to allow running npm lifecycle scripts.",\n "type": "boolean"\n }, {\n "$ref": "#/$defs/allowScriptsList"\n }]\n },\n "deny": {\n "description": "List of npm package constraints to deny running lifecycle scripts for.",\n "$ref": "#/$defs/allowScriptsList"\n }\n }\n }]\n },\n "compile": {\n "type": "object",\n "description": "Configuration for `deno compile`.",\n "additionalProperties": false,\n "properties": {\n "include": {\n "type": "array",\n "description": "List of additional modules or files/directories to include in the compiled executable.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files/directories to exclude from the compiled executable.",\n "items": {\n "type": "string"\n }\n },\n "permissions": {\n "$ref": "#/$defs/permissionNameOrSet"\n }\n }\n },\n "desktop": {\n "type": "object",\n "description": "Configuration for `deno desktop`.",\n "additionalProperties": false,\n "properties": {\n "app": {\n "type": "object",\n "description": "Application metadata.",\n "additionalProperties": false,\n "properties": {\n "name": {\n "type": "string",\n "description": "The application name."\n },\n "icons": {\n "type": "object",\n "description": "Platform-specific icon paths.",\n "additionalProperties": false,\n "properties": {\n "macos": {\n "type": "string",\n "description": "Icon path for macOS (.icns or .png)."\n },\n "windows": {\n "type": "string",\n "description": "Icon path for Windows (.ico)."\n },\n "linux": {\n "type": "string",\n "description": "Icon path for Linux (.png)."\n }\n }\n }\n }\n },\n "backend": {\n "type": "string",\n "description": "Backend to use for the desktop app.",\n "enum": ["webview", "cef"]\n },\n "output": {\n "type": "object",\n "description": "Platform-specific output paths.",\n "additionalProperties": false,\n "properties": {\n "macos": {\n "type": "string",\n "description": "Output path for macOS (e.g. MyApp.app, MyApp.dmg)."\n },\n "windows": {\n "type": "string",\n "description": "Output path for Windows (e.g. MyApp.msi, MyApp.exe)."\n },\n "linux": {\n "type": "string",\n "description": "Output path for Linux (e.g. MyApp.AppImage, MyApp.deb)."\n }\n }\n },\n "release": {\n "type": "object",\n "description": "Release and auto-update configuration.",\n "additionalProperties": false,\n "properties": {\n "baseUrl": {\n "type": "string",\n "description": "Base URL for auto-update release artifacts."\n }\n }\n }\n }\n },\n "compilerOptions": {\n "type": "object",\n "description": "Instructs the TypeScript compiler how to compile .ts files.",\n "additionalProperties": false,\n "properties": {\n "allowJs": {\n "description": "Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#allowJs"\n },\n "allowUnreachableCode": {\n "description": "Disable error reporting for unreachable code.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Disable error reporting for unreachable code.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#allowUnreachableCode"\n },\n "allowUnusedLabels": {\n "description": "Disable error reporting for unused labels.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Disable error reporting for unused labels.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#allowUnusedLabels"\n },\n "checkJs": {\n "description": "Enable error reporting in type-checked JavaScript files.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Enable error reporting in type-checked JavaScript files.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#checkJs"\n },\n "emitDecoratorMetadata": {\n "description": "Emit design-type metadata for decorated declarations in source files.",\n "type": "boolean",\n "default": false,\n "deprecated": true,\n "markdownDescription": "Emit design-type metadata for decorated declarations in source files.\\n\\nSee more: https://www.typescriptlang.org/tsconfig/#emitDecoratorMetadata"\n },\n "erasableSyntaxOnly": {\n "description": "Do not allow runtime constructs that are not part of ECMAScript.",\n "type": ["boolean", "null"],\n "default": false,\n "markdownDescription": "Do not allow runtime constructs that are not part of ECMAScript.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#erasableSyntaxOnly"\n },\n "exactOptionalPropertyTypes": {\n "description": "Interpret optional property types as written, rather than adding \'undefined\'.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Interpret optional property types as written, rather than adding \'undefined\'.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes"\n },\n "experimentalDecorators": {\n "description": "Enable experimental support for legacy experimental decorators.",\n "type": "boolean",\n "default": false,\n "deprecated": true,\n "markdownDescription": "Enable experimental support for legacy experimental decorators.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#experimentalDecorators"\n },\n "isolatedDeclarations": {\n "description": "Require sufficient annotation on exports so other tools can trivially generate declaration files.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Require sufficient annotation on exports so other tools can trivially generate declaration files.\\n\\nSee more: https://www.typescriptlang.org/tsconfig/#isolatedDeclarations"\n },\n "jsx": {\n "description": "Specify what JSX code is generated.",\n "default": "react",\n "enum": [\n "preserve",\n "react",\n "react-jsx",\n "react-jsxdev",\n "react-native",\n "precompile"\n ]\n },\n "jsxFactory": {\n "description": "Specify the JSX factory function used when targeting React JSX emit, e.g. \'React.createElement\' or \'h\'",\n "type": "string",\n "default": "React.createElement",\n "markdownDescription": "Specify the JSX factory function used when targeting React JSX emit, e.g. \'React.createElement\' or \'h\'\\n\\nSee more: https://www.typescriptlang.org/tsconfig#jsxFactory"\n },\n "jsxFragmentFactory": {\n "description": "Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. \'React.Fragment\' or \'Fragment\'.",\n "type": "string",\n "default": "React.Fragment",\n "markdownDescription": "Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. \'React.Fragment\' or \'Fragment\'.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#jsxFragmentFactory"\n },\n "jsxImportSource": {\n "description": "Specify module specifier used to import the JSX factory functions when using jsx: \'react-jsx*\'.",\n "type": "string",\n "default": "react",\n "markdownDescription": "Specify module specifier used to import the JSX factory functions when using jsx: `react-jsx*`.\\n\\nSee more: https://www.typescriptlang.org/tsconfig/#jsxImportSource"\n },\n "jsxImportSourceTypes": {\n "description": "Specify module specifier used to import the types for the JSX factory functions when using jsx: \'react-jsx*\'. This is the logical equivalent of prefixing an import to the jsxImportSource with `// @deno-types=\\"...\\"`.",\n "type": "string",\n "default": "@types/react",\n "markdownDescription": "Specify module specifier used to import the types for the JSX factory functions when using jsx: `react-jsx*`. This is the logical equivalent of prefixing an import to the jsxImportSource with `// @deno-types=\\"...\\"`."\n },\n "jsxPrecompileSkipElements": {\n "description": "Specify list of elements that should be exempt from being precompiled when the jsx \'precompile\' transform is used.",\n "type": "array",\n "items": {\n "type": "string"\n },\n "markdownDescription": "Specify list of elements that should be exempt from being precompiled when the jsx `precompile` transform is used."\n },\n "lib": {\n "description": "Specify a set of bundled library declaration files that describe the target runtime environment.",\n "type": "array",\n "uniqueItems": true,\n "default": ["deno.window", "deno.unstable", "node"],\n "items": {\n "type": "string",\n "examples": [\n "deno.ns",\n "deno.window",\n "deno.worker",\n "deno.unstable",\n "dom",\n "dom.iterable",\n "dom.asynciterable",\n "webworker",\n "webworker.importscripts",\n "webworker.iterable",\n "webworker.asynciterable",\n "scripthost",\n "decorators",\n "decorators.legacy",\n "es5",\n "es2015",\n "es2016",\n "es2017",\n "es2018",\n "es2019",\n "es2020",\n "es2021",\n "es2022",\n "es2023",\n "es2024",\n "esnext",\n "node"\n ]\n },\n "markdownDescription": "Specify a set of bundled library declaration files that describe the target runtime environment.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#lib"\n },\n "module": {\n "description": "Specify what module code is generated.",\n "type": ["string", "null"],\n "anyOf": [\n {\n "enum": [\n "esnext",\n "nodenext",\n "preserve"\n ]\n },\n {\n "pattern": "^([Ee][Ss][Nn][Ee][Xx][Tt]|[Nn][Oo][Dd][Ee][Nn][Ee][Xx][Tt]|[Pp][Rr][Ee][Ss][Ee][Rr][Vv][Ee])$"\n }\n ],\n "markdownDescription": "Specify what module code is generated.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#module"\n },\n "moduleResolution": {\n "description": "Specify how TypeScript looks up a file from a given module specifier.",\n "type": ["string", "null"],\n "anyOf": [\n {\n "enum": [\n "nodenext",\n "bundler"\n ],\n "markdownEnumDescriptions": [\n "This is the recommended setting for libraries and Node.js applications",\n "This is the recommended setting in TypeScript 5.0+ for applications that use a bundler"\n ]\n },\n {\n "pattern": "^([Nn]ode[Nn]ext|[Bb]undler)$"\n }\n ],\n "markdownDescription": "Specify how TypeScript looks up a file from a given module specifier.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#moduleResolution"\n },\n "noErrorTruncation": {\n "description": "Do not truncate error messages.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Do not truncate error messages.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noErrorTruncation"\n },\n "noFallthroughCasesInSwitch": {\n "description": "Enable error reporting for fallthrough cases in switch statements.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Enable error reporting for fallthrough cases in switch statements.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noFallthroughCasesInSwitch"\n },\n "noImplicitAny": {\n "description": "Enable error reporting for expressions and declarations with an implied `any` type.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Enable error reporting for expressions and declarations with an implied `any` type.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noImplicitAny"\n },\n "noImplicitOverride": {\n "description": "Ensure overriding members in derived classes are marked with an override modifier.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Ensure overriding members in derived classes are marked with an override modifier.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noImplicitOverride"\n },\n "noImplicitReturns": {\n "description": "Enable error reporting for codepaths that do not explicitly return in a function.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Enable error reporting for codepaths that do not explicitly return in a function.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noImplicitReturns"\n },\n "noImplicitThis": {\n "description": "Enable error reporting when `this` is given the type `any`.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Enable error reporting when `this` is given the type `any`.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noImplicitThis"\n },\n "noPropertyAccessFromIndexSignature": {\n "description": "Enforces using indexed accessors for keys declared using an indexed type.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Enforces using indexed accessors for keys declared using an indexed type.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noPropertyAccessFromIndexSignature"\n },\n "noUncheckedIndexedAccess": {\n "description": "Add `undefined` to a type when accessed using an index.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Add `undefined` to a type when accessed using an index.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess"\n },\n "noUnusedLocals": {\n "description": "Enable error reporting when a local variables aren\'t read.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Enable error reporting when a local variables aren\'t read.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noUnusedLocals"\n },\n "noUnusedParameters": {\n "description": "Raise an error when a function parameter isn\'t read",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Raise an error when a function parameter isn\'t read\\n\\nSee more: https://www.typescriptlang.org/tsconfig#noUnusedParameters"\n },\n "baseUrl": {\n "description": "Specify the base directory to resolve non-relative module names.",\n "type": ["string", "null"],\n "markdownDescription": "Specify the base directory to resolve non-relative module names.\\n\\nIn Deno, this is only applied to bare specifier entries in `compilerOptions.paths` and `compilerOptions.rootDirs`.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#baseUrl"\n },\n "paths": {\n "description": "Specify a set of entries that re-map imports to additional lookup locations.",\n "type": ["object", "null"],\n "additionalProperties": {\n "type": ["array", "null"],\n "uniqueItems": true,\n "items": {\n "type": ["string", "null"],\n "description": "Path mapping to be computed relative to baseUrl option."\n }\n },\n "markdownDescription": "Specify a set of entries that re-map imports to additional lookup locations.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#paths"\n },\n "rootDirs": {\n "description": "Declare many “virtual” directories acting as a single root.",\n "type": "array",\n "items": {\n "type": "string"\n },\n "markdownDescription": "Declare many “virtual” directories acting as a single root.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#rootDirs"\n },\n "skipLibCheck": {\n "description": "Skip type checking all .d.ts files.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Skip type checking all .d.ts files.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#skipLibCheck"\n },\n "strict": {\n "description": "Enable all strict type checking options.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Enable all strict type checking options.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#strict"\n },\n "strictBindCallApply": {\n "description": "Check that the arguments for `bind`, `call`, and `apply` methods match the original function.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Check that the arguments for `bind`, `call`, and `apply` methods match the original function.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#strictBindCallApply"\n },\n "strictBuiltinIteratorReturn": {\n "description": "Built-in iterators are instantiated with a `TReturn` type of undefined instead of `any`.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Built-in iterators are instantiated with a `TReturn` type of undefined instead of `any`.\\n\\nSee more: https://www.typescriptlang.org/tsconfig/#strictBuiltinIteratorReturn"\n },\n "strictFunctionTypes": {\n "description": "When assigning functions, check to ensure parameters and the return values are subtype-compatible.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "When assigning functions, check to ensure parameters and the return values are subtype-compatible.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#strictFunctionTypes"\n },\n "strictNullChecks": {\n "description": "When type checking, take into account `null` and `undefined`.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "When type checking, take into account `null` and `undefined`.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#strictNullChecks"\n },\n "strictPropertyInitialization": {\n "description": "Check for class properties that are declared but not set in the constructor.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Check for class properties that are declared but not set in the constructor.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#strictPropertyInitialization"\n },\n "types": {\n "description": "Specify type package names to be included without being referenced in a source file.",\n "type": "array",\n "items": {\n "type": "string"\n },\n "markdownDescription": "Specify type package names to be included without being referenced in a source file.\\n\\nSee more: https://www.typescriptlang.org/tsconfig/#types"\n },\n "useUnknownInCatchVariables": {\n "description": "Default catch clause variables as `unknown` instead of `any`.",\n "type": "boolean",\n "default": true,\n "markdownDescription": "Default catch clause variables as `unknown` instead of `any`.\\n\\nSee more: https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables"\n },\n "verbatimModuleSyntax": {\n "description": "Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file\'s format based on the \'module\' setting.",\n "type": "boolean",\n "default": false,\n "markdownDescription": "Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file\'s format based on the \'module\' setting.\\n\\nSee more: https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax"\n }\n }\n },\n "deploy": {\n "type": "object",\n "description": "Configuration for `deno deploy` and `deno sandbox`.",\n "additionalProperties": false,\n "properties": {\n "org": {\n "type": "string",\n "description": "The organization slug or ID to interact with."\n },\n "app": {\n "type": "string",\n "description": "The application slug or ID to interact with."\n },\n "framework": {\n "type": "string",\n "description": "The framework this application is built with, such as `nextjs` or `fresh`. Part of the build configuration. When specified, takes precedence over all configuration specified in the console."\n },\n "install": {\n "type": "string",\n "description": "The command to install dependencies. Part of the build configuration. When specified, takes precedence over all configuration specified in the console."\n },\n "build": {\n "type": "string",\n "description": "The command to build the application. Part of the build configuration. When specified, takes precedence over all configuration specified in the console."\n },\n "predeploy": {\n "type": "string",\n "description": "The command to run before deploying, usually used to run database migrations. When specified, takes precedence over all configuration specified in the console."\n },\n "runtime": {\n "type": "object",\n "description": "Runtime configuration for the deployed application. When specified, takes precedence over all configuration specified in the console.",\n "additionalProperties": false,\n "properties": {\n "mode": {\n "type": "string",\n "enum": ["dynamic", "static"],\n "default": "dynamic",\n "description": "The runtime mode. Use \'dynamic\' for server-rendered applications or \'static\' for pre-built static files."\n },\n "entrypoint": {\n "type": "string",\n "description": "The entrypoint file for dynamic mode (e.g., \'main.ts\')."\n },\n "args": {\n "type": "array",\n "items": { "type": "string" },\n "description": "Arguments to pass to the entrypoint for dynamic mode."\n },\n "cwd": {\n "type": "string",\n "description": "The working directory. For dynamic mode, this is the current working directory. For static mode, this is the directory containing static files to serve."\n },\n "spa": {\n "type": "boolean",\n "description": "Enable single-page application mode for static deployments. When enabled, all routes will fall back to index.html.",\n "default": false\n }\n }\n },\n "include": {\n "type": "array",\n "description": "List of files, directories or globs that will be included in deployments.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will not be included in deployments.",\n "items": {\n "type": "string"\n }\n }\n }\n },\n "importMap": {\n "description": "The location of an import map to be used when resolving modules. If an import map is specified as an `--importmap` flag or using \\"imports\\" and \\"scopes\\" properties, they will override this value.",\n "type": "string"\n },\n "catalog": {\n "description": "A map of package names to version requirements for the default catalog, used with the catalog: protocol in workspace member package.json files.",\n "type": "object",\n "additionalProperties": {\n "description": "The key is the npm package name, with a value that is the version requirement string.",\n "type": "string"\n }\n },\n "catalogs": {\n "description": "Named catalogs mapping catalog names to package name/version requirement mappings, used with the catalog: protocol.",\n "type": "object",\n "additionalProperties": {\n "type": "object",\n "additionalProperties": {\n "type": "string"\n }\n }\n },\n "imports": {\n "description": "A map of specifiers to their remapped specifiers.",\n "type": "object",\n "additionalProperties": {\n "description": "The key is the specifier or partial specifier to match, with a value that represents the target specifier.",\n "type": "string"\n }\n },\n "scopes": {\n "default": {},\n "description": "Define a scope which remaps a specifier in only a specified scope",\n "type": "object",\n "properties": {},\n "additionalProperties": {\n "description": "A definition of a scoped remapping.",\n "type": "object",\n "additionalProperties": {\n "description": "The key is the specifier or partial specifier to match within the referring scope, with a value that represents the target specifier.",\n "type": "string"\n }\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will be ignored by all other configurations. Requires Deno 1.34 or later.",\n "items": {\n "type": "string"\n }\n },\n "lint": {\n "description": "Configuration for linter",\n "type": "object",\n "properties": {\n "include": {\n "type": "array",\n "description": "List of files, directories or globs that will be linted.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will not be linted.",\n "items": {\n "type": "string"\n }\n },\n "plugins": {\n "type": "array",\n "description": "UNSTABLE: List of plugins to load. These can be paths, npm or jsr specifiers",\n "items": {\n "type": "string"\n }\n },\n "rules": {\n "type": "object",\n "properties": {\n "tags": {\n "type": "array",\n "description": "List of tag names that will be run. Empty list disables all tags and will only use rules from `include`.",\n "items": {\n "$ref": "lint-tags.v1.json"\n },\n "minItems": 0,\n "uniqueItems": true\n },\n "exclude": {\n "type": "array",\n "description": "List of rule names that will be excluded from configured tag sets. If the same rule is in `include` it will be run.",\n "items": {\n "$ref": "lint-rules.v1.json"\n },\n "minItems": 0,\n "uniqueItems": true\n },\n "include": {\n "type": "array",\n "description": "List of rule names that will be run. Even if the same rule is in `exclude` it will be run.",\n "items": {\n "$ref": "lint-rules.v1.json"\n },\n "minItems": 0,\n "uniqueItems": true\n }\n }\n },\n "report": {\n "default": "pretty",\n "enum": ["pretty", "json", "compact"],\n "description": "The default report format to use when linting"\n }\n }\n },\n "fmt": {\n "description": "Configuration for formatter",\n "type": "object",\n "properties": {\n "include": {\n "type": "array",\n "description": "List of files, directories or globs that will be formatted.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will not be formatted.",\n "items": {\n "type": "string"\n }\n },\n "useTabs": {\n "description": "Whether to use tabs (true) or spaces (false) for indentation.",\n "type": "boolean",\n "default": false\n },\n "lineWidth": {\n "description": "The width of a line the printer will try to stay under. Note that the printer may exceed this width in certain cases.",\n "type": "number",\n "default": 80\n },\n "indentWidth": {\n "description": "The number of characters for an indent.",\n "type": "number",\n "default": 2\n },\n "singleQuote": {\n "type": "boolean",\n "description": "Whether to use single quote (true) or double quote (false) for quotation.",\n "default": false\n },\n "proseWrap": {\n "description": "Define how prose should be wrapped in Markdown files.",\n "default": "always",\n "enum": ["always", "never", "preserve"]\n },\n "semiColons": {\n "description": "Whether to prefer using semicolons.",\n "type": "boolean",\n "default": true\n },\n "quoteProps": {\n "description": "Change when properties in objects are quoted in JavaScript and TypeScript.",\n "default": "preserve",\n "enum": ["asNeeded", "consistent", "preserve"]\n },\n "newLineKind": {\n "description": "The newline character to use.",\n "default": "lf",\n "enum": ["auto", "crlf", "lf", "system"]\n },\n "useBraces": {\n "description": "Whether to use braces for if statements, for statements, and while statements in JavaScript and TypeScript.",\n "default": "whenNotSingleLine",\n "enum": ["maintain", "whenNotSingleLine", "always", "preferNone"]\n },\n "bracePosition": {\n "description": "The position of opening braces for blocks in JavaScript and TypeScript.",\n "default": "sameLine",\n "enum": [\n "maintain",\n "sameLine",\n "nextLine",\n "sameLineUnlessHanging"\n ]\n },\n "singleBodyPosition": {\n "description": "The position of the body in single body blocks in JavaScript and TypeScript.",\n "default": "maintain",\n "enum": [\n "maintain",\n "sameLine",\n "nextLine"\n ]\n },\n "nextControlFlowPosition": {\n "description": "Where to place the next control flow within a control flow statement in JavaScript and TypeScript.",\n "default": "sameLine",\n "enum": [\n "maintain",\n "sameLine",\n "nextLine"\n ]\n },\n "trailingCommas": {\n "description": "Whether to add trailing commas in JavaScript and TypeScript.",\n "default": "onlyMultiLine",\n "enum": ["never", "always", "onlyMultiLine"]\n },\n "json.trailingCommas": {\n "description": "Whether to add trailing commas in JSON and JSONC. Defaults to \\"never\\". The \\"jsonc\\" option adds trailing commas in JSONC files and omits them in JSON files.",\n "default": "never",\n "enum": ["never", "always", "maintain", "jsonc"]\n },\n "operatorPosition": {\n "description": "Where to place the operator for expressions that span multiple lines in JavaScript and TypeScript.",\n "default": "sameLine",\n "enum": [\n "maintain",\n "sameLine",\n "nextLine"\n ]\n },\n "jsx.bracketPosition": {\n "description": "If the end angle bracket of a jsx open element or self closing element should be on the same or next line when the attributes span multiple lines.",\n "default": "nextLine",\n "enum": ["maintain", "sameLine", "nextLine"]\n },\n "jsx.forceNewLineSurroundingContent": {\n "description": "Forces newlines surrounding the content of JSX elements.",\n "default": false,\n "type": "boolean"\n },\n "jsx.multiLineParens": {\n "description": "Surrounds the top-most JSX element or fragment in parentheses when it spans multiple lines.",\n "default": "prefer",\n "enum": ["never", "prefer", "always"]\n },\n "typeLiteral.separatorKind": {\n "description": "The kind of separator to use in type literals.",\n "default": "semiColon",\n "enum": ["comma", "semiColon"]\n },\n "spaceAround": {\n "description": "Whether to place spaces around enclosed expressions in JavaScript and TypeScript.",\n "default": false,\n "type": "boolean"\n },\n "spaceSurroundingProperties": {\n "description": "Whether to add a space surrounding the properties of single line object-like nodes in JavaScript and TypeScript.",\n "default": true,\n "type": "boolean"\n },\n "vueComponentCase": {\n "description": "Case style for Vue component tags.",\n "default": "ignore",\n "enum": ["ignore", "pascal-case", "kebab-case"]\n },\n "angularNextControlFlowSameLine": {\n "description": "Whether Angular next control-flow clauses stay on the same line.",\n "default": true,\n "type": "boolean"\n },\n "options": {\n "type": "object",\n "properties": {\n "useTabs": {\n "description": "Whether to use tabs (true) or spaces (false) for indentation.",\n "type": "boolean",\n "default": false\n },\n "lineWidth": {\n "description": "The width of a line the printer will try to stay under. Note that the printer may exceed this width in certain cases.",\n "type": "number",\n "default": 80\n },\n "indentWidth": {\n "description": "The number of characters for an indent.",\n "type": "number",\n "default": 2\n },\n "singleQuote": {\n "type": "boolean",\n "description": "Whether to use single quote (true) or double quote (false) for quotation.",\n "default": false\n },\n "proseWrap": {\n "description": "Define how prose should be wrapped in Markdown files.",\n "default": "always",\n "enum": ["always", "never", "preserve"]\n },\n "semiColons": {\n "description": "Whether to prefer using semicolons.",\n "type": "boolean",\n "default": true\n }\n }\n }\n }\n },\n "minimumDependencyAge": {\n "oneOf": [{\n "$ref": "#/$defs/minimumDependencyAgeDate"\n }, {\n "type": "object",\n "description": "Minimum dependency age config.",\n "additionalProperties": false,\n "properties": {\n "age": { "$ref": "#/$defs/minimumDependencyAgeDate" },\n "exclude": {\n "type": "array",\n "description": "List of jsr or npm packages to exclude from requiring a minimum dependnecy age.",\n "items": {\n "type": "string",\n "pattern": "^(?:npm:|jsr:).+"\n }\n }\n }\n }]\n },\n "nodeModulesDir": {\n "oneOf": [\n {\n "description": "Sets the node_modules management mode for npm packages. Alternatively, use the `--node-modules-dir=` flag. Requires Deno 2.0-rc.1 or later.",\n "default": "none",\n "enum": ["auto", "manual", "none"]\n },\n {\n "description": "Enables or disables the use of a local node_modules folder for npm packages. Alternatively, use the `--node-modules-dir` flag or override the config via `--node-modules-dir=false`. Requires Deno 1.34 or later.",\n "type": "boolean",\n "deprecated": false\n }\n ]\n },\n "vendor": {\n "description": "Enables or disables the use of a local vendor folder as a local cache for remote modules and node_modules folder for npm packages. Alternatively, use the `--vendor` flag or override the config via `--vendor=false`. Requires Deno 1.36.1 or later.",\n "type": "boolean"\n },\n "tasks": {\n "description": "Configuration for deno task",\n "type": "object",\n "patternProperties": {\n "^[A-Za-z][A-Za-z0-9_\\\\-:]*$": {\n "oneOf": [\n {\n "type": "string",\n "description": "Command to execute for this task name."\n },\n {\n "type": "object",\n "description": "A definition of a task to execute",\n "properties": {\n "description": {\n "type": "string",\n "description": "Description of a task that will be shown when running `deno task` without a task name"\n },\n "command": {\n "type": "string",\n "description": "The task to execute"\n },\n "dependencies": {\n "type": "array",\n "items": {\n "type": "string"\n },\n "description": "Tasks that should be executed before this task"\n }\n }\n }\n ]\n }\n },\n "additionalProperties": false\n },\n "test": {\n "description": "Configuration for deno test",\n "type": "object",\n "properties": {\n "include": {\n "type": "array",\n "description": "List of files, directories or globs that will be searched for tests.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will not be searched for tests.",\n "items": {\n "type": "string"\n }\n },\n "permissions": {\n "$ref": "#/$defs/permissionNameOrSet"\n },\n "sanitizeOps": {\n "type": "boolean",\n "description": "Enable the ops sanitizer for all tests. Ensures that all async ops started in a test are completed before the test ends. Can be overridden per-test or per-module."\n },\n "sanitizeResources": {\n "type": "boolean",\n "description": "Enable the resources sanitizer for all tests. Ensures that all resources opened in a test are closed before the test ends. Can be overridden per-test or per-module."\n }\n }\n },\n "publish": {\n "oneOf": [{\n "description": "Configuration for deno publish",\n "type": "object",\n "properties": {\n "include": {\n "type": "array",\n "description": "List of files, directories or globs that will be included in the published package.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will be excluded from the published package.",\n "items": {\n "type": "string"\n }\n }\n }\n }, {\n "description": "Disable publishing this package with deno publish",\n "const": false\n }]\n },\n "bench": {\n "description": "Configuration for deno bench",\n "type": "object",\n "properties": {\n "include": {\n "type": "array",\n "description": "List of files, directories or globs that will be searched for benchmarks.",\n "items": {\n "type": "string"\n }\n },\n "exclude": {\n "type": "array",\n "description": "List of files, directories or globs that will not be searched for benchmarks.",\n "items": {\n "type": "string"\n }\n },\n "permissions": {\n "$ref": "#/$defs/permissionNameOrSet"\n }\n }\n },\n "license": {\n "description": "The SPDX license identifier if this is a JSR package. Specify this or add a license file to the package.",\n "type": ["string"]\n },\n "lock": {\n "description": "Whether to use a lock file or the path to use for the lock file. Can be overridden by CLI arguments.",\n "type": ["string", "boolean", "object"],\n "default": true,\n "properties": {\n "path": {\n "type": "string",\n "description": "The path to use for the lock file.",\n "default": "deno.lock"\n },\n "frozen": {\n "type": "boolean",\n "description": "Whether to exit with an error if lock file is out of date.",\n "default": false\n }\n }\n },\n "unstable": {\n "type": "array",\n "description": "List of unstable features to enable.",\n "items": {\n "type": "string",\n "examples": [\n "bare-node-builtins",\n "bundle",\n "byonm",\n "cron",\n "detect-cjs",\n "ffi",\n "fs",\n "fmt-component",\n "fmt-sql",\n "http",\n "kv",\n "net",\n "node-globals",\n "raw-imports",\n "sloppy-imports",\n "unsafe-proto",\n "webgpu",\n "worker-options"\n ]\n }\n },\n "name": {\n "type": "string",\n "description": "The name of this JSR or workspace package."\n },\n "version": {\n "type": "string",\n "description": "The version of this JSR package."\n },\n "exports": {\n "oneOf": [\n {\n "type": "string",\n "description": "The path to the main module of this JSR package.",\n "examples": ["./mod.ts", "./index.js"],\n "pattern": "^\\\\./.*$"\n },\n {\n "type": "object",\n "description": "A map of package exports to files in this JSR package.",\n "propertyNames": {\n "description": "Package export name",\n "examples": [".", "./foo", "./bar"],\n "pattern": "^\\\\.(/.*)?$"\n },\n "patternProperties": {\n "^\\\\.(/.*)?$": {\n "type": "string",\n "pattern": "^\\\\./.*$"\n }\n },\n "examples": [{ ".": "./mod.ts" }]\n }\n ]\n },\n "permissions": {\n "type": "object",\n "description": "Named permission sets that can be selected with -P/--permission-set or referenced in \\"test\\", \\"bench\\", or \\"compile\\" permissions. A special name \\"default\\" is used when -P is passed without a value.",\n "additionalProperties": { "$ref": "#/$defs/permissionSet" }\n },\n "patch": {\n "type": "array",\n "items": {\n "type": "string"\n },\n "deprecated": true,\n "description": "This unstable property was renamed to \\"links\\" in Deno 2.3.6."\n },\n "links": {\n "type": "array",\n "items": {\n "type": "string"\n },\n "description": "List of paths, file URLs, or glob patterns to folders containing JSR packages to use local versions of."\n },\n "workspace": {\n "oneOf": [\n {\n "type": "array",\n "items": {\n "type": "string"\n },\n "description": "The members of this workspace."\n },\n {\n "type": "object",\n "properties": {\n "members": {\n "type": "array",\n "items": {\n "type": "string"\n },\n "description": "The members of this workspace."\n }\n }\n }\n ]\n }\n }\n}\n'; diff --git a/packages/cli/src/kernel/constants/jsr-specifiers.ts b/packages/cli/src/kernel/constants/jsr-specifiers.ts index 5dc0adab0..b2b384b6e 100644 --- a/packages/cli/src/kernel/constants/jsr-specifiers.ts +++ b/packages/cli/src/kernel/constants/jsr-specifiers.ts @@ -2,7 +2,7 @@ * JSR package specifiers used by public CLI scaffolding. */ -import cliPackageJson from '../../../deno.json' with { type: 'json' }; +import { CLI_PACKAGE_VERSION } from '../assets/publish-assets.generated.ts'; /** NetScript package names that public scaffolds may import from JSR. */ export type NetscriptPackage = @@ -32,7 +32,7 @@ export type NetscriptPackage = | 'workers'; /** Release train version sourced from the CLI package manifest. */ -export const NETSCRIPT_RELEASE_VERSION: string = cliPackageJson.version; +export const NETSCRIPT_RELEASE_VERSION: string = CLI_PACKAGE_VERSION; /** Exact JSR version suffix for NetScript prerelease package pins. */ export const NETSCRIPT_RELEASE_TAG = `@${NETSCRIPT_RELEASE_VERSION}`; diff --git a/packages/cli/src/public/features/root/public-command-tree.ts b/packages/cli/src/public/features/root/public-command-tree.ts index 95e218e28..0636d117b 100644 --- a/packages/cli/src/public/features/root/public-command-tree.ts +++ b/packages/cli/src/public/features/root/public-command-tree.ts @@ -18,7 +18,7 @@ import { createPublicCommandDependencies, type PublicCommandDependencies, } from './public-command-dependencies.ts'; -import cliMeta from '../../../../deno.json' with { type: 'json' }; +import { CLI_PACKAGE_VERSION } from '../../../kernel/assets/publish-assets.generated.ts'; /** Host services supplied by the binary edge. */ export interface PublicCliHost { @@ -118,7 +118,7 @@ export function createPublicCommandTree(host: PublicCliHost): PublicCliCommand { return registry.program({ name: 'netscript', - version: cliMeta.version, + version: CLI_PACKAGE_VERSION, description: 'NetScript - enterprise-grade polyglot backend framework CLI', context: { host, dependencies }, }); diff --git a/packages/mcp/cli.ts b/packages/mcp/cli.ts index 896d7ed5d..86e15d71a 100644 --- a/packages/mcp/cli.ts +++ b/packages/mcp/cli.ts @@ -15,7 +15,7 @@ import { runNewlineStdio } from './src/infrastructure/stdio-transport.ts'; import { FilesystemDocsCorpus } from './src/infrastructure/filesystem-docs-corpus.ts'; import { EmbeddedDocsCorpus } from './src/infrastructure/embedded-docs-corpus.ts'; import { resolve } from '@std/path'; -import packageReadme from './README.md' with { type: 'text' }; +import { MCP_PACKAGE_README } from './src/publish-assets.generated.ts'; import { createGetAppStatusFlow } from './src/application/flows/get-app-status-flow.ts'; import { createGetRecentErrorsFlow } from './src/application/flows/get-recent-errors-flow.ts'; import { createGetRunFlow } from './src/application/flows/get-run-flow.ts'; @@ -92,7 +92,7 @@ export function createMcpCliServer(options: McpCliOptions = {}): McpServer { const docsCorpus = configuredDocsRoot ? new FilesystemDocsCorpus({ root: configuredDocsRoot }) : new EmbeddedDocsCorpus({ - documents: [{ slug: 'mcp', source: packageReadme }], + documents: [{ slug: 'mcp', source: MCP_PACKAGE_README }], }); const probe = new FetchTelemetryProbe((endpoint) => createAspireDashboardFetch(endpoint, {}) ?? fetch diff --git a/packages/mcp/src/infrastructure/spawn-command-executor.ts b/packages/mcp/src/infrastructure/spawn-command-executor.ts index 677383447..f866acd50 100644 --- a/packages/mcp/src/infrastructure/spawn-command-executor.ts +++ b/packages/mcp/src/infrastructure/spawn-command-executor.ts @@ -3,14 +3,14 @@ import type { CommandExecutionResult, CommandExecutorPort, } from '../domain/command-executor-port.ts'; -import mcpPackageJson from '../../deno.json' with { type: 'json' }; +import { MCP_PACKAGE_VERSION } from '../publish-assets.generated.ts'; /** Public CLI invocation used when an outer composition does not inject one. */ export const DEFAULT_CLI_COMMAND: readonly string[] = Object.freeze([ 'deno', 'run', '-A', - `jsr:@netscript/cli@${mcpPackageJson.version}`, + `jsr:@netscript/cli@${MCP_PACKAGE_VERSION}`, ]); /** Default command deadline in milliseconds. */ export const DEFAULT_COMMAND_TIMEOUT_MS = 120_000; diff --git a/packages/mcp/src/publish-assets.generated.ts b/packages/mcp/src/publish-assets.generated.ts new file mode 100644 index 000000000..3ec8c3cfe --- /dev/null +++ b/packages/mcp/src/publish-assets.generated.ts @@ -0,0 +1,9 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published MCP package. */ +export const MCP_PACKAGE_VERSION: string = '0.0.1-beta.10'; + +/** Published MCP README embedded as the default documentation corpus. */ +export const MCP_PACKAGE_README: string = + '# @netscript/mcp\n\n[![JSR](https://jsr.io/badges/@netscript/mcp)](https://jsr.io/@netscript/mcp)\n[![CI](https://github.com/rickylabs/netscript/actions/workflows/ci.yml/badge.svg)](https://github.com/rickylabs/netscript/actions/workflows/ci.yml)\n[![Docs](https://img.shields.io/badge/docs-rickylabs.github.io-blue)](https://rickylabs.github.io/netscript/)\n\n**The Model Context Protocol server for NetScript: 13 token-bounded tools that let a coding agent\nmonitor a running app, debug a correlated execution, read framework-semantic telemetry, run the\ndoctor, and search the docs — all over stdio.**\n\nIt also triggers allowlisted CLI commands through a default-deny policy, and carries no npm MCP SDK\non its dependency graph.\n\n---\n\n## 🧭 Why\n\nAn agent working on a NetScript app has to answer operational questions — _did the last import job\nsucceed, why is the checkout service slow, which query is hammering the database, is my Aspire\nwiring broken_ — and it usually answers them by shelling out, tailing logs, and pasting thousands of\ntokens of raw trace JSON into its own context. That is slow, expensive, and lossy: the agent burns\nits budget re-deriving structure NetScript already knows.\n\n`@netscript/mcp` closes that gap. It exposes NetScript\'s own read models — the\n[`TelemetryQueryPort`](https://jsr.io/@netscript/telemetry/doc/query) trace/span/log reader, the\nproject\'s generated registries, the plugin doctor, and the public docs corpus — as MCP tools whose\nresults are **summaries, not dumps**. Every successful result is bounded server-side before it\nreaches the model, and the analytics tools return percentiles, error rates, and ranked operations\nrather than the spans they were computed from. The tools are NetScript-semantic, not generic OTLP:\nthey speak `worker`, `saga`, `trigger`, `stream`, and `service`, because they classify spans by the\n`netscript.*` attribute conventions the framework already emits.\n\nThe server is one third of the NetScript agentic surface — the CLI is the hands, the skills are the\ndoctrine, MCP is the eyes. It deliberately **wraps the CLI rather than reimplementing it**:\n`list_commands` reflects the live command tree, and `execute_command` shells the CLI through a\ndefault-deny policy. An agent that can run `netscript db migrate` directly should just run it; MCP\nexists for what a shell cannot cheaply give it — bounded aggregation, cross-domain diagnostics, and\ndocumentation lookup.\n\n---\n\n## Install\n\nMost users never import this package. Install the server into a project with the CLI:\n\n```bash\nnetscript agent init\n```\n\nThat writes `.mcp.json` (Claude Code) and/or `.vscode/mcp.json` pointing at `netscript agent mcp`,\nand installs the version-matched NetScript skills. Start the app, and the agent can ask its\nquestions:\n\n> _"Is the app healthy?"_ → `get_app_status` · _"Why did the last import job fail?"_ →\n> `get_last_job_result`, then `get_run` · _"What is slowing down `checkout`?"_ →\n> `analyze_service_performance`\n\nTo embed the server in your own host process, add it as a library:\n\n```bash\ndeno add jsr:@netscript/mcp\n```\n\nRun the standalone stdio entrypoint directly when you are integrating another MCP host:\n\n```bash\ndeno x -A jsr:@netscript/mcp@/cli\n```\n\nPin `` to match your installed CLI; bare `jsr:@netscript/*` specifiers do not resolve on\nthe pre-release line, and `netscript agent init` writes the correct pinned form for you.\n\n## Quick example\n\n`netscript agent init` writes the host configuration for you. The Claude Code form is equivalent to:\n\n```json\n{\n "mcpServers": {\n "netscript": {\n "command": "deno",\n "args": [\n "run",\n "-A",\n "jsr:@netscript/cli@",\n "agent",\n "mcp",\n "--project-root",\n ""\n ]\n }\n }\n}\n```\n\nThe process speaks newline-delimited JSON-RPC over standard input and output. After MCP\ninitialization, `tools/list` returns the 13 bounded NetScript tools for telemetry, diagnostics,\ndocumentation, and allowlisted CLI actions.\n\n## Docs\n\n- [MCP package reference](https://rickylabs.github.io/netscript/reference/mcp/)\n- [Agent tooling](https://rickylabs.github.io/netscript/capabilities/agent-tooling/)\n\n---\n\n## 🧩 Mental model\n\n```text\n agent (Claude Code, VS Code, …)\n │ JSON-RPC over stdio\n ┌─────────▼──────────┐\n │ runner + policy │ initialize · tools/list · tools/call\n │ (truncation) │ every result bounded before it is returned\n └─────────┬──────────┘\n │ 13 tool flows\n ┌─────────────┼───────────────┬──────────────────┐\n ▼ ▼ ▼ ▼\ntelemetry docs corpus doctor families command policy\n(read model) (public .md) (aspire/wiring/ (default-deny\n plugins) allowlist)\n │ │ │\n ▼ ▼ ▼\nAspire dashboard HTTP project metadata `netscript` binary\n```\n\nThree ideas carry the design.\n\n**Tools are flows over ports.** A tool is a name, an input contract, an output contract, and a flow.\nThe flow depends only on a port — `TelemetryProbePort`, `DocsCorpusPort`, `CommandCatalogPort`,\n`CommandExecutorPort`, `ProjectDoctorPort` — never on a concrete client. That is why this package\ncan report on the CLI without depending on it: `@netscript/cli` implements the ports and injects\nthem at its own composition root, so the dependency points inward and no cycle exists.\n\n**Results are bounded by construction.** `truncateResult` walks every successful result and caps\narrays at 50 elements and strings at 2,000 UTF-16 code units before the runner serializes it. The\nanalytics tools go further and never return raw spans at all. A failure is a structured tool error,\nnot a crash: an unreachable telemetry endpoint produces a `warn`/`fail` result the agent can reason\nabout.\n\n**Execution is default-deny.** `execute_command` matches a normalized command path against an\nordered policy. Deny rules win; unmatched paths are denied. Destructive and account-bound verbs are\nnever reachable through MCP.\n\n---\n\n## 🧰 Tool catalog\n\n| Tool | Required input | Bounded result |\n| ----------------------------- | -------------- | ----------------------------------------------------------- |\n| `get_app_status` | — | Health verdict, counts, per-domain summaries |\n| `list_runs` | — | Recent executions filtered by domain, status, service, time |\n| `get_run` | `id` | One correlated execution with bounded spans and logs |\n| `get_recent_errors` | — | Recent errors grouped by service and domain |\n| `get_last_job_result` | — | The latest matching job outcome |\n| `analyze_service_performance` | `service` | Duration percentiles, throughput, error rate |\n| `analyze_db_bottlenecks` | — | Ranked database and KV operations |\n| `doctor` | — | Telemetry, Aspire, wiring, and plugin checks with fixes |\n| `search_docs` | `query` | Ranked public-document matches with snippets |\n| `list_docs` | — | Public-document summaries |\n| `get_doc` | `slug` | One public document, or one named section of it |\n| `list_commands` | — | Live CLI command descriptors from the injected catalog |\n| `execute_command` | `command` | Policy decision, exit status, bounded output tail |\n\n### Recipes\n\n- **Triage a failing app.** `doctor` first — it aggregates telemetry reachability, Aspire markers,\n project wiring, and plugin diagnostics into one verdict with suggested fixes, so a single call\n usually names the broken seam.\n- **Find why the last job failed.** `get_last_job_result` (optionally filtered by `jobName` or\n `service`) returns the outcome plus its execution `id`; feed that `id` to `get_run` for the spans\n and logs of just that execution.\n- **Investigate a slow service.** `analyze_service_performance` with `{ service: "checkout" }`\n returns p50/p95 duration, throughput, and error rate over the window — not the spans. Narrow the\n window with `sinceUnixMs`.\n- **Read the docs without burning context.** Funnel, never dump: `search_docs` to locate a slug,\n then `get_doc` with that slug and — when you only need one part — a `section` heading.\n- **Discover and run a safe command.** `list_commands` reflects the CLI\'s live command tree (so it\n never drifts from the installed binary); `execute_command` runs an allowlisted one, e.g.\n `{ command: "db", args: ["migrate"] }`. A denied path returns `command_denied` _before_ the\n executor is invoked.\n\n---\n\n## 📦 Public surface\n\nThe default entrypoint publishes the contracts, registry, and generic server composition; `./cli`\npublishes the executable composition that binds the real adapters.\n\n| Export | Entry | Role |\n| --------------------------------------------------------------------------- | ------- | ----------------------------------------------------------- |\n| `createToolRegistry()` | `.` | Immutable, enumerable definitions of the 13 tools |\n| `createMcpServer()` | `.` | Protocol runner: `initialize` / `tools/list` / `tools/call` |\n| `TOOL_NAMES`, `TOOL_INPUT_SCHEMAS`, `TOOL_OUTPUT_SCHEMAS`, `validateSchema` | `.` | Standard Schema contracts for every tool |\n| `DEFAULT_TRUNCATION_POLICY`, `truncateResult` | `.` | Server-side output bounds |\n| `DEFAULT_COMMAND_POLICY`, `decideCommand` | `.` | The default-deny allowlist and its decision function |\n| `TelemetryProbePort`, `DocsCorpusPort`, `ProjectDoctorPort`, … | `.` | Port contracts an embedder implements |\n| `EmbeddedDocsCorpus`, `FilesystemDocsCorpus`, process/command adapters | `.` | Default infrastructure adapters |\n| `createMcpCliServer()` | `./cli` | Full composition: telemetry, docs, doctor, CLI trigger |\n| `runMcpStdioServer()` | `./cli` | Newline-delimited JSON-RPC stdio loop |\n| `resolveDocsRoot()` | `./cli` | Explicit docs-root resolution from flag or environment |\n\nFull symbol reference: [`deno doc jsr:@netscript/mcp`](https://jsr.io/@netscript/mcp/doc).\n\n---\n\n## ⚙️ Configuration\n\n### Telemetry endpoint discovery\n\nTelemetry tools and `doctor` share one ordered policy:\n\n1. an explicit `endpoint` option (the CLI surfaces it as `--endpoint`);\n2. `NETSCRIPT_TELEMETRY_ENDPOINT`;\n3. `ASPIRE_DASHBOARD_PORT`, converted to a local HTTP endpoint with an HTTPS fallback;\n4. `http://localhost:18888`.\n\nOnly `http:` and `https:` endpoints are accepted. An unreachable endpoint yields a structured\nwarning or failure result rather than a crash.\n\n### Composition seams\n\n`createMcpCliServer(options)` / `runMcpStdioServer(options)` accept:\n\n| Option | Purpose |\n| ----------------- | -------------------------------------------------------------- |\n| `commandCatalog` | Supplies the live CLI command tree to `list_commands` |\n| `commandExecutor` | Runs an allowed command, returning structured process data |\n| `commandPolicy` | Replaces the ordered allow/deny prefixes for `execute_command` |\n| `projectDoctor` | Supplies typed project and plugin diagnostics |\n| `projectRoot` | Root for execution and doctor flows |\n| `docsRoot` | Overrides the package-shipped docs with a public Markdown root |\n| `endpoint` | Overrides telemetry endpoint discovery |\n\nWithout an override, `list_docs`, `search_docs`, and `get_doc` index the README shipped with the\ninstalled `@netscript/mcp` package under the `mcp` slug. Set `--docs-root ` (or\n`NETSCRIPT_DOCS_ROOT`) to use a project or site corpus instead. A configured path that does not\nexist returns `docs_corpus_not_found` with the missing path and `--docs-root` remediation; it never\nsilently reports an empty corpus.\n\nThe generic `createMcpServer(options)` takes the lower-level seams instead — `probe`, `environment`,\n`flows`, and `truncation`, the last of which overrides the 50-item / 2,000-character output bounds.\n\n### Command policy\n\n`DEFAULT_COMMAND_POLICY` **allows** `db init|generate|migrate|seed|status|introspect`, `generate`,\n`contract`, `service list`, `plugin install|list|sync|doctor`, and\n`ui:add|ui:init|ui:list|ui:update`. It **denies** `deploy`, `init`, `marketplace`, `db reset`,\n`plugin remove`, and `ui:remove`. Deny beats allow; anything unmatched is denied by default. Pass\nyour own `CommandPolicy` to tighten or (deliberately) widen it.\n\n### Data boundary and permissions\n\nThe server reads telemetry, project metadata, generated registries, and public documentation. It\nnever returns project source, environment-variable values, credentials, or secrets. Stdio is\nprocess-local; the only outbound traffic is the telemetry probe to the resolved endpoint.\n\nThe executable needs `--allow-env` (endpoint discovery), `--allow-net` (telemetry), `--allow-read`\n(project metadata and docs), and `--allow-run` only when `execute_command` is wired to a process\nexecutor. The `netscript` binary grants these at its edge; embedders should grant only what their\nchosen adapters use.\n\n---\n\n## 🔭 Observability\n\nThis package is a telemetry **consumer**, not a producer: it emits no spans of its own. It reads\nthrough `TelemetryQueryPort` from `@netscript/telemetry/query` and classifies what it reads using\nthe `netscript.*` attribute convention, mapping namespace prefixes onto the five semantic domains it\nexposes:\n\n| Domain | Classified from |\n| --------- | --------------------------------------- |\n| `worker` | `netscript.worker.*` |\n| `saga` | `netscript.saga.*` |\n| `trigger` | `netscript.trigger.*` |\n| `stream` | `netscript.stream.*`, `netscript.sse.*` |\n| `service` | `netscript.job.*` |\n\nExecution lookups (`get_run`, `get_last_job_result`) key off the first execution identifier a span\ncarries — `netscript.execution.id`, then the job, saga-instance, and trigger ids — and widen to the\nwhole trace from there. The attribute convention itself is owned by `@netscript/telemetry` — see\n[the telemetry convention](https://rickylabs.github.io/netscript/reference/telemetry/convention/).\n\n---\n\n## 🏗 Architecture\n\nArchetype 6 (CLI/Tooling) — a thin protocol router over flows. The package is layered\n`domain → application → infrastructure`: tool contracts, schemas, port interfaces, and pure policy\nin `src/domain/`; the tool flows and the protocol runner in `src/application/`; and the concrete\ntelemetry, docs, doctor, and process adapters in `src/infrastructure/`. Dependencies point inward —\nflows know ports, never adapters.\n\nThe transport is deliberately minimal — UTF-8 newline-delimited JSON-RPC implementing `initialize`,\n`tools/list`, and `tools/call` against protocol version `2025-11-25` — rather than the npm MCP SDK.\nThat keeps the published dependency graph and the lockfile stable, which matters because this\npackage ships inside the CLI binary.\n\nThe CLI surface (`netscript agent mcp`, `netscript agent init`) lives in `@netscript/cli`, not here;\nthis package stays a library engine. See\n[Agent tooling](https://rickylabs.github.io/netscript/capabilities/agent-tooling/) for the whole\ncombo.\n\n### Testing\n\nThere is no `./testing` entrypoint, and none is needed: every flow depends on a port, so a test\nsupplies a fake and asserts on the bounded result.\n\n```ts\nimport { assertEquals } from \'@std/assert\';\nimport { createMcpServer, type TelemetryProbePort } from \'@netscript/mcp\';\n\nconst probe: TelemetryProbePort = {\n probe: (endpoint: string) =>\n Promise.resolve({ reachable: true, status: 200, message: `reached ${endpoint}` }),\n};\n\nconst server = createMcpServer({ probe });\nconst response = await server.handle({ jsonrpc: \'2.0\', id: 1, method: \'tools/list\' });\nassertEquals((response?.result?.tools as unknown[]).length, 13);\n```\n\nAssert against `TOOL_INPUT_SCHEMAS` / `TOOL_OUTPUT_SCHEMAS` via `validateSchema`, so a flow that\ndrifts from its published contract fails locally rather than at the agent.\n\n---\n\n## 🧱 Compatibility\n\n| Runtime | Support |\n| ------------- | -------------------------------------------------------------------------- |\n| Deno 2.9+ | Full — both the `.` library surface and the `./cli` executable composition |\n| Node.js / Bun | Not supported — both entrypoints reach for `Deno.*` |\n\nThe `.` entrypoint is Deno-only, not just `./cli`: it re-exports the default adapters\n`FilesystemDocsCorpus` (`Deno.readDir`, `Deno.readTextFile`, `Deno.stat`) and `SpawnCommandExecutor`\n(`Deno.Command`), and `./cli` additionally uses `Deno.stdin` and `Deno.env`.\n\nThat constrains the **server**, not the **client**. An MCP host only has to spawn a process and\nspeak JSON-RPC over stdio, so any MCP-capable client — Claude Code, VS Code, and others — can\nconsume this server regardless of the runtime it is written in.\n\n---\n\n## 📖 Documentation\n\n- **Reference**:\n [rickylabs.github.io/netscript/reference/mcp/](https://rickylabs.github.io/netscript/reference/mcp/)\n- **Agent tooling**:\n [rickylabs.github.io/netscript/capabilities/agent-tooling/](https://rickylabs.github.io/netscript/capabilities/agent-tooling/)\n- **Telemetry convention**:\n [rickylabs.github.io/netscript/reference/telemetry/convention/](https://rickylabs.github.io/netscript/reference/telemetry/convention/)\n\n---\n\n## 📝 License\n\nApache-2.0 — see [LICENSE](https://github.com/rickylabs/netscript/blob/main/LICENSE). Published to\nJSR with cryptographically verified provenance.\n'; diff --git a/plugins/ai/src/constants.ts b/plugins/ai/src/constants.ts index 01f53c79c..fbd6a3126 100644 --- a/plugins/ai/src/constants.ts +++ b/plugins/ai/src/constants.ts @@ -3,7 +3,7 @@ * @module */ -import denoJson from '../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from './package-metadata.generated.ts'; /** Canonical plugin id used across the manifest, connector, and scaffolder. */ export const AI_PLUGIN_ID = '@netscript/plugin-ai' as const; @@ -12,7 +12,7 @@ export const AI_PLUGIN_ID = '@netscript/plugin-ai' as const; export const AI_WORKSPACE_NAME = 'ai' as const; /** Plugin package version, single-sourced from the package `deno.json`. */ -export const AI_PLUGIN_VERSION: string = denoJson.version; +export const AI_PLUGIN_VERSION: string = PLUGIN_PACKAGE_VERSION; /** Literal type of the AI plugin id. */ export type AiPluginId = typeof AI_PLUGIN_ID; diff --git a/plugins/ai/src/package-metadata.generated.ts b/plugins/ai/src/package-metadata.generated.ts new file mode 100644 index 000000000..68aaef600 --- /dev/null +++ b/plugins/ai/src/package-metadata.generated.ts @@ -0,0 +1,5 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = '0.0.1-beta.10'; diff --git a/plugins/auth/src/constants.ts b/plugins/auth/src/constants.ts index 52118ad9a..5c1caae47 100644 --- a/plugins/auth/src/constants.ts +++ b/plugins/auth/src/constants.ts @@ -1,10 +1,10 @@ -import denoJson from '../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from './package-metadata.generated.ts'; /** Stable plugin identifier used by manifests and runtime ownership checks. */ export const AUTH_PLUGIN_ID = 'auth' as const; /** Plugin manifest version advertised to the NetScript host, single-sourced from `deno.json`. */ -export const AUTH_PLUGIN_VERSION: string = denoJson.version; +export const AUTH_PLUGIN_VERSION: string = PLUGIN_PACKAGE_VERSION; /** Service contribution name for the auth API process. */ export const AUTH_API_SERVICE_NAME = 'auth-api' as const; diff --git a/plugins/auth/src/package-metadata.generated.ts b/plugins/auth/src/package-metadata.generated.ts new file mode 100644 index 000000000..68aaef600 --- /dev/null +++ b/plugins/auth/src/package-metadata.generated.ts @@ -0,0 +1,5 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = '0.0.1-beta.10'; diff --git a/plugins/auth/verify-plugin.ts b/plugins/auth/verify-plugin.ts index 3bc7de7dd..13d32ff8a 100644 --- a/plugins/auth/verify-plugin.ts +++ b/plugins/auth/verify-plugin.ts @@ -10,7 +10,7 @@ import { verifyPlugin, } from '@netscript/plugin'; import { authPlugin } from './mod.ts'; -import denoJson from './deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from './src/package-metadata.generated.ts'; export type { InspectionReport } from '@netscript/plugin'; @@ -18,7 +18,7 @@ export type { InspectionReport } from '@netscript/plugin'; export function verifyAuthPlugin(): PluginVerificationResult { return verifyPlugin(authPlugin, { name: '@netscript/plugin-auth', - version: denoJson.version, + version: PLUGIN_PACKAGE_VERSION, services: [{ name: 'auth-api', message: 'expected an auth-api service contribution' }], contractVersions: [{ version: 'v1', diff --git a/plugins/sagas/src/package-metadata.generated.ts b/plugins/sagas/src/package-metadata.generated.ts new file mode 100644 index 000000000..68aaef600 --- /dev/null +++ b/plugins/sagas/src/package-metadata.generated.ts @@ -0,0 +1,5 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = '0.0.1-beta.10'; diff --git a/plugins/sagas/src/public/mod.ts b/plugins/sagas/src/public/mod.ts index 5c4fd2c8a..6c5b84fb7 100644 --- a/plugins/sagas/src/public/mod.ts +++ b/plugins/sagas/src/public/mod.ts @@ -8,10 +8,10 @@ import { definePlugin, type PluginManifest } from '@netscript/plugin'; import { streamsPlugin } from '@netscript/plugin-streams'; import { workersPlugin } from '@netscript/plugin-workers'; import { SAGAS_API_DEFAULT_PORT, SAGAS_API_SERVICE_NAME, SAGAS_PLUGIN_ID } from '../constants.ts'; -import denoJson from '../../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from '../package-metadata.generated.ts'; /** Plugin package version, single-sourced from the package `deno.json`. */ -const VERSION: string = denoJson.version; +const VERSION: string = PLUGIN_PACKAGE_VERSION; const SAGAS_SERVICE_PERMISSIONS = [ '--unstable-kv', diff --git a/plugins/sagas/verify-plugin.ts b/plugins/sagas/verify-plugin.ts index b652b19c6..b254038b2 100644 --- a/plugins/sagas/verify-plugin.ts +++ b/plugins/sagas/verify-plugin.ts @@ -10,7 +10,7 @@ import { verifyPlugin, } from '@netscript/plugin'; import { sagasPlugin } from './mod.ts'; -import denoJson from './deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from './src/package-metadata.generated.ts'; export type { InspectionReport } from '@netscript/plugin'; @@ -18,7 +18,7 @@ export type { InspectionReport } from '@netscript/plugin'; export function verifySagasPlugin(): PluginVerificationResult { return verifyPlugin(sagasPlugin, { name: '@netscript/plugin-sagas', - version: denoJson.version, + version: PLUGIN_PACKAGE_VERSION, dependencies: [ { alias: 'workers', message: 'expected workers plugin dependency' }, { alias: 'streams', message: 'expected streams plugin dependency' }, diff --git a/plugins/streams/services/src/main.ts b/plugins/streams/services/src/main.ts index 9251ef56a..d2827bae0 100644 --- a/plugins/streams/services/src/main.ts +++ b/plugins/streams/services/src/main.ts @@ -22,11 +22,11 @@ import { getAvailablePort } from '@std/net'; import { healthChecks } from '@netscript/service'; import { createPluginService } from '@netscript/plugin/service'; import { DurableStreamTestServer } from '@durable-streams/server'; -import denoJson from '../../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from '../../src/package-metadata.generated.ts'; import { createStreamsProxyHandler } from './proxy.ts'; /** Connector version, single-sourced from the streams package `deno.json`. */ -const VERSION: string = denoJson.version; +const VERSION: string = PLUGIN_PACKAGE_VERSION; const port = parseInt( Deno.env.get('PORT') ?? Deno.env.get('STREAMS_PORT') ?? '4437', diff --git a/plugins/streams/src/package-metadata.generated.ts b/plugins/streams/src/package-metadata.generated.ts new file mode 100644 index 000000000..68aaef600 --- /dev/null +++ b/plugins/streams/src/package-metadata.generated.ts @@ -0,0 +1,5 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = '0.0.1-beta.10'; diff --git a/plugins/streams/src/public/mod.ts b/plugins/streams/src/public/mod.ts index 9012735dd..c7936ee3c 100644 --- a/plugins/streams/src/public/mod.ts +++ b/plugins/streams/src/public/mod.ts @@ -11,10 +11,10 @@ import { StreamUnsupportedOperationError, unsupportedStreamOperation, } from './stream-api.ts'; -import denoJson from '../../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from '../package-metadata.generated.ts'; /** Plugin package version, single-sourced from the package `deno.json`. */ -const VERSION: string = denoJson.version; +const VERSION: string = PLUGIN_PACKAGE_VERSION; const STREAMS_SERVICE_PERMISSIONS = [ '--allow-net', diff --git a/plugins/triggers/services/src/main.ts b/plugins/triggers/services/src/main.ts index 87004ee0d..3dc941d23 100644 --- a/plugins/triggers/services/src/main.ts +++ b/plugins/triggers/services/src/main.ts @@ -58,7 +58,7 @@ import { type WebhookTestDelivery, } from '@netscript/plugin-triggers-core/runtime'; import { TRIGGERS_API_DEFAULT_PORT, TRIGGERS_API_SERVICE_NAME } from '../../src/constants.ts'; -import denoJson from '../../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from '../../src/package-metadata.generated.ts'; import type { KvStore } from '@netscript/kv'; import { loadProjectTriggerDefinitions } from '../../src/runtime/project-trigger-registry.ts'; import { createRuntimeTriggerProcessor } from '../../src/runtime/trigger-runtime-processor.ts'; @@ -133,7 +133,7 @@ export type { export type { TriggerServiceContext } from './routers/v1-types.ts'; /** Connector version, single-sourced from the triggers package `deno.json`. */ -const VERSION: string = denoJson.version; +const VERSION: string = PLUGIN_PACKAGE_VERSION; /** Legacy event-list path preserved for scaffold runtime smoke gates. */ const LEGACY_EVENTS_PATH = '/api/v1/events' as const; diff --git a/plugins/triggers/src/constants.ts b/plugins/triggers/src/constants.ts index e3a9d1c8b..911064841 100644 --- a/plugins/triggers/src/constants.ts +++ b/plugins/triggers/src/constants.ts @@ -1,10 +1,10 @@ -import denoJson from '../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from './package-metadata.generated.ts'; /** Stable plugin identifier for NetScript triggers. */ export const TRIGGERS_PLUGIN_ID = 'triggers' as const; /** Plugin package version, single-sourced from the package `deno.json`. */ -export const TRIGGERS_PLUGIN_VERSION: string = denoJson.version; +export const TRIGGERS_PLUGIN_VERSION: string = PLUGIN_PACKAGE_VERSION; /** Default HTTP service name for trigger ingress and management APIs. */ export const TRIGGERS_API_SERVICE_NAME = 'triggers-api' as const; diff --git a/plugins/triggers/src/package-metadata.generated.ts b/plugins/triggers/src/package-metadata.generated.ts new file mode 100644 index 000000000..68aaef600 --- /dev/null +++ b/plugins/triggers/src/package-metadata.generated.ts @@ -0,0 +1,5 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = '0.0.1-beta.10'; diff --git a/plugins/workers/services/src/init.ts b/plugins/workers/services/src/init.ts index 1983bb9e9..5707cbc45 100644 --- a/plugins/workers/services/src/init.ts +++ b/plugins/workers/services/src/init.ts @@ -1,11 +1,11 @@ import { emitJobToStream } from '../../streams/server.ts'; import type { WorkersServiceRuntime } from './routers/router-context.ts'; -import workersPackageJson from '../../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from '../../src/package-metadata.generated.ts'; export const WORKERS_PLUGIN_HEALTH_CHECK_JOB_ID = 'workers-plugin-health-check'; export const WORKERS_PLUGIN_HEALTH_CHECK_ENTRYPOINT = './jobs/health-check.ts'; export const WORKERS_PLUGIN_HEALTH_CHECK_SOURCE_URL: string = - `jsr:@netscript/plugin-workers@${workersPackageJson.version}/jobs/health-check.ts`; + `jsr:@netscript/plugin-workers@${PLUGIN_PACKAGE_VERSION}/jobs/health-check.ts`; /** * Register jobs defined in the workers plugin. diff --git a/plugins/workers/src/package-metadata.generated.ts b/plugins/workers/src/package-metadata.generated.ts new file mode 100644 index 000000000..68aaef600 --- /dev/null +++ b/plugins/workers/src/package-metadata.generated.ts @@ -0,0 +1,5 @@ +// @generated by .llm/tools/generate-publish-assets.ts +// Do not edit by hand. Run `deno task gen:publish-assets`. + +/** Version of the published plugin package. */ +export const PLUGIN_PACKAGE_VERSION: string = '0.0.1-beta.10'; diff --git a/plugins/workers/src/public/mod.ts b/plugins/workers/src/public/mod.ts index 66be8b295..c6e75162e 100644 --- a/plugins/workers/src/public/mod.ts +++ b/plugins/workers/src/public/mod.ts @@ -13,7 +13,7 @@ import { definePlugin, type PluginManifest } from '@netscript/plugin'; import type { StreamTopicContribution } from '@netscript/plugin'; -import denoJson from '../../deno.json' with { type: 'json' }; +import { PLUGIN_PACKAGE_VERSION } from '../package-metadata.generated.ts'; import { PublicJobDefinitionSchema, PublicTaskDefinitionSchema, @@ -49,7 +49,7 @@ function toTopicContribution( } /** Plugin package version, single-sourced from the package `deno.json`. */ -const VERSION: string = denoJson.version; +const VERSION: string = PLUGIN_PACKAGE_VERSION; const workersManifest = definePlugin('@netscript/plugin-workers', VERSION) .withDisplayName('Background Workers') From ad0e5d549c68699f502fccfd5cf5b33e99743384 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:34:11 +0200 Subject: [PATCH 04/11] fix(release): reject import attributes before JSR --- .agents/skills/jsr-audit/SKILL.md | 36 +++---- .agents/skills/netscript-release/SKILL.md | 39 ++++---- .claude/skills/jsr-audit/SKILL.md | 36 +++---- .claude/skills/netscript-release/SKILL.md | 39 ++++---- .../context-pack.md | 13 ++- .../worklog.md | 17 +++- .llm/tools/release/preflight-text-imports.ts | 98 ++++++++++++++++++- .../release/preflight-text-imports_test.ts | 28 +++++- .../fixtures/negative-url-composition.ts | 2 +- 9 files changed, 224 insertions(+), 84 deletions(-) diff --git a/.agents/skills/jsr-audit/SKILL.md b/.agents/skills/jsr-audit/SKILL.md index 00079c7da..84efe4dae 100644 --- a/.agents/skills/jsr-audit/SKILL.md +++ b/.agents/skills/jsr-audit/SKILL.md @@ -182,9 +182,9 @@ This reveals: **The dry-run is a static gate, not proof of a working publish.** It never loads the module over the real `https:`/`jsr:` graph, so it cannot catch the runtime-only publish failures listed in -[JSR publish gotchas](#jsr-publish-gotchas-netscript-grounded) — a green `--dry-run` is necessary but -not sufficient. The authoritative post-publish check is the production CLI e2e (`e2e-cli-prod`), which -installs and runs the published package over the remote graph. +[JSR publish gotchas](#jsr-publish-gotchas-netscript-grounded) — a green `--dry-run` is necessary +but not sufficient. The authoritative post-publish check is the production CLI e2e (`e2e-cli-prod`), +which installs and runs the published package over the remote graph. ### Step 5: Audit the File List @@ -561,18 +561,20 @@ here as the canonical home; the `deno doc --lint` full-export-surface bar is cov **`deno publish --dry-run` is NOT publish-equivalent.** Every trap below passes a clean dry-run and only fails at real publish/install time, because the dry-run analyzes the local source graph rather than loading the module over the remote `https:`/`jsr:` graph a consumer resolves. Treat a green -dry-run as a static pre-check, never as the release verdict — the verdict is a real-publish preflight -plus `e2e-cli-prod` against the published package. - -- **Embed assets via import attributes, never `readTextFile`/`fromFileUrl`.** A published module runs - over an `https:`/`jsr:` graph where there is no filesystem, so `Deno.readTextFile(...)` / - `fromFileUrl(new URL(..., import.meta.url))` crash at runtime. Bundle text/JSON assets with import - attributes instead (`import data from "./x.json" with { type: "json" }`, `with { type: "text" }`). - Guard: `deno lint` + the production CLI e2e (`e2e-cli-prod`) exercise the real remote graph. -- **Top-level `import.meta`/`fromFileUrl` crashes over https.** Same root cause as above but even for - path resolution: a top-level `fromFileUrl(new URL("...", import.meta.url))` throws when the module - is imported over `https:`/`jsr:`. Make it lazy (resolve inside the function that needs it) and - guard on `import.meta.url`'s protocol before touching the filesystem. +dry-run as a static pre-check, never as the release verdict — the verdict is a real-publish +preflight plus `e2e-cli-prod` against the published package. + +- **Embed assets as generated TypeScript constants, never import attributes or runtime file reads.** + The JSR registry can reject `with { type: "text" }` or `with { type: "json" }` while building the + module graph even when local `deno publish --dry-run` passes. A published module also runs over an + `https:`/`jsr:` graph where `Deno.readTextFile(...)` / + `fromFileUrl(new URL(..., import.meta.url))` have no package filesystem. Generate checked-in + `*.generated.ts` constants and protect them with a regeneration-plus-diff freshness gate. Guard: + `release:preflight` + `e2e-cli-prod`. +- **Top-level `import.meta`/`fromFileUrl` crashes over https.** Same root cause as above but even + for path resolution: a top-level `fromFileUrl(new URL("...", import.meta.url))` throws when the + module is imported over `https:`/`jsr:`. Make it lazy (resolve inside the function that needs it) + and guard on `import.meta.url`'s protocol before touching the filesystem. - **Self-referential subpath import trap (#188).** A package that imports its OWN bare specifier (e.g. `@netscript/x/sub` from inside `@netscript/x`) resolves at publish time against the LATEST PUBLISHED version on JSR, not the in-repo source — so the publish graph fails or silently binds an @@ -584,8 +586,8 @@ plus `e2e-cli-prod` against the published package. a PATCH to the package config; otherwise ensure the `@module` doc carries the intended landing content. - **Prerelease-only packages show `latest=null`.** A package with only prerelease versions has JSR - `latest = null`, which renders a blank version badge/README on the package page. This self-heals at - the first non-prerelease (stable) publish; no config fix is needed. + `latest = null`, which renders a blank version badge/README on the package page. This self-heals + at the first non-prerelease (stable) publish; no config fix is needed. ## Known Limitations (2024-2025) diff --git a/.agents/skills/netscript-release/SKILL.md b/.agents/skills/netscript-release/SKILL.md index 0d5a58f8f..e44e21a41 100644 --- a/.agents/skills/netscript-release/SKILL.md +++ b/.agents/skills/netscript-release/SKILL.md @@ -13,8 +13,9 @@ semantics and `netscript-pr` for branch, PR, and comment mechanics. - Work from a clean release-prep branch. - Confirm `deno task release:preflight` is green before cutting. It enforces the JSR-safe bundled - asset rule: publishable source must use text imports or generated string constants, not - `Deno.readTextFile(new URL(..., import.meta.url))` or an identifier assigned from that URL. + asset rule: publishable source must use generated TypeScript string constants. Import attributes + (`with { type: ... }`) and `Deno.readTextFile(new URL(..., import.meta.url))`-style runtime reads + are rejected because the JSR registry can reject them even when local dry-run passes. - Do not delete `deno.lock`, delete caches, or run `deno cache --reload`. - Do not publish from a local machine. Publishing stays in GitHub Actions through OIDC. - Use `gh ... --body-file` for release PR creation and comments. @@ -39,8 +40,9 @@ For rehearsal: deno task release:cut -- --dry-run ``` -Dry-run performs the bump, residue check, and gates, then skips branch creation, commit, push, and PR. -Run it in a disposable copy if you do not want the working tree version-bumped after a failed gate. +Dry-run performs the bump, residue check, and gates, then skips branch creation, commit, push, and +PR. Run it in a disposable copy if you do not want the working tree version-bumped after a failed +gate. ## What The Command Proves @@ -50,7 +52,7 @@ Run it in a disposable copy if you do not want the working tree version-bumped a 2. Workspace bump sets the root version, every package/plugin `deno.json`, nested workspace `deno.json` files, and `deno.lock` `@netscript/*` ranges to the new version. 3. Residue check aborts if the old version remains in JSON files or `deno.lock`. -4. `release:preflight` blocks JSR-unsafe import-meta-relative runtime reads. +4. `release:preflight` blocks JSR-unsafe import attributes and import-meta-relative runtime reads. 5. `publish:dry-run` proves the package publish surface builds before the real publish. 6. `deno ci --prod` proves the production dependency graph installs from the locked graph. 7. Non-dry-run creates `release/cut-`, stages only bumped files, commits @@ -66,17 +68,17 @@ After the release PR merges: deno task release:publish -- v --notes-file ``` - This creates `v`, which is what triggers `publish.yml`. There is no JSR publish - without a GitHub Release, so **never hand-run `gh release create`** — it forgets the intro and - leaves the `prerelease` flag set (which stranded the Latest badge on alpha.16 through alpha.19). + This creates `v`, which is what triggers `publish.yml`. There is no JSR publish without + a GitHub Release, so **never hand-run `gh release create`** — it forgets the intro and leaves the + `prerelease` flag set (which stranded the Latest badge on alpha.16 through alpha.19). - **The introduction summary is written by hand** — the prose describing what the release ships. Pass it via `--notes-file ` or `--message ""`; the tool refuses to run without one. This is the single deliberately-manual step. - **Everything else is generated:** the "What's Changed" merged-PR list, the "Closed Issues" list since the previous release, and the `prerelease=false` + `make_latest` flags so the newest release shows as **Latest**. The JSR package links are appended later by `publish.yml`. - - Rehearse with `--dry-run` to print the composed body before creating. Use `--prerelease` - (with `--no-latest`) only for a genuine prerelease that must not become Latest. + - Rehearse with `--dry-run` to print the composed body before creating. Use `--prerelease` (with + `--no-latest`) only for a genuine prerelease that must not become Latest. 2. `publish.yml` resolves the release version, runs the release preflight, runs publish dry-run, and publishes every `@netscript/*` workspace member to JSR through OIDC. 3. On successful publish, `publish.yml` writes `version.txt` and uploads it as @@ -103,18 +105,19 @@ prerelease and repeat both gates. The release is not complete until the pair is - #122: one command prevents manual root version, member version, and lockfile drift. - #123: `workflow_run` plus the run-id artifact removes the race where prod E2E installs before JSR has the just-published CLI version. -- #133: text-import preflight catches the `import.meta.url` asset-read defect class that dry-run can - miss and real publish can reject. +- #133: asset preflight catches import attributes and `import.meta.url` asset-read defects that + dry-run can miss and real publish can reject. - #146: `deno ci --prod` is already lockfile-frozen in Deno 2.9; an explicit extra flag is rejected. ## Rollback And Retry -- If `release:cut` fails before branch creation, fix the reported gate and rerun. Restore any dry-run - version bump with normal git checkout of the bumped files if you ran it in the live checkout. -- If the release PR is wrong before merge, push a follow-up commit to the release branch or close the - PR and cut again. -- If GitHub Release publish fails before any JSR package publishes, fix the workflow or gate and rerun - the release workflow. +- If `release:cut` fails before branch creation, fix the reported gate and rerun. Restore any + dry-run version bump with normal git checkout of the bumped files if you ran it in the live + checkout. +- If the release PR is wrong before merge, push a follow-up commit to the release branch or close + the PR and cut again. +- If GitHub Release publish fails before any JSR package publishes, fix the workflow or gate and + rerun the release workflow. - If publish partially succeeds, do not delete the tag or lockfile. Deno 2.9 skips already-published members on retry; rerun after fixing the failing member or gate. - If `e2e-cli-prod` fails after publish, keep the release record intact, investigate against the diff --git a/.claude/skills/jsr-audit/SKILL.md b/.claude/skills/jsr-audit/SKILL.md index 00079c7da..84efe4dae 100644 --- a/.claude/skills/jsr-audit/SKILL.md +++ b/.claude/skills/jsr-audit/SKILL.md @@ -182,9 +182,9 @@ This reveals: **The dry-run is a static gate, not proof of a working publish.** It never loads the module over the real `https:`/`jsr:` graph, so it cannot catch the runtime-only publish failures listed in -[JSR publish gotchas](#jsr-publish-gotchas-netscript-grounded) — a green `--dry-run` is necessary but -not sufficient. The authoritative post-publish check is the production CLI e2e (`e2e-cli-prod`), which -installs and runs the published package over the remote graph. +[JSR publish gotchas](#jsr-publish-gotchas-netscript-grounded) — a green `--dry-run` is necessary +but not sufficient. The authoritative post-publish check is the production CLI e2e (`e2e-cli-prod`), +which installs and runs the published package over the remote graph. ### Step 5: Audit the File List @@ -561,18 +561,20 @@ here as the canonical home; the `deno doc --lint` full-export-surface bar is cov **`deno publish --dry-run` is NOT publish-equivalent.** Every trap below passes a clean dry-run and only fails at real publish/install time, because the dry-run analyzes the local source graph rather than loading the module over the remote `https:`/`jsr:` graph a consumer resolves. Treat a green -dry-run as a static pre-check, never as the release verdict — the verdict is a real-publish preflight -plus `e2e-cli-prod` against the published package. - -- **Embed assets via import attributes, never `readTextFile`/`fromFileUrl`.** A published module runs - over an `https:`/`jsr:` graph where there is no filesystem, so `Deno.readTextFile(...)` / - `fromFileUrl(new URL(..., import.meta.url))` crash at runtime. Bundle text/JSON assets with import - attributes instead (`import data from "./x.json" with { type: "json" }`, `with { type: "text" }`). - Guard: `deno lint` + the production CLI e2e (`e2e-cli-prod`) exercise the real remote graph. -- **Top-level `import.meta`/`fromFileUrl` crashes over https.** Same root cause as above but even for - path resolution: a top-level `fromFileUrl(new URL("...", import.meta.url))` throws when the module - is imported over `https:`/`jsr:`. Make it lazy (resolve inside the function that needs it) and - guard on `import.meta.url`'s protocol before touching the filesystem. +dry-run as a static pre-check, never as the release verdict — the verdict is a real-publish +preflight plus `e2e-cli-prod` against the published package. + +- **Embed assets as generated TypeScript constants, never import attributes or runtime file reads.** + The JSR registry can reject `with { type: "text" }` or `with { type: "json" }` while building the + module graph even when local `deno publish --dry-run` passes. A published module also runs over an + `https:`/`jsr:` graph where `Deno.readTextFile(...)` / + `fromFileUrl(new URL(..., import.meta.url))` have no package filesystem. Generate checked-in + `*.generated.ts` constants and protect them with a regeneration-plus-diff freshness gate. Guard: + `release:preflight` + `e2e-cli-prod`. +- **Top-level `import.meta`/`fromFileUrl` crashes over https.** Same root cause as above but even + for path resolution: a top-level `fromFileUrl(new URL("...", import.meta.url))` throws when the + module is imported over `https:`/`jsr:`. Make it lazy (resolve inside the function that needs it) + and guard on `import.meta.url`'s protocol before touching the filesystem. - **Self-referential subpath import trap (#188).** A package that imports its OWN bare specifier (e.g. `@netscript/x/sub` from inside `@netscript/x`) resolves at publish time against the LATEST PUBLISHED version on JSR, not the in-repo source — so the publish graph fails or silently binds an @@ -584,8 +586,8 @@ plus `e2e-cli-prod` against the published package. a PATCH to the package config; otherwise ensure the `@module` doc carries the intended landing content. - **Prerelease-only packages show `latest=null`.** A package with only prerelease versions has JSR - `latest = null`, which renders a blank version badge/README on the package page. This self-heals at - the first non-prerelease (stable) publish; no config fix is needed. + `latest = null`, which renders a blank version badge/README on the package page. This self-heals + at the first non-prerelease (stable) publish; no config fix is needed. ## Known Limitations (2024-2025) diff --git a/.claude/skills/netscript-release/SKILL.md b/.claude/skills/netscript-release/SKILL.md index 0d5a58f8f..e44e21a41 100644 --- a/.claude/skills/netscript-release/SKILL.md +++ b/.claude/skills/netscript-release/SKILL.md @@ -13,8 +13,9 @@ semantics and `netscript-pr` for branch, PR, and comment mechanics. - Work from a clean release-prep branch. - Confirm `deno task release:preflight` is green before cutting. It enforces the JSR-safe bundled - asset rule: publishable source must use text imports or generated string constants, not - `Deno.readTextFile(new URL(..., import.meta.url))` or an identifier assigned from that URL. + asset rule: publishable source must use generated TypeScript string constants. Import attributes + (`with { type: ... }`) and `Deno.readTextFile(new URL(..., import.meta.url))`-style runtime reads + are rejected because the JSR registry can reject them even when local dry-run passes. - Do not delete `deno.lock`, delete caches, or run `deno cache --reload`. - Do not publish from a local machine. Publishing stays in GitHub Actions through OIDC. - Use `gh ... --body-file` for release PR creation and comments. @@ -39,8 +40,9 @@ For rehearsal: deno task release:cut -- --dry-run ``` -Dry-run performs the bump, residue check, and gates, then skips branch creation, commit, push, and PR. -Run it in a disposable copy if you do not want the working tree version-bumped after a failed gate. +Dry-run performs the bump, residue check, and gates, then skips branch creation, commit, push, and +PR. Run it in a disposable copy if you do not want the working tree version-bumped after a failed +gate. ## What The Command Proves @@ -50,7 +52,7 @@ Run it in a disposable copy if you do not want the working tree version-bumped a 2. Workspace bump sets the root version, every package/plugin `deno.json`, nested workspace `deno.json` files, and `deno.lock` `@netscript/*` ranges to the new version. 3. Residue check aborts if the old version remains in JSON files or `deno.lock`. -4. `release:preflight` blocks JSR-unsafe import-meta-relative runtime reads. +4. `release:preflight` blocks JSR-unsafe import attributes and import-meta-relative runtime reads. 5. `publish:dry-run` proves the package publish surface builds before the real publish. 6. `deno ci --prod` proves the production dependency graph installs from the locked graph. 7. Non-dry-run creates `release/cut-`, stages only bumped files, commits @@ -66,17 +68,17 @@ After the release PR merges: deno task release:publish -- v --notes-file ``` - This creates `v`, which is what triggers `publish.yml`. There is no JSR publish - without a GitHub Release, so **never hand-run `gh release create`** — it forgets the intro and - leaves the `prerelease` flag set (which stranded the Latest badge on alpha.16 through alpha.19). + This creates `v`, which is what triggers `publish.yml`. There is no JSR publish without + a GitHub Release, so **never hand-run `gh release create`** — it forgets the intro and leaves the + `prerelease` flag set (which stranded the Latest badge on alpha.16 through alpha.19). - **The introduction summary is written by hand** — the prose describing what the release ships. Pass it via `--notes-file ` or `--message ""`; the tool refuses to run without one. This is the single deliberately-manual step. - **Everything else is generated:** the "What's Changed" merged-PR list, the "Closed Issues" list since the previous release, and the `prerelease=false` + `make_latest` flags so the newest release shows as **Latest**. The JSR package links are appended later by `publish.yml`. - - Rehearse with `--dry-run` to print the composed body before creating. Use `--prerelease` - (with `--no-latest`) only for a genuine prerelease that must not become Latest. + - Rehearse with `--dry-run` to print the composed body before creating. Use `--prerelease` (with + `--no-latest`) only for a genuine prerelease that must not become Latest. 2. `publish.yml` resolves the release version, runs the release preflight, runs publish dry-run, and publishes every `@netscript/*` workspace member to JSR through OIDC. 3. On successful publish, `publish.yml` writes `version.txt` and uploads it as @@ -103,18 +105,19 @@ prerelease and repeat both gates. The release is not complete until the pair is - #122: one command prevents manual root version, member version, and lockfile drift. - #123: `workflow_run` plus the run-id artifact removes the race where prod E2E installs before JSR has the just-published CLI version. -- #133: text-import preflight catches the `import.meta.url` asset-read defect class that dry-run can - miss and real publish can reject. +- #133: asset preflight catches import attributes and `import.meta.url` asset-read defects that + dry-run can miss and real publish can reject. - #146: `deno ci --prod` is already lockfile-frozen in Deno 2.9; an explicit extra flag is rejected. ## Rollback And Retry -- If `release:cut` fails before branch creation, fix the reported gate and rerun. Restore any dry-run - version bump with normal git checkout of the bumped files if you ran it in the live checkout. -- If the release PR is wrong before merge, push a follow-up commit to the release branch or close the - PR and cut again. -- If GitHub Release publish fails before any JSR package publishes, fix the workflow or gate and rerun - the release workflow. +- If `release:cut` fails before branch creation, fix the reported gate and rerun. Restore any + dry-run version bump with normal git checkout of the bumped files if you ran it in the live + checkout. +- If the release PR is wrong before merge, push a follow-up commit to the release branch or close + the PR and cut again. +- If GitHub Release publish fails before any JSR package publishes, fix the workflow or gate and + rerun the release workflow. - If publish partially succeeds, do not delete the tag or lockfile. Deno 2.9 skips already-published members on retry; rerun after fixing the failing member or gate. - If `e2e-cli-prod` fails after publish, keep the release record intact, investigate against the diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md index 90f030df7..ce96959d1 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md @@ -12,7 +12,7 @@ ## Current State -Separate-session PLAN-EVAL passed. Slice 2 is implemented and reviewed: generated constants now carry MCP README, CLI schema/version, and affected plugin versions; publishable consumers no longer use import attributes. +Separate-session PLAN-EVAL passed. Slices 2 and 3 are implemented and reviewed: generated constants replace publishable attributes, and release preflight plus mirrored release/JSR guidance now enforce the registry-safe rule. ## Completed @@ -21,16 +21,17 @@ Separate-session PLAN-EVAL passed. Slice 2 is implemented and reviewed: generate - PLAN-EVAL passed in local Qwen session `f03ae1dd-da69-406a-b725-f3bf391255a8`. - Generated publish assets, all affected consumers, and the regeneration/freshness tasks are implemented. - MCP (45 tests), CLI, and six plugin checks pass; freshness is witnessed green and red; MCP publish dry-run and changed-file quality scan pass. +- Release scanner tests pass; full preflight is green and an explicit seeded attribute is witnessed red; skill mirror sync passes. ## In Progress -- Slice 3 release-preflight and release-guidance correction. +- Slice 4 final evidence and separate IMPL-EVAL. ## Next Steps -1. Commit, push, and comment slice 2. -2. Finish and review the release-preflight/guidance slice. -3. Run full fixed-tree and seeded-red release evidence. +1. Commit, push, and comment slice 3. +2. Re-run final required gates on the committed tree. +3. Dispatch separate-session IMPL-EVAL and address any findings. ## Key Decisions @@ -46,6 +47,8 @@ Separate-session PLAN-EVAL passed. Slice 2 is implemented and reviewed: generate | `.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/` | new | Harness planning artifacts only. | | `.llm/tools/generate-publish-assets.ts`, `deno.json` | new/changed | Deterministic generation and freshness task. | | `packages/mcp`, `packages/cli`, `plugins/{ai,auth,sagas,streams,triggers,workers}` | changed | Generated assets and registry-safe consumers. | +| `.llm/tools/release/preflight-text-imports.ts` + tests | changed | Publish-rule-aware import-attribute rejection and negative proof. | +| `.agents/skills`, `.claude/skills` | changed | Corrected release/JSR registry guidance, synchronized mirrors. | ## Gates diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md index d51f757d3..1b173f9be 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -58,6 +58,11 @@ Update the source README/schema/package metadata, run the publish-assets generat | 2026-07-17 | 2 | negative proof | Seeded stale plugin metadata made `check:publish-assets` exit 1; regeneration restored a green exit 0. | | 2026-07-17 | 2 | review | Supervisor reviewed generated source fidelity, consumer import paths, publish include coverage, and excluded test/verifier attributes; no scope gap found. | | 2026-07-17 | 2 | reconcile | #808 is closed and remains a non-closing `Refs #808`; PR #810 is draft with `status:impl`; no new reviewer comments required adjustment. | +| 2026-07-17 | 3 | implement | Release preflight now rejects `with { type: ... }` syntax in publish-rule-filtered source and recommends generated constants for import-meta reads. | +| 2026-07-17 | 3 | negative proof | Explicit seeded JSON attribute made the preflight CLI exit 1 with file/line evidence; the fixed full tree exits 0 with zero findings. | +| 2026-07-17 | 3 | guidance | Corrected release and JSR-audit guidance in `.agents` and `.claude`; mirror sync and hook lock check pass. | +| 2026-07-17 | 3 | review | Supervisor reviewed lexical stripping against strings/comments/templates, line attribution, publish-rule reuse, failure output, and mirror parity; no suppression or false-green path introduced. | +| 2026-07-17 | 3 | reconcile | PR #810 remains draft and correctly references closed #808 without auto-close; no new comments or issue state require scope changes. | ## Decisions @@ -89,6 +94,16 @@ Update the source README/schema/package metadata, run the publish-assets generat | MCP publish dry-run | PASS | `@netscript/mcp@0.0.1-beta.10` dry-run complete; generated README asset included | | architecture | PASS | `deno task arch:check` exit 0; baseline warnings only, no failures | +### Slice 3 — release preflight and guidance + +| Gate | Result | Evidence | +| --- | --- | --- | +| scanner tests | PASS | 7 passed, 0 failed; includes syntax seed and inert-region coverage | +| fixed-tree preflight | PASS | text reads, import attributes, file URL conversions, and self-imports all report zero findings | +| preflight negative proof | PASS | `.llm/tmp/seed-import-attribute.ts:1` produced `import-attributes — FAIL`, exit 1 | +| release/JSR skill sync | PASS | `deno task agentic:check-claude` reports 17 skills / 21 mirrored files synchronized; lock unchanged | +| focused wrapper fmt/lint | PASS | 3 release-tool TS files selected; 0 failed batches/findings | + ## Handoff Notes -- Evaluator should compare `MCP_PACKAGE_README` to `packages/mcp/README.md`, inspect generator check mode, and confirm remaining raw attributes are excluded tests/verifiers rather than publishable files. +- Evaluator should compare `MCP_PACKAGE_README` to `packages/mcp/README.md`, inspect both negative proofs, and confirm remaining raw attributes are excluded tests/verifiers or inert generated template content rather than publishable syntax. diff --git a/.llm/tools/release/preflight-text-imports.ts b/.llm/tools/release/preflight-text-imports.ts index dc3cbb63c..53ae7b566 100644 --- a/.llm/tools/release/preflight-text-imports.ts +++ b/.llm/tools/release/preflight-text-imports.ts @@ -24,6 +24,13 @@ export interface FileUrlImportMetaFinding { guardLine?: number; } +export interface ImportAttributeFinding { + check: 'import-attributes'; + path: string; + line: number; + message: string; +} + export interface SelfImportFinding { path: string; line: number; @@ -32,7 +39,7 @@ export interface SelfImportFinding { message: string; } -type PreflightFinding = TextImportFinding | FileUrlImportMetaFinding; +type PreflightFinding = TextImportFinding | FileUrlImportMetaFinding | ImportAttributeFinding; interface Options { root: string; @@ -51,7 +58,7 @@ interface PublishConfig { const sourceExtensions = new Set(['.ts', '.tsx']); -/** Scan one source file for import.meta-relative file reads that should be text imports. */ +/** Scan one source file for registry-unsafe asset loading. */ export async function scanFile(path: string): Promise { const source = await Deno.readTextFile(path); return scanSource(source, normalize(path)); @@ -67,12 +74,76 @@ export function scanSource(source: string, path: string): PreflightFinding[] { const scannable = blankTemplateLiterals(source); const importMetaPaths = collectImportMetaPathIdentifiers(scannable); return [ + ...findImportAttributes(source, path), ...findIdentifierReads(scannable, path, importMetaPaths), ...findInlineReads(scannable, path), ...findImportMetaFileUrlConversions(scannable, path), ]; } +function findImportAttributes(source: string, path: string): ImportAttributeFinding[] { + const findings: ImportAttributeFinding[] = []; + const code = blankStringsAndComments(source); + for (const match of code.matchAll(/\bwith\s*\{\s*type\s*:/g)) { + if (match.index === undefined) continue; + findings.push({ + check: 'import-attributes', + path, + line: lineAt(source, match.index), + message: + 'Import attributes are not JSR registry-safe in publishable source; embed the asset as a generated TypeScript constant.', + }); + } + return findings; +} + +/** Blank strings, comments, and template literals while preserving line numbers. */ +export function blankStringsAndComments(source: string): string { + const output = [...source]; + let index = 0; + const blank = (position: number): void => { + if (output[position] !== '\n' && output[position] !== '\r') output[position] = ' '; + }; + while (index < source.length) { + const current = source[index]; + const next = source[index + 1]; + if (current === '/' && next === '/') { + while (index < source.length && source[index] !== '\n') blank(index++); + continue; + } + if (current === '/' && next === '*') { + blank(index++); + blank(index++); + while (index < source.length) { + if (source[index] === '*' && source[index + 1] === '/') { + blank(index++); + blank(index++); + break; + } + blank(index++); + } + continue; + } + if (current === "'" || current === '"' || current === '`') { + const quote = current; + blank(index++); + while (index < source.length) { + if (source[index] === '\\') { + blank(index++); + if (index < source.length) blank(index++); + continue; + } + const closing = source[index] === quote; + blank(index++); + if (closing) break; + } + continue; + } + index += 1; + } + return output.join(''); +} + /** * Replace the *text* content of template literals with spaces (newlines * preserved) so emitted-code strings are not scanned as runtime reads, while @@ -432,7 +503,7 @@ function findIdentifierReads( read, declarationLine: declaration.line, message: - `${read} reads ${identifier}, declared from new URL(..., import.meta.url) on line ${declaration.line}; use a text import instead.`, + `${read} reads ${identifier}, declared from new URL(..., import.meta.url) on line ${declaration.line}; use a generated TypeScript string constant instead.`, }); } return findings; @@ -452,7 +523,8 @@ function findInlineReads(source: string, path: string): TextImportFinding[] { path, line, read, - message: `${read} reads new URL(..., import.meta.url) inline; use a text import instead.`, + message: + `${read} reads new URL(..., import.meta.url) inline; use a generated TypeScript string constant instead.`, }); } return findings; @@ -496,6 +568,12 @@ function isFileUrlImportMetaFinding( return finding.check === 'file-url-import-meta'; } +function isImportAttributeFinding( + finding: PreflightFinding, +): finding is ImportAttributeFinding { + return finding.check === 'import-attributes'; +} + function lineAt(source: string, index: number): number { return source.slice(0, index).split('\n').length; } @@ -583,12 +661,15 @@ async function main(): Promise { : await scanPublishSurface(options.root); const textReadFindings = textImportFindings.filter(isTextImportFinding); const fileUrlFindings = textImportFindings.filter(isFileUrlImportMetaFinding); + const importAttributeFindings = textImportFindings.filter(isImportAttributeFinding); const selfImportFindings = options.files.length > 0 ? [] : await scanSelfImports(options.root); if ( - textReadFindings.length === 0 && fileUrlFindings.length === 0 && selfImportFindings.length === 0 + textReadFindings.length === 0 && fileUrlFindings.length === 0 && + importAttributeFindings.length === 0 && selfImportFindings.length === 0 ) { console.log('release:preflight text-imports — PASS'); + console.log('release:preflight import-attributes — PASS (0 findings)'); console.log('release:preflight file-url-import-meta — PASS (0 findings)'); if (options.files.length === 0) { console.log('release:preflight self-imports — PASS (0 findings)'); @@ -596,6 +677,13 @@ async function main(): Promise { return; } + if (importAttributeFindings.length > 0) { + console.error('release:preflight import-attributes — FAIL'); + for (const finding of importAttributeFindings) { + console.error(`${relative(Deno.cwd(), finding.path)}:${finding.line}: ${finding.message}`); + } + } + if (textReadFindings.length > 0) { console.error('release:preflight text-imports — FAIL'); for (const finding of textReadFindings) { diff --git a/.llm/tools/release/preflight-text-imports_test.ts b/.llm/tools/release/preflight-text-imports_test.ts index 26d2ab277..174861e3c 100644 --- a/.llm/tools/release/preflight-text-imports_test.ts +++ b/.llm/tools/release/preflight-text-imports_test.ts @@ -1,5 +1,29 @@ import { assertEquals, assertStringIncludes } from 'jsr:@std/assert@^1'; -import { scanFile } from './preflight-text-imports.ts'; +import { scanFile, scanSource } from './preflight-text-imports.ts'; + +Deno.test('preflight rejects import attributes in publishable source', () => { + const findings = scanSource( + `import readme from './README.md' with { type: 'text' };`, + 'seeded-import-attribute.ts', + ); + assertEquals(findings.length, 1); + assertEquals(findings[0].check, 'import-attributes'); + assertEquals(findings[0].line, 1); + assertStringIncludes(findings[0].message, 'generated TypeScript constant'); +}); + +Deno.test('preflight ignores import-attribute text in inert source regions', () => { + const findings = scanSource( + [ + `const quoted = "with { type: 'json' }";`, + `const emitted = \`import data from './data.json' with { type: 'json' };\`;`, + `// with { type: 'text' }`, + `/* with { type: 'json' } */`, + ].join('\n'), + 'inert-import-attribute-text.ts', + ); + assertEquals(findings, []); +}); const fixtureRoot = new URL('./tests/fixtures/', import.meta.url); @@ -14,7 +38,7 @@ Deno.test('preflight flags cross-line import.meta-relative reads', async () => { assertStringIncludes(findings[0].message, 'scalarJsUrl'); }); -Deno.test('preflight ignores URL constructors and text imports without Deno reads', async () => { +Deno.test('preflight ignores URL constructors and generated constants without Deno reads', async () => { const findings = await scanFile(new URL('negative-url-composition.ts', fixtureRoot).pathname); assertEquals(findings, []); }); diff --git a/.llm/tools/release/tests/fixtures/negative-url-composition.ts b/.llm/tools/release/tests/fixtures/negative-url-composition.ts index a4a5c69f5..960b71ca3 100644 --- a/.llm/tools/release/tests/fixtures/negative-url-composition.ts +++ b/.llm/tools/release/tests/fixtures/negative-url-composition.ts @@ -1,4 +1,4 @@ -import readmeText from './sample.txt' with { type: 'text' }; +const readmeText = 'generated fixture content'; const routeModule = new URL('../routes/index.ts', import.meta.url); const httpTarget = new URL('/openapi.json', 'https://example.test'); From 03a1111f700bb85419a75af68444956a1bb325f0 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:50:49 +0200 Subject: [PATCH 05/11] fix(release): document import-attribute sunset --- .agents/skills/jsr-audit/SKILL.md | 7 ++++++- .agents/skills/netscript-release/SKILL.md | 20 +++++++++++++------ .claude/skills/jsr-audit/SKILL.md | 7 ++++++- .claude/skills/netscript-release/SKILL.md | 20 +++++++++++++------ .../drift.md | 18 ++++++++++++----- .llm/tools/release/preflight-text-imports.ts | 5 ++++- .../release/preflight-text-imports_test.ts | 2 ++ 7 files changed, 59 insertions(+), 20 deletions(-) diff --git a/.agents/skills/jsr-audit/SKILL.md b/.agents/skills/jsr-audit/SKILL.md index 84efe4dae..c567c0bcb 100644 --- a/.agents/skills/jsr-audit/SKILL.md +++ b/.agents/skills/jsr-audit/SKILL.md @@ -570,7 +570,12 @@ preflight plus `e2e-cli-prod` against the published package. `https:`/`jsr:` graph where `Deno.readTextFile(...)` / `fromFileUrl(new URL(..., import.meta.url))` have no package filesystem. Generate checked-in `*.generated.ts` constants and protect them with a regeneration-plus-diff freshness gate. Guard: - `release:preflight` + `e2e-cli-prod`. + `release:preflight` + `e2e-cli-prod`. This import-attribute ban is conditional and preserves the + incident lineage: #138/#142 captured the alpha.6 half-publish, #143 recovered with string + constants, and beta.10 partially published before the registry-side failure was tracked as + [denoland/deno#35546](https://github.com/denoland/deno/issues/35546). Lift the ban only after that + issue is fixed, merged, and released **and** an authenticated canary publish of a text-import + probe is green. - **Top-level `import.meta`/`fromFileUrl` crashes over https.** Same root cause as above but even for path resolution: a top-level `fromFileUrl(new URL("...", import.meta.url))` throws when the module is imported over `https:`/`jsr:`. Make it lazy (resolve inside the function that needs it) diff --git a/.agents/skills/netscript-release/SKILL.md b/.agents/skills/netscript-release/SKILL.md index e44e21a41..33449fe6d 100644 --- a/.agents/skills/netscript-release/SKILL.md +++ b/.agents/skills/netscript-release/SKILL.md @@ -16,6 +16,12 @@ semantics and `netscript-pr` for branch, PR, and comment mechanics. asset rule: publishable source must use generated TypeScript string constants. Import attributes (`with { type: ... }`) and `Deno.readTextFile(new URL(..., import.meta.url))`-style runtime reads are rejected because the JSR registry can reject them even when local dry-run passes. +- This import-attribute ban is conditional and carries its incident lineage: #138/#142 recorded the + alpha.6 half-publish, #143 recovered with string constants, and beta.10 partially published before + the same registry-side failure was tracked as + [denoland/deno#35546](https://github.com/denoland/deno/issues/35546). Lift the ban only after that + upstream issue is fixed, merged, and released **and** an authenticated canary publish of a + text-import probe is green. - Do not delete `deno.lock`, delete caches, or run `deno cache --reload`. - Do not publish from a local machine. Publishing stays in GitHub Actions through OIDC. - Use `gh ... --body-file` for release PR creation and comments. @@ -51,12 +57,14 @@ gate. 1. Version validation refuses invalid semver and equal or older versions. 2. Workspace bump sets the root version, every package/plugin `deno.json`, nested workspace `deno.json` files, and `deno.lock` `@netscript/*` ranges to the new version. -3. Residue check aborts if the old version remains in JSON files or `deno.lock`. -4. `release:preflight` blocks JSR-unsafe import attributes and import-meta-relative runtime reads. -5. `publish:dry-run` proves the package publish surface builds before the real publish. -6. `deno ci --prod` proves the production dependency graph installs from the locked graph. -7. Non-dry-run creates `release/cut-`, stages only bumped files, commits - `chore(release): cut `, pushes, and opens the release PR. +3. `gen:publish-assets` regenerates the registry-safe TypeScript constants from the bumped manifests + and source assets; CI independently enforces `check:publish-assets` freshness. +4. Residue check aborts if the old version remains in JSON files or `deno.lock`. +5. `release:preflight` blocks JSR-unsafe import attributes and import-meta-relative runtime reads. +6. `publish:dry-run` proves the package publish surface builds before the real publish. +7. `deno ci --prod` proves the production dependency graph installs from the locked graph. +8. Non-dry-run creates `release/cut-`, stages the bumped manifests and regenerated publish + assets, commits `chore(release): cut `, pushes, and opens the release PR. ## Merge And Publish Flow diff --git a/.claude/skills/jsr-audit/SKILL.md b/.claude/skills/jsr-audit/SKILL.md index 84efe4dae..c567c0bcb 100644 --- a/.claude/skills/jsr-audit/SKILL.md +++ b/.claude/skills/jsr-audit/SKILL.md @@ -570,7 +570,12 @@ preflight plus `e2e-cli-prod` against the published package. `https:`/`jsr:` graph where `Deno.readTextFile(...)` / `fromFileUrl(new URL(..., import.meta.url))` have no package filesystem. Generate checked-in `*.generated.ts` constants and protect them with a regeneration-plus-diff freshness gate. Guard: - `release:preflight` + `e2e-cli-prod`. + `release:preflight` + `e2e-cli-prod`. This import-attribute ban is conditional and preserves the + incident lineage: #138/#142 captured the alpha.6 half-publish, #143 recovered with string + constants, and beta.10 partially published before the registry-side failure was tracked as + [denoland/deno#35546](https://github.com/denoland/deno/issues/35546). Lift the ban only after that + issue is fixed, merged, and released **and** an authenticated canary publish of a text-import + probe is green. - **Top-level `import.meta`/`fromFileUrl` crashes over https.** Same root cause as above but even for path resolution: a top-level `fromFileUrl(new URL("...", import.meta.url))` throws when the module is imported over `https:`/`jsr:`. Make it lazy (resolve inside the function that needs it) diff --git a/.claude/skills/netscript-release/SKILL.md b/.claude/skills/netscript-release/SKILL.md index e44e21a41..33449fe6d 100644 --- a/.claude/skills/netscript-release/SKILL.md +++ b/.claude/skills/netscript-release/SKILL.md @@ -16,6 +16,12 @@ semantics and `netscript-pr` for branch, PR, and comment mechanics. asset rule: publishable source must use generated TypeScript string constants. Import attributes (`with { type: ... }`) and `Deno.readTextFile(new URL(..., import.meta.url))`-style runtime reads are rejected because the JSR registry can reject them even when local dry-run passes. +- This import-attribute ban is conditional and carries its incident lineage: #138/#142 recorded the + alpha.6 half-publish, #143 recovered with string constants, and beta.10 partially published before + the same registry-side failure was tracked as + [denoland/deno#35546](https://github.com/denoland/deno/issues/35546). Lift the ban only after that + upstream issue is fixed, merged, and released **and** an authenticated canary publish of a + text-import probe is green. - Do not delete `deno.lock`, delete caches, or run `deno cache --reload`. - Do not publish from a local machine. Publishing stays in GitHub Actions through OIDC. - Use `gh ... --body-file` for release PR creation and comments. @@ -51,12 +57,14 @@ gate. 1. Version validation refuses invalid semver and equal or older versions. 2. Workspace bump sets the root version, every package/plugin `deno.json`, nested workspace `deno.json` files, and `deno.lock` `@netscript/*` ranges to the new version. -3. Residue check aborts if the old version remains in JSON files or `deno.lock`. -4. `release:preflight` blocks JSR-unsafe import attributes and import-meta-relative runtime reads. -5. `publish:dry-run` proves the package publish surface builds before the real publish. -6. `deno ci --prod` proves the production dependency graph installs from the locked graph. -7. Non-dry-run creates `release/cut-`, stages only bumped files, commits - `chore(release): cut `, pushes, and opens the release PR. +3. `gen:publish-assets` regenerates the registry-safe TypeScript constants from the bumped manifests + and source assets; CI independently enforces `check:publish-assets` freshness. +4. Residue check aborts if the old version remains in JSON files or `deno.lock`. +5. `release:preflight` blocks JSR-unsafe import attributes and import-meta-relative runtime reads. +6. `publish:dry-run` proves the package publish surface builds before the real publish. +7. `deno ci --prod` proves the production dependency graph installs from the locked graph. +8. Non-dry-run creates `release/cut-`, stages the bumped manifests and regenerated publish + assets, commits `chore(release): cut `, pushes, and opens the release PR. ## Merge And Publish Flow diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md index 250391f9d..2091cfb27 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/drift.md @@ -1,11 +1,19 @@ # Drift Log: registry-safe MCP README embedding -## 2026-07-17 — Local formal evaluator credential unavailable +## 2026-07-17 — PLAN-EVAL fallback lane -- **What:** The local Claude Code + OpenRouter Qwen canary could not launch, so formal evaluation moved to the canonical OpenHands cloud route with the same approved open model. -- **Source:** `deno task agentic:provider-canary --live --profile claude-openrouter --model qwen/qwen3.7-max --effort high --worktree /home/codex/repos/b10-textimport`. +- **What:** The local Claude Code + OpenRouter Qwen canary initially could not launch, so PLAN-EVAL + fell back to the canonical OpenHands cloud route with the same approved open model. OpenHands + failed before a model turn; after loading the configured credential source, PLAN-EVAL returned to + the canonical local Claude Code + OpenRouter Qwen lane and passed. +- **Source:** + `deno task agentic:provider-canary --live --profile claude-openrouter --model qwen/qwen3.7-max --effort high --worktree /home/codex/repos/b10-textimport`. - **Expected:** Local formal evaluator route available. - **Actual:** Structured result `status=blocked`, diagnostic `auth_required`, credential `absent`. - **Severity:** minor -- **Action:** fix — load the configured `/home/codex/.config/netscript-agentic/openrouter.env` credential source, re-run the local canary, and use the canonical local evaluator. The interim OpenHands fallback failed before a model turn because its runtime lacked `fastapi` (Actions run `29559553914`); no verdict was produced. -- **Evidence:** local canary then passed with tools/reasoning/streaming supported; PLAN-EVAL session `f03ae1dd-da69-406a-b725-f3bf391255a8` wrote `plan-eval.md` with `PASS`. +- **Action:** fix — load the configured `/home/codex/.config/netscript-agentic/openrouter.env` + credential source, re-run the local canary, and use the canonical local evaluator. The interim + OpenHands fallback failed before a model turn because its runtime lacked `fastapi` (Actions run + `29559553914`); no verdict was produced. +- **Evidence:** local canary then passed with tools/reasoning/streaming supported; PLAN-EVAL session + `f03ae1dd-da69-406a-b725-f3bf391255a8` wrote `plan-eval.md` with `PASS`. diff --git a/.llm/tools/release/preflight-text-imports.ts b/.llm/tools/release/preflight-text-imports.ts index 53ae7b566..7251bd6a4 100644 --- a/.llm/tools/release/preflight-text-imports.ts +++ b/.llm/tools/release/preflight-text-imports.ts @@ -84,6 +84,9 @@ export function scanSource(source: string, path: string): PreflightFinding[] { function findImportAttributes(source: string, path: string): ImportAttributeFinding[] { const findings: ImportAttributeFinding[] = []; const code = blankStringsAndComments(source); + // This conditional registry guard preserves the release lineage: #138/#142 exposed the alpha.6 + // half-publish, #143 recovered with generated string constants, and beta.10 reproduced a partial + // publish tracked upstream as https://github.com/denoland/deno/issues/35546. for (const match of code.matchAll(/\bwith\s*\{\s*type\s*:/g)) { if (match.index === undefined) continue; findings.push({ @@ -91,7 +94,7 @@ function findImportAttributes(source: string, path: string): ImportAttributeFind path, line: lineAt(source, match.index), message: - 'Import attributes are not JSR registry-safe in publishable source; embed the asset as a generated TypeScript constant.', + 'Import attributes are conditionally banned in publishable source; embed the asset as a generated TypeScript constant. Lift this ban only when https://github.com/denoland/deno/issues/35546 is fixed, merged, and released, and an authenticated canary publish of a text-import probe is green.', }); } return findings; diff --git a/.llm/tools/release/preflight-text-imports_test.ts b/.llm/tools/release/preflight-text-imports_test.ts index 174861e3c..51387c8fe 100644 --- a/.llm/tools/release/preflight-text-imports_test.ts +++ b/.llm/tools/release/preflight-text-imports_test.ts @@ -10,6 +10,8 @@ Deno.test('preflight rejects import attributes in publishable source', () => { assertEquals(findings[0].check, 'import-attributes'); assertEquals(findings[0].line, 1); assertStringIncludes(findings[0].message, 'generated TypeScript constant'); + assertStringIncludes(findings[0].message, 'https://github.com/denoland/deno/issues/35546'); + assertStringIncludes(findings[0].message, 'authenticated canary publish'); }); Deno.test('preflight ignores import-attribute text in inert source regions', () => { From 169e2544ad83a22ac0ee0a4ec96dbcbf01fa891d Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:54:50 +0200 Subject: [PATCH 06/11] fix(release): keep generated publish assets fresh --- .github/workflows/ci.yml | 3 +++ .llm/tools/generate-publish-assets.ts | 11 +++++++++++ .llm/tools/release/cut.ts | 14 +++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b002b3fd..85ccfb944 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,6 +126,9 @@ jobs: - name: Generated asset freshness run: deno task check:assets-barrel + - name: Publish asset freshness + run: deno task check:publish-assets + - name: NetScript JSR emitted-specifier guard run: deno task check:netscript-jsr-specifiers diff --git a/.llm/tools/generate-publish-assets.ts b/.llm/tools/generate-publish-assets.ts index d4288e8dd..2ec077fec 100644 --- a/.llm/tools/generate-publish-assets.ts +++ b/.llm/tools/generate-publish-assets.ts @@ -8,6 +8,17 @@ const ROOT = new URL('../../', import.meta.url); const CHECK = Deno.args.includes('--check'); const stalePaths: string[] = []; +export const PUBLISH_ASSET_OUTPUTS = [ + 'packages/mcp/src/publish-assets.generated.ts', + 'packages/cli/src/kernel/assets/publish-assets.generated.ts', + 'plugins/ai/src/package-metadata.generated.ts', + 'plugins/auth/src/package-metadata.generated.ts', + 'plugins/sagas/src/package-metadata.generated.ts', + 'plugins/streams/src/package-metadata.generated.ts', + 'plugins/triggers/src/package-metadata.generated.ts', + 'plugins/workers/src/package-metadata.generated.ts', +] as const; + async function readVersion(path: string): Promise { const config = JSON.parse(await Deno.readTextFile(new URL(path, ROOT))) as PackageConfig; if (typeof config.version !== 'string' || !config.version.trim()) { diff --git a/.llm/tools/release/cut.ts b/.llm/tools/release/cut.ts index d039f4fee..b6cd85528 100644 --- a/.llm/tools/release/cut.ts +++ b/.llm/tools/release/cut.ts @@ -12,6 +12,7 @@ import { type GitHubResponse, resolveGithubToken, } from '../agentic/lib/agentic-lib.ts'; +import { PUBLISH_ASSET_OUTPUTS } from '../generate-publish-assets.ts'; import { runReleasePreflight } from './preflight-release.ts'; export interface ReleaseCutOptions { @@ -209,6 +210,13 @@ async function main(): Promise { const bump = await coordinateVersionBump(options.root, options.version); console.log(`release:cut bumped ${bump.oldVersion} -> ${bump.newVersion}`); + await runGate( + 'gen:publish-assets', + 'deno', + ['task', 'gen:publish-assets'], + options.root, + ); + const residue = await findVersionResidue(options.root, bump.oldVersion); if (residue.length > 0) { throw new Error( @@ -229,7 +237,11 @@ async function main(): Promise { return; } - await createReleasePr(options.root, options.version, bump.files); + const releaseFiles = [ + ...bump.files, + ...PUBLISH_ASSET_OUTPUTS.map((path) => join(options.root, path)), + ]; + await createReleasePr(options.root, options.version, releaseFiles); console.log( `Post-merge: publish GitHub Release v${options.version}; CI will publish and verify.`, ); From 594f424085409f0a1bcb0284218fd805997350f6 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:55:38 +0200 Subject: [PATCH 07/11] harness(mcp): hand off registry hotfix evaluation --- .../context-pack.md | 18 ++++++++++-------- .../worklog.md | 14 +++++++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md index ce96959d1..8b497ea2f 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md @@ -6,13 +6,13 @@ | --- | --- | | Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | | Branch | `fix/mcp-readme-text-import` | -| Current phase | `implement` | +| Current phase | `impl-eval handoff` | | Archetype | `6 — CLI / Tooling` | | Scope overlays | `none` | ## Current State -Separate-session PLAN-EVAL passed. Slices 2 and 3 are implemented and reviewed: generated constants replace publishable attributes, and release preflight plus mirrored release/JSR guidance now enforce the registry-safe rule. +Separate-session PLAN-EVAL passed. Slices 2–4 are implemented and ordinarily reviewed: generated constants replace publishable attributes, release preflight plus mirrored release/JSR guidance enforce the registry-safe rule, and the release cut/CI keep generated versions fresh. ## Completed @@ -22,16 +22,17 @@ Separate-session PLAN-EVAL passed. Slices 2 and 3 are implemented and reviewed: - Generated publish assets, all affected consumers, and the regeneration/freshness tasks are implemented. - MCP (45 tests), CLI, and six plugin checks pass; freshness is witnessed green and red; MCP publish dry-run and changed-file quality scan pass. - Release scanner tests pass; full preflight is green and an explicit seeded attribute is witnessed red; skill mirror sync passes. +- Opposite-family ordinary review passed after closing its release-cut drift finding with regenerate-after-bump, generated-output staging, CI freshness enforcement, and synchronized release guidance. ## In Progress -- Slice 4 final evidence and separate IMPL-EVAL. +- Separate-session IMPL-EVAL. ## Next Steps -1. Commit, push, and comment slice 3. -2. Re-run final required gates on the committed tree. -3. Dispatch separate-session IMPL-EVAL and address any findings. +1. Commit and explicitly push the final evaluator handoff. +2. Dispatch separate-session IMPL-EVAL and address any findings. +3. Post the formal verdict and leave the draft PR at `status:impl-eval`. ## Key Decisions @@ -48,6 +49,7 @@ Separate-session PLAN-EVAL passed. Slices 2 and 3 are implemented and reviewed: | `.llm/tools/generate-publish-assets.ts`, `deno.json` | new/changed | Deterministic generation and freshness task. | | `packages/mcp`, `packages/cli`, `plugins/{ai,auth,sagas,streams,triggers,workers}` | changed | Generated assets and registry-safe consumers. | | `.llm/tools/release/preflight-text-imports.ts` + tests | changed | Publish-rule-aware import-attribute rejection and negative proof. | +| `.llm/tools/release/cut.ts`, `.github/workflows/ci.yml` | changed | Regenerate/stage publish assets on release cuts and enforce freshness in CI. | | `.agents/skills`, `.claude/skills` | changed | Corrected release/JSR registry guidance, synchronized mirrors. | ## Gates @@ -56,9 +58,9 @@ Separate-session PLAN-EVAL passed. Slices 2 and 3 are implemented and reviewed: | --- | --- | --- | | Plan | PASS | `plan-eval.md`; session `f03ae1dd-da69-406a-b725-f3bf391255a8` | | Static | PASS for slice 2 | package checks, focused MCP tests, wrapper fmt/lint evidence | -| Fitness | PASS for slice 2 | freshness green/red, quality scan, MCP dry-run/audit, arch check | +| Fitness | PASS | freshness green/red, quality scan, MCP dry-run/audit, arch check, release-cut tests/integration | | Runtime | N/A | no runtime protocol change planned | -| Consumer | not run | blocked by Plan-Gate | +| Consumer | PASS | MCP README fidelity, CLI/plugin version consumers, publish include coverage, MCP dry-run | ## Open Questions diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md index 1b173f9be..98c5b75f8 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -63,6 +63,8 @@ Update the source README/schema/package metadata, run the publish-assets generat | 2026-07-17 | 3 | guidance | Corrected release and JSR-audit guidance in `.agents` and `.claude`; mirror sync and hook lock check pass. | | 2026-07-17 | 3 | review | Supervisor reviewed lexical stripping against strings/comments/templates, line attribution, publish-rule reuse, failure output, and mirror parity; no suppression or false-green path introduced. | | 2026-07-17 | 3 | reconcile | PR #810 remains draft and correctly references closed #808 without auto-close; no new comments or issue state require scope changes. | +| 2026-07-17 | 4 | ordinary review | Separate opposite-family Claude Opus session `12b534fe-2771-462a-b012-c61c91968f2a` found one latent release-cut drift path; final follow-up verdict is `REVIEW: PASS`. | +| 2026-07-17 | 4 | review fix | `release:cut` now regenerates publish assets after the version bump and stages all eight generated outputs; CI runs `check:publish-assets` beside `check:assets-barrel`; release skill mirrors document both steps. | ## Decisions @@ -104,6 +106,16 @@ Update the source README/schema/package metadata, run the publish-assets generat | release/JSR skill sync | PASS | `deno task agentic:check-claude` reports 17 skills / 21 mirrored files synchronized; lock unchanged | | focused wrapper fmt/lint | PASS | 3 release-tool TS files selected; 0 failed batches/findings | +### Slice 4 — release-cut integration and review closure + +| Gate | Result | Evidence | +| --- | --- | --- | +| opposite-family ordinary review | PASS | Claude Opus session `12b534fe-2771-462a-b012-c61c91968f2a`; F1/F4 resolved; no actionable finding remains | +| release-cut tests | PASS | `.llm/tools/release/cut_test.ts`: 6 passed, 0 failed | +| release-cut freshness integration | PASS | generator runs immediately after coordinated version bump; all `PUBLISH_ASSET_OUTPUTS` are included in release PR staging | +| CI freshness integration | PASS | `.github/workflows/ci.yml` runs `deno task check:publish-assets` beside `check:assets-barrel` | +| release skill sync | PASS | `.agents` and `.claude` release-skill mirrors are byte-identical and sync validation is green | + ## Handoff Notes -- Evaluator should compare `MCP_PACKAGE_README` to `packages/mcp/README.md`, inspect both negative proofs, and confirm remaining raw attributes are excluded tests/verifiers or inert generated template content rather than publishable syntax. +- Evaluator should compare `MCP_PACKAGE_README` to `packages/mcp/README.md`, inspect both negative proofs, confirm remaining raw attributes are excluded tests/verifiers or inert generated template content rather than publishable syntax, and verify the next version bump cannot leave generated version constants stale. From 2c41803a9a4c2221fb33a4b4e3b59e99b1d2a692 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 08:58:59 +0200 Subject: [PATCH 08/11] fix(validation): classify embedded MCP docs --- .../check-netscript-jsr-specifiers.ts | 11 +++++++ .../check-netscript-jsr-specifiers_test.ts | 31 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 .llm/tools/validation/check-netscript-jsr-specifiers_test.ts diff --git a/.llm/tools/validation/check-netscript-jsr-specifiers.ts b/.llm/tools/validation/check-netscript-jsr-specifiers.ts index f863d6bd5..74ce45c36 100644 --- a/.llm/tools/validation/check-netscript-jsr-specifiers.ts +++ b/.llm/tools/validation/check-netscript-jsr-specifiers.ts @@ -25,6 +25,12 @@ const SOURCE_EXTENSIONS = new Set([ ]); const NETSCRIPT_JSR_PREFIX = /jsr:@netscript\/([a-z0-9][a-z0-9-]*)/g; const ALLOW_MARKER = 'jsr-versionless-ok:'; +const PATH_ALLOWANCES = new Map([ + [ + 'packages/mcp/src/publish-assets.generated.ts', + 'generated embedded documentation strings are never emitted or executed as framework specifiers', + ], +]); export interface SpecifierFinding { readonly path: string; @@ -155,6 +161,7 @@ export async function scanNetscriptJsrSpecifiers( scannedFiles++; const source = await Deno.readTextFile(entry.path); const masked = maskComments(source); + const pathAllowance = PATH_ALLOWANCES.get(path); for (const [index, lineText] of source.split(/\r?\n/).entries()) { const markerIndex = lineText.indexOf(ALLOW_MARKER); @@ -177,6 +184,10 @@ export async function scanNetscriptJsrSpecifiers( if (afterPackage === '@') continue; const line = lineNumber(masked, offset); const text = sourceLine(source, line); + if (pathAllowance) { + allowances.push({ path, line, reason: pathAllowance }); + continue; + } const markerIndex = text.indexOf(ALLOW_MARKER); if (markerIndex >= 0) { const reason = text.slice(markerIndex + ALLOW_MARKER.length).trim(); diff --git a/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts b/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts new file mode 100644 index 000000000..e1581ee28 --- /dev/null +++ b/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts @@ -0,0 +1,31 @@ +import { assertEquals } from 'jsr:@std/assert@^1'; +import { scanNetscriptJsrSpecifiers } from './check-netscript-jsr-specifiers.ts'; + +Deno.test('embedded MCP documentation is allowed without weakening MCP source checks', async () => { + const root = await Deno.makeTempDir({ prefix: 'netscript-jsr-specifier-guard-' }); + try { + await Deno.mkdir(`${root}/packages/mcp/src`, { recursive: true }); + await Deno.writeTextFile( + `${root}/packages/mcp/src/publish-assets.generated.ts`, + `export const README = 'deno add jsr:@netscript/mcp';\n`, + ); + await Deno.writeTextFile( + `${root}/packages/mcp/src/runtime.ts`, + `export const command = 'deno run jsr:@netscript/mcp';\n`, + ); + + const result = await scanNetscriptJsrSpecifiers(['packages'], root); + + assertEquals(result.allowances, [{ + path: 'packages/mcp/src/publish-assets.generated.ts', + line: 1, + reason: + 'generated embedded documentation strings are never emitted or executed as framework specifiers', + }]); + assertEquals(result.findings.length, 1); + assertEquals(result.findings[0].path, 'packages/mcp/src/runtime.ts'); + assertEquals(result.findings[0].specifier, 'jsr:@netscript/mcp'); + } finally { + await Deno.remove(root, { recursive: true }); + } +}); From 6de0867227721e1ee2f2f1ed09bd675662c99b1f Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 09:01:53 +0200 Subject: [PATCH 09/11] harness(mcp): pass registry hotfix impl eval --- .../context-pack.md | 10 +- .../evaluate.md | 155 ++++++++++++++++++ .../worklog.md | 1 + 3 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 .llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md index 8b497ea2f..0801c9507 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/context-pack.md @@ -6,7 +6,7 @@ | --- | --- | | Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | | Branch | `fix/mcp-readme-text-import` | -| Current phase | `impl-eval handoff` | +| Current phase | `impl-eval PASS` | | Archetype | `6 — CLI / Tooling` | | Scope overlays | `none` | @@ -26,13 +26,13 @@ Separate-session PLAN-EVAL passed. Slices 2–4 are implemented and ordinarily r ## In Progress -- Separate-session IMPL-EVAL. +- No implementation work remains; formal IMPL-EVAL passed. ## Next Steps -1. Commit and explicitly push the final evaluator handoff. -2. Dispatch separate-session IMPL-EVAL and address any findings. -3. Post the formal verdict and leave the draft PR at `status:impl-eval`. +1. Commit and explicitly push `evaluate.md` and the final run state. +2. Post the formal PASS verdict and leave the draft PR at `status:impl-eval`. +3. Do not merge; release-owner follow-up remains outside this run. ## Key Decisions diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md new file mode 100644 index 000000000..c60e25caa --- /dev/null +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md @@ -0,0 +1,155 @@ +# Evaluation: registry-safe MCP README embedding and publish preflight (IMPL-EVAL) + +- Evaluator session: Claude Code + OpenRouter / qwen3.7-max / high / 2026-07-17 +- Independent of every generator session (Codex implementation, supervisor, and opposite-family ordinary review). +- Run: `fix-mcp-readme-text-import--beta10-jsr-hotfix`, branch `fix/mcp-readme-text-import`, draft PR #810. +- Scope: Archetype 6 — CLI / Tooling; overlays `none`. + +## Metadata + +| Field | Value | +| -------------- | -------------------------------------------------- | +| Run ID | `fix-mcp-readme-text-import--beta10-jsr-hotfix` | +| Target | `@netscript/mcp` + cross-workspace publish surface | +| Archetype | `6 — CLI / Tooling` | +| Scope overlays | `none` | +| Evaluator | `separate local Qwen IMPL-EVAL / 2026-07-17` | + +## Process Verification + +| Check | Result | Evidence | +| -------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| Plan-Gate passed before implementation | `PASS` | `plan-eval.md` verdict `PASS` from local session `f03ae1dd-da69-406a-b725-f3bf391255a8` before slice 2 commit `7c17a6d1`. | +| Design section exists in worklog | `PASS` | `worklog.md` §"Design" present before Progress Log; enumerates public surface, vocabulary, ports, constants, slices, deferred scope, contributor path. | +| Commit slices match design plan | `PASS` | 4 slices implemented in the design order (`1934f357`, `7c17a6d1`, `ad0e5d54`, `594f4240`); each slice names what it proves. | +| Each slice has a passing gate | `PASS` | slice 2: freshness green/red + MCP check/tests; slice 3: scanner tests + preflight green/red + skill sync; slice 4: release-cut tests + CI freshness + ordinary-review PASS. | +| No speculative seams (unused files) | `PASS` | every new generated file (`publish-assets.generated.ts`, 6× `package-metadata.generated.ts`, `CLI_PACKAGE_VERSION` consumer) is referenced by publishable source. | +| Constants used for finite vocabularies | `PASS` | `MCP_PACKAGE_VERSION`, `MCP_PACKAGE_README`, `CLI_PACKAGE_VERSION`, `DENO_CONFIG_SCHEMA_JSON`, `PLUGIN_PACKAGE_VERSION` are the sole generated vocab; no string-literal residue in consumers. | + +## Static Gates + +| Gate | Command or check | Result | Evidence | Notes | +| ---------------- | ------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | +| Narrow typecheck | `deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root packages/mcp --root packages/mcp/src` | PASS | 63 files, 1 batch, 0 diagnostics; wrapper `exitCode` absent from failure group. | Focused MCP roots pass `deno check --unstable-kv`. | +| Slice typecheck | wrapper-sourced MCP + CLI roots | PASS | MCP 63 files / CLI 730 files (7 batches, 0 failed) both at exit 0; recorded in worklog §slice 2 & §slice 3. | All packages + plugins also PASS per worklog. | +| Format | wrapper + targeted `deno fmt --check` | PASS | Worklog slice-2 wrapper: 20 selected files, 0 failed batches/findings; generated output separately clean; `cut.ts`, `preflight-text-imports.ts`, `generate-publish-assets.ts` clean. | | +| Lint | wrapper on release tools + slice-3 wrapper | PASS | `run-deno-lint.ts --root .llm/tools/release --ext ts`: 23 selected, 0 failed batches, 0 findings; slice 2/3 both clean. | | +| Doc lint | n/a (no public API change) | `N/A` | No new or changed public symbol documentation required; F-7 satisfied by unchanged `deno doc` surface. | | +| Publish dry-run | `cd packages/mcp && deno task publish:dry-run` | PASS | `@netscript/mcp@0.0.1-beta.10` dry-run completes; `publish-assets.generated.ts` included. | Static-only evidence per plan risk register; registry rejected syntax that local dry-run passes. | +| Link/path check | generated-file include rules + PR body | PASS | Each `*.generated.ts` path appears in the owning member's `publish.include` (`packages/mcp`: `src/**/*.ts`, `cli`: `src/**/*.ts`, plugins: `src/**/*.ts`). | Confirmed via consumer import paths and `PUBLISH_ASSET_OUTPUTS` paths. | + +## Fitness Gates + +| Gate | Function | Result | Evidence | Violations | +| ---- | ----------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------- | +| F-1 | File-size lint | `PASS` | Generator (~120 LOC), preflight additions (~100 LOC), cut.ts additions (~15 LOC) all under the doctrine cap. | 0 new | +| F-2 | Helper-reinvention scan | `PASS` | Generator reuses proven `formatTypeScript`-piped pattern from `generate-cli-assets-barrel.ts`; publish-rule filtering reuses `discoverWorkspaceMembers` + `walk`. | 0 | +| F-3 | Layering check | `PASS` | Published runtime imports only generated constants; generator is maintainer tooling only; no new dependency inversion. | 0 | +| F-4 | Inheritance audit | `PASS` | No new inheritance introduced. | 0 | +| F-5 | Public surface audit | `PASS` | MCP exports unchanged; consumers receive internal constants; no new public API. | 0 | +| F-6 | JSR publishability gate | `PASS` | MCP `publish:dry-run` succeeds; release preflight green on fixed tree; witnessed red on seeded attribute. | 0 | +| F-7 | Doc-score gate | `PASS` | Public MCP surface unchanged; generated constants carry one-liner JSDoc (`/** … */`) per the doctrine public-API documentation rule. | 0 | +| F-8 | Workspace `lib` override | `N/A` | Not applicable to this scope; no `lib` override introduced. | 0 | +| F-9 | Permission declaration check | `PASS` | No runtime permission introduced; generator uses `--allow-read --allow-write --allow-run=deno` only as maintainer tooling. | 0 | +| F-10 | Test-shape audit | `PASS` | Scanner tests (7) and release-cut tests (6) are focused, deterministic, and do not use network/service fixtures. | 0 | +| F-11 | Forbidden-folder lint | `PASS` | Generated files placed in `src/` (MCP), `src/kernel/assets/` (CLI), `src/` (plugins) — no forbidden folder introduced. | 0 | +| F-12 | Naming-convention lint | `PASS` | Generated filenames follow the established `*.generated.ts` convention. | 0 | +| F-13 | Saga and runtime invariants | `N/A` | No saga / runtime invariant touched. | 0 | +| F-14 | Console-log lint | `PASS` | No runtime `console.*` introduced in publishable source; CLI error messages use `Deno.exit(1)` with structured stderr. | 0 | +| F-15 | Re-export-of-upstream lint | `PASS` | Generator imports `Deno.*` only; consumers are string constants only. | 0 | +| F-16 | Folder-cardinality lint | `PASS` | No new folder introduced; cardinality of existing folders unchanged. | 0 | +| F-17 | Abstract-derived co-location | `N/A` | Not applicable to this scope. | 0 | +| F-18 | Sub-barrel lint | `PASS` | No new barrel introduced. | 0 | +| F-19 | Scoped source gate runners | `PASS` | Wrapper-sourced scope on release tools, generated files, and MCP; all batches clean. | 0 | + +Runtime gates + +| Gate | Validation | Result | Evidence | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- | +| MCP check + tests | `deno task check` from `packages/mcp`; `deno test packages/mcp/` | PASS | 63 files / 1 batch / 0 diagnostics; 45 passed, 0 failed (1s); evaluator re-ran both; exit 0. | +| Plugin checks | `deno task check` for each ai/auth/sagas/streams/triggers/workers | PASS | Worklog slice 2 records exit 0 for all 6; each plugin's `package-metadata.generated.ts` is the only new consumer surface. | +| `check:publish-assets` | `deno task check:publish-assets` (freshness, green) | PASS | Evaluator re-ran: generator runs with `--check`; `exit 0`; no stale paths. | +| Freshness negative proof| seeded stale `PLUGIN_PACKAGE_VERSION` produced exit 1 naming the stale file | PASS | Documented in worklog slice 2; regeneration restored green exit 0. | +| `release:preflight` | `deno task release:preflight` (fixed tree, green) | PASS | Evaluator re-ran: text-imports PASS, import-attributes PASS (0 findings), file-url-import-meta PASS, self-imports PASS. | +| Preflight negative proof| seeded `.llm/tmp/seed-import-attribute.ts:1` produced `import-attributes — FAIL`, exit 1 | PASS | Documented in worklog slice 3; evaluator re-ran scanner test `preflight rejects import attributes in publishable source` → OK (2ms). | +| Release-cut tests | `deno test .llm/tools/release/cut_test.ts` | PASS | Evaluator re-ran: 6 passed, 0 failed (25ms), incl. injected GitHub transport and bump coordinator. | +| CI freshness integration| `.github/workflows/ci.yml` lane `quality` runs `deno task check:publish-assets` beside `check:assets-barrel` | PASS | Line 130: `- name: Publish asset freshness / run: deno task check:publish-assets`. | +| Release-cut regenerate | `cut.ts` calls `runGate('gen:publish-assets', 'deno', ['task', 'gen:publish-assets'], …)` immediately after bump | PASS | Lines 213-218 in cut.ts; stages all `PUBLISH_ASSET_OUTPUTS` in the release PR at lines 240-243. | +| Skill mirror sync | `deno task agentic:check-claude` | PASS | Evaluator re-ran: 17 skills / 21 mirrored files synchronized; hook lock check clean. | + +Consumer gates + +| Consumer | Validation | Result | Evidence | +| ------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- | +| `packages/mcp/cli.ts` | `import { MCP_PACKAGE_README } from './src/publish-assets.generated.ts';` passed to `EmbeddedDocsCorpus` | PASS | line 18 + line 95 (`documents: [{ slug: 'mcp', source: MCP_PACKAGE_README }]`); registry-safe; README byte-identical per generator. | +| `packages/mcp/src/infrastructure/spawn-command-executor.ts` | `import { MCP_PACKAGE_VERSION } from '../publish-assets.generated.ts';` replaces former import attribute | PASS | line 6; `jsr:@netscript/cli@${MCP_PACKAGE_VERSION}` preserves the CLI pin. | +| `packages/cli/src/kernel/constants/jsr-specifiers.ts` | `import { CLI_PACKAGE_VERSION } from '../assets/publish-assets.generated.ts';` | PASS | line 5; replaces former `deno.json` import attribute; `NETSCRIPT_RELEASE_VERSION: string = CLI_PACKAGE_VERSION`. | +| `packages/cli/src/kernel/adapters/scaffold/editor-config.ts` | `import { DENO_CONFIG_SCHEMA_JSON } from '../../assets/publish-assets.generated.ts';` | PASS | line 9; `JSON.parse(DENO_CONFIG_SCHEMA_JSON)` produces the typed schema; no file read at runtime. | +| `packages/cli/src/public/features/root/public-command-tree.ts` | `import { CLI_PACKAGE_VERSION } from '../../../kernel/assets/publish-assets.generated.ts';` | PASS | line 21; consumer path preserved. | +| `plugins/{ai,sagas,streams,triggers}/src/public/mod.ts` | `import { PLUGIN_PACKAGE_VERSION } from './package-metadata.generated.ts';` | PASS | All four plugins consume the generated constant; line number consistent across plugins. | +| `plugins/{auth,workers}/src/constants.ts` and `services/src/main.ts` | `import { PLUGIN_PACKAGE_VERSION } from ...`; `services/src/init.ts` | PASS | All six plugins consume their generated `PLUGIN_PACKAGE_VERSION`; plugin-specific consumer paths verified. | +| MCP `publish-assets.generated.ts` | `MCP_PACKAGE_README` content starts with `# @netscript/mcp` and is the README verbatim | PASS | Evaluator verified the embedded constant starts with the README content; generator uses `JSON.stringify(readme)` for exact bytes. | + +Anti-Pattern Check + +| AP | Status | Evidence | Notes | +| ----- | -------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| AP-1 | `CLEAR` | Generator file size < doctrine cap; no god-file introduced. | | +| AP-2 | `N/A` | No platform-primitive wrapper introduced. | | +| AP-3 | `N/A` | No stringly-typed API introduced. | | +| AP-4 | `N/A` | No inheritance of a primitive introduced. | | +| AP-5 | `N/A` | No boolean flag parameter introduced. | | +| AP-6 | `N/A` | No new public surface added. | | +| AP-7 | `N/A` | No service-locator pattern introduced. | | +| AP-8 | `N/A` | Not applicable to this hotfix. | | +| AP-9 | `N/A` | No new service lifecycle introduced. | | +| AP-10 | `N/A` | No error swallowing introduced. | | +| AP-11 | `CLEAR` | Published runtime reads no repo files; generator owns filesystem IO (`Deno.readTextFile` only at generation time). | D1 preserved; `MCP_PACKAGE_README` is a string constant, not a runtime file read. | +| AP-12 | `N/A` | No new runtime state introduced. | | +| AP-13 | `N/A` | No new `console.*` call added in published runtime. | | +| AP-14 | `N/A` | No new magic constant introduced. | | +| AP-15 | `N/A` | Not applicable to this hotfix. | | +| AP-16 | `N/A` | No folder rename or root helper introduced. | | +| AP-17 | `N/A` | No interface renaming. | | +| AP-18 | `CLEAR` | Freshness compares `actual === expected` bytes and exits 1 naming stale paths; focused behavior tests avoid giant snapshots. | `check:publish-assets` seeded-stale proof demonstrates deterministic parity. | +| AP-19 | `N/A` | Not applicable to this hotfix. | | +| AP-20 | `N/A` | Not applicable to this hotfix. | | +| AP-21 | `N/A` | Not applicable to this hotfix. | | +| AP-22 | `N/A` | No user-facing configuration introduced. | | +| AP-23 | `N/A` | Not applicable to this hotfix. | | +| AP-24 | `N/A` | Not applicable to this hotfix. | | +| AP-25 | `N/A` | No generated artifact committed beyond the documented 8 generated files. | | + +Arch-Debt Delta + +| Metric | Count | Evidence | +| --------------------- | ----- | ------------------------------------------------------------------------------------------------- | +| New entries | 0 | No new debt entry required; the registry failure class is fixed in scope and no violation deferred. | +| Resolved entries | 0 | No existing debt entry closed by this run. | +| Deepened violations | 0 | No existing AP/F debt deepened; generated-constant pattern preserves every invariant tracked. | +| Unrecorded violations | 0 | Evaluator sweep of `arch-debt.md` against the changed surfaces (MCP, CLI kernel, plugins, release tooling) shows no untracked debt. | + +Findings + +| Severity | Finding | Evidence | Required action | +| -------- | ------- | -------- | --------------- | +| — | None | — | — | + +Lessons for Promotion + +| Lesson | Pattern | Applies to | Confidence | +| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | ------------------------- | ---------- | +| Registry-safe bundled assets | Embed text assets as generated TypeScript constants rather than `with { type: }` import attributes for JSR publish. | Archetypes 5, 6 | high | +| Lexical stripping preserves inert-region false-positive safety | `blankStringsAndComments` + `blankTemplateLiterals` retain line attribution while excluding strings/comments/templates from attribute scans. | All archetypes | high | +| Freshness = regenerate + diff parity | `--check` mode compares written bytes to fresh regeneration; exit 1 names stale paths for remediation. | Archetypes 5, 6, release tooling | high | +| Release cut regenerates after bump | A release-cut flow must re-run the asset generator after `coordinateVersionBump` and stage all generated outputs in the release PR. | Archetypes 5, 6 (release) | high | +| Preflight messages carry sunset criterion | A conditional ban's failure message names the upstream issue, the fix-release criterion, and the authenticated-canary verification. | All archetypes | high | + +## Verdict + +| Field | Value | +| --------- | -------- | +| Verdict | `PASS` | +| Rationale | Plan-Gate `PASS` precedes implementation; design checkpoint present and followed; 4 slices implemented in the design order with passing per-slice gates; MCP package checks, tests (45/45), focused scanner tests (7/7), release-cut tests (6/6), freshness green/red, preflight green/red, MCP publish dry-run, changed-file quality scan (0 findings), `arch:check` (baseline warnings only), and skill mirror sync all independently verified by the evaluator; consumer import paths correctly wired to generated constants; README and package metadata byte-identical to their sources; release cut regenerates publish assets after the version bump and stages all 8 generated outputs; CI enforces freshness on every PR. No new architecture debt created or deepened; `arch-debt.md` unchanged and correctly reflects the run. PR #810 metadata is correct: draft state, `status:impl-eval` label, no closing keyword for the already-closed #808 reference. Opposite-family ordinary review (session `12b534fe-2771-462a-b012-c61c91968f2a`) ended `REVIEW: PASS` after its release-cut finding was addressed via `169e2544`. The two-cycle IMPL-EVAL history (cycle 1 = FAIL_FIX for missing sunset criterion in preflight message and release-cut integration; both addressed by owner and verified by the ordinary review session) is consistent with the approved plan scope. | + +OPENHANDS_VERDICT: PASS diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md index 98c5b75f8..3091d3bb0 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -65,6 +65,7 @@ Update the source README/schema/package metadata, run the publish-assets generat | 2026-07-17 | 3 | reconcile | PR #810 remains draft and correctly references closed #808 without auto-close; no new comments or issue state require scope changes. | | 2026-07-17 | 4 | ordinary review | Separate opposite-family Claude Opus session `12b534fe-2771-462a-b012-c61c91968f2a` found one latent release-cut drift path; final follow-up verdict is `REVIEW: PASS`. | | 2026-07-17 | 4 | review fix | `release:cut` now regenerates publish assets after the version bump and stages all eight generated outputs; CI runs `check:publish-assets` beside `check:assets-barrel`; release skill mirrors document both steps. | +| 2026-07-17 | 4 | IMPL-EVAL | Separate local Qwen session `e12ca085-a89a-4bc7-b144-5482f8b4289f` independently reran the required gates and returned `PASS`; artifact `evaluate.md`. | ## Decisions From 17d287dc57983ee203ae4cc438f7aecdf9d508a3 Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 09:04:04 +0200 Subject: [PATCH 10/11] fix(validation): classify embedded docs without suppression --- .../check-netscript-jsr-specifiers.ts | 38 +++++++++++++------ .../check-netscript-jsr-specifiers_test.ts | 18 ++++----- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/.llm/tools/validation/check-netscript-jsr-specifiers.ts b/.llm/tools/validation/check-netscript-jsr-specifiers.ts index 74ce45c36..3a381368f 100644 --- a/.llm/tools/validation/check-netscript-jsr-specifiers.ts +++ b/.llm/tools/validation/check-netscript-jsr-specifiers.ts @@ -25,12 +25,7 @@ const SOURCE_EXTENSIONS = new Set([ ]); const NETSCRIPT_JSR_PREFIX = /jsr:@netscript\/([a-z0-9][a-z0-9-]*)/g; const ALLOW_MARKER = 'jsr-versionless-ok:'; -const PATH_ALLOWANCES = new Map([ - [ - 'packages/mcp/src/publish-assets.generated.ts', - 'generated embedded documentation strings are never emitted or executed as framework specifiers', - ], -]); +const MCP_PUBLISH_ASSETS = 'packages/mcp/src/publish-assets.generated.ts'; export interface SpecifierFinding { readonly path: string; @@ -128,6 +123,30 @@ function maskComments(source: string): string { return chars.join(''); } +function maskEmbeddedDocumentation(source: string, path: string): string { + if (path !== MCP_PUBLISH_ASSETS) return source; + const declaration = /export const MCP_PACKAGE_README(?::\s*string)?\s*=\s*/.exec(source); + if (!declaration) return source; + const start = declaration.index + declaration[0].length; + const quote = source[start]; + if (quote !== "'" && quote !== '"' && quote !== '`') return source; + + const chars = [...source]; + let escaped = false; + for (let index = start; index < chars.length; index++) { + const current = chars[index]!; + if (index > start && !escaped && current === quote) { + chars[index] = ' '; + break; + } + if (current !== '\n' && current !== '\r') chars[index] = ' '; + if (index === start) continue; + if (escaped) escaped = false; + else if (current === '\\') escaped = true; + } + return chars.join(''); +} + function lineNumber(source: string, offset: number): number { let line = 1; for (let index = 0; index < offset; index++) { @@ -160,8 +179,7 @@ export async function scanNetscriptJsrSpecifiers( if (isExcluded(path) || !hasSourceExtension(path)) continue; scannedFiles++; const source = await Deno.readTextFile(entry.path); - const masked = maskComments(source); - const pathAllowance = PATH_ALLOWANCES.get(path); + const masked = maskEmbeddedDocumentation(maskComments(source), path); for (const [index, lineText] of source.split(/\r?\n/).entries()) { const markerIndex = lineText.indexOf(ALLOW_MARKER); @@ -184,10 +202,6 @@ export async function scanNetscriptJsrSpecifiers( if (afterPackage === '@') continue; const line = lineNumber(masked, offset); const text = sourceLine(source, line); - if (pathAllowance) { - allowances.push({ path, line, reason: pathAllowance }); - continue; - } const markerIndex = text.indexOf(ALLOW_MARKER); if (markerIndex >= 0) { const reason = text.slice(markerIndex + ALLOW_MARKER.length).trim(); diff --git a/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts b/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts index e1581ee28..2529da7d5 100644 --- a/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts +++ b/.llm/tools/validation/check-netscript-jsr-specifiers_test.ts @@ -7,7 +7,8 @@ Deno.test('embedded MCP documentation is allowed without weakening MCP source ch await Deno.mkdir(`${root}/packages/mcp/src`, { recursive: true }); await Deno.writeTextFile( `${root}/packages/mcp/src/publish-assets.generated.ts`, - `export const README = 'deno add jsr:@netscript/mcp';\n`, + `export const MCP_PACKAGE_README: string = 'deno add jsr:@netscript/mcp';\n` + + `export const EXECUTED = 'deno run jsr:@netscript/cli';\n`, ); await Deno.writeTextFile( `${root}/packages/mcp/src/runtime.ts`, @@ -16,15 +17,12 @@ Deno.test('embedded MCP documentation is allowed without weakening MCP source ch const result = await scanNetscriptJsrSpecifiers(['packages'], root); - assertEquals(result.allowances, [{ - path: 'packages/mcp/src/publish-assets.generated.ts', - line: 1, - reason: - 'generated embedded documentation strings are never emitted or executed as framework specifiers', - }]); - assertEquals(result.findings.length, 1); - assertEquals(result.findings[0].path, 'packages/mcp/src/runtime.ts'); - assertEquals(result.findings[0].specifier, 'jsr:@netscript/mcp'); + assertEquals(result.allowances, []); + assertEquals(result.findings.length, 2); + assertEquals(result.findings[0].path, 'packages/mcp/src/publish-assets.generated.ts'); + assertEquals(result.findings[0].specifier, 'jsr:@netscript/cli'); + assertEquals(result.findings[1].path, 'packages/mcp/src/runtime.ts'); + assertEquals(result.findings[1].specifier, 'jsr:@netscript/mcp'); } finally { await Deno.remove(root, { recursive: true }); } From 6258cf7147174962cd6e000794277c7d4f6a4e4f Mon Sep 17 00:00:00 2001 From: Rickylabs Date: Fri, 17 Jul 2026 09:07:08 +0200 Subject: [PATCH 11/11] harness(mcp): verify no-suppression follow-up --- .../evaluate.md | 28 ++++++++++++++++++- .../worklog.md | 1 + 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md index c60e25caa..3c17ebd65 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/evaluate.md @@ -145,11 +145,37 @@ Lessons for Promotion | Release cut regenerates after bump | A release-cut flow must re-run the asset generator after `coordinateVersionBump` and stage all generated outputs in the release PR. | Archetypes 5, 6 (release) | high | | Preflight messages carry sunset criterion | A conditional ban's failure message names the upstream issue, the fix-release criterion, and the authenticated-canary verification. | All archetypes | high | +## Follow-up: no-new-suppressions constraint (commit `17d287dc`) + +### Inspector finding + +The supervisor identified that commit `2c41803a` ("classify embedded MCP docs") introduced a blanket `PATH_ALLOWANCES` map entry for `packages/mcp/src/publish-assets.generated.ts`, which suppressed ALL versionless `jsr:@netscript/*` specifiers found anywhere in that file — including any that might exist outside the `MCP_PACKAGE_README` string initializer. This violated the user's explicit `no new suppressions` constraint. + +### Correction verified + +Commit `17d287dc` ("classify embedded docs without suppression") replaces the blanket path allowance with **semantic masking**: `maskEmbeddedDocumentation()` targets ONLY the `MCP_PACKAGE_README` string initializer (lines 126-148 in `check-netscript-jsr-specifiers.ts`), leaving all other content in the file scannable. The `PATH_ALLOWANCES` map is deleted entirely. + +### Independent re-verification + +| Gate | Command | Result | Evidence | +| --------------------------------------------- | ----------------------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- | +| Focused validator test | `deno test .llm/tools/validation/check-netscript-jsr-specifiers_test.ts` | PASS | 1 passed, 0 failed. Test asserts `result.allowances === []` (zero allowances) and 2 findings (README-excluded specifiers). | +| Full JSR specifier guard | `deno task check:netscript-jsr-specifiers` | PASS | `scanned=2156 allowances=1 failures=0`. The sole allowance is the pre-existing scaffold import-map alias (line 29), not new. | +| No-new-suppressions in generated file | `grep "jsr-versionless-ok:" publish-assets.generated.ts` | PASS | Zero matches; no suppression marker added to the generated file. | +| Masking scope (non-README specifiers visible) | test fixture adds `export const EXECUTED = 'deno run jsr:@netscript/cli'` | PASS | Test asserts this is reported as finding #1 (`specifier: 'jsr:@netscript/cli'`), proving masking is scoped to the README only. | + +### Constraint satisfaction + +- **No new `jsr-versionless-ok:` markers**: verified zero matches across all newly changed or generated files. +- **No blanket path allowances**: `PATH_ALLOWANCES` map deleted; only inline markers on specific lines survive. +- **Semantic masking, not suppression**: the `MCP_PACKAGE_README` initializer is masked by character-level replacement (quote-aware, escape-aware), leaving `MCP_PACKAGE_VERSION` and any other generated constants fully scannable. +- **Test enforces zero new allowances**: `assertEquals(result.allowances, [])` at line 25 of the test is a regression lock against future blanket suppressions. + ## Verdict | Field | Value | | --------- | -------- | | Verdict | `PASS` | -| Rationale | Plan-Gate `PASS` precedes implementation; design checkpoint present and followed; 4 slices implemented in the design order with passing per-slice gates; MCP package checks, tests (45/45), focused scanner tests (7/7), release-cut tests (6/6), freshness green/red, preflight green/red, MCP publish dry-run, changed-file quality scan (0 findings), `arch:check` (baseline warnings only), and skill mirror sync all independently verified by the evaluator; consumer import paths correctly wired to generated constants; README and package metadata byte-identical to their sources; release cut regenerates publish assets after the version bump and stages all 8 generated outputs; CI enforces freshness on every PR. No new architecture debt created or deepened; `arch-debt.md` unchanged and correctly reflects the run. PR #810 metadata is correct: draft state, `status:impl-eval` label, no closing keyword for the already-closed #808 reference. Opposite-family ordinary review (session `12b534fe-2771-462a-b012-c61c91968f2a`) ended `REVIEW: PASS` after its release-cut finding was addressed via `169e2544`. The two-cycle IMPL-EVAL history (cycle 1 = FAIL_FIX for missing sunset criterion in preflight message and release-cut integration; both addressed by owner and verified by the ordinary review session) is consistent with the approved plan scope. | +| Rationale | Plan-Gate `PASS` precedes implementation; design checkpoint present and followed; 4 slices implemented in the design order with passing per-slice gates; MCP package checks, tests (45/45), focused scanner tests (7/7), release-cut tests (6/6), freshness green/red, preflight green/red, MCP publish dry-run, changed-file quality scan (0 findings), `arch:check` (baseline warnings only), and skill mirror sync all independently verified by the evaluator; consumer import paths correctly wired to generated constants; README and package metadata byte-identical to their sources; release cut regenerates publish assets after the version bump and stages all 8 generated outputs; CI enforces freshness on every PR. No new architecture debt created or deepened; `arch-debt.md` unchanged and correctly reflects the run. PR #810 metadata is correct: draft state, `status:impl-eval` label, no closing keyword for the already-closed #808 reference. Opposite-family ordinary review (session `12b534fe-2771-462a-b012-c61c91968f2a`) ended `REVIEW: PASS` after its release-cut finding was addressed via `169e2544`. The two-cycle IMPL-EVAL history (cycle 1 = FAIL_FIX for missing sunset criterion in preflight message and release-cut integration; both addressed by owner and verified by the ordinary review session) is consistent with the approved plan scope. **The no-new-suppressions constraint is satisfied**: commit `17d287dc` replaces the concurrent blanket path allowance with scoped semantic masking of only the `MCP_PACKAGE_README` initializer; `check:netscript-jsr-specifiers` reports 0 failures and 1 allowance (the pre-existing scaffold import-map alias, not new); the focused test enforces zero new allowances and two live findings outside the embedded docs initializer. | OPENHANDS_VERDICT: PASS diff --git a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md index 3091d3bb0..e51765f35 100644 --- a/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md +++ b/.llm/runs/fix-mcp-readme-text-import--beta10-jsr-hotfix/worklog.md @@ -66,6 +66,7 @@ Update the source README/schema/package metadata, run the publish-assets generat | 2026-07-17 | 4 | ordinary review | Separate opposite-family Claude Opus session `12b534fe-2771-462a-b012-c61c91968f2a` found one latent release-cut drift path; final follow-up verdict is `REVIEW: PASS`. | | 2026-07-17 | 4 | review fix | `release:cut` now regenerates publish assets after the version bump and stages all eight generated outputs; CI runs `check:publish-assets` beside `check:assets-barrel`; release skill mirrors document both steps. | | 2026-07-17 | 4 | IMPL-EVAL | Separate local Qwen session `e12ca085-a89a-4bc7-b144-5482f8b4289f` independently reran the required gates and returned `PASS`; artifact `evaluate.md`. | +| 2026-07-17 | 4 | no-suppression recheck | Replaced a concurrent generated-file path allowance with semantic README-initializer classification in `17d287dc`; the same formal evaluator reran the focused/full guards and retained `PASS` with zero new allowances. | ## Decisions