pi-agent-flow 2.0.0 → 2.0.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 +126 -489
- package/agents/audit.md +7 -2
- package/agents/build.md +6 -2
- package/agents/craft.md +6 -3
- package/agents/debug.md +7 -3
- package/agents/ideas.md +8 -4
- package/agents/scout.md +8 -1
- package/dist/batch/apply-patch.d.ts +60 -0
- package/dist/batch/apply-patch.d.ts.map +1 -0
- package/dist/batch/apply-patch.js +477 -0
- package/dist/batch/apply-patch.js.map +1 -0
- package/dist/batch/batch-bash.d.ts +0 -6
- package/dist/batch/batch-bash.d.ts.map +1 -1
- package/dist/batch/batch-bash.js +52 -14
- package/dist/batch/batch-bash.js.map +1 -1
- package/dist/batch/constants.d.ts +45 -4
- package/dist/batch/constants.d.ts.map +1 -1
- package/dist/batch/constants.js +72 -4
- package/dist/batch/constants.js.map +1 -1
- package/dist/batch/execute.d.ts +8 -2
- package/dist/batch/execute.d.ts.map +1 -1
- package/dist/batch/execute.js +338 -70
- package/dist/batch/execute.js.map +1 -1
- package/dist/batch/fuzzy-edit.d.ts +4 -1
- package/dist/batch/fuzzy-edit.d.ts.map +1 -1
- package/dist/batch/fuzzy-edit.js +7 -2
- package/dist/batch/fuzzy-edit.js.map +1 -1
- package/dist/batch/index.d.ts +3 -15
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +48 -78
- package/dist/batch/index.js.map +1 -1
- package/dist/batch/render.d.ts.map +1 -1
- package/dist/batch/render.js +30 -7
- package/dist/batch/render.js.map +1 -1
- package/dist/batch/shell-compress.d.ts +25 -0
- package/dist/batch/shell-compress.d.ts.map +1 -0
- package/dist/batch/shell-compress.js +602 -0
- package/dist/batch/shell-compress.js.map +1 -0
- package/dist/batch/summary.d.ts.map +1 -1
- package/dist/batch/summary.js +4 -0
- package/dist/batch/summary.js.map +1 -1
- package/dist/batch/symbols.d.ts.map +1 -1
- package/dist/batch/symbols.js +12 -7
- package/dist/batch/symbols.js.map +1 -1
- package/dist/config/config.d.ts +5 -0
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +63 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/models.d.ts +2 -0
- package/dist/config/models.d.ts.map +1 -0
- package/dist/config/models.js +49 -0
- package/dist/config/models.js.map +1 -0
- package/dist/config/settings-resolver.js +2 -2
- package/dist/config/settings-resolver.js.map +1 -1
- package/dist/core/agents.js +2 -2
- package/dist/core/agents.js.map +1 -1
- package/dist/core/depth.d.ts +3 -3
- package/dist/core/depth.d.ts.map +1 -1
- package/dist/core/depth.js +5 -5
- package/dist/core/depth.js.map +1 -1
- package/dist/core/executor.d.ts +10 -3
- package/dist/core/executor.d.ts.map +1 -1
- package/dist/core/executor.js +7 -3
- package/dist/core/executor.js.map +1 -1
- package/dist/core/flow.d.ts +19 -3
- package/dist/core/flow.d.ts.map +1 -1
- package/dist/core/flow.js +97 -58
- package/dist/core/flow.js.map +1 -1
- package/dist/core/session-mode.d.ts +1 -1
- package/dist/core/session-mode.d.ts.map +1 -1
- package/dist/core/session-mode.js +2 -1
- package/dist/core/session-mode.js.map +1 -1
- package/dist/core/{delegation.d.ts → transition.d.ts} +9 -9
- package/dist/core/transition.d.ts.map +1 -0
- package/dist/core/{delegation.js → transition.js} +17 -24
- package/dist/core/transition.js.map +1 -0
- package/dist/flow/auto-warp.d.ts +12 -0
- package/dist/flow/auto-warp.d.ts.map +1 -0
- package/dist/flow/auto-warp.js +29 -0
- package/dist/flow/auto-warp.js.map +1 -0
- package/dist/flow/command.d.ts.map +1 -1
- package/dist/flow/command.js +7 -2
- package/dist/flow/command.js.map +1 -1
- package/dist/flow/continuation.d.ts.map +1 -1
- package/dist/flow/continuation.js +52 -15
- package/dist/flow/continuation.js.map +1 -1
- package/dist/flow/index.d.ts +5 -2
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +6 -3
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/loop-command.d.ts +8 -0
- package/dist/flow/loop-command.d.ts.map +1 -0
- package/dist/flow/loop-command.js +102 -0
- package/dist/flow/loop-command.js.map +1 -0
- package/dist/flow/loop-templates.d.ts +7 -0
- package/dist/flow/loop-templates.d.ts.map +1 -0
- package/dist/flow/loop-templates.js +38 -0
- package/dist/flow/loop-templates.js.map +1 -0
- package/dist/flow/loop.d.ts +19 -0
- package/dist/flow/loop.d.ts.map +1 -0
- package/dist/flow/loop.js +95 -0
- package/dist/flow/loop.js.map +1 -0
- package/dist/flow/settings-command.d.ts.map +1 -1
- package/dist/flow/settings-command.js +93 -4
- package/dist/flow/settings-command.js.map +1 -1
- package/dist/flow/store.d.ts +3 -3
- package/dist/flow/store.d.ts.map +1 -1
- package/dist/flow/store.js +24 -16
- package/dist/flow/store.js.map +1 -1
- package/dist/flow/template-shared.d.ts +9 -0
- package/dist/flow/template-shared.d.ts.map +1 -0
- package/dist/flow/template-shared.js +13 -0
- package/dist/flow/template-shared.js.map +1 -0
- package/dist/flow/template-strings.d.ts.map +1 -1
- package/dist/flow/template-strings.js +2 -5
- package/dist/flow/template-strings.js.map +1 -1
- package/dist/flow/types.d.ts +15 -9
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/flow/warp.d.ts +15 -0
- package/dist/flow/warp.d.ts.map +1 -0
- package/dist/flow/warp.js +207 -0
- package/dist/flow/warp.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +185 -28
- package/dist/index.js.map +1 -1
- package/dist/snapshot/cli-args.d.ts +1 -0
- package/dist/snapshot/cli-args.d.ts.map +1 -1
- package/dist/snapshot/cli-args.js +12 -0
- package/dist/snapshot/cli-args.js.map +1 -1
- package/dist/snapshot/runner-events.d.ts +5 -0
- package/dist/snapshot/runner-events.d.ts.map +1 -1
- package/dist/snapshot/runner-events.js +89 -15
- package/dist/snapshot/runner-events.js.map +1 -1
- package/dist/snapshot/snapshot.d.ts +22 -19
- package/dist/snapshot/snapshot.d.ts.map +1 -1
- package/dist/snapshot/snapshot.js +1063 -167
- package/dist/snapshot/snapshot.js.map +1 -1
- package/dist/steering/flow-prompt.d.ts +2 -2
- package/dist/steering/flow-prompt.d.ts.map +1 -1
- package/dist/steering/flow-prompt.js +4 -4
- package/dist/steering/flow-prompt.js.map +1 -1
- package/dist/steering/sliding-prompt.d.ts.map +1 -1
- package/dist/steering/sliding-prompt.js +9 -6
- package/dist/steering/sliding-prompt.js.map +1 -1
- package/dist/steering/tool-utils.d.ts +31 -8
- package/dist/steering/tool-utils.d.ts.map +1 -1
- package/dist/steering/tool-utils.js +63 -30
- package/dist/steering/tool-utils.js.map +1 -1
- package/dist/tools/ask-user.d.ts +0 -17
- package/dist/tools/ask-user.d.ts.map +1 -1
- package/dist/tools/ask-user.js +13 -37
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/timed-bash.d.ts +1 -1
- package/dist/tools/timed-bash.d.ts.map +1 -1
- package/dist/tools/timed-bash.js +19 -8
- package/dist/tools/timed-bash.js.map +1 -1
- package/dist/tools/web-tool.d.ts.map +1 -1
- package/dist/tools/web-tool.js +11 -13
- package/dist/tools/web-tool.js.map +1 -1
- package/dist/tui/render-utils.d.ts +5 -1
- package/dist/tui/render-utils.d.ts.map +1 -1
- package/dist/tui/render-utils.js +36 -10
- package/dist/tui/render-utils.js.map +1 -1
- package/dist/tui/render.d.ts +9 -0
- package/dist/tui/render.d.ts.map +1 -1
- package/dist/tui/render.js +112 -100
- package/dist/tui/render.js.map +1 -1
- package/dist/tui/scramble/constants.d.ts +8 -8
- package/dist/tui/scramble/constants.d.ts.map +1 -1
- package/dist/tui/scramble/constants.js +7 -7
- package/dist/tui/scramble/constants.js.map +1 -1
- package/dist/tui/scramble/index.d.ts +1 -1
- package/dist/tui/scramble/index.d.ts.map +1 -1
- package/dist/tui/scramble/index.js +1 -1
- package/dist/tui/scramble/index.js.map +1 -1
- package/dist/tui/scramble/manager.d.ts +1 -5
- package/dist/tui/scramble/manager.d.ts.map +1 -1
- package/dist/tui/scramble/manager.js +16 -64
- package/dist/tui/scramble/manager.js.map +1 -1
- package/dist/tui/scramble/utils.js +1 -1
- package/dist/tui/scramble/utils.js.map +1 -1
- package/dist/types/flow.d.ts +2 -0
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/flow.js +11 -2
- package/dist/types/flow.js.map +1 -1
- package/dist/types/output.d.ts +6 -0
- package/dist/types/output.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/core/delegation.d.ts.map +0 -1
- package/dist/core/delegation.js.map +0 -1
- package/dist/flow/warp-command.d.ts +0 -9
- package/dist/flow/warp-command.d.ts.map +0 -1
- package/dist/flow/warp-command.js +0 -405
- package/dist/flow/warp-command.js.map +0 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warp extension — transfer context to a new focused session
|
|
3
|
+
*
|
|
4
|
+
* Instead of compacting (which is lossy), warp extracts what matters
|
|
5
|
+
* for your next task and creates a new session with a generated prompt.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* /flow:warp now implement this for teams as well
|
|
9
|
+
* /flow:warp execute phase one of the plan
|
|
10
|
+
* /flow:warp check other places that need this fix
|
|
11
|
+
* /flow:warp (no args = default continuation goal)
|
|
12
|
+
*/
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return typeof value === "object" && value !== null;
|
|
15
|
+
}
|
|
16
|
+
const WARP_TIMEOUT_MS = 5 * 60 * 1000;
|
|
17
|
+
const WARP_POLL_INTERVAL_MS = 25;
|
|
18
|
+
const WARP_INSTRUCTIONS = `You are writing a warp note for another AI agent with NO access to this chat.
|
|
19
|
+
|
|
20
|
+
Extract only task-relevant context from this conversation.
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
- Be tight and token-efficient.
|
|
24
|
+
- Use only concrete facts from this conversation.
|
|
25
|
+
- Prefer specifics: file paths, symbols, commands, errors, outputs, decisions.
|
|
26
|
+
- Include constraints/invariants only when explicit, non-negotiable, and task-relevant.
|
|
27
|
+
- Include line numbers only if known from this conversation.
|
|
28
|
+
- Omit irrelevant history and broad retrospectives.
|
|
29
|
+
- Do not invent missing details.
|
|
30
|
+
- If a critical detail is unknown, say so briefly and include the smallest verification step.
|
|
31
|
+
- Do not write a plan unless one already exists in this conversation.
|
|
32
|
+
- Do not call tools.
|
|
33
|
+
|
|
34
|
+
Your output MUST use this exact format:
|
|
35
|
+
|
|
36
|
+
FRONTMATTER (YAML between --- delimiters):
|
|
37
|
+
context — 1-2 sentence orientation summary
|
|
38
|
+
end_goal — The finish line, not the next step
|
|
39
|
+
decisions — Key choices already made (list)
|
|
40
|
+
files — Files touched with what changed (list)
|
|
41
|
+
open_items — Unresolved work or questions (list)
|
|
42
|
+
watch_out — Edge cases, gotchas, fragile assumptions (list)
|
|
43
|
+
context_gathering:
|
|
44
|
+
aim — What the initial scout/discovery should accomplish
|
|
45
|
+
scope — Specific things to explore or map (list)
|
|
46
|
+
execution_plan:
|
|
47
|
+
- phase — Phase name
|
|
48
|
+
parallel — true/false, can this run alongside other phases?
|
|
49
|
+
group — If parallel, which execution group (A, B, C...)
|
|
50
|
+
flow — Which flow type to use (scout, build, audit, craft...)
|
|
51
|
+
flows — OR multiple flows if parallel within the phase
|
|
52
|
+
task — Clear, actionable task for this phase
|
|
53
|
+
depends_on — Phase(s) that must complete first
|
|
54
|
+
produces — What "done" means for this phase
|
|
55
|
+
success_criteria — How to know the overall work is complete (list)
|
|
56
|
+
|
|
57
|
+
BODY (after the closing ---):
|
|
58
|
+
## Context
|
|
59
|
+
A concise summary of the conversation context.
|
|
60
|
+
|
|
61
|
+
RULES:
|
|
62
|
+
1. Always start with a context_gathering phase — the new session has no context yet, so discovery comes first.
|
|
63
|
+
2. Mark phases parallel:true when they have no data dependencies on each other. Use group labels (A, B, C) to cluster parallel work.
|
|
64
|
+
3. Each phase should produce a concrete artifact, evidence of completion before moving on to the next.
|
|
65
|
+
4. Respect the given plan scaffold.
|
|
66
|
+
5. Use flow types from: scout, build, audit, craft, debug, ideas.
|
|
67
|
+
6. Success criteria should be the final state, i.e. integration test pass, code coverage with verified output, etc.
|
|
68
|
+
7. If an active goal from the prior session exists, include it in the frontmatter context.
|
|
69
|
+
8. Preserve unresolved blockers, open questions, or "not done" items from prior flow results in open_items.
|
|
70
|
+
9. Flag any uncertain areas — parts of the codebase, design decisions, or assumptions that may have shifted since the conversation and need re-assessment via a scout or audit flow before committing to a plan.
|
|
71
|
+
10. No tool calls; all attempts that you need to discover, note them to the watch_out list or execution_plan.
|
|
72
|
+
11. Your entire response must be the warp prompt starting with '---' (YAML frontmatter opening). No preamble, no explanations, no tool calls.
|
|
73
|
+
|
|
74
|
+
IMPORTANT: You are a text generation assistant, not an agent. Do NOT attempt tool calls, file operations, code execution, or any actions. Output ONLY the structured prompt text.`;
|
|
75
|
+
function getRoleMessage(entry, role) {
|
|
76
|
+
if (entry.type !== "message" || !isRecord(entry.message)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const message = entry.message;
|
|
80
|
+
if (message.role !== role || !("content" in message)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return message;
|
|
84
|
+
}
|
|
85
|
+
function getAssistantMessage(entry) {
|
|
86
|
+
const message = getRoleMessage(entry, "assistant");
|
|
87
|
+
if (!message || !isRecord(message)) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return message;
|
|
91
|
+
}
|
|
92
|
+
function getMessageText(entry) {
|
|
93
|
+
if (entry.type !== "message" || !isRecord(entry.message) || !("content" in entry.message)) {
|
|
94
|
+
return "";
|
|
95
|
+
}
|
|
96
|
+
const content = entry.message.content;
|
|
97
|
+
if (typeof content === "string") {
|
|
98
|
+
return content.trim();
|
|
99
|
+
}
|
|
100
|
+
if (!Array.isArray(content)) {
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
return content
|
|
104
|
+
.filter((block) => isRecord(block) && block.type === "text" && typeof block.text === "string")
|
|
105
|
+
.map((block) => block.text)
|
|
106
|
+
.join("\n")
|
|
107
|
+
.trim();
|
|
108
|
+
}
|
|
109
|
+
function findUserMessageIndex(entries, fromIndex, text) {
|
|
110
|
+
for (let i = entries.length - 1; i >= fromIndex; i--) {
|
|
111
|
+
const entry = entries[i];
|
|
112
|
+
if (!getRoleMessage(entry, "user")) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (getMessageText(entry) === text) {
|
|
116
|
+
return i;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return -1;
|
|
120
|
+
}
|
|
121
|
+
function hasAssistantAfterIndex(entries, fromIndex) {
|
|
122
|
+
for (let i = entries.length - 1; i > fromIndex; i--) {
|
|
123
|
+
const entry = entries[i];
|
|
124
|
+
if (getRoleMessage(entry, "assistant")) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
async function waitForWarpTurn(ctx, startIndex, warpRequest, timeoutMs = WARP_TIMEOUT_MS) {
|
|
131
|
+
const deadline = Date.now() + timeoutMs;
|
|
132
|
+
while (Date.now() < deadline) {
|
|
133
|
+
const branch = ctx.sessionManager.getBranch();
|
|
134
|
+
const warpUserIndex = findUserMessageIndex(branch, startIndex, warpRequest);
|
|
135
|
+
if (warpUserIndex !== -1 && hasAssistantAfterIndex(branch, warpUserIndex) && ctx.isIdle()) {
|
|
136
|
+
return { branch, warpUserIndex };
|
|
137
|
+
}
|
|
138
|
+
await new Promise((resolve) => setTimeout(resolve, WARP_POLL_INTERVAL_MS));
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
function getAssistantText(entries, fromIndex) {
|
|
143
|
+
for (let i = entries.length - 1; i >= fromIndex; i--) {
|
|
144
|
+
const entry = entries[i];
|
|
145
|
+
const message = getAssistantMessage(entry);
|
|
146
|
+
if (!message) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (message.stopReason !== "stop") {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const text = getMessageText(entry);
|
|
153
|
+
if (text.length > 0) {
|
|
154
|
+
return text;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const DEFAULT_GOAL = "Continue where we left off — summarize what we have done, where we are, and what the natural next step is.";
|
|
160
|
+
export default function (pi) {
|
|
161
|
+
pi.registerCommand("flow:warp", {
|
|
162
|
+
description: "Transfer context to a new focused session",
|
|
163
|
+
handler: async (args, ctx) => {
|
|
164
|
+
const notify = (message, level) => {
|
|
165
|
+
ctx.ui?.notify?.(message, level);
|
|
166
|
+
};
|
|
167
|
+
if (!ctx.model) {
|
|
168
|
+
notify("No model selected", "error");
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const task = args.trim() || DEFAULT_GOAL;
|
|
172
|
+
const currentSessionFile = ctx.sessionManager.getSessionFile();
|
|
173
|
+
const startIndex = ctx.sessionManager.getBranch().length;
|
|
174
|
+
const warpRequest = `${WARP_INSTRUCTIONS}\n\nTask for the next agent:\n${task}`;
|
|
175
|
+
if (ctx.isIdle()) {
|
|
176
|
+
pi.sendUserMessage(warpRequest);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
pi.sendUserMessage(warpRequest, { deliverAs: "followUp" });
|
|
180
|
+
}
|
|
181
|
+
notify("Generating warp note...", "info");
|
|
182
|
+
const warpTurn = await waitForWarpTurn(ctx, startIndex, warpRequest);
|
|
183
|
+
if (!warpTurn) {
|
|
184
|
+
notify("Timed out waiting for warp note", "error");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const warpNote = getAssistantText(warpTurn.branch, warpTurn.warpUserIndex + 1);
|
|
188
|
+
if (!warpNote) {
|
|
189
|
+
notify("Failed to capture warp note from the assistant response", "error");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const promptForNewSession = `${warpNote}\n\n---\n\n## Task\n${task}`;
|
|
193
|
+
const newSessionResult = await ctx.newSession({
|
|
194
|
+
parentSession: currentSessionFile,
|
|
195
|
+
withSession: async (newCtx) => {
|
|
196
|
+
await newCtx.sendUserMessage(promptForNewSession);
|
|
197
|
+
newCtx.ui?.notify?.("Warp ready...", "info");
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
if (newSessionResult.cancelled) {
|
|
201
|
+
notify("New session cancelled", "info");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=warp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warp.js","sourceRoot":"","sources":["../../src/flow/warp.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* Each flow receives a forked snapshot of the current session context.
|
|
6
6
|
*/
|
|
7
7
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
8
|
-
|
|
9
|
-
export {
|
|
8
|
+
import { logWarn, logError } from "./config/log.js";
|
|
9
|
+
export { logWarn, logError };
|
|
10
|
+
export { compressToolResults, stripBatchReadToolCalls } from "./snapshot/snapshot.js";
|
|
10
11
|
export { type FlowColorConfig } from "./tui/flow-colors.js";
|
|
11
12
|
export default function (pi: ExtensionAPI): void;
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;AA+CpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AA+K7B,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAM5D,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QAycxC"}
|
package/dist/index.js
CHANGED
|
@@ -10,25 +10,133 @@ import { discoverFlows, getFlowTier } from "./core/agents.js";
|
|
|
10
10
|
import { getInheritedCliArgs } from "./snapshot/cli-args.js";
|
|
11
11
|
import { renderFlowCall, renderFlowResult } from "./tui/render.js";
|
|
12
12
|
import { terminateAllChildGroups } from "./core/flow.js";
|
|
13
|
-
import { executeFlows } from "./core/executor.js";
|
|
14
|
-
import {
|
|
13
|
+
import { executeFlows, evictCacheOverflow } from "./core/executor.js";
|
|
14
|
+
import { appendDirectiveOnce, resetDirectiveTracker, configureDirective, stripDirectivesFromMessages } from "./steering/tool-utils.js";
|
|
15
15
|
import { createBatchTool, createBatchReadTool, BashProcessTracker, createBatchBashPollTool, } from "./batch/index.js";
|
|
16
16
|
import { createWebTool } from "./tools/web-tool.js";
|
|
17
17
|
import { createAskUserTool } from "./tools/ask-user.js";
|
|
18
18
|
import { stripSteeringHintText, stripSteeringHintsFromMessages, makeSteeringHintMessage, configureSteering, } from "./steering/sliding-prompt.js";
|
|
19
|
-
import { registerFlow, getGoalForSession, recordFlowCompletion, addTokens, shutdownWakeup } from "./flow/index.js";
|
|
19
|
+
import { registerFlow, getGoal, getGoalForSession, recordFlowCompletion, addTokens, shutdownWakeup } from "./flow/index.js";
|
|
20
20
|
import * as sessionRegistry from "./core/session-registry.js";
|
|
21
21
|
import { createTimedBashToolDefinition } from "./tools/timed-bash.js";
|
|
22
22
|
import { resolveFlowDepthConfig, } from "./core/depth.js";
|
|
23
23
|
import { buildForkSessionSnapshotJsonl, sanitizeForkSnapshot, } from "./snapshot/snapshot.js";
|
|
24
24
|
import { resolveSettings, } from "./config/settings-resolver.js";
|
|
25
25
|
import { scrambleManager } from "./tui/scramble/index.js";
|
|
26
|
-
|
|
26
|
+
import { logWarn, logError } from "./config/log.js";
|
|
27
|
+
export { logWarn, logError };
|
|
27
28
|
// ---------------------------------------------------------------------------
|
|
28
29
|
// Persistent flow result cache — shared across execute() calls so historical
|
|
29
30
|
// flow results are compressed properly in fork snapshots.
|
|
30
31
|
// ---------------------------------------------------------------------------
|
|
31
32
|
const flowResultCache = new Map();
|
|
33
|
+
/**
|
|
34
|
+
* Reconstruct flowResultCache from an existing session branch after restart.
|
|
35
|
+
* Scans tool results for the "flow" tool and rebuilds CompressedFlowResult
|
|
36
|
+
* entries so child-fork compression works immediately without waiting for
|
|
37
|
+
* new flows to complete.
|
|
38
|
+
*/
|
|
39
|
+
function reconstructFlowResultCache(sessionManager, cache) {
|
|
40
|
+
const branch = sessionManager.getBranch();
|
|
41
|
+
if (!Array.isArray(branch) || branch.length === 0)
|
|
42
|
+
return;
|
|
43
|
+
// Pass 1: map toolCallId -> "flow" from assistant messages
|
|
44
|
+
const toolCallIdToName = new Map();
|
|
45
|
+
for (const entry of branch) {
|
|
46
|
+
if (!entry || typeof entry !== "object")
|
|
47
|
+
continue;
|
|
48
|
+
const e = entry;
|
|
49
|
+
if (e.type !== "message")
|
|
50
|
+
continue;
|
|
51
|
+
const msg = e.message;
|
|
52
|
+
if (!msg || msg.role !== "assistant")
|
|
53
|
+
continue;
|
|
54
|
+
const content = msg.content;
|
|
55
|
+
if (!Array.isArray(content))
|
|
56
|
+
continue;
|
|
57
|
+
for (const part of content) {
|
|
58
|
+
if (!part || typeof part !== "object")
|
|
59
|
+
continue;
|
|
60
|
+
const p = part;
|
|
61
|
+
if (p.type === "toolCall" && p.name === "flow") {
|
|
62
|
+
const tcId = (p.id ?? p.toolCallId);
|
|
63
|
+
if (tcId)
|
|
64
|
+
toolCallIdToName.set(tcId, "flow");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Pass 2: scan tool/toolResult messages and rebuild cache
|
|
69
|
+
for (const entry of branch) {
|
|
70
|
+
if (!entry || typeof entry !== "object")
|
|
71
|
+
continue;
|
|
72
|
+
const e = entry;
|
|
73
|
+
if (e.type !== "message")
|
|
74
|
+
continue;
|
|
75
|
+
const msg = e.message;
|
|
76
|
+
if (!msg || (msg.role !== "tool" && msg.role !== "toolResult"))
|
|
77
|
+
continue;
|
|
78
|
+
let toolCallId;
|
|
79
|
+
if (typeof msg.toolCallId === "string" && msg.toolCallId.trim()) {
|
|
80
|
+
toolCallId = msg.toolCallId;
|
|
81
|
+
}
|
|
82
|
+
else if (Array.isArray(msg.content)) {
|
|
83
|
+
for (const part of msg.content) {
|
|
84
|
+
if (!part || typeof part !== "object")
|
|
85
|
+
continue;
|
|
86
|
+
const p = part;
|
|
87
|
+
if (p.type === "toolResult" && typeof p.toolCallId === "string" && p.toolCallId.trim()) {
|
|
88
|
+
toolCallId = p.toolCallId;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (!toolCallId || toolCallIdToName.get(toolCallId) !== "flow")
|
|
94
|
+
continue;
|
|
95
|
+
const details = msg.details;
|
|
96
|
+
if (!details || !Array.isArray(details.results))
|
|
97
|
+
continue;
|
|
98
|
+
const results = details.results;
|
|
99
|
+
const compressed = [];
|
|
100
|
+
for (const r of results) {
|
|
101
|
+
const so = r.structuredOutput;
|
|
102
|
+
if (!so)
|
|
103
|
+
continue;
|
|
104
|
+
const c = {
|
|
105
|
+
type: typeof r.type === "string" ? r.type : "unknown",
|
|
106
|
+
status: typeof r.exitCode === "number" && r.exitCode === 0 ? "accomplished" : "failed",
|
|
107
|
+
};
|
|
108
|
+
if (typeof r.intent === "string")
|
|
109
|
+
c.intent = r.intent;
|
|
110
|
+
if (typeof r.aim === "string")
|
|
111
|
+
c.aim = r.aim;
|
|
112
|
+
if (typeof so.summary === "string")
|
|
113
|
+
c.summary = so.summary;
|
|
114
|
+
if (Array.isArray(so.files))
|
|
115
|
+
c.files = so.files;
|
|
116
|
+
if (Array.isArray(so.actions))
|
|
117
|
+
c.actions = so.actions;
|
|
118
|
+
if (Array.isArray(so.commands))
|
|
119
|
+
c.commands = so.commands;
|
|
120
|
+
if (Array.isArray(so.notDone))
|
|
121
|
+
c.notDone = so.notDone;
|
|
122
|
+
if (Array.isArray(so.nextSteps))
|
|
123
|
+
c.nextSteps = so.nextSteps;
|
|
124
|
+
if (Array.isArray(so.reasoning))
|
|
125
|
+
c.reasoning = so.reasoning;
|
|
126
|
+
if (Array.isArray(so.notes))
|
|
127
|
+
c.notes = so.notes;
|
|
128
|
+
if (typeof r.errorMessage === "string")
|
|
129
|
+
c.error = r.errorMessage;
|
|
130
|
+
compressed.push(c);
|
|
131
|
+
}
|
|
132
|
+
if (compressed.length > 0) {
|
|
133
|
+
const existing = cache.get(toolCallId) ?? [];
|
|
134
|
+
existing.push(...compressed);
|
|
135
|
+
cache.set(toolCallId, existing);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
evictCacheOverflow(cache);
|
|
139
|
+
}
|
|
32
140
|
import { computeActiveTools, buildBeforeAgentStartPrompt, } from "./steering/flow-prompt.js";
|
|
33
141
|
// ---------------------------------------------------------------------------
|
|
34
142
|
// Tool parameter schema
|
|
@@ -46,12 +154,13 @@ const FlowItem = Type.Object({
|
|
|
46
154
|
acceptance: Type.Optional(Type.String({ description: "Short success criteria — one sentence stating what done looks like." })),
|
|
47
155
|
cwd: Type.Optional(Type.String({ description: "Working directory override for this flow." })),
|
|
48
156
|
sessionMode: Type.Optional(Type.Union([
|
|
157
|
+
Type.Literal("snap"),
|
|
49
158
|
Type.Literal("fast"),
|
|
50
159
|
Type.Literal("default"),
|
|
51
160
|
Type.Literal("long"),
|
|
52
161
|
Type.Literal("extreme_long"),
|
|
53
162
|
], {
|
|
54
|
-
description: "Agent session budget for this flow: fast=300s, default=600s, long=900s, extreme_long=1200s. Use long or extreme_long only when the work genuinely needs the larger budget.",
|
|
163
|
+
description: "Agent session budget for this flow: snap=90s, fast=300s, default=600s, long=900s, extreme_long=1200s. Use long or extreme_long only when the work genuinely needs the larger budget.",
|
|
55
164
|
})),
|
|
56
165
|
}, {
|
|
57
166
|
title: "FlowTask",
|
|
@@ -60,7 +169,7 @@ const FlowItem = Type.Object({
|
|
|
60
169
|
const FlowParams = Type.Object({
|
|
61
170
|
flow: Type.Array(FlowItem, {
|
|
62
171
|
description: "Array of flow tasks to execute. Each runs in its own forked process. " +
|
|
63
|
-
"Optional sessionMode selects the
|
|
172
|
+
"Optional sessionMode selects the flow state budget: fast=300s, default=600s, long=900s, extreme_long=1200s.",
|
|
64
173
|
examples: [
|
|
65
174
|
{ type: "scout", intent: "Map auth module files and trace JWT validation path", aim: "Map auth and trace JWT" },
|
|
66
175
|
{ type: "audit", intent: "Audit input validation and SQL injection risks in user routes", aim: "Audit user route security" },
|
|
@@ -85,7 +194,7 @@ function makeFlowDetailsFactory(projectFlowsDir) {
|
|
|
85
194
|
});
|
|
86
195
|
}
|
|
87
196
|
// Re-export compressToolResults and stripBatchReadToolCalls for tests
|
|
88
|
-
export { compressToolResults,
|
|
197
|
+
export { compressToolResults, stripBatchReadToolCalls } from "./snapshot/snapshot.js";
|
|
89
198
|
// ---------------------------------------------------------------------------
|
|
90
199
|
// Extension entry point
|
|
91
200
|
// ---------------------------------------------------------------------------
|
|
@@ -123,7 +232,7 @@ export default function (pi) {
|
|
|
123
232
|
type: "string",
|
|
124
233
|
});
|
|
125
234
|
pi.registerFlag("flow-session-mode", {
|
|
126
|
-
description: "Default child-flow session mode: fast (300s), default (600s), long (900s), or extreme_long (1200s).",
|
|
235
|
+
description: "Default child-flow session mode: snap (90s), fast (300s), default (600s), long (900s), or extreme_long (1200s).",
|
|
127
236
|
type: "string",
|
|
128
237
|
});
|
|
129
238
|
pi.registerFlag("tool-optimize", {
|
|
@@ -131,7 +240,7 @@ export default function (pi) {
|
|
|
131
240
|
type: "boolean",
|
|
132
241
|
});
|
|
133
242
|
pi.registerFlag("no-steering", {
|
|
134
|
-
description: "Disable
|
|
243
|
+
description: "Disable root state steering hint injection.",
|
|
135
244
|
type: "boolean",
|
|
136
245
|
});
|
|
137
246
|
pi.registerFlag("steering-prompt", {
|
|
@@ -155,7 +264,7 @@ export default function (pi) {
|
|
|
155
264
|
// Wire up /flow command and continuation hooks
|
|
156
265
|
registerFlow(pi);
|
|
157
266
|
const depthConfig = resolveFlowDepthConfig(pi);
|
|
158
|
-
const { currentDepth, maxDepth,
|
|
267
|
+
const { currentDepth, maxDepth, canTransition, ancestorFlowStack, preventCycles } = depthConfig;
|
|
159
268
|
let resolved;
|
|
160
269
|
let _sessionCtx;
|
|
161
270
|
let bashTracker;
|
|
@@ -164,18 +273,23 @@ export default function (pi) {
|
|
|
164
273
|
sessionRegistry.register(ctx.cwd, ctx.sessionManager.getSessionId());
|
|
165
274
|
_sessionCtx = ctx;
|
|
166
275
|
resolved = resolveSettings(pi, ctx.cwd);
|
|
276
|
+
// Reconstruct historical flow result cache so fork snapshots can compress
|
|
277
|
+
// past flow results immediately (instead of showing placeholder text until
|
|
278
|
+
// new flows complete). bashTracker is created fresh below — pending OS
|
|
279
|
+
// processes are inherently lost across restarts, which is expected.
|
|
280
|
+
reconstructFlowResultCache(ctx.sessionManager, flowResultCache);
|
|
167
281
|
// Wire resolved settings to modules
|
|
168
282
|
configureSteering({ enabled: resolved.steeringEnabled, customPrompt: resolved.steeringCustomPrompt });
|
|
169
|
-
|
|
283
|
+
configureDirective(resolved.steeringStrategicHint);
|
|
170
284
|
scrambleManager.setAnimationConfig({ enabled: resolved.animationEnabled, glitch: resolved.animationGlitch });
|
|
171
|
-
// Only restrict tools for the main
|
|
285
|
+
// Only restrict tools for the main root state (depth 0).
|
|
172
286
|
// Child flows (depth > 0) receive their tools via --tools CLI arg;
|
|
173
287
|
// overriding them here would strip bash/batch from children.
|
|
174
288
|
if (currentDepth === 0) {
|
|
175
289
|
pi.setActiveTools(computeActiveTools(resolved.toolOptimize));
|
|
176
290
|
}
|
|
177
291
|
// Register tools based on depth.
|
|
178
|
-
// Depth 0 (main
|
|
292
|
+
// Depth 0 (main root state): only batch_read — no bash ops, only reads + flow tool.
|
|
179
293
|
// Depth > 0 (child flows): batch (with bash), batch_bash_poll — they need bash ops.
|
|
180
294
|
// Children use batch for reads (which includes read ops), so batch_read is NOT
|
|
181
295
|
// registered for depth > 0 to avoid confusion and keep the tool set minimal.
|
|
@@ -200,13 +314,27 @@ export default function (pi) {
|
|
|
200
314
|
}
|
|
201
315
|
}
|
|
202
316
|
});
|
|
317
|
+
// Clean up global mutable state on session shutdown
|
|
318
|
+
pi.on("session_shutdown", () => {
|
|
319
|
+
flowResultCache.clear();
|
|
320
|
+
_sessionCtx = undefined;
|
|
321
|
+
// bashTracker and its pending OS processes are discarded on restart.
|
|
322
|
+
// This is expected — child process state is not serializable.
|
|
323
|
+
if (bashTracker) {
|
|
324
|
+
try {
|
|
325
|
+
bashTracker.abortAll();
|
|
326
|
+
}
|
|
327
|
+
catch { /* best-effort */ }
|
|
328
|
+
bashTracker = undefined;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
203
331
|
// Re-apply active tools every turn to survive registry refreshes.
|
|
204
332
|
// Skip for child flows — they get tools from --tools CLI arg.
|
|
205
333
|
pi.on("turn_start", () => {
|
|
206
334
|
if (currentDepth > 0 || !resolved)
|
|
207
335
|
return;
|
|
208
336
|
pi.setActiveTools(computeActiveTools(resolved.toolOptimize));
|
|
209
|
-
|
|
337
|
+
resetDirectiveTracker();
|
|
210
338
|
});
|
|
211
339
|
// Inject available flows into the system prompt.
|
|
212
340
|
// Skip entirely for child flows (depth > 0) — they get their instructions
|
|
@@ -214,7 +342,7 @@ export default function (pi) {
|
|
|
214
342
|
pi.on("before_agent_start", async (event) => {
|
|
215
343
|
if (currentDepth > 0 || !resolved)
|
|
216
344
|
return undefined;
|
|
217
|
-
const augmented = buildBeforeAgentStartPrompt(event, resolved.toolOptimize,
|
|
345
|
+
const augmented = buildBeforeAgentStartPrompt(event, resolved.toolOptimize, canTransition, resolved.discoveredFlows, depthConfig);
|
|
218
346
|
if (augmented === undefined)
|
|
219
347
|
return undefined;
|
|
220
348
|
return { systemPrompt: augmented };
|
|
@@ -229,7 +357,10 @@ export default function (pi) {
|
|
|
229
357
|
if (currentDepth > 0)
|
|
230
358
|
return undefined;
|
|
231
359
|
// Always strip old steering hint messages to prevent accumulation
|
|
232
|
-
const { messages, changed:
|
|
360
|
+
const { messages: steeringStrippedMessages, changed: steeringChanged } = stripSteeringHintsFromMessages(event.messages);
|
|
361
|
+
// Also strip directive hints (adaptive hints appended to tool results)
|
|
362
|
+
const { messages, changed: directiveChanged } = stripDirectivesFromMessages(steeringStrippedMessages);
|
|
363
|
+
const messagesChanged = steeringChanged || directiveChanged;
|
|
233
364
|
// Find latest user message
|
|
234
365
|
const userIndices = messages
|
|
235
366
|
.map((m, i) => (m.role === "user" ? i : -1))
|
|
@@ -287,10 +418,16 @@ export default function (pi) {
|
|
|
287
418
|
// Register the ask_user tool
|
|
288
419
|
pi.registerTool(createAskUserTool());
|
|
289
420
|
// Register the flow tool
|
|
290
|
-
if (
|
|
421
|
+
if (canTransition) {
|
|
291
422
|
pi.registerTool({
|
|
292
423
|
name: "flow",
|
|
293
424
|
label: "Flow",
|
|
425
|
+
promptSnippet: "Transition to specialized agent flows running in isolated forked processes",
|
|
426
|
+
promptGuidelines: [
|
|
427
|
+
"Use `flow` when the task requires skills beyond your current context (scout, debug, build, craft, audit, ideas).",
|
|
428
|
+
"Combine multiple related tasks into a single `flow` call with an array of flow items.",
|
|
429
|
+
"Always provide a concrete intent, aim, and optional acceptance criteria.",
|
|
430
|
+
],
|
|
294
431
|
description: [
|
|
295
432
|
"If you cannot answer from your current context, you are forbidden from guessing.",
|
|
296
433
|
"You MUST enter to the following flow states, with tool call method.",
|
|
@@ -304,11 +441,7 @@ export default function (pi) {
|
|
|
304
441
|
parameters: FlowParams,
|
|
305
442
|
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
306
443
|
if (!resolved) {
|
|
307
|
-
|
|
308
|
-
content: [{ type: "text", text: "Error: session not initialized" }],
|
|
309
|
-
details: makeFlowDetailsFactory(null)([]),
|
|
310
|
-
isError: true,
|
|
311
|
-
};
|
|
444
|
+
throw new Error("Error: session not initialized");
|
|
312
445
|
}
|
|
313
446
|
const discovery = discoverFlows(ctx.cwd, "all");
|
|
314
447
|
const { flows } = discovery;
|
|
@@ -317,7 +450,7 @@ export default function (pi) {
|
|
|
317
450
|
// artifacts before passing it to child flows.
|
|
318
451
|
// Uses the persistent module-level cache so historical flow results
|
|
319
452
|
// are properly compressed (not passed through verbatim).
|
|
320
|
-
const { result: forkSessionSnapshotJsonl } = sanitizeForkSnapshot(buildForkSessionSnapshotJsonl(ctx.sessionManager), flowResultCache, {
|
|
453
|
+
const { result: forkSessionSnapshotJsonl, stats: forkSessionSnapshotStats } = sanitizeForkSnapshot(buildForkSessionSnapshotJsonl(ctx.sessionManager), flowResultCache, {
|
|
321
454
|
forkedFrom: ctx.sessionManager.getSessionId(),
|
|
322
455
|
forkedAt: new Date().toISOString(),
|
|
323
456
|
depth: currentDepth + 1,
|
|
@@ -335,7 +468,14 @@ export default function (pi) {
|
|
|
335
468
|
const inheritedValue = inheritedCliArgs.tieredModels?.[tier];
|
|
336
469
|
return typeof inheritedValue === "string" && inheritedValue.trim() ? inheritedValue.trim() : undefined;
|
|
337
470
|
};
|
|
338
|
-
|
|
471
|
+
let activeGoal = getGoalForSession(ctx.cwd, sessionRegistry.getSessionId(ctx.cwd));
|
|
472
|
+
if (!activeGoal) {
|
|
473
|
+
const anyGoal = getGoal(ctx.cwd);
|
|
474
|
+
if (anyGoal && anyGoal.status === "active") {
|
|
475
|
+
logWarn(`[pi-agent-flow] Session mismatch for goal: expected ${sessionRegistry.getSessionId(ctx.cwd)}, got ${anyGoal.sessionId ?? "none"}. Using goal anyway.`);
|
|
476
|
+
activeGoal = anyGoal;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
339
479
|
const goalContext = activeGoal ? {
|
|
340
480
|
objective: activeGoal.objective,
|
|
341
481
|
acceptance: activeGoal.acceptance,
|
|
@@ -361,6 +501,7 @@ export default function (pi) {
|
|
|
361
501
|
tierOverrideResolver: getTierOverride,
|
|
362
502
|
fallbackModel: inheritedCliArgs.fallbackModel,
|
|
363
503
|
forkSessionSnapshotJsonl,
|
|
504
|
+
forkSessionSnapshotStats,
|
|
364
505
|
flowResultCache,
|
|
365
506
|
projectFlowsDir: discovery.projectFlowsDir,
|
|
366
507
|
sessionManager: ctx.sessionManager,
|
|
@@ -380,13 +521,29 @@ export default function (pi) {
|
|
|
380
521
|
}
|
|
381
522
|
},
|
|
382
523
|
}, params.flow.map((f) => ({ type: f.type, intent: f.intent, aim: f.aim, acceptance: f.acceptance, cwd: f.cwd, sessionMode: f.sessionMode })), toolCallId);
|
|
524
|
+
if (result.failed) {
|
|
525
|
+
const text = result.content?.[0]?.text ?? "Flow execution failed";
|
|
526
|
+
throw new Error(text);
|
|
527
|
+
}
|
|
383
528
|
const flowToolResult = {
|
|
384
529
|
content: result.content,
|
|
385
530
|
details: result.details,
|
|
386
|
-
|
|
531
|
+
failed: result.failed,
|
|
387
532
|
_toolCallId: toolCallId,
|
|
388
533
|
};
|
|
389
|
-
|
|
534
|
+
// Build adaptive directive context from flow results
|
|
535
|
+
const hintContext = { hasNotDone: false, statusVague: false };
|
|
536
|
+
if (result.details?.results && Array.isArray(result.details.results)) {
|
|
537
|
+
for (const r of result.details.results) {
|
|
538
|
+
if (r.structuredOutput?.notDone?.length) {
|
|
539
|
+
hintContext.hasNotDone = true;
|
|
540
|
+
}
|
|
541
|
+
if (!r.structuredOutput || !["complete", "partial", "blocked"].includes(r.structuredOutput.status)) {
|
|
542
|
+
hintContext.statusVague = true;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
appendDirectiveOnce(flowToolResult, hintContext);
|
|
390
547
|
return flowToolResult;
|
|
391
548
|
},
|
|
392
549
|
renderCall: (args, theme) => renderFlowCall(args, theme),
|
|
@@ -427,11 +584,11 @@ export default function (pi) {
|
|
|
427
584
|
}
|
|
428
585
|
// Register cleanup on process exit (once).
|
|
429
586
|
// We use prependListener on SIGINT/SIGTERM to propagate to child processes
|
|
430
|
-
// before the host's own signal handler runs. This avoids orphaned
|
|
587
|
+
// before the host's own signal handler runs. This avoids orphaned flow states.
|
|
431
588
|
// The host handler still runs afterward and handles terminal cleanup.
|
|
432
589
|
if (!globalThis.__pi_agent_flow_shutdown_registered) {
|
|
433
590
|
globalThis.__pi_agent_flow_shutdown_registered = true;
|
|
434
|
-
// Propagate signals to child process groups so
|
|
591
|
+
// Propagate signals to child process groups so flow states don't become orphans.
|
|
435
592
|
// We use prependListener so our handler runs first, before the host's cleanup.
|
|
436
593
|
const shutdown = () => {
|
|
437
594
|
// First, abort any pending bash operations tracked by the batch tool.
|