@duckmind/dm-linux-x64 0.61.5 → 0.62.1

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 (285) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +215 -71
  3. package/extensions/dm-cua/bin/browser-cua.mjs +6 -1
  4. package/extensions/dm-cua/index.js +3 -2
  5. package/extensions/dm-cua/src/browser-cua-lib.mjs +69 -13
  6. package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
  7. package/extensions/dm-subagents/agents/claude-code.md +15 -0
  8. package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
  9. package/extensions/dm-subagents/agents/codex-exec.md +15 -0
  10. package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
  11. package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
  12. package/extensions/dm-subagents/agents/delegate.md +3 -2
  13. package/extensions/dm-subagents/agents/oracle.md +10 -5
  14. package/extensions/dm-subagents/agents/researcher.md +2 -2
  15. package/extensions/dm-subagents/agents/reviewer.md +17 -7
  16. package/extensions/dm-subagents/agents/scout.md +5 -5
  17. package/extensions/dm-subagents/agents/worker.md +6 -2
  18. package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
  19. package/extensions/dm-subagents/index.js +4 -0
  20. package/extensions/dm-subagents/inspector-runner.mjs +10 -0
  21. package/extensions/dm-subagents/install.mjs +3 -2
  22. package/extensions/dm-subagents/package.json +2 -2
  23. package/extensions/dm-subagents/prompts/council.md +60 -0
  24. package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
  25. package/extensions/dm-subagents/prompts/review-loop.md +13 -7
  26. package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
  27. package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
  28. package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
  29. package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
  30. package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
  31. package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
  32. package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
  33. package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
  34. package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
  35. package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
  36. package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
  37. package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
  38. package/extensions/dm-subagents/src/agents/agents.js +1447 -299
  39. package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
  40. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
  41. package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
  42. package/extensions/dm-subagents/src/agents/identity.js +1 -1
  43. package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
  44. package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
  45. package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
  46. package/extensions/dm-subagents/src/agents/skills.js +52 -35
  47. package/extensions/dm-subagents/src/api/agents.js +6 -0
  48. package/extensions/dm-subagents/src/api/background-work.js +151 -0
  49. package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
  50. package/extensions/dm-subagents/src/api/control-channel.js +3 -0
  51. package/extensions/dm-subagents/src/api/delegation.js +5 -0
  52. package/extensions/dm-subagents/src/api/dm-args.js +3 -0
  53. package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
  54. package/extensions/dm-subagents/src/api/external-runs.js +233 -0
  55. package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
  56. package/extensions/dm-subagents/src/api/preflight.js +322 -0
  57. package/extensions/dm-subagents/src/api/project-panes.js +11 -0
  58. package/extensions/dm-subagents/src/api/shared-types.js +4 -0
  59. package/extensions/dm-subagents/src/extension/config.js +175 -0
  60. package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
  61. package/extensions/dm-subagents/src/extension/doctor.js +71 -17
  62. package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
  63. package/extensions/dm-subagents/src/extension/index.js +711 -265
  64. package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
  65. package/extensions/dm-subagents/src/extension/rpc.js +427 -22
  66. package/extensions/dm-subagents/src/extension/schemas.js +158 -65
  67. package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
  68. package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
  69. package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
  70. package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
  71. package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
  72. package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
  73. package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
  74. package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
  75. package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
  76. package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
  77. package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
  78. package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
  79. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
  80. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
  81. package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
  82. package/extensions/dm-subagents/src/missions/actions.js +394 -0
  83. package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
  84. package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
  85. package/extensions/dm-subagents/src/missions/store.js +548 -0
  86. package/extensions/dm-subagents/src/missions/types.js +9 -0
  87. package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
  88. package/extensions/dm-subagents/src/policy/authority.js +37 -0
  89. package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
  90. package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
  91. package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
  92. package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
  93. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
  94. package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
  95. package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
  96. package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
  97. package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
  98. package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
  99. package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
  100. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
  101. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
  102. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
  103. package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
  104. package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
  105. package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
  106. package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
  107. package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
  108. package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
  109. package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
  110. package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
  111. package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
  112. package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
  113. package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
  114. package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
  115. package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
  116. package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
  117. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
  118. package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
  119. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
  120. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
  121. package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
  122. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
  123. package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
  124. package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
  125. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
  126. package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
  127. package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
  128. package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
  129. package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
  130. package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
  131. package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
  132. package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
  133. package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
  134. package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
  135. package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
  136. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
  137. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
  138. package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
  139. package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
  140. package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
  141. package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
  142. package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
  143. package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
  144. package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
  145. package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
  146. package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
  147. package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
  148. package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
  149. package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
  150. package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
  151. package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
  152. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
  153. package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
  154. package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
  155. package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
  156. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
  157. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
  158. package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
  159. package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
  160. package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
  161. package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
  162. package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
  163. package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
  164. package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
  165. package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
  166. package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
  167. package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
  168. package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
  169. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
  170. package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
  171. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
  172. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
  173. package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
  174. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
  175. package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
  176. package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
  177. package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
  178. package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
  179. package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
  180. package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
  181. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
  182. package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
  183. package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
  184. package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
  185. package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
  186. package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
  187. package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
  188. package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
  189. package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
  190. package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
  191. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
  192. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
  193. package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
  194. package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
  195. package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
  196. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
  197. package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
  198. package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
  199. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
  200. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
  201. package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
  202. package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
  203. package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
  204. package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
  205. package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
  206. package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
  207. package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
  208. package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
  209. package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
  210. package/extensions/dm-subagents/src/shared/display-text.js +142 -0
  211. package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
  212. package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
  213. package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
  214. package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
  215. package/extensions/dm-subagents/src/shared/formatters.js +21 -7
  216. package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
  217. package/extensions/dm-subagents/src/shared/model-info.js +10 -5
  218. package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
  219. package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
  220. package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
  221. package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
  222. package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
  223. package/extensions/dm-subagents/src/shared/settings.js +39 -47
  224. package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
  225. package/extensions/dm-subagents/src/shared/status-format.js +9 -2
  226. package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
  227. package/extensions/dm-subagents/src/shared/types.js +47 -7
  228. package/extensions/dm-subagents/src/shared/utf8.js +12 -0
  229. package/extensions/dm-subagents/src/shared/utils.js +151 -131
  230. package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
  231. package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
  232. package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
  233. package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
  234. package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
  235. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
  236. package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
  237. package/extensions/dm-subagents/src/slash/selector.js +101 -0
  238. package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
  239. package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
  240. package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
  241. package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
  242. package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
  243. package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
  244. package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
  245. package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
  246. package/extensions/dm-subagents/src/tui/render.js +1511 -261
  247. package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
  248. package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
  249. package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
  250. package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
  251. package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
  252. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
  253. package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
  254. package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
  255. package/extensions/dm-subagents/src/watchdog/render.js +54 -0
  256. package/extensions/dm-subagents/src/watchdog/review.js +251 -0
  257. package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
  258. package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
  259. package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
  260. package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
  261. package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
  262. package/extensions/dm-subagents/src/watchdog/types.js +29 -0
  263. package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
  264. package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
  265. package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
  266. package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
  267. package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
  268. package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
  269. package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
  270. package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
  271. package/extensions/greedysearch-dm/bin/cdp.mjs +28 -3
  272. package/extensions/greedysearch-dm/bin/launch.mjs +2 -3
  273. package/extensions/greedysearch-dm/src/search/constants.mjs +5 -2
  274. package/package.json +4 -3
  275. package/extensions/dm-fff/package.json +0 -21
  276. package/extensions/dm-fff/src/index.js +0 -691
  277. package/extensions/dm-fff/src/query.js +0 -60
  278. package/extensions/dm-subagents/agents/context-builder.md +0 -46
  279. package/extensions/dm-subagents/agents/planner.md +0 -55
  280. package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
  281. package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
  282. package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
  283. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
  284. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
  285. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
@@ -1,1013 +0,0 @@
1
- import { matchesKey, visibleWidth, truncateToWidth } from "@duckmind/dm-tui";
2
- import { resolveModelCandidate, splitThinkingSuffix } from "../shared/model-fallback.js";
3
- import { findModelInfo, getSupportedThinkingLevels } from "../../shared/model-info.js";
4
- function createEditorState(initial = "") {
5
- return { buffer: initial, cursor: 0, viewportOffset: 0 };
6
- }
7
- function wrapText(text, width) {
8
- if (width <= 0)
9
- return { lines: [text], starts: [0] };
10
- if (text.length === 0)
11
- return { lines: [""], starts: [0] };
12
- const lines = [];
13
- const starts = [];
14
- let offset = 0;
15
- const segments = text.split(`
16
- `);
17
- for (const [index, segment] of segments.entries()) {
18
- if (segment.length === 0) {
19
- starts.push(offset);
20
- lines.push("");
21
- } else {
22
- let lineStart = 0;
23
- let pos = 0;
24
- let lineWidth = 0;
25
- while (pos < segment.length) {
26
- const char = String.fromCodePoint(segment.codePointAt(pos));
27
- const charWidth = visibleWidth(char);
28
- if (lineWidth > 0 && lineWidth + charWidth > width) {
29
- starts.push(offset + lineStart);
30
- lines.push(segment.slice(lineStart, pos));
31
- lineStart = pos;
32
- lineWidth = 0;
33
- continue;
34
- }
35
- pos += char.length;
36
- lineWidth += charWidth;
37
- }
38
- starts.push(offset + lineStart);
39
- lines.push(segment.slice(lineStart));
40
- }
41
- offset += segment.length + (index < segments.length - 1 ? 1 : 0);
42
- }
43
- if (!text.endsWith(`
44
- `) && text.length > 0 && visibleWidth(lines[lines.length - 1] ?? "") === width) {
45
- starts.push(text.length);
46
- lines.push("");
47
- }
48
- return { lines, starts };
49
- }
50
- function getCursorDisplayPos(cursor, starts) {
51
- for (let i = starts.length - 1;i >= 0; i--) {
52
- if (cursor >= starts[i])
53
- return { line: i, col: cursor - starts[i] };
54
- }
55
- return { line: 0, col: 0 };
56
- }
57
- function ensureCursorVisible(cursorLine, viewportHeight, currentOffset) {
58
- if (cursorLine < currentOffset)
59
- return Math.max(0, cursorLine);
60
- if (cursorLine >= currentOffset + viewportHeight)
61
- return Math.max(0, cursorLine - viewportHeight + 1);
62
- return Math.max(0, currentOffset);
63
- }
64
- function isWordChar(ch) {
65
- const code = ch.charCodeAt(0);
66
- return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || code === 95;
67
- }
68
- function wordBackward(buffer, cursor) {
69
- let pos = cursor;
70
- while (pos > 0 && !isWordChar(buffer[pos - 1]))
71
- pos--;
72
- while (pos > 0 && isWordChar(buffer[pos - 1]))
73
- pos--;
74
- return pos;
75
- }
76
- function wordForward(buffer, cursor) {
77
- let pos = cursor;
78
- while (pos < buffer.length && isWordChar(buffer[pos]))
79
- pos++;
80
- while (pos < buffer.length && !isWordChar(buffer[pos]))
81
- pos++;
82
- return pos;
83
- }
84
- function normalizeInsertText(data) {
85
- let text = data.split("\x1B[200~").join("").split("\x1B[201~").join("");
86
- text = text.replace(/\r\n/g, `
87
- `).replace(/\r/g, `
88
- `);
89
- const newline = text.indexOf(`
90
- `);
91
- if (newline !== -1)
92
- text = text.slice(0, newline);
93
- text = text.replace(/\t/g, " ");
94
- if (text.length === 0)
95
- return null;
96
- for (let i = 0;i < text.length; i++) {
97
- if (text.charCodeAt(i) < 32)
98
- return null;
99
- }
100
- return text;
101
- }
102
- function handleEditorInput(state, data, textWidth) {
103
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c") || matchesKey(data, "return"))
104
- return null;
105
- const { lines: wrapped, starts } = wrapText(state.buffer, textWidth);
106
- const cursorPos = getCursorDisplayPos(state.cursor, starts);
107
- if (matchesKey(data, "alt+left") || matchesKey(data, "ctrl+left"))
108
- return { ...state, cursor: wordBackward(state.buffer, state.cursor) };
109
- if (matchesKey(data, "alt+right") || matchesKey(data, "ctrl+right"))
110
- return { ...state, cursor: wordForward(state.buffer, state.cursor) };
111
- if (matchesKey(data, "left"))
112
- return state.cursor > 0 ? { ...state, cursor: state.cursor - 1 } : state;
113
- if (matchesKey(data, "right"))
114
- return state.cursor < state.buffer.length ? { ...state, cursor: state.cursor + 1 } : state;
115
- if (matchesKey(data, "up") && cursorPos.line > 0) {
116
- const targetLine = cursorPos.line - 1;
117
- return { ...state, cursor: starts[targetLine] + Math.min(cursorPos.col, wrapped[targetLine]?.length ?? 0) };
118
- }
119
- if (matchesKey(data, "down") && cursorPos.line < wrapped.length - 1) {
120
- const targetLine = cursorPos.line + 1;
121
- return { ...state, cursor: starts[targetLine] + Math.min(cursorPos.col, wrapped[targetLine]?.length ?? 0) };
122
- }
123
- if (matchesKey(data, "home"))
124
- return { ...state, cursor: starts[cursorPos.line] };
125
- if (matchesKey(data, "end"))
126
- return { ...state, cursor: starts[cursorPos.line] + (wrapped[cursorPos.line]?.length ?? 0) };
127
- if (matchesKey(data, "ctrl+home"))
128
- return { ...state, cursor: 0 };
129
- if (matchesKey(data, "ctrl+end"))
130
- return { ...state, cursor: state.buffer.length };
131
- if (matchesKey(data, "alt+backspace")) {
132
- const target = wordBackward(state.buffer, state.cursor);
133
- return target === state.cursor ? state : { ...state, buffer: state.buffer.slice(0, target) + state.buffer.slice(state.cursor), cursor: target };
134
- }
135
- if (matchesKey(data, "backspace")) {
136
- return state.cursor > 0 ? { ...state, buffer: state.buffer.slice(0, state.cursor - 1) + state.buffer.slice(state.cursor), cursor: state.cursor - 1 } : state;
137
- }
138
- if (matchesKey(data, "delete")) {
139
- return state.cursor < state.buffer.length ? { ...state, buffer: state.buffer.slice(0, state.cursor) + state.buffer.slice(state.cursor + 1) } : state;
140
- }
141
- const insert = normalizeInsertText(data);
142
- return insert ? { ...state, buffer: state.buffer.slice(0, state.cursor) + insert + state.buffer.slice(state.cursor), cursor: state.cursor + insert.length } : null;
143
- }
144
- function renderWithCursor(text, cursorPos) {
145
- const before = text.slice(0, cursorPos);
146
- const cursorChar = text[cursorPos] ?? " ";
147
- const after = text.slice(cursorPos + 1);
148
- return `${before}\x1B[7m${cursorChar}\x1B[27m${after}`;
149
- }
150
- function renderEditor(state, width, viewportHeight) {
151
- const { lines: wrapped, starts } = wrapText(state.buffer, width);
152
- const cursorPos = getCursorDisplayPos(state.cursor, starts);
153
- const lines = [];
154
- for (let i = 0;i < viewportHeight; i++) {
155
- const lineIdx = state.viewportOffset + i;
156
- let content = lineIdx < wrapped.length ? wrapped[lineIdx] ?? "" : "";
157
- if (lineIdx === cursorPos.line)
158
- content = renderWithCursor(content, cursorPos.col);
159
- lines.push(content);
160
- }
161
- return lines;
162
- }
163
-
164
- export class ChainClarifyComponent {
165
- width = 84;
166
- selectedStep = 0;
167
- editingStep = null;
168
- editMode = "template";
169
- editState = createEditorState();
170
- EDIT_VIEWPORT_HEIGHT = 12;
171
- behaviorOverrides = new Map;
172
- modelSearchQuery = "";
173
- modelSelectedIndex = 0;
174
- filteredModels = [];
175
- MODEL_SELECTOR_HEIGHT = 10;
176
- thinkingSelectedIndex = 0;
177
- skillSearchQuery = "";
178
- skillSelectedNames = new Set;
179
- skillCursorIndex = 0;
180
- filteredSkills = [];
181
- noticeMessage = null;
182
- noticeMessageTimer = null;
183
- runInBackground = false;
184
- tui;
185
- theme;
186
- agentConfigs;
187
- templates;
188
- originalTask;
189
- chainDir;
190
- resolvedBehaviors;
191
- availableModels;
192
- preferredProvider;
193
- availableSkills;
194
- done;
195
- mode;
196
- constructor(tui, theme, agentConfigs, templates, originalTask, chainDir, resolvedBehaviors, availableModels, preferredProvider, availableSkills, done, mode = "chain") {
197
- this.tui = tui;
198
- this.theme = theme;
199
- this.agentConfigs = agentConfigs;
200
- this.templates = templates;
201
- this.originalTask = originalTask;
202
- this.chainDir = chainDir;
203
- this.resolvedBehaviors = resolvedBehaviors;
204
- this.availableModels = availableModels;
205
- this.preferredProvider = preferredProvider;
206
- this.availableSkills = availableSkills;
207
- this.done = done;
208
- this.mode = mode;
209
- this.filteredModels = [...availableModels];
210
- this.filteredSkills = [...availableSkills];
211
- }
212
- pad(s, len) {
213
- const vis = visibleWidth(s);
214
- return s + " ".repeat(Math.max(0, len - vis));
215
- }
216
- row(content) {
217
- const innerW = this.width - 2;
218
- return this.theme.fg("border", "│") + this.pad(content, innerW) + this.theme.fg("border", "│");
219
- }
220
- renderHeader(text) {
221
- const innerW = this.width - 2;
222
- const padLen = Math.max(0, innerW - visibleWidth(text));
223
- const padLeft = Math.floor(padLen / 2);
224
- const padRight = padLen - padLeft;
225
- return this.theme.fg("border", "╭" + "─".repeat(padLeft)) + this.theme.fg("accent", text) + this.theme.fg("border", "─".repeat(padRight) + "╮");
226
- }
227
- renderFooter(text) {
228
- const innerW = this.width - 2;
229
- const padLen = Math.max(0, innerW - visibleWidth(text));
230
- const padLeft = Math.floor(padLen / 2);
231
- const padRight = padLen - padLeft;
232
- return this.theme.fg("border", "╰" + "─".repeat(padLeft)) + this.theme.fg("dim", text) + this.theme.fg("border", "─".repeat(padRight) + "╯");
233
- }
234
- exitEditMode() {
235
- this.editingStep = null;
236
- this.editState = createEditorState();
237
- this.tui.requestRender();
238
- }
239
- renderFullEditMode() {
240
- const innerW = this.width - 2;
241
- const textWidth = innerW - 2;
242
- const lines = [];
243
- const { lines: wrapped, starts } = wrapText(this.editState.buffer, textWidth);
244
- const cursorPos = getCursorDisplayPos(this.editState.cursor, starts);
245
- this.editState = {
246
- ...this.editState,
247
- viewportOffset: ensureCursorVisible(cursorPos.line, this.EDIT_VIEWPORT_HEIGHT, this.editState.viewportOffset)
248
- };
249
- const fieldName = this.editMode === "template" ? "task" : this.editMode;
250
- const rawAgentName = this.agentConfigs[this.editingStep]?.name ?? "unknown";
251
- const maxAgentLen = innerW - 30;
252
- const agentName = rawAgentName.length > maxAgentLen ? rawAgentName.slice(0, maxAgentLen - 1) + "…" : rawAgentName;
253
- const stepLabel = this.mode === "single" ? agentName : this.mode === "parallel" ? `Task ${this.editingStep + 1}: ${agentName}` : `Step ${this.editingStep + 1}: ${agentName}`;
254
- const headerText = ` Editing ${fieldName} (${stepLabel}) `;
255
- lines.push(this.renderHeader(headerText));
256
- lines.push(this.row(""));
257
- const editorLines = renderEditor(this.editState, textWidth, this.EDIT_VIEWPORT_HEIGHT);
258
- for (const line of editorLines) {
259
- lines.push(this.row(` ${line}`));
260
- }
261
- const linesBelow = wrapped.length - this.editState.viewportOffset - this.EDIT_VIEWPORT_HEIGHT;
262
- const hasMore = linesBelow > 0;
263
- const hasLess = this.editState.viewportOffset > 0;
264
- let scrollInfo = "";
265
- if (hasLess)
266
- scrollInfo += "↑";
267
- if (hasMore)
268
- scrollInfo += `↓ ${linesBelow}+`;
269
- lines.push(this.row(""));
270
- const footerText = scrollInfo ? ` [Esc] Done • [Ctrl+C] Discard • ${scrollInfo} ` : " [Esc] Done • [Ctrl+C] Discard ";
271
- lines.push(this.renderFooter(footerText));
272
- return lines;
273
- }
274
- getEffectiveBehavior(stepIndex) {
275
- const base = this.resolvedBehaviors[stepIndex];
276
- const override = this.behaviorOverrides.get(stepIndex);
277
- if (!override)
278
- return base;
279
- return {
280
- output: override.output !== undefined ? override.output : base.output,
281
- outputMode: base.outputMode,
282
- reads: override.reads !== undefined ? override.reads : base.reads,
283
- progress: override.progress !== undefined ? override.progress : base.progress,
284
- skills: override.skills !== undefined ? override.skills : base.skills,
285
- model: override.model !== undefined ? override.model : base.model
286
- };
287
- }
288
- getEffectiveModel(stepIndex) {
289
- const override = this.behaviorOverrides.get(stepIndex);
290
- if (override?.model)
291
- return this.resolveModelFullId(override.model);
292
- const baseModel = this.resolvedBehaviors[stepIndex]?.model;
293
- if (baseModel)
294
- return this.resolveModelFullId(baseModel);
295
- return "default";
296
- }
297
- resolveModelFullId(modelName) {
298
- return resolveModelCandidate(modelName, this.availableModels, this.preferredProvider) ?? modelName;
299
- }
300
- updateBehavior(stepIndex, field, value) {
301
- const existing = this.behaviorOverrides.get(stepIndex) ?? {};
302
- this.behaviorOverrides.set(stepIndex, { ...existing, [field]: value });
303
- }
304
- showNotice(text, type) {
305
- this.noticeMessage = { text, type };
306
- if (this.noticeMessageTimer)
307
- clearTimeout(this.noticeMessageTimer);
308
- this.noticeMessageTimer = setTimeout(() => {
309
- this.noticeMessage = null;
310
- this.noticeMessageTimer = null;
311
- this.tui.requestRender();
312
- }, 2000);
313
- this.tui.requestRender();
314
- }
315
- handleInput(data) {
316
- if (this.editingStep !== null) {
317
- if (this.editMode === "model") {
318
- this.handleModelSelectorInput(data);
319
- } else if (this.editMode === "thinking") {
320
- this.handleThinkingSelectorInput(data);
321
- } else if (this.editMode === "skills") {
322
- this.handleSkillSelectorInput(data);
323
- } else {
324
- this.handleEditInput(data);
325
- }
326
- return;
327
- }
328
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
329
- this.done({ confirmed: false, templates: [], behaviorOverrides: [] });
330
- return;
331
- }
332
- if (matchesKey(data, "return")) {
333
- const overrides = [];
334
- for (let i = 0;i < this.agentConfigs.length; i++) {
335
- overrides.push(this.behaviorOverrides.get(i));
336
- }
337
- this.done({ confirmed: true, templates: this.templates, behaviorOverrides: overrides, runInBackground: this.runInBackground });
338
- return;
339
- }
340
- if (matchesKey(data, "up")) {
341
- this.selectedStep = Math.max(0, this.selectedStep - 1);
342
- this.tui.requestRender();
343
- return;
344
- }
345
- if (matchesKey(data, "down")) {
346
- const maxStep = Math.max(0, this.agentConfigs.length - 1);
347
- this.selectedStep = Math.min(maxStep, this.selectedStep + 1);
348
- this.tui.requestRender();
349
- return;
350
- }
351
- if (data === "e") {
352
- this.enterEditMode("template");
353
- return;
354
- }
355
- if (data === "m") {
356
- this.enterModelSelector();
357
- return;
358
- }
359
- if (data === "t") {
360
- this.enterThinkingSelector();
361
- return;
362
- }
363
- if (data === "s") {
364
- this.editingStep = this.selectedStep;
365
- this.editMode = "skills";
366
- this.skillSearchQuery = "";
367
- this.skillCursorIndex = 0;
368
- this.filteredSkills = [...this.availableSkills];
369
- const current = this.getEffectiveBehavior(this.selectedStep).skills;
370
- this.skillSelectedNames.clear();
371
- if (current !== false && current.length > 0) {
372
- current.forEach((skillName) => this.skillSelectedNames.add(skillName));
373
- }
374
- this.tui.requestRender();
375
- return;
376
- }
377
- if (data === "w" && this.mode !== "parallel") {
378
- this.enterEditMode("output");
379
- return;
380
- }
381
- if (data === "r" && this.mode === "chain") {
382
- this.enterEditMode("reads");
383
- return;
384
- }
385
- if (data === "p" && this.mode === "chain") {
386
- const anyEnabled = this.agentConfigs.some((_, i) => this.getEffectiveBehavior(i).progress);
387
- const newState = !anyEnabled;
388
- for (let i = 0;i < this.agentConfigs.length; i++) {
389
- this.updateBehavior(i, "progress", newState);
390
- }
391
- this.tui.requestRender();
392
- return;
393
- }
394
- if (data === "b") {
395
- this.runInBackground = !this.runInBackground;
396
- this.tui.requestRender();
397
- return;
398
- }
399
- }
400
- enterEditMode(mode) {
401
- this.editingStep = this.selectedStep;
402
- this.editMode = mode;
403
- let buffer = "";
404
- if (mode === "template") {
405
- const template = this.templates[this.selectedStep] ?? "";
406
- buffer = template.split(`
407
- `)[0] ?? "";
408
- } else if (mode === "output") {
409
- const behavior = this.getEffectiveBehavior(this.selectedStep);
410
- buffer = behavior.output === false ? "" : behavior.output || "";
411
- } else if (mode === "reads") {
412
- const behavior = this.getEffectiveBehavior(this.selectedStep);
413
- buffer = behavior.reads === false ? "" : behavior.reads?.join(", ") || "";
414
- }
415
- this.editState = createEditorState(buffer);
416
- this.tui.requestRender();
417
- }
418
- enterModelSelector() {
419
- this.editingStep = this.selectedStep;
420
- this.editMode = "model";
421
- this.modelSearchQuery = "";
422
- this.modelSelectedIndex = 0;
423
- this.filteredModels = [...this.availableModels];
424
- const currentModel = splitThinkingSuffix(this.getEffectiveModel(this.selectedStep)).baseModel;
425
- const currentIndex = this.filteredModels.findIndex((m) => m.fullId === currentModel || m.id === currentModel);
426
- if (currentIndex >= 0) {
427
- this.modelSelectedIndex = currentIndex;
428
- }
429
- this.tui.requestRender();
430
- }
431
- filterModels() {
432
- const query = this.modelSearchQuery.toLowerCase();
433
- if (!query) {
434
- this.filteredModels = [...this.availableModels];
435
- } else {
436
- this.filteredModels = this.availableModels.filter((m) => m.fullId.toLowerCase().includes(query) || m.id.toLowerCase().includes(query) || m.provider.toLowerCase().includes(query));
437
- }
438
- this.modelSelectedIndex = Math.min(this.modelSelectedIndex, Math.max(0, this.filteredModels.length - 1));
439
- }
440
- handleModelSelectorInput(data) {
441
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
442
- this.exitEditMode();
443
- return;
444
- }
445
- if (matchesKey(data, "return")) {
446
- const selected = this.filteredModels[this.modelSelectedIndex];
447
- if (selected) {
448
- const { thinkingSuffix } = splitThinkingSuffix(this.getEffectiveModel(this.editingStep));
449
- const requestedLevel = thinkingSuffix.slice(1);
450
- const selectedModel = findModelInfo(selected.fullId, this.availableModels, this.preferredProvider);
451
- const suffix = getSupportedThinkingLevels(selectedModel).some((level) => level === requestedLevel) ? thinkingSuffix : "";
452
- this.updateBehavior(this.editingStep, "model", `${selected.fullId}${suffix}`);
453
- }
454
- this.exitEditMode();
455
- return;
456
- }
457
- if (matchesKey(data, "up")) {
458
- if (this.filteredModels.length > 0) {
459
- this.modelSelectedIndex = this.modelSelectedIndex === 0 ? this.filteredModels.length - 1 : this.modelSelectedIndex - 1;
460
- }
461
- this.tui.requestRender();
462
- return;
463
- }
464
- if (matchesKey(data, "down")) {
465
- if (this.filteredModels.length > 0) {
466
- this.modelSelectedIndex = this.modelSelectedIndex === this.filteredModels.length - 1 ? 0 : this.modelSelectedIndex + 1;
467
- }
468
- this.tui.requestRender();
469
- return;
470
- }
471
- if (matchesKey(data, "backspace")) {
472
- if (this.modelSearchQuery.length > 0) {
473
- this.modelSearchQuery = this.modelSearchQuery.slice(0, -1);
474
- this.filterModels();
475
- }
476
- this.tui.requestRender();
477
- return;
478
- }
479
- if (data.length === 1 && data.charCodeAt(0) >= 32) {
480
- this.modelSearchQuery += data;
481
- this.filterModels();
482
- this.tui.requestRender();
483
- return;
484
- }
485
- }
486
- getAvailableThinkingLevels(stepIndex) {
487
- return getSupportedThinkingLevels(findModelInfo(this.getEffectiveModel(stepIndex), this.availableModels, this.preferredProvider));
488
- }
489
- enterThinkingSelector() {
490
- if (!this.getEffectiveBehavior(this.selectedStep).model) {
491
- this.showNotice("Select a model first", "error");
492
- return;
493
- }
494
- this.editingStep = this.selectedStep;
495
- this.editMode = "thinking";
496
- const levels = this.getAvailableThinkingLevels(this.selectedStep);
497
- const { thinkingSuffix } = splitThinkingSuffix(this.getEffectiveModel(this.selectedStep));
498
- const suffix = thinkingSuffix.slice(1);
499
- const levelIdx = levels.findIndex((level) => level === suffix);
500
- this.thinkingSelectedIndex = levelIdx >= 0 ? levelIdx : Math.max(0, levels.indexOf("off"));
501
- this.tui.requestRender();
502
- }
503
- handleThinkingSelectorInput(data) {
504
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
505
- this.exitEditMode();
506
- return;
507
- }
508
- const levels = this.getAvailableThinkingLevels(this.editingStep);
509
- if (levels.length === 0)
510
- return;
511
- if (matchesKey(data, "return")) {
512
- const selectedLevel = levels[this.thinkingSelectedIndex] ?? "off";
513
- this.applyThinkingLevel(selectedLevel);
514
- this.exitEditMode();
515
- return;
516
- }
517
- if (matchesKey(data, "up")) {
518
- this.thinkingSelectedIndex = this.thinkingSelectedIndex === 0 ? levels.length - 1 : this.thinkingSelectedIndex - 1;
519
- this.tui.requestRender();
520
- return;
521
- }
522
- if (matchesKey(data, "down")) {
523
- this.thinkingSelectedIndex = this.thinkingSelectedIndex === levels.length - 1 ? 0 : this.thinkingSelectedIndex + 1;
524
- this.tui.requestRender();
525
- return;
526
- }
527
- }
528
- applyThinkingLevel(level) {
529
- const stepIndex = this.editingStep;
530
- const currentModel = this.getEffectiveBehavior(stepIndex).model;
531
- if (!currentModel)
532
- return;
533
- const { baseModel } = splitThinkingSuffix(currentModel);
534
- const newModel = level === "off" ? baseModel : `${baseModel}:${level}`;
535
- this.updateBehavior(stepIndex, "model", newModel);
536
- }
537
- filterSkills() {
538
- const query = this.skillSearchQuery.toLowerCase();
539
- if (!query) {
540
- this.filteredSkills = [...this.availableSkills];
541
- } else {
542
- this.filteredSkills = this.availableSkills.filter((s) => s.name.toLowerCase().includes(query) || (s.description?.toLowerCase().includes(query) ?? false));
543
- }
544
- this.skillCursorIndex = Math.min(this.skillCursorIndex, Math.max(0, this.filteredSkills.length - 1));
545
- }
546
- handleSkillSelectorInput(data) {
547
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
548
- this.exitEditMode();
549
- return;
550
- }
551
- if (matchesKey(data, "return")) {
552
- const selected = [...this.skillSelectedNames];
553
- this.updateBehavior(this.editingStep, "skills", selected);
554
- this.exitEditMode();
555
- return;
556
- }
557
- if (data === " ") {
558
- if (this.filteredSkills.length > 0) {
559
- const skill = this.filteredSkills[this.skillCursorIndex];
560
- if (skill) {
561
- if (this.skillSelectedNames.has(skill.name)) {
562
- this.skillSelectedNames.delete(skill.name);
563
- } else {
564
- this.skillSelectedNames.add(skill.name);
565
- }
566
- }
567
- }
568
- this.tui.requestRender();
569
- return;
570
- }
571
- if (matchesKey(data, "up")) {
572
- if (this.filteredSkills.length > 0) {
573
- this.skillCursorIndex = this.skillCursorIndex === 0 ? this.filteredSkills.length - 1 : this.skillCursorIndex - 1;
574
- }
575
- this.tui.requestRender();
576
- return;
577
- }
578
- if (matchesKey(data, "down")) {
579
- if (this.filteredSkills.length > 0) {
580
- this.skillCursorIndex = this.skillCursorIndex === this.filteredSkills.length - 1 ? 0 : this.skillCursorIndex + 1;
581
- }
582
- this.tui.requestRender();
583
- return;
584
- }
585
- if (matchesKey(data, "backspace")) {
586
- if (this.skillSearchQuery.length > 0) {
587
- this.skillSearchQuery = this.skillSearchQuery.slice(0, -1);
588
- this.filterSkills();
589
- }
590
- this.tui.requestRender();
591
- return;
592
- }
593
- if (data.length === 1 && data.charCodeAt(0) >= 32) {
594
- this.skillSearchQuery += data;
595
- this.filterSkills();
596
- this.tui.requestRender();
597
- return;
598
- }
599
- }
600
- handleEditInput(data) {
601
- const textWidth = this.width - 4;
602
- if (matchesKey(data, "shift+up") || matchesKey(data, "pageup")) {
603
- const { lines: wrapped, starts } = wrapText(this.editState.buffer, textWidth);
604
- const cursorPos = getCursorDisplayPos(this.editState.cursor, starts);
605
- const targetLine = Math.max(0, cursorPos.line - this.EDIT_VIEWPORT_HEIGHT);
606
- const targetCol = Math.min(cursorPos.col, wrapped[targetLine]?.length ?? 0);
607
- this.editState = { ...this.editState, cursor: starts[targetLine] + targetCol };
608
- this.tui.requestRender();
609
- return;
610
- }
611
- if (matchesKey(data, "shift+down") || matchesKey(data, "pagedown")) {
612
- const { lines: wrapped, starts } = wrapText(this.editState.buffer, textWidth);
613
- const cursorPos = getCursorDisplayPos(this.editState.cursor, starts);
614
- const targetLine = Math.min(wrapped.length - 1, cursorPos.line + this.EDIT_VIEWPORT_HEIGHT);
615
- const targetCol = Math.min(cursorPos.col, wrapped[targetLine]?.length ?? 0);
616
- this.editState = { ...this.editState, cursor: starts[targetLine] + targetCol };
617
- this.tui.requestRender();
618
- return;
619
- }
620
- if (matchesKey(data, "tab"))
621
- return;
622
- const nextState = handleEditorInput(this.editState, data, textWidth);
623
- if (nextState) {
624
- this.editState = nextState;
625
- this.tui.requestRender();
626
- return;
627
- }
628
- if (matchesKey(data, "escape")) {
629
- this.saveEdit();
630
- this.exitEditMode();
631
- return;
632
- }
633
- if (matchesKey(data, "ctrl+c")) {
634
- this.exitEditMode();
635
- return;
636
- }
637
- }
638
- saveEdit() {
639
- const stepIndex = this.editingStep;
640
- if (this.editMode === "template") {
641
- const original = this.templates[stepIndex] ?? "";
642
- const originalLines = original.split(`
643
- `);
644
- originalLines[0] = this.editState.buffer;
645
- this.templates[stepIndex] = originalLines.join(`
646
- `);
647
- } else if (this.editMode === "output") {
648
- const oldBehavior = this.getEffectiveBehavior(stepIndex);
649
- const oldOutput = typeof oldBehavior.output === "string" ? oldBehavior.output : null;
650
- const trimmed = this.editState.buffer.trim();
651
- const newOutput = trimmed === "" ? false : trimmed;
652
- this.updateBehavior(stepIndex, "output", newOutput);
653
- if (oldOutput && typeof newOutput === "string" && oldOutput !== newOutput) {
654
- this.propagateOutputChange(stepIndex, oldOutput, newOutput);
655
- }
656
- } else if (this.editMode === "reads") {
657
- const trimmed = this.editState.buffer.trim();
658
- if (trimmed === "") {
659
- this.updateBehavior(stepIndex, "reads", false);
660
- } else {
661
- const files = trimmed.split(",").map((f) => f.trim()).filter((f) => f !== "");
662
- this.updateBehavior(stepIndex, "reads", files.length > 0 ? files : false);
663
- }
664
- }
665
- }
666
- propagateOutputChange(changedStepIndex, oldOutput, newOutput) {
667
- for (let i = changedStepIndex + 1;i < this.agentConfigs.length; i++) {
668
- const behavior = this.getEffectiveBehavior(i);
669
- if (behavior.reads === false || !behavior.reads || behavior.reads.length === 0) {
670
- continue;
671
- }
672
- const readsArray = behavior.reads;
673
- const oldIndex = readsArray.indexOf(oldOutput);
674
- if (oldIndex !== -1) {
675
- const newReads = [...readsArray];
676
- newReads[oldIndex] = newOutput;
677
- this.updateBehavior(i, "reads", newReads);
678
- }
679
- }
680
- }
681
- render(_width) {
682
- if (this.editingStep !== null) {
683
- if (this.editMode === "model") {
684
- return this.renderModelSelector();
685
- }
686
- if (this.editMode === "thinking") {
687
- return this.renderThinkingSelector();
688
- }
689
- if (this.editMode === "skills") {
690
- return this.renderSkillSelector();
691
- }
692
- return this.renderFullEditMode();
693
- }
694
- switch (this.mode) {
695
- case "single":
696
- return this.renderSingleMode();
697
- case "parallel":
698
- return this.renderParallelMode();
699
- case "chain":
700
- return this.renderChainMode();
701
- }
702
- }
703
- renderModelSelector() {
704
- const th = this.theme;
705
- const lines = [];
706
- const agentName = this.agentConfigs[this.editingStep]?.name ?? "unknown";
707
- const stepLabel = this.mode === "single" ? agentName : this.mode === "parallel" ? `Task ${this.editingStep + 1}: ${agentName}` : `Step ${this.editingStep + 1}: ${agentName}`;
708
- const headerText = ` Select Model (${stepLabel}) `;
709
- lines.push(this.renderHeader(headerText));
710
- lines.push(this.row(""));
711
- const searchPrefix = th.fg("dim", "Search: ");
712
- const cursor = "\x1B[7m \x1B[27m";
713
- const searchDisplay = this.modelSearchQuery + cursor;
714
- lines.push(this.row(` ${searchPrefix}${searchDisplay}`));
715
- lines.push(this.row(""));
716
- const currentModel = this.getEffectiveModel(this.editingStep);
717
- const currentModelBase = splitThinkingSuffix(currentModel).baseModel;
718
- const currentLabel = th.fg("dim", "Current: ");
719
- lines.push(this.row(` ${currentLabel}${th.fg("warning", currentModel)}`));
720
- lines.push(this.row(""));
721
- if (this.filteredModels.length === 0) {
722
- lines.push(this.row(` ${th.fg("dim", "No matching models")}`));
723
- } else {
724
- const maxVisible = this.MODEL_SELECTOR_HEIGHT;
725
- let startIdx = 0;
726
- if (this.filteredModels.length > maxVisible) {
727
- startIdx = Math.max(0, this.modelSelectedIndex - Math.floor(maxVisible / 2));
728
- startIdx = Math.min(startIdx, this.filteredModels.length - maxVisible);
729
- }
730
- const endIdx = Math.min(startIdx + maxVisible, this.filteredModels.length);
731
- if (startIdx > 0) {
732
- lines.push(this.row(` ${th.fg("dim", ` ↑ ${startIdx} more`)}`));
733
- }
734
- for (let i = startIdx;i < endIdx; i++) {
735
- const model = this.filteredModels[i];
736
- const isSelected = i === this.modelSelectedIndex;
737
- const isCurrent = model.fullId === currentModelBase || model.id === currentModelBase;
738
- const prefix = isSelected ? th.fg("accent", "→ ") : " ";
739
- const modelText = isSelected ? th.fg("accent", model.id) : model.id;
740
- const providerBadge = th.fg("dim", ` [${model.provider}]`);
741
- const currentBadge = isCurrent ? th.fg("success", " current") : "";
742
- lines.push(this.row(` ${prefix}${modelText}${providerBadge}${currentBadge}`));
743
- }
744
- const remaining = this.filteredModels.length - endIdx;
745
- if (remaining > 0) {
746
- lines.push(this.row(` ${th.fg("dim", ` ↓ ${remaining} more`)}`));
747
- }
748
- }
749
- const contentLines = lines.length;
750
- const targetHeight = 18;
751
- for (let i = contentLines;i < targetHeight; i++) {
752
- lines.push(this.row(""));
753
- }
754
- const footerText = " [Enter] Select • [Esc] Cancel • Type to search ";
755
- lines.push(this.renderFooter(footerText));
756
- return lines;
757
- }
758
- renderThinkingSelector() {
759
- const th = this.theme;
760
- const lines = [];
761
- const agentName = this.agentConfigs[this.editingStep]?.name ?? "unknown";
762
- const stepLabel = this.mode === "single" ? agentName : this.mode === "parallel" ? `Task ${this.editingStep + 1}: ${agentName}` : `Step ${this.editingStep + 1}: ${agentName}`;
763
- const headerText = ` Thinking Level (${stepLabel}) `;
764
- lines.push(this.renderHeader(headerText));
765
- lines.push(this.row(""));
766
- const currentModel = this.getEffectiveModel(this.editingStep);
767
- const currentLabel = th.fg("dim", "Model: ");
768
- lines.push(this.row(` ${currentLabel}${th.fg("accent", currentModel)}`));
769
- lines.push(this.row(""));
770
- lines.push(this.row(` ${th.fg("dim", "Select thinking level (extended thinking budget):")}`));
771
- lines.push(this.row(""));
772
- const levelDescriptions = {
773
- off: "No extended thinking",
774
- minimal: "Brief reasoning",
775
- low: "Light reasoning",
776
- medium: "Moderate reasoning",
777
- high: "Deep reasoning",
778
- xhigh: "Maximum reasoning (ultrathink)"
779
- };
780
- const levels = this.getAvailableThinkingLevels(this.editingStep);
781
- if (levels.length === 0) {
782
- lines.push(this.row(` ${th.fg("dim", "No supported thinking levels")}`));
783
- } else {
784
- for (let i = 0;i < levels.length; i++) {
785
- const level = levels[i];
786
- const isSelected = i === this.thinkingSelectedIndex;
787
- const prefix = isSelected ? th.fg("accent", "→ ") : " ";
788
- const levelText = isSelected ? th.fg("accent", level) : level;
789
- const desc = th.fg("dim", ` - ${levelDescriptions[level]}`);
790
- lines.push(this.row(` ${prefix}${levelText}${desc}`));
791
- }
792
- }
793
- const contentLines = lines.length;
794
- const targetHeight = 16;
795
- for (let i = contentLines;i < targetHeight; i++) {
796
- lines.push(this.row(""));
797
- }
798
- const footerText = levels.length === 0 ? " [Esc] Cancel " : " [Enter] Select • [Esc] Cancel • ↑↓ Navigate ";
799
- lines.push(this.renderFooter(footerText));
800
- return lines;
801
- }
802
- renderSkillSelector() {
803
- const innerW = this.width - 2;
804
- const th = this.theme;
805
- const lines = [];
806
- const agentName = this.agentConfigs[this.editingStep]?.name ?? "unknown";
807
- const stepLabel = this.mode === "single" ? agentName : this.mode === "parallel" ? `Task ${this.editingStep + 1}: ${agentName}` : `Step ${this.editingStep + 1}: ${agentName}`;
808
- lines.push(this.renderHeader(` Select Skills (${stepLabel}) `));
809
- lines.push(this.row(""));
810
- const cursor = "\x1B[7m \x1B[27m";
811
- lines.push(this.row(` ${th.fg("dim", "Search: ")}${this.skillSearchQuery}${cursor}`));
812
- lines.push(this.row(""));
813
- const selected = [...this.skillSelectedNames].join(", ") || th.fg("dim", "(none)");
814
- lines.push(this.row(` ${th.fg("dim", "Selected: ")}${truncateToWidth(selected, innerW - 12)}`));
815
- lines.push(this.row(""));
816
- const selectorHeight = 10;
817
- if (this.filteredSkills.length === 0) {
818
- lines.push(this.row(` ${th.fg("dim", "No matching skills")}`));
819
- } else {
820
- let startIdx = 0;
821
- if (this.filteredSkills.length > selectorHeight) {
822
- startIdx = Math.max(0, this.skillCursorIndex - Math.floor(selectorHeight / 2));
823
- startIdx = Math.min(startIdx, this.filteredSkills.length - selectorHeight);
824
- }
825
- const endIdx = Math.min(startIdx + selectorHeight, this.filteredSkills.length);
826
- if (startIdx > 0) {
827
- lines.push(this.row(` ${th.fg("dim", ` ↑ ${startIdx} more`)}`));
828
- }
829
- for (let i = startIdx;i < endIdx; i++) {
830
- const skill = this.filteredSkills[i];
831
- const isCursor = i === this.skillCursorIndex;
832
- const isSelected = this.skillSelectedNames.has(skill.name);
833
- const prefix = isCursor ? th.fg("accent", "→ ") : " ";
834
- const checkbox = isSelected ? th.fg("success", "[x]") : "[ ]";
835
- const nameText = isCursor ? th.fg("accent", skill.name) : skill.name;
836
- const sourceBadge = th.fg("dim", ` [${skill.source}]`);
837
- const desc = skill.description ? th.fg("dim", ` - ${truncateToWidth(skill.description, 25)}`) : "";
838
- lines.push(this.row(` ${prefix}${checkbox} ${nameText}${sourceBadge}${desc}`));
839
- }
840
- const remaining = this.filteredSkills.length - endIdx;
841
- if (remaining > 0) {
842
- lines.push(this.row(` ${th.fg("dim", ` ↓ ${remaining} more`)}`));
843
- }
844
- }
845
- const targetHeight = 18;
846
- for (let i = lines.length;i < targetHeight; i++) {
847
- lines.push(this.row(""));
848
- }
849
- lines.push(this.renderFooter(" [Enter] Confirm • [Space] Toggle • [Esc] Cancel "));
850
- return lines;
851
- }
852
- getFooterText() {
853
- const bgLabel = this.runInBackground ? "[b]g:ON" : "[b]g";
854
- switch (this.mode) {
855
- case "single":
856
- return ` [Enter] Run • [Esc] Cancel • e m t w s ${bgLabel} `;
857
- case "parallel":
858
- return ` [Enter] Run • [Esc] Cancel • e m t s ${bgLabel} • ↑↓ Nav `;
859
- case "chain":
860
- return ` [Enter] Run • [Esc] Cancel • e m t w r p s ${bgLabel} • ↑↓ Nav `;
861
- }
862
- }
863
- appendNotice(lines) {
864
- if (!this.noticeMessage)
865
- return;
866
- const color = this.noticeMessage.type === "error" ? "error" : "success";
867
- lines.push(this.row(` ${this.theme.fg(color, this.noticeMessage.text)}`));
868
- }
869
- renderSingleMode() {
870
- const innerW = this.width - 2;
871
- const th = this.theme;
872
- const lines = [];
873
- const agentName = this.agentConfigs[0]?.name ?? "unknown";
874
- const maxHeaderLen = innerW - 4;
875
- const headerText = ` Agent: ${truncateToWidth(agentName, maxHeaderLen - 9)} `;
876
- lines.push(this.renderHeader(headerText));
877
- lines.push(this.row(""));
878
- const config = this.agentConfigs[0];
879
- const behavior = this.getEffectiveBehavior(0);
880
- const stepLabel = config.name;
881
- lines.push(this.row(` ${th.fg("accent", "▶ " + stepLabel)}`));
882
- const template = (this.templates[0] ?? "").split(`
883
- `)[0] ?? "";
884
- const taskLabel = th.fg("dim", "task: ");
885
- lines.push(this.row(` ${taskLabel}${truncateToWidth(template, innerW - 12)}`));
886
- const effectiveModel = this.getEffectiveModel(0);
887
- const override = this.behaviorOverrides.get(0);
888
- const isOverridden = override?.model !== undefined;
889
- const modelValue = isOverridden ? th.fg("warning", effectiveModel) + th.fg("dim", " ✎") : effectiveModel;
890
- const modelLabel = th.fg("dim", "model: ");
891
- lines.push(this.row(` ${modelLabel}${truncateToWidth(modelValue, innerW - 13)}`));
892
- const writesValue = behavior.output === false ? th.fg("dim", "(disabled)") : behavior.output || th.fg("dim", "(none)");
893
- const writesLabel = th.fg("dim", "writes: ");
894
- lines.push(this.row(` ${writesLabel}${truncateToWidth(writesValue, innerW - 14)}`));
895
- const skillsValue = behavior.skills === false ? th.fg("dim", "(disabled)") : behavior.skills?.length ? behavior.skills.join(", ") : th.fg("dim", "(none)");
896
- const skillsLabel = th.fg("dim", "skills: ");
897
- lines.push(this.row(` ${skillsLabel}${truncateToWidth(skillsValue, innerW - 14)}`));
898
- lines.push(this.row(""));
899
- this.appendNotice(lines);
900
- lines.push(this.renderFooter(this.getFooterText()));
901
- return lines;
902
- }
903
- renderParallelMode() {
904
- const innerW = this.width - 2;
905
- const th = this.theme;
906
- const lines = [];
907
- const headerText = ` Parallel Tasks (${this.agentConfigs.length}) `;
908
- lines.push(this.renderHeader(headerText));
909
- lines.push(this.row(""));
910
- for (let i = 0;i < this.agentConfigs.length; i++) {
911
- const config = this.agentConfigs[i];
912
- const isSelected = i === this.selectedStep;
913
- const color = isSelected ? "accent" : "dim";
914
- const prefix = isSelected ? "▶ " : " ";
915
- const taskPrefix = `Task ${i + 1}: `;
916
- const maxNameLen = innerW - 4 - prefix.length - taskPrefix.length;
917
- const agentName = config.name.length > maxNameLen ? config.name.slice(0, maxNameLen - 1) + "…" : config.name;
918
- const taskLabel = `${taskPrefix}${agentName}`;
919
- lines.push(this.row(` ${th.fg(color, prefix + taskLabel)}`));
920
- const template = (this.templates[i] ?? "").split(`
921
- `)[0] ?? "";
922
- const taskTextLabel = th.fg("dim", "task: ");
923
- lines.push(this.row(` ${taskTextLabel}${truncateToWidth(template, innerW - 12)}`));
924
- const effectiveModel = this.getEffectiveModel(i);
925
- const override = this.behaviorOverrides.get(i);
926
- const isOverridden = override?.model !== undefined;
927
- const modelValue = isOverridden ? th.fg("warning", effectiveModel) + th.fg("dim", " ✎") : effectiveModel;
928
- const modelLabel = th.fg("dim", "model: ");
929
- lines.push(this.row(` ${modelLabel}${truncateToWidth(modelValue, innerW - 13)}`));
930
- const behavior = this.getEffectiveBehavior(i);
931
- const skillsValue = behavior.skills === false ? th.fg("dim", "(disabled)") : behavior.skills?.length ? behavior.skills.join(", ") : th.fg("dim", "(none)");
932
- const skillsLabel = th.fg("dim", "skills: ");
933
- lines.push(this.row(` ${skillsLabel}${truncateToWidth(skillsValue, innerW - 14)}`));
934
- lines.push(this.row(""));
935
- }
936
- this.appendNotice(lines);
937
- lines.push(this.renderFooter(this.getFooterText()));
938
- return lines;
939
- }
940
- renderChainMode() {
941
- const innerW = this.width - 2;
942
- const th = this.theme;
943
- const lines = [];
944
- const chainLabel = this.agentConfigs.map((c) => c.name).join(" → ");
945
- const maxHeaderLen = innerW - 4;
946
- const headerText = ` Chain: ${truncateToWidth(chainLabel, maxHeaderLen - 9)} `;
947
- lines.push(this.renderHeader(headerText));
948
- lines.push(this.row(""));
949
- const taskPreview = truncateToWidth(this.originalTask, innerW - 16);
950
- lines.push(this.row(` Original Task: ${taskPreview}`));
951
- const chainDirPreview = truncateToWidth(this.chainDir ?? "", innerW - 12);
952
- lines.push(this.row(` Chain Dir: ${th.fg("dim", chainDirPreview)}`));
953
- const progressEnabled = this.agentConfigs.some((_, i) => this.getEffectiveBehavior(i).progress);
954
- const progressValue = progressEnabled ? th.fg("success", "enabled") : th.fg("dim", "disabled");
955
- lines.push(this.row(` Progress: ${progressValue} ${th.fg("dim", "(press [p] to toggle)")}`));
956
- lines.push(this.row(""));
957
- for (let i = 0;i < this.agentConfigs.length; i++) {
958
- const config = this.agentConfigs[i];
959
- const isSelected = i === this.selectedStep;
960
- const behavior = this.getEffectiveBehavior(i);
961
- const color = isSelected ? "accent" : "dim";
962
- const prefix = isSelected ? "▶ " : " ";
963
- const stepPrefix = `Step ${i + 1}: `;
964
- const maxNameLen = innerW - 4 - prefix.length - stepPrefix.length;
965
- const agentName = config.name.length > maxNameLen ? config.name.slice(0, maxNameLen - 1) + "…" : config.name;
966
- const stepLabel = `${stepPrefix}${agentName}`;
967
- lines.push(this.row(` ${th.fg(color, prefix + stepLabel)}`));
968
- const template = (this.templates[i] ?? "").split(`
969
- `)[0] ?? "";
970
- const highlighted = template.replace(/\{task\}/g, th.fg("success", "{task}")).replace(/\{previous\}/g, th.fg("warning", "{previous}")).replace(/\{chain_dir\}/g, th.fg("accent", "{chain_dir}"));
971
- const templateLabel = th.fg("dim", "task: ");
972
- lines.push(this.row(` ${templateLabel}${truncateToWidth(highlighted, innerW - 12)}`));
973
- const effectiveModel = this.getEffectiveModel(i);
974
- const override = this.behaviorOverrides.get(i);
975
- const isOverridden = override?.model !== undefined;
976
- const modelValue = isOverridden ? th.fg("warning", effectiveModel) + th.fg("dim", " ✎") : effectiveModel;
977
- const modelLabel = th.fg("dim", "model: ");
978
- lines.push(this.row(` ${modelLabel}${truncateToWidth(modelValue, innerW - 13)}`));
979
- const writesValue = behavior.output === false ? th.fg("dim", "(disabled)") : behavior.output || th.fg("dim", "(none)");
980
- const writesLabel = th.fg("dim", "writes: ");
981
- lines.push(this.row(` ${writesLabel}${truncateToWidth(writesValue, innerW - 14)}`));
982
- const readsValue = behavior.reads === false ? th.fg("dim", "(disabled)") : behavior.reads && behavior.reads.length > 0 ? behavior.reads.join(", ") : th.fg("dim", "(none)");
983
- const readsLabel = th.fg("dim", "reads: ");
984
- lines.push(this.row(` ${readsLabel}${truncateToWidth(readsValue, innerW - 13)}`));
985
- const skillsValue = behavior.skills === false ? th.fg("dim", "(disabled)") : behavior.skills?.length ? behavior.skills.join(", ") : th.fg("dim", "(none)");
986
- const skillsLabel = th.fg("dim", "skills: ");
987
- lines.push(this.row(` ${skillsLabel}${truncateToWidth(skillsValue, innerW - 14)}`));
988
- if (progressEnabled) {
989
- const isFirstStep = i === 0;
990
- const progressAction = isFirstStep ? th.fg("success", "writes progress.md") : th.fg("accent", "reads progress.md");
991
- const progressLabel = th.fg("dim", "progress: ");
992
- lines.push(this.row(` ${progressLabel}${progressAction}`));
993
- }
994
- if (i < this.agentConfigs.length - 1) {
995
- const nextStepUsePrevious = (this.templates[i + 1] ?? "").includes("{previous}");
996
- if (nextStepUsePrevious) {
997
- const indicator = th.fg("dim", " ↳ response → ") + th.fg("warning", "{previous}");
998
- lines.push(this.row(indicator));
999
- }
1000
- }
1001
- lines.push(this.row(""));
1002
- }
1003
- this.appendNotice(lines);
1004
- lines.push(this.renderFooter(this.getFooterText()));
1005
- return lines;
1006
- }
1007
- invalidate() {}
1008
- dispose() {
1009
- if (this.noticeMessageTimer)
1010
- clearTimeout(this.noticeMessageTimer);
1011
- this.noticeMessageTimer = null;
1012
- }
1013
- }