pi-agent-flow 2.2.13 → 2.2.15

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 (254) hide show
  1. package/README.md +12 -0
  2. package/dist/batch/apply-patch.d.ts +2 -1
  3. package/dist/batch/apply-patch.d.ts.map +1 -1
  4. package/dist/batch/batch-bash.d.ts.map +1 -1
  5. package/dist/batch/batch-bash.js +9 -43
  6. package/dist/batch/batch-bash.js.map +1 -1
  7. package/dist/batch/constants.d.ts +9 -1
  8. package/dist/batch/constants.d.ts.map +1 -1
  9. package/dist/batch/constants.js +7 -0
  10. package/dist/batch/constants.js.map +1 -1
  11. package/dist/batch/execute.d.ts +1 -13
  12. package/dist/batch/execute.d.ts.map +1 -1
  13. package/dist/batch/execute.js +87 -28
  14. package/dist/batch/execute.js.map +1 -1
  15. package/dist/batch/index.d.ts.map +1 -1
  16. package/dist/batch/index.js +16 -14
  17. package/dist/batch/index.js.map +1 -1
  18. package/dist/batch/render.d.ts.map +1 -1
  19. package/dist/batch/render.js.map +1 -1
  20. package/dist/batch/summary.d.ts +0 -6
  21. package/dist/batch/summary.d.ts.map +1 -1
  22. package/dist/batch/summary.js +3 -3
  23. package/dist/batch/summary.js.map +1 -1
  24. package/dist/batch/symbols.d.ts.map +1 -1
  25. package/dist/batch/symbols.js +3 -1
  26. package/dist/batch/symbols.js.map +1 -1
  27. package/dist/batch/truncate-output.d.ts +31 -0
  28. package/dist/batch/truncate-output.d.ts.map +1 -0
  29. package/dist/batch/truncate-output.js +120 -0
  30. package/dist/batch/truncate-output.js.map +1 -0
  31. package/dist/config/config.d.ts +2 -1
  32. package/dist/config/config.d.ts.map +1 -1
  33. package/dist/config/config.js +10 -24
  34. package/dist/config/config.js.map +1 -1
  35. package/dist/config/models.d.ts.map +1 -1
  36. package/dist/config/models.js +7 -5
  37. package/dist/config/models.js.map +1 -1
  38. package/dist/config/paths.d.ts +3 -0
  39. package/dist/config/paths.d.ts.map +1 -0
  40. package/dist/config/paths.js +9 -0
  41. package/dist/config/paths.js.map +1 -0
  42. package/dist/config/resolver-helpers.d.ts +44 -0
  43. package/dist/config/resolver-helpers.d.ts.map +1 -0
  44. package/dist/config/resolver-helpers.js +135 -0
  45. package/dist/config/resolver-helpers.js.map +1 -0
  46. package/dist/config/settings-resolver.d.ts +0 -6
  47. package/dist/config/settings-resolver.d.ts.map +1 -1
  48. package/dist/config/settings-resolver.js +27 -256
  49. package/dist/config/settings-resolver.js.map +1 -1
  50. package/dist/core2/snapshot.d.ts +0 -2
  51. package/dist/core2/snapshot.d.ts.map +1 -1
  52. package/dist/core2/snapshot.js +98 -24
  53. package/dist/core2/snapshot.js.map +1 -1
  54. package/dist/flow/agents.d.ts +1 -1
  55. package/dist/flow/agents.d.ts.map +1 -1
  56. package/dist/flow/agents.js +18 -9
  57. package/dist/flow/agents.js.map +1 -1
  58. package/dist/flow/audit-formatters.d.ts +20 -0
  59. package/dist/flow/audit-formatters.d.ts.map +1 -0
  60. package/dist/flow/audit-formatters.js +123 -0
  61. package/dist/flow/audit-formatters.js.map +1 -0
  62. package/dist/flow/complexity.d.ts +3 -2
  63. package/dist/flow/complexity.d.ts.map +1 -1
  64. package/dist/flow/complexity.js +1 -1
  65. package/dist/flow/complexity.js.map +1 -1
  66. package/dist/flow/continuation.d.ts.map +1 -1
  67. package/dist/flow/continuation.js +6 -4
  68. package/dist/flow/continuation.js.map +1 -1
  69. package/dist/flow/cycle-guard.d.ts +20 -0
  70. package/dist/flow/cycle-guard.d.ts.map +1 -0
  71. package/dist/flow/cycle-guard.js +56 -0
  72. package/dist/flow/cycle-guard.js.map +1 -0
  73. package/dist/flow/depth.d.ts +0 -1
  74. package/dist/flow/depth.d.ts.map +1 -1
  75. package/dist/flow/depth.js +3 -2
  76. package/dist/flow/depth.js.map +1 -1
  77. package/dist/flow/dump-io.d.ts +15 -0
  78. package/dist/flow/dump-io.d.ts.map +1 -0
  79. package/dist/flow/dump-io.js +169 -0
  80. package/dist/flow/dump-io.js.map +1 -0
  81. package/dist/flow/execute-single.d.ts +8 -0
  82. package/dist/flow/execute-single.d.ts.map +1 -0
  83. package/dist/flow/execute-single.js +132 -0
  84. package/dist/flow/execute-single.js.map +1 -0
  85. package/dist/flow/executor.d.ts +3 -62
  86. package/dist/flow/executor.d.ts.map +1 -1
  87. package/dist/flow/executor.js +36 -342
  88. package/dist/flow/executor.js.map +1 -1
  89. package/dist/flow/flow-args.d.ts +14 -0
  90. package/dist/flow/flow-args.d.ts.map +1 -0
  91. package/dist/flow/flow-args.js +119 -0
  92. package/dist/flow/flow-args.js.map +1 -0
  93. package/dist/flow/flow-live.d.ts +18 -0
  94. package/dist/flow/flow-live.d.ts.map +1 -0
  95. package/dist/flow/flow-live.js +46 -0
  96. package/dist/flow/flow-live.js.map +1 -0
  97. package/dist/flow/process-lifecycle.d.ts +28 -0
  98. package/dist/flow/process-lifecycle.d.ts.map +1 -0
  99. package/dist/flow/process-lifecycle.js +114 -0
  100. package/dist/flow/process-lifecycle.js.map +1 -0
  101. package/dist/flow/runner.d.ts +4 -54
  102. package/dist/flow/runner.d.ts.map +1 -1
  103. package/dist/flow/runner.js +55 -517
  104. package/dist/flow/runner.js.map +1 -1
  105. package/dist/flow/settings-command.d.ts +2 -24
  106. package/dist/flow/settings-command.d.ts.map +1 -1
  107. package/dist/flow/settings-command.js +14 -716
  108. package/dist/flow/settings-command.js.map +1 -1
  109. package/dist/flow/settings-handler.d.ts +9 -0
  110. package/dist/flow/settings-handler.d.ts.map +1 -0
  111. package/dist/flow/settings-handler.js +377 -0
  112. package/dist/flow/settings-handler.js.map +1 -0
  113. package/dist/flow/settings-items.d.ts +42 -0
  114. package/dist/flow/settings-items.d.ts.map +1 -0
  115. package/dist/flow/settings-items.js +380 -0
  116. package/dist/flow/settings-items.js.map +1 -0
  117. package/dist/flow/spawn-utils.d.ts +17 -0
  118. package/dist/flow/spawn-utils.d.ts.map +1 -0
  119. package/dist/flow/spawn-utils.js +40 -0
  120. package/dist/flow/spawn-utils.js.map +1 -0
  121. package/dist/flow/store.d.ts.map +1 -1
  122. package/dist/flow/store.js +2 -8
  123. package/dist/flow/store.js.map +1 -1
  124. package/dist/flow/transition.d.ts +0 -1
  125. package/dist/flow/transition.d.ts.map +1 -1
  126. package/dist/flow/transition.js +0 -3
  127. package/dist/flow/transition.js.map +1 -1
  128. package/dist/index.d.ts +3 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +94 -57
  131. package/dist/index.js.map +1 -1
  132. package/dist/io/atomic-write.d.ts +10 -0
  133. package/dist/io/atomic-write.d.ts.map +1 -0
  134. package/dist/io/atomic-write.js +30 -0
  135. package/dist/io/atomic-write.js.map +1 -0
  136. package/dist/notify/notify.d.ts.map +1 -1
  137. package/dist/notify/notify.js +1 -4
  138. package/dist/notify/notify.js.map +1 -1
  139. package/dist/snapshot/cli-args.d.ts +1 -2
  140. package/dist/snapshot/cli-args.d.ts.map +1 -1
  141. package/dist/snapshot/runner-events.d.ts +10 -0
  142. package/dist/snapshot/runner-events.d.ts.map +1 -1
  143. package/dist/snapshot/runner-events.js +112 -30
  144. package/dist/snapshot/runner-events.js.map +1 -1
  145. package/dist/snapshot/structured-output.d.ts.map +1 -1
  146. package/dist/snapshot/structured-output.js +3 -1
  147. package/dist/snapshot/structured-output.js.map +1 -1
  148. package/dist/snapshot/trace-output.d.ts.map +1 -1
  149. package/dist/snapshot/trace-output.js +8 -4
  150. package/dist/snapshot/trace-output.js.map +1 -1
  151. package/dist/steering/sliding-prompt.d.ts.map +1 -1
  152. package/dist/steering/sliding-prompt.js +12 -15
  153. package/dist/steering/sliding-prompt.js.map +1 -1
  154. package/dist/steering/tool-utils.d.ts +3 -3
  155. package/dist/steering/tool-utils.d.ts.map +1 -1
  156. package/dist/steering/tool-utils.js +3 -3
  157. package/dist/steering/tool-utils.js.map +1 -1
  158. package/dist/tools/ask-user.js.map +1 -1
  159. package/dist/tools/timed-bash.d.ts.map +1 -1
  160. package/dist/tools/timed-bash.js +8 -3
  161. package/dist/tools/timed-bash.js.map +1 -1
  162. package/dist/tools/trace.d.ts +0 -1
  163. package/dist/tools/trace.d.ts.map +1 -1
  164. package/dist/tools/trace.js +79 -62
  165. package/dist/tools/trace.js.map +1 -1
  166. package/dist/tools/web-ops.d.ts +0 -49
  167. package/dist/tools/web-ops.d.ts.map +1 -1
  168. package/dist/tools/web-ops.js +9 -9
  169. package/dist/tools/web-ops.js.map +1 -1
  170. package/dist/tui/body-render.d.ts +31 -0
  171. package/dist/tui/body-render.d.ts.map +1 -0
  172. package/dist/tui/body-render.js +589 -0
  173. package/dist/tui/body-render.js.map +1 -0
  174. package/dist/tui/context-display.d.ts +18 -0
  175. package/dist/tui/context-display.d.ts.map +1 -0
  176. package/dist/tui/context-display.js +29 -0
  177. package/dist/tui/context-display.js.map +1 -0
  178. package/dist/tui/flow-colors.d.ts +6 -1
  179. package/dist/tui/flow-colors.d.ts.map +1 -1
  180. package/dist/tui/flow-colors.js +1 -0
  181. package/dist/tui/flow-colors.js.map +1 -1
  182. package/dist/tui/flow-live-state.d.ts +36 -0
  183. package/dist/tui/flow-live-state.d.ts.map +1 -0
  184. package/dist/tui/flow-live-state.js +53 -0
  185. package/dist/tui/flow-live-state.js.map +1 -0
  186. package/dist/tui/grouping.d.ts +27 -0
  187. package/dist/tui/grouping.d.ts.map +1 -0
  188. package/dist/tui/grouping.js +191 -0
  189. package/dist/tui/grouping.js.map +1 -0
  190. package/dist/tui/header.d.ts +25 -0
  191. package/dist/tui/header.d.ts.map +1 -0
  192. package/dist/tui/header.js +95 -0
  193. package/dist/tui/header.js.map +1 -0
  194. package/dist/tui/render-utils.d.ts +1 -0
  195. package/dist/tui/render-utils.d.ts.map +1 -1
  196. package/dist/tui/render-utils.js +4 -5
  197. package/dist/tui/render-utils.js.map +1 -1
  198. package/dist/tui/render.d.ts +19 -33
  199. package/dist/tui/render.d.ts.map +1 -1
  200. package/dist/tui/render.js +112 -1014
  201. package/dist/tui/render.js.map +1 -1
  202. package/dist/tui/scramble/animation-status.d.ts +5 -0
  203. package/dist/tui/scramble/animation-status.d.ts.map +1 -0
  204. package/dist/tui/scramble/animation-status.js +93 -0
  205. package/dist/tui/scramble/animation-status.js.map +1 -0
  206. package/dist/tui/scramble/constants.d.ts +0 -4
  207. package/dist/tui/scramble/constants.d.ts.map +1 -1
  208. package/dist/tui/scramble/constants.js +3 -3
  209. package/dist/tui/scramble/constants.js.map +1 -1
  210. package/dist/tui/scramble/dynamic-text.d.ts +10 -0
  211. package/dist/tui/scramble/dynamic-text.d.ts.map +1 -0
  212. package/dist/tui/scramble/dynamic-text.js +19 -0
  213. package/dist/tui/scramble/dynamic-text.js.map +1 -0
  214. package/dist/tui/scramble/index.d.ts +8 -2
  215. package/dist/tui/scramble/index.d.ts.map +1 -1
  216. package/dist/tui/scramble/index.js +8 -1
  217. package/dist/tui/scramble/index.js.map +1 -1
  218. package/dist/tui/scramble/lifecycle.d.ts +4 -0
  219. package/dist/tui/scramble/lifecycle.d.ts.map +1 -0
  220. package/dist/tui/scramble/lifecycle.js +75 -0
  221. package/dist/tui/scramble/lifecycle.js.map +1 -0
  222. package/dist/tui/scramble/line-state.d.ts +5 -0
  223. package/dist/tui/scramble/line-state.d.ts.map +1 -0
  224. package/dist/tui/scramble/line-state.js +99 -0
  225. package/dist/tui/scramble/line-state.js.map +1 -0
  226. package/dist/tui/scramble/manager.d.ts +3 -14
  227. package/dist/tui/scramble/manager.d.ts.map +1 -1
  228. package/dist/tui/scramble/manager.js +22 -405
  229. package/dist/tui/scramble/manager.js.map +1 -1
  230. package/dist/tui/scramble/singleton.d.ts +3 -0
  231. package/dist/tui/scramble/singleton.d.ts.map +1 -0
  232. package/dist/tui/scramble/singleton.js +3 -0
  233. package/dist/tui/scramble/singleton.js.map +1 -0
  234. package/dist/tui/scramble/timer.d.ts +6 -0
  235. package/dist/tui/scramble/timer.d.ts.map +1 -0
  236. package/dist/tui/scramble/timer.js +28 -0
  237. package/dist/tui/scramble/timer.js.map +1 -0
  238. package/dist/tui/scramble/utils.d.ts +0 -2
  239. package/dist/tui/scramble/utils.d.ts.map +1 -1
  240. package/dist/tui/scramble/utils.js +0 -9
  241. package/dist/tui/scramble/utils.js.map +1 -1
  242. package/dist/tui/scramble/value-flash.d.ts +6 -0
  243. package/dist/tui/scramble/value-flash.d.ts.map +1 -0
  244. package/dist/tui/scramble/value-flash.js +141 -0
  245. package/dist/tui/scramble/value-flash.js.map +1 -0
  246. package/dist/tui/traces.d.ts +13 -0
  247. package/dist/tui/traces.d.ts.map +1 -0
  248. package/dist/tui/traces.js +97 -0
  249. package/dist/tui/traces.js.map +1 -0
  250. package/dist/types/ui.d.ts +0 -4
  251. package/dist/types/ui.d.ts.map +1 -1
  252. package/dist/types/ui.js +1 -30
  253. package/dist/types/ui.js.map +1 -1
  254. package/package.json +5 -1
@@ -7,16 +7,17 @@
7
7
  * When called with no arguments, opens an interactive TUI overlay.
8
8
  */
9
9
  import { DynamicBorder } from "@earendil-works/pi-coding-agent";
10
- import { loadFlowSettings, writeFlowSetting, loadFlowModelConfigs, writeGlobalFlowMode, writeFlowModelConfig } from "../config/config.js";
10
+ import { loadFlowSettings, writeFlowSetting } from "../config/config.js";
11
11
  import { configureSteering } from "../steering/sliding-prompt.js";
12
12
  import { configureStrategicHint } from "../steering/tool-utils.js";
13
13
  import { scrambleManager } from "../tui/scramble/index.js";
14
- import { getLoop } from "./loop.js";
15
- import { Container, Input, matchesKey, SelectList, Key, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@earendil-works/pi-tui";
16
- // Module-level refs for submenu builders (set during handler call)
17
- let _modelRegistry = null;
18
- let _theme = null;
19
- let _keybindings = null;
14
+ import { Container, matchesKey, SelectList, Key, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@earendil-works/pi-tui";
15
+ import { getMainMenuItems, getSteeringItems, getAnimationItems, getToolItems, getDebugItems, getSessionItems, getAskUserItems, getLoopItems, getModelConfigItems, _moduleRefs, } from "./settings-items.js";
16
+ import { getCategoryHandler, handleTextCommand } from "./settings-handler.js";
17
+ export { getMainMenuItems, getSteeringItems, getAnimationItems, getToolItems, getDebugItems, getSessionItems, getAskUserItems, getLoopItems, getModelConfigItems, buildInputSubmenu, buildModelPickerSubmenu, } from "./settings-items.js";
18
+ // ---------------------------------------------------------------------------
19
+ // SettingsList component (local implementation matching sub-core pattern)
20
+ // ---------------------------------------------------------------------------
20
21
  export class SettingsList {
21
22
  items;
22
23
  theme;
@@ -190,368 +191,6 @@ export class SettingsList {
190
191
  lines.push(this.theme.hint(" ←/→ change • Enter/Space edit custom • Esc to cancel"));
191
192
  }
192
193
  }
193
- function getMainMenuItems(settings, cwd) {
194
- const steeringEnabled = settings.steering?.enabled ?? true;
195
- const animationEnabled = settings.animation?.enabled ?? true;
196
- const toolOptimize = settings.toolOptimize ?? true;
197
- const structuredOutput = settings.structuredOutput ?? true;
198
- const complexity = settings.complexity ?? "moderate";
199
- const askUserEnabled = settings.askUser?.enabled ?? false;
200
- const askUserTimeout = settings.askUser?.timeout ?? 300;
201
- const loaded = loadFlowModelConfigs(cwd);
202
- const strategyName = loaded.selectedName;
203
- const litePrimary = loaded.strategy.lite?.primary ?? "(default)";
204
- const primaryModelShort = litePrimary.includes("/") ? litePrimary.split("/").pop() : litePrimary;
205
- const loop = getLoop(cwd);
206
- const loopDescription = loop ? `${loop.status} • ${loop.sessionCount} sessions` : "none";
207
- return [
208
- {
209
- value: "steering",
210
- label: "Steering Settings",
211
- description: steeringEnabled ? "enabled" : "disabled",
212
- tooltip: "Configure root state steering and strategic hints",
213
- },
214
- {
215
- value: "animation",
216
- label: "Animation Settings",
217
- description: animationEnabled ? "enabled" : "disabled",
218
- tooltip: "Toggle animation effects and glitch/scramble",
219
- },
220
- {
221
- value: "tools",
222
- label: "Tool Settings",
223
- description: `tool-optimize: ${toolOptimize ? "on" : "off"}, structured-output: ${structuredOutput ? "on" : "off"}, trace: ${(settings.tools?.trace ?? true) ? "on" : "off"}, batch-read: ${(settings.tools?.batchRead ?? toolOptimize) ? "on" : "off"}`,
224
- tooltip: "Configure tool optimization and structured output",
225
- },
226
- {
227
- value: "session",
228
- label: "Session Settings",
229
- description: `complexity: ${complexity} · body: ${settings.bodyVerbosity ?? "lite"}`,
230
- tooltip: "Set default complexity and concurrency",
231
- },
232
- {
233
- value: "ask-user",
234
- label: "Ask User Settings",
235
- description: `enabled: ${askUserEnabled ? "on" : "off"}, timeout: ${askUserTimeout}s`,
236
- tooltip: "Configure ask_user timeout and countdown",
237
- },
238
- {
239
- value: "model-config",
240
- label: "Model Config",
241
- description: `${strategyName} ▸ lite: ${primaryModelShort}`,
242
- tooltip: "Configure LLM models for lite, flash, and full flow tiers",
243
- },
244
- {
245
- value: "loop",
246
- label: "Loop Status",
247
- description: loopDescription,
248
- tooltip: "Endless loop state and statistics",
249
- },
250
- {
251
- value: "debug",
252
- label: "Debug Settings",
253
- description: `debugMode: ${settings.debugMode ?? false ? "on" : "off"}`,
254
- tooltip: "Write full child flow prompt to disk on every spawn",
255
- },
256
- {
257
- value: "reset",
258
- label: "Reset to Defaults",
259
- description: "restore all settings",
260
- tooltip: "Restore all flow settings to their default values",
261
- },
262
- ];
263
- }
264
- function getSteeringItems(settings) {
265
- const steering = settings.steering ?? {};
266
- return [
267
- {
268
- id: "steering.enabled",
269
- label: "enabled",
270
- description: "Toggle steering injection",
271
- currentValue: (steering.enabled ?? true) ? "on" : "off",
272
- values: ["on", "off"],
273
- },
274
- {
275
- id: "steering.strategicHint",
276
- label: "strategic-hint",
277
- description: "Toggle [Hint: Plan next step...]",
278
- currentValue: (steering.strategicHint ?? true) ? "on" : "off",
279
- values: ["on", "off"],
280
- },
281
- {
282
- id: "steering.customPrompt",
283
- label: "custom-prompt",
284
- description: "Enter custom steering prompt or type 'default' to reset",
285
- currentValue: steering.customPrompt ?? "(default)",
286
- submenu: buildInputSubmenu("Custom prompt (or 'default')", (v) => {
287
- const trimmed = v.trim();
288
- if (!trimmed || trimmed.toLowerCase() === "default")
289
- return "(default)";
290
- return trimmed;
291
- }),
292
- },
293
- ];
294
- }
295
- function getAnimationItems(settings) {
296
- const animation = settings.animation ?? {};
297
- return [
298
- {
299
- id: "animation.enabled",
300
- label: "enabled",
301
- description: "Master animation switch",
302
- currentValue: (animation.enabled ?? true) ? "on" : "off",
303
- values: ["on", "off"],
304
- },
305
- {
306
- id: "animation.glitch",
307
- label: "glitch",
308
- description: "Glitch/scramble effect",
309
- currentValue: (animation.glitch ?? true) ? "on" : "off",
310
- values: ["on", "off"],
311
- },
312
- ];
313
- }
314
- function getToolItems(settings) {
315
- return [
316
- {
317
- id: "toolOptimize",
318
- label: "tool-optimize",
319
- description: "Unified batch tool vs separate tools",
320
- currentValue: (settings.toolOptimize ?? true) ? "on" : "off",
321
- values: ["on", "off"],
322
- },
323
- {
324
- id: "structuredOutput",
325
- label: "structured-output",
326
- description: "Structured JSON output from flows",
327
- currentValue: (settings.structuredOutput ?? true) ? "on" : "off",
328
- values: ["on", "off"],
329
- },
330
- {
331
- id: "tools.trace",
332
- label: "trace",
333
- description: "Enable the trace tool",
334
- currentValue: (settings.tools?.trace ?? true) ? "on" : "off",
335
- values: ["on", "off"],
336
- },
337
- {
338
- id: "tools.batchRead",
339
- label: "batch-read",
340
- description: "Enable the batch_read tool",
341
- currentValue: (settings.tools?.batchRead ?? settings.toolOptimize ?? true) ? "on" : "off",
342
- values: ["on", "off"],
343
- },
344
- ];
345
- }
346
- function getDebugItems(settings) {
347
- return [
348
- {
349
- id: "debugMode",
350
- label: "emit-flow-content",
351
- description: "Write full child flow prompt to disk on every spawn",
352
- currentValue: (settings.debugMode ?? false) ? "on" : "off",
353
- values: ["on", "off"],
354
- },
355
- ];
356
- }
357
- function getSessionItems(settings) {
358
- return [
359
- {
360
- id: "bodyVerbosity",
361
- label: "body",
362
- description: "Collapsed result verbosity",
363
- currentValue: settings.bodyVerbosity ?? "lite",
364
- values: ["lite", "full"],
365
- },
366
- {
367
- id: "complexity",
368
- label: "complexity",
369
- description: "Complexity sets budget + review",
370
- currentValue: settings.complexity ?? "moderate",
371
- values: ["snap", "simple", "moderate", "complex", "intricate"],
372
- },
373
- {
374
- id: "maxConcurrency",
375
- label: "max-concurrency",
376
- description: "Maximum concurrent flows",
377
- currentValue: String(settings.maxConcurrency ?? 4),
378
- values: ["1", "2", "3", "4", "5", "6", "7", "8"],
379
- submenu: buildInputSubmenu("Max concurrency (1-20)", (v) => {
380
- const n = Number(v.trim());
381
- if (!Number.isSafeInteger(n) || n < 1 || n > 20)
382
- return null;
383
- return String(n);
384
- }),
385
- },
386
- ];
387
- }
388
- function getAskUserItems(settings) {
389
- const askUser = settings.askUser ?? {};
390
- return [
391
- {
392
- id: "askUser.enabled",
393
- label: "enabled",
394
- description: "Show countdown timer in ask_user prompt",
395
- currentValue: (askUser.enabled ?? false) ? "on" : "off",
396
- values: ["on", "off"],
397
- },
398
- {
399
- id: "askUser.timeout",
400
- label: "timeout",
401
- description: "Auto-dismiss timeout in seconds",
402
- currentValue: String(askUser.timeout ?? 300),
403
- values: ["30", "60", "120", "300", "600"],
404
- submenu: buildInputSubmenu("Timeout in seconds (10-3600)", (v) => {
405
- const n = Number(v.trim());
406
- if (!Number.isSafeInteger(n) || n < 10 || n > 3600)
407
- return null;
408
- return String(n);
409
- }),
410
- },
411
- ];
412
- }
413
- function getLoopItems(_settings, cwd) {
414
- const loop = getLoop(cwd);
415
- if (!loop) {
416
- return [
417
- {
418
- id: "loop.status",
419
- label: "status",
420
- description: "No active loop",
421
- currentValue: "none",
422
- },
423
- ];
424
- }
425
- return [
426
- {
427
- id: "loop.status",
428
- label: "status",
429
- description: "Current loop status",
430
- currentValue: loop.status,
431
- },
432
- {
433
- id: "loop.objective",
434
- label: "objective",
435
- description: "Loop objective",
436
- currentValue: loop.objective,
437
- },
438
- {
439
- id: "loop.sessions",
440
- label: "sessions",
441
- description: "Number of warped sessions",
442
- currentValue: String(loop.sessionCount),
443
- },
444
- {
445
- id: "loop.flows",
446
- label: "flows",
447
- description: "Total flows across sessions",
448
- currentValue: String(loop.totalFlowsAcrossSessions),
449
- },
450
- {
451
- id: "loop.tokens",
452
- label: "tokens",
453
- description: "Total tokens across sessions",
454
- currentValue: String(loop.totalTokensAcrossSessions),
455
- },
456
- ];
457
- }
458
- function getModelConfigItems(settings, cwd) {
459
- const loaded = loadFlowModelConfigs(cwd);
460
- const strategyName = loaded.selectedName;
461
- const strategy = loaded.strategy;
462
- const items = [
463
- {
464
- id: "modelConfig.strategy",
465
- label: "strategy",
466
- description: "Active model strategy",
467
- currentValue: strategyName,
468
- values: Object.keys(loaded.configs).sort(),
469
- },
470
- ];
471
- for (const tier of ["lite", "flash", "full"]) {
472
- const tierConfig = strategy[tier];
473
- const primary = tierConfig?.primary ?? "(default)";
474
- const failover = tierConfig?.failover?.join(", ") ?? "(none)";
475
- items.push({
476
- id: `modelConfig.${tier}.primary`,
477
- label: `${tier}: primary`,
478
- description: `Primary model for ${tier} tier`,
479
- currentValue: primary,
480
- submenu: buildModelPickerSubmenu(primary, tier, "primary"),
481
- });
482
- items.push({
483
- id: `modelConfig.${tier}.failover`,
484
- label: `${tier}: failover`,
485
- description: `Failover models for ${tier} tier`,
486
- currentValue: failover,
487
- submenu: buildModelPickerSubmenu(failover, tier, "failover"),
488
- });
489
- }
490
- return items;
491
- }
492
- // ---------------------------------------------------------------------------
493
- // Submenu helpers
494
- // ---------------------------------------------------------------------------
495
- function buildInputSubmenu(label, parseValue) {
496
- return (currentValue, done) => {
497
- const input = new Input();
498
- input.focused = true;
499
- input.setValue(currentValue);
500
- input.onSubmit = (value) => {
501
- const parsed = parseValue(value);
502
- if (parsed === null)
503
- return;
504
- done(parsed);
505
- };
506
- input.onEscape = () => {
507
- done();
508
- };
509
- const container = new Container();
510
- container.addChild(new Text(label, 1, 0));
511
- container.addChild(new Spacer(1));
512
- container.addChild(input);
513
- return {
514
- render: (width) => container.render(width),
515
- invalidate: () => container.invalidate(),
516
- handleInput: (data) => input.handleInput(data),
517
- };
518
- };
519
- }
520
- function buildModelPickerSubmenu(currentValue, tier, slot) {
521
- return (_currentValue, done) => {
522
- const models = _modelRegistry?.getAvailable() ?? [];
523
- const items = models.map((m) => ({
524
- value: `${m.provider}/${m.id}`,
525
- label: `${m.provider}/${m.id}`,
526
- description: m.name ?? "",
527
- }));
528
- items.unshift({ value: "(default)", label: "(default)", description: "Use the default model" });
529
- const selectList = new SelectList(items, 15, {
530
- selectedPrefix: (t) => _theme?.fg("accent", t) ?? t,
531
- selectedText: (t) => _theme?.fg("accent", t) ?? t,
532
- description: (t) => _theme?.fg("muted", t) ?? t,
533
- scrollInfo: (t) => _theme?.fg("dim", t) ?? t,
534
- noMatch: (t) => _theme?.fg("warning", t) ?? t,
535
- });
536
- selectList.onSelect = (item) => {
537
- done(item.value);
538
- };
539
- selectList.onCancel = () => {
540
- done();
541
- };
542
- return {
543
- render(width) {
544
- return selectList.render(width);
545
- },
546
- invalidate() {
547
- selectList.invalidate?.();
548
- },
549
- handleInput(data) {
550
- selectList.handleInput(data);
551
- },
552
- };
553
- };
554
- }
555
194
  // ---------------------------------------------------------------------------
556
195
  // Command registration
557
196
  // ---------------------------------------------------------------------------
@@ -562,24 +201,22 @@ export function setupSettingsCommand(pi) {
562
201
  if (!ctx.ui) {
563
202
  return;
564
203
  }
565
- const cwd = ctx.cwd;
566
204
  const trimmed = args.trim().toLowerCase();
567
205
  const parts = trimmed.split(/\s+/);
568
206
  const sub = parts[0] ?? "";
569
- const value = parts[1] ?? "";
570
207
  if (!sub) {
208
+ const cwd = ctx.cwd;
571
209
  const settings = loadFlowSettings(cwd);
572
- _modelRegistry = ctx.modelRegistry;
210
+ _moduleRefs.modelRegistry = ctx.modelRegistry;
573
211
  await ctx.ui.custom((tui, theme, keybindings, done) => {
574
- _theme = theme;
575
- _keybindings = keybindings;
212
+ _moduleRefs.theme = theme;
213
+ _moduleRefs.keybindings = keybindings;
576
214
  let currentCategory = "main";
577
215
  let container = new Container();
578
216
  let activeList = null;
579
217
  function rebuild() {
580
218
  container = new Container();
581
219
  activeList = null;
582
- // Header
583
220
  container.addChild(new DynamicBorder());
584
221
  container.addChild(new Text(theme.fg("accent", theme.bold("Flow Settings")), 1, 0));
585
222
  container.addChild(new Spacer(1));
@@ -630,169 +267,33 @@ export function setupSettingsCommand(pi) {
630
267
  }
631
268
  else {
632
269
  let items;
633
- let handleChange;
634
270
  const backCategory = "main";
635
271
  if (currentCategory === "steering") {
636
272
  items = getSteeringItems(currentSettings);
637
- handleChange = (id, value) => {
638
- if (id === "steering.enabled") {
639
- const boolValue = value === "on";
640
- writeFlowSetting(cwd, "steering.enabled", boolValue);
641
- configureSteering({
642
- enabled: boolValue,
643
- customPrompt: currentSettings.steering?.customPrompt,
644
- });
645
- }
646
- else if (id === "steering.strategicHint") {
647
- const boolValue = value === "on";
648
- writeFlowSetting(cwd, "steering.strategicHint", boolValue);
649
- configureStrategicHint(boolValue);
650
- }
651
- else if (id === "steering.customPrompt") {
652
- if (value === "(default)") {
653
- writeFlowSetting(cwd, "steering.customPrompt", undefined);
654
- configureSteering({
655
- enabled: currentSettings.steering?.enabled ?? true,
656
- customPrompt: undefined,
657
- });
658
- }
659
- else {
660
- writeFlowSetting(cwd, "steering.customPrompt", value);
661
- configureSteering({
662
- enabled: currentSettings.steering?.enabled ?? true,
663
- customPrompt: value,
664
- });
665
- }
666
- }
667
- rebuild();
668
- tui.requestRender();
669
- };
670
273
  }
671
274
  else if (currentCategory === "animation") {
672
275
  items = getAnimationItems(currentSettings);
673
- handleChange = (id, value) => {
674
- if (id === "animation.enabled") {
675
- const boolValue = value === "on";
676
- writeFlowSetting(cwd, "animation.enabled", boolValue);
677
- scrambleManager.setAnimationConfig({
678
- enabled: boolValue,
679
- glitch: currentSettings.animation?.glitch ?? true,
680
- });
681
- }
682
- else if (id === "animation.glitch") {
683
- const boolValue = value === "on";
684
- writeFlowSetting(cwd, "animation.glitch", boolValue);
685
- scrambleManager.setAnimationConfig({
686
- enabled: currentSettings.animation?.enabled ?? true,
687
- glitch: boolValue,
688
- });
689
- }
690
- rebuild();
691
- tui.requestRender();
692
- };
693
276
  }
694
277
  else if (currentCategory === "tools") {
695
278
  items = getToolItems(currentSettings);
696
- handleChange = (id, value) => {
697
- if (id === "toolOptimize") {
698
- writeFlowSetting(cwd, "toolOptimize", value === "on");
699
- }
700
- else if (id === "structuredOutput") {
701
- writeFlowSetting(cwd, "structuredOutput", value === "on");
702
- }
703
- else if (id === "tools.trace") {
704
- writeFlowSetting(cwd, "tools.trace", value === "on");
705
- }
706
- else if (id === "tools.batchRead") {
707
- writeFlowSetting(cwd, "tools.batchRead", value === "on");
708
- }
709
- rebuild();
710
- tui.requestRender();
711
- };
712
279
  }
713
280
  else if (currentCategory === "session") {
714
281
  items = getSessionItems(currentSettings);
715
- handleChange = (id, value) => {
716
- if (id === "complexity") {
717
- writeFlowSetting(cwd, "complexity", value);
718
- }
719
- else if (id === "maxConcurrency") {
720
- writeFlowSetting(cwd, "maxConcurrency", Number(value));
721
- }
722
- rebuild();
723
- tui.requestRender();
724
- };
725
282
  }
726
283
  else if (currentCategory === "ask-user") {
727
284
  items = getAskUserItems(currentSettings);
728
- handleChange = (id, value) => {
729
- if (id === "askUser.enabled") {
730
- writeFlowSetting(cwd, "askUser.enabled", value === "on");
731
- }
732
- else if (id === "askUser.timeout") {
733
- writeFlowSetting(cwd, "askUser.timeout", Number(value));
734
- }
735
- rebuild();
736
- tui.requestRender();
737
- };
738
285
  }
739
286
  else if (currentCategory === "model-config") {
740
287
  items = getModelConfigItems(currentSettings, cwd);
741
- handleChange = (id, value) => {
742
- if (id === "modelConfig.strategy") {
743
- try {
744
- writeGlobalFlowMode(value);
745
- }
746
- catch (e) {
747
- /* ignore */
748
- }
749
- }
750
- else if (id.startsWith("modelConfig.")) {
751
- const match = id.match(/^modelConfig\.(lite|flash|full)\.(primary|failover)$/);
752
- if (match) {
753
- const tier = match[1];
754
- const slot = match[2];
755
- const loaded = loadFlowModelConfigs(cwd);
756
- const strategyName = loaded.selectedName;
757
- if (slot === "primary") {
758
- if (value === "(default)") {
759
- writeFlowModelConfig(cwd, strategyName, tier, { primary: null, failover: null });
760
- }
761
- else {
762
- writeFlowModelConfig(cwd, strategyName, tier, { primary: value });
763
- }
764
- }
765
- else {
766
- if (value === "(default)") {
767
- writeFlowModelConfig(cwd, strategyName, tier, { failover: [] });
768
- }
769
- else {
770
- writeFlowModelConfig(cwd, strategyName, tier, { failover: [value] });
771
- }
772
- }
773
- }
774
- }
775
- rebuild();
776
- tui.requestRender();
777
- };
778
288
  }
779
289
  else if (currentCategory === "loop") {
780
290
  items = getLoopItems(currentSettings, cwd);
781
- handleChange = () => { };
782
291
  }
783
292
  else if (currentCategory === "debug") {
784
293
  items = getDebugItems(currentSettings);
785
- handleChange = (id, value) => {
786
- if (id === "debugMode") {
787
- writeFlowSetting(cwd, "debugMode", value === "on");
788
- }
789
- rebuild();
790
- tui.requestRender();
791
- };
792
294
  }
793
295
  else {
794
296
  items = [];
795
- handleChange = () => { };
796
297
  }
797
298
  const settingsTheme = {
798
299
  label: (text, selected) => selected ? theme.fg("accent", theme.bold(text)) : theme.fg("text", text),
@@ -801,7 +302,7 @@ export function setupSettingsCommand(pi) {
801
302
  cursor: theme.fg("accent", "▶ "),
802
303
  hint: (text) => theme.fg("dim", text),
803
304
  };
804
- const settingsList = new SettingsList(items, Math.min(items.length + 2, 15), settingsTheme, keybindings, handleChange, () => {
305
+ const settingsList = new SettingsList(items, Math.min(items.length + 2, 15), settingsTheme, keybindings, getCategoryHandler(currentCategory, cwd, currentSettings, rebuild, tui, ctx), () => {
805
306
  currentCategory = backCategory;
806
307
  rebuild();
807
308
  tui.requestRender();
@@ -829,210 +330,7 @@ export function setupSettingsCommand(pi) {
829
330
  });
830
331
  return;
831
332
  }
832
- // -----------------------------------------------------------------
833
- // Text-based fallback for subcommands with arguments
834
- // -----------------------------------------------------------------
835
- const parseOnOff = (v) => {
836
- if (v === "on" || v === "true" || v === "1")
837
- return true;
838
- if (v === "off" || v === "false" || v === "0")
839
- return false;
840
- return null;
841
- };
842
- switch (sub) {
843
- case "steering": {
844
- const parsed = parseOnOff(value);
845
- if (parsed === null) {
846
- ctx.ui.notify?.("Usage: /flow:settings steering <on|off>", "error");
847
- return;
848
- }
849
- writeFlowSetting(cwd, "steering.enabled", parsed);
850
- configureSteering({ enabled: parsed, customPrompt: undefined });
851
- ctx.ui.notify?.(`steering.enabled = ${parsed}`, "info");
852
- break;
853
- }
854
- case "strategic-hint": {
855
- const parsed = parseOnOff(value);
856
- if (parsed === null) {
857
- ctx.ui.notify?.("Usage: /flow:settings strategic-hint <on|off>", "error");
858
- return;
859
- }
860
- writeFlowSetting(cwd, "steering.strategicHint", parsed);
861
- configureStrategicHint(parsed);
862
- ctx.ui.notify?.(`steering.strategicHint = ${parsed}`, "info");
863
- break;
864
- }
865
- case "animation": {
866
- const parsed = parseOnOff(value);
867
- if (parsed === null) {
868
- ctx.ui.notify?.("Usage: /flow:settings animation <on|off>", "error");
869
- return;
870
- }
871
- writeFlowSetting(cwd, "animation.enabled", parsed);
872
- scrambleManager.setAnimationConfig({ enabled: parsed, glitch: true });
873
- ctx.ui.notify?.(`animation.enabled = ${parsed}`, "info");
874
- break;
875
- }
876
- case "glitch": {
877
- const parsed = parseOnOff(value);
878
- if (parsed === null) {
879
- ctx.ui.notify?.("Usage: /flow:settings glitch <on|off>", "error");
880
- return;
881
- }
882
- writeFlowSetting(cwd, "animation.glitch", parsed);
883
- scrambleManager.setAnimationConfig({ enabled: true, glitch: parsed });
884
- ctx.ui.notify?.(`animation.glitch = ${parsed}`, "info");
885
- break;
886
- }
887
- case "tool-optimize": {
888
- const parsed = parseOnOff(value);
889
- if (parsed === null) {
890
- ctx.ui.notify?.("Usage: /flow:settings tool-optimize <on|off>", "error");
891
- return;
892
- }
893
- writeFlowSetting(cwd, "toolOptimize", parsed);
894
- ctx.ui.notify?.(`toolOptimize = ${parsed}`, "info");
895
- break;
896
- }
897
- case "structured-output": {
898
- const parsed = parseOnOff(value);
899
- if (parsed === null) {
900
- ctx.ui.notify?.("Usage: /flow:settings structured-output <on|off>", "error");
901
- return;
902
- }
903
- writeFlowSetting(cwd, "structuredOutput", parsed);
904
- ctx.ui.notify?.(`structuredOutput = ${parsed}`, "info");
905
- break;
906
- }
907
- case "trace": {
908
- const parsed = parseOnOff(value);
909
- if (parsed === null) {
910
- ctx.ui.notify?.("Usage: /flow:settings trace <on|off>", "error");
911
- return;
912
- }
913
- writeFlowSetting(cwd, "tools.trace", parsed);
914
- ctx.ui.notify?.(`tools.trace = ${parsed}`, "info");
915
- break;
916
- }
917
- case "batch-read": {
918
- const parsed = parseOnOff(value);
919
- if (parsed === null) {
920
- ctx.ui.notify?.("Usage: /flow:settings batch-read <on|off>", "error");
921
- return;
922
- }
923
- writeFlowSetting(cwd, "tools.batchRead", parsed);
924
- ctx.ui.notify?.(`tools.batchRead = ${parsed}`, "info");
925
- break;
926
- }
927
- case "body": {
928
- if (args[0] === "lite" || args[0] === "full") {
929
- writeFlowSetting(cwd, "bodyVerbosity", args[0]);
930
- ctx.ui.notify?.(`bodyVerbosity = ${args[0]}`, "info");
931
- }
932
- else {
933
- ctx.ui.notify?.("Usage: /flow:settings body <lite|full>", "error");
934
- }
935
- break;
936
- }
937
- case "debug":
938
- case "emit-flow-content": {
939
- const parsed = parseOnOff(value);
940
- if (parsed === null) {
941
- ctx.ui.notify?.("Usage: /flow:settings debug <on|off>", "error");
942
- return;
943
- }
944
- writeFlowSetting(cwd, "debugMode", parsed);
945
- ctx.ui.notify?.(`debugMode = ${parsed}`, "info");
946
- break;
947
- }
948
- case "complexity": {
949
- const validModes = ["snap", "simple", "moderate", "complex", "intricate"];
950
- if (!validModes.includes(value)) {
951
- ctx.ui.notify?.("Usage: /flow:settings complexity <snap|simple|moderate|complex|intricate>", "error");
952
- return;
953
- }
954
- writeFlowSetting(cwd, "complexity", value);
955
- ctx.ui.notify?.(`complexity = ${value}`, "info");
956
- break;
957
- }
958
- case "max-concurrency": {
959
- const n = Number(value);
960
- if (!Number.isSafeInteger(n) || n < 1) {
961
- ctx.ui.notify?.("Usage: /flow:settings max-concurrency <n>", "error");
962
- return;
963
- }
964
- writeFlowSetting(cwd, "maxConcurrency", n);
965
- ctx.ui.notify?.(`maxConcurrency = ${n}`, "info");
966
- break;
967
- }
968
- case "ask-user": {
969
- const askParts = trimmed.split(/\s+/);
970
- const askSub = askParts[1] ?? "";
971
- const askValue = askParts[2] ?? "";
972
- if (askSub === "enabled") {
973
- const parsed = parseOnOff(askValue);
974
- if (parsed === null) {
975
- ctx.ui.notify?.("Usage: /flow:settings ask-user enabled <on|off>", "error");
976
- return;
977
- }
978
- writeFlowSetting(cwd, "askUser.enabled", parsed);
979
- ctx.ui.notify?.(`askUser.enabled = ${parsed}`, "info");
980
- }
981
- else if (askSub === "timeout") {
982
- const n = Number(askValue);
983
- if (!Number.isSafeInteger(n) || n < 10) {
984
- ctx.ui.notify?.("Usage: /flow:settings ask-user timeout <seconds>", "error");
985
- return;
986
- }
987
- writeFlowSetting(cwd, "askUser.timeout", n);
988
- ctx.ui.notify?.(`askUser.timeout = ${n}`, "info");
989
- }
990
- else {
991
- ctx.ui.notify?.("Usage: /flow:settings ask-user {enabled <on|off> | timeout <seconds>}", "error");
992
- }
993
- break;
994
- }
995
- case "reset": {
996
- writeFlowSetting(cwd, "", {});
997
- ctx.ui.notify?.("Flow settings reset to defaults", "info");
998
- break;
999
- }
1000
- case "show": {
1001
- const currentSettings = loadFlowSettings(cwd);
1002
- const loop = getLoop(cwd);
1003
- const lines = [
1004
- `bodyVerbosity: ${currentSettings.bodyVerbosity ?? "lite"}`,
1005
- `toolOptimize: ${currentSettings.toolOptimize ?? true}`,
1006
- `structuredOutput: ${currentSettings.structuredOutput ?? true}`,
1007
- `complexity: ${currentSettings.complexity ?? "moderate"}`,
1008
- `maxConcurrency: ${currentSettings.maxConcurrency ?? 4}`,
1009
- `steering.enabled: ${currentSettings.steering?.enabled ?? true}`,
1010
- `steering.strategicHint: ${currentSettings.steering?.strategicHint ?? true}`,
1011
- `animation.enabled: ${currentSettings.animation?.enabled ?? true}`,
1012
- `animation.glitch: ${currentSettings.animation?.glitch ?? true}`,
1013
- `askUser.enabled: ${currentSettings.askUser?.enabled ?? false}`,
1014
- `askUser.timeout: ${currentSettings.askUser?.timeout ?? 300}`,
1015
- `debugMode: ${currentSettings.debugMode ?? false}`,
1016
- `tools.trace: ${currentSettings.tools?.trace ?? true}`,
1017
- `tools.batchRead: ${currentSettings.tools?.batchRead ?? currentSettings.toolOptimize ?? true}`,
1018
- ];
1019
- if (loop) {
1020
- lines.push("");
1021
- lines.push(`loop.status: ${loop.status}`);
1022
- lines.push(`loop.objective: ${loop.objective}`);
1023
- lines.push(`loop.sessions: ${loop.sessionCount}`);
1024
- lines.push(`loop.flows: ${loop.totalFlowsAcrossSessions}`);
1025
- lines.push(`loop.tokens: ${loop.totalTokensAcrossSessions}`);
1026
- if (loop.terminationReason)
1027
- lines.push(`loop.terminationReason: ${loop.terminationReason}`);
1028
- }
1029
- ctx.ui.notify?.(lines.join("\n"), "info");
1030
- break;
1031
- }
1032
- default: {
1033
- ctx.ui.notify?.("Unknown subcommand. Usage: /flow:settings {steering|strategic-hint|animation|glitch|tool-optimize|structured-output|body|complexity|max-concurrency|ask-user|debug|trace|batch-read|reset|show}", "error");
1034
- }
1035
- }
333
+ await handleTextCommand(args, ctx);
1036
334
  },
1037
335
  });
1038
336
  }