pi-agent-flow 1.0.8 → 1.2.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/README.md +159 -45
- package/agents/audit.md +56 -0
- package/agents/build.md +60 -0
- package/agents/craft.md +53 -0
- package/agents/debug.md +33 -15
- package/agents/ideas.md +51 -0
- package/agents/scout.md +51 -0
- package/package.json +12 -15
- package/{agents.ts → src/agents.ts} +15 -12
- package/src/ambient.d.ts +85 -0
- package/src/batch.ts +1221 -0
- package/src/cli-args.ts +283 -0
- package/src/config.ts +305 -0
- package/{flow.ts → src/flow.ts} +120 -33
- package/{hooks.ts → src/hooks.ts} +31 -13
- package/src/index.ts +1002 -0
- package/{render-utils.ts → src/render-utils.ts} +5 -5
- package/{render.ts → src/render.ts} +66 -30
- package/src/runner-events.ts +692 -0
- package/{types.ts → src/types.ts} +5 -2
- package/src/web-tool.ts +663 -0
- package/agents/architect.md +0 -35
- package/agents/brainstorm.md +0 -29
- package/agents/code.md +0 -55
- package/agents/explore.md +0 -29
- package/agents/review.md +0 -35
- package/config.ts +0 -67
- package/index.ts +0 -645
- package/runner-cli.js +0 -254
- package/runner-events.js +0 -405
|
@@ -27,12 +27,12 @@ export function formatFixedTokens(count: number): string {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Format flow type name to fixed width (
|
|
31
|
-
* Examples: "debug" → "debug
|
|
30
|
+
* Format flow type name to fixed width (5 chars) in lowercase with space padding.
|
|
31
|
+
* Examples: "debug" → "debug", "scout" → "scout", "build" → "build"
|
|
32
32
|
*/
|
|
33
33
|
export function formatFlowTypeName(type: string): string {
|
|
34
34
|
const lower = type.toLowerCase();
|
|
35
|
-
const targetWidth =
|
|
35
|
+
const targetWidth = 5;
|
|
36
36
|
if (lower.length >= targetWidth) return lower.slice(0, targetWidth);
|
|
37
37
|
return lower.padEnd(targetWidth, " ");
|
|
38
38
|
}
|
|
@@ -50,8 +50,8 @@ export function formatCompactStats(usage: Partial<UsageStats>, model?: string, m
|
|
|
50
50
|
parts.push(`tps: ${formatTps(usage.smoothedTps)}`);
|
|
51
51
|
parts.push(`ctx: ${formatFixedTokens(usage.contextTokens || 0)}`);
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const displayModel = model ? model.replace(/^[^/]+\//, "") : undefined;
|
|
54
|
+
let result = parts.join(" · ") + (displayModel ? ` · ${displayModel}` : "");
|
|
55
55
|
if (maxWidth && visibleLength(result) > maxWidth) {
|
|
56
56
|
// Drop model first
|
|
57
57
|
let narrow = parts.join(" · ");
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
isFlowError,
|
|
23
23
|
isFlowSuccess,
|
|
24
24
|
} from "./types.js";
|
|
25
|
-
import { formatCompactStats, formatFlowTypeName, truncateChars, contentBudget } from "./render-utils.js";
|
|
25
|
+
import { formatCompactStats, formatFlowTypeName, truncateChars, tailText, contentBudget } from "./render-utils.js";
|
|
26
26
|
|
|
27
27
|
function shortenPath(p: string): string {
|
|
28
28
|
const home = os.homedir();
|
|
@@ -66,6 +66,27 @@ function formatFlowToolCall(toolName: string, args: Record<string, unknown>, fg:
|
|
|
66
66
|
return fg("muted", "find ") + fg("accent", (args.pattern || "*") as string) + fg("dim", ` in ${shortenPath((args.path || ".") as string)}`);
|
|
67
67
|
case "grep":
|
|
68
68
|
return fg("muted", "grep ") + fg("accent", `/${(args.pattern || "") as string}/`) + fg("dim", ` in ${shortenPath((args.path || ".") as string)}`);
|
|
69
|
+
case "batch":
|
|
70
|
+
case "batch_read": {
|
|
71
|
+
const ops = Array.isArray(args.o) ? args.o : Array.isArray(args.op) ? args.op : Array.isArray(args.operations) ? args.operations : Array.isArray(args) ? args : [];
|
|
72
|
+
if (ops.length === 0) return fg("muted", `${toolName} (empty)`);
|
|
73
|
+
const parts: string[] = [];
|
|
74
|
+
for (const op of ops) {
|
|
75
|
+
const opObj = op as Record<string, unknown>;
|
|
76
|
+
const opName = (opObj.o ?? opObj.op ?? "?") as string;
|
|
77
|
+
const opPath = (opObj.p ?? opObj.path ?? "?") as string;
|
|
78
|
+
const shortPath = shortenPath(opPath);
|
|
79
|
+
if (opName === "edit") {
|
|
80
|
+
const edits = (opObj.e ?? opObj.edits) as unknown[] | undefined;
|
|
81
|
+
const blockInfo = edits && edits.length > 1 ? ` (${edits.length} blocks)` : "";
|
|
82
|
+
parts.push(`edit ${shortPath}${blockInfo}`);
|
|
83
|
+
} else {
|
|
84
|
+
parts.push(`${opName} ${shortPath}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const summary = parts.length <= 3 ? parts.join(", ") : `${parts.slice(0, 2).join(", ")} +${parts.length - 2} more`;
|
|
88
|
+
return fg("muted", `${toolName} `) + fg("accent", summary);
|
|
89
|
+
}
|
|
69
90
|
default:
|
|
70
91
|
return fg("accent", toolName) + fg("dim", ` ${JSON.stringify(args)}`);
|
|
71
92
|
}
|
|
@@ -107,6 +128,16 @@ function flowStatusIcon(r: SingleResult, theme: { fg: ThemeFg }): string {
|
|
|
107
128
|
return isFlowError(r) ? theme.fg("error", "✗") : theme.fg("success", "✓");
|
|
108
129
|
}
|
|
109
130
|
|
|
131
|
+
/** Center a label in a fixed-width header using em-dashes. Total width = 20. */
|
|
132
|
+
function sectionHeader(label: string): string {
|
|
133
|
+
const total = 20;
|
|
134
|
+
const innerLen = label.length + 2; // account for spaces around label
|
|
135
|
+
const side = (total - innerLen) / 2;
|
|
136
|
+
const left = "─".repeat(Math.floor(side));
|
|
137
|
+
const right = "─".repeat(Math.ceil(side));
|
|
138
|
+
return `${left} ${label} ${right}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
110
141
|
// ---------------------------------------------------------------------------
|
|
111
142
|
// renderFlowCall — shown while the flow is being invoked
|
|
112
143
|
// ---------------------------------------------------------------------------
|
|
@@ -139,6 +170,7 @@ export function renderFlowResult(
|
|
|
139
170
|
type: flowRequest.type || "unknown",
|
|
140
171
|
agentSource: "user",
|
|
141
172
|
intent: flowRequest.intent || "Processing...",
|
|
173
|
+
aim: flowRequest.aim || flowRequest.intent || "Processing...",
|
|
142
174
|
exitCode: -1, // In progress
|
|
143
175
|
messages: [],
|
|
144
176
|
stderr: "",
|
|
@@ -203,12 +235,12 @@ function renderFlowExpanded(
|
|
|
203
235
|
|
|
204
236
|
// Intent
|
|
205
237
|
container.addChild(new Spacer(1));
|
|
206
|
-
container.addChild(new Text(theme.fg("muted", "
|
|
238
|
+
container.addChild(new Text(theme.fg("muted", sectionHeader("intent")), 0, 0));
|
|
207
239
|
container.addChild(new Text(theme.fg("dim", r.intent), 0, 0));
|
|
208
240
|
|
|
209
241
|
// Flow report (structured output)
|
|
210
242
|
container.addChild(new Spacer(1));
|
|
211
|
-
container.addChild(new Text(theme.fg("muted", "
|
|
243
|
+
container.addChild(new Text(theme.fg("muted", sectionHeader("report")), 0, 0));
|
|
212
244
|
if (flowOutput) {
|
|
213
245
|
container.addChild(new Markdown(flowOutput.trim(), 0, 0, mdTheme));
|
|
214
246
|
} else {
|
|
@@ -220,7 +252,7 @@ function renderFlowExpanded(
|
|
|
220
252
|
const toolTraces = renderToolTraces(displayItems, theme);
|
|
221
253
|
if (toolTraces) {
|
|
222
254
|
container.addChild(new Spacer(1));
|
|
223
|
-
container.addChild(new Text(theme.fg("muted", "
|
|
255
|
+
container.addChild(new Text(theme.fg("muted", sectionHeader("tool calls")), 0, 0));
|
|
224
256
|
container.addChild(new Text(toolTraces, 0, 0));
|
|
225
257
|
}
|
|
226
258
|
|
|
@@ -239,14 +271,14 @@ function renderFlowCollapsed(
|
|
|
239
271
|
const maxWidth = process.stdout.columns ?? 80;
|
|
240
272
|
const stats = formatCompactStats(r.usage, r.model, maxWidth);
|
|
241
273
|
const typeName = formatFlowTypeName(r.type);
|
|
242
|
-
let header = `${theme.fg("accent", theme.bold(typeName))} ${theme.fg("dim",
|
|
274
|
+
let header = `${theme.fg("accent", theme.bold(typeName))} ${theme.fg("dim", stats)}`;
|
|
243
275
|
if (error && r.stopReason) header += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
244
276
|
container.addChild(new TruncatedText(header, 0, 0));
|
|
245
277
|
|
|
246
|
-
//
|
|
247
|
-
if (r.
|
|
248
|
-
const dirContent = truncateChars(r.
|
|
249
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", "├─
|
|
278
|
+
// aim: line (short headline)
|
|
279
|
+
if (r.aim) {
|
|
280
|
+
const dirContent = truncateChars(r.aim, contentBudget(10));
|
|
281
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", "├─ aim:")} ${theme.fg("dim", dirContent)}`, 0, 0));
|
|
250
282
|
}
|
|
251
283
|
|
|
252
284
|
// act: line (last tool call with count)
|
|
@@ -258,18 +290,21 @@ function renderFlowCollapsed(
|
|
|
258
290
|
container.addChild(new TruncatedText(`${theme.fg("dim", "├─ " + actPrefix)}${actContent}`, 0, 0));
|
|
259
291
|
}
|
|
260
292
|
|
|
261
|
-
//
|
|
262
|
-
if (
|
|
263
|
-
const logContent =
|
|
264
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", "└─
|
|
293
|
+
// msg: line (last assistant text or streaming)
|
|
294
|
+
if (r.exitCode === -1 && streamingText) {
|
|
295
|
+
const logContent = tailText(streamingText, contentBudget(10));
|
|
296
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
|
|
297
|
+
} else if (flowOutput) {
|
|
298
|
+
const logContent = tailText(flowOutput, contentBudget(10));
|
|
299
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
|
|
265
300
|
} else if (streamingText) {
|
|
266
|
-
const logContent =
|
|
267
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", "└─
|
|
301
|
+
const logContent = tailText(streamingText, contentBudget(10));
|
|
302
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
|
|
268
303
|
} else if (error && r.errorMessage) {
|
|
269
304
|
const logContent = truncateChars(r.errorMessage, contentBudget(10));
|
|
270
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", "└─
|
|
305
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("error", logContent)}`, 0, 0));
|
|
271
306
|
} else {
|
|
272
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", "└─
|
|
307
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", "└─ msg:")} ${theme.fg("dim", "[n/a]")}`, 0, 0));
|
|
273
308
|
}
|
|
274
309
|
|
|
275
310
|
return container;
|
|
@@ -317,7 +352,7 @@ function renderMultiFlowExpanded(
|
|
|
317
352
|
|
|
318
353
|
container.addChild(new Spacer(1));
|
|
319
354
|
// Per-flow header: ─── EXPLORER (no icon)
|
|
320
|
-
container.addChild(new Text(
|
|
355
|
+
container.addChild(new Text(theme.fg("muted", sectionHeader(typeName)), 0, 0));
|
|
321
356
|
|
|
322
357
|
// Stats: dashboard format
|
|
323
358
|
const flowStats = formatCompactStats(r.usage, r.model);
|
|
@@ -335,7 +370,7 @@ function renderMultiFlowExpanded(
|
|
|
335
370
|
const toolTraces = renderToolTraces(displayItems, theme);
|
|
336
371
|
if (toolTraces) {
|
|
337
372
|
container.addChild(new Spacer(1));
|
|
338
|
-
container.addChild(new Text(theme.fg("muted", "
|
|
373
|
+
container.addChild(new Text(theme.fg("muted", sectionHeader("tool calls")), 0, 0));
|
|
339
374
|
container.addChild(new Text(toolTraces, 0, 0));
|
|
340
375
|
}
|
|
341
376
|
}
|
|
@@ -366,7 +401,7 @@ function renderActivityPanel(
|
|
|
366
401
|
|
|
367
402
|
// Header line
|
|
368
403
|
const headerPrefix = isLast ? "└─" : "├─";
|
|
369
|
-
let headerLine = `${theme.fg("dim", headerPrefix)} ${theme.fg("accent", theme.bold(typeName))} ${theme.fg("dim",
|
|
404
|
+
let headerLine = `${theme.fg("dim", headerPrefix)} ${theme.fg("accent", theme.bold(typeName))} ${theme.fg("dim", stats)}`;
|
|
370
405
|
if (error && r.stopReason) {
|
|
371
406
|
headerLine += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
372
407
|
}
|
|
@@ -375,10 +410,10 @@ function renderActivityPanel(
|
|
|
375
410
|
// Continuation indent for sub-lines
|
|
376
411
|
const indent = isLast ? " " : "│ ";
|
|
377
412
|
|
|
378
|
-
//
|
|
379
|
-
if (r.
|
|
380
|
-
const dirContent = truncateChars(r.
|
|
381
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "├─
|
|
413
|
+
// aim: line (short headline)
|
|
414
|
+
if (r.aim) {
|
|
415
|
+
const dirContent = truncateChars(r.aim, contentBudget(10));
|
|
416
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "├─ aim:")} ${theme.fg("dim", dirContent)}`, 0, 0));
|
|
382
417
|
}
|
|
383
418
|
|
|
384
419
|
// act: line (last tool call with count)
|
|
@@ -390,16 +425,17 @@ function renderActivityPanel(
|
|
|
390
425
|
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "├─ " + actPrefix)}${actContent}`, 0, 0));
|
|
391
426
|
}
|
|
392
427
|
|
|
393
|
-
//
|
|
394
|
-
const
|
|
428
|
+
// msg: line (live streaming text or last assistant text)
|
|
429
|
+
const liveText = r.exitCode === -1 ? r.streamingText : undefined;
|
|
430
|
+
const lastText = liveText || getLastAssistantText(r.messages);
|
|
395
431
|
if (lastText) {
|
|
396
|
-
const logContent =
|
|
397
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─
|
|
432
|
+
const logContent = tailText(lastText, contentBudget(10));
|
|
433
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─ msg:")} ${theme.fg("dim", logContent)}`, 0, 0));
|
|
398
434
|
} else if (error && r.errorMessage) {
|
|
399
435
|
const logContent = truncateChars(r.errorMessage, contentBudget(10));
|
|
400
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─
|
|
436
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─ msg:")} ${theme.fg("error", logContent)}`, 0, 0));
|
|
401
437
|
} else {
|
|
402
|
-
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─
|
|
438
|
+
container.addChild(new TruncatedText(`${theme.fg("dim", indent + "└─ msg:")} ${theme.fg("dim", "[n/a]")}`, 0, 0));
|
|
403
439
|
}
|
|
404
440
|
|
|
405
441
|
// Add blank line separator between flows (with continuation pipe)
|