@dreki-gg/pi-subagent 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.fallowrc.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
3
+ "entry": [
4
+ "extensions/subagent/index.ts"
5
+ ]
6
+ }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @dreki-gg/pi-subagent
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`3a246f3`](https://github.com/dreki-gg/pi-extensions/commit/3a246f3fd55b900ebfcfbea2eff2a7ab9f9f94cf) Thanks [@jalbarrang](https://github.com/jalbarrang)! - Refactor agent distribution from custom `pi.agents` to standard `pi.prompts`
8
+
9
+ - Rename `agents/` directory to `prompts/` to follow pi's standard resource type
10
+ - Use `pi.prompts` in package.json instead of non-standard `pi.agents`
11
+ - Remove legacy bundled-directory fallback — agent prompts are now resolved via pi's package manager
12
+ - Remove `/delegate-agents` command (unused; `/run-agent` and `subagent` tool cover all usage)
13
+ - Extract shared spawn logic into `spawn-utils.ts`, eliminating cross-file duplication between `agent-runner.ts` and `index.ts`
14
+ - Remove dead exports (`formatAgentList`, `buildSynthesisPrompt`, `SYNTHESIS_INSTRUCTION`)
15
+ - Clean up unused imports
16
+ - Maintainability score improved from 70.7 (moderate) to 90.6 (good)
17
+ - Model configuration (`model`, `thinking`, `tools` frontmatter) is unchanged
18
+
3
19
  ## 0.7.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @dreki-gg/pi-subagent
2
2
 
3
- Subagent tool and direct agent runs for pi — isolated agents, parallel scouts, manager workflows, and bundled agents.
3
+ Subagent tool and direct agent runs for pi — isolated agents, parallel scouts, manager workflows, and bundled prompts.
4
4
 
5
5
  ## Install
6
6
 
@@ -118,7 +118,7 @@ If the chosen agent frontmatter sets `sessionStrategy: fork-at`, the command clo
118
118
 
119
119
  ## Agent Definitions
120
120
 
121
- Create agent files in `~/.pi/agent/agents/` or `.pi/agents/` as markdown with YAML frontmatter:
121
+ Create agent prompt files in `~/.pi/agent/prompts/` or `.pi/prompts/` as markdown with YAML frontmatter:
122
122
 
123
123
  ```markdown
124
124
  ---
@@ -153,22 +153,13 @@ Notes:
153
153
  - `worker`, `reviewer`, `bug-prover`, and `manager` default to `sessionStrategy: fork-at`.
154
154
  - "Default reasoning level" maps to the frontmatter field `thinking` and can be overridden per run.
155
155
 
156
- Resolution order is: bundled → user (`~/.pi/agent/agents/`) → project (`.pi/agents/`). Project agents override user and bundled agents by name.
156
+ Resolution order is: bundled → user (`~/.pi/agent/prompts/`) → project (`.pi/prompts/`). Project agents override user and bundled agents by name.
157
157
 
158
158
  Optional frontmatter:
159
159
  - `thinking` — default reasoning effort for the spawned pi process
160
160
  - `sessionStrategy: fork-at` — when used with `/run-agent`, clone the current active branch into a new session before running
161
161
 
162
- > Note: pi now supports package-shipped agents via `pi.agents` (or conventional `agents/` directories). This package publishes its bundled agents that way, while user agents in `~/.pi/agent/agents/` and project agents in `.pi/agents/` still override them by name.
163
-
164
- ### Managing Agents
165
-
166
- ```
167
- /delegate-agents # list all agents with source
168
- /delegate-agents reset scout # restore bundled version
169
- /delegate-agents reset --all # restore all bundled versions
170
- /delegate-agents edit scout # copy bundled to user dir for customization
171
- ```
162
+ > Note: pi supports package-shipped prompts via `pi.prompts` (or conventional `prompts/` directories). This package publishes its bundled agent prompts that way, while user prompts in `~/.pi/agent/prompts/` and project prompts in `.pi/prompts/` still override them by name.
172
163
 
173
164
  ## Bundled Resources
174
165
 
@@ -39,12 +39,12 @@ Current relevant file tree on disk:
39
39
  - `packages/subagent/extensions/subagent/agent-result-utils.ts`
40
40
  - `packages/subagent/extensions/subagent/run-agent-args.ts`
41
41
  - `packages/subagent/extensions/subagent/synthesis.ts`
42
- - `packages/subagent/agents/docs-scout.md`
43
- - `packages/subagent/agents/planner.md`
44
- - `packages/subagent/agents/reviewer.md`
45
- - `packages/subagent/agents/scout.md`
46
- - `packages/subagent/agents/ux-designer.md`
47
- - `packages/subagent/agents/worker.md`
42
+ - `packages/subagent/prompts/docs-scout.md`
43
+ - `packages/subagent/prompts/planner.md`
44
+ - `packages/subagent/prompts/reviewer.md`
45
+ - `packages/subagent/prompts/scout.md`
46
+ - `packages/subagent/prompts/ux-designer.md`
47
+ - `packages/subagent/prompts/worker.md`
48
48
  - `packages/subagent/prompts/implement.md`
49
49
  - `packages/subagent/prompts/implement-and-review.md`
50
50
  - `packages/subagent/prompts/scout-and-plan.md`
@@ -326,10 +326,10 @@ export function buildHandoffFromResult(input: {
326
326
  ## 3. Tighten bundled prompts so handoffs have stable sections to summarize
327
327
 
328
328
  ### Files
329
- - Modify `packages/subagent/agents/scout.md`
330
- - Modify `packages/subagent/agents/docs-scout.md`
331
- - Modify `packages/subagent/agents/planner.md`
332
- - Modify `packages/subagent/agents/worker.md`
329
+ - Modify `packages/subagent/prompts/scout.md`
330
+ - Modify `packages/subagent/prompts/docs-scout.md`
331
+ - Modify `packages/subagent/prompts/planner.md`
332
+ - Modify `packages/subagent/prompts/worker.md`
333
333
  - Modify `packages/subagent/prompts/implement.md`
334
334
  - Modify `packages/subagent/prompts/scout-and-plan.md`
335
335
 
@@ -352,10 +352,10 @@ export function buildHandoffFromResult(input: {
352
352
  # Files to modify
353
353
 
354
354
  - `packages/subagent/extensions/subagent/index.ts` — switch chain substitution from raw final text to rendered structured handoff
355
- - `packages/subagent/agents/scout.md` — make scout output easier to summarize deterministically
356
- - `packages/subagent/agents/docs-scout.md` — make docs handoff more consistent
357
- - `packages/subagent/agents/planner.md` — preserve plan structure but expose constraints explicitly
358
- - `packages/subagent/agents/worker.md` — add explicit decision / unresolved sections for downstream agents
355
+ - `packages/subagent/prompts/scout.md` — make scout output easier to summarize deterministically
356
+ - `packages/subagent/prompts/docs-scout.md` — make docs handoff more consistent
357
+ - `packages/subagent/prompts/planner.md` — preserve plan structure but expose constraints explicitly
358
+ - `packages/subagent/prompts/worker.md` — add explicit decision / unresolved sections for downstream agents
359
359
  - `packages/subagent/prompts/implement.md` — document structured `{previous}` expectations
360
360
  - `packages/subagent/prompts/scout-and-plan.md` — document structured `{previous}` expectations
361
361
 
@@ -28,8 +28,8 @@ Improve the bundled review loop so the reviewer reasons from a fresh, diff-first
28
28
 
29
29
  Current relevant file tree on disk:
30
30
 
31
- - `packages/subagent/agents/reviewer.md`
32
- - `packages/subagent/agents/worker.md`
31
+ - `packages/subagent/prompts/reviewer.md`
32
+ - `packages/subagent/prompts/worker.md`
33
33
  - `packages/subagent/prompts/implement-and-review.md`
34
34
  - `packages/subagent/skills/spawn-subagents/SKILL.md`
35
35
  - `packages/subagent/extensions/subagent/index.ts`
@@ -43,10 +43,10 @@ Actual current behavior on disk:
43
43
  3. run `worker` again to apply review feedback from `{previous}`
44
44
  - Chain execution in `packages/subagent/extensions/subagent/index.ts:658-716` performs raw `{previous}` replacement with the previous step’s final assistant text. There is no review-specific minimization layer in code today.
45
45
  - The current reviewer prompt already points in the right direction:
46
- - `packages/subagent/agents/reviewer.md:12-18` restricts bash to read-only commands and tells the agent to start with `git diff`, then read modified files.
46
+ - `packages/subagent/prompts/reviewer.md:12-18` restricts bash to read-only commands and tells the agent to start with `git diff`, then read modified files.
47
47
  - But the prompt does **not** explicitly tell the reviewer to distrust or deprioritize the worker’s implementation narrative when that narrative is also passed through `{previous}`.
48
48
  - The current worker prompt includes a helpful but minimal handoff hint:
49
- - `packages/subagent/agents/worker.md:13-26` asks for `Completed`, `Files Changed`, and `Notes`, and says that if handing off to another agent it should include exact file paths changed and key functions/types touched.
49
+ - `packages/subagent/prompts/worker.md:13-26` asks for `Completed`, `Files Changed`, and `Notes`, and says that if handing off to another agent it should include exact file paths changed and key functions/types touched.
50
50
  - There is no required section for validation run, constraints, or unresolved risk, so the review handoff is underspecified.
51
51
  - The `spawn-subagents` skill currently recommends a `reviewer` loop after implementation and says the main agent may apply fixes directly or send a focused follow-up to `worker` (`packages/subagent/skills/spawn-subagents/SKILL.md:44-58`). It does not yet describe “clean context” review explicitly.
52
52
  - There is no additional workflow prompt for “clean review”; the current `/implement-and-review` prompt is the only bundled implementation review loop.
@@ -55,7 +55,7 @@ Actual current behavior on disk:
55
55
 
56
56
  ## Existing reviewer and worker contracts
57
57
 
58
- From `packages/subagent/agents/reviewer.md`:
58
+ From `packages/subagent/prompts/reviewer.md`:
59
59
 
60
60
  ```md
61
61
  Strategy:
@@ -80,7 +80,7 @@ Output format:
80
80
  Overall assessment in 2-3 sentences.
81
81
  ```
82
82
 
83
- From `packages/subagent/agents/worker.md`:
83
+ From `packages/subagent/prompts/worker.md`:
84
84
 
85
85
  ```md
86
86
  Output format when finished:
@@ -126,7 +126,7 @@ This means the review workflow can be improved significantly even with prompt-on
126
126
  ## 1. Tighten the reviewer prompt so review starts from `git diff` and re-discovered code context
127
127
 
128
128
  ### Files
129
- - Modify `packages/subagent/agents/reviewer.md`
129
+ - Modify `packages/subagent/prompts/reviewer.md`
130
130
 
131
131
  ### What to change
132
132
  - Keep the reviewer read-only.
@@ -149,7 +149,7 @@ This means the review workflow can be improved significantly even with prompt-on
149
149
  ## 2. Change the worker output contract so implementation handoff becomes a compact review packet
150
150
 
151
151
  ### Files
152
- - Modify `packages/subagent/agents/worker.md`
152
+ - Modify `packages/subagent/prompts/worker.md`
153
153
 
154
154
  ### What to change
155
155
  - Keep the worker autonomous and implementation-focused.
@@ -217,8 +217,8 @@ This means the review workflow can be improved significantly even with prompt-on
217
217
 
218
218
  # Files to modify
219
219
 
220
- - `packages/subagent/agents/reviewer.md` — make clean-context review an explicit prompt rule
221
- - `packages/subagent/agents/worker.md` — emit a compact review packet instead of only freeform notes
220
+ - `packages/subagent/prompts/reviewer.md` — make clean-context review an explicit prompt rule
221
+ - `packages/subagent/prompts/worker.md` — emit a compact review packet instead of only freeform notes
222
222
  - `packages/subagent/prompts/implement-and-review.md` — encode diff-first review semantics in the bundled workflow
223
223
 
224
224
  # Testing notes
@@ -233,8 +233,8 @@ This means the review workflow can be improved significantly even with prompt-on
233
233
 
234
234
  # Patterns to follow
235
235
 
236
- - `packages/subagent/agents/reviewer.md:12-18` — existing diff-first reviewer stance to strengthen, not replace
237
- - `packages/subagent/agents/worker.md:24-26` — current handoff hints to make mandatory and more compact
236
+ - `packages/subagent/prompts/reviewer.md:12-18` — existing diff-first reviewer stance to strengthen, not replace
237
+ - `packages/subagent/prompts/worker.md:24-26` — current handoff hints to make mandatory and more compact
238
238
  - `packages/subagent/prompts/implement-and-review.md:4-10` — current workflow entry point to refine
239
239
  - `packages/subagent/skills/spawn-subagents/SKILL.md:44-58` — current review-loop guidance
240
240
  - `packages/subagent/skills/write-an-agent/SKILL.md:15-20` and `:62-67` — keep prompt files sharp, minimal, and output-contract-driven
@@ -33,10 +33,10 @@ Current relevant file tree on disk:
33
33
  - `packages/subagent/prompts/implement.md`
34
34
  - `packages/subagent/prompts/scout-and-plan.md`
35
35
  - `packages/subagent/prompts/implement-and-review.md`
36
- - `packages/subagent/agents/scout.md`
37
- - `packages/subagent/agents/planner.md`
38
- - `packages/subagent/agents/reviewer.md`
39
- - `packages/subagent/agents/worker.md`
36
+ - `packages/subagent/prompts/scout.md`
37
+ - `packages/subagent/prompts/planner.md`
38
+ - `packages/subagent/prompts/reviewer.md`
39
+ - `packages/subagent/prompts/worker.md`
40
40
  - `packages/subagent/package.json`
41
41
  - `packages/subagent/CHANGELOG.md`
42
42
 
@@ -28,11 +28,11 @@ Introduce a first-class manager workflow that can decompose larger tasks into bo
28
28
 
29
29
  Current relevant file tree on disk:
30
30
 
31
- - `packages/subagent/agents/scout.md`
32
- - `packages/subagent/agents/docs-scout.md`
33
- - `packages/subagent/agents/planner.md`
34
- - `packages/subagent/agents/worker.md`
35
- - `packages/subagent/agents/reviewer.md`
31
+ - `packages/subagent/prompts/scout.md`
32
+ - `packages/subagent/prompts/docs-scout.md`
33
+ - `packages/subagent/prompts/planner.md`
34
+ - `packages/subagent/prompts/worker.md`
35
+ - `packages/subagent/prompts/reviewer.md`
36
36
  - `packages/subagent/prompts/implement.md`
37
37
  - `packages/subagent/prompts/scout-and-plan.md`
38
38
  - `packages/subagent/prompts/implement-and-review.md`
@@ -65,7 +65,7 @@ Actual current state on disk:
65
65
  - `runSingleAgent()` in `index.ts:325-328` only passes `--tools` when the agent frontmatter declares a tool list.
66
66
  - `runAgent()` in `agent-runner.ts:73-76` behaves the same way.
67
67
  - This means a new `manager` agent can omit `tools:` in frontmatter if it needs access to the full tool set, including the `subagent` tool itself.
68
- - There is no project-local `.pi/agents/*.md` manager override in this repo right now; `.pi/agents/` exists but is empty.
68
+ - There is no project-local `.pi/prompts/*.md` manager override in this repo right now; `.pi/prompts/` exists but is empty.
69
69
 
70
70
  # API inventory
71
71
 
@@ -154,7 +154,7 @@ Create a prompt contract that is directly usable by the main agent or a human:
154
154
  ## 1. Add a bundled `manager` agent with a narrow orchestration role
155
155
 
156
156
  ### Files
157
- - Create `packages/subagent/agents/manager.md`
157
+ - Create `packages/subagent/prompts/manager.md`
158
158
 
159
159
  ### What to add
160
160
  Author a concise bundled agent prompt that:
@@ -221,7 +221,7 @@ The manager should:
221
221
 
222
222
  # Files to create
223
223
 
224
- - `packages/subagent/agents/manager.md`
224
+ - `packages/subagent/prompts/manager.md`
225
225
  - `packages/subagent/prompts/manage.md`
226
226
 
227
227
  # Files to modify
@@ -243,6 +243,6 @@ The manager should:
243
243
 
244
244
  - `packages/subagent/skills/spawn-subagents/SKILL.md:31-58` — existing orchestration philosophy to extend upward
245
245
  - `packages/subagent/skills/write-an-agent/SKILL.md:15-20` and `:46-67` — agent-authoring constraints for concise, high-signal prompts
246
- - `packages/subagent/agents/planner.md:9-38` — good example of a narrow role with a clear output contract
247
- - `packages/subagent/agents/worker.md:9-26` — example of a task-focused executor the manager should call, not replace
246
+ - `packages/subagent/prompts/planner.md:9-38` — good example of a narrow role with a clear output contract
247
+ - `packages/subagent/prompts/worker.md:9-26` — example of a task-focused executor the manager should call, not replace
248
248
  - `packages/subagent/README.md:88-124` — bundled-agent and bundled-prompt sections to update
@@ -28,10 +28,10 @@ Introduce a lightweight advisor pattern so primary agents can consult a strong s
28
28
 
29
29
  Current relevant file tree on disk:
30
30
 
31
- - `packages/subagent/agents/planner.md`
32
- - `packages/subagent/agents/reviewer.md`
33
- - `packages/subagent/agents/worker.md`
34
- - `packages/subagent/agents/docs-scout.md`
31
+ - `packages/subagent/prompts/planner.md`
32
+ - `packages/subagent/prompts/reviewer.md`
33
+ - `packages/subagent/prompts/worker.md`
34
+ - `packages/subagent/prompts/docs-scout.md`
35
35
  - `packages/subagent/prompts/implement.md`
36
36
  - `packages/subagent/prompts/implement-and-review.md`
37
37
  - `packages/subagent/README.md`
@@ -42,12 +42,12 @@ Current relevant file tree on disk:
42
42
 
43
43
  Actual current state on disk:
44
44
 
45
- - There is no bundled `advisor` agent in `packages/subagent/agents/`.
45
+ - There is no bundled `advisor` agent in `packages/subagent/prompts/`.
46
46
  - There is no advisor-oriented prompt template in `packages/subagent/prompts/`.
47
47
  - The current bundled roles are:
48
- - `planner` for planning (`packages/subagent/agents/planner.md`)
49
- - `worker` for implementation (`packages/subagent/agents/worker.md`)
50
- - `reviewer` for verification (`packages/subagent/agents/reviewer.md`)
48
+ - `planner` for planning (`packages/subagent/prompts/planner.md`)
49
+ - `worker` for implementation (`packages/subagent/prompts/worker.md`)
50
+ - `reviewer` for verification (`packages/subagent/prompts/reviewer.md`)
51
51
  - plus `scout`, `docs-scout`, and `ux-designer`
52
52
  - The package runner already supports spawned agents consulting tools as needed:
53
53
  - in `packages/subagent/extensions/subagent/index.ts:325-328`, `runSingleAgent()` passes `--tools` only when frontmatter declares them
@@ -63,21 +63,21 @@ Actual current state on disk:
63
63
 
64
64
  ## Existing agent prompt contracts that may invoke advisor
65
65
 
66
- From `packages/subagent/agents/planner.md`:
66
+ From `packages/subagent/prompts/planner.md`:
67
67
 
68
68
  ```md
69
69
  You are a planning specialist.
70
70
  You must NOT make any changes. Only read, analyze, and plan.
71
71
  ```
72
72
 
73
- From `packages/subagent/agents/worker.md`:
73
+ From `packages/subagent/prompts/worker.md`:
74
74
 
75
75
  ```md
76
76
  You are a worker agent with full capabilities.
77
77
  Work autonomously to complete the assigned task. Use all available tools as needed.
78
78
  ```
79
79
 
80
- From `packages/subagent/agents/reviewer.md`:
80
+ From `packages/subagent/prompts/reviewer.md`:
81
81
 
82
82
  ```md
83
83
  You are a senior code reviewer.
@@ -124,7 +124,7 @@ The advisor should not claim to have implemented or verified anything it did not
124
124
  ## 1. Add a bundled `advisor` agent with a focused consultative contract
125
125
 
126
126
  ### Files
127
- - Create `packages/subagent/agents/advisor.md`
127
+ - Create `packages/subagent/prompts/advisor.md`
128
128
 
129
129
  ### What to add
130
130
  Create a concise bundled agent whose sole job is to provide focused second-opinion guidance.
@@ -150,9 +150,9 @@ Create a concise bundled agent whose sole job is to provide focused second-opini
150
150
  ## 2. Teach bundled prompts when to call the advisor and what context to send
151
151
 
152
152
  ### Files
153
- - Modify `packages/subagent/agents/worker.md`
154
- - Modify `packages/subagent/agents/planner.md`
155
- - Modify `packages/subagent/agents/reviewer.md`
153
+ - Modify `packages/subagent/prompts/worker.md`
154
+ - Modify `packages/subagent/prompts/planner.md`
155
+ - Modify `packages/subagent/prompts/reviewer.md`
156
156
 
157
157
  ### What to change
158
158
  Add small, explicit escalation rules to the existing bundled roles.
@@ -215,14 +215,14 @@ The advisor should:
215
215
 
216
216
  # Files to create
217
217
 
218
- - `packages/subagent/agents/advisor.md`
218
+ - `packages/subagent/prompts/advisor.md`
219
219
  - `packages/subagent/prompts/consult-advisor.md`
220
220
 
221
221
  # Files to modify
222
222
 
223
- - `packages/subagent/agents/worker.md` — add narrow escalation guidance
224
- - `packages/subagent/agents/planner.md` — add narrow escalation guidance
225
- - `packages/subagent/agents/reviewer.md` — add narrow escalation guidance
223
+ - `packages/subagent/prompts/worker.md` — add narrow escalation guidance
224
+ - `packages/subagent/prompts/planner.md` — add narrow escalation guidance
225
+ - `packages/subagent/prompts/reviewer.md` — add narrow escalation guidance
226
226
  - `packages/subagent/README.md` — document the new advisor role and one or two examples
227
227
  - `packages/subagent/skills/spawn-subagents/SKILL.md` — explain when to use advisor vs. planner/reviewer
228
228
 
@@ -238,7 +238,7 @@ The advisor should:
238
238
  # Patterns to follow
239
239
 
240
240
  - `packages/subagent/skills/write-an-agent/SKILL.md:15-20` and `:46-67` — keep the new agent narrow, concise, and output-contract-driven
241
- - `packages/subagent/agents/planner.md:9-38` — example of a specialist planner role that the advisor should complement, not replace
242
- - `packages/subagent/agents/reviewer.md:10-37` — example of a verifier role that may occasionally need escalation
243
- - `packages/subagent/agents/worker.md:9-26` — example of a primary owner role that should remain in charge after consulting advisor
241
+ - `packages/subagent/prompts/planner.md:9-38` — example of a specialist planner role that the advisor should complement, not replace
242
+ - `packages/subagent/prompts/reviewer.md:10-37` — example of a verifier role that may occasionally need escalation
243
+ - `packages/subagent/prompts/worker.md:9-26` — example of a primary owner role that should remain in charge after consulting advisor
244
244
  - `packages/subagent/skills/spawn-subagents/SKILL.md:23-58` — existing specialist-selection guidance to extend with optional escalation
@@ -1,4 +1,4 @@
1
- import type { Message } from '@mariozechner/pi-ai';
1
+ import type { Message } from '@earendil-works/pi-ai';
2
2
 
3
3
  export interface UsageStats {
4
4
  input: number;
@@ -1,42 +1,7 @@
1
- import { spawn } from 'node:child_process';
2
- import * as fs from 'node:fs';
3
- import * as os from 'node:os';
4
- import * as path from 'node:path';
5
- import { withFileMutationQueue } from '@mariozechner/pi-coding-agent';
6
- import type { ResolvedPaths } from '@mariozechner/pi-coding-agent';
7
- import type { Message } from '@mariozechner/pi-ai';
8
- import { discoverAgentsWithPackages, type AgentScope } from './agents.js';
9
- import type { AgentResult, UsageStats } from './agent-runner-types.js';
10
-
11
- function emptyUsage(): UsageStats {
12
- return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 };
13
- }
14
-
15
- function getPiInvocation(args: string[]): { command: string; args: string[] } {
16
- const currentScript = process.argv[1];
17
- if (currentScript && fs.existsSync(currentScript)) {
18
- return { command: process.execPath, args: [currentScript, ...args] };
19
- }
20
-
21
- const execName = path.basename(process.execPath).toLowerCase();
22
- const isGenericRuntime = /^(node|bun)(\.exe)?$/.test(execName);
23
- if (!isGenericRuntime) return { command: process.execPath, args };
24
-
25
- return { command: 'pi', args };
26
- }
27
-
28
- async function writePromptToTempFile(
29
- agentName: string,
30
- prompt: string,
31
- ): Promise<{ dir: string; filePath: string }> {
32
- const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'pi-subagent-'));
33
- const safeName = agentName.replace(/[^\w.-]+/g, '_');
34
- const filePath = path.join(tmpDir, `prompt-${safeName}.md`);
35
- await withFileMutationQueue(filePath, async () => {
36
- await fs.promises.writeFile(filePath, prompt, { encoding: 'utf-8', mode: 0o600 });
37
- });
38
- return { dir: tmpDir, filePath };
39
- }
1
+ import type { ResolvedPaths } from '@earendil-works/pi-coding-agent';
2
+ import { discoverAgents, type AgentScope } from './agents.js';
3
+ import type { AgentResult } from './agent-runner-types.js';
4
+ import { emptyUsage, spawnPiAgent } from './spawn-utils.js';
40
5
 
41
6
  export type OnPhaseUpdate = (phaseName: string, agentName: string, result: AgentResult) => void;
42
7
 
@@ -57,7 +22,7 @@ export async function runAgent(
57
22
  task: string,
58
23
  options: RunAgentOptions = {},
59
24
  ): Promise<AgentResult> {
60
- const { agents } = discoverAgentsWithPackages(cwd, options.agentScope ?? 'user', options.resolvedPaths);
25
+ const { agents } = discoverAgents(cwd, options.agentScope ?? 'user', options.resolvedPaths);
61
26
  const agent = agents.find((a) => a.name === agentName);
62
27
 
63
28
  if (!agent) {
@@ -75,14 +40,6 @@ export async function runAgent(
75
40
  const selectedModel = options.model ?? agent.model;
76
41
  const selectedThinking = options.thinking ?? agent.thinking;
77
42
 
78
- const args: string[] = ['--mode', 'json', '-p', '--no-session'];
79
- if (selectedModel) args.push('--model', selectedModel);
80
- if (selectedThinking) args.push('--thinking', selectedThinking);
81
- if (agent.tools && agent.tools.length > 0) args.push('--tools', agent.tools.join(','));
82
-
83
- let tmpPromptDir: string | null = null;
84
- let tmpPromptPath: string | null = null;
85
-
86
43
  const result: AgentResult = {
87
44
  agent: agentName,
88
45
  task,
@@ -93,110 +50,41 @@ export async function runAgent(
93
50
  model: selectedModel,
94
51
  };
95
52
 
96
- try {
97
- if (agent.systemPrompt.trim()) {
98
- const tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);
99
- tmpPromptDir = tmp.dir;
100
- tmpPromptPath = tmp.filePath;
101
- args.push('--append-system-prompt', tmpPromptPath);
102
- }
103
-
104
- args.push(`Task: ${task}`);
105
-
106
- const exitCode = await new Promise<number>((resolve) => {
107
- const invocation = getPiInvocation(args);
108
- const proc = spawn(invocation.command, invocation.args, {
109
- cwd: options.cwd ?? cwd,
110
- shell: false,
111
- stdio: ['ignore', 'pipe', 'pipe'],
112
- });
113
-
114
- let buffer = '';
115
-
116
- const processLine = (line: string) => {
117
- if (!line.trim()) return;
118
- let event: any;
119
- try {
120
- event = JSON.parse(line);
121
- } catch {
122
- return;
123
- }
124
-
125
- if (event.type === 'message_end' && event.message) {
126
- const msg = event.message as Message;
127
- result.messages.push(msg);
128
-
129
- if (msg.role === 'assistant') {
130
- result.usage.turns++;
131
- const usage = msg.usage;
132
- if (usage) {
133
- result.usage.input += usage.input || 0;
134
- result.usage.output += usage.output || 0;
135
- result.usage.cacheRead += usage.cacheRead || 0;
136
- result.usage.cacheWrite += usage.cacheWrite || 0;
137
- result.usage.cost += usage.cost?.total || 0;
138
- result.usage.contextTokens = usage.totalTokens || 0;
139
- }
140
- if (!result.model && msg.model) result.model = msg.model;
141
- if (msg.stopReason) result.stopReason = msg.stopReason;
142
- if (msg.errorMessage) result.errorMessage = msg.errorMessage;
143
- }
144
-
145
- if (options.onUpdate)
146
- options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
147
- }
148
-
149
- if (event.type === 'tool_result_end' && event.message) {
150
- result.messages.push(event.message as Message);
151
- if (options.onUpdate)
152
- options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
153
- }
154
- };
155
-
156
- proc.stdout.on('data', (data: Buffer) => {
157
- buffer += data.toString();
158
- const lines = buffer.split('\n');
159
- buffer = lines.pop() || '';
160
- for (const line of lines) processLine(line);
161
- });
162
-
163
- proc.stderr.on('data', (data: Buffer) => {
164
- result.stderr += data.toString();
165
- });
166
-
167
- proc.on('close', (code: number | null) => {
168
- if (buffer.trim()) processLine(buffer);
169
- resolve(code ?? 0);
170
- });
171
-
172
- proc.on('error', () => resolve(1));
173
-
174
- if (options.signal) {
175
- const killProc = () => {
176
- proc.kill('SIGTERM');
177
- setTimeout(() => {
178
- if (!proc.killed) proc.kill('SIGKILL');
179
- }, 5000);
180
- };
181
- if (options.signal.aborted) killProc();
182
- else options.signal.addEventListener('abort', killProc, { once: true });
183
- }
184
- });
185
-
186
- result.exitCode = exitCode;
187
- return result;
188
- } finally {
189
- if (tmpPromptPath)
190
- try {
191
- fs.unlinkSync(tmpPromptPath);
192
- } catch {
193
- /* ignore */
53
+ const spawnResult = await spawnPiAgent({
54
+ cwd: options.cwd ?? cwd,
55
+ agentName: agent.name,
56
+ task,
57
+ systemPrompt: agent.systemPrompt,
58
+ model: selectedModel,
59
+ thinking: selectedThinking,
60
+ tools: agent.tools,
61
+ signal: options.signal,
62
+ onMessage: () => {
63
+ // Copy accumulated state for the phase update callback
64
+ if (options.onUpdate) {
65
+ result.messages = spawnResult.messages;
66
+ result.usage = spawnResult.usage;
67
+ result.model = spawnResult.model ?? result.model;
68
+ result.stopReason = spawnResult.stopReason;
69
+ result.errorMessage = spawnResult.errorMessage;
70
+ options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
194
71
  }
195
- if (tmpPromptDir)
196
- try {
197
- fs.rmdirSync(tmpPromptDir);
198
- } catch {
199
- /* ignore */
72
+ },
73
+ onToolResult: () => {
74
+ if (options.onUpdate) {
75
+ result.messages = spawnResult.messages;
76
+ options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
200
77
  }
201
- }
78
+ },
79
+ });
80
+
81
+ result.exitCode = spawnResult.exitCode;
82
+ result.messages = spawnResult.messages;
83
+ result.stderr = spawnResult.stderr;
84
+ result.usage = spawnResult.usage;
85
+ result.model = spawnResult.model ?? result.model;
86
+ result.stopReason = spawnResult.stopReason;
87
+ result.errorMessage = spawnResult.errorMessage;
88
+
89
+ return result;
202
90
  }