@dreki-gg/pi-subagent 0.7.0 → 0.8.1
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 +6 -0
- package/CHANGELOG.md +22 -0
- package/README.md +4 -13
- package/docs/plans/01_structured-handoffs-and-synthesis.plan.md +14 -14
- package/docs/plans/02_clean-context-review-loop.plan.md +12 -12
- package/docs/plans/03_parallel-recon-single-writer-docs.plan.md +4 -4
- package/docs/plans/04_manager-workflow.plan.md +10 -10
- package/docs/plans/05_advisor-routing.plan.md +22 -22
- package/extensions/subagent/agent-runner-types.ts +1 -1
- package/extensions/subagent/agent-runner.ts +40 -152
- package/extensions/subagent/agents.ts +31 -77
- package/extensions/subagent/index.ts +83 -354
- package/extensions/subagent/spawn-utils.ts +198 -0
- package/extensions/subagent/synthesis.ts +1 -51
- package/package.json +25 -8
- package/skills/write-an-agent/SKILL.md +5 -5
- /package/{agents → prompts}/advisor.md +0 -0
- /package/{agents → prompts}/bug-prover.md +0 -0
- /package/{agents → prompts}/docs-scout.md +0 -0
- /package/{agents → prompts}/manager.md +0 -0
- /package/{agents → prompts}/planner.md +0 -0
- /package/{agents → prompts}/reviewer.md +0 -0
- /package/{agents → prompts}/scout.md +0 -0
- /package/{agents → prompts}/ux-designer.md +0 -0
- /package/{agents → prompts}/validator.md +0 -0
- /package/{agents → prompts}/worker.md +0 -0
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent discovery and configuration
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Package agents are resolved, filtered, and toggleable via pi config.
|
|
8
|
-
* 2. Legacy: Manual filesystem discovery from bundled, user, and project dirs.
|
|
9
|
-
* Used as fallback when ResolvedPaths.agents is not available.
|
|
4
|
+
* Uses pi's ResolvedPaths.prompts from the package manager to discover
|
|
5
|
+
* agent prompts from installed packages. User and project prompts are
|
|
6
|
+
* discovered from the filesystem and override package prompts by name.
|
|
10
7
|
*/
|
|
11
8
|
|
|
12
9
|
import * as fs from 'node:fs';
|
|
13
10
|
import * as path from 'node:path';
|
|
14
|
-
import { getAgentDir, parseFrontmatter } from '@
|
|
15
|
-
import type { ResolvedPaths } from '@
|
|
11
|
+
import { getAgentDir, parseFrontmatter } from '@earendil-works/pi-coding-agent';
|
|
12
|
+
import type { ResolvedPaths } from '@earendil-works/pi-coding-agent';
|
|
16
13
|
|
|
17
14
|
export type AgentScope = 'user' | 'project' | 'both';
|
|
18
|
-
export type AgentSource = '
|
|
15
|
+
export type AgentSource = 'user' | 'project' | 'package';
|
|
19
16
|
export type AgentSessionStrategy = 'inline' | 'fork-at';
|
|
20
17
|
|
|
21
18
|
export interface AgentConfig {
|
|
@@ -32,12 +29,9 @@ export interface AgentConfig {
|
|
|
32
29
|
|
|
33
30
|
export interface AgentDiscoveryResult {
|
|
34
31
|
agents: AgentConfig[];
|
|
35
|
-
|
|
32
|
+
projectPromptsDir: string | null;
|
|
36
33
|
}
|
|
37
34
|
|
|
38
|
-
/** Bundled agents ship with the package (../../agents relative to extensions/subagent/) */
|
|
39
|
-
const bundledAgentsDir = path.resolve(import.meta.dirname, '..', '..', 'agents');
|
|
40
|
-
|
|
41
35
|
function parseSessionStrategy(value?: string): AgentSessionStrategy | undefined {
|
|
42
36
|
if (!value) return undefined;
|
|
43
37
|
const normalized = value.trim().toLowerCase();
|
|
@@ -106,10 +100,10 @@ function isDirectory(p: string): boolean {
|
|
|
106
100
|
}
|
|
107
101
|
}
|
|
108
102
|
|
|
109
|
-
function
|
|
103
|
+
function findNearestProjectPromptsDir(cwd: string): string | null {
|
|
110
104
|
let currentDir = cwd;
|
|
111
105
|
while (true) {
|
|
112
|
-
const candidate = path.join(currentDir, '.pi', '
|
|
106
|
+
const candidate = path.join(currentDir, '.pi', 'prompts');
|
|
113
107
|
if (isDirectory(candidate)) return candidate;
|
|
114
108
|
|
|
115
109
|
const parentDir = path.dirname(currentDir);
|
|
@@ -119,18 +113,14 @@ function findNearestProjectAgentsDir(cwd: string): string | null {
|
|
|
119
113
|
}
|
|
120
114
|
|
|
121
115
|
/**
|
|
122
|
-
* Load agents from package-manager resolved paths (enabled only).
|
|
123
|
-
* This is called with pre-resolved paths from an async context.
|
|
116
|
+
* Load agents from package-manager resolved prompt paths (enabled only).
|
|
124
117
|
*/
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (!agentResources || !Array.isArray(agentResources)) {
|
|
129
|
-
return [];
|
|
130
|
-
}
|
|
118
|
+
function loadAgentsFromResolvedPaths(resolvedPaths: ResolvedPaths): AgentConfig[] {
|
|
119
|
+
const promptResources = (resolvedPaths as unknown as Record<string, unknown>).prompts;
|
|
120
|
+
if (!Array.isArray(promptResources)) return [];
|
|
131
121
|
|
|
132
122
|
const agents: AgentConfig[] = [];
|
|
133
|
-
for (const resource of
|
|
123
|
+
for (const resource of promptResources) {
|
|
134
124
|
if (!resource.enabled) continue;
|
|
135
125
|
const agent = loadAgentFromFile(resource.path, 'package');
|
|
136
126
|
if (agent) agents.push(agent);
|
|
@@ -169,21 +159,28 @@ function loadAgentFromFile(filePath: string, source: AgentSource): AgentConfig |
|
|
|
169
159
|
};
|
|
170
160
|
}
|
|
171
161
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Discover agents from package-resolved prompts, user, and project directories.
|
|
164
|
+
*
|
|
165
|
+
* Priority: package (lowest) → user → project (highest, overrides by name).
|
|
166
|
+
*/
|
|
167
|
+
export function discoverAgents(
|
|
168
|
+
cwd: string,
|
|
169
|
+
scope: AgentScope,
|
|
170
|
+
resolvedPaths?: ResolvedPaths,
|
|
171
|
+
): AgentDiscoveryResult {
|
|
172
|
+
const userDir = path.join(getAgentDir(), 'prompts');
|
|
173
|
+
const projectPromptsDir = findNearestProjectPromptsDir(cwd);
|
|
178
174
|
|
|
175
|
+
const packageAgents = resolvedPaths ? loadAgentsFromResolvedPaths(resolvedPaths) : [];
|
|
179
176
|
const userAgents = scope === 'project' ? [] : loadAgentsFromDir(userDir, 'user');
|
|
180
177
|
const projectAgents =
|
|
181
|
-
scope === 'user' || !
|
|
178
|
+
scope === 'user' || !projectPromptsDir ? [] : loadAgentsFromDir(projectPromptsDir, 'project');
|
|
182
179
|
|
|
183
|
-
// Priority: bundled (lowest) → user → project (highest, overrides by name)
|
|
184
180
|
const agentMap = new Map<string, AgentConfig>();
|
|
185
181
|
|
|
186
|
-
|
|
182
|
+
// Package agents are lowest priority
|
|
183
|
+
for (const agent of packageAgents) agentMap.set(agent.name, agent);
|
|
187
184
|
|
|
188
185
|
if (scope === 'both') {
|
|
189
186
|
for (const agent of userAgents) agentMap.set(agent.name, agent);
|
|
@@ -194,48 +191,5 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
194
191
|
for (const agent of projectAgents) agentMap.set(agent.name, agent);
|
|
195
192
|
}
|
|
196
193
|
|
|
197
|
-
return { agents: Array.from(agentMap.values()),
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Discover agents with package-resolved paths merged in.
|
|
202
|
-
* Package-resolved agents (from pi.agents in installed packages) are loaded
|
|
203
|
-
* at lowest priority, then overridden by bundled, user, and project agents.
|
|
204
|
-
*
|
|
205
|
-
* Falls back to discoverAgents() when resolvedPaths is not provided or
|
|
206
|
-
* does not contain the agents field (upstream pi compatibility).
|
|
207
|
-
*/
|
|
208
|
-
export function discoverAgentsWithPackages(
|
|
209
|
-
cwd: string,
|
|
210
|
-
scope: AgentScope,
|
|
211
|
-
resolvedPaths?: ResolvedPaths,
|
|
212
|
-
): AgentDiscoveryResult {
|
|
213
|
-
const base = discoverAgents(cwd, scope);
|
|
214
|
-
|
|
215
|
-
if (!resolvedPaths) return base;
|
|
216
|
-
|
|
217
|
-
const packageAgents = loadAgentsFromResolvedPaths(resolvedPaths);
|
|
218
|
-
if (packageAgents.length === 0) return base;
|
|
219
|
-
|
|
220
|
-
// Package agents are lowest priority: existing agents override by name
|
|
221
|
-
const agentMap = new Map<string, AgentConfig>();
|
|
222
|
-
for (const agent of packageAgents) agentMap.set(agent.name, agent);
|
|
223
|
-
for (const agent of base.agents) agentMap.set(agent.name, agent);
|
|
224
|
-
|
|
225
|
-
return { agents: Array.from(agentMap.values()), projectAgentsDir: base.projectAgentsDir };
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export { bundledAgentsDir };
|
|
229
|
-
|
|
230
|
-
export function formatAgentList(
|
|
231
|
-
agents: AgentConfig[],
|
|
232
|
-
maxItems: number,
|
|
233
|
-
): { text: string; remaining: number } {
|
|
234
|
-
if (agents.length === 0) return { text: 'none', remaining: 0 };
|
|
235
|
-
const listed = agents.slice(0, maxItems);
|
|
236
|
-
const remaining = agents.length - listed.length;
|
|
237
|
-
return {
|
|
238
|
-
text: listed.map((a) => `${a.name} (${a.source}): ${a.description}`).join('; '),
|
|
239
|
-
remaining,
|
|
240
|
-
};
|
|
194
|
+
return { agents: Array.from(agentMap.values()), projectPromptsDir };
|
|
241
195
|
}
|