pi-agent-flow 1.8.1 → 1.8.3

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 (154) hide show
  1. package/README.md +4 -30
  2. package/agents/audit.md +1 -2
  3. package/agents/build.md +1 -0
  4. package/agents/craft.md +12 -8
  5. package/agents/debug.md +2 -2
  6. package/agents/ideas.md +1 -0
  7. package/agents/scout.md +1 -0
  8. package/dist/agents.d.ts +41 -0
  9. package/dist/agents.d.ts.map +1 -0
  10. package/dist/agents.js +283 -0
  11. package/dist/agents.js.map +1 -0
  12. package/dist/batch/batch-bash.d.ts +87 -0
  13. package/dist/batch/batch-bash.d.ts.map +1 -0
  14. package/dist/batch/batch-bash.js +369 -0
  15. package/dist/batch/batch-bash.js.map +1 -0
  16. package/dist/batch/constants.d.ts +100 -0
  17. package/dist/batch/constants.d.ts.map +1 -0
  18. package/dist/batch/constants.js +15 -0
  19. package/dist/batch/constants.js.map +1 -0
  20. package/dist/batch/execute.d.ts +21 -0
  21. package/dist/batch/execute.d.ts.map +1 -0
  22. package/dist/batch/execute.js +440 -0
  23. package/dist/batch/execute.js.map +1 -0
  24. package/dist/batch/fuzzy-edit.d.ts +29 -0
  25. package/dist/batch/fuzzy-edit.d.ts.map +1 -0
  26. package/dist/batch/fuzzy-edit.js +257 -0
  27. package/dist/batch/fuzzy-edit.js.map +1 -0
  28. package/dist/batch/index.d.ts +85 -0
  29. package/dist/batch/index.d.ts.map +1 -0
  30. package/dist/batch/index.js +422 -0
  31. package/dist/batch/index.js.map +1 -0
  32. package/dist/batch/render.d.ts +14 -0
  33. package/dist/batch/render.d.ts.map +1 -0
  34. package/dist/batch/render.js +74 -0
  35. package/dist/batch/render.js.map +1 -0
  36. package/dist/batch/symbols.d.ts +9 -0
  37. package/dist/batch/symbols.d.ts.map +1 -0
  38. package/dist/batch/symbols.js +310 -0
  39. package/dist/batch/symbols.js.map +1 -0
  40. package/dist/batch.d.ts +12 -0
  41. package/dist/batch.d.ts.map +1 -0
  42. package/dist/batch.js +11 -0
  43. package/dist/batch.js.map +1 -0
  44. package/dist/cli-args.d.ts +27 -0
  45. package/dist/cli-args.d.ts.map +1 -0
  46. package/dist/cli-args.js +265 -0
  47. package/dist/cli-args.js.map +1 -0
  48. package/dist/config.d.ts +58 -0
  49. package/dist/config.d.ts.map +1 -0
  50. package/dist/config.js +296 -0
  51. package/dist/config.js.map +1 -0
  52. package/dist/depth.d.ts +25 -0
  53. package/dist/depth.d.ts.map +1 -0
  54. package/dist/depth.js +160 -0
  55. package/dist/depth.js.map +1 -0
  56. package/dist/executor.d.ts +87 -0
  57. package/dist/executor.d.ts.map +1 -0
  58. package/dist/executor.js +295 -0
  59. package/dist/executor.js.map +1 -0
  60. package/dist/flow-prompt.d.ts +23 -0
  61. package/dist/flow-prompt.d.ts.map +1 -0
  62. package/dist/flow-prompt.js +99 -0
  63. package/dist/flow-prompt.js.map +1 -0
  64. package/dist/flow.d.ts +76 -0
  65. package/dist/flow.d.ts.map +1 -0
  66. package/dist/flow.js +704 -0
  67. package/dist/flow.js.map +1 -0
  68. package/dist/index.d.ts +10 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +327 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/reasoning-strip.d.ts +26 -0
  73. package/dist/reasoning-strip.d.ts.map +1 -0
  74. package/dist/reasoning-strip.js +58 -0
  75. package/dist/reasoning-strip.js.map +1 -0
  76. package/dist/render-utils.d.ts +42 -0
  77. package/dist/render-utils.d.ts.map +1 -0
  78. package/dist/render-utils.js +182 -0
  79. package/dist/render-utils.js.map +1 -0
  80. package/dist/render.d.ts +24 -0
  81. package/dist/render.d.ts.map +1 -0
  82. package/dist/render.js +409 -0
  83. package/dist/render.js.map +1 -0
  84. package/dist/runner-events.d.ts +59 -0
  85. package/dist/runner-events.d.ts.map +1 -0
  86. package/dist/runner-events.js +539 -0
  87. package/dist/runner-events.js.map +1 -0
  88. package/dist/session-mode.d.ts +10 -0
  89. package/dist/session-mode.d.ts.map +1 -0
  90. package/dist/session-mode.js +25 -0
  91. package/dist/session-mode.js.map +1 -0
  92. package/dist/settings-resolver.d.ts +28 -0
  93. package/dist/settings-resolver.d.ts.map +1 -0
  94. package/dist/settings-resolver.js +148 -0
  95. package/dist/settings-resolver.js.map +1 -0
  96. package/dist/sliding-prompt.d.ts +40 -0
  97. package/dist/sliding-prompt.d.ts.map +1 -0
  98. package/dist/sliding-prompt.js +121 -0
  99. package/dist/sliding-prompt.js.map +1 -0
  100. package/dist/snapshot.d.ts +29 -0
  101. package/dist/snapshot.d.ts.map +1 -0
  102. package/dist/snapshot.js +199 -0
  103. package/dist/snapshot.js.map +1 -0
  104. package/dist/structured-output.d.ts +36 -0
  105. package/dist/structured-output.d.ts.map +1 -0
  106. package/dist/structured-output.js +244 -0
  107. package/dist/structured-output.js.map +1 -0
  108. package/dist/timed-bash.d.ts +45 -0
  109. package/dist/timed-bash.d.ts.map +1 -0
  110. package/dist/timed-bash.js +219 -0
  111. package/dist/timed-bash.js.map +1 -0
  112. package/dist/tool-utils.d.ts +20 -0
  113. package/dist/tool-utils.d.ts.map +1 -0
  114. package/dist/tool-utils.js +38 -0
  115. package/dist/tool-utils.js.map +1 -0
  116. package/dist/transitions.d.ts +39 -0
  117. package/dist/transitions.d.ts.map +1 -0
  118. package/dist/transitions.js +59 -0
  119. package/dist/transitions.js.map +1 -0
  120. package/dist/types.d.ts +207 -0
  121. package/dist/types.d.ts.map +1 -0
  122. package/dist/types.js +143 -0
  123. package/dist/types.js.map +1 -0
  124. package/dist/web-tool.d.ts +35 -0
  125. package/dist/web-tool.d.ts.map +1 -0
  126. package/dist/web-tool.js +545 -0
  127. package/dist/web-tool.js.map +1 -0
  128. package/package.json +7 -5
  129. package/src/agents.ts +0 -299
  130. package/src/ambient.d.ts +0 -107
  131. package/src/batch/batch-bash.ts +0 -443
  132. package/src/batch/constants.ts +0 -128
  133. package/src/batch/execute.ts +0 -551
  134. package/src/batch/fuzzy-edit.ts +0 -323
  135. package/src/batch/index.ts +0 -494
  136. package/src/batch/render.ts +0 -81
  137. package/src/batch/symbols.ts +0 -341
  138. package/src/batch.ts +0 -28
  139. package/src/cli-args.ts +0 -315
  140. package/src/config.ts +0 -391
  141. package/src/executor.ts +0 -445
  142. package/src/flow.ts +0 -834
  143. package/src/hooks.ts +0 -294
  144. package/src/index.ts +0 -1132
  145. package/src/render-utils.ts +0 -205
  146. package/src/render.ts +0 -524
  147. package/src/runner-events.ts +0 -692
  148. package/src/session-mode.ts +0 -33
  149. package/src/sliding-prompt.ts +0 -144
  150. package/src/structured-output.ts +0 -195
  151. package/src/timed-bash.ts +0 -270
  152. package/src/transitions.ts +0 -86
  153. package/src/types.ts +0 -386
  154. package/src/web-tool.ts +0 -663
@@ -1,341 +0,0 @@
1
- /**
2
- * batch — symbol extraction and context-map building.
3
- *
4
- * Parses source files to produce a navigable symbol map for context-aware
5
- * reading of large files.
6
- */
7
-
8
- import * as path from "node:path";
9
- import {
10
- type ContextLanguage,
11
- type ContextMapEntry,
12
- type FileContextMap,
13
- MAX_CONTEXT_MAP_ENTRIES,
14
- } from "./constants.js";
15
-
16
- // ---------------------------------------------------------------------------
17
- // Symbol extraction
18
- // ---------------------------------------------------------------------------
19
-
20
- function countLeadingWhitespace(line: string): number {
21
- return line.match(/^\s*/)?.[0].length ?? 0;
22
- }
23
-
24
- function findBraceBlockEnd(lines: string[], startIndex: number): number {
25
- let depth = 0;
26
- let sawOpenBrace = false;
27
-
28
- for (let i = startIndex; i < lines.length; i++) {
29
- for (const char of lines[i]) {
30
- if (char === "{") {
31
- depth++;
32
- sawOpenBrace = true;
33
- } else if (char === "}") {
34
- depth--;
35
- }
36
- }
37
- if (sawOpenBrace && depth <= 0) return i + 1;
38
- }
39
-
40
- return sawOpenBrace ? lines.length : startIndex + 1;
41
- }
42
-
43
- function findStatementEnd(lines: string[], startIndex: number): number {
44
- for (let i = startIndex; i < lines.length; i++) {
45
- if (lines[i].includes(";")) return i + 1;
46
- }
47
- return startIndex + 1;
48
- }
49
-
50
- function findIndentedBlockEnd(lines: string[], startIndex: number, indent: number): number {
51
- for (let i = startIndex + 1; i < lines.length; i++) {
52
- const trimmed = lines[i].trim();
53
- if (!trimmed || trimmed.startsWith("#")) continue;
54
- if (countLeadingWhitespace(lines[i]) <= indent) return i;
55
- }
56
- return lines.length;
57
- }
58
-
59
- function findYamlBlockEnd(lines: string[], startIndex: number, indent: number): number {
60
- for (let i = startIndex + 1; i < lines.length; i++) {
61
- const trimmed = lines[i].trim();
62
- if (!trimmed || trimmed.startsWith("#")) continue;
63
- if (trimmed === "---" || countLeadingWhitespace(lines[i]) <= indent) return i;
64
- }
65
- return lines.length;
66
- }
67
-
68
- function extractTsJsSymbols(lines: string[]): ContextMapEntry[] {
69
- const entries: ContextMapEntry[] = [];
70
- const classes: ContextMapEntry[] = [];
71
-
72
- for (let i = 0; i < lines.length; i++) {
73
- const line = lines[i];
74
- let match = line.match(/^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/);
75
- if (match) {
76
- entries.push({ kind: "function", name: match[1], startLine: i + 1, endLine: findBraceBlockEnd(lines, i) });
77
- continue;
78
- }
79
-
80
- match = line.match(/^\s*(?:export\s+)?(?:default\s+)?class\s+([A-Za-z_$][\w$]*)\b/);
81
- if (match) {
82
- const entry = { kind: "class", name: match[1], startLine: i + 1, endLine: findBraceBlockEnd(lines, i) };
83
- entries.push(entry);
84
- classes.push(entry);
85
- continue;
86
- }
87
-
88
- match = line.match(/^\s*(?:export\s+)?interface\s+([A-Za-z_$][\w$]*)\b/);
89
- if (match) {
90
- entries.push({ kind: "interface", name: match[1], startLine: i + 1, endLine: findBraceBlockEnd(lines, i) });
91
- continue;
92
- }
93
-
94
- match = line.match(/^\s*(?:export\s+)?type\s+([A-Za-z_$][\w$]*)\b/);
95
- if (match) {
96
- entries.push({ kind: "type", name: match[1], startLine: i + 1, endLine: line.includes("{") ? findBraceBlockEnd(lines, i) : findStatementEnd(lines, i) });
97
- continue;
98
- }
99
-
100
- match = line.match(/^\s*(?:export\s+)?enum\s+([A-Za-z_$][\w$]*)\b/);
101
- if (match) {
102
- entries.push({ kind: "enum", name: match[1], startLine: i + 1, endLine: findBraceBlockEnd(lines, i) });
103
- continue;
104
- }
105
-
106
- match = line.match(/^\s*(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:function\b|(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*=>)/);
107
- if (match) {
108
- entries.push({ kind: "function", name: match[1], startLine: i + 1, endLine: line.includes("{") ? findBraceBlockEnd(lines, i) : findStatementEnd(lines, i) });
109
- }
110
- }
111
-
112
- const methodNameBlacklist = new Set(["if", "for", "while", "switch", "catch", "function"]);
113
- for (const classEntry of classes) {
114
- for (let i = classEntry.startLine; i < classEntry.endLine - 1 && i < lines.length; i++) {
115
- const match = lines[i].match(/^\s*(?:(?:public|private|protected|static|async|override|readonly)\s+)*([A-Za-z_$][\w$]*)\s*(?:<[^>]+>)?\s*\([^)]*\)\s*(?::\s*[^={]+)?\s*\{/);
116
- if (!match || methodNameBlacklist.has(match[1])) continue;
117
- entries.push({
118
- kind: "method",
119
- name: `${classEntry.name}.${match[1]}`,
120
- parent: classEntry.name,
121
- startLine: i + 1,
122
- endLine: findBraceBlockEnd(lines, i),
123
- });
124
- }
125
- }
126
-
127
- return entries;
128
- }
129
-
130
- function extractPythonSymbols(lines: string[]): ContextMapEntry[] {
131
- const entries: ContextMapEntry[] = [];
132
- const classes: Array<ContextMapEntry & { indent: number }> = [];
133
-
134
- for (let i = 0; i < lines.length; i++) {
135
- const match = lines[i].match(/^(\s*)class\s+([A-Za-z_]\w*)\b/);
136
- if (!match) continue;
137
- const indent = match[1].length;
138
- const entry = { kind: "class", name: match[2], startLine: i + 1, endLine: findIndentedBlockEnd(lines, i, indent), indent };
139
- classes.push(entry);
140
- entries.push(entry);
141
- }
142
-
143
- for (let i = 0; i < lines.length; i++) {
144
- const match = lines[i].match(/^(\s*)(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/);
145
- if (!match) continue;
146
- const indent = match[1].length;
147
- const parent = classes.find((cls) => i + 1 > cls.startLine && i + 1 < cls.endLine && indent > cls.indent);
148
- entries.push({
149
- kind: parent ? "method" : "function",
150
- name: parent ? `${parent.name}.${match[2]}` : match[2],
151
- parent: parent?.name,
152
- startLine: i + 1,
153
- endLine: findIndentedBlockEnd(lines, i, indent),
154
- });
155
- }
156
-
157
- return entries;
158
- }
159
-
160
- function extractTerraformSymbols(lines: string[]): ContextMapEntry[] {
161
- const entries: ContextMapEntry[] = [];
162
-
163
- for (let i = 0; i < lines.length; i++) {
164
- const line = lines[i];
165
- let match = line.match(/^\s*(resource|data)\s+"([^"]+)"\s+"([^"]+)"\s*\{/);
166
- if (match) {
167
- entries.push({ kind: match[1], name: `${match[2]}.${match[3]}`, startLine: i + 1, endLine: findBraceBlockEnd(lines, i) });
168
- continue;
169
- }
170
-
171
- match = line.match(/^\s*(module|variable|output|provider)\s+"([^"]+)"\s*\{/);
172
- if (match) {
173
- entries.push({ kind: match[1], name: match[2], startLine: i + 1, endLine: findBraceBlockEnd(lines, i) });
174
- continue;
175
- }
176
-
177
- match = line.match(/^\s*(locals|terraform)\s*\{/);
178
- if (match) {
179
- entries.push({ kind: match[1], name: match[1], startLine: i + 1, endLine: findBraceBlockEnd(lines, i) });
180
- continue;
181
- }
182
-
183
- match = line.match(/^([A-Za-z_][\w-]*)\s*=/);
184
- if (match) {
185
- entries.push({ kind: "assignment", name: match[1], startLine: i + 1, endLine: i + 1 });
186
- }
187
- }
188
-
189
- return entries;
190
- }
191
-
192
- function extractYamlSymbols(lines: string[]): ContextMapEntry[] {
193
- const entries: ContextMapEntry[] = [];
194
-
195
- let docStart = 0;
196
- for (let i = 0; i <= lines.length; i++) {
197
- if (i < lines.length && lines[i].trim() !== "---") continue;
198
- const docEnd = i === lines.length ? lines.length : i;
199
- const docLines = lines.slice(docStart, docEnd);
200
- const kindLine = docLines.findIndex((line) => /^kind:\s*\S+/.test(line));
201
- const nameLine = docLines.findIndex((line) => /^\s{2}name:\s*\S+/.test(line));
202
- if (kindLine >= 0 && nameLine >= 0) {
203
- const kind = docLines[kindLine].replace(/^kind:\s*/, "").trim();
204
- const name = docLines[nameLine].replace(/^\s{2}name:\s*/, "").trim();
205
- entries.push({ kind, name, startLine: docStart + 1, endLine: Math.max(docStart + 1, docEnd) });
206
- }
207
- docStart = i + 1;
208
- }
209
-
210
- for (let i = 0; i < lines.length; i++) {
211
- const topLevel = lines[i].match(/^([A-Za-z_][\w.-]*):\s*/);
212
- if (topLevel) {
213
- const key = topLevel[1];
214
- entries.push({ kind: "section", name: key, startLine: i + 1, endLine: findYamlBlockEnd(lines, i, 0) });
215
-
216
- if (["jobs", "services", "volumes", "networks"].includes(key)) {
217
- for (let j = i + 1; j < lines.length; j++) {
218
- const trimmed = lines[j].trim();
219
- if (!trimmed || trimmed.startsWith("#")) continue;
220
- const indent = countLeadingWhitespace(lines[j]);
221
- if (indent <= 0) break;
222
- const child = lines[j].match(/^\s{2}([A-Za-z0-9_.-]+):\s*/);
223
- if (!child) continue;
224
- const childKind = key === "jobs" ? "job" : key.slice(0, -1);
225
- entries.push({ kind: childKind, name: child[1], startLine: j + 1, endLine: findYamlBlockEnd(lines, j, 2) });
226
- }
227
- }
228
- }
229
-
230
- const step = lines[i].match(/^\s*-\s+(?:name:\s*(.+)|uses:\s*(.+)|run:\s*(.+))/);
231
- if (step) {
232
- const name = (step[1] ?? step[2] ?? step[3] ?? "step").trim();
233
- entries.push({ kind: "step", name: name.slice(0, 120), startLine: i + 1, endLine: i + 1 });
234
- }
235
- }
236
-
237
- return entries;
238
- }
239
-
240
- function findDockerInstructionEnd(lines: string[], startIndex: number): number {
241
- let endIndex = startIndex;
242
- while (endIndex + 1 < lines.length && lines[endIndex].trimEnd().endsWith("\\")) {
243
- endIndex++;
244
- }
245
- return endIndex + 1;
246
- }
247
-
248
- function extractDockerfileSymbols(lines: string[]): ContextMapEntry[] {
249
- const entries: ContextMapEntry[] = [];
250
- const fromLines: number[] = [];
251
-
252
- for (let i = 0; i < lines.length; i++) {
253
- if (/^\s*FROM\s+/i.test(lines[i])) fromLines.push(i);
254
- }
255
-
256
- for (let idx = 0; idx < fromLines.length; idx++) {
257
- const i = fromLines[idx];
258
- const nextFrom = fromLines[idx + 1] ?? lines.length;
259
- const match = lines[i].match(/^\s*FROM\s+(\S+)(?:\s+AS\s+(\S+))?/i);
260
- const image = match?.[1] ?? "unknown";
261
- const alias = match?.[2];
262
- entries.push({ kind: "stage", name: alias ? `${alias} FROM ${image}` : image, startLine: i + 1, endLine: nextFrom });
263
- }
264
-
265
- const important = /^(RUN|COPY|ADD|ENTRYPOINT|CMD|EXPOSE|ENV|ARG|WORKDIR)\b\s*(.*)/i;
266
- for (let i = 0; i < lines.length; i++) {
267
- const match = lines[i].trim().match(important);
268
- if (!match) continue;
269
- entries.push({ kind: match[1].toUpperCase(), name: (match[2] || match[1]).slice(0, 120), startLine: i + 1, endLine: findDockerInstructionEnd(lines, i) });
270
- }
271
-
272
- return entries;
273
- }
274
-
275
- // ---------------------------------------------------------------------------
276
- // Language detection
277
- // ---------------------------------------------------------------------------
278
-
279
- function detectContextLanguage(filePath: string): ContextLanguage {
280
- const base = path.basename(filePath);
281
- const lowerBase = base.toLowerCase();
282
- const ext = path.extname(lowerBase);
283
-
284
- if (
285
- lowerBase === "dockerfile" ||
286
- lowerBase.startsWith("dockerfile.") ||
287
- lowerBase === ".dockerfile" ||
288
- lowerBase.endsWith(".dockerfile")
289
- ) {
290
- return "dockerfile";
291
- }
292
-
293
- if ([".ts", ".tsx", ".mts", ".cts"].includes(ext)) return "typescript";
294
- if ([".js", ".jsx", ".mjs", ".cjs"].includes(ext)) return "javascript";
295
- if ([".py", ".pyw"].includes(ext)) return "python";
296
- if ([".tf", ".tfvars"].includes(ext)) return "terraform";
297
- if (ext === ".hcl") return "hcl";
298
- if ([".yml", ".yaml"].includes(ext)) return "yaml";
299
- return "plain";
300
- }
301
-
302
- export function buildFileContextMap(filePath: string, lines: string[]): FileContextMap {
303
- const language = detectContextLanguage(filePath);
304
- let symbols: ContextMapEntry[] = [];
305
-
306
- try {
307
- switch (language) {
308
- case "typescript":
309
- case "javascript":
310
- symbols = extractTsJsSymbols(lines);
311
- break;
312
- case "python":
313
- symbols = extractPythonSymbols(lines);
314
- break;
315
- case "terraform":
316
- case "hcl":
317
- symbols = extractTerraformSymbols(lines);
318
- break;
319
- case "yaml":
320
- symbols = extractYamlSymbols(lines);
321
- break;
322
- case "dockerfile":
323
- symbols = extractDockerfileSymbols(lines);
324
- break;
325
- default:
326
- symbols = [];
327
- }
328
- } catch {
329
- symbols = [];
330
- }
331
-
332
- const sorted = symbols
333
- .filter((entry) => entry.startLine > 0 && entry.endLine >= entry.startLine)
334
- .sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine);
335
-
336
- return {
337
- language,
338
- symbols: sorted.slice(0, MAX_CONTEXT_MAP_ENTRIES),
339
- symbolsTruncated: sorted.length > MAX_CONTEXT_MAP_ENTRIES || undefined,
340
- };
341
- }
package/src/batch.ts DELETED
@@ -1,28 +0,0 @@
1
- /**
2
- * batch — re-export barrel.
3
- *
4
- * Delegates to src/batch/ submodules. This file exists for backward
5
- * compatibility with existing import paths.
6
- */
7
- export {
8
- WeavePatchParams,
9
- BatchReadParams,
10
- createBatchTool,
11
- createBatchReadTool,
12
- } from "./batch/index.js";
13
-
14
- export {
15
- BashProcessTracker,
16
- createBatchBashPollTool,
17
- pollBatchBashResults,
18
- } from "./batch/index.js";
19
-
20
- export { suggestSimilarFiles } from "./batch/execute.js";
21
- export { isWithinDirectory } from "./batch/fuzzy-edit.js";
22
-
23
- export type {
24
- BashOpResult,
25
- PendingBashResult,
26
- OpResult,
27
- FileOpInput,
28
- } from "./batch/constants.js";
package/src/cli-args.ts DELETED
@@ -1,315 +0,0 @@
1
- /**
2
- * Helpers for inheriting selected parent CLI flags in child flow processes.
3
- */
4
-
5
- import * as fs from "node:fs";
6
- import * as os from "node:os";
7
- import * as path from "node:path";
8
- import { parseAgentSessionMode, type AgentSessionMode } from "./session-mode.js";
9
-
10
- function looksLikeExplicitRelativePath(value: string): boolean {
11
- return (
12
- value.startsWith("./") ||
13
- value.startsWith("../") ||
14
- value.startsWith(".\\") ||
15
- value.startsWith("..\\")
16
- );
17
- }
18
-
19
- interface ResolvePathOptions {
20
- allowPackageSource?: boolean;
21
- alwaysResolveRelative?: boolean;
22
- }
23
-
24
- function resolvePathArg(value: string, options: ResolvePathOptions = {}): string {
25
- const { allowPackageSource = false, alwaysResolveRelative = false } = options;
26
- if (!value) return value;
27
- if (allowPackageSource && (value.startsWith("npm:") || value.startsWith("git:"))) return value;
28
- if (value.startsWith("~/")) return path.join(os.homedir(), value.slice(2));
29
- if (path.isAbsolute(value)) return value;
30
-
31
- const resolved = path.resolve(process.cwd(), value);
32
- if (
33
- alwaysResolveRelative ||
34
- looksLikeExplicitRelativePath(value) ||
35
- path.extname(value) !== "" ||
36
- fs.existsSync(resolved)
37
- ) {
38
- return resolved;
39
- }
40
- return value;
41
- }
42
-
43
- export interface ParsedFlowCliArgs {
44
- extensionArgs: string[];
45
- alwaysProxy: string[];
46
- fallbackModel?: string;
47
- fallbackThinking?: string;
48
- fallbackTools?: string;
49
- fallbackNoTools: boolean;
50
- flowModelConfig?: string;
51
- flowMode?: string;
52
- flowSessionMode?: AgentSessionMode;
53
- tieredModels: {
54
- lite?: string;
55
- flash?: string;
56
- full?: string;
57
- };
58
- }
59
-
60
- /**
61
- * Parse process.argv into groups used for child flow invocations.
62
- *
63
- * - extensionArgs: forwarded with path resolution
64
- * - alwaysProxy: forwarded verbatim to every child
65
- * - fallbackModel/thinking/tools: used only when the flow file does not set them
66
- */
67
- let _cachedArgs: ParsedFlowCliArgs | undefined;
68
-
69
- /**
70
- * Lazily parse process.argv once and cache the result.
71
- * Avoids module-level side effects at import time.
72
- */
73
- export function getInheritedCliArgs(): ParsedFlowCliArgs {
74
- if (!_cachedArgs) _cachedArgs = parseFlowCliArgs(process.argv);
75
- return _cachedArgs;
76
- }
77
-
78
- export function parseFlowCliArgs(argv: string[]): ParsedFlowCliArgs {
79
- const extensionArgs: string[] = [];
80
- const alwaysProxy: string[] = [];
81
- let fallbackModel: string | undefined;
82
- let fallbackThinking: string | undefined;
83
- let fallbackTools: string | undefined;
84
- let fallbackNoTools = false;
85
- let flowModelConfig: string | undefined;
86
- let flowMode: string | undefined;
87
- let flowSessionMode: AgentSessionMode | undefined;
88
- let tieredLiteModel: string | undefined;
89
- let tieredFlashModel: string | undefined;
90
- let tieredFullModel: string | undefined;
91
-
92
- let i = 2; // skip executable + script name
93
- while (i < argv.length) {
94
- const raw = argv[i];
95
- if (!raw.startsWith("-")) {
96
- i++;
97
- continue;
98
- }
99
-
100
- const eqIdx = raw.indexOf("=");
101
- const flagName = eqIdx !== -1 ? raw.slice(0, eqIdx) : raw;
102
- const inlineValue = eqIdx !== -1 ? raw.slice(eqIdx + 1) : undefined;
103
-
104
- const nextToken = argv[i + 1];
105
- const nextIsValue = nextToken !== undefined && !nextToken.startsWith("-");
106
-
107
- const getValue = (): [string | undefined, number] => {
108
- if (inlineValue !== undefined) return [inlineValue, 1];
109
- if (nextIsValue) return [nextToken, 2];
110
- return [undefined, 1];
111
- };
112
-
113
- if (flagName === "--flow-model-config") {
114
- const [value, skip] = getValue();
115
- if (value !== undefined) flowModelConfig = value;
116
- i += skip;
117
- continue;
118
- }
119
-
120
- if (flagName === "--flow-mode") {
121
- const [value, skip] = getValue();
122
- if (value !== undefined) flowMode = value;
123
- i += skip;
124
- continue;
125
- }
126
-
127
- if (flagName === "--flow-session-mode") {
128
- const [value, skip] = getValue();
129
- flowSessionMode = parseAgentSessionMode(value);
130
- i += skip;
131
- continue;
132
- }
133
-
134
- if (
135
- [
136
- "--mode",
137
- "--session",
138
- "--append-system-prompt",
139
- "--export",
140
- "--flow-max-depth",
141
- ].includes(flagName)
142
- ) {
143
- const [, skip] = getValue();
144
- i += skip;
145
- continue;
146
- }
147
-
148
- if (["--flow-prevent-cycles", "--list-models"].includes(flagName)) {
149
- const [, skip] = getValue();
150
- i += skip;
151
- continue;
152
- }
153
-
154
- if (
155
- [
156
- "--print",
157
- "-p",
158
- "--no-session",
159
- "--continue",
160
- "-c",
161
- "--resume",
162
- "-r",
163
- "--offline",
164
- "--help",
165
- "-h",
166
- "--version",
167
- "-v",
168
- "--no-flow-prevent-cycles",
169
- ].includes(flagName)
170
- ) {
171
- i++;
172
- continue;
173
- }
174
-
175
- if (flagName === "--no-extensions" || flagName === "-ne") {
176
- extensionArgs.push(flagName);
177
- i++;
178
- continue;
179
- }
180
-
181
- if (flagName === "--extension" || flagName === "-e") {
182
- const [value, skip] = getValue();
183
- if (value !== undefined) {
184
- extensionArgs.push(flagName, resolvePathArg(value, { allowPackageSource: true }));
185
- }
186
- i += skip;
187
- continue;
188
- }
189
-
190
- if (["--skill", "--prompt-template", "--theme"].includes(flagName)) {
191
- const [value, skip] = getValue();
192
- if (value !== undefined) alwaysProxy.push(flagName, resolvePathArg(value));
193
- i += skip;
194
- continue;
195
- }
196
-
197
- if (flagName === "--session-dir") {
198
- const [value, skip] = getValue();
199
- if (value !== undefined) {
200
- alwaysProxy.push(flagName, resolvePathArg(value, { alwaysResolveRelative: true }));
201
- }
202
- i += skip;
203
- continue;
204
- }
205
-
206
- if (
207
- [
208
- "--provider",
209
- "--api-key",
210
- "--system-prompt",
211
- "--models",
212
- ].includes(flagName)
213
- ) {
214
- const [value, skip] = getValue();
215
- if (value !== undefined) alwaysProxy.push(flagName, value);
216
- i += skip;
217
- continue;
218
- }
219
-
220
- if (
221
- [
222
- "--no-skills",
223
- "-ns",
224
- "--no-prompt-templates",
225
- "-np",
226
- "--no-themes",
227
- "--verbose",
228
- ].includes(flagName)
229
- ) {
230
- alwaysProxy.push(flagName);
231
- i++;
232
- continue;
233
- }
234
-
235
- if (flagName === "--model") {
236
- const [value, skip] = getValue();
237
- if (value !== undefined) fallbackModel = value;
238
- i += skip;
239
- continue;
240
- }
241
-
242
- if (flagName === "--thinking") {
243
- const [value, skip] = getValue();
244
- if (value !== undefined) fallbackThinking = value;
245
- i += skip;
246
- continue;
247
- }
248
-
249
- if (flagName === "--tools") {
250
- const [value, skip] = getValue();
251
- if (value !== undefined) fallbackTools = value;
252
- i += skip;
253
- continue;
254
- }
255
-
256
- if (flagName === "--no-tools") {
257
- fallbackNoTools = true;
258
- i++;
259
- continue;
260
- }
261
-
262
- if (flagName === "--flow-lite-model") {
263
- const [value, skip] = getValue();
264
- if (value !== undefined) tieredLiteModel = value;
265
- i += skip;
266
- continue;
267
- }
268
-
269
- if (flagName === "--flow-flash-model") {
270
- const [value, skip] = getValue();
271
- if (value !== undefined) tieredFlashModel = value;
272
- i += skip;
273
- continue;
274
- }
275
-
276
- if (flagName === "--flow-full-model") {
277
- const [value, skip] = getValue();
278
- if (value !== undefined) tieredFullModel = value;
279
- i += skip;
280
- continue;
281
- }
282
-
283
- if (inlineValue !== undefined) {
284
- alwaysProxy.push(flagName, inlineValue);
285
- i++;
286
- continue;
287
- }
288
-
289
- if (nextIsValue) {
290
- alwaysProxy.push(flagName, nextToken);
291
- i += 2;
292
- continue;
293
- }
294
-
295
- alwaysProxy.push(flagName);
296
- i++;
297
- }
298
-
299
- return {
300
- extensionArgs,
301
- alwaysProxy,
302
- fallbackModel,
303
- fallbackThinking,
304
- fallbackTools,
305
- fallbackNoTools,
306
- flowModelConfig,
307
- flowMode,
308
- flowSessionMode,
309
- tieredModels: {
310
- lite: tieredLiteModel,
311
- flash: tieredFlashModel,
312
- full: tieredFullModel,
313
- },
314
- };
315
- }