@duckmind/dm-windows-x64 0.60.6 → 0.60.9

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 (197) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +70 -123
  3. package/extensions/dm-9router-ext/src/index.js +410 -5
  4. package/extensions/dm-caveman/extensions/caveman.js +283 -12
  5. package/extensions/dm-cliproxy/index.js +182 -2
  6. package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
  7. package/extensions/dm-cliproxy/src/apply.js +228 -1
  8. package/extensions/dm-cliproxy/src/cache.js +42 -1
  9. package/extensions/dm-cliproxy/src/commands.js +50 -2
  10. package/extensions/dm-cliproxy/src/compat.js +81 -1
  11. package/extensions/dm-cliproxy/src/config.js +192 -2
  12. package/extensions/dm-cliproxy/src/conflicts.js +46 -1
  13. package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
  14. package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
  15. package/extensions/dm-cliproxy/src/log.js +23 -1
  16. package/extensions/dm-cliproxy/src/status-quota.js +77 -1
  17. package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
  18. package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
  19. package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
  20. package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
  21. package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
  22. package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
  23. package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
  24. package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
  25. package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
  26. package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
  27. package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
  28. package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
  29. package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
  30. package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
  31. package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
  32. package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
  33. package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
  34. package/extensions/dm-context/src/context.js +144 -1
  35. package/extensions/dm-context/src/index.js +339 -7
  36. package/extensions/dm-context/src/utils.js +9 -1
  37. package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
  38. package/extensions/dm-cua/index.js +75 -6
  39. package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
  40. package/extensions/dm-cua/src/browser-install.mjs +331 -2
  41. package/extensions/dm-fff/src/index.js +688 -12
  42. package/extensions/dm-fff/src/query.js +60 -1
  43. package/extensions/dm-goal/src/goal.js +894 -23
  44. package/extensions/dm-image2/index.js +103 -9
  45. package/extensions/dm-image2/src/image-lib.mjs +1275 -8
  46. package/extensions/dm-subagents/install.mjs +62 -8
  47. package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
  48. package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
  49. package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
  50. package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
  51. package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
  52. package/extensions/dm-subagents/src/agents/agents.js +1139 -11
  53. package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
  54. package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
  55. package/extensions/dm-subagents/src/agents/identity.js +29 -1
  56. package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
  57. package/extensions/dm-subagents/src/agents/skills.js +614 -6
  58. package/extensions/dm-subagents/src/extension/config.js +35 -2
  59. package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
  60. package/extensions/dm-subagents/src/extension/doctor.js +172 -15
  61. package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
  62. package/extensions/dm-subagents/src/extension/index.js +521 -359
  63. package/extensions/dm-subagents/src/extension/rpc.js +266 -7
  64. package/extensions/dm-subagents/src/extension/schemas.js +275 -1
  65. package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
  66. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
  67. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
  68. package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
  69. package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
  70. package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
  71. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
  72. package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
  73. package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
  74. package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
  75. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
  76. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
  77. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
  78. package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
  79. package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
  80. package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
  81. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
  82. package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
  83. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
  84. package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
  85. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
  86. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
  87. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
  88. package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
  89. package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
  90. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
  91. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
  92. package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
  93. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
  94. package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
  95. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
  96. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
  97. package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
  98. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
  99. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
  100. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
  101. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
  102. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
  103. package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
  104. package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
  105. package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
  106. package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
  107. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
  108. package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
  109. package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
  110. package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
  111. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
  112. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
  113. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
  114. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
  115. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
  116. package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
  117. package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
  118. package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
  119. package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
  120. package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
  121. package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
  122. package/extensions/dm-subagents/src/shared/formatters.js +98 -7
  123. package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
  124. package/extensions/dm-subagents/src/shared/model-info.js +62 -1
  125. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
  126. package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
  127. package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
  128. package/extensions/dm-subagents/src/shared/settings.js +198 -11
  129. package/extensions/dm-subagents/src/shared/status-format.js +53 -1
  130. package/extensions/dm-subagents/src/shared/types.js +184 -6
  131. package/extensions/dm-subagents/src/shared/utils.js +462 -2
  132. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
  133. package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
  134. package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
  135. package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
  136. package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
  137. package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
  138. package/extensions/dm-subagents/src/tui/render.js +1542 -4
  139. package/extensions/dm-usage/index.js +1294 -9
  140. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
  141. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
  142. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
  143. package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
  144. package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
  145. package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
  146. package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
  147. package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
  148. package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
  149. package/extensions/greedysearch-dm/bin/search.mjs +620 -540
  150. package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
  151. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
  152. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
  153. package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
  154. package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
  155. package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
  156. package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
  157. package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
  158. package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
  159. package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
  160. package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
  161. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
  162. package/extensions/greedysearch-dm/index.js +123 -23
  163. package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
  164. package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
  165. package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
  166. package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
  167. package/extensions/greedysearch-dm/src/github.mjs +222 -7
  168. package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
  169. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
  170. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
  171. package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
  172. package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
  173. package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
  174. package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
  175. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
  176. package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
  177. package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
  178. package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
  179. package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
  180. package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
  181. package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
  182. package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
  183. package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
  184. package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
  185. package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
  186. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
  187. package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
  188. package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
  189. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
  190. package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
  191. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
  192. package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
  193. package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
  194. package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
  195. package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
  196. package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
  197. package/package.json +1 -1
@@ -1,12 +1,1013 @@
1
- import{matchesKey as F,visibleWidth as P,truncateToWidth as H}from"@duckmind/dm-tui";var I=["off","minimal","low","medium","high","xhigh"];function u(j){let J=j.lastIndexOf(":");if(J===-1)return{baseModel:j,thinkingSuffix:""};let Q=I.find((X)=>X===j.substring(J+1));if(!Q)return{baseModel:j,thinkingSuffix:""};return{baseModel:j.substring(0,J),thinkingSuffix:`:${Q}`}}function g(j,J,Q){if(!j||!J||J.length===0)return;let{baseModel:X}=u(j),Z=J.find((Y)=>Y.fullId===X);if(Z)return Z;let $=J.filter((Y)=>Y.id===X);if(Q){let Y=$.find((U)=>U.provider===Q);if(Y)return Y}return $.length===1?$[0]:void 0}function b(j){if(!j)return[...I];if(j.reasoning===!1)return["off"];if(!j.thinkingLevelMap)return[...I];return I.filter((Q)=>{let X=j.thinkingLevelMap?.[Q];if(X===null)return!1;if(Q==="xhigh")return X!==void 0;return!0})}function S(j){let J=j.lastIndexOf(":");if(J===-1)return{baseModel:j,thinkingSuffix:""};return{baseModel:j.substring(0,J),thinkingSuffix:j.substring(J)}}function K(j){return j.toLowerCase().replace(/[._]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")}function p(j,J,Q){let X=Number(j),Z=Number(J),$=Number(Q);return X>=1900&&X<=2099&&Z>=1&&Z<=12&&$>=1&&$<=31}function c(j){let J=/^(.*)-(\d{4})-(\d{2})-(\d{2})$/.exec(j);if(J&&p(J[2],J[3],J[4]))return J[1];let Q=/^(.*)-(\d{4})(\d{2})(\d{2})$/.exec(j);if(Q&&p(Q[2],Q[3],Q[4]))return Q[1];return j}function m(j,J,Q){if(j.includes("/")){let X=J.find((Z)=>Z.fullId===j);if(X)return X.fullId}else{let X=J.filter((Z)=>Z.id===j);if(Q){let Z=X.find(($)=>$.provider===Q);if(Z)return Z.fullId}if(X.length===1)return X[0].fullId}return Jj(j,J,Q)}function Jj(j,J,Q){let X,Z=j,$=j.indexOf("/");if($!==-1)X=K(j.slice(0,$)),Z=j.slice($+1);else{let G=[":","."];for(let z of G){let A=j.indexOf(z);if(A<=0)continue;let B=K(j.slice(0,A));if(!J.some((D)=>K(D.provider)===B))continue;X=B,Z=j.slice(A+1);break}}let Y=K(Z),U=c(Y),_=J.filter((G)=>{let z=K(G.id);if(z!==Y&&c(z)!==U)return!1;if(X!==void 0&&K(G.provider)!==X)return!1;return!0});if(_.length===0)return;if(Q){let G=K(Q),z=_.find((A)=>K(A.provider)===G);if(z)return z.fullId}if(_.length===1)return _[0].fullId;return}function h(j,J,Q){if(!j)return;if(!J||J.length===0)return j;let X=m(j,J,Q);if(X)return X;let{baseModel:Z,thinkingSuffix:$}=S(j);if(!$)return j;let Y=m(Z,J,Q);if(Y)return`${Y}${$}`;return j}function x(j=""){return{buffer:j,cursor:0,viewportOffset:0}}function W(j,J){if(J<=0)return{lines:[j],starts:[0]};if(j.length===0)return{lines:[""],starts:[0]};let Q=[],X=[],Z=0,$=j.split(`
2
- `);for(let[Y,U]of $.entries()){if(U.length===0)X.push(Z),Q.push("");else{let _=0,G=0,z=0;while(G<U.length){let A=String.fromCodePoint(U.codePointAt(G)),B=P(A);if(z>0&&z+B>J){X.push(Z+_),Q.push(U.slice(_,G)),_=G,z=0;continue}G+=A.length,z+=B}X.push(Z+_),Q.push(U.slice(_))}Z+=U.length+(Y<$.length-1?1:0)}if(!j.endsWith(`
3
- `)&&j.length>0&&P(Q[Q.length-1]??"")===J)X.push(j.length),Q.push("");return{lines:Q,starts:X}}function L(j,J){for(let Q=J.length-1;Q>=0;Q--)if(j>=J[Q])return{line:Q,col:j-J[Q]};return{line:0,col:0}}function Qj(j,J,Q){if(j<Q)return Math.max(0,j);if(j>=Q+J)return Math.max(0,j-J+1);return Math.max(0,Q)}function M(j){let J=j.charCodeAt(0);return J>=48&&J<=57||J>=65&&J<=90||J>=97&&J<=122||J===95}function n(j,J){let Q=J;while(Q>0&&!M(j[Q-1]))Q--;while(Q>0&&M(j[Q-1]))Q--;return Q}function Xj(j,J){let Q=J;while(Q<j.length&&M(j[Q]))Q++;while(Q<j.length&&!M(j[Q]))Q++;return Q}function Zj(j){let J=j.split("\x1B[200~").join("").split("\x1B[201~").join("");J=J.replace(/\r\n/g,`
4
- `).replace(/\r/g,`
5
- `);let Q=J.indexOf(`
6
- `);if(Q!==-1)J=J.slice(0,Q);if(J=J.replace(/\t/g," "),J.length===0)return null;for(let X=0;X<J.length;X++)if(J.charCodeAt(X)<32)return null;return J}function $j(j,J,Q){if(F(J,"escape")||F(J,"ctrl+c")||F(J,"return"))return null;let{lines:X,starts:Z}=W(j.buffer,Q),$=L(j.cursor,Z);if(F(J,"alt+left")||F(J,"ctrl+left"))return{...j,cursor:n(j.buffer,j.cursor)};if(F(J,"alt+right")||F(J,"ctrl+right"))return{...j,cursor:Xj(j.buffer,j.cursor)};if(F(J,"left"))return j.cursor>0?{...j,cursor:j.cursor-1}:j;if(F(J,"right"))return j.cursor<j.buffer.length?{...j,cursor:j.cursor+1}:j;if(F(J,"up")&&$.line>0){let U=$.line-1;return{...j,cursor:Z[U]+Math.min($.col,X[U]?.length??0)}}if(F(J,"down")&&$.line<X.length-1){let U=$.line+1;return{...j,cursor:Z[U]+Math.min($.col,X[U]?.length??0)}}if(F(J,"home"))return{...j,cursor:Z[$.line]};if(F(J,"end"))return{...j,cursor:Z[$.line]+(X[$.line]?.length??0)};if(F(J,"ctrl+home"))return{...j,cursor:0};if(F(J,"ctrl+end"))return{...j,cursor:j.buffer.length};if(F(J,"alt+backspace")){let U=n(j.buffer,j.cursor);return U===j.cursor?j:{...j,buffer:j.buffer.slice(0,U)+j.buffer.slice(j.cursor),cursor:U}}if(F(J,"backspace"))return j.cursor>0?{...j,buffer:j.buffer.slice(0,j.cursor-1)+j.buffer.slice(j.cursor),cursor:j.cursor-1}:j;if(F(J,"delete"))return j.cursor<j.buffer.length?{...j,buffer:j.buffer.slice(0,j.cursor)+j.buffer.slice(j.cursor+1)}:j;let Y=Zj(J);return Y?{...j,buffer:j.buffer.slice(0,j.cursor)+Y+j.buffer.slice(j.cursor),cursor:j.cursor+Y.length}:null}function Uj(j,J){let Q=j.slice(0,J),X=j[J]??" ",Z=j.slice(J+1);return`${Q}\x1B[7m${X}\x1B[27m${Z}`}function Yj(j,J,Q){let{lines:X,starts:Z}=W(j.buffer,J),$=L(j.cursor,Z),Y=[];for(let U=0;U<Q;U++){let _=j.viewportOffset+U,G=_<X.length?X[_]??"":"";if(_===$.line)G=Uj(G,$.col);Y.push(G)}return Y}class Fj{width=84;selectedStep=0;editingStep=null;editMode="template";editState=x();EDIT_VIEWPORT_HEIGHT=12;behaviorOverrides=new Map;modelSearchQuery="";modelSelectedIndex=0;filteredModels=[];MODEL_SELECTOR_HEIGHT=10;thinkingSelectedIndex=0;skillSearchQuery="";skillSelectedNames=new Set;skillCursorIndex=0;filteredSkills=[];noticeMessage=null;noticeMessageTimer=null;runInBackground=!1;tui;theme;agentConfigs;templates;originalTask;chainDir;resolvedBehaviors;availableModels;preferredProvider;availableSkills;done;mode;constructor(j,J,Q,X,Z,$,Y,U,_,G,z,A="chain"){this.tui=j,this.theme=J,this.agentConfigs=Q,this.templates=X,this.originalTask=Z,this.chainDir=$,this.resolvedBehaviors=Y,this.availableModels=U,this.preferredProvider=_,this.availableSkills=G,this.done=z,this.mode=A,this.filteredModels=[...U],this.filteredSkills=[...G]}pad(j,J){let Q=P(j);return j+" ".repeat(Math.max(0,J-Q))}row(j){let J=this.width-2;return this.theme.fg("border","│")+this.pad(j,J)+this.theme.fg("border","│")}renderHeader(j){let J=this.width-2,Q=Math.max(0,J-P(j)),X=Math.floor(Q/2),Z=Q-X;return this.theme.fg("border","╭"+"─".repeat(X))+this.theme.fg("accent",j)+this.theme.fg("border","─".repeat(Z)+"╮")}renderFooter(j){let J=this.width-2,Q=Math.max(0,J-P(j)),X=Math.floor(Q/2),Z=Q-X;return this.theme.fg("border","╰"+"─".repeat(X))+this.theme.fg("dim",j)+this.theme.fg("border","─".repeat(Z)+"╯")}exitEditMode(){this.editingStep=null,this.editState=x(),this.tui.requestRender()}renderFullEditMode(){let j=this.width-2,J=j-2,Q=[],{lines:X,starts:Z}=W(this.editState.buffer,J),$=L(this.editState.cursor,Z);this.editState={...this.editState,viewportOffset:Qj($.line,this.EDIT_VIEWPORT_HEIGHT,this.editState.viewportOffset)};let Y=this.editMode==="template"?"task":this.editMode,U=this.agentConfigs[this.editingStep]?.name??"unknown",_=j-30,G=U.length>_?U.slice(0,_-1)+"…":U,z=this.mode==="single"?G:this.mode==="parallel"?`Task ${this.editingStep+1}: ${G}`:`Step ${this.editingStep+1}: ${G}`,A=` Editing ${Y} (${z}) `;Q.push(this.renderHeader(A)),Q.push(this.row(""));let B=Yj(this.editState,J,this.EDIT_VIEWPORT_HEIGHT);for(let C of B)Q.push(this.row(` ${C}`));let D=X.length-this.editState.viewportOffset-this.EDIT_VIEWPORT_HEIGHT,R=D>0,O=this.editState.viewportOffset>0,V="";if(O)V+="↑";if(R)V+=`↓ ${D}+`;Q.push(this.row(""));let q=V?` [Esc] Done • [Ctrl+C] Discard • ${V} `:" [Esc] Done • [Ctrl+C] Discard ";return Q.push(this.renderFooter(q)),Q}getEffectiveBehavior(j){let J=this.resolvedBehaviors[j],Q=this.behaviorOverrides.get(j);if(!Q)return J;return{output:Q.output!==void 0?Q.output:J.output,outputMode:J.outputMode,reads:Q.reads!==void 0?Q.reads:J.reads,progress:Q.progress!==void 0?Q.progress:J.progress,skills:Q.skills!==void 0?Q.skills:J.skills,model:Q.model!==void 0?Q.model:J.model}}getEffectiveModel(j){let J=this.behaviorOverrides.get(j);if(J?.model)return this.resolveModelFullId(J.model);let Q=this.resolvedBehaviors[j]?.model;if(Q)return this.resolveModelFullId(Q);return"default"}resolveModelFullId(j){return h(j,this.availableModels,this.preferredProvider)??j}updateBehavior(j,J,Q){let X=this.behaviorOverrides.get(j)??{};this.behaviorOverrides.set(j,{...X,[J]:Q})}showNotice(j,J){if(this.noticeMessage={text:j,type:J},this.noticeMessageTimer)clearTimeout(this.noticeMessageTimer);this.noticeMessageTimer=setTimeout(()=>{this.noticeMessage=null,this.noticeMessageTimer=null,this.tui.requestRender()},2000),this.tui.requestRender()}handleInput(j){if(this.editingStep!==null){if(this.editMode==="model")this.handleModelSelectorInput(j);else if(this.editMode==="thinking")this.handleThinkingSelectorInput(j);else if(this.editMode==="skills")this.handleSkillSelectorInput(j);else this.handleEditInput(j);return}if(F(j,"escape")||F(j,"ctrl+c")){this.done({confirmed:!1,templates:[],behaviorOverrides:[]});return}if(F(j,"return")){let J=[];for(let Q=0;Q<this.agentConfigs.length;Q++)J.push(this.behaviorOverrides.get(Q));this.done({confirmed:!0,templates:this.templates,behaviorOverrides:J,runInBackground:this.runInBackground});return}if(F(j,"up")){this.selectedStep=Math.max(0,this.selectedStep-1),this.tui.requestRender();return}if(F(j,"down")){let J=Math.max(0,this.agentConfigs.length-1);this.selectedStep=Math.min(J,this.selectedStep+1),this.tui.requestRender();return}if(j==="e"){this.enterEditMode("template");return}if(j==="m"){this.enterModelSelector();return}if(j==="t"){this.enterThinkingSelector();return}if(j==="s"){this.editingStep=this.selectedStep,this.editMode="skills",this.skillSearchQuery="",this.skillCursorIndex=0,this.filteredSkills=[...this.availableSkills];let J=this.getEffectiveBehavior(this.selectedStep).skills;if(this.skillSelectedNames.clear(),J!==!1&&J.length>0)J.forEach((Q)=>this.skillSelectedNames.add(Q));this.tui.requestRender();return}if(j==="w"&&this.mode!=="parallel"){this.enterEditMode("output");return}if(j==="r"&&this.mode==="chain"){this.enterEditMode("reads");return}if(j==="p"&&this.mode==="chain"){let Q=!this.agentConfigs.some((X,Z)=>this.getEffectiveBehavior(Z).progress);for(let X=0;X<this.agentConfigs.length;X++)this.updateBehavior(X,"progress",Q);this.tui.requestRender();return}if(j==="b"){this.runInBackground=!this.runInBackground,this.tui.requestRender();return}}enterEditMode(j){this.editingStep=this.selectedStep,this.editMode=j;let J="";if(j==="template")J=(this.templates[this.selectedStep]??"").split(`
7
- `)[0]??"";else if(j==="output"){let Q=this.getEffectiveBehavior(this.selectedStep);J=Q.output===!1?"":Q.output||""}else if(j==="reads"){let Q=this.getEffectiveBehavior(this.selectedStep);J=Q.reads===!1?"":Q.reads?.join(", ")||""}this.editState=x(J),this.tui.requestRender()}enterModelSelector(){this.editingStep=this.selectedStep,this.editMode="model",this.modelSearchQuery="",this.modelSelectedIndex=0,this.filteredModels=[...this.availableModels];let j=S(this.getEffectiveModel(this.selectedStep)).baseModel,J=this.filteredModels.findIndex((Q)=>Q.fullId===j||Q.id===j);if(J>=0)this.modelSelectedIndex=J;this.tui.requestRender()}filterModels(){let j=this.modelSearchQuery.toLowerCase();if(!j)this.filteredModels=[...this.availableModels];else this.filteredModels=this.availableModels.filter((J)=>J.fullId.toLowerCase().includes(j)||J.id.toLowerCase().includes(j)||J.provider.toLowerCase().includes(j));this.modelSelectedIndex=Math.min(this.modelSelectedIndex,Math.max(0,this.filteredModels.length-1))}handleModelSelectorInput(j){if(F(j,"escape")||F(j,"ctrl+c")){this.exitEditMode();return}if(F(j,"return")){let J=this.filteredModels[this.modelSelectedIndex];if(J){let{thinkingSuffix:Q}=S(this.getEffectiveModel(this.editingStep)),X=Q.slice(1),Z=g(J.fullId,this.availableModels,this.preferredProvider),$=b(Z).some((Y)=>Y===X)?Q:"";this.updateBehavior(this.editingStep,"model",`${J.fullId}${$}`)}this.exitEditMode();return}if(F(j,"up")){if(this.filteredModels.length>0)this.modelSelectedIndex=this.modelSelectedIndex===0?this.filteredModels.length-1:this.modelSelectedIndex-1;this.tui.requestRender();return}if(F(j,"down")){if(this.filteredModels.length>0)this.modelSelectedIndex=this.modelSelectedIndex===this.filteredModels.length-1?0:this.modelSelectedIndex+1;this.tui.requestRender();return}if(F(j,"backspace")){if(this.modelSearchQuery.length>0)this.modelSearchQuery=this.modelSearchQuery.slice(0,-1),this.filterModels();this.tui.requestRender();return}if(j.length===1&&j.charCodeAt(0)>=32){this.modelSearchQuery+=j,this.filterModels(),this.tui.requestRender();return}}getAvailableThinkingLevels(j){return b(g(this.getEffectiveModel(j),this.availableModels,this.preferredProvider))}enterThinkingSelector(){if(!this.getEffectiveBehavior(this.selectedStep).model){this.showNotice("Select a model first","error");return}this.editingStep=this.selectedStep,this.editMode="thinking";let j=this.getAvailableThinkingLevels(this.selectedStep),{thinkingSuffix:J}=S(this.getEffectiveModel(this.selectedStep)),Q=J.slice(1),X=j.findIndex((Z)=>Z===Q);this.thinkingSelectedIndex=X>=0?X:Math.max(0,j.indexOf("off")),this.tui.requestRender()}handleThinkingSelectorInput(j){if(F(j,"escape")||F(j,"ctrl+c")){this.exitEditMode();return}let J=this.getAvailableThinkingLevels(this.editingStep);if(J.length===0)return;if(F(j,"return")){let Q=J[this.thinkingSelectedIndex]??"off";this.applyThinkingLevel(Q),this.exitEditMode();return}if(F(j,"up")){this.thinkingSelectedIndex=this.thinkingSelectedIndex===0?J.length-1:this.thinkingSelectedIndex-1,this.tui.requestRender();return}if(F(j,"down")){this.thinkingSelectedIndex=this.thinkingSelectedIndex===J.length-1?0:this.thinkingSelectedIndex+1,this.tui.requestRender();return}}applyThinkingLevel(j){let J=this.editingStep,Q=this.getEffectiveBehavior(J).model;if(!Q)return;let{baseModel:X}=S(Q),Z=j==="off"?X:`${X}:${j}`;this.updateBehavior(J,"model",Z)}filterSkills(){let j=this.skillSearchQuery.toLowerCase();if(!j)this.filteredSkills=[...this.availableSkills];else this.filteredSkills=this.availableSkills.filter((J)=>J.name.toLowerCase().includes(j)||(J.description?.toLowerCase().includes(j)??!1));this.skillCursorIndex=Math.min(this.skillCursorIndex,Math.max(0,this.filteredSkills.length-1))}handleSkillSelectorInput(j){if(F(j,"escape")||F(j,"ctrl+c")){this.exitEditMode();return}if(F(j,"return")){let J=[...this.skillSelectedNames];this.updateBehavior(this.editingStep,"skills",J),this.exitEditMode();return}if(j===" "){if(this.filteredSkills.length>0){let J=this.filteredSkills[this.skillCursorIndex];if(J)if(this.skillSelectedNames.has(J.name))this.skillSelectedNames.delete(J.name);else this.skillSelectedNames.add(J.name)}this.tui.requestRender();return}if(F(j,"up")){if(this.filteredSkills.length>0)this.skillCursorIndex=this.skillCursorIndex===0?this.filteredSkills.length-1:this.skillCursorIndex-1;this.tui.requestRender();return}if(F(j,"down")){if(this.filteredSkills.length>0)this.skillCursorIndex=this.skillCursorIndex===this.filteredSkills.length-1?0:this.skillCursorIndex+1;this.tui.requestRender();return}if(F(j,"backspace")){if(this.skillSearchQuery.length>0)this.skillSearchQuery=this.skillSearchQuery.slice(0,-1),this.filterSkills();this.tui.requestRender();return}if(j.length===1&&j.charCodeAt(0)>=32){this.skillSearchQuery+=j,this.filterSkills(),this.tui.requestRender();return}}handleEditInput(j){let J=this.width-4;if(F(j,"shift+up")||F(j,"pageup")){let{lines:X,starts:Z}=W(this.editState.buffer,J),$=L(this.editState.cursor,Z),Y=Math.max(0,$.line-this.EDIT_VIEWPORT_HEIGHT),U=Math.min($.col,X[Y]?.length??0);this.editState={...this.editState,cursor:Z[Y]+U},this.tui.requestRender();return}if(F(j,"shift+down")||F(j,"pagedown")){let{lines:X,starts:Z}=W(this.editState.buffer,J),$=L(this.editState.cursor,Z),Y=Math.min(X.length-1,$.line+this.EDIT_VIEWPORT_HEIGHT),U=Math.min($.col,X[Y]?.length??0);this.editState={...this.editState,cursor:Z[Y]+U},this.tui.requestRender();return}if(F(j,"tab"))return;let Q=$j(this.editState,j,J);if(Q){this.editState=Q,this.tui.requestRender();return}if(F(j,"escape")){this.saveEdit(),this.exitEditMode();return}if(F(j,"ctrl+c")){this.exitEditMode();return}}saveEdit(){let j=this.editingStep;if(this.editMode==="template"){let Q=(this.templates[j]??"").split(`
8
- `);Q[0]=this.editState.buffer,this.templates[j]=Q.join(`
9
- `)}else if(this.editMode==="output"){let J=this.getEffectiveBehavior(j),Q=typeof J.output==="string"?J.output:null,X=this.editState.buffer.trim(),Z=X===""?!1:X;if(this.updateBehavior(j,"output",Z),Q&&typeof Z==="string"&&Q!==Z)this.propagateOutputChange(j,Q,Z)}else if(this.editMode==="reads"){let J=this.editState.buffer.trim();if(J==="")this.updateBehavior(j,"reads",!1);else{let Q=J.split(",").map((X)=>X.trim()).filter((X)=>X!=="");this.updateBehavior(j,"reads",Q.length>0?Q:!1)}}}propagateOutputChange(j,J,Q){for(let X=j+1;X<this.agentConfigs.length;X++){let Z=this.getEffectiveBehavior(X);if(Z.reads===!1||!Z.reads||Z.reads.length===0)continue;let $=Z.reads,Y=$.indexOf(J);if(Y!==-1){let U=[...$];U[Y]=Q,this.updateBehavior(X,"reads",U)}}}render(j){if(this.editingStep!==null){if(this.editMode==="model")return this.renderModelSelector();if(this.editMode==="thinking")return this.renderThinkingSelector();if(this.editMode==="skills")return this.renderSkillSelector();return this.renderFullEditMode()}switch(this.mode){case"single":return this.renderSingleMode();case"parallel":return this.renderParallelMode();case"chain":return this.renderChainMode()}}renderModelSelector(){let j=this.theme,J=[],Q=this.agentConfigs[this.editingStep]?.name??"unknown",Z=` Select Model (${this.mode==="single"?Q:this.mode==="parallel"?`Task ${this.editingStep+1}: ${Q}`:`Step ${this.editingStep+1}: ${Q}`}) `;J.push(this.renderHeader(Z)),J.push(this.row(""));let $=j.fg("dim","Search: "),Y="\x1B[7m \x1B[27m",U=this.modelSearchQuery+Y;J.push(this.row(` ${$}${U}`)),J.push(this.row(""));let _=this.getEffectiveModel(this.editingStep),G=S(_).baseModel,z=j.fg("dim","Current: ");if(J.push(this.row(` ${z}${j.fg("warning",_)}`)),J.push(this.row("")),this.filteredModels.length===0)J.push(this.row(` ${j.fg("dim","No matching models")}`));else{let R=this.MODEL_SELECTOR_HEIGHT,O=0;if(this.filteredModels.length>R)O=Math.max(0,this.modelSelectedIndex-Math.floor(R/2)),O=Math.min(O,this.filteredModels.length-R);let V=Math.min(O+R,this.filteredModels.length);if(O>0)J.push(this.row(` ${j.fg("dim",` ↑ ${O} more`)}`));for(let C=O;C<V;C++){let E=this.filteredModels[C],N=C===this.modelSelectedIndex,T=E.fullId===G||E.id===G,k=N?j.fg("accent","→ "):" ",w=N?j.fg("accent",E.id):E.id,v=j.fg("dim",` [${E.provider}]`),f=T?j.fg("success"," current"):"";J.push(this.row(` ${k}${w}${v}${f}`))}let q=this.filteredModels.length-V;if(q>0)J.push(this.row(` ${j.fg("dim",` ↓ ${q} more`)}`))}let A=J.length,B=18;for(let R=A;R<B;R++)J.push(this.row(""));let D=" [Enter] Select • [Esc] Cancel • Type to search ";return J.push(this.renderFooter(D)),J}renderThinkingSelector(){let j=this.theme,J=[],Q=this.agentConfigs[this.editingStep]?.name??"unknown",Z=` Thinking Level (${this.mode==="single"?Q:this.mode==="parallel"?`Task ${this.editingStep+1}: ${Q}`:`Step ${this.editingStep+1}: ${Q}`}) `;J.push(this.renderHeader(Z)),J.push(this.row(""));let $=this.getEffectiveModel(this.editingStep),Y=j.fg("dim","Model: ");J.push(this.row(` ${Y}${j.fg("accent",$)}`)),J.push(this.row("")),J.push(this.row(` ${j.fg("dim","Select thinking level (extended thinking budget):")}`)),J.push(this.row(""));let U={off:"No extended thinking",minimal:"Brief reasoning",low:"Light reasoning",medium:"Moderate reasoning",high:"Deep reasoning",xhigh:"Maximum reasoning (ultrathink)"},_=this.getAvailableThinkingLevels(this.editingStep);if(_.length===0)J.push(this.row(` ${j.fg("dim","No supported thinking levels")}`));else for(let B=0;B<_.length;B++){let D=_[B],R=B===this.thinkingSelectedIndex,O=R?j.fg("accent","→ "):" ",V=R?j.fg("accent",D):D,q=j.fg("dim",` - ${U[D]}`);J.push(this.row(` ${O}${V}${q}`))}let G=J.length,z=16;for(let B=G;B<z;B++)J.push(this.row(""));let A=_.length===0?" [Esc] Cancel ":" [Enter] Select • [Esc] Cancel • ↑↓ Navigate ";return J.push(this.renderFooter(A)),J}renderSkillSelector(){let j=this.width-2,J=this.theme,Q=[],X=this.agentConfigs[this.editingStep]?.name??"unknown",Z=this.mode==="single"?X:this.mode==="parallel"?`Task ${this.editingStep+1}: ${X}`:`Step ${this.editingStep+1}: ${X}`;Q.push(this.renderHeader(` Select Skills (${Z}) `)),Q.push(this.row(""));let $="\x1B[7m \x1B[27m";Q.push(this.row(` ${J.fg("dim","Search: ")}${this.skillSearchQuery}${$}`)),Q.push(this.row(""));let Y=[...this.skillSelectedNames].join(", ")||J.fg("dim","(none)");Q.push(this.row(` ${J.fg("dim","Selected: ")}${H(Y,j-12)}`)),Q.push(this.row(""));let U=10;if(this.filteredSkills.length===0)Q.push(this.row(` ${J.fg("dim","No matching skills")}`));else{let G=0;if(this.filteredSkills.length>U)G=Math.max(0,this.skillCursorIndex-Math.floor(U/2)),G=Math.min(G,this.filteredSkills.length-U);let z=Math.min(G+U,this.filteredSkills.length);if(G>0)Q.push(this.row(` ${J.fg("dim",` ↑ ${G} more`)}`));for(let B=G;B<z;B++){let D=this.filteredSkills[B],R=B===this.skillCursorIndex,O=this.skillSelectedNames.has(D.name),V=R?J.fg("accent","→ "):" ",q=O?J.fg("success","[x]"):"[ ]",C=R?J.fg("accent",D.name):D.name,E=J.fg("dim",` [${D.source}]`),N=D.description?J.fg("dim",` - ${H(D.description,25)}`):"";Q.push(this.row(` ${V}${q} ${C}${E}${N}`))}let A=this.filteredSkills.length-z;if(A>0)Q.push(this.row(` ${J.fg("dim",` ↓ ${A} more`)}`))}let _=18;for(let G=Q.length;G<_;G++)Q.push(this.row(""));return Q.push(this.renderFooter(" [Enter] Confirm • [Space] Toggle • [Esc] Cancel ")),Q}getFooterText(){let j=this.runInBackground?"[b]g:ON":"[b]g";switch(this.mode){case"single":return` [Enter] Run • [Esc] Cancel • e m t w s ${j} `;case"parallel":return` [Enter] Run • [Esc] Cancel • e m t s ${j} • ↑↓ Nav `;case"chain":return` [Enter] Run • [Esc] Cancel • e m t w r p s ${j} • ↑↓ Nav `}}appendNotice(j){if(!this.noticeMessage)return;let J=this.noticeMessage.type==="error"?"error":"success";j.push(this.row(` ${this.theme.fg(J,this.noticeMessage.text)}`))}renderSingleMode(){let j=this.width-2,J=this.theme,Q=[],X=this.agentConfigs[0]?.name??"unknown",Z=j-4,$=` Agent: ${H(X,Z-9)} `;Q.push(this.renderHeader($)),Q.push(this.row(""));let Y=this.agentConfigs[0],U=this.getEffectiveBehavior(0),_=Y.name;Q.push(this.row(` ${J.fg("accent","▶ "+_)}`));let G=(this.templates[0]??"").split(`
10
- `)[0]??"",z=J.fg("dim","task: ");Q.push(this.row(` ${z}${H(G,j-12)}`));let A=this.getEffectiveModel(0),R=this.behaviorOverrides.get(0)?.model!==void 0?J.fg("warning",A)+J.fg("dim"," ✎"):A,O=J.fg("dim","model: ");Q.push(this.row(` ${O}${H(R,j-13)}`));let V=U.output===!1?J.fg("dim","(disabled)"):U.output||J.fg("dim","(none)"),q=J.fg("dim","writes: ");Q.push(this.row(` ${q}${H(V,j-14)}`));let C=U.skills===!1?J.fg("dim","(disabled)"):U.skills?.length?U.skills.join(", "):J.fg("dim","(none)"),E=J.fg("dim","skills: ");return Q.push(this.row(` ${E}${H(C,j-14)}`)),Q.push(this.row("")),this.appendNotice(Q),Q.push(this.renderFooter(this.getFooterText())),Q}renderParallelMode(){let j=this.width-2,J=this.theme,Q=[],X=` Parallel Tasks (${this.agentConfigs.length}) `;Q.push(this.renderHeader(X)),Q.push(this.row(""));for(let Z=0;Z<this.agentConfigs.length;Z++){let $=this.agentConfigs[Z],Y=Z===this.selectedStep,U=Y?"accent":"dim",_=Y?"▶ ":" ",G=`Task ${Z+1}: `,z=j-4-_.length-G.length,A=$.name.length>z?$.name.slice(0,z-1)+"…":$.name,B=`${G}${A}`;Q.push(this.row(` ${J.fg(U,_+B)}`));let D=(this.templates[Z]??"").split(`
11
- `)[0]??"",R=J.fg("dim","task: ");Q.push(this.row(` ${R}${H(D,j-12)}`));let O=this.getEffectiveModel(Z),C=this.behaviorOverrides.get(Z)?.model!==void 0?J.fg("warning",O)+J.fg("dim"," ✎"):O,E=J.fg("dim","model: ");Q.push(this.row(` ${E}${H(C,j-13)}`));let N=this.getEffectiveBehavior(Z),T=N.skills===!1?J.fg("dim","(disabled)"):N.skills?.length?N.skills.join(", "):J.fg("dim","(none)"),k=J.fg("dim","skills: ");Q.push(this.row(` ${k}${H(T,j-14)}`)),Q.push(this.row(""))}return this.appendNotice(Q),Q.push(this.renderFooter(this.getFooterText())),Q}renderChainMode(){let j=this.width-2,J=this.theme,Q=[],X=this.agentConfigs.map((z)=>z.name).join(" → "),Z=j-4,$=` Chain: ${H(X,Z-9)} `;Q.push(this.renderHeader($)),Q.push(this.row(""));let Y=H(this.originalTask,j-16);Q.push(this.row(` Original Task: ${Y}`));let U=H(this.chainDir??"",j-12);Q.push(this.row(` Chain Dir: ${J.fg("dim",U)}`));let _=this.agentConfigs.some((z,A)=>this.getEffectiveBehavior(A).progress),G=_?J.fg("success","enabled"):J.fg("dim","disabled");Q.push(this.row(` Progress: ${G} ${J.fg("dim","(press [p] to toggle)")}`)),Q.push(this.row(""));for(let z=0;z<this.agentConfigs.length;z++){let A=this.agentConfigs[z],B=z===this.selectedStep,D=this.getEffectiveBehavior(z),R=B?"accent":"dim",O=B?"▶ ":" ",V=`Step ${z+1}: `,q=j-4-O.length-V.length,C=A.name.length>q?A.name.slice(0,q-1)+"…":A.name,E=`${V}${C}`;Q.push(this.row(` ${J.fg(R,O+E)}`));let T=((this.templates[z]??"").split(`
12
- `)[0]??"").replace(/\{task\}/g,J.fg("success","{task}")).replace(/\{previous\}/g,J.fg("warning","{previous}")).replace(/\{chain_dir\}/g,J.fg("accent","{chain_dir}")),k=J.fg("dim","task: ");Q.push(this.row(` ${k}${H(T,j-12)}`));let w=this.getEffectiveModel(z),o=this.behaviorOverrides.get(z)?.model!==void 0?J.fg("warning",w)+J.fg("dim"," ✎"):w,l=J.fg("dim","model: ");Q.push(this.row(` ${l}${H(o,j-13)}`));let d=D.output===!1?J.fg("dim","(disabled)"):D.output||J.fg("dim","(none)"),i=J.fg("dim","writes: ");Q.push(this.row(` ${i}${H(d,j-14)}`));let r=D.reads===!1?J.fg("dim","(disabled)"):D.reads&&D.reads.length>0?D.reads.join(", "):J.fg("dim","(none)"),s=J.fg("dim","reads: ");Q.push(this.row(` ${s}${H(r,j-13)}`));let a=D.skills===!1?J.fg("dim","(disabled)"):D.skills?.length?D.skills.join(", "):J.fg("dim","(none)"),t=J.fg("dim","skills: ");if(Q.push(this.row(` ${t}${H(a,j-14)}`)),_){let y=z===0?J.fg("success","writes progress.md"):J.fg("accent","reads progress.md"),jj=J.fg("dim","progress: ");Q.push(this.row(` ${jj}${y}`))}if(z<this.agentConfigs.length-1){if((this.templates[z+1]??"").includes("{previous}")){let y=J.fg("dim"," ↳ response → ")+J.fg("warning","{previous}");Q.push(this.row(y))}}Q.push(this.row(""))}return this.appendNotice(Q),Q.push(this.renderFooter(this.getFooterText())),Q}invalidate(){}dispose(){if(this.noticeMessageTimer)clearTimeout(this.noticeMessageTimer);this.noticeMessageTimer=null}}export{Fj as ChainClarifyComponent};
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
+ }