@mystilleef/pi-subagent 0.6.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.
@@ -3,12 +3,18 @@ import {
3
3
  isStatusOnlyFailure,
4
4
  isStatusOnlySuccess,
5
5
  makeToolPreview,
6
+ normalizeAndTruncate,
6
7
  normalizeSummaryValue,
7
8
  normalizeTerminalSentence,
8
- TOOL_PREVIEW_MAX_CHARS,
9
9
  truncateText,
10
10
  } from "../output/normalize.js";
11
- import type { SubagentDetails } from "../shared/types.js";
11
+ import type {
12
+ SingleResult,
13
+ SubagentDetails,
14
+ ToolActivity,
15
+ } from "../shared/types.js";
16
+
17
+ export const SENSITIVE_PATTERN = /secret|token|password/i;
12
18
 
13
19
  export type ThemeBg = "toolPendingBg" | "toolSuccessBg" | "toolErrorBg";
14
20
 
@@ -43,7 +49,9 @@ export interface SubagentProgressState {
43
49
  status: ProgressStatus;
44
50
  startTime: number;
45
51
  durationMs?: number;
52
+ activeToolActivity?: ToolActivity;
46
53
  lastToolPreview?: string;
54
+ toolResultCompleted?: boolean;
47
55
  toolCount: number;
48
56
  inputTokens?: number;
49
57
  outputTokens?: number;
@@ -59,7 +67,7 @@ export function createProgressState(
59
67
  requestId: string,
60
68
  agent: string,
61
69
  task: string,
62
- instanceName = requestId,
70
+ instanceName?: string,
63
71
  ): void {
64
72
  store.set(requestId, {
65
73
  requestId,
@@ -91,7 +99,9 @@ export function patchProgressState(
91
99
  store.set(requestId, {
92
100
  ...state,
93
101
  ...patch,
102
+ activeToolActivity: undefined,
94
103
  lastToolPreview: undefined,
104
+ toolResultCompleted: undefined,
95
105
  });
96
106
  return;
97
107
  }
@@ -115,7 +125,9 @@ export function finalizeProgressState(
115
125
  storeTerminalProgressState(requestId, {
116
126
  status: "success",
117
127
  finalOutput: makeProgressFinalOutput(finalOutput),
128
+ activeToolActivity: undefined,
118
129
  lastToolPreview: undefined,
130
+ toolResultCompleted: undefined,
119
131
  });
120
132
  }
121
133
 
@@ -124,14 +136,18 @@ export function failProgressState(requestId: string, errorText: string): void {
124
136
  storeTerminalProgressState(requestId, {
125
137
  status: "error",
126
138
  errorText: sentence,
139
+ activeToolActivity: undefined,
127
140
  lastToolPreview: undefined,
141
+ toolResultCompleted: undefined,
128
142
  });
129
143
  }
130
144
 
131
145
  export function cancelProgressState(requestId: string, reason?: string): void {
132
146
  storeTerminalProgressState(requestId, {
133
147
  status: "cancelled",
148
+ activeToolActivity: undefined,
134
149
  lastToolPreview: undefined,
150
+ toolResultCompleted: undefined,
135
151
  ...(reason !== undefined
136
152
  ? { errorText: normalizeTerminalSentence(reason) }
137
153
  : {}),
@@ -198,53 +214,110 @@ function isMeaningfulProgressErrorLine(line: string): boolean {
198
214
 
199
215
  export interface DetailsProgress {
200
216
  lastToolPreview?: string;
217
+ activityText?: string;
218
+ activeToolActivity?: ToolActivity;
219
+ progressLastToolPreview?: string;
220
+ toolResultCompleted?: boolean;
201
221
  newToolCallIds: string[];
202
222
  }
203
223
 
224
+ function trackNewToolCall(
225
+ id: string,
226
+ preview: string,
227
+ seenToolCallIds: Set<string>,
228
+ state: DetailsProgress,
229
+ ): void {
230
+ if (seenToolCallIds.has(id)) return;
231
+ seenToolCallIds.add(id);
232
+ state.newToolCallIds.push(id);
233
+ state.lastToolPreview = preview;
234
+ }
235
+
236
+ function extractProgressFromExistingProgress(
237
+ progress: {
238
+ activityText?: string;
239
+ activeToolActivity?: ToolActivity;
240
+ lastToolPreview?: string;
241
+ toolCalls: { id: string; preview: string }[];
242
+ toolResultCompleted?: boolean;
243
+ },
244
+ seenToolCallIds: Set<string>,
245
+ state: DetailsProgress,
246
+ ): void {
247
+ if (
248
+ typeof progress.activityText === "string" &&
249
+ progress.activityText.trim()
250
+ ) {
251
+ state.activityText = normalizeAndTruncate(progress.activityText);
252
+ }
253
+ if (progress.activeToolActivity) {
254
+ state.activeToolActivity = progress.activeToolActivity;
255
+ }
256
+ if (
257
+ typeof progress.lastToolPreview === "string" &&
258
+ progress.lastToolPreview.trim()
259
+ ) {
260
+ state.progressLastToolPreview = normalizeAndTruncate(
261
+ progress.lastToolPreview,
262
+ );
263
+ }
264
+ if (progress.toolResultCompleted) {
265
+ state.toolResultCompleted = true;
266
+ }
267
+ for (const toolCall of progress.toolCalls) {
268
+ if (!isDerivedToolCall(toolCall)) continue;
269
+ const preview = normalizeAndTruncate(toolCall.preview);
270
+ trackNewToolCall(toolCall.id, preview, seenToolCallIds, state);
271
+ }
272
+ }
273
+
274
+ function extractProgressFromMessages(
275
+ messages: SingleResult["messages"] = [],
276
+ seenToolCallIds: Set<string>,
277
+ state: DetailsProgress,
278
+ ): void {
279
+ for (const msg of messages) {
280
+ if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
281
+ for (const part of msg.content) {
282
+ if (isToolCallPart(part)) {
283
+ const preview = makeToolPreview(part.name, part.arguments);
284
+ trackNewToolCall(part.id, preview, seenToolCallIds, state);
285
+ }
286
+ }
287
+ }
288
+ }
289
+
204
290
  export function extractProgressFromDetails(
205
291
  details: SubagentDetails,
206
292
  seenToolCallIds: Set<string>,
207
293
  ): DetailsProgress {
208
- const newToolCallIds: string[] = [];
209
- let lastToolPreview: string | undefined;
294
+ const state: DetailsProgress = { newToolCallIds: [] };
210
295
  const results = Array.isArray(details.results) ? details.results : [];
211
296
  for (const result of results) {
212
297
  if (result.progress) {
213
- for (const toolCall of result.progress.toolCalls) {
214
- if (!isDerivedToolCall(toolCall)) continue;
215
- lastToolPreview = truncateText(
216
- normalizeSummaryValue(toolCall.preview),
217
- TOOL_PREVIEW_MAX_CHARS,
218
- );
219
- if (seenToolCallIds.has(toolCall.id)) continue;
220
- seenToolCallIds.add(toolCall.id);
221
- newToolCallIds.push(toolCall.id);
222
- }
298
+ extractProgressFromExistingProgress(
299
+ result.progress,
300
+ seenToolCallIds,
301
+ state,
302
+ );
223
303
  continue;
224
304
  }
225
305
  const messages = Array.isArray(result.messages) ? result.messages : [];
226
- for (const msg of messages) {
227
- if (msg.role !== "assistant" || !Array.isArray(msg.content)) continue;
228
- for (const part of msg.content) {
229
- if (isToolCallPart(part)) {
230
- lastToolPreview = makeToolPreview(part.name, part.arguments);
231
- if (seenToolCallIds.has(part.id)) continue;
232
- seenToolCallIds.add(part.id);
233
- newToolCallIds.push(part.id);
234
- }
235
- }
236
- }
306
+ extractProgressFromMessages(messages, seenToolCallIds, state);
237
307
  }
238
- return { lastToolPreview, newToolCallIds };
308
+ return state;
309
+ }
310
+
311
+ function isObjectWith(part: unknown): part is Record<string, unknown> {
312
+ return typeof part === "object" && part !== null;
239
313
  }
240
314
 
241
315
  function isDerivedToolCall(part: unknown): part is {
242
316
  id: string;
243
317
  preview: string;
244
318
  } {
245
- if (typeof part !== "object" || part === null) return false;
246
- const maybe = part as { id?: unknown; preview?: unknown };
247
- return typeof maybe.id === "string" && typeof maybe.preview === "string";
319
+ if (!isObjectWith(part)) return false;
320
+ return typeof part.id === "string" && typeof part.preview === "string";
248
321
  }
249
322
 
250
323
  export function isToolCallPart(part: unknown): part is {
@@ -253,12 +326,11 @@ export function isToolCallPart(part: unknown): part is {
253
326
  name: string;
254
327
  arguments?: Record<string, unknown>;
255
328
  } {
256
- if (typeof part !== "object" || part === null) return false;
257
- const maybe = part as { type?: unknown; id?: unknown; name?: unknown };
329
+ if (!isObjectWith(part)) return false;
258
330
  return (
259
- maybe.type === "toolCall" &&
260
- typeof maybe.id === "string" &&
261
- typeof maybe.name === "string"
331
+ part.type === "toolCall" &&
332
+ typeof part.id === "string" &&
333
+ typeof part.name === "string"
262
334
  );
263
335
  }
264
336
 
@@ -274,22 +346,6 @@ export function formatElapsed(ms: number): string {
274
346
  return `${mins}m ${secs}s`;
275
347
  }
276
348
 
277
- /**
278
- * Format a raw token count for compact inline display.
279
- * Values below 1000 rendered as-is. Larger counts use `k`
280
- * or `M` suffixes with one decimal place, stripping trailing `.0`.
281
- */
282
- export function formatTokenCount(count: number): string {
283
- if (count < 1000) return String(count);
284
- const unit = count >= 1_000_000 ? "M" : "k";
285
- const divisor = count >= 1_000_000 ? 1_000_000 : 1000;
286
- return `${trimTrailingZero((count / divisor).toFixed(1))}${unit}`;
287
- }
288
-
289
- function trimTrailingZero(value: string): string {
290
- return value.endsWith(".0") ? value.slice(0, -2) : value;
291
- }
292
-
293
349
  export function formatContextPercent(state: SubagentProgressState): string {
294
350
  const d = state.contextWindowTokens;
295
351
  if (!d || d <= 0 || !Number.isFinite(d)) return "--%";
@@ -311,3 +367,59 @@ export function formatHeaderStats(state: SubagentProgressState): string {
311
367
  const toolLabel = state.toolCount === 1 ? "tool" : "tools";
312
368
  return `${state.toolCount} ${toolLabel} · ${formatContextPercent(state)} ctx · ${formatElapsed(elapsedMs)}\n`;
313
369
  }
370
+
371
+ const REDACTED_PLACEHOLDER = "(running...)";
372
+ const REDACTED_PLACEHOLDER_LENGTH = REDACTED_PLACEHOLDER.length;
373
+
374
+ function redactOrTruncate(text: string, maxChars: number): string {
375
+ if (SENSITIVE_PATTERN.test(text))
376
+ return maxChars >= REDACTED_PLACEHOLDER_LENGTH ? REDACTED_PLACEHOLDER : "";
377
+ return truncateText(text, maxChars);
378
+ }
379
+
380
+ function walkActivityTree(activity: ToolActivity): string[] {
381
+ const parts: string[] = [];
382
+ let current: ToolActivity | undefined = activity;
383
+ while (current) {
384
+ if (current.inputSummary) {
385
+ const annotated = current.instanceName
386
+ ? `${current.inputSummary} [${current.instanceName}]`
387
+ : current.inputSummary;
388
+ parts.push(annotated);
389
+ }
390
+ current = current.child;
391
+ }
392
+ return parts;
393
+ }
394
+
395
+ /**
396
+ * Renders a ToolActivity tree for storage. Each segment is
397
+ * independently normalized and truncated to TOOL_PREVIEW_MAX_CHARS (120).
398
+ */
399
+ export function renderToolActivity(
400
+ activity: ToolActivity | undefined,
401
+ ): string | undefined {
402
+ if (!activity) return undefined;
403
+ const parts = walkActivityTree(activity);
404
+ if (parts.length === 0) return activity.toolName;
405
+ const result = parts.map((p) => normalizeAndTruncate(p)).join(" - ");
406
+ if (SENSITIVE_PATTERN.test(result)) return REDACTED_PLACEHOLDER;
407
+ return result;
408
+ }
409
+
410
+ /**
411
+ * Renders a ToolActivity tree for display with a caller-provided truncation
412
+ * budget. Segments are normalized without individual truncation so the
413
+ * joined result shares one post-join display budget.
414
+ */
415
+ export function renderToolActivityForDisplay(
416
+ activity: ToolActivity | undefined,
417
+ maxChars: number,
418
+ ): string | undefined {
419
+ if (!activity) return undefined;
420
+ if (maxChars <= 0) return "";
421
+ const parts = walkActivityTree(activity);
422
+ if (parts.length === 0) return redactOrTruncate(activity.toolName, maxChars);
423
+ const joined = parts.map((p) => normalizeSummaryValue(p)).join(" - ");
424
+ return redactOrTruncate(joined, maxChars);
425
+ }
@@ -23,6 +23,7 @@ import {
23
23
  formatHeaderStats,
24
24
  getProgressState,
25
25
  type ProgressStatus,
26
+ renderToolActivityForDisplay,
26
27
  STATUS_BG,
27
28
  STATUS_COLOR,
28
29
  STATUS_ICON,
@@ -41,11 +42,12 @@ export {
41
42
  formatContextPercent,
42
43
  formatElapsed,
43
44
  formatHeaderStats,
44
- formatTokenCount,
45
45
  getProgressState,
46
46
  makeTaskPreview,
47
47
  type ProgressStatus,
48
48
  patchProgressState,
49
+ renderToolActivity,
50
+ renderToolActivityForDisplay,
49
51
  resetProgressStore,
50
52
  STATUS_COLOR,
51
53
  STATUS_ICON,
@@ -96,7 +98,9 @@ class DynamicSubagentProgressText implements Component {
96
98
  render(width: number): string[] {
97
99
  const state = getProgressState(this.requestId);
98
100
  if (!state) return [];
99
- return renderProgressBox(state, this.options, this.theme).render(width);
101
+ return renderProgressBox(state, this.options, this.theme, width).render(
102
+ width,
103
+ );
100
104
  }
101
105
  }
102
106
 
@@ -108,6 +112,7 @@ function renderProgressBox(
108
112
  state: SubagentProgressState,
109
113
  options: { expanded: boolean },
110
114
  theme: SubagentTheme,
115
+ width: number,
111
116
  ): Box {
112
117
  const status = state.status;
113
118
  const title = formatSubagentTitle(state.agent, state.instanceName, theme);
@@ -116,28 +121,19 @@ function renderProgressBox(
116
121
  theme.bg(getProgressBackground(status), line),
117
122
  );
118
123
  box.addChild(new Text(header, 0, 0));
119
- addProgressBody(box, state, options, theme);
120
- return box;
121
- }
122
-
123
- function addProgressBody(
124
- box: Box,
125
- state: SubagentProgressState,
126
- options: { expanded: boolean },
127
- theme: SubagentTheme,
128
- ): void {
129
- const body = makeProgressBody(state, options, theme);
130
- if (body.length === 0) return;
124
+ const body = makeProgressBody(state, options, theme, width);
131
125
  for (const line of body) box.addChild(line);
126
+ return box;
132
127
  }
133
128
 
134
129
  function makeProgressBody(
135
130
  state: SubagentProgressState,
136
131
  options: { expanded: boolean },
137
132
  theme: SubagentTheme,
133
+ width: number,
138
134
  ): Text[] {
139
135
  if (state.status === "running")
140
- return makeRunningProgressBody(state, options, theme);
136
+ return makeRunningProgressBody(state, options, theme, width);
141
137
  if (state.status === "error" || state.status === "cancelled") {
142
138
  return makeStoppedProgressBody(state, options, theme);
143
139
  }
@@ -150,12 +146,16 @@ function makeRunningProgressBody(
150
146
  state: SubagentProgressState,
151
147
  options: { expanded: boolean },
152
148
  theme: SubagentTheme,
149
+ width: number,
153
150
  ): Text[] {
154
151
  const body: Text[] = [];
155
- if (state.lastToolPreview) {
156
- body.push(
157
- new Text(formatRunningToolPreview(state.lastToolPreview, theme), 2, 0),
158
- );
152
+ const activityBudget = Math.max(0, width - 8);
153
+ const activityPreview = renderToolActivityForDisplay(
154
+ state.activeToolActivity,
155
+ activityBudget,
156
+ );
157
+ if (activityPreview) {
158
+ body.push(new Text(formatRunningToolPreview(activityPreview, theme), 2, 0));
159
159
  }
160
160
  if (options.expanded)
161
161
  body.push(new Text(theme.fg("dim", state.taskPreview), 2, 0));
@@ -7,12 +7,14 @@ import type {
7
7
  SingleResult,
8
8
  SubagentDetails,
9
9
  SubagentToolResult,
10
+ ToolActivity,
10
11
  } from "../shared/types.js";
11
12
  import { detectMessageError } from "../shared/utils.js";
12
13
  import {
13
14
  extractProgressFromDetails,
14
15
  getProgressState,
15
16
  patchProgressState,
17
+ renderToolActivity,
16
18
  } from "./progress.js";
17
19
 
18
20
  export function hasSubagentFailed(result: SingleResult): boolean {
@@ -53,22 +55,56 @@ export function sanitizeDetailsForDisplay(
53
55
  };
54
56
  }
55
57
 
58
+ export function getLatestResult(
59
+ details: SubagentDetails,
60
+ ): SingleResult | undefined {
61
+ return details.results[0];
62
+ }
63
+
56
64
  export function patchProgressFromDetails(
57
65
  requestId: string,
58
66
  details: SubagentDetails,
59
67
  seenToolCallIds: Set<string>,
60
68
  ): void {
61
- const latestResult = details.results[0];
62
- const { newToolCallIds, lastToolPreview } = extractProgressFromDetails(
63
- details,
64
- seenToolCallIds,
65
- );
69
+ const latestResult = getLatestResult(details);
70
+ const {
71
+ newToolCallIds,
72
+ lastToolPreview,
73
+ activityText,
74
+ activeToolActivity,
75
+ toolResultCompleted,
76
+ } = extractProgressFromDetails(details, seenToolCallIds);
66
77
  const current = getProgressState(requestId);
67
78
  if (!current) return;
68
79
  const patch: Record<string, unknown> = {
69
80
  toolCount: current.toolCount + newToolCallIds.length,
70
81
  };
71
- if (lastToolPreview) patch.lastToolPreview = lastToolPreview;
82
+ let nextActivity: ToolActivity | undefined;
83
+ if (newToolCallIds.length > 0 && lastToolPreview) {
84
+ nextActivity = { toolName: "tool", inputSummary: lastToolPreview };
85
+ } else if (activeToolActivity) {
86
+ nextActivity = activeToolActivity;
87
+ } else if (activityText) {
88
+ nextActivity = { toolName: "tool", inputSummary: activityText };
89
+ } else if (current.activeToolActivity) {
90
+ nextActivity = current.activeToolActivity;
91
+ }
92
+ if (toolResultCompleted && nextActivity?.child) {
93
+ nextActivity = { ...nextActivity, child: undefined };
94
+ } else if (toolResultCompleted) {
95
+ nextActivity = undefined;
96
+ }
97
+ patch.activeToolActivity = nextActivity;
98
+ const renderedPreview = renderToolActivity(nextActivity);
99
+ if (renderedPreview) {
100
+ patch.lastToolPreview = renderedPreview;
101
+ } else if (toolResultCompleted && !nextActivity) {
102
+ patch.lastToolPreview = undefined;
103
+ }
104
+ if (toolResultCompleted) {
105
+ patch.toolResultCompleted = true;
106
+ }
107
+ // Token accounting always applies when usage data is available
72
108
  if (latestResult?.usage) {
73
109
  patch.inputTokens = latestResult.usage.input;
74
110
  patch.outputTokens = latestResult.usage.output;
@@ -86,11 +122,13 @@ export function getSubagentText(result: SubagentToolResult): string {
86
122
  }
87
123
 
88
124
  export function getResultDisplayText(result: SubagentToolResult): string {
89
- return result.details.results[0]?.finalOutput ?? getSubagentText(result);
125
+ return (
126
+ getLatestResult(result.details)?.finalOutput ?? getSubagentText(result)
127
+ );
90
128
  }
91
129
 
92
130
  export function getFeedbackSummaryText(result: SubagentToolResult): string {
93
- const rawFinalOutput = result.details.results[0]?.finalOutput;
131
+ const rawFinalOutput = getLatestResult(result.details)?.finalOutput;
94
132
  if (rawFinalOutput?.trim())
95
133
  return summarizeFeedbackUiFinalOutput(rawFinalOutput);
96
134
  return getSubagentText(result).trim() || "(no output)";
@@ -13,6 +13,13 @@ export interface UsageStats {
13
13
  turns: number;
14
14
  }
15
15
 
16
+ export interface ToolActivity {
17
+ toolName: string;
18
+ inputSummary?: string;
19
+ instanceName?: string;
20
+ child?: ToolActivity;
21
+ }
22
+
16
23
  export interface StreamingProgressToolCall {
17
24
  id: string;
18
25
  preview: string;
@@ -20,8 +27,10 @@ export interface StreamingProgressToolCall {
20
27
 
21
28
  export interface StreamingProgress {
22
29
  activityText?: string;
30
+ activeToolActivity?: ToolActivity;
23
31
  toolCalls: StreamingProgressToolCall[];
24
32
  lastToolPreview?: string;
33
+ toolResultCompleted?: boolean;
25
34
  }
26
35
 
27
36
  export interface SingleResult {
@@ -48,6 +57,7 @@ export interface SubagentDetails {
48
57
  agentScope: AgentScope;
49
58
  projectAgentsDir: string | null;
50
59
  results: SingleResult[];
60
+ renderedByMessage?: true;
51
61
  }
52
62
 
53
63
  export interface SubagentToolResult {
@@ -89,15 +89,54 @@ export function getPiInvocation(args: string[]): {
89
89
  return { command: "pi", args };
90
90
  }
91
91
 
92
+ const SKILL_DISCOVERY_CACHE_TTL_MS = 300_000;
93
+
94
+ type ResolvedSkillArgsCacheEntry = {
95
+ skillPaths: Map<string, string>;
96
+ ts: number;
97
+ };
98
+
99
+ const resolvedSkillArgsCache = new Map<string, ResolvedSkillArgsCacheEntry>();
100
+
101
+ async function canonicalPath(filePath: string): Promise<string> {
102
+ try {
103
+ return await fs.promises.realpath(filePath);
104
+ } catch {
105
+ return path.resolve(filePath);
106
+ }
107
+ }
108
+
109
+ function buildSkillArgs(
110
+ requested: string[],
111
+ skillPaths: Map<string, string>,
112
+ ): string[] {
113
+ return requested.flatMap((name) => ["--skill", skillPaths.get(name) ?? name]);
114
+ }
115
+
116
+ export function resetResolvedAgentSkillArgsCache(): void {
117
+ resolvedSkillArgsCache.clear();
118
+ }
119
+
92
120
  export async function resolveAgentSkillArgs(
93
121
  cwd: string,
94
122
  skillNames: string[],
95
123
  ): Promise<{ args: string[] } | { error: string }> {
96
124
  const requested = Array.from(new Set(skillNames));
97
125
  if (requested.length === 0) return { args: [] };
126
+ const cacheIdentitySkills = [...requested].sort();
127
+ const agentDir = getAgentDir();
128
+ const cacheKey = JSON.stringify({
129
+ cwd: await canonicalPath(cwd),
130
+ agentDir: await canonicalPath(agentDir),
131
+ skills: cacheIdentitySkills,
132
+ });
133
+ const cached = resolvedSkillArgsCache.get(cacheKey);
134
+ if (cached && Date.now() - cached.ts <= SKILL_DISCOVERY_CACHE_TTL_MS) {
135
+ return { args: buildSkillArgs(requested, cached.skillPaths) };
136
+ }
98
137
  const loader = new DefaultResourceLoader({
99
138
  cwd,
100
- agentDir: getAgentDir(),
139
+ agentDir,
101
140
  noContextFiles: true,
102
141
  noPromptTemplates: true,
103
142
  noThemes: true,
@@ -124,12 +163,12 @@ export async function resolveAgentSkillArgs(
124
163
  .join(", ")}. Available skills: ${available}.`,
125
164
  };
126
165
  }
127
- return {
128
- args: requested.flatMap((name) => [
129
- "--skill",
130
- skillMap.get(name)?.filePath ?? name,
131
- ]),
132
- };
166
+ const skillPaths = new Map(
167
+ requested.map((name) => [name, skillMap.get(name)?.filePath ?? name]),
168
+ );
169
+ const args = buildSkillArgs(requested, skillPaths);
170
+ resolvedSkillArgsCache.set(cacheKey, { skillPaths, ts: Date.now() });
171
+ return { args };
133
172
  }
134
173
 
135
174
  export function getSubagentDepth(): number {