@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.
@@ -1,21 +1,18 @@
1
1
  /**
2
2
  * Agent discovery and configuration
3
3
  *
4
- * Supports two discovery strategies:
5
- * 1. Package-resolved: Uses pi's ResolvedPaths.agents from the package manager
6
- * when available (pi forks with first-class agents resource support).
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 '@mariozechner/pi-coding-agent';
15
- import type { ResolvedPaths } from '@mariozechner/pi-coding-agent';
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 = 'bundled' | 'user' | 'project' | 'package';
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
- projectAgentsDir: string | null;
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 findNearestProjectAgentsDir(cwd: string): string | null {
103
+ function findNearestProjectPromptsDir(cwd: string): string | null {
110
104
  let currentDir = cwd;
111
105
  while (true) {
112
- const candidate = path.join(currentDir, '.pi', 'agents');
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
- export function loadAgentsFromResolvedPaths(resolvedPaths: ResolvedPaths): AgentConfig[] {
126
- // Check if the agents field exists (compatibility with upstream pi)
127
- const agentResources = (resolvedPaths as unknown as Record<string, unknown>).agents;
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 agentResources) {
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
- export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {
173
- const userDir = path.join(getAgentDir(), 'agents');
174
- const projectAgentsDir = findNearestProjectAgentsDir(cwd);
175
-
176
- // Bundled agents from the package itself (lowest priority)
177
- const bundledAgents = loadAgentsFromDir(bundledAgentsDir, 'bundled');
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' || !projectAgentsDir ? [] : loadAgentsFromDir(projectAgentsDir, 'project');
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
- for (const agent of bundledAgents) agentMap.set(agent.name, agent);
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()), projectAgentsDir };
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
  }