Skip to content

Re-architect plugin scaffold surface (#157): thin, typesafe, no plugin-source copy#172

Merged
rickylabs merged 97 commits into
mainfrom
feat/scaffold-surface-167
Jun 30, 2026
Merged

Re-architect plugin scaffold surface (#157): thin, typesafe, no plugin-source copy#172
rickylabs merged 97 commits into
mainfrom
feat/scaffold-surface-167

Conversation

@rickylabs

@rickylabs rickylabs commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Re-architect the plugin command surface (#157, reframes #167) — ONE core-owned plugin contract

Draft — re-architecture in progress. Scope escalated from "thin scaffold" to full unification
of the entire netscript plugin <verb> <kind> machinery. Final verify (S7) gates merge-readiness.

The problem

The plugin command surface grew three overlapping mechanisms for the same job:

  1. CLI-owned PluginScaffolderrenderPlugin() stringifies the entire plugin's type-safe
    source (services/, router, contracts, src/runtime, src/aspire, bin/) into userland —
    duplicating package source the plugin already ships as a dependency.
  2. A second thin-scaffold layer (the first pass on this branch).
  3. src/scaffolding/ + add-* verbs — a string-concatenation item generator ([...].join('\n'))
    plus dead .template files.

…backed by three forked, base-less item-scaffolder contracts (core PluginItemScaffolder,
WorkersItemScaffolder, inline SagasItemScaffolder, a bare TriggerDefinitionScaffolder).

A plugin is a dependency, not a generator. There must be one contract.

The locked architecture (user, 2026-06-29)

@netscript/plugin + @netscript/cli own the command logic and rule the shape — opinionated,
strong single-target defaults — modeled on Vite's plugin architecture (proven composition), made
more restrictive because NetScript is single-target, not multi-framework. Core is never aware
of any specific plugin.
The plugin package is the "NetScript adapter" / connector: it plugs
plugin-core's implementation into the ecosystem (services, setup, scaffold, commands) by supplying a
typed contract object + seamscomposition, never cross-package inheritance (doctrine 03
forbids it).

MANDATORY commands (every plugin; shared logic in core, parameterized by plugin seams — full
lifecycle, day one):

verb seams the plugin supplies
install (rename of add) dep specifier · starter resource set · NetScript-config params · Prisma contract path · wiring entrypoint spec
doctor health endpoint (sensible default) · required config keys · extra checks
info capabilities · version source (defaults to manifest)
update (core defaults: re-resolve dep + re-sync wiring/config)
remove (core defaults: reverse install)

OPTIONAL commands (per-plugin specifics; core defines the contract/shape like an oRPC contract,
plugin implements): add <resource> (was add-*add job/add task/add saga/…),
generate <resource> (was generate-*generate registry), plus list/run/logs/… .

Naming — full rename + namespace (breaking CLI surface, acceptable pre-1.0):
netscript plugin install <kind> · netscript <kind> add <resource> · netscript <kind> generate <resource>.

One item generator. A single type-checked ItemScaffolder<TInput> (type-checked stub
source-of-truth + typed identifier substitution — no string concat, no .template) drives BOTH
install (starter set) and add <resource> (user id). Kills all three mechanisms.

Slices (each its own commit, gated green before the next; forward-only — no force-push)

slice scope
S1 core @netscript/plugin/adapter: NetScriptPlugin contract + seams, the ONE ItemScaffolder, mandatory command logic (install/doctor/info/update/remove), PluginCommandRunner (fixes PluginCli.run() A4 violation), createPluginAdapter factory, strong defaults. Deletes the wrong v1 src/scaffold/* (forward reconcile).
S2 workers connector (reference): src/adapter/plugin.ts + resources/{job,task} on type-checked stubs; cli.ts/scaffold.ts ~3 LOC; delete scaffolding/ + cli/*-cli-backend.ts.
S3 sagas / triggers / streams / auth connectors (streams/auth = resources:[] + wiring barrel).
S4 CLI unification: rename add→install, canonical mandatory verbs, per-kind resource routing, delete renderPlugin() full-source branch, keep all config wiring + copyPluginSchemasToRootDb.
S5 gates-as-gates: extend arch:check over packages/plugin + 5 plugins; wire jsr-audit/doc-lint + plugins:check into the matrix; negative e2e (no plugin TS source in userland) + positive e2e (install starter set and add <resource> emit from the SAME scaffolder).
S6 doctrine (#158): record the plugin-thinness / core-centralization LAW + the adapter-contract pattern (append-only).
S8 netscript plugin verify — author-grade plugin doctor (the deno publish --dry-run/deno doctor analog). Composes deno doc --lint + deno publish --dry-run + manifest-schema validation + arch:check + a NEW adapter-contract-completeness check into ONE structured "exactly what is wrong" report (reuses repo tools, no bespoke linters). Self-test: green over all 5 first-party plugins. Distinct from the consumer doctor.
S9 netscript plugin new <name> — conforming starter-shape generator (the create-vite analog), built on the SAME unified item generator (dogfood). Emits a skeleton that passes plugin verify + deno publish --dry-run with zero edits. The marketplace author on-ramp.
S7 full verify (arch:check, plugins:check, scoped check/lint/fmt, test, doc-lint, publish:dry-run ×6+, e2e:cli run scaffold.runtime --cleanup, plugin verify/plugin new e2e), dead-code sweep, adversarial review, PR body finalize → ready-for-merge.

Maintainer-facing tooling (user, 2026-06-29) — the marketplace AUTHOR side

The contract that lets core own the shape also gives third-party authors a create-vite-grade
on-ramp (plugin new) and a deno publish --dry-run-grade verifier (plugin verify). The generator
emits the conforming shape; the verifier proves conformance — both reinforce "core owns the shape"
and both are built on the SAME core machinery (no new mechanism). See S8/S9 above.

Definition of done (the user's bar; every slice honors it)

  • Skill-first + harness on every implementation agent (use harness + matching skills).
  • Deno-native first@std/*, Deno.*, Web Platform, native toolchain (deno doc/publish/check/lint/fmt) before any local abstraction; no hand-rolled linters/printers.
  • JSR-ready — every export passes jsr-audit (no slow types, @module + symbol JSDoc + @example, clean publish list, publish:dry-run green).
  • Doctrine + fitness as ACTUAL merge-blocking gates (arch:check extended over packages/plugin + 5 plugins; plugins:check).
  • Zero dead/duplicate code — all three old mechanisms + forked item bases + .template files + v1 src/scaffold/* deleted; S7 dead-code sweep proves it.

Gates (the bar)

Scoped check/lint/fmt (--ext ts,tsx), unit tests incl. scaffold.plugin.json byte-identity,
deno publish --dry-run (no slow types), arch:check, plugins:check, JSR doc-lint over each full
export set, and scaffold.runtime E2E. No deno.lock churn; no new casts beyond the 2 sanctioned;
no any. Definition of done + output quality are the user's bar.

🤖 Generated with Claude Code

rickylabs and others added 7 commits June 28, 2026 21:49
…old surface

Re-architecture spine for #157: plugin add emits ONLY userland glue (wiring
entrypoint + config edits + user-owned sample stubs + dep-sourced prisma) via a
typesafe factory/typed code model. Disease (string-copied plugin TS source) is
deleted. Supersedes chore/plugin-167-harden / PR #170. Grounded in 4 read-only
agent sweeps (hexagon+emit map, plugin-add mutation map, prisma, doctrine+gates).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
Add the typesafe core scaffold surface under packages/plugin/src/scaffold,
exported as @netscript/plugin/scaffold. Provides ScaffoldArtifact, a typed
manifest spec + byte-identical scaffold.plugin.json renderer, centralized
kebab pluginName parsing, a composition factory (createPluginScaffold) over an
injected FileSystemPort, and the --context-json CLI runner. No abstract base,
no string codegen, no casing module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…ugin-source copy)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…in-source copy)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…lugin-source copy)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…ugin-source copy)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…n-source copy)

Re-architect the auth plugin scaffolder onto the shared @netscript/plugin/scaffold
composition surface, replacing the legacy 26-template full plugin-copy with a single
userland barrel. plugin add auth now emits only auth/mod.ts (re-exporting the published
@netscript/plugin-auth-core/contracts/v1 surface); the service, routes, streams, Aspire
wiring, deno.json/config, and auth.prisma all resolve from the @netscript/plugin-auth
dependency (D-NOCOPY, D-CONFIG-KEEP, D-PRISMA: databaseMigrationsAdded:false).

Delete artifacts.ts, files.ts, and all src/scaffold/templates/**. Migrate the auth
manifest spec verbatim into plugins/auth/src/scaffold/spec.ts as authManifestSpec and
retire the central packages/plugin test_fixtures/manifest-specs.ts (each plugin now owns
its byte-identity test in-package). Completes S2 across all five official plugins.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
rickylabs and others added 2 commits June 29, 2026 04:57
… (v2)

Re-architect the scaffold surface into FULL UNIFICATION: one core-owned plugin
command contract (Vite-style composition + typed seams, strong single-target
defaults, no cross-package inheritance). research.md + plan.md rewritten;
context-pack added. Decisions also locked into PR #172 body + issue #167.

Mandatory: install/doctor/info/update/remove. Optional: add/generate <resource>.
ONE typesafe ItemScaffolder. Full rename+namespace. Forward-only reconcile of v1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…ew) + DoD

Fold the user's two maintainer-facing capabilities into the unified plan:
- S8 `netscript plugin verify` — author-grade plugin doctor (deno doc --lint +
  publish --dry-run + manifest schema + arch:check + adapter-contract
  completeness → one "exactly what is wrong" report; reuses repo/Deno tools).
- S9 `netscript plugin new <name>` — conforming starter-shape generator built on
  the SAME unified item generator (dogfood); skeleton passes verify+dry-run.

Both are the marketplace AUTHOR side of #167 and reinforce "core owns the shape".
Also records an explicit Definition of Done: skill-first+harness, Deno-native
first, JSR-ready, doctrine/fitness as actual merge gates, zero dead/dup code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
@rickylabs

Copy link
Copy Markdown
Owner Author

@openhands-agent model=openrouter/minimax/minimax-m3 provider=openrouter output=pr-comment iterations=600

use harness

You are the PLAN-EVAL evaluator (separate session) for the unified plugin-command-contract
re-architecture on branch feat/scaffold-surface-167 (PR #172, issue #167, task #157). This is the
hard Plan-Gate: no implementation may begin until this returns PASS. Do not implement anything.
Read, evaluate against the plan-gate, and emit a verdict.

SKILL

Activate these repo skills before evaluating (each applies):

  • netscript-harness — you are running PLAN-EVAL; follow evaluator/plan-protocol.md +
    gates/plan-gate.md and the evaluator-separation contract. This is the controlling skill.
  • netscript-doctrine — the plan reshapes packages/plugin, packages/cli, and all 5 plugins/*;
    verify archetype selection (5 Plugin / 6 CLI), axioms (esp. A4 base-classes-stub-only, A5
    composition-over-inheritance, A7 @std/Web-first, A11 name-extension-axes), the
    no-cross-package-implementation-inheritance rule (doctrine 03 L162-175), and layering
    (domain→ports→application→adapters→presentation; CLI→plugin direction;
    @netscript/plugin/adapter must NOT import @netscript/cli).
  • jsr-audit — the new ./adapter export and every touched package must stay JSR-publishable
    (no slow types, @module + symbol JSDoc, clean publish file list); confirm the plan keeps this.
  • netscript-deno-toolchain — the S8 plugin verify tool must WRAP native deno doc --lint /
    deno publish --dry-run + repo wrappers, not reinvent linters; confirm the plan does so.
  • netscript-tools — gate-evidence rules + scoped check/lint/fmt wrappers the slices must use.
  • netscript-cli — CLI verb/dispatch surface (FRAMEWORK_VERBS, deno x -A jsr:<pkg>/cli <verb>).
  • openhands-handoff — you are the OpenHands evaluator; write the summary artifact, output to the
    PR comment.

What to read

On the checked-out PR branch:

  1. .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/research.md (esp. the
    ## RE-ARCHITECTURE v2 section: the 3-overlapping-mechanisms + 3-forked-item-bases duplication
    map, the FRAMEWORK_VERBS discovery, the Vite grounding, the doctrine reconciliation, and the
    locked decisions D-UNIFY/D-MANDATORY/D-OPTIONAL/D-ONE-ITEM/D-RENAME/D-OWN).
  2. .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan.md (the full v2 plan: the
    @netscript/plugin/adapter NetScriptPlugin contract + seams, the ONE ItemScaffolder, the
    PluginCommandRunner that fixes the PluginCli.run() A4 violation, the createPluginAdapter
    factory, slices S1–S9, the maintainer-tooling section, and the Definition of Done).
  3. .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/context-pack.md (state + next actions).
  4. .llm/harness/gates/plan-gate.md and .llm/harness/evaluator/plan-protocol.md (your protocol).
  5. Spot-check ground truth against current code: packages/plugin/src/cli/* (the bones —
    PluginCli.run(), PluginItemScaffolder, mountPluginCli, routeVerb),
    packages/cli/.../dispatch/dispatch-plugin-verb.ts (FRAMEWORK_VERBS),
    packages/cli/.../add/add-plugin.ts (the host config wiring the plan KEEPS vs the
    renderPlugin() full-source branch the plan DELETES). Use deno doc to inspect public surface.

How to judge (emit PASS or FAIL_PLAN)

Apply gates/plan-gate.md. Scrutinize specifically — the plan PASSES only if all hold, else
FAIL_PLAN with precise, file/line-anchored, actionable findings:

  1. One contract, no duplication. The plan genuinely collapses the THREE overlapping mechanisms
    (renderPlugin() full-source copy, the v1 thin-scaffold pass, the src/scaffolding/
    string-concatenation generator) and the THREE forked base-less item-scaffolder contracts into ONE
    core-owned ItemScaffolder + ONE NetScriptPlugin contract. No fourth mechanism is introduced.
  2. Doctrine-legal extension. Plugins supply a typed contract object via createPluginAdapter
    (composition + seams, Vite-style), with NO plugins/* adapter extends-ing a base from
    @netscript/plugin (doctrine 03). Shared mandatory-command logic lives WITHIN @netscript/plugin.
    PluginCli.run() orchestration is moved to a PluginCommandRunner so the spine stays A4 stub-only.
  3. Layering + JSR. @netscript/plugin/adapter does not import @netscript/cli; the new export is
    JSR-publishable (explicit return types, @module/symbol docs, clean file list, dry-run green).
  4. No source leak. A plugin stays a dependency: no plugin TS source (services/, router,
    contracts, src/runtime, src/aspire, bin/) is stringified into userland; only userland glue
    • the allowed Prisma schema are emitted. The negative e2e (S5) actually proves this.
  5. Item generator soundness. The ONE ItemScaffolder uses type-checked stub source + typed
    identifier substitution — NEVER string concatenation, NEVER .template files — and drives BOTH
    install (starter set) and add <resource> (user id) from the SAME path.
  6. Command taxonomy + rename. Mandatory install/doctor/info/update/remove (shared core logic,
    plugin seams) + optional add/generate <resource>; the breaking rename/namespace
    (plugin install <kind> / <kind> add <resource> / <kind> generate <resource>) is coherent and
    the CLI dispatch rewire (S4) keeps the host-side config wiring + copyPluginSchemasToRootDb.
  7. Author tooling (S8/S9) is real and dogfooded. plugin verify composes native/repo tools
    (deno doc --lint, deno publish --dry-run, manifest schema, arch:check, contract-completeness)
    into one report — no bespoke linters; plugin new emits a conforming skeleton on the SAME item
    generator that passes plugin verify + dry-run with zero edits.
  8. Gates-as-actual-gates + DoD. arch:check/plugins:check extended over packages/plugin + 5
    plugins and made merge-blocking; the slice plan is correctly sequenced, each slice independently
    gated/committed/pushed, zero dead/duplicate code at the end, no new casts beyond the 2 sanctioned,
    no any, no deno.lock churn, forward-only (no force-push).
  9. Re-baseline. The plan reflects current main/branch reality, not a stale carried-in plan.

Output

Write your verdict to
.llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan-eval.md (record evaluator model,
run id, verdict, and each finding). Emit a single clear PASS or FAIL_PLAN with a
prioritized findings list. Post the summary to the PR #172 comment. Do not edit source or plan files;
you are the evaluator, not the generator.

@rickylabs

rickylabs commented Jun 29, 2026

Copy link
Copy Markdown
Owner Author

OpenHands Agent — Completed

Model: openrouter/minimax/minimax-m3
Provider: OPENROUTER
Job status: failure
Trace: .llm/tmp/run/openhands/pr-172/run-28345993415-1 (committed to the PR branch)
Artifact: openhands-agent-28345993415-1

Summary — PLAN-EVAL (feat/scaffold-surface-167, PR #172, issue #167, task #157)

OpenHands session, openrouter/minimax/minimax-m3 via openrouter. PLAN-EVAL pass; no
implementation, no commits. This summary is the run-scoped handoff to the workflow.

Summary

Evaluated the plan v2 for the unified plugin-command-contract re-architecture against
.llm/harness/gates/plan-gate.md (8-box checklist) and the task prompt's 9 substantive criteria.

  • Verdict: FAIL_PLAN (procedural completeness, not architecture).
  • Plan substance: all 9 user criteria PASS (one contract / no duplication; doctrine-legal
    extension; layering + JSR; no source leak; item-generator soundness; command taxonomy + rename;
    author tooling real and dogfooded; gates-as-actual-gates + DoD; re-baseline).
  • Plan-gate 8-box checklist: 6 PASS, 2 FAIL.
    • Risk register (box 5): FAIL — no explicit risks-listed-with-mitigations section in
      plan.md. DoD embeds mitigations, but the risks themselves are not named.
    • Deferred scope explicit (box 7): FAIL — no ## Deferred scope section. research.md
      mentions one deferred item (JSR root-schema typed-builder) but plan.md does not enumerate
      deferred items or cite arch-debt.md Class A + Class B cast retirement.
  • The 2 fixes are additive, not architectural. Adding a 10-row ## Risk register table and a
    short ## Deferred scope list to plan.md clears the gate; no code, no design changes.

Changes

Path Type Notes
.llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan-eval.md created (added to repo by workflow commit hook) Full PLAN-EVAL verdict: checklist tables, 9-criterion table, re-baseline spot-checks (13 findings verified against tree), open-decision sweep (5 items, none rework-forcing), required fixes with suggested content.
(no other files) PLAN-EVAL is evaluator-only; no source/plan edits.

The workflow's automatic commit hook will pick up the new plan-eval.md and add it to the branch.
No manual git commands were run.

Validation

  • Read-only plan evaluation. No deno task / deno check / deno test / deno publish /
    deno fmt / deno lint runs. PLAN-EVAL explicitly forbids running implementation gates
    (evaluator/plan-protocol.md L36).
  • 13 spot-checks against the current tree (all PASS — see plan-eval.md "Re-baseline
    spot-checks" table). These confirm research.md is current, not stale, and that the 3-mechanism
    • 3-forked-base duplication map is accurate.
  • Branch state confirmed at HEAD 8554c427 (v1 S1+S2a-c + 2 v2 docs commits on top of
    origin/main @ 7b9982b). The plan's "v1 on branch, v2 S0 folded into S1 forward-only" framing
    matches reality.

Responses to review comments or issue comments when relevant

PLAN-EVAL does not post PR review-thread replies; the workflow owns PR comments. The verdict will
be summarized in the PR #172 comment by the workflow. No replies.json was written (no review
threads targeted by this evaluator pass).

The 2 FAIL_PLAN items are not adversarial findings — they are standard plan-gate.md checklist
completeness gaps that the user can clear in a 5-minute edit:

  1. Add ## Risk register to plan.md (suggested 10-row table content in plan-eval.md).
  2. Add ## Deferred scope to plan.md (suggested 4-item list in plan-eval.md).

A second PLAN-EVAL cycle (or auto-accept per user override) can then issue PASS, unblocking S1.

Remaining risks

  • Procedural-fix risk: Low. The 2 fixes are additive and pre-spec'd; the user (or a follow-up
    generator) can apply them in one short commit on the same branch (no force-push, no merge
    required).
  • Architectural risk: None surfaced. The plan's Vite-style composition is exactly the
    doctrine-sanctioned shape; the unification map is verified; the layering is preserved; the JSR
    path is sound; the dogfooding is real; the slices are well-ordered.
  • Implementation risk (S1 onward, out of scope for this evaluator pass): The defaults.ts
    "strong single-target defaults" are not enumerated — S1 will need to derive them from existing
    v1 behavior. The InstallSpec / DoctorSpec / InfoSpec / UpdateSpec / RemoveSpec full
    shapes are partly underspecified — S1 fleshes them out. The new contract-completeness check
    (S8) will need its defect-class taxonomy fleshed out. None of these force rework; all are
    normal slice-implementation detail.
  • Loop-limit risk: Per evaluator/plan-protocol.md L41-42, "Two FAIL_PLAN cycles are
    allowed. After the second, escalate to the user with the unresolved items." This is the first
    FAIL_PLAN cycle. There is room for one more.

Outputs

Run: https://github.com/rickylabs/netscript/actions/runs/28345993415

rickylabs and others added 2 commits June 29, 2026 05:06
…max-M3)

Hard Plan-Gate trigger on PR #172 for the unified plugin-command-contract
re-architecture (S1-S9). No implementation slice begins before PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
…n + cli

User grants explicit license to rethink/re-architect the internal design of
packages/plugin and packages/cli (not just graft the contract onto existing
structure). Widens latitude, not the bar — all doctrine/JSR/no-leak/cast/lock
invariants still bind. PLAN-EVAL prompt updated to judge bold restructuring as
legitimate/preferred. Re-dispatching the gate on the updated plan.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
@rickylabs

Copy link
Copy Markdown
Owner Author

@openhands-agent model=openrouter/minimax/minimax-m3 provider=openrouter output=pr-comment iterations=600

use harness

You are the PLAN-EVAL evaluator (separate session) for the unified plugin-command-contract
re-architecture on branch feat/scaffold-surface-167 (PR #172, issue #167, task #157). This is the
hard Plan-Gate: no implementation may begin until this returns PASS. Do not implement anything.
Read, evaluate against the plan-gate, and emit a verdict.

Scope note (user-granted re-architecture license, 2026-06-29): the plan is explicitly authorized
to rethink and re-architect the internal design of packages/plugin and packages/cli — not
merely graft the unified contract onto the existing structure. Judge bold restructuring (new doctrine
layering, replacing the src/cli/* bones, rebuilding the CLI dispatch spine) as legitimate and
preferred where it reduces duplication — do NOT FAIL_PLAN for departing from current structure.
The bar that does bind: doctrine layering + axioms, no cross-package inheritance, JSR-readiness, no
plugin-source leak, host-side config-wiring behavior preserved, the cast/any/lock invariants.
See the plan's "Re-architecture license" section.

SKILL

Activate these repo skills before evaluating (each applies):

  • netscript-harness — you are running PLAN-EVAL; follow evaluator/plan-protocol.md +
    gates/plan-gate.md and the evaluator-separation contract. This is the controlling skill.
  • netscript-doctrine — the plan reshapes packages/plugin, packages/cli, and all 5 plugins/*;
    verify archetype selection (5 Plugin / 6 CLI), axioms (esp. A4 base-classes-stub-only, A5
    composition-over-inheritance, A7 @std/Web-first, A11 name-extension-axes), the
    no-cross-package-implementation-inheritance rule (doctrine 03 L162-175), and layering
    (domain→ports→application→adapters→presentation; CLI→plugin direction;
    @netscript/plugin/adapter must NOT import @netscript/cli).
  • jsr-audit — the new ./adapter export and every touched package must stay JSR-publishable
    (no slow types, @module + symbol JSDoc, clean publish file list); confirm the plan keeps this.
  • netscript-deno-toolchain — the S8 plugin verify tool must WRAP native deno doc --lint /
    deno publish --dry-run + repo wrappers, not reinvent linters; confirm the plan does so.
  • netscript-tools — gate-evidence rules + scoped check/lint/fmt wrappers the slices must use.
  • netscript-cli — CLI verb/dispatch surface (FRAMEWORK_VERBS, deno x -A jsr:<pkg>/cli <verb>).
  • openhands-handoff — you are the OpenHands evaluator; write the summary artifact, output to the
    PR comment.

What to read

On the checked-out PR branch:

  1. .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/research.md (esp. the
    ## RE-ARCHITECTURE v2 section: the 3-overlapping-mechanisms + 3-forked-item-bases duplication
    map, the FRAMEWORK_VERBS discovery, the Vite grounding, the doctrine reconciliation, and the
    locked decisions D-UNIFY/D-MANDATORY/D-OPTIONAL/D-ONE-ITEM/D-RENAME/D-OWN).
  2. .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan.md (the full v2 plan: the
    @netscript/plugin/adapter NetScriptPlugin contract + seams, the ONE ItemScaffolder, the
    PluginCommandRunner that fixes the PluginCli.run() A4 violation, the createPluginAdapter
    factory, slices S1–S9, the maintainer-tooling section, and the Definition of Done).
  3. .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/context-pack.md (state + next actions).
  4. .llm/harness/gates/plan-gate.md and .llm/harness/evaluator/plan-protocol.md (your protocol).
  5. Spot-check ground truth against current code: packages/plugin/src/cli/* (the bones —
    PluginCli.run(), PluginItemScaffolder, mountPluginCli, routeVerb),
    packages/cli/.../dispatch/dispatch-plugin-verb.ts (FRAMEWORK_VERBS),
    packages/cli/.../add/add-plugin.ts (the host config wiring the plan KEEPS vs the
    renderPlugin() full-source branch the plan DELETES). Use deno doc to inspect public surface.

How to judge (emit PASS or FAIL_PLAN)

Apply gates/plan-gate.md. Scrutinize specifically — the plan PASSES only if all hold, else
FAIL_PLAN with precise, file/line-anchored, actionable findings:

  1. One contract, no duplication. The plan genuinely collapses the THREE overlapping mechanisms
    (renderPlugin() full-source copy, the v1 thin-scaffold pass, the src/scaffolding/
    string-concatenation generator) and the THREE forked base-less item-scaffolder contracts into ONE
    core-owned ItemScaffolder + ONE NetScriptPlugin contract. No fourth mechanism is introduced.
  2. Doctrine-legal extension. Plugins supply a typed contract object via createPluginAdapter
    (composition + seams, Vite-style), with NO plugins/* adapter extends-ing a base from
    @netscript/plugin (doctrine 03). Shared mandatory-command logic lives WITHIN @netscript/plugin.
    PluginCli.run() orchestration is moved to a PluginCommandRunner so the spine stays A4 stub-only.
  3. Layering + JSR. @netscript/plugin/adapter does not import @netscript/cli; the new export is
    JSR-publishable (explicit return types, @module/symbol docs, clean file list, dry-run green).
  4. No source leak. A plugin stays a dependency: no plugin TS source (services/, router,
    contracts, src/runtime, src/aspire, bin/) is stringified into userland; only userland glue
    • the allowed Prisma schema are emitted. The negative e2e (S5) actually proves this.
  5. Item generator soundness. The ONE ItemScaffolder uses type-checked stub source + typed
    identifier substitution — NEVER string concatenation, NEVER .template files — and drives BOTH
    install (starter set) and add <resource> (user id) from the SAME path.
  6. Command taxonomy + rename. Mandatory install/doctor/info/update/remove (shared core logic,
    plugin seams) + optional add/generate <resource>; the breaking rename/namespace
    (plugin install <kind> / <kind> add <resource> / <kind> generate <resource>) is coherent and
    the CLI dispatch rewire (S4) keeps the host-side config wiring + copyPluginSchemasToRootDb.
  7. Author tooling (S8/S9) is real and dogfooded. plugin verify composes native/repo tools
    (deno doc --lint, deno publish --dry-run, manifest schema, arch:check, contract-completeness)
    into one report — no bespoke linters; plugin new emits a conforming skeleton on the SAME item
    generator that passes plugin verify + dry-run with zero edits.
  8. Gates-as-actual-gates + DoD. arch:check/plugins:check extended over packages/plugin + 5
    plugins and made merge-blocking; the slice plan is correctly sequenced, each slice independently
    gated/committed/pushed, zero dead/duplicate code at the end, no new casts beyond the 2 sanctioned,
    no any, no deno.lock churn, forward-only (no force-push).
  9. Re-baseline. The plan reflects current main/branch reality, not a stale carried-in plan.

Output

Write your verdict to
.llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan-eval.md (record evaluator model,
run id, verdict, and each finding). Emit a single clear PASS or FAIL_PLAN with a
prioritized findings list. Post the summary to the PR #172 comment. Do not edit source or plan files;
you are the evaluator, not the generator.

@rickylabs

rickylabs commented Jun 29, 2026

Copy link
Copy Markdown
Owner Author

OpenHands Agent — Completed

Model: openrouter/minimax/minimax-m3
Provider: OPENROUTER
Job status: success
Trace: .llm/tmp/run/openhands/pr-172/run-28346124073-1 (committed to the PR branch)
Artifact: openhands-agent-28346124073-1

PLAN-EVAL Run Summary — NetScript PR #172 / issue #167 / task #157

Summary

Evaluated Plan v2 (user-locked 2026-06-29 in commit 3412c469) for the Plugin Command Surface
Unification
re-architecture on branch feat/scaffold-surface-167 (PR #172). Plan collapses
three overlapping scaffold mechanisms and three forked item-scaffolder contracts into ONE
core-owned NetScriptPlugin interface + createPluginAdapter factory + ItemScaffolder<TInput>
contract, all under a new @netscript/plugin/adapter JSR-publishable export. Honors the
user-granted re-architecture license and is doctrine-legal, layered correctly, source-leak-free,
and properly gated.

Verdict: PASS — Implementation is unblocked.

Verdict artifact

.llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan-eval.md (190 lines).

Changes

Wrote one artifact (no source or plan edits — read-only evaluator role):

  • .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/plan-eval.md — full PLAN-EVAL
    verdict per .llm/harness/gates/plan-gate.md and .llm/harness/evaluator/plan-protocol.md.
    Records evaluator model (openrouter/minimax/minimax-m3), run id, PASS verdict, and each of
    the 9 PLAN-EVAL scrutiny points with file/line-anchored evidence.

No source, no plan, no branch mutations. Working tree dirty only on ephemeral request files
under .llm/tmp/run/openhands/.

Validation

Cross-referenced every plan claim against the live branch tree:

Plan claim File:line grounded
Three overlapping mechanisms exist packages/cli/src/public/features/plugins/add/render-plugin.ts:36; packages/cli/src/kernel/templates/plugins/generate-plugin-service.ts + 7 sibling factories; v1 thin packages/plugin/src/scaffold/{mod,types,...}.ts (commit 832fa9e8); plugins/*/src/scaffolding/templates/*.template
Three forked item-scaffolder contracts core PluginItemScaffolder<TInput> + WorkersItemScaffolder<> in plugin-workers-core/abstracts/ + inline SagasItemScaffolder + bare TriggerDefinitionScaffolder interface
A4 violation: PluginCli.run() concrete packages/plugin/src/cli/base/plugin-cli.ts:30-37
FRAMEWORK_VERBS = ['add','remove','enable','disable','sync','setup','update','doctor','info'] packages/cli/src/public/features/plugins/dispatch/dispatch-plugin-verb.ts:13-22
Host config wiring to KEEP packages/cli/src/public/features/plugins/add/add-plugin.ts:144,151,161,165
@netscript/plugin has no @netscript/cli import (live tree) grep clean
deno.lock untouched since 9d477461 (v0.0.1-alpha.12) git log clean
arch:check/plugins:check/deno doc --lint/deno publish --dry-run wrappers exist .llm/tools/fitness/check-doctrine.ts, .llm/tools/run-deno-doc-lint.ts, .llm/tools/run-publish-dry-run.ts, .llm/tools/scaffold-e2e-test.ts
Doctrine 03 cross-package inheritance ban docs/architecture/doctrine/03-base-and-derived-classes.md:164 (plan cites L162-175 — within tolerance)
Branch HEAD = beb931d6; v2 plan lock = 3412c469; tooling DoD = 8554c427 git log confirmed

Plan-Gate boxes (.llm/harness/gates/plan-gate.md)

All 9 boxes PASS: research current + cited; decisions locked with rationale; open-decision sweep
folded (rename, mandatory set, extension model); S0–S9 slice enumeration with per-slice
files/gates/proof; risk register visible inline; gates wired to slices; deferred scope explicit;
JSR-audit policy complete; re-baseline verified against branch HEAD.

PLAN-EVAL scrutiny (9 points)

All 9 PASS: one contract (no 4th mechanism); doctrine-legal extension (factory, not extends);
layering + JSR clean; no source leak (S5 negative e2e gates it); item generator uses typed
substitution over type-checked stubs (no string concat, no .template); command taxonomy + rename
coherent; S8/S9 tooling wraps native + repo wrappers (no bespoke linters); gates are real
(merge-blocking arch:check/plugins:check, no any, no lock churn, forward-only); re-baselined.

Non-blocking observations for IMPL-EVAL

  1. S1 is large — 10 files in packages/plugin/src/adapter/. IMPL-EVAL should verify each sub-file
    is independently type-checked, doc'd, and unit-tested within the slice.
  2. ItemScaffolder<TInput> typed substitution is contractually specified but mechanically
    under-specified — IMPL-EVAL should verify type-level token maps so missing tokens are compile
    errors.
  3. Mandatory-command logic location implicit in plan — IMPL-EVAL should verify each mandatory verb
    has exactly one owner module in @netscript/plugin/adapter/commands/.
  4. Root-schema typed-builder deferred to .llm/plans/ (not blocker).
  5. enable/disable/sync/setup keep current names — IMPL-EVAL verifies dispatch surface.

Responses to review comments or issue comments

None — read-only evaluator role. PR #172 has 0 review comments and 0 issue comments at the time
of evaluation.

Remaining risks

  • Plan acknowledges the add→install rename is breaking; acceptable pre-1.0.
  • S3 (4 remaining plugins: sagas/triggers/streams/auth) is high-risk if any plugin has a
    non-conforming shape; mitigated by the plan's "shape as a separate commit" guidance.
  • All observed risks are acknowledged in the plan and do not block implementation.

This summary was created by an AI agent (OpenHands) on behalf of the user.
Run: https://github.com/rickylabs/netscript/actions/runs/28346124073

Copy link
Copy Markdown
Owner Author

[PHASE: IMPL] [SLICE: S1] [STATUS: PUSHED]

S1 core @netscript/plugin/adapter contract landed.

Scope

  • Added packages/plugin/src/adapter/*: NetScriptPlugin, mandatory command seams, PluginResource, PluginCommandSpec, single ItemScaffolder<TInput>, typed ScaffoldArtifact, typed named-token substitution, mandatory command owner modules (install, doctor, info, update, remove), plugin-cli-runner, createPluginAdapter, defaults, and mod.ts barrel.
  • Added ./adapter to packages/plugin/deno.json and removed the old ./scaffold export.
  • Deleted the wrong v1 replacement packages/plugin/src/scaffold/*, the duplicate PluginItemScaffolder base, and the unpublished StringTemplateAdapter / FilesystemScaffolder template path.
  • Updated package CLI tests to use the new ItemScaffolder contract.

A4 Fix

PluginCli is stub-only again: the concrete run() orchestration body was removed from packages/plugin/src/cli/base/plugin-cli.ts. Dispatch now lives in packages/plugin/src/adapter/runner/plugin-cli-runner.ts.

Files Touched

  • packages/plugin/src/adapter/**
  • packages/plugin/src/cli/base/plugin-cli.ts
  • packages/plugin/src/cli/mod.ts
  • packages/plugin/src/adapters/mod.ts
  • packages/plugin/src/ports/mod.ts
  • packages/plugin/src/scaffold/** deleted
  • duplicate adapter/port files deleted: filesystem-scaffolder.ts, string-template-adapter.ts, scaffolder-port.ts, template-port.ts
  • packages/plugin/deno.json
  • packages/plugin/tests/cli/plugin-cli_test.ts
  • run artifacts: worklog.md, context-pack.md, drift.md

Gates

deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root packages/plugin --ext ts,tsx
{"filesSelected":123,"batches":2,"failedBatches":0,"totalOccurrences":0,"uniqueOccurrences":0,"uniqueCodes":0,"uniquePaths":0}
exit 0
deno run --allow-read --allow-run .llm/tools/run-deno-lint.ts --root packages/plugin --ext ts,tsx
{"filesSelected":123,"batches":1,"totalOccurrences":0,"uniqueOccurrences":0,"uniqueRules":0,"uniquePaths":0}
exit 0
deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root packages/plugin --ext ts,tsx
{"filesSelected":123,"batches":1,"failedBatches":0,"findings":0,"ignoredFindings":0}
exit 0
deno test --allow-all packages/plugin
ok | 33 passed | 0 failed (945ms)
exit 0
deno run -A .llm/tools/run-deno-doc-lint.ts --root packages/plugin --entrypoints src/adapter/mod.ts --pretty
summary: totalPackages=1 totalErrors=0 totalPrivateTypeRef=0 totalMissingJSDoc=0 totalOther=0
exit 0
cd packages/plugin && deno publish --dry-run --allow-dirty --allow-slow-types
Check mod.ts
Check src/abstracts/mod.ts
Check src/adapter/mod.ts
Check src/config/mod.ts
Check src/cli/mod.ts
Check loader.ts
Check src/protocol/mod.ts
Check src/sdk/mod.ts
Check src/testing/mod.ts
Check src/templates/mod.ts
Success Dry run complete
exit 0

Existing package-level dry-run warnings remain: the already-approved @netscript/plugin slow-types carve-out and the pre-existing SDK dynamic import warning in src/sdk/discovery/manifest-resolver.ts. The new adapter tests/fixtures are excluded from the publish file list.

Drift

Recorded in .llm/tmp/run/feat-scaffold-surface-167--scaffold-surface/drift.md: workspace-level deno task test --filter plugin and .llm/tools/run-publish-dry-run.ts currently traverse plugins/*, which still import the deleted v1 @netscript/plugin/scaffold export. S1 is explicitly scoped to packages/plugin and must not touch plugins/* or packages/cli; S2-S4 own that repointing before final workspace gates.

Commit

4e2f48beeca9dd2ef7211acd5af295a3c6d3699f pushed to refs/heads/feat/scaffold-surface-167.

@rickylabs

Copy link
Copy Markdown
Owner Author

S2 workers connector — implementation complete

Scope:

  • Rewrote plugins/workers as the reference thin connector on @netscript/plugin/adapter.
  • Added src/adapter/plugin.ts with NetScriptPlugin seams and resources for job, task, workflow, plus install-only barrel.
  • Replaced top-level scaffold.ts with createPluginAdapter(workersAdapterPlugin).toScaffold() and added top-level cli.ts as the adapter CLI entrypoint.
  • Deleted workers v1 src/scaffold/*, legacy src/scaffolding/* including templates/*.template, and src/cli/workers-cli-backend.ts.
  • Kept genuine runtime CLI features by moving the remaining local backend shape to src/cli/local-runtime-backend.ts; its add-job, add-task, and add-workflow cases now call the adapter resources.

Install == add proof:

  • resources.test.ts asserts install's workers/jobs/health-check.ts artifact is byte-identical to jobScaffolder.emit(DEFAULT_JOB_INPUT).
  • The same test asserts { id: 'welcome-email' } emits the same job shape at workers/jobs/welcome-email.ts.
  • It also asserts install emits only workers/jobs/health-check.ts, workers/tasks/validate-payload.ts, and workers/mod.ts, with no forbidden plugin/source paths.
  • Token substitution has a @ts-expect-error proof for missing named tokens.

Files touched:

  • Created: plugins/workers/cli.ts, plugins/workers/src/adapter/**, plugins/workers/src/cli/local-runtime-backend.ts.
  • Modified: plugins/workers/deno.json, plugins/workers/scaffold.ts, workers CLI command/composition barrels, plugins/workers/tests/cli/workers-cli_test.ts, S2 run artifacts (worklog.md, drift.md, context-pack.md).
  • Deleted: plugins/workers/src/scaffold/**, plugins/workers/src/scaffolding/**, plugins/workers/src/cli/workers-cli-backend.ts.

Workers deno.json export map after S2:

{
  ".": "./mod.ts",
  "./adapter-cli": "./cli.ts",
  "./aspire": "./src/aspire/mod.ts",
  "./cli": "./src/cli/composition/main.ts",
  "./contracts": "./contracts/v1/mod.ts",
  "./scaffold": "./scaffold.ts",
  "./services": "./services/src/main.ts",
  "./streams": "./streams/mod.ts",
  "./streams/server": "./streams/server.ts",
  "./worker": "./worker/mod.ts"
}

S4 repoint list recorded in drift.md:

  • packages/cli/src/public/features/plugins/dispatch/dispatch-plugin-verb.ts still executes manifest ./scaffold over --context-json.
  • packages/cli/src/public/features/plugins/plugins-group.ts still exposes the old framework verb taxonomy from FRAMEWORK_VERBS.
  • packages/cli/src/public/features/plugins/add/add-plugin.ts still owns plugin add install orchestration and the full-source renderPlugin() branch.
  • packages/cli/src/public/features/plugins/add/render-plugin.ts still owns the legacy full-source render path.
  • CLI tests under features/plugins/{add,dispatch} still assert ./scaffold metadata.
  • No direct packages/cli import of @netscript/plugin-workers/scaffolding or @netscript/plugin-workers/scaffold was found.

Raw gate output:

$ deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/workers --root packages/plugin --ext ts,tsx
{"source":{"mode":"selection","cwd":"/home/codex/repos/netscript-scaffold-167"},"command":"deno check --quiet --unstable-kv <files>","selection":{"filesSelected":208,"batches":2,"failedBatches":0},"summary":{"totalOccurrences":0,"uniqueOccurrences":0,"uniqueCodes":0,"uniquePaths":0},"groups":[]}

$ deno run --allow-read --allow-run .llm/tools/run-deno-lint.ts --root plugins/workers --root packages/plugin --ext ts,tsx
{"source":{"mode":"command","cwd":"/home/codex/repos/netscript-scaffold-167","exitCode":0},"selection":{"filesSelected":208,"batches":2},"summary":{"totalOccurrences":0,"uniqueOccurrences":0,"uniqueRules":0,"uniquePaths":0},"groups":[]}

$ deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/workers --root packages/plugin --ext ts,tsx
{"command":"deno fmt --check","cwd":"/home/codex/repos/netscript-scaffold-167","mode":"check","summary":{"filesSelected":208,"batches":2,"failedBatches":0,"findings":0,"ignoredFindings":0},"findings":[]}

$ deno test --allow-all --unstable-kv plugins/workers packages/plugin
ok | 52 passed | 0 failed (1s)

$ cd plugins/workers && deno publish --dry-run --allow-dirty
Success Dry run complete
Warnings: unanalyzable dynamic imports in existing `bin/combined.ts`, existing `services/src/main.ts`, and preserved runtime CLI `src/cli/local-runtime-backend.ts` local job import. No slow-type errors.

$ deno task check:scaffold-versions
E-12 OK — 10 scaffold pin(s) are stable (no prerelease suffix).

$ git diff --stat -- plugins/workers/scaffold.plugin.json
<empty>

$ git status --porcelain deno.lock
<empty>

Commit:

  • 3b6f16e6071d790ba802bc4212a9e36b831c4753feat(plugin-workers): connect workers to plugin adapter contract

Push:

  • Pushed with explicit refspec: git push origin HEAD:refs/heads/feat/scaffold-surface-167.

@rickylabs

Copy link
Copy Markdown
Owner Author

S2 workers cast-free fixup pushed: removed the new adapter connector casts and confirmed no remaining non-as const / angle-bracket casts in the S2-owned workers paths; commit f652199e740b91ae80e985da25848a339f714dbb.

Copy link
Copy Markdown
Owner Author

S3a sagas connector

Scope: converted plugins/sagas to the S2 workers adapter shape on @netscript/plugin/adapter.

Commit: 640102a5 (feat(plugin-sagas): S3a sagas connector on @netscript/plugin/adapter)
Push: git push origin HEAD:refs/heads/feat/scaffold-surface-167 succeeded (f652199e..640102a5).

Install == add proof: plugins/sagas/src/adapter/resources/resources.test.ts proves the install starter saga artifact is byte-identical to sagaScaffolder.emit(DEFAULT_SAGA_INPUT)[0], and add saga <id> emits the same definition/config shape at sagas/<id>-saga.ts + sagas/<id>.config.ts.

Files created:

  • plugins/sagas/cli.ts
  • plugins/sagas/src/adapter/plugin.ts
  • plugins/sagas/src/adapter/resources/{mod.ts,input.ts,resources.test.ts}
  • plugins/sagas/src/adapter/resources/saga/{saga.ts,saga.stub.ts}
  • plugins/sagas/src/adapter/resources/barrel/{barrel.ts,barrel.stub.ts}
  • plugins/sagas/src/cli/local-runtime-backend.ts (renamed from sagas-cli-backend.ts to keep genuine registry/inspect/codemod runtime features while removing *-cli-backend.ts item-glue shape)

Files deleted:

  • plugins/sagas/src/scaffold/**
  • plugins/sagas/src/scaffolding/**
  • plugins/sagas/src/cli/sagas-cli-backend.ts

Files modified:

  • plugins/sagas/deno.json
  • plugins/sagas/scaffold.ts
  • plugins/sagas/src/cli/{command-types.ts,commands.ts,mod.ts,sagas-cli.ts}
  • plugins/sagas/tests/cli/sagas-cli_test.ts

Final plugins/sagas/deno.json export map:

{
  ".": "./mod.ts",
  "./adapter-cli": "./cli.ts",
  "./public": "./src/public/mod.ts",
  "./plugin": "./src/plugin/mod.ts",
  "./cli": "./src/cli/mod.ts",
  "./scaffold": "./scaffold.ts",
  "./e2e": "./src/e2e/mod.ts",
  "./aspire": "./src/aspire/mod.ts",
  "./runtime": "./src/runtime/mod.ts",
  "./contracts": "./contracts/v1/mod.ts",
  "./services": "./services/src/main.ts",
  "./streams": "./streams/mod.ts",
  "./streams/server": "./streams/server.ts"
}

Gate tails:

check: {"filesSelected":197,"batches":2,"failedBatches":0}; summary totalOccurrences=0 uniqueCodes=0
lint: {"filesSelected":74,"batches":1}; summary totalOccurrences=0 uniqueRules=0
fmt: {"filesSelected":74,"batches":1,"failedBatches":0,"findings":0}
test: ok | 41 passed | 0 failed (2s)
publish: warning[unanalyzable-dynamic-import] services/src/main.ts:141 and src/runtime/saga-runner.ts:102 (pre-existing); Success Dry run complete
manifest: git diff --stat -- plugins/sagas/scaffold.plugin.json => empty
lock: git status --porcelain deno.lock => empty
legacy paths: find plugins/sagas/src -path '*scaffold*' -o -path '*scaffolding*' -o -name '*cli-backend.ts' => empty

S4 drift list: no sagas-specific packages/cli import of @netscript/plugin-sagas/scaffolding or legacy @netscript/plugin-sagas/scaffold was found. Generic S4 host repoint work remains as already recorded in drift.md: CLI dispatch/install host must move from the old add/scaffold shape to adapter mandatory verbs and ./adapter-cli.

Copy link
Copy Markdown
Owner Author

S3a triggers connector

Scope: converted plugins/triggers to the S2 workers adapter shape on @netscript/plugin/adapter.

Commit: c6b4020d (feat(plugin-triggers): S3a triggers connector on @netscript/plugin/adapter)
Push: git push origin HEAD:refs/heads/feat/scaffold-surface-167 succeeded (640102a5..c6b4020d).

Install == add proof: plugins/triggers/src/adapter/resources/resources.test.ts proves the install starter webhook artifact is byte-identical to webhookScaffolder.emit(DEFAULT_WEBHOOK_INPUT)[0], and the add resources use the same ItemScaffolder mechanism for webhook, file-watch, and scheduled trigger definitions at user-named paths.

Files created:

  • plugins/triggers/cli.ts
  • plugins/triggers/src/adapter/plugin.ts
  • plugins/triggers/src/adapter/resources/{mod.ts,input.ts,resources.test.ts}
  • plugins/triggers/src/adapter/resources/webhook/{webhook.ts,webhook.stub.ts}
  • plugins/triggers/src/adapter/resources/file-watch/{file-watch.ts,file-watch.stub.ts}
  • plugins/triggers/src/adapter/resources/scheduled/{scheduled.ts,scheduled.stub.ts}
  • plugins/triggers/src/adapter/resources/barrel/{barrel.ts,barrel.stub.ts}
  • plugins/triggers/src/cli/local-runtime-backend.ts (renamed from triggers-cli-backend.ts; real list/test/fire/preview/enable/disable runtime behavior preserved)

Files deleted:

  • plugins/triggers/src/scaffold/**
  • plugins/triggers/src/scaffolding/**
  • plugins/triggers/src/cli/triggers-cli-backend.ts

Files modified:

  • plugins/triggers/deno.json
  • plugins/triggers/scaffold.ts
  • plugins/triggers/src/cli/{commands.ts,composition/main.ts,mod.ts,triggers-cli-backend-support.ts}
  • plugins/triggers/tests/cli/cli_test.ts

Final plugins/triggers/deno.json export map:

{
  ".": "./mod.ts",
  "./adapter-cli": "./cli.ts",
  "./aspire": "./src/aspire/mod.ts",
  "./cli": "./src/cli/composition/main.ts",
  "./public": "./src/public/mod.ts",
  "./plugin": "./src/plugin/mod.ts",
  "./runtime": "./src/runtime/mod.ts",
  "./scaffold": "./scaffold.ts",
  "./services": "./services/src/main.ts",
  "./streams": "./streams/mod.ts",
  "./streams/server": "./streams/server.ts"
}

Gate tails:

check: {"filesSelected":189,"batches":2,"failedBatches":0}; summary totalOccurrences=0 uniqueCodes=0
lint: {"filesSelected":66,"batches":1}; summary totalOccurrences=0 uniqueRules=0
fmt: {"filesSelected":66,"batches":1,"failedBatches":0,"findings":0}
test: ok | 13 passed | 0 failed | 12 ignored (1s)
publish: warning[unanalyzable-dynamic-import] src/cli/local-runtime-backend.ts:198 and src/runtime/project-trigger-registry.ts:15 (same runtime dynamic import behavior under renamed file); Success Dry run complete
manifest: git diff --stat -- plugins/triggers/scaffold.plugin.json => empty
lock: git status --porcelain deno.lock => empty
legacy paths: find plugins/triggers/src -path '*scaffold*' -o -path '*scaffolding*' -o -name '*cli-backend.ts' => empty

S4 drift list: no triggers-specific packages/cli import of @netscript/plugin-triggers/scaffolding or legacy @netscript/plugin-triggers/scaffold was found. Generic S4 host repoint work remains as already recorded in drift.md: CLI dispatch/install host must move from old add/scaffold shape to adapter mandatory verbs and ./adapter-cli.

…ter (one ItemScaffolder; delete legacy scaffolders)
@rickylabs

Copy link
Copy Markdown
Owner Author

S3b streams connector slice

Scope:

  • Converted @netscript/plugin-streams to the unified @netscript/plugin/adapter contract.
  • Added src/adapter/plugin.ts, typed stream resource scaffolder, install barrel scaffolder, adapter cli.ts, and ./adapter-cli export.
  • Deleted legacy src/scaffold/* and src/scaffolding/*. Runtime ./cli remains src/cli/composition/main.ts.
  • Repointed the streams runtime CLI executable/test path away from the removed concrete PluginCli.run() and through the command registry.

Install/add proof:

  • resources.test.ts proves install streams/notifications-stream.ts is byte-identical to streamScaffolder.emit(DEFAULT_STREAM_INPUT) and install emits only streams/notifications-stream.ts + streams/mod.ts.
  • Typed-token proof uses @ts-expect-error against streamDefinitionStub.
  • Userland leak sweep rejects plugins/, services/, contracts/, src/runtime/, src/aspire/, bin/, scaffold.plugin.json, and deno.json.

Files:

  • Created: plugins/streams/cli.ts, plugins/streams/src/adapter/**.
  • Modified: plugins/streams/deno.json, plugins/streams/scaffold.ts, plugins/streams/src/cli/composition/main.ts, plugins/streams/tests/cli/streams-cli_test.ts.
  • Deleted: plugins/streams/src/scaffold/**, plugins/streams/src/scaffolding/mod.ts.

Final export map:

{
  ".": "./mod.ts",
  "./scaffold": "./scaffold.ts",
  "./adapter-cli": "./cli.ts",
  "./cli": "./src/cli/composition/main.ts",
  "./e2e": "./src/e2e/mod.ts",
  "./aspire": "./src/aspire/mod.ts"
}

Gate tails:

deno run --allow-read --allow-run .llm/tools/run-deno-check.ts --root plugins/streams --root packages/plugin --ext ts,tsx
summary: totalOccurrences=0 uniqueOccurrences=0 uniqueCodes=0 uniquePaths=0; failedBatches=0

deno run --allow-read --allow-run .llm/tools/run-deno-lint.ts --root plugins/streams --ext ts,tsx
summary: totalOccurrences=0 uniqueOccurrences=0 uniqueRules=0 uniquePaths=0

deno run --allow-read --allow-run .llm/tools/run-deno-fmt.ts --root plugins/streams --ext ts,tsx
summary: filesSelected=30 failedBatches=0 findings=0

deno test --allow-all --unstable-kv plugins/streams
ok | 11 passed | 0 failed (392ms)

cd plugins/streams && deno publish --dry-run --allow-dirty
Success Dry run complete

git diff --stat -- plugins/streams/scaffold.plugin.json plugins/streams/scaffold.runtime.json
<empty>

git status --porcelain deno.lock
<empty>

S4 drift additions:

  • No streams-specific packages/cli import of @netscript/plugin-streams/scaffolding or legacy streams internals was found. Generic S4 host repoint sites remain as already recorded in drift.md.

Commit: 635dec6c557524e079c12b69428640ca54eb53f6

@rickylabs

Copy link
Copy Markdown
Owner Author

Scaffold Runtime Finalization

PR #172 is now functional against the full scaffold runtime bar.

Commits

  • 8aaddbc1feat(cli): follow .netscript-source-root marker for local plugin source discovery
  • 4a991d16fix(triggers): expose registry to package-launched service
  • 50bf9867chore(harness): finalize scaffold runtime evidence

Runtime Evidence

Command:

deno task e2e:cli run scaffold.runtime --cleanup --format pretty

Raw summary:

Summary: passed=48 failed=0

Notable green gates:

  • runtime.wait.workers-api
  • runtime.wait.workers
  • runtime.wait.sagas-api
  • runtime.wait.sagas
  • runtime.wait.triggers-api
  • runtime.wait.triggers
  • runtime.wait.auth
  • behavior.triggers-webhook
  • behavior.triggers-events
  • behavior.otel.traces

Final Gates

  • deno task arch:check — exit 0; all 13 doctrine roots FAIL=0
  • cd packages/cli && deno publish --dry-run --allow-dirty — exit 0, Success Dry run complete
  • cd plugins/triggers && deno publish --dry-run --allow-dirty — exit 0, Success Dry run complete

Debt

Closed PLUGIN-RUNTIME-DEPENDENCY-ENTRYPOINT-EXPORTS in .llm/harness/debt/arch-debt.md with the passing scaffold.runtime evidence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct
@rickylabs

Copy link
Copy Markdown
Owner Author

Check-test finalization for PR #172 is complete.

Root causes fixed:

  • generators-service-plugin_test.ts used a hardcoded pinned jsr:@netscript/plugin-triggers@0.0.1-alpha.12/services fixture, which violated the version-drift guard. The fixture now derives the specifier through netscriptJsrSpecifier('plugin-triggers', '/services').
  • Workers install/appsettings drift came from mixing plugin manifest authoring metadata with generated launch metadata. The chosen rule is: plugin manifests keep local authoring paths such as services/src/main.ts; generated appsettings service entries launch by derived JSR package spec such as netscriptJsrSpecifier('plugin-workers', '/services'); background runtime entries remain local project glue such as workers/runtime.ts.
  • Auth and the other first-party plugin manifests had service entrypoints rewritten to pinned JSR launch specs. Those were restored to local authoring paths across auth, workers, sagas, triggers, and streams.
  • The repo-wide test rerun also exposed a saga KV isolation bug: openSagaRuntimeKv() passed NETSCRIPT_SAGA_KV_PATH as getKv({ path }) while leaving provider auto, and auto detection ignored that path after shared KV state had already initialized. It now forces Deno KV only when the saga-specific path is set, and the supervisor fixture resets shared KV around the isolated path.

Commits:

  • fd82f58btest(cli): derive trigger service fixture specifier
  • c062aac5fix(cli): keep official plugin services package-launched
  • 4fb5fc3dfix(sagas): honor runtime kv path in supervisor tests
  • ad8edc28chore(harness): record check-test finalization

Validation:

  • deno task check exit: 0
  • deno task test: ok | 1017 passed (431 steps) | 0 failed | 12 ignored

@rickylabs
rickylabs marked this pull request as ready for review June 30, 2026 13:19
@rickylabs
rickylabs merged commit b7eb6be into main Jun 30, 2026
6 checks passed
rickylabs added a commit that referenced this pull request Jul 1, 2026
…nfig (#199)

* docs(site): reconcile to merged #193/#183/#190 surface + fmt-guard config

Brings the doc site current with the three just-merged PRs, and hardens the
standalone docs project config so `deno fmt` can never again reflow Vento
markdown or split its `{{ comp }}` tags.

Content (12 pages):
- #190 fresh-ui: document the AI/workspace primitive catalog (11 L2 primitives
  + command-palette/search) and the headless Combobox interactive namespace;
  extra `ui:add` examples. (customize-fresh-ui, capabilities/fresh-ui)
- #193 triggers-oRPC truth: triggers serve a typed v1 oRPC contract for
  introspection/management/SSE; only the webhook ingress endpoint
  (POST /api/v1/webhooks/:triggerId) stays a raw HMAC-verifying route by design.
  Corrected every stale "raw Hono, not oRPC" claim. (triggers, capabilities/index,
  contracts, architecture, glossary, deploy, storefront/05-shipping-webhook)
- #183/#172 two-tier plugin shape: `netscript plugin new <name>` emits a
  core engine package + thin connector; --kind feature|proxy (default proxy),
  --overwrite. (cli-reference, author-a-plugin, plugin-system)

Config:
- docs/site/deno.json gains an fmt block (proseWrap preserve; excludes
  **/*.md, **/*.mdx, **/*.vto, _site/, _cache/) and a lint block, so the
  authored Markdown/Vento surface is out of scope for `deno fmt`.

Verified: `deno task build` green (306 files); `check:links` green
(18456 internal links across 130 pages resolve). Docs-only; no framework source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct

* chore(openhands): record run trace 28485224548-1

* docs(site): correct `plugin new` flag names (IMPL-EVAL #199 Domain 2 FAIL_FIX)

The two-tier topology prose was correct, but the CLI flag spellings were
invented. Ground truth (packages/cli/.../new/new-plugin-command.ts):
- boolean `--feature` (default proxy) → kind: feature|proxy
- boolean `--force` → overwrite
- `--project-root <path>`

There is no `--kind feature|proxy` flag and no `--overwrite` flag. Running
`netscript plugin new billing --kind proxy` would fail. Corrected the two docs
that showed the wrong flags:
- cli-reference.md: example → `netscript plugin new billing` (proxy default);
  desc → `--feature` / `--force`.
- how-to/author-a-plugin.md: example → `netscript plugin new notifier`;
  options prose → `--feature` (route-backed feature connector vs default proxy),
  `--force` (overwrite), `--project-root <path>`.

Verified: `deno task build` green (306 files); `check:links` green
(18456 internal links across 130 pages resolve). Docs-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gW4zfhMMQU6txC828ijct

* chore(openhands): record run trace 28486223232-1

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: OpenHands Bot <openhands@all-hands.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants