diff --git a/README.md b/README.md index f324924..de4b36b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Pi Arc Package -Arc issue tracker integration for [Pi](https://pi.dev): packaged Arc skills, prompt templates, session context injection, workflow command aliases, and bundled checklist support via `@juicesharp/rpiv-todo`. +Arc issue tracker integration for [Pi](https://pi.dev): packaged Arc skills, prompt templates, session context injection, workflow command aliases, bundled checklist support via `@juicesharp/rpiv-todo`, and bundled Arc specialist support via `pi-subagents`. This package is a Pi-native port of the Claude Code Arc plugin at https://github.com/sentiolabs/arc @@ -29,7 +29,7 @@ This package is a Pi-native port of the Claude Code Arc plugin at https://github - `/arc-which` — run `arc which` - `/arc-prime` — show cached `arc prime` context - `/arc-refresh` — refresh cached `arc prime` context - - `/arc-subagents-sync [project|user]` — generate Arc specialist definitions for `pi-subagents` + - `/arc-subagents-sync [project|user]` — generate Arc specialist definitions from the bundled `pi-subagents` copy - `/arc-plan`, `/arc-build`, `/arc-review`, etc. — friendly aliases for the corresponding skills - **Session context injection**: - On session start, the extension runs `arc prime` and injects its output into the system prompt as ``. @@ -49,14 +49,10 @@ This package is a Pi-native port of the Claude Code Arc plugin at https://github - Supports `builder`, `code-reviewer`, `doc-writer`, `evaluator`, `issue-manager`, and `spec-reviewer`. - Resolves Arc model tiers (`small`, `standard`, `large`) to concrete Pi models so orchestrators can right-size subagent dispatches. - Current limitation: `isolation: "worktree"` is recognized but not implemented yet. -- **Optional `pi-subagents` companion support**: - - Run `/arc-subagents-sync` to generate Arc specialist agents (`arc-builder`, `arc-doc-writer`, `arc-spec-reviewer`, `arc-code-reviewer`, `arc-evaluator`, `arc-issue-manager`) in project or user scope. - - Arc workflow skills document where the `subagent` tool is a better fit when `pi-subagents` is installed. - - Use Arc specialists for Arc gates (especially spec review). Do not substitute generic `worker`/`reviewer` agents, which can drift from Arc prompts and model policy. - - Use `subagent({ action: "list" })` and `/agents` after sync to confirm Arc specialist availability. - - Use `/subagents-status` to monitor active/recent async Arc specialist runs; idle installed agents are listed by `/agents`, not the status overlay. - - Keep `arc_agent` as the self-contained fallback when Arc `pi-subagents` definitions are unavailable. - - Claude-style team deployment is intentionally not ported to Pi. +- **Bundled `pi-subagents` companion support**: + - `@sentiolabs/pi-arc` bundles and loads `pi-subagents` by default, so Arc specialists are available without a separate install. + - Pi's package docs recommend bundling other Pi packages through `dependencies` + `bundledDependencies`, then referencing their resources through `node_modules/...` paths in the package's `pi` manifest. + - If you previously installed standalone `pi-subagents`, remove the standalone package from `~/.pi/agent/settings.json` or project `.pi/settings.json` if duplicate tools or commands appear. The bundled copy from `@sentiolabs/pi-arc` is enough for Arc workflows. ## Prerequisites @@ -193,7 +189,9 @@ Override the defaults in `~/.pi/agent/settings.json` or project `.pi/settings.js For compatibility, `arc_agent` still maps legacy aliases: `haiku` → `small`, `sonnet` → `standard`, `opus` → `large`. -## Sync Arc specialists into `pi-subagents` +## Sync Arc specialists into bundled `pi-subagents` + +`@sentiolabs/pi-arc` bundles and loads `pi-subagents` by default, so `/arc-subagents-sync` refreshes the bundled specialist definitions rather than relying on a standalone install. Use `/arc-subagents-sync` to generate Arc specialist agent files from this package's bundled prompts: @@ -204,8 +202,16 @@ Use `/arc-subagents-sync` to generate Arc specialist agent files from this packa - `arc-evaluator` - `arc-issue-manager` +Pi's package docs recommend bundling other Pi packages through `dependencies` + `bundledDependencies`, then referencing their resources through `node_modules/...` paths in the package's `pi` manifest. + +Bundled resources resolve from `./node_modules/pi-subagents/src/extension/index.ts`, `./node_modules/pi-subagents/skills`, and `./node_modules/pi-subagents/prompts`. + By default, files are written to project scope (`/.pi/agents/`). Pass `user` or `--user` to write to `~/.pi/agent/agents/` instead. +If you previously installed standalone `pi-subagents`, remove the standalone package from `~/.pi/agent/settings.json` or project `.pi/settings.json` if duplicate tools or commands appear. The bundled copy from `@sentiolabs/pi-arc` is enough for Arc workflows. + +The `issue-manager` agent stays phased: create the epic first, then child tasks next, then dependencies/labels after all IDs exist. This is sequencing only; true parallel issue creation is not enabled yet. + Generated files include a marker comment so reruns can safely update Arc-managed files while preserving manual edits in user-authored files. After syncing, verify agent registration: @@ -219,6 +225,15 @@ Use `/subagents-status` to monitor active/recent async Arc specialist runs after For Arc gates (especially spec compliance), use Arc specialists (`arc-spec-reviewer`, etc.) instead of generic `worker`/`reviewer` agents. +- Keep `arc_agent` as the self-contained fallback when Arc `pi-subagents` definitions are unavailable. +- Claude-style team deployment is intentionally not ported to Pi. + +## Execution lanes + +- Sequential Arc build: use when tasks overlap, dependencies are linear, or `pi-subagents` is unavailable. +- Parallel Arc batch: use when `/arc-plan` provides a T0 foundation, file ownership matrix, parallel batch manifest, and validation matrix. +- Ant Colony: future/optional lane for large exploratory work; not a replacement for Arc gates in this iteration. + ## Naming differences from the Claude plugin Claude plugin commands used names like `/arc:create`. Pi prompt templates are filename-based, so this package uses hyphenated names: @@ -245,7 +260,7 @@ Implemented: - Bundled `@juicesharp/rpiv-ask-user-question` package for interactive workflow decisions - Pi-native `arc_agent` custom tool for sequential subagent execution - `/arc-subagents-sync` command for generating Arc specialist `pi-subagents` definitions -- Optional guidance for using `pi-subagents` for worktree-isolated evaluator runs and independent parallel builder batches +- Bundled `pi-subagents` support for worktree-isolated evaluator runs, independent parallel builder batches, and phased issue-manager creation - Maintainer-only `/arc-source-sync` workflow for syncing from the Claude Arc plugin source Not yet implemented: diff --git a/STACKING.md b/STACKING.md index b7ff03f..b559baa 100644 --- a/STACKING.md +++ b/STACKING.md @@ -23,7 +23,7 @@ when **all** of the following hold: **Don't stack** when: - Tasks are independent and have no shared files — use arc's - [Parallel Dispatch Protocol](./skills/build/SKILL.md#parallel-dispatch-protocol) + [Parallel Patch Protocol](./skills/arc-build/SKILL.md#parallel-patch-protocol) with worktrees. Stacking dependent tasks and parallelizing independent tasks are different problem shapes; don't conflate them. - The epic is one task, or a handful of tasks that share files heavily — one PR @@ -64,7 +64,7 @@ git-spice auth status # confirm logged into the forge ### 1. Brainstorm + plan (unchanged) -``` +```text /arc:brainstorm # produces docs/plans/.md with the marker /arc:plan # creates epic + tasks with dependencies ``` @@ -104,7 +104,7 @@ arc update $TASK --take git-spice branch create $SLUG --no-commit # Dispatch the builder per the normal arc:build flow. -# Use the model-selection guidance and prompt template from skills/build/SKILL.md. +# Use the model-selection guidance and prompt template from skills/arc-build/SKILL.md. # The builder implements + commits on the new branch. # ↳ run spec-reviewer, code-reviewer, evaluator (if applicable) per the # orchestration loop — they all operate on PRE_TASK_SHA..HEAD on this branch. diff --git a/agents/issue-manager.md b/agents/issue-manager.md index 11360c4..3e43412 100644 --- a/agents/issue-manager.md +++ b/agents/issue-manager.md @@ -94,36 +94,32 @@ The `--parent` flag automatically creates a parent-child dependency. No manual ` ## Processing Task Manifests -When receiving a structured manifest from the `plan` or `brainstorm` skills: +When receiving a structured manifest from the `plan` or `brainstorm` skills, parse the `## Epic` and `## Tasks` sections to assemble the manifest, then process it in phases: -1. **Parse tasks** from the `## Tasks` section — each `### T: ` block defines one task -2. **Create all tasks in parallel** using concurrent Bash tool calls — arc handles concurrent writes safely. Issue one Bash call per task in a single response: +1. **Create the epic first** and capture the epic ID. +2. **Create all child tasks** with the epic as parent before applying dependencies. ```bash arc create "Task title" --type=task --parent=<epic-id> --stdin <<'EOF' Full multi-line description here. EOF ``` -3. **Track the ID mapping** — record logical name (T1, T2, P1, etc.) → arc ID from each creation output -4. **Set dependencies** from the `## Dependencies` section, substituting logical names with real IDs: +3. **Capture the complete task-name-to-ID table**. +4. **Apply dependencies only after all child IDs exist**. ```bash arc dep add <real-later-id> <real-earlier-id> --type=blocks ``` -5. **Apply labels** from the `## Labels` section — use the API via the arc client: +5. **Apply labels after dependencies**, or in the same post-creation phase. ```bash # Labels are managed via the REST API (no CLI command exists) # Use arc update to add label context in the description, or # note the labels in the summary for the dispatcher to handle ``` -6. **Return a markdown summary table** matching the `## Required Output` format: - ``` - | Task | Arc ID | Title | - |------|----------|--------------------------| - | T1 | PROJ-5.1 | Implement storage layer | - | T2 | PROJ-5.2 | Add API endpoints | - ``` +6. **Return the final ID table and dependency summary**. + +**Concurrency note:** Concurrent child-task creation is future work pending Arc CLI/server concurrency verification. Do not claim true parallel CLI issue creation is safe today. **Handling partial failures**: If a task creation fails mid-manifest: -- Continue creating the remaining tasks — do not abort the batch +- Continue creating the remaining tasks in order — do not abort the manifest - Report partial results clearly: "Created 4/5 tasks. T3 failed: `<error message>`" - Include the ID mapping for all successfully created tasks so the dispatcher can act on what exists - Do not attempt to clean up already-created tasks — the dispatcher will decide diff --git a/package-lock.json b/package-lock.json index 2ede9bc..3df670d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,14 @@ "version": "0.6.0", "bundleDependencies": [ "@juicesharp/rpiv-todo", - "@juicesharp/rpiv-ask-user-question" + "@juicesharp/rpiv-ask-user-question", + "pi-subagents" ], "license": "MIT", "dependencies": { "@juicesharp/rpiv-ask-user-question": "^1.0.14", - "@juicesharp/rpiv-todo": "^0.12.5" + "@juicesharp/rpiv-todo": "^0.12.5", + "pi-subagents": "^0.23.0" }, "engines": { "node": ">=20.6.0" @@ -64,6 +66,46 @@ "@mariozechner/pi-tui": "*", "@sinclair/typebox": "*" } + }, + "node_modules/pi-subagents": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/pi-subagents/-/pi-subagents-0.23.0.tgz", + "integrity": "sha512-f1m7+gRBgEVJcfNMe9gD1GFjYZWchn3nKZkPkYtTSwLI3Y6eOUqPdQM6Hry4dA/gTyWXsUVFv29Gw9JZsfh3mA==", + "inBundle": true, + "license": "MIT", + "dependencies": { + "typebox": "^1.1.24" + }, + "bin": { + "pi-subagents": "install.mjs" + }, + "peerDependencies": { + "@mariozechner/pi-agent-core": "*", + "@mariozechner/pi-ai": "*", + "@mariozechner/pi-coding-agent": "*", + "@mariozechner/pi-tui": "*" + }, + "peerDependenciesMeta": { + "@mariozechner/pi-agent-core": { + "optional": true + }, + "@mariozechner/pi-ai": { + "optional": true + }, + "@mariozechner/pi-coding-agent": { + "optional": true + }, + "@mariozechner/pi-tui": { + "optional": true + } + } + }, + "node_modules/typebox": { + "version": "1.1.37", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.37.tgz", + "integrity": "sha512-jb7jp6KvOvvy5sd+11AfJ0/e0F0AS9RcOXd55oGi2ZnRHIGmFvrTaNF+ZidRmGBmmNTkM5KKl0Z37KzxJ+owEQ==", + "inBundle": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index 153fd87..5446e9c 100644 --- a/package.json +++ b/package.json @@ -45,11 +45,13 @@ }, "dependencies": { "@juicesharp/rpiv-ask-user-question": "^1.0.14", - "@juicesharp/rpiv-todo": "^0.12.5" + "@juicesharp/rpiv-todo": "^0.12.5", + "pi-subagents": "^0.23.0" }, "bundledDependencies": [ "@juicesharp/rpiv-todo", - "@juicesharp/rpiv-ask-user-question" + "@juicesharp/rpiv-ask-user-question", + "pi-subagents" ], "peerDependencies": { "@mariozechner/pi-ai": "*", @@ -73,15 +75,18 @@ }, "pi": { "skills": [ - "./skills" + "./skills", + "./node_modules/pi-subagents/skills" ], "prompts": [ - "./prompts/*.md" + "./prompts/*.md", + "./node_modules/pi-subagents/prompts" ], "extensions": [ "./extensions/*.ts", "./node_modules/@juicesharp/rpiv-todo/index.ts", - "./node_modules/@juicesharp/rpiv-ask-user-question/index.ts" + "./node_modules/@juicesharp/rpiv-ask-user-question/index.ts", + "./node_modules/pi-subagents/src/extension/index.ts" ] } } diff --git a/skills/arc-brainstorm/SKILL.md b/skills/arc-brainstorm/SKILL.md index 8fd78be..c3f99c0 100644 --- a/skills/arc-brainstorm/SKILL.md +++ b/skills/arc-brainstorm/SKILL.md @@ -107,7 +107,24 @@ Create a task for each step below using the bundled `todo` checklist (via `todo` ### 5. Identify Shared Contracts (Parallel Readiness) -If the design will produce multiple implementation tasks that could run in parallel, explicitly identify the **shared contracts** — types, interfaces, config keys, constants, and function signatures that multiple tasks will reference. +If the design can produce independent implementation tasks, the brainstorm output must include a `## Parallel Readiness` section **before** `/arc-plan` creates Arc issues. Use these exact subsection headings: + +```markdown +## Parallel Readiness + +### T0 Foundation Decision + +### File Ownership Matrix + +### Parallel Batch Manifest + +### Validation Matrix +``` + +- `T0 Foundation Decision` records the sequential foundation step that must land first when multiple tasks depend on the same shared contracts. +- `File Ownership Matrix` assigns every implementation file to exactly one task. Any overlap must be moved to T0, serialized with dependencies, or merged into one task. +- `Parallel Batch Manifest` lists the batches, their prerequisites, the tasks in each batch, the independence proof, and the validation. +- `Validation Matrix` shows which checks prove each batch or task is safe to merge. Contracts fall into two tiers: diff --git a/skills/arc-build/SKILL.md b/skills/arc-build/SKILL.md index d112d24..d9b1d9e 100644 --- a/skills/arc-build/SKILL.md +++ b/skills/arc-build/SKILL.md @@ -71,6 +71,12 @@ subagent({ agent: "arc-builder", task: "...", model: "openai-codex/gpt-5.5", con ## Dispatch Modes +Choose the manifest-driven parallel path first; if the batch is not ready, fall back to sequential dispatch. + +### Parallel (plan-driven) + +If the plan includes a `### Parallel Batch Manifest`, read it first. Select a batch only when all prerequisites are complete and the gates below pass. When the batch is ready, use [Parallel Patch Protocol](#parallel-patch-protocol) below. + ### Sequential (default) Tasks are dispatched one at a time through the orchestration loop below. Use this for: @@ -95,7 +101,11 @@ Parallel worktree dispatch is available **only** through the optional `pi-subage ## Orchestration Loop -By default, use sequential dispatch. For independent batches with `pi-subagents` available, see [Parallel Patch Protocol](#parallel-patch-protocol) below. +Start here by checking whether the plan's `Parallel Batch Manifest` can be dispatched in parallel. + +### 0. Choose Dispatch Mode + +Inspect the plan's `Parallel Batch Manifest` first. If it yields a ready batch and the gates below pass, dispatch that batch through [Parallel Patch Protocol](#parallel-patch-protocol). Otherwise, continue with sequential dispatch. **Task tracking**: At the start of implementation, create a task list using the bundled `todo` checklist (via `todo` tool / `/todos`) with one entry per arc issue to implement. This provides a visible progress tracker in the CLI. Update each task as you work: - `in_progress` when dispatching the subagent @@ -182,7 +192,7 @@ When the subagent reports back, check its **Status** (one of `DONE | DONE_WITH_C When re-dispatching, include the previous report's concerns / blockers so the implementer knows exactly what to fix: -``` +```text Continue implementing this task. A previous attempt reported <status> with these concerns: <paste concerns> @@ -332,51 +342,40 @@ Use this protocol only with `pi-subagents` worktree mode. Do **not** use `arc_ag ### P1. Commit Checkpoint -Before switching to parallel, ensure all sequential work is committed and pushed: - -```bash -git status # Must be clean — no unstaged or uncommitted changes -git log -3 # Verify recent sequential commits are present -git push # Establish a recovery point on the remote -``` - -**Hard gate**: Do NOT proceed if `git status` shows uncommitted changes. - -### P2. Record HEAD Anchor +Before switching to parallel, ensure all sequential work is committed and pushed. Run this exact gate: ```bash +git status --short +git push PARALLEL_BASE=$(git rev-parse HEAD) echo "Parallel base: $PARALLEL_BASE" ``` -This is the baseline all temporary worktrees will branch from. Record it — you'll need it for verification after patch application. +If `git status --short` reports changes, stop and clean the tree first. -### P3. Verify Independence +### P2. Record HEAD Anchor -For each task in the planned parallel batch: +This anchor is the baseline all temporary worktrees will branch from. Record it before dispatching the batch. -```bash -arc show <task-id> -``` +### P3. Re-check Batch Gates Before Dispatch -Confirm: -- No `blocks`/`blockedBy` relationships between tasks in this batch -- No overlapping file paths in task descriptions -- Each task has a clearly scoped, non-ambiguous specification -- Each task can be validated independently after its patch is applied +Re-check these gates immediately before dispatching the batch: +- `subagent({ action: "list" })` shows Arc specialists such as `arc-builder` and `arc-doc-writer`. +- Each task in the batch is ready in Arc. +- No task in the batch blocks another task in the batch. +- No builder/doc-writer task owns the same file as another task in the batch. +- Each task has a clear validation command. -If any task fails these checks, remove it from the parallel batch and handle it sequentially after. +For each task in the manifest, `arc show <task-id>` and confirm the batch is still independent. ### P4. Dispatch with `pi-subagents` -Dispatch all parallel tasks in one `subagent` tool call so they branch from the same `PARALLEL_BASE`: +Dispatch the selected batch in one `subagent` tool call so the tasks branch from the same `PARALLEL_BASE`: -```ts +```typescript subagent({ tasks: [ - { agent: "arc-builder", task: "<filled builder prompt for task 1>", model: "openai-codex/gpt-5.3-codex" }, - { agent: "arc-builder", task: "<filled builder prompt for task 2>", model: "openai-codex/gpt-5.3-codex" }, - { agent: "arc-doc-writer", task: "<filled doc-writer prompt for task 3>", model: "openai-codex/gpt-5.4-mini" } + { agent: "arc-builder", task: "<filled builder prompt>", model: "<configured standard model>" } ], worktree: true, concurrency: 3, @@ -390,6 +389,8 @@ When the async run completes, `pi-subagents` returns diff stats and a `Full patc ### P5. Apply and Verify Patches One at a Time +Apply, validate, review, commit, and close exactly one returned patch at a time. + For each returned patch: ```bash diff --git a/skills/arc-plan/SKILL.md b/skills/arc-plan/SKILL.md index 1fb857d..70f1fea 100644 --- a/skills/arc-plan/SKILL.md +++ b/skills/arc-plan/SKILL.md @@ -194,7 +194,18 @@ arc share list --json | jq -r '.[] | select(.id=="<id>") | .plan_file' arc plan show <id> | grep -oE '^File: \S+' | awk '{print $2}' ``` -The share keyring entries have `{id, kind, url, key_b64url, plan_file, created_at}` — edit tokens are intentionally redacted. Then dispatch the manifest. Prefer true `pi-subagents` so long issue-creation runs are visible in `/subagents-status`: +The share keyring entries have `{id, kind, url, key_b64url, plan_file, created_at}` — edit tokens are intentionally redacted. + +Issue creation must be phased: + +1. Create the epic first and capture the epic ID. +2. Create all child tasks with the epic as parent before applying dependencies. +3. Capture the complete task-name-to-ID table. +4. Apply dependencies only after all child IDs exist. +5. Apply labels after dependencies, or in the same post-creation phase. +6. Return the final ID table and dependency summary. + +Then dispatch the manifest. Prefer true `pi-subagents` so long issue-creation runs are visible in `/subagents-status`: Dispatch preference (use **async** so long-running issue creation appears in `/subagents-status`): - Primary: `subagent({ agent: "arc-issue-manager", task: "<manifest below>", context: "fresh", async: true, clarify: false })` @@ -332,6 +343,35 @@ Replace `<epic-id>` with the actual epic ID. **Done for now**: Confirm the epic and tasks are saved in arc. The user can run `/arc-build <epic-id>` whenever they're ready. +## Parallel Readiness + +When a design can split into parallel implementation batches, document the readiness proof before handing off tasks. + +### T0 Foundation Decision + +State whether the design needs a T0 foundation task. If shared contracts, shared constants, or any other multi-task interface are referenced by more than one task, create T0 first and block every dependent parallel batch on it. + +### File Ownership Matrix + +Do not mark any task parallelizable until this matrix is complete and every file is owned by exactly one task. + +| Task | Owns files | Reads files | Overlap handling | +|---|---|---|---| + +### Parallel Batch Manifest + +Group only disjoint tasks into parallel batches after file ownership is settled. + +| Batch | Prerequisites | Tasks | Independence proof | Validation | +|---|---|---|---|---| + +### Validation Matrix + +List the validation command(s) for each batch and the result that proves the batch is ready to hand off. + +| Check | Scope | Command | Expected result | +|---|---|---|---| + ## Task Description Format Each task's `--description` must be **self-contained** (~3-5k tokens). The task description IS the implementation context — the implementer loads `arc show <task-id>` and nothing else. diff --git a/tests/arc-subagents-sync.test.mjs b/tests/arc-subagents-sync.test.mjs index da6958b..cfc1a3a 100644 --- a/tests/arc-subagents-sync.test.mjs +++ b/tests/arc-subagents-sync.test.mjs @@ -75,7 +75,9 @@ test('README documents arc-subagents-sync and status semantics', () => { const source = read('README.md'); assert.match(source, /\/arc-subagents-sync/); assert.match(source, /generic `worker`/i); - assert.match(source, /Use `subagent\(\{ action: "list" \}\)` and `\/agents` after sync to confirm Arc specialist availability/); + assert.match(source, /After syncing, verify agent registration/); + assert.match(source, /subagent\(\{ action: "list" \}\)/); + assert.match(source, /\/agents/); assert.match(source, /Use `\/subagents-status` to monitor active\/recent async Arc specialist runs/); assert.match(source, /It does not list idle installed agents/); assert.doesNotMatch(source, /\/subagents-status.*confirm availability/); diff --git a/tests/parallel-readiness-guidance.test.mjs b/tests/parallel-readiness-guidance.test.mjs new file mode 100644 index 0000000..608051b --- /dev/null +++ b/tests/parallel-readiness-guidance.test.mjs @@ -0,0 +1,50 @@ +import { readFileSync } from 'node:fs'; +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { + ISSUE_MANAGER_PHASE_TERMS, + PARALLEL_READINESS_HEADINGS, + PI_SUBAGENTS_PACKAGE, +} from './parallel-throughput-contract.mjs'; + +function read(path) { + return readFileSync(path, 'utf8'); +} + +function assertIncludesAll(source, terms) { + for (const term of terms) { + assert.match(source, new RegExp(term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); + } +} + +test('arc-brainstorm documents parallel readiness headings', () => { + assertIncludesAll(read('skills/arc-brainstorm/SKILL.md'), PARALLEL_READINESS_HEADINGS); +}); + +test('arc-plan documents parallel readiness and issue-manager phases', () => { + const source = read('skills/arc-plan/SKILL.md'); + assertIncludesAll(source, PARALLEL_READINESS_HEADINGS); + assertIncludesAll(source, ISSUE_MANAGER_PHASE_TERMS); +}); + +test('issue-manager documents safe phased issue creation', () => { + assertIncludesAll(read('agents/issue-manager.md'), ISSUE_MANAGER_PHASE_TERMS); +}); + +test('arc-build consumes the parallel batch manifest safely', () => { + const source = read('skills/arc-build/SKILL.md'); + assert.match(source, /Parallel Batch Manifest/); + assert.match(source, /worktree: true/); + assert.match(source, /PARALLEL_BASE/); + assert.match(source, /one (returned )?patch|one patch/i); +}); + +test('README documents bundled subagents and execution lanes', () => { + const source = read('README.md'); + assert.match(source, new RegExp(PI_SUBAGENTS_PACKAGE)); + assert.match(source, /bundledDependencies/); + assert.match(source, /duplicate/i); + assert.match(source, /Parallel Arc batch/); + assert.match(source, /Ant Colony/); + assert.doesNotMatch(source, /pi-plan.*replace.*arc-plan/i); +}); diff --git a/tests/parallel-throughput-contract.mjs b/tests/parallel-throughput-contract.mjs new file mode 100644 index 0000000..d94a81f --- /dev/null +++ b/tests/parallel-throughput-contract.mjs @@ -0,0 +1,20 @@ +export const PI_SUBAGENTS_PACKAGE = 'pi-subagents'; +export const PI_SUBAGENTS_VERSION_RANGE = '^0.23.0'; +export const PI_SUBAGENTS_EXTENSION_PATH = './node_modules/pi-subagents/src/extension/index.ts'; +export const PI_SUBAGENTS_SKILLS_PATH = './node_modules/pi-subagents/skills'; +export const PI_SUBAGENTS_PROMPTS_PATH = './node_modules/pi-subagents/prompts'; + +export const PARALLEL_READINESS_HEADINGS = [ + '## Parallel Readiness', + '### T0 Foundation Decision', + '### File Ownership Matrix', + '### Parallel Batch Manifest', + '### Validation Matrix', +]; + +export const ISSUE_MANAGER_PHASE_TERMS = [ + 'Create the epic first', + 'Create all child tasks', + 'Apply dependencies only after all child IDs exist', + 'Apply labels after dependencies', +]; diff --git a/tests/parallel-throughput-contract.test.mjs b/tests/parallel-throughput-contract.test.mjs new file mode 100644 index 0000000..5cf803f --- /dev/null +++ b/tests/parallel-throughput-contract.test.mjs @@ -0,0 +1,38 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { + ISSUE_MANAGER_PHASE_TERMS, + PARALLEL_READINESS_HEADINGS, + PI_SUBAGENTS_EXTENSION_PATH, + PI_SUBAGENTS_PACKAGE, + PI_SUBAGENTS_PROMPTS_PATH, + PI_SUBAGENTS_SKILLS_PATH, + PI_SUBAGENTS_VERSION_RANGE, +} from './parallel-throughput-contract.mjs'; + +test('pi-subagents package contract is explicit', () => { + assert.equal(PI_SUBAGENTS_PACKAGE, 'pi-subagents'); + assert.equal(PI_SUBAGENTS_VERSION_RANGE, '^0.23.0'); + assert.equal(PI_SUBAGENTS_EXTENSION_PATH, './node_modules/pi-subagents/src/extension/index.ts'); + assert.equal(PI_SUBAGENTS_SKILLS_PATH, './node_modules/pi-subagents/skills'); + assert.equal(PI_SUBAGENTS_PROMPTS_PATH, './node_modules/pi-subagents/prompts'); +}); + +test('parallel readiness headings are stable', () => { + assert.deepEqual(PARALLEL_READINESS_HEADINGS, [ + '## Parallel Readiness', + '### T0 Foundation Decision', + '### File Ownership Matrix', + '### Parallel Batch Manifest', + '### Validation Matrix', + ]); +}); + +test('issue-manager phase terms are stable', () => { + assert.deepEqual(ISSUE_MANAGER_PHASE_TERMS, [ + 'Create the epic first', + 'Create all child tasks', + 'Apply dependencies only after all child IDs exist', + 'Apply labels after dependencies', + ]); +}); diff --git a/tests/pi-subagents-bundle.test.mjs b/tests/pi-subagents-bundle.test.mjs new file mode 100644 index 0000000..c5ae21d --- /dev/null +++ b/tests/pi-subagents-bundle.test.mjs @@ -0,0 +1,33 @@ +import { readFileSync } from 'node:fs'; +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { + PI_SUBAGENTS_EXTENSION_PATH, + PI_SUBAGENTS_PACKAGE, + PI_SUBAGENTS_PROMPTS_PATH, + PI_SUBAGENTS_SKILLS_PATH, + PI_SUBAGENTS_VERSION_RANGE, +} from './parallel-throughput-contract.mjs'; + +function read(path) { + return readFileSync(path, 'utf8'); +} + +function readJson(path) { + return JSON.parse(read(path)); +} + +test('package metadata bundles and loads pi-subagents', () => { + const pkg = readJson('package.json'); + const lock = readJson('package-lock.json'); + + assert.equal(pkg.dependencies[PI_SUBAGENTS_PACKAGE], PI_SUBAGENTS_VERSION_RANGE); + assert.ok(pkg.bundledDependencies.includes(PI_SUBAGENTS_PACKAGE)); + assert.ok(pkg.pi.extensions.includes(PI_SUBAGENTS_EXTENSION_PATH)); + assert.ok(pkg.pi.skills.includes(PI_SUBAGENTS_SKILLS_PATH)); + assert.ok(pkg.pi.prompts.includes(PI_SUBAGENTS_PROMPTS_PATH)); + + assert.equal(lock.packages[''].dependencies[PI_SUBAGENTS_PACKAGE], PI_SUBAGENTS_VERSION_RANGE); + assert.ok(lock.packages[''].bundleDependencies.includes(PI_SUBAGENTS_PACKAGE)); + assert.ok(lock.packages[`node_modules/${PI_SUBAGENTS_PACKAGE}`]); +});