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.
Files changed (195) hide show
  1. package/README.md +126 -489
  2. package/agents/audit.md +7 -2
  3. package/agents/build.md +6 -2
  4. package/agents/craft.md +6 -3
  5. package/agents/debug.md +7 -3
  6. package/agents/ideas.md +8 -4
  7. package/agents/scout.md +8 -1
  8. package/dist/batch/apply-patch.d.ts +60 -0
  9. package/dist/batch/apply-patch.d.ts.map +1 -0
  10. package/dist/batch/apply-patch.js +477 -0
  11. package/dist/batch/apply-patch.js.map +1 -0
  12. package/dist/batch/batch-bash.d.ts +0 -6
  13. package/dist/batch/batch-bash.d.ts.map +1 -1
  14. package/dist/batch/batch-bash.js +52 -14
  15. package/dist/batch/batch-bash.js.map +1 -1
  16. package/dist/batch/constants.d.ts +45 -4
  17. package/dist/batch/constants.d.ts.map +1 -1
  18. package/dist/batch/constants.js +72 -4
  19. package/dist/batch/constants.js.map +1 -1
  20. package/dist/batch/execute.d.ts +8 -2
  21. package/dist/batch/execute.d.ts.map +1 -1
  22. package/dist/batch/execute.js +338 -70
  23. package/dist/batch/execute.js.map +1 -1
  24. package/dist/batch/fuzzy-edit.d.ts +4 -1
  25. package/dist/batch/fuzzy-edit.d.ts.map +1 -1
  26. package/dist/batch/fuzzy-edit.js +7 -2
  27. package/dist/batch/fuzzy-edit.js.map +1 -1
  28. package/dist/batch/index.d.ts +3 -15
  29. package/dist/batch/index.d.ts.map +1 -1
  30. package/dist/batch/index.js +48 -78
  31. package/dist/batch/index.js.map +1 -1
  32. package/dist/batch/render.d.ts.map +1 -1
  33. package/dist/batch/render.js +30 -7
  34. package/dist/batch/render.js.map +1 -1
  35. package/dist/batch/shell-compress.d.ts +25 -0
  36. package/dist/batch/shell-compress.d.ts.map +1 -0
  37. package/dist/batch/shell-compress.js +602 -0
  38. package/dist/batch/shell-compress.js.map +1 -0
  39. package/dist/batch/summary.d.ts.map +1 -1
  40. package/dist/batch/summary.js +4 -0
  41. package/dist/batch/summary.js.map +1 -1
  42. package/dist/batch/symbols.d.ts.map +1 -1
  43. package/dist/batch/symbols.js +12 -7
  44. package/dist/batch/symbols.js.map +1 -1
  45. package/dist/config/config.d.ts +5 -0
  46. package/dist/config/config.d.ts.map +1 -1
  47. package/dist/config/config.js +63 -0
  48. package/dist/config/config.js.map +1 -1
  49. package/dist/config/models.d.ts +2 -0
  50. package/dist/config/models.d.ts.map +1 -0
  51. package/dist/config/models.js +49 -0
  52. package/dist/config/models.js.map +1 -0
  53. package/dist/config/settings-resolver.js +2 -2
  54. package/dist/config/settings-resolver.js.map +1 -1
  55. package/dist/core/agents.js +2 -2
  56. package/dist/core/agents.js.map +1 -1
  57. package/dist/core/depth.d.ts +3 -3
  58. package/dist/core/depth.d.ts.map +1 -1
  59. package/dist/core/depth.js +5 -5
  60. package/dist/core/depth.js.map +1 -1
  61. package/dist/core/executor.d.ts +10 -3
  62. package/dist/core/executor.d.ts.map +1 -1
  63. package/dist/core/executor.js +7 -3
  64. package/dist/core/executor.js.map +1 -1
  65. package/dist/core/flow.d.ts +19 -3
  66. package/dist/core/flow.d.ts.map +1 -1
  67. package/dist/core/flow.js +97 -58
  68. package/dist/core/flow.js.map +1 -1
  69. package/dist/core/session-mode.d.ts +1 -1
  70. package/dist/core/session-mode.d.ts.map +1 -1
  71. package/dist/core/session-mode.js +2 -1
  72. package/dist/core/session-mode.js.map +1 -1
  73. package/dist/core/{delegation.d.ts → transition.d.ts} +9 -9
  74. package/dist/core/transition.d.ts.map +1 -0
  75. package/dist/core/{delegation.js → transition.js} +17 -24
  76. package/dist/core/transition.js.map +1 -0
  77. package/dist/flow/auto-warp.d.ts +12 -0
  78. package/dist/flow/auto-warp.d.ts.map +1 -0
  79. package/dist/flow/auto-warp.js +29 -0
  80. package/dist/flow/auto-warp.js.map +1 -0
  81. package/dist/flow/command.d.ts.map +1 -1
  82. package/dist/flow/command.js +7 -2
  83. package/dist/flow/command.js.map +1 -1
  84. package/dist/flow/continuation.d.ts.map +1 -1
  85. package/dist/flow/continuation.js +52 -15
  86. package/dist/flow/continuation.js.map +1 -1
  87. package/dist/flow/index.d.ts +5 -2
  88. package/dist/flow/index.d.ts.map +1 -1
  89. package/dist/flow/index.js +6 -3
  90. package/dist/flow/index.js.map +1 -1
  91. package/dist/flow/loop-command.d.ts +8 -0
  92. package/dist/flow/loop-command.d.ts.map +1 -0
  93. package/dist/flow/loop-command.js +102 -0
  94. package/dist/flow/loop-command.js.map +1 -0
  95. package/dist/flow/loop-templates.d.ts +7 -0
  96. package/dist/flow/loop-templates.d.ts.map +1 -0
  97. package/dist/flow/loop-templates.js +38 -0
  98. package/dist/flow/loop-templates.js.map +1 -0
  99. package/dist/flow/loop.d.ts +19 -0
  100. package/dist/flow/loop.d.ts.map +1 -0
  101. package/dist/flow/loop.js +95 -0
  102. package/dist/flow/loop.js.map +1 -0
  103. package/dist/flow/settings-command.d.ts.map +1 -1
  104. package/dist/flow/settings-command.js +93 -4
  105. package/dist/flow/settings-command.js.map +1 -1
  106. package/dist/flow/store.d.ts +3 -3
  107. package/dist/flow/store.d.ts.map +1 -1
  108. package/dist/flow/store.js +24 -16
  109. package/dist/flow/store.js.map +1 -1
  110. package/dist/flow/template-shared.d.ts +9 -0
  111. package/dist/flow/template-shared.d.ts.map +1 -0
  112. package/dist/flow/template-shared.js +13 -0
  113. package/dist/flow/template-shared.js.map +1 -0
  114. package/dist/flow/template-strings.d.ts.map +1 -1
  115. package/dist/flow/template-strings.js +2 -5
  116. package/dist/flow/template-strings.js.map +1 -1
  117. package/dist/flow/types.d.ts +15 -9
  118. package/dist/flow/types.d.ts.map +1 -1
  119. package/dist/flow/warp.d.ts +15 -0
  120. package/dist/flow/warp.d.ts.map +1 -0
  121. package/dist/flow/warp.js +207 -0
  122. package/dist/flow/warp.js.map +1 -0
  123. package/dist/index.d.ts +3 -2
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +185 -28
  126. package/dist/index.js.map +1 -1
  127. package/dist/snapshot/cli-args.d.ts +1 -0
  128. package/dist/snapshot/cli-args.d.ts.map +1 -1
  129. package/dist/snapshot/cli-args.js +12 -0
  130. package/dist/snapshot/cli-args.js.map +1 -1
  131. package/dist/snapshot/runner-events.d.ts +5 -0
  132. package/dist/snapshot/runner-events.d.ts.map +1 -1
  133. package/dist/snapshot/runner-events.js +89 -15
  134. package/dist/snapshot/runner-events.js.map +1 -1
  135. package/dist/snapshot/snapshot.d.ts +22 -19
  136. package/dist/snapshot/snapshot.d.ts.map +1 -1
  137. package/dist/snapshot/snapshot.js +1063 -167
  138. package/dist/snapshot/snapshot.js.map +1 -1
  139. package/dist/steering/flow-prompt.d.ts +2 -2
  140. package/dist/steering/flow-prompt.d.ts.map +1 -1
  141. package/dist/steering/flow-prompt.js +4 -4
  142. package/dist/steering/flow-prompt.js.map +1 -1
  143. package/dist/steering/sliding-prompt.d.ts.map +1 -1
  144. package/dist/steering/sliding-prompt.js +9 -6
  145. package/dist/steering/sliding-prompt.js.map +1 -1
  146. package/dist/steering/tool-utils.d.ts +31 -8
  147. package/dist/steering/tool-utils.d.ts.map +1 -1
  148. package/dist/steering/tool-utils.js +63 -30
  149. package/dist/steering/tool-utils.js.map +1 -1
  150. package/dist/tools/ask-user.d.ts +0 -17
  151. package/dist/tools/ask-user.d.ts.map +1 -1
  152. package/dist/tools/ask-user.js +13 -37
  153. package/dist/tools/ask-user.js.map +1 -1
  154. package/dist/tools/timed-bash.d.ts +1 -1
  155. package/dist/tools/timed-bash.d.ts.map +1 -1
  156. package/dist/tools/timed-bash.js +19 -8
  157. package/dist/tools/timed-bash.js.map +1 -1
  158. package/dist/tools/web-tool.d.ts.map +1 -1
  159. package/dist/tools/web-tool.js +11 -13
  160. package/dist/tools/web-tool.js.map +1 -1
  161. package/dist/tui/render-utils.d.ts +5 -1
  162. package/dist/tui/render-utils.d.ts.map +1 -1
  163. package/dist/tui/render-utils.js +36 -10
  164. package/dist/tui/render-utils.js.map +1 -1
  165. package/dist/tui/render.d.ts +9 -0
  166. package/dist/tui/render.d.ts.map +1 -1
  167. package/dist/tui/render.js +112 -100
  168. package/dist/tui/render.js.map +1 -1
  169. package/dist/tui/scramble/constants.d.ts +8 -8
  170. package/dist/tui/scramble/constants.d.ts.map +1 -1
  171. package/dist/tui/scramble/constants.js +7 -7
  172. package/dist/tui/scramble/constants.js.map +1 -1
  173. package/dist/tui/scramble/index.d.ts +1 -1
  174. package/dist/tui/scramble/index.d.ts.map +1 -1
  175. package/dist/tui/scramble/index.js +1 -1
  176. package/dist/tui/scramble/index.js.map +1 -1
  177. package/dist/tui/scramble/manager.d.ts +1 -5
  178. package/dist/tui/scramble/manager.d.ts.map +1 -1
  179. package/dist/tui/scramble/manager.js +16 -64
  180. package/dist/tui/scramble/manager.js.map +1 -1
  181. package/dist/tui/scramble/utils.js +1 -1
  182. package/dist/tui/scramble/utils.js.map +1 -1
  183. package/dist/types/flow.d.ts +2 -0
  184. package/dist/types/flow.d.ts.map +1 -1
  185. package/dist/types/flow.js +11 -2
  186. package/dist/types/flow.js.map +1 -1
  187. package/dist/types/output.d.ts +6 -0
  188. package/dist/types/output.d.ts.map +1 -1
  189. package/package.json +2 -2
  190. package/dist/core/delegation.d.ts.map +0 -1
  191. package/dist/core/delegation.js.map +0 -1
  192. package/dist/flow/warp-command.d.ts +0 -9
  193. package/dist/flow/warp-command.d.ts.map +0 -1
  194. package/dist/flow/warp-command.js +0 -405
  195. 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
- export { logWarn, logError } from "./config/log.js";
9
- export { compressToolResults, compressFlowToolResults, stripBatchReadToolCalls } from "./snapshot/snapshot.js";
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
@@ -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;AA6CpF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAmFpD,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC/G,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAM5D,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QAwZxC"}
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 { appendStrategicHintOnce, resetStrategicHintTracker, configureStrategicHint } from "./steering/tool-utils.js";
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
- export { logWarn, logError } from "./config/log.js";
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 child-agent budget: fast=300s, default=600s, long=900s, extreme_long=1200s.",
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, compressFlowToolResults, stripBatchReadToolCalls } from "./snapshot/snapshot.js";
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 orchestrator steering hint injection.",
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, canDelegate, ancestorFlowStack, preventCycles } = depthConfig;
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
- configureStrategicHint(resolved.steeringStrategicHint);
283
+ configureDirective(resolved.steeringStrategicHint);
170
284
  scrambleManager.setAnimationConfig({ enabled: resolved.animationEnabled, glitch: resolved.animationGlitch });
171
- // Only restrict tools for the main orchestrator (depth 0).
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 orchestrator): only batch_read — no bash ops, only reads + flow tool.
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
- resetStrategicHintTracker();
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, canDelegate, resolved.discoveredFlows, depthConfig);
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: messagesChanged } = stripSteeringHintsFromMessages(event.messages);
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 (canDelegate) {
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
- return {
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
- const activeGoal = getGoalForSession(ctx.cwd, sessionRegistry.getSessionId(ctx.cwd));
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
- isError: result.isError,
531
+ failed: result.failed,
387
532
  _toolCallId: toolCallId,
388
533
  };
389
- appendStrategicHintOnce(flowToolResult);
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 sub-agents.
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 sub-agents don't become orphans.
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.