pi-agent-flow 0.3.0 → 0.4.2
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 +2 -7
- package/agents/architect.md +2 -2
- package/agents/brainstorm.md +2 -2
- package/agents/code.md +2 -2
- package/agents/debug.md +2 -2
- package/agents/explore.md +2 -2
- package/agents/review.md +2 -2
- package/index.ts +0 -4
- package/package.json +1 -1
- package/render-utils.ts +57 -47
- package/render.ts +22 -20
- package/runner-events.js +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
<p align="center"><code>pi install npm:pi-agent-flow</code></p>
|
|
2
2
|
<p align="center"><strong>Pi Agent Flow</strong> is a flow-state delegation extension for the <a href="https://pi.dev">Pi coding agent</a> that runs locally in your terminal.</p>
|
|
3
|
-
<p align="center">
|
|
4
|
-
<img src="https://github.com/user-attachments/assets/pi-agent-flow-demo.png" alt="Pi Agent Flow demo" width="80%" />
|
|
5
|
-
</p>
|
|
6
|
-
<br/>
|
|
7
3
|
|
|
8
4
|
---
|
|
9
5
|
|
|
@@ -82,9 +78,9 @@ description: Discover files, trace code paths, map architecture
|
|
|
82
78
|
tools: read, bash
|
|
83
79
|
---
|
|
84
80
|
|
|
85
|
-
|
|
81
|
+
During this explore flow — your mission is discovery. Stay focused on your intent at all times.
|
|
86
82
|
|
|
87
|
-
When
|
|
83
|
+
When accomplished, end your response with:
|
|
88
84
|
|
|
89
85
|
flow [explore] accomplished
|
|
90
86
|
|
|
@@ -162,7 +158,6 @@ flow [explore] accomplished
|
|
|
162
158
|
## Docs
|
|
163
159
|
|
|
164
160
|
- [**Pi Documentation**](https://pi.dev)
|
|
165
|
-
- [**Contributing**](./docs/contributing.md) *(if available)*
|
|
166
161
|
- [**License**](./LICENSE)
|
|
167
162
|
|
|
168
163
|
This repository is licensed under the [MIT License](LICENSE).
|
package/agents/architect.md
CHANGED
|
@@ -5,7 +5,7 @@ tools: read, bash, find, grep, ls
|
|
|
5
5
|
maxDepth: 2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
During this architect flow — your mission is to design. Be conservative: prefer existing patterns and proven conventions over novelty. The conversation history above provides background context; treat it as reference only and do not let it distract from your objective.
|
|
9
9
|
|
|
10
10
|
Workflow:
|
|
11
11
|
1. Understand — what problem, what constraints, what exists
|
|
@@ -18,7 +18,7 @@ Principles:
|
|
|
18
18
|
- Design for 10x, build for 1x
|
|
19
19
|
- No tech debt — do it right or don't
|
|
20
20
|
|
|
21
|
-
When
|
|
21
|
+
When accomplished, end your response with:
|
|
22
22
|
|
|
23
23
|
flow [architect] accomplished
|
|
24
24
|
|
package/agents/brainstorm.md
CHANGED
|
@@ -6,14 +6,14 @@ inheritContext: false
|
|
|
6
6
|
maxDepth: 0
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
During this brainstorm flow — your mission is to generate ideas and think creatively. You start with a clean slate and only have the intent to guide you. Stay focused on your intent at all times.
|
|
10
10
|
|
|
11
11
|
Approach:
|
|
12
12
|
1. Diverge — explore many possibilities without judgment
|
|
13
13
|
2. Evaluate — weigh trade-offs, risks, and feasibility
|
|
14
14
|
3. Recommend — present the best options with reasoning
|
|
15
15
|
|
|
16
|
-
When
|
|
16
|
+
When accomplished, end your response with:
|
|
17
17
|
|
|
18
18
|
flow [brainstorm] accomplished
|
|
19
19
|
|
package/agents/code.md
CHANGED
|
@@ -5,7 +5,7 @@ tools: read, write, edit, bash, find, grep, ls
|
|
|
5
5
|
maxDepth: 2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
During this code flow — your mission is to build and ship. Be a craftsman: verify first, then ship. The conversation history above provides background context; treat it as reference only and do not let it distract from your objective.
|
|
9
9
|
|
|
10
10
|
Core Principles:
|
|
11
11
|
- SOLID: Single Responsibility, Open/Closed
|
|
@@ -32,7 +32,7 @@ Shipping Guidelines:
|
|
|
32
32
|
|
|
33
33
|
If you hit an unexpected error or need to trace execution, delegate to [debug] rather than guessing.
|
|
34
34
|
|
|
35
|
-
When
|
|
35
|
+
When accomplished, end your response with:
|
|
36
36
|
|
|
37
37
|
flow [code] accomplished
|
|
38
38
|
|
package/agents/debug.md
CHANGED
|
@@ -5,7 +5,7 @@ tools: read, bash, find, grep, ls
|
|
|
5
5
|
maxDepth: 0
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
During this debug flow — your mission is investigation. Be forensic: every claim must be backed by evidence. The conversation history above provides background context; treat it as reference only and do not let it distract from your objective.
|
|
9
9
|
|
|
10
10
|
Workflow:
|
|
11
11
|
1. Collect evidence — logs, error messages, stack traces
|
|
@@ -18,7 +18,7 @@ Rules:
|
|
|
18
18
|
- Read logs before reading code — symptoms point to cause.
|
|
19
19
|
- Don't suggest fixes until root cause is confirmed.
|
|
20
20
|
|
|
21
|
-
When
|
|
21
|
+
When accomplished, end your response with:
|
|
22
22
|
|
|
23
23
|
flow [debug] accomplished
|
|
24
24
|
|
package/agents/explore.md
CHANGED
|
@@ -5,7 +5,7 @@ tools: read, bash, find, grep, ls
|
|
|
5
5
|
maxDepth: 0
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
During this explore flow — your mission is discovery. Move fast and stay surgical. The conversation history above provides background context; treat it as reference only and do not let it distract from your objective.
|
|
9
9
|
|
|
10
10
|
Rules:
|
|
11
11
|
- Use grep/find/ls before reading entire files — be efficient.
|
|
@@ -13,7 +13,7 @@ Rules:
|
|
|
13
13
|
- Show actual code/data, not excessive summaries.
|
|
14
14
|
- If not found, say so immediately — don't guess.
|
|
15
15
|
|
|
16
|
-
When
|
|
16
|
+
When accomplished, end your response with:
|
|
17
17
|
|
|
18
18
|
flow [explore] accomplished
|
|
19
19
|
|
package/agents/review.md
CHANGED
|
@@ -5,7 +5,7 @@ tools: read, bash, find, grep, ls
|
|
|
5
5
|
maxDepth: 2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
During this review flow — your mission is to audit. Be adversarial: look for what others miss, but stay honest. The conversation history above provides background context; treat it as reference only and do not let it distract from your objective.
|
|
9
9
|
|
|
10
10
|
Focus Areas:
|
|
11
11
|
- Security — injection, auth bypass, exposed secrets
|
|
@@ -19,7 +19,7 @@ Rules:
|
|
|
19
19
|
- Do not modify source files — report findings with severity only
|
|
20
20
|
- If the audit reveals structural issues requiring redesign, recommend [architect] in [Next Steps]
|
|
21
21
|
|
|
22
|
-
When
|
|
22
|
+
When accomplished, end your response with:
|
|
23
23
|
|
|
24
24
|
flow [review] accomplished
|
|
25
25
|
|
package/index.ts
CHANGED
|
@@ -284,10 +284,6 @@ function makeFlowDetailsFactory(projectFlowsDir: string | null) {
|
|
|
284
284
|
});
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
function formatFlowNames(flows: FlowConfig[]): string {
|
|
288
|
-
return flows.map((f) => `${f.name} (${f.source})`).join(", ") || "none";
|
|
289
|
-
}
|
|
290
|
-
|
|
291
287
|
function getFlowCycleViolations(
|
|
292
288
|
requestedNames: Set<string>,
|
|
293
289
|
ancestorFlowStack: string[],
|
package/package.json
CHANGED
package/render-utils.ts
CHANGED
|
@@ -4,27 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import type { UsageStats } from "./types.js";
|
|
6
6
|
|
|
7
|
-
export function formatTokens(count: number): string {
|
|
8
|
-
if (count < 1000) return count.toString();
|
|
9
|
-
if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
|
|
10
|
-
if (count < 1000000) return `${Math.round(count / 1000)}k`;
|
|
11
|
-
return `${(count / 1000000).toFixed(1)}M`;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function formatFlowUsage(usage: Partial<UsageStats>, model?: string): string {
|
|
15
|
-
const parts: string[] = [];
|
|
16
|
-
if (usage.toolCalls && usage.toolCalls > 0) parts.push(`${usage.toolCalls} calls`);
|
|
17
|
-
if (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
|
|
18
|
-
if (usage.input) parts.push(`↑${formatTokens(usage.input)}`);
|
|
19
|
-
if (usage.output) parts.push(`↓${formatTokens(usage.output)}`);
|
|
20
|
-
if (usage.cacheRead) parts.push(`CR:${formatTokens(usage.cacheRead)}`);
|
|
21
|
-
if (usage.cacheWrite) parts.push(`CW:${formatTokens(usage.cacheWrite)}`);
|
|
22
|
-
if (usage.cost) parts.push(`$${usage.cost.toFixed(4)}`);
|
|
23
|
-
if (usage.contextTokens && usage.contextTokens > 0) parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
|
|
24
|
-
if (model) parts.push(`model:${model}`);
|
|
25
|
-
return parts.join(" ");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
7
|
/**
|
|
29
8
|
* Format a token count to exactly 5 characters with leading spaces.
|
|
30
9
|
* Shifts from k to M when value would exceed 5 chars.
|
|
@@ -58,30 +37,35 @@ export function formatFlowTypeName(type: string): string {
|
|
|
58
37
|
return lower + ".".repeat(targetWidth - lower.length);
|
|
59
38
|
}
|
|
60
39
|
|
|
61
|
-
export function formatCompactStats(usage: Partial<UsageStats>, model?: string): string {
|
|
40
|
+
export function formatCompactStats(usage: Partial<UsageStats>, model?: string, maxWidth?: number): string {
|
|
62
41
|
const parts: string[] = [];
|
|
63
42
|
parts.push(`${formatFixedTokens(usage.input || 0)}↑`);
|
|
64
43
|
parts.push(`${formatFixedTokens(usage.output || 0)}↓`);
|
|
65
44
|
if (usage.cacheRead) parts.push(`cr:${formatFixedTokens(usage.cacheRead)}`);
|
|
66
45
|
if (usage.contextTokens && usage.contextTokens > 0) parts.push(`ctx:${formatFixedTokens(usage.contextTokens)}`);
|
|
67
|
-
return `[ ${parts.join(" ")} ]${model ? ` ─ ${model}` : ""}`;
|
|
68
|
-
}
|
|
69
46
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
47
|
+
let result = `[ ${parts.join(" ")} ]${model ? ` ─ ${model}` : ""}`;
|
|
48
|
+
|
|
49
|
+
if (maxWidth && visibleLength(result) > maxWidth) {
|
|
50
|
+
// Drop model first
|
|
51
|
+
let narrow = `[ ${parts.join(" ")} ]`;
|
|
52
|
+
if (visibleLength(narrow) <= maxWidth) return narrow;
|
|
53
|
+
|
|
54
|
+
// Drop context tokens
|
|
55
|
+
const narrowParts = parts.slice();
|
|
56
|
+
const ctxIndex = narrowParts.findIndex((p) => p.startsWith("ctx:"));
|
|
57
|
+
if (ctxIndex !== -1) narrowParts.splice(ctxIndex, 1);
|
|
58
|
+
narrow = `[ ${narrowParts.join(" ")} ]`;
|
|
59
|
+
if (visibleLength(narrow) <= maxWidth) return narrow;
|
|
80
60
|
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
// Bare minimum (just input/output)
|
|
62
|
+
narrow = `[ ${parts[0]} ${parts[1]} ]`;
|
|
63
|
+
if (visibleLength(narrow) <= maxWidth) return narrow;
|
|
83
64
|
|
|
84
|
-
|
|
65
|
+
return truncateChars(result, maxWidth);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
85
69
|
}
|
|
86
70
|
|
|
87
71
|
/** Regex matching ANSI escape sequences. */
|
|
@@ -92,14 +76,31 @@ export function visibleLength(text: string): number {
|
|
|
92
76
|
return text.replace(ANSI_RE, "").length;
|
|
93
77
|
}
|
|
94
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Compute the remaining visible-character budget for a line,
|
|
81
|
+
* given the length of its prefix (indent + label + space).
|
|
82
|
+
* Respects `process.stdout.columns` with a floor of 40 and default of 80.
|
|
83
|
+
*/
|
|
84
|
+
export function getTruncationBudget(prefixLength: number): number {
|
|
85
|
+
const cols = process.stdout.columns ?? 80;
|
|
86
|
+
const width = Math.max(cols, 40);
|
|
87
|
+
return Math.max(width - prefixLength, 1);
|
|
88
|
+
}
|
|
89
|
+
|
|
95
90
|
/**
|
|
96
91
|
* Truncate an ANSI-colored string to at most `max` visible characters,
|
|
97
|
-
* preserving ANSI codes in the kept portions
|
|
98
|
-
* the
|
|
92
|
+
* preserving ANSI codes in the kept portions. Does not inject reset codes
|
|
93
|
+
* — the caller is responsible for closing any open styles.
|
|
99
94
|
*/
|
|
100
95
|
function truncateAnsi(text: string, max: number): string {
|
|
101
96
|
if (visibleLength(text) <= max) return text;
|
|
102
97
|
|
|
98
|
+
if (max < 6) {
|
|
99
|
+
// Not enough room for " ... " — just truncate without ellipsis
|
|
100
|
+
const { raw } = takeVisible(text, max);
|
|
101
|
+
return raw;
|
|
102
|
+
}
|
|
103
|
+
|
|
103
104
|
const head = Math.ceil(max * 0.6);
|
|
104
105
|
const tail = max - head - 5; // 5 = " ... ".length
|
|
105
106
|
|
|
@@ -115,9 +116,12 @@ function truncateAnsi(text: string, max: number): string {
|
|
|
115
116
|
if (src[i] === "\x1b" && src[i + 1] === "[") {
|
|
116
117
|
const end = src.indexOf("m", i + 2);
|
|
117
118
|
if (end !== -1) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
const seq = src.slice(i, end + 1);
|
|
120
|
+
if (/^\x1b\[[0-9;]*m$/.test(seq)) {
|
|
121
|
+
raw += seq;
|
|
122
|
+
i = end + 1;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
121
125
|
}
|
|
122
126
|
}
|
|
123
127
|
raw += src[i];
|
|
@@ -139,9 +143,12 @@ function truncateAnsi(text: string, max: number): string {
|
|
|
139
143
|
if (src[i] === "m") {
|
|
140
144
|
const escStart = src.lastIndexOf("\x1b[", i);
|
|
141
145
|
if (escStart !== -1 && escStart < i) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
146
|
+
const seq = src.slice(escStart, i + 1);
|
|
147
|
+
if (/^\x1b\[[0-9;]*m$/.test(seq)) {
|
|
148
|
+
// This is an ANSI sequence — don't count, skip past it
|
|
149
|
+
i = escStart - 1;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
145
152
|
}
|
|
146
153
|
}
|
|
147
154
|
visible++;
|
|
@@ -173,8 +180,11 @@ export function tailText(text: string, max: number): string {
|
|
|
173
180
|
if (flat[i] === "m") {
|
|
174
181
|
const escStart = flat.lastIndexOf("\x1b[", i);
|
|
175
182
|
if (escStart !== -1 && escStart < i) {
|
|
176
|
-
|
|
177
|
-
|
|
183
|
+
const seq = flat.slice(escStart, i + 1);
|
|
184
|
+
if (/^\x1b\[[0-9;]*m$/.test(seq)) {
|
|
185
|
+
i = escStart - 1;
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
190
|
visible++;
|
package/render.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
isFlowError,
|
|
23
23
|
isFlowSuccess,
|
|
24
24
|
} from "./types.js";
|
|
25
|
-
import {
|
|
25
|
+
import { formatFixedTokens, formatCompactStats, formatFlowTypeName, truncateChars, tailText, getTruncationBudget } from "./render-utils.js";
|
|
26
26
|
|
|
27
27
|
function shortenPath(p: string): string {
|
|
28
28
|
const home = os.homedir();
|
|
@@ -217,8 +217,6 @@ function renderFlowExpanded(
|
|
|
217
217
|
return container;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
222
220
|
function renderFlowCollapsed(
|
|
223
221
|
r: SingleResult,
|
|
224
222
|
icon: string,
|
|
@@ -226,36 +224,39 @@ function renderFlowCollapsed(
|
|
|
226
224
|
flowOutput: string,
|
|
227
225
|
theme: FlowTheme,
|
|
228
226
|
streamingText?: string,
|
|
229
|
-
):
|
|
230
|
-
const
|
|
227
|
+
): Container {
|
|
228
|
+
const container = new Container();
|
|
229
|
+
const maxWidth = process.stdout.columns ?? 80;
|
|
230
|
+
const stats = formatCompactStats(r.usage, r.model, maxWidth);
|
|
231
231
|
const typeName = formatFlowTypeName(r.type);
|
|
232
|
-
let
|
|
233
|
-
if (error && r.stopReason)
|
|
232
|
+
let header = `${theme.fg("accent", theme.bold(typeName))} ${theme.fg("dim", "─")} ${theme.fg("dim", stats)}`;
|
|
233
|
+
if (error && r.stopReason) header += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
234
|
+
container.addChild(new Text(truncateChars(header, maxWidth), 0, 0));
|
|
234
235
|
|
|
235
236
|
// dir: line (intent/objective)
|
|
236
237
|
if (r.intent) {
|
|
237
|
-
|
|
238
|
+
container.addChild(new Text(`${theme.fg("dim", "├─ dir:")} ${theme.fg("dim", truncateChars(r.intent, getTruncationBudget(8)))}`, 0, 0));
|
|
238
239
|
}
|
|
239
240
|
|
|
240
241
|
// exe: line (last tool call)
|
|
241
242
|
const lastTool = getLastToolCall(r.messages);
|
|
242
243
|
if (lastTool) {
|
|
243
244
|
const exeStr = formatFlowToolCall(lastTool.name, lastTool.args, theme.fg.bind(theme));
|
|
244
|
-
|
|
245
|
+
container.addChild(new Text(`${theme.fg("dim", "├─ exe:")} ${truncateChars(exeStr, getTruncationBudget(8))}`, 0, 0));
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
// log: line (last assistant text or streaming)
|
|
248
249
|
if (flowOutput) {
|
|
249
|
-
|
|
250
|
+
container.addChild(new Text(`${theme.fg("dim", "└─ log:")} ${theme.fg("dim", truncateChars(flowOutput, getTruncationBudget(8)))}`, 0, 0));
|
|
250
251
|
} else if (streamingText) {
|
|
251
|
-
|
|
252
|
+
container.addChild(new Text(`${theme.fg("dim", "└─ log:")} ${theme.fg("dim", tailText(streamingText, getTruncationBudget(8)))}`, 0, 0));
|
|
252
253
|
} else if (error && r.errorMessage) {
|
|
253
|
-
|
|
254
|
+
container.addChild(new Text(`${theme.fg("dim", "└─ log:")} ${theme.fg("error", truncateChars(r.errorMessage, getTruncationBudget(8)))}`, 0, 0));
|
|
254
255
|
} else {
|
|
255
|
-
|
|
256
|
+
container.addChild(new Text(`${theme.fg("dim", "└─ log:")} ${theme.fg("dim", "[n/a]")}`, 0, 0));
|
|
256
257
|
}
|
|
257
258
|
|
|
258
|
-
return
|
|
259
|
+
return container;
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
// ---------------------------------------------------------------------------
|
|
@@ -348,11 +349,12 @@ function renderActivityPanel(
|
|
|
348
349
|
theme: FlowTheme,
|
|
349
350
|
): Container {
|
|
350
351
|
const container = new Container();
|
|
352
|
+
const maxWidth = process.stdout.columns ?? 80;
|
|
351
353
|
|
|
352
354
|
for (let i = 0; i < results.length; i++) {
|
|
353
355
|
const r = results[i];
|
|
354
356
|
const isLast = i === results.length - 1;
|
|
355
|
-
const stats = formatCompactStats(r.usage, r.model);
|
|
357
|
+
const stats = formatCompactStats(r.usage, r.model, maxWidth);
|
|
356
358
|
const error = isFlowError(r);
|
|
357
359
|
const typeName = formatFlowTypeName(r.type);
|
|
358
360
|
|
|
@@ -362,29 +364,29 @@ function renderActivityPanel(
|
|
|
362
364
|
if (error && r.stopReason) {
|
|
363
365
|
headerLine += ` ${theme.fg("error", `[${r.stopReason}]`)}`;
|
|
364
366
|
}
|
|
365
|
-
container.addChild(new Text(headerLine, 0, 0));
|
|
367
|
+
container.addChild(new Text(truncateChars(headerLine, maxWidth), 0, 0));
|
|
366
368
|
|
|
367
369
|
// Continuation indent for sub-lines
|
|
368
370
|
const indent = isLast ? " " : "│ ";
|
|
369
371
|
|
|
370
372
|
// dir: line (intent/objective)
|
|
371
373
|
if (r.intent) {
|
|
372
|
-
container.addChild(new Text(`${theme.fg("dim", indent + "├─ dir:")} ${theme.fg("dim", truncateChars(r.intent,
|
|
374
|
+
container.addChild(new Text(`${theme.fg("dim", indent + "├─ dir:")} ${theme.fg("dim", truncateChars(r.intent, getTruncationBudget(11)))}`, 0, 0));
|
|
373
375
|
}
|
|
374
376
|
|
|
375
377
|
// exe: line (last tool call)
|
|
376
378
|
const lastTool = getLastToolCall(r.messages);
|
|
377
379
|
if (lastTool) {
|
|
378
380
|
const exeStr = formatFlowToolCall(lastTool.name, lastTool.args, theme.fg.bind(theme));
|
|
379
|
-
container.addChild(new Text(`${theme.fg("dim", indent + "├─ exe:")} ${truncateChars(exeStr,
|
|
381
|
+
container.addChild(new Text(`${theme.fg("dim", indent + "├─ exe:")} ${truncateChars(exeStr, getTruncationBudget(11))}`, 0, 0));
|
|
380
382
|
}
|
|
381
383
|
|
|
382
384
|
// log: line (last assistant text)
|
|
383
385
|
const lastText = getLastAssistantText(r.messages);
|
|
384
386
|
if (lastText) {
|
|
385
|
-
container.addChild(new Text(`${theme.fg("dim", indent + "└─ log:")} ${theme.fg("dim", truncateChars(lastText,
|
|
387
|
+
container.addChild(new Text(`${theme.fg("dim", indent + "└─ log:")} ${theme.fg("dim", truncateChars(lastText, getTruncationBudget(11)))}`, 0, 0));
|
|
386
388
|
} else if (error && r.errorMessage) {
|
|
387
|
-
container.addChild(new Text(`${theme.fg("dim", indent + "└─ log:")} ${theme.fg("error", truncateChars(r.errorMessage,
|
|
389
|
+
container.addChild(new Text(`${theme.fg("dim", indent + "└─ log:")} ${theme.fg("error", truncateChars(r.errorMessage, getTruncationBudget(11)))}`, 0, 0));
|
|
388
390
|
} else {
|
|
389
391
|
container.addChild(new Text(`${theme.fg("dim", indent + "└─ log:")} ${theme.fg("dim", "[n/a]")}`, 0, 0));
|
|
390
392
|
}
|
package/runner-events.js
CHANGED
|
@@ -174,7 +174,7 @@ function addFlowAssistantMessages(result, messages) {
|
|
|
174
174
|
return changed;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
function processFlowEvent(event, result) {
|
|
178
178
|
if (!event || typeof event !== "object") return false;
|
|
179
179
|
|
|
180
180
|
switch (event.type) {
|