@bastani/atomic 0.9.21-alpha.1 → 0.9.21

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 (516) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/package.json +1 -1
  4. package/dist/builtin/subagents/CHANGELOG.md +22 -0
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/subagents/src/extension/index.bundle.mjs +292 -60
  7. package/dist/builtin/web-access/package.json +1 -1
  8. package/dist/builtin/workflows/CHANGELOG.md +23 -0
  9. package/dist/builtin/workflows/builtin/adversarial-verification.js +3 -3
  10. package/dist/builtin/workflows/builtin/{chunk-cw86srkf.js → chunk-632fxeb8.js} +1 -1
  11. package/dist/builtin/workflows/builtin/{chunk-w18kbz63.js → chunk-94f8zfz1.js} +1 -1
  12. package/dist/builtin/workflows/builtin/{chunk-kspvwc24.js → chunk-9cm2ckq2.js} +1 -1
  13. package/dist/builtin/workflows/builtin/{chunk-jaj27rqc.js → chunk-a1ar035d.js} +1 -1
  14. package/dist/builtin/workflows/builtin/{chunk-wh19f5ee.js → chunk-d3xhj946.js} +5 -4
  15. package/dist/builtin/workflows/builtin/{chunk-crw7q5g1.js → chunk-gyjck9z8.js} +1 -1
  16. package/dist/builtin/workflows/builtin/{chunk-maqv731g.js → chunk-hj8mh07f.js} +10 -6
  17. package/dist/builtin/workflows/builtin/{chunk-0nrgfbag.js → chunk-kb7s3gx2.js} +1 -1
  18. package/dist/builtin/workflows/builtin/{chunk-73c5tayt.js → chunk-kgn5wz1c.js} +19 -1
  19. package/dist/builtin/workflows/builtin/{chunk-2hak3b7g.js → chunk-nkj4qhj6.js} +1 -1
  20. package/dist/builtin/workflows/builtin/{chunk-bzdvx2xr.js → chunk-r97ndfvt.js} +1 -1
  21. package/dist/builtin/workflows/builtin/{chunk-vkmpdat4.js → chunk-wf876n16.js} +1 -1
  22. package/dist/builtin/workflows/builtin/classify-and-act.js +3 -3
  23. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -3
  24. package/dist/builtin/workflows/builtin/generate-and-filter.js +3 -3
  25. package/dist/builtin/workflows/builtin/goal.js +4 -4
  26. package/dist/builtin/workflows/builtin/index.js +12 -12
  27. package/dist/builtin/workflows/builtin/loop-until-done.js +3 -3
  28. package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
  29. package/dist/builtin/workflows/builtin/ralph.js +4 -4
  30. package/dist/builtin/workflows/builtin/steering-context.js +1 -1
  31. package/dist/builtin/workflows/builtin/tournament.js +3 -3
  32. package/dist/builtin/workflows/package.json +1 -1
  33. package/dist/builtin/workflows/src/extension/index.bundle.mjs +40 -11
  34. package/dist/builtin/workflows/src/index.js +9 -3
  35. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +6 -1
  36. package/dist/cli/auth-command.js +5 -0
  37. package/dist/cli/auth-command.js.map +1 -1
  38. package/dist/cli/credential-print.js +2 -0
  39. package/dist/cli/credential-print.js.map +1 -1
  40. package/dist/cli/experimental/command.js +5 -2
  41. package/dist/cli/experimental/command.js.map +1 -1
  42. package/dist/cli.js +1 -1
  43. package/dist/cli.js.map +1 -1
  44. package/dist/config.d.ts +4 -4
  45. package/dist/config.js +4 -4
  46. package/dist/config.js.map +1 -1
  47. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  48. package/dist/core/agent-session-extension-bindings.js +9 -4
  49. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  50. package/dist/core/agent-session-methods.d.ts +4 -4
  51. package/dist/core/agent-session-methods.d.ts.map +1 -1
  52. package/dist/core/agent-session-methods.js.map +1 -1
  53. package/dist/core/agent-session-prompt.d.ts +4 -4
  54. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  55. package/dist/core/agent-session-prompt.js +38 -15
  56. package/dist/core/agent-session-prompt.js.map +1 -1
  57. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  58. package/dist/core/agent-session-runtime.js +14 -9
  59. package/dist/core/agent-session-runtime.js.map +1 -1
  60. package/dist/core/agent-session-types.d.ts +4 -1
  61. package/dist/core/agent-session-types.d.ts.map +1 -1
  62. package/dist/core/agent-session-types.js.map +1 -1
  63. package/dist/core/agent-session.d.ts +1 -1
  64. package/dist/core/agent-session.d.ts.map +1 -1
  65. package/dist/core/agent-session.js +140 -95
  66. package/dist/core/agent-session.js.map +1 -1
  67. package/dist/core/auth-storage-backends.js +2 -3
  68. package/dist/core/auth-storage-backends.js.map +1 -1
  69. package/dist/core/auth-storage.js +4 -1
  70. package/dist/core/auth-storage.js.map +1 -1
  71. package/dist/core/builtin-resource-loader.js +9 -0
  72. package/dist/core/builtin-resource-loader.js.map +1 -1
  73. package/dist/core/cache-warmer.js +8 -1
  74. package/dist/core/cache-warmer.js.map +1 -1
  75. package/dist/core/compaction/range-planner.js +6 -0
  76. package/dist/core/compaction/range-planner.js.map +1 -1
  77. package/dist/core/execution-model-router.d.ts +13 -3
  78. package/dist/core/execution-model-router.d.ts.map +1 -1
  79. package/dist/core/execution-model-router.js +227 -131
  80. package/dist/core/execution-model-router.js.map +1 -1
  81. package/dist/core/export-html/template-js/entries-navigation.js +16 -6
  82. package/dist/core/export-html/template-js/initialization.js +34 -11
  83. package/dist/core/export-html/template.css +10 -0
  84. package/dist/core/export-html/template.js +50 -17
  85. package/dist/core/extensions/context-types.d.ts +2 -0
  86. package/dist/core/extensions/context-types.d.ts.map +1 -1
  87. package/dist/core/extensions/context-types.js.map +1 -1
  88. package/dist/core/extensions/host-input.js +8 -4
  89. package/dist/core/extensions/host-input.js.map +1 -1
  90. package/dist/core/extensions/reactive-widget.js +1 -0
  91. package/dist/core/extensions/reactive-widget.js.map +1 -1
  92. package/dist/core/extensions/runner-context.d.ts +1 -0
  93. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  94. package/dist/core/extensions/runner-context.js +4 -0
  95. package/dist/core/extensions/runner-context.js.map +1 -1
  96. package/dist/core/extensions/runner.d.ts +1 -0
  97. package/dist/core/extensions/runner.d.ts.map +1 -1
  98. package/dist/core/extensions/runner.js +48 -30
  99. package/dist/core/extensions/runner.js.map +1 -1
  100. package/dist/core/extensions/runtime-types.d.ts +1 -0
  101. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  102. package/dist/core/extensions/runtime-types.js.map +1 -1
  103. package/dist/core/extensions/workflow-activity-hub.js +9 -7
  104. package/dist/core/extensions/workflow-activity-hub.js.map +1 -1
  105. package/dist/core/footer-data-provider.js +24 -23
  106. package/dist/core/footer-data-provider.js.map +1 -1
  107. package/dist/core/keybindings.js +1 -0
  108. package/dist/core/keybindings.js.map +1 -1
  109. package/dist/core/mandatory-resource-loader.js +4 -1
  110. package/dist/core/mandatory-resource-loader.js.map +1 -1
  111. package/dist/core/model-config.js +2 -0
  112. package/dist/core/model-config.js.map +1 -1
  113. package/dist/core/model-registry.js +1 -0
  114. package/dist/core/model-registry.js.map +1 -1
  115. package/dist/core/model-resolver-defaults.js +1 -1
  116. package/dist/core/model-resolver-defaults.js.map +1 -1
  117. package/dist/core/{model-routing-task.d.ts → model-routing-bytes.d.ts} +1 -4
  118. package/dist/core/model-routing-bytes.d.ts.map +1 -0
  119. package/dist/core/model-routing-bytes.js +33 -0
  120. package/dist/core/model-routing-bytes.js.map +1 -0
  121. package/dist/core/model-routing-candidates.d.ts +42 -0
  122. package/dist/core/model-routing-candidates.d.ts.map +1 -0
  123. package/dist/core/model-routing-candidates.js +309 -0
  124. package/dist/core/model-routing-candidates.js.map +1 -0
  125. package/dist/core/model-routing-constraints.d.ts +4 -0
  126. package/dist/core/model-routing-constraints.d.ts.map +1 -1
  127. package/dist/core/model-routing-constraints.js +13 -1
  128. package/dist/core/model-routing-constraints.js.map +1 -1
  129. package/dist/core/model-routing-debug.d.ts +9 -0
  130. package/dist/core/model-routing-debug.d.ts.map +1 -0
  131. package/dist/core/model-routing-debug.js +14 -0
  132. package/dist/core/model-routing-debug.js.map +1 -0
  133. package/dist/core/model-routing-evals.d.ts +50 -0
  134. package/dist/core/model-routing-evals.d.ts.map +1 -0
  135. package/dist/core/model-routing-evals.js +190 -0
  136. package/dist/core/model-routing-evals.js.map +1 -0
  137. package/dist/core/model-routing-needs.d.ts +75 -0
  138. package/dist/core/model-routing-needs.d.ts.map +1 -0
  139. package/dist/core/model-routing-needs.js +176 -0
  140. package/dist/core/model-routing-needs.js.map +1 -0
  141. package/dist/core/model-runtime-streaming.js +3 -0
  142. package/dist/core/model-runtime-streaming.js.map +1 -1
  143. package/dist/core/model-runtime.js +26 -14
  144. package/dist/core/model-runtime.js.map +1 -1
  145. package/dist/core/models-store.js +2 -3
  146. package/dist/core/models-store.js.map +1 -1
  147. package/dist/core/output-guard.js +1 -0
  148. package/dist/core/output-guard.js.map +1 -1
  149. package/dist/core/package-manager-paths.d.ts +2 -1
  150. package/dist/core/package-manager-paths.d.ts.map +1 -1
  151. package/dist/core/package-manager-paths.js +4 -3
  152. package/dist/core/package-manager-paths.js.map +1 -1
  153. package/dist/core/package-manager.js +1 -0
  154. package/dist/core/package-manager.js.map +1 -1
  155. package/dist/core/resource-loader-assets.d.ts.map +1 -1
  156. package/dist/core/resource-loader-assets.js +9 -7
  157. package/dist/core/resource-loader-assets.js.map +1 -1
  158. package/dist/core/resource-loader-core.js +49 -0
  159. package/dist/core/resource-loader-core.js.map +1 -1
  160. package/dist/core/runtime-credentials.js +2 -1
  161. package/dist/core/runtime-credentials.js.map +1 -1
  162. package/dist/core/session-cwd.js +1 -0
  163. package/dist/core/session-cwd.js.map +1 -1
  164. package/dist/core/session-manager-archive.d.ts.map +1 -1
  165. package/dist/core/session-manager-archive.js +4 -2
  166. package/dist/core/session-manager-archive.js.map +1 -1
  167. package/dist/core/session-manager-core.js +11 -7
  168. package/dist/core/session-manager-core.js.map +1 -1
  169. package/dist/core/session-manager-storage.d.ts +10 -4
  170. package/dist/core/session-manager-storage.d.ts.map +1 -1
  171. package/dist/core/session-manager-storage.js +12 -6
  172. package/dist/core/session-manager-storage.js.map +1 -1
  173. package/dist/core/settings-manager-basic-accessors.d.ts +2 -1
  174. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  175. package/dist/core/settings-manager-basic-accessors.js +21 -0
  176. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  177. package/dist/core/settings-manager-core.js +13 -7
  178. package/dist/core/settings-manager-core.js.map +1 -1
  179. package/dist/core/settings-manager.d.ts +1 -1
  180. package/dist/core/settings-manager.d.ts.map +1 -1
  181. package/dist/core/settings-manager.js.map +1 -1
  182. package/dist/core/settings-storage.js +6 -0
  183. package/dist/core/settings-storage.js.map +1 -1
  184. package/dist/core/settings-types.d.ts +8 -0
  185. package/dist/core/settings-types.d.ts.map +1 -1
  186. package/dist/core/settings-types.js.map +1 -1
  187. package/dist/core/structured-output/index.d.ts.map +1 -1
  188. package/dist/core/structured-output/index.js +4 -1
  189. package/dist/core/structured-output/index.js.map +1 -1
  190. package/dist/core/structured-output/invalid-output.js +1 -0
  191. package/dist/core/structured-output/invalid-output.js.map +1 -1
  192. package/dist/core/tasks/agent-adapter.js +5 -3
  193. package/dist/core/tasks/agent-adapter.js.map +1 -1
  194. package/dist/core/tasks/child-command-owner.js +3 -7
  195. package/dist/core/tasks/child-command-owner.js.map +1 -1
  196. package/dist/core/tasks/completion.js +5 -1
  197. package/dist/core/tasks/completion.js.map +1 -1
  198. package/dist/core/tasks/owner-store.js +12 -8
  199. package/dist/core/tasks/owner-store.js.map +1 -1
  200. package/dist/core/tasks/supervisor.js +14 -35
  201. package/dist/core/tasks/supervisor.js.map +1 -1
  202. package/dist/core/tools/ask-user-question/state/build-questionnaire.js +13 -4
  203. package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
  204. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +11 -1
  205. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  206. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +1 -0
  207. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
  208. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js +1 -0
  209. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
  210. package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
  211. package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
  212. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js +5 -0
  213. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
  214. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js +2 -0
  215. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
  216. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js +13 -8
  217. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js.map +1 -1
  218. package/dist/core/tools/ask-user-question/view/components/submit-picker.js +1 -0
  219. package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
  220. package/dist/core/tools/ask-user-question/view/components/tab-bar.js +1 -0
  221. package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
  222. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +30 -24
  223. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  224. package/dist/core/tools/ask-user-question/view/dialog-builder.js +5 -0
  225. package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
  226. package/dist/core/tools/ask-user-question/view/props-adapter.js +8 -0
  227. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  228. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js +4 -4
  229. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
  230. package/dist/core/tools/bash.js +5 -8
  231. package/dist/core/tools/bash.js.map +1 -1
  232. package/dist/core/tools/edit-batch.js +4 -0
  233. package/dist/core/tools/edit-batch.js.map +1 -1
  234. package/dist/core/tools/edit.js +2 -0
  235. package/dist/core/tools/edit.js.map +1 -1
  236. package/dist/core/tools/file-mutation-coordinator.js +9 -0
  237. package/dist/core/tools/file-mutation-coordinator.js.map +1 -1
  238. package/dist/core/tools/find.js +1 -1
  239. package/dist/core/tools/find.js.map +1 -1
  240. package/dist/core/tools/hashline-engine/fs.js +1 -1
  241. package/dist/core/tools/hashline-engine/fs.js.map +1 -1
  242. package/dist/core/tools/hashline-engine/input.js +4 -0
  243. package/dist/core/tools/hashline-engine/input.js.map +1 -1
  244. package/dist/core/tools/hashline-engine/mismatch.js +6 -0
  245. package/dist/core/tools/hashline-engine/mismatch.js.map +1 -1
  246. package/dist/core/tools/hashline-engine/patcher.js +13 -0
  247. package/dist/core/tools/hashline-engine/patcher.js.map +1 -1
  248. package/dist/core/tools/hashline-engine/recovery.js +1 -0
  249. package/dist/core/tools/hashline-engine/recovery.js.map +1 -1
  250. package/dist/core/tools/output-accumulator.js +20 -13
  251. package/dist/core/tools/output-accumulator.js.map +1 -1
  252. package/dist/core/tools/persisted-output-file.js +9 -3
  253. package/dist/core/tools/persisted-output-file.js.map +1 -1
  254. package/dist/core/tools/resource-selectors.js +1 -0
  255. package/dist/core/tools/resource-selectors.js.map +1 -1
  256. package/dist/core/tools/write.js +1 -0
  257. package/dist/core/tools/write.js.map +1 -1
  258. package/dist/core/trust-manager.js +1 -0
  259. package/dist/core/trust-manager.js.map +1 -1
  260. package/dist/core/workflow-stage-admission.js +17 -10
  261. package/dist/core/workflow-stage-admission.js.map +1 -1
  262. package/dist/extensions/llama/client.js +2 -0
  263. package/dist/extensions/llama/client.js.map +1 -1
  264. package/dist/extensions/llama/huggingface-ui.js +17 -9
  265. package/dist/extensions/llama/huggingface-ui.js.map +1 -1
  266. package/dist/extensions/llama/huggingface.js +2 -0
  267. package/dist/extensions/llama/huggingface.js.map +1 -1
  268. package/dist/extensions/llama/ui.js +11 -3
  269. package/dist/extensions/llama/ui.js.map +1 -1
  270. package/dist/index.d.ts +4 -2
  271. package/dist/index.d.ts.map +1 -1
  272. package/dist/index.js +3 -1
  273. package/dist/index.js.map +1 -1
  274. package/dist/modes/interactive/components/armin.js +10 -6
  275. package/dist/modes/interactive/components/armin.js.map +1 -1
  276. package/dist/modes/interactive/components/assistant-message.js +10 -2
  277. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  278. package/dist/modes/interactive/components/atomic-working-status.js +10 -2
  279. package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
  280. package/dist/modes/interactive/components/bash-execution.js +9 -4
  281. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  282. package/dist/modes/interactive/components/bordered-loader.js +3 -0
  283. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  284. package/dist/modes/interactive/components/branch-summary-message.js +4 -1
  285. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  286. package/dist/modes/interactive/components/chat-message-renderer.js +2 -1
  287. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  288. package/dist/modes/interactive/components/chat-session-host-state.js +63 -31
  289. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  290. package/dist/modes/interactive/components/chat-session-host.js +8 -1
  291. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  292. package/dist/modes/interactive/components/chat-transcript.js +24 -14
  293. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  294. package/dist/modes/interactive/components/compaction-boundary-message.js +2 -1
  295. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  296. package/dist/modes/interactive/components/config-selector-list.js +15 -6
  297. package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
  298. package/dist/modes/interactive/components/config-selector.js +7 -1
  299. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  300. package/dist/modes/interactive/components/countdown-timer.js +2 -0
  301. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  302. package/dist/modes/interactive/components/custom-editor.js +21 -1
  303. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  304. package/dist/modes/interactive/components/custom-entry.js +4 -1
  305. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  306. package/dist/modes/interactive/components/custom-message.js +9 -1
  307. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  308. package/dist/modes/interactive/components/daxnuts.js +8 -6
  309. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  310. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  311. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  312. package/dist/modes/interactive/components/extension-editor.js +7 -1
  313. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  314. package/dist/modes/interactive/components/extension-input.js +8 -2
  315. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  316. package/dist/modes/interactive/components/extension-selector.js +9 -1
  317. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  318. package/dist/modes/interactive/components/first-time-setup.js +4 -2
  319. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  320. package/dist/modes/interactive/components/footer.js +5 -2
  321. package/dist/modes/interactive/components/footer.js.map +1 -1
  322. package/dist/modes/interactive/components/host-input-form.js +13 -2
  323. package/dist/modes/interactive/components/host-input-form.js.map +1 -1
  324. package/dist/modes/interactive/components/login-dialog.js +9 -3
  325. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  326. package/dist/modes/interactive/components/model-selector.js +24 -12
  327. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  328. package/dist/modes/interactive/components/oauth-selector.js +12 -3
  329. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  330. package/dist/modes/interactive/components/reserved-bottom-overlay.js +11 -2
  331. package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
  332. package/dist/modes/interactive/components/scoped-models-selector.js +13 -8
  333. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  334. package/dist/modes/interactive/components/scroll-widget.js +4 -0
  335. package/dist/modes/interactive/components/scroll-widget.js.map +1 -1
  336. package/dist/modes/interactive/components/session-selector-header.js +11 -7
  337. package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
  338. package/dist/modes/interactive/components/session-selector-list.js +25 -12
  339. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  340. package/dist/modes/interactive/components/session-selector.js +23 -15
  341. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  342. package/dist/modes/interactive/components/settings-selector-submenus.js +19 -1
  343. package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
  344. package/dist/modes/interactive/components/settings-selector.js +1 -0
  345. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  346. package/dist/modes/interactive/components/show-images-selector.js +1 -0
  347. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  348. package/dist/modes/interactive/components/skill-invocation-message.js +4 -1
  349. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  350. package/dist/modes/interactive/components/startup-identity.js +8 -3
  351. package/dist/modes/interactive/components/startup-identity.js.map +1 -1
  352. package/dist/modes/interactive/components/task-completion-message.js +2 -0
  353. package/dist/modes/interactive/components/task-completion-message.js.map +1 -1
  354. package/dist/modes/interactive/components/task-detail.js +2 -0
  355. package/dist/modes/interactive/components/task-detail.js.map +1 -1
  356. package/dist/modes/interactive/components/task-inspector.js +22 -12
  357. package/dist/modes/interactive/components/task-inspector.js.map +1 -1
  358. package/dist/modes/interactive/components/task-list.js +2 -0
  359. package/dist/modes/interactive/components/task-list.js.map +1 -1
  360. package/dist/modes/interactive/components/task-live-transcript.js +8 -3
  361. package/dist/modes/interactive/components/task-live-transcript.js.map +1 -1
  362. package/dist/modes/interactive/components/task-navigation.js +5 -2
  363. package/dist/modes/interactive/components/task-navigation.js.map +1 -1
  364. package/dist/modes/interactive/components/task-row.js +2 -0
  365. package/dist/modes/interactive/components/task-row.js.map +1 -1
  366. package/dist/modes/interactive/components/theme-selector.js +2 -0
  367. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  368. package/dist/modes/interactive/components/thinking-selector.js +7 -1
  369. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  370. package/dist/modes/interactive/components/tool-execution.js +25 -10
  371. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  372. package/dist/modes/interactive/components/transcript-follow-indicator.js +1 -0
  373. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
  374. package/dist/modes/interactive/components/tree-selector-component.js +7 -3
  375. package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
  376. package/dist/modes/interactive/components/tree-selector-help.js +1 -0
  377. package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
  378. package/dist/modes/interactive/components/tree-selector-label-input.js +6 -2
  379. package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
  380. package/dist/modes/interactive/components/tree-selector-list.js +4 -0
  381. package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
  382. package/dist/modes/interactive/components/trust-selector.js +6 -0
  383. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  384. package/dist/modes/interactive/components/user-message-selector.js +6 -3
  385. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  386. package/dist/modes/interactive/components/user-message.js +5 -0
  387. package/dist/modes/interactive/components/user-message.js.map +1 -1
  388. package/dist/modes/interactive/components/working-status.js +1 -0
  389. package/dist/modes/interactive/components/working-status.js.map +1 -1
  390. package/dist/modes/interactive/interactive-autocomplete.js +2 -0
  391. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  392. package/dist/modes/interactive/interactive-extension-runtime.js +1 -0
  393. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  394. package/dist/modes/interactive/interactive-mode-base.js +162 -120
  395. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  396. package/dist/modes/interactive/interactive-mode-helpers.js +3 -0
  397. package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -1
  398. package/dist/modes/interactive/interactive-mode-surface.d.ts +0 -6
  399. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  400. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  401. package/dist/modes/interactive/interactive-resource-disclosure.js +0 -4
  402. package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -1
  403. package/dist/modes/interactive/interactive-resource-rendering.js +0 -12
  404. package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -1
  405. package/dist/modes/interactive/interactive-startup-chat-container.js +1 -4
  406. package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
  407. package/dist/modes/interactive/model-catalog-refresh.js +1 -3
  408. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -1
  409. package/dist/modes/interactive/theme/color-utils.d.ts +5 -0
  410. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  411. package/dist/modes/interactive/theme/color-utils.js +11 -0
  412. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  413. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  414. package/dist/modes/interactive/theme/global-theme.js +4 -3
  415. package/dist/modes/interactive/theme/global-theme.js.map +1 -1
  416. package/dist/modes/interactive/theme/theme-class.js +7 -0
  417. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  418. package/dist/modes/interactive/theme/theme-controller.js +9 -2
  419. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  420. package/dist/modes/interactive-engine/activity-watchdog.js +8 -3
  421. package/dist/modes/interactive-engine/activity-watchdog.js.map +1 -1
  422. package/dist/modes/interactive-engine/engine-custom-ui.js +12 -8
  423. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  424. package/dist/modes/interactive-engine/engine-dialog-host.js +7 -3
  425. package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
  426. package/dist/modes/interactive-engine/engine-health.js +23 -13
  427. package/dist/modes/interactive-engine/engine-health.js.map +1 -1
  428. package/dist/modes/interactive-engine/engine-input-form.js +3 -2
  429. package/dist/modes/interactive-engine/engine-input-form.js.map +1 -1
  430. package/dist/modes/interactive-engine/engine-monitor.js +13 -1
  431. package/dist/modes/interactive-engine/engine-monitor.js.map +1 -1
  432. package/dist/modes/interactive-engine/engine-project-trust.js +2 -1
  433. package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -1
  434. package/dist/modes/interactive-engine/engine-render-service.js +7 -4
  435. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  436. package/dist/modes/interactive-engine/engine-session-picker.js +3 -2
  437. package/dist/modes/interactive-engine/engine-session-picker.js.map +1 -1
  438. package/dist/modes/interactive-engine/input-form-host.js +5 -1
  439. package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
  440. package/dist/modes/interactive-engine/isolated-runtime.js +37 -23
  441. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  442. package/dist/modes/interactive-engine/remote-command-catalog.js +4 -3
  443. package/dist/modes/interactive-engine/remote-command-catalog.js.map +1 -1
  444. package/dist/modes/interactive-engine/remote-component.js +24 -12
  445. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  446. package/dist/modes/interactive-engine/remote-frame-clamp.js +3 -3
  447. package/dist/modes/interactive-engine/remote-frame-clamp.js.map +1 -1
  448. package/dist/modes/interactive-engine/remote-model-catalog.js +5 -4
  449. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  450. package/dist/modes/interactive-engine/remote-queue-pause.js +3 -1
  451. package/dist/modes/interactive-engine/remote-queue-pause.js.map +1 -1
  452. package/dist/modes/interactive-engine/remote-renderer.js +24 -13
  453. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  454. package/dist/modes/interactive-engine/resource-readiness-error.js +1 -0
  455. package/dist/modes/interactive-engine/resource-readiness-error.js.map +1 -1
  456. package/dist/modes/interactive-engine/session-picker-host.js +5 -1
  457. package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
  458. package/dist/modes/interactive-engine/terminal-mode-controller.js +2 -1
  459. package/dist/modes/interactive-engine/terminal-mode-controller.js.map +1 -1
  460. package/dist/modes/rpc/queued-writer.js +13 -4
  461. package/dist/modes/rpc/queued-writer.js.map +1 -1
  462. package/dist/modes/rpc/rpc-bash-request-owners.js +2 -1
  463. package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
  464. package/dist/modes/rpc/rpc-client-api.d.ts +8 -4
  465. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  466. package/dist/modes/rpc/rpc-client-api.js +10 -3
  467. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  468. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  469. package/dist/modes/rpc/rpc-client.js +35 -22
  470. package/dist/modes/rpc/rpc-client.js.map +1 -1
  471. package/dist/modes/rpc/rpc-command-handler.js +6 -6
  472. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  473. package/dist/modes/rpc/rpc-event-buffer.js +3 -1
  474. package/dist/modes/rpc/rpc-event-buffer.js.map +1 -1
  475. package/dist/modes/rpc/rpc-generation-buffer.js +1 -3
  476. package/dist/modes/rpc/rpc-generation-buffer.js.map +1 -1
  477. package/dist/modes/rpc/rpc-keybindings-reload.js +4 -1
  478. package/dist/modes/rpc/rpc-keybindings-reload.js.map +1 -1
  479. package/dist/modes/rpc/rpc-output-buffer.js +3 -4
  480. package/dist/modes/rpc/rpc-output-buffer.js.map +1 -1
  481. package/dist/modes/rpc/rpc-pending-requests.js +1 -3
  482. package/dist/modes/rpc/rpc-pending-requests.js.map +1 -1
  483. package/dist/modes/rpc/rpc-provider-auth.js +3 -1
  484. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  485. package/dist/modes/rpc/rpc-resource-readiness.js +4 -5
  486. package/dist/modes/rpc/rpc-resource-readiness.js.map +1 -1
  487. package/dist/modes/rpc/rpc-session-binding.js +15 -0
  488. package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
  489. package/dist/modes/rpc/rpc-terminal-drain.js +3 -0
  490. package/dist/modes/rpc/rpc-terminal-drain.js.map +1 -1
  491. package/dist/modes/rpc/rpc-types.d.ts +10 -1
  492. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  493. package/dist/modes/rpc/rpc-types.js.map +1 -1
  494. package/docs/models/evals.md +883 -39
  495. package/docs/models/model-selection.md +7 -8
  496. package/docs/rpc/examples.md +1 -1
  497. package/docs/rpc/protocol.md +9 -3
  498. package/docs/sdk/structured-decisions.md +1 -1
  499. package/docs/sdk.md +3 -3
  500. package/docs/settings.md +24 -3
  501. package/docs/subagents/reference.md +22 -4
  502. package/docs/subagents.md +2 -0
  503. package/docs/usage.md +3 -3
  504. package/docs/workflows/api-reference.md +1 -1
  505. package/docs/workflows/authoring.md +1 -7
  506. package/docs/workflows/builtins.md +1 -1
  507. package/docs/workflows/reliable-design.md +1 -1
  508. package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
  509. package/examples/extensions/gondolin/package.json +1 -1
  510. package/examples/rpc-client.ts +1 -1
  511. package/examples/rpc-extension-ui.ts +1 -1
  512. package/npm-shrinkwrap.json +70 -33
  513. package/package.json +6 -7
  514. package/dist/core/model-routing-task.d.ts.map +0 -1
  515. package/dist/core/model-routing-task.js +0 -120
  516. package/dist/core/model-routing-task.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"wrapping-select.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/view/components/wrapping-select.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AA+C5D,MAAM,OAAO,cAAc;aACF,mBAAc,GAAG,IAAI,AAAP,CAAQ;aACtB,qBAAgB,GAAG,IAAI,AAAP,CAAQ;aACxB,qBAAgB,GAAG,IAAI,AAAP,CAAQ;aACxB,yBAAoB,GAAG,SAAS,AAAZ,CAAa;aACjC,uBAAkB,GAAG,SAAS,AAAZ,CAAa;aAC/B,mBAAc,GAAG,IAAI,AAAP,CAAQ;aACtB,sBAAiB,GAAG,CAAC,AAAJ,CAAK;IA2B9C,YACC,KAAoC,EACpC,UAAkB,EAClB,KAA0B,EAC1B,OAAO,GAA0B,EAAE;QAtB5B,kBAAa,GAAG,CAAC,CAAC;QAClB,YAAO,GAAG,IAAI,CAAC;QACf,gBAAW,GAAG,EAAE,CAAC;QACjB,gBAAW,GAAuB,SAAS,CAAC;QACpD;;;;;WAKG;QACK,mBAAc,GAAuB,SAAS,CAAC;QACvD;;;;WAIG;QACK,2BAAsB,GAAuB,SAAS,CAAC;QAQ9D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,KAAK,KAAK,CAAC;QAC/D,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,CAAC,CAAC;QACxD,IAAI,CAAC,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,IAAI,KAAK,CAAC,MAAM,CAAC;IAC9E,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,iBAAyB,EAAE,sBAA8B;QACrE,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;IACnE,CAAC;IAED,gBAAgB,CAAC,KAAa;QAC7B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,UAAU,CAAC,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED;;;;;OAKG;IACH,iBAAiB,CAAC,KAAyB,EAAE,aAAsB;QAClE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;YAChC,IAAI,CAAC,sBAAsB,GAAG,SAAS,CAAC;YACxC,OAAO;QACR,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC1E,IAAI,CAAC,sBAAsB,GAAG,aAAa,CAAC;IAC7C,CAAC;IAED,cAAc,CAAC,IAAY;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;YAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAChG,CAAC;IAED,cAAc,CAAC,MAAc;QAC5B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC;IAED,oEAAoE;IACpE,WAAW,CAAC,KAAa,IAAS,CAAC;IAEnC,UAAU,KAAU,CAAC;IAErB,MAAM,CAAC,KAAa;QACnB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEvC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC7D,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5E,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,MAAM,QAAQ,GAAG,CAAC,KAAK,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,OAAO,CAAC;YAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;YACzE,yEAAyE;YACzE,uEAAuE;YACvE,IAAI,QAAQ,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,yBAAyB,EAAE,CAAC;YACpE,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;QAC1B,CAAC;QAED,IAAI,IAAI,CAAC,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;YACtD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAEO,oBAAoB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,GAAG,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACzG,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3E,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IACjC,CAAC;IAEO,qBAAqB,CAAC,UAAkB,EAAE,QAAgB;QACjE,OAAO,UAAU,GAAG,CAAC,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IACvD,CAAC;IAEO,UAAU,CACjB,IAAwB,EACxB,KAAa,EACb,QAAiB,EACjB,KAAa,EACb,WAAmB;QAEnB,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QACpE,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,iBAAiB,EAAE,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;QAEjG,IAAI,IAAI,CAAC,yBAAyB,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAC/E,CAAC;QAED,qFAAqF;QACrF,sFAAsF;QACtF,oFAAoF;QACpF,kFAAkF;QAClF,wFAAwF;QACxF,uGAAuG;QACvG,MAAM,WAAW,GAAG,KAAK,KAAK,IAAI,CAAC,cAAc,CAAC;QAClD,MAAM,KAAK,GAAG,WAAW;YACxB,CAAC,CAAC,GAAG,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,KAAK,GAAG,cAAc,CAAC,cAAc,EAAE;YAChF,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACd,MAAM,kBAAkB,GAAG,QAAQ,IAAI,WAAW,CAAC;QAEnD,OAAO;YACN,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,CAAC;YAChG,GAAG,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,EAAE,YAAY,CAAC;SAClF,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,KAAa,EAAE,QAAiB,EAAE,WAAmB;QAC3E,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC;QAC3F,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,GAAG,KAAK,GAAG,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACtE,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,cAAc,CAAC,gBAAgB,EAAE,CAAC;IACtE,CAAC;IAEO,yBAAyB,CAAC,IAAwB,EAAE,QAAiB;QAC5E,OAAO,IAAI,CAAC,kBAAkB,IAAI,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC;IAC7F,CAAC;IAED;;;;;;;;OAQG;IACK,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B,EAAE,YAAoB;QAC/F,MAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACpD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC;YAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,mBAAmB;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClF,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACf,OAAO,GAAG,MAAM,GAAG,cAAc,CAAC,oBAAoB,IAAI,cAAc,CAAC,kBAAkB,EAAE,CAAC;QAC/F,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,GAAG,MAAM,GAAG,cAAc,CAAC,oBAAoB,GAAG,EAAE,GAAG,cAAc,CAAC,kBAAkB,GAAG,IAAI,EAAE,CAAC;IAC1G,CAAC;IAEO,gBAAgB,CAAC,MAAc;QACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QAC7D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,CAAC;IAEO,gBAAgB,CACvB,KAAa,EACb,SAAiB,EACjB,kBAA0B,EAC1B,YAAoB,EACpB,kBAA2B;QAE3B,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;QACtD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC;YAC5D,MAAM,IAAI,GAAG,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC;YACnC,OAAO,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClE,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,sBAAsB,CAC7B,WAA+B,EAC/B,kBAA0B,EAC1B,YAAoB;QAEpB,IAAI,CAAC,WAAW;YAAE,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,gBAAgB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAC5D,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,kBAAkB,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC;CACD","sourcesContent":["import type { Component } from \"@earendil-works/pi-tui\";\nimport { visibleWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport { OVERLAY_ACTIVE_ROW_MARKER } from \"../../../../extensions/ui-types.js\";\nimport { ROW_INTENT_META } from \"../../state/row-intent.ts\";\n\n/**\n * Row-intent discriminated union. `kind` is the single discriminator —\n * pre-1.0.3 boolean flags have been removed (see `banned-flags.test.ts`).\n * Modeled after `QuestionnaireAction` (`key-router.ts:13-32`) and `Effect`\n * (`state-reducer.ts:26-32`) — pure literal-tagged variants, no shared base,\n * exhaustive-`switch` enforcement via non-`void` returns.\n *\n * Variant semantics:\n * - `option`: a regular author-defined option row.\n * - `other`: the inline free-text input row appended to single-select questions\n * (label is \"Type something.\"). Renders as inline `Input` when active.\n * - `chat`: the abandon-questionnaire escape-hatch row (label is \"Chat about this\").\n * Renders as inline `Input` when active.\n * - `next`: the explicit commit-and-advance row appended to multi-select questions\n * (label is \"Next\"). Renders without a number / checkbox.\n */\nexport type WrappingSelectItem =\n\t| { kind: \"option\"; label: string; description?: string }\n\t| { kind: \"other\"; label: string; description?: string }\n\t| { kind: \"chat\"; label: string; description?: string }\n\t| { kind: \"next\"; label: string; description?: string };\n\nexport interface WrappingSelectTheme {\n\tselectedText: (text: string) => string;\n\tdescription: (text: string) => string;\n\tscrollInfo: (text: string) => string;\n}\n\n/**\n * Numbering controls.\n *\n * Use `numberStartOffset` + `totalItemsForNumbering` when a list is logically a slice of a\n * larger numbered sequence — e.g. the chat row lives in its own WrappingSelect but should\n * render as `(N+1).` where N is the previous list's item count, with the column padded as\n * if both lists were one continuous numbered sequence.\n */\nexport interface WrappingSelectOptions {\n\t/** Start numbering at this offset + 1 (default 0 → rows labeled 1, 2, 3 …). */\n\tnumberStartOffset?: number;\n\t/** Override the total used to pad the number column (useful when items span multiple lists). */\n\ttotalItemsForNumbering?: number;\n\t/** When false, rows that normally open an inline editor stay ordinary labeled rows. */\n\tinlineInputEnabled?: boolean;\n}\n\nexport class WrappingSelect implements Component {\n\tprivate static readonly ACTIVE_POINTER = \"❯ \";\n\tprivate static readonly INACTIVE_POINTER = \" \";\n\tprivate static readonly NUMBER_SEPARATOR = \". \";\n\tprivate static readonly CURSOR_INVERSE_START = \"\\x1b[7m\";\n\tprivate static readonly CURSOR_INVERSE_END = \"\\x1b[0m\";\n\tprivate static readonly CONFIRMED_MARK = \" ✔\";\n\tprivate static readonly MIN_CONTENT_WIDTH = 1;\n\n\tprivate readonly items: readonly WrappingSelectItem[];\n\tprivate readonly maxVisible: number;\n\tprivate readonly theme: WrappingSelectTheme;\n\tprivate readonly inlineInputEnabled: boolean;\n\tprivate numberStartOffset: number;\n\tprivate totalItemsForNumbering: number;\n\n\tprivate selectedIndex = 0;\n\tprivate focused = true;\n\tprivate inputBuffer = \"\";\n\tprivate inputCursor: number | undefined = undefined;\n\t/**\n\t * Index of the row that was previously confirmed for this list (e.g. the user's prior\n\t * answer when re-entering a multi-question tab). Renders `<label> ✔` in the active-row\n\t * styling but WITHOUT the `❯` pointer — pointer is reserved for the live cursor. When\n\t * `selectedIndex === confirmedIndex && focused`, the active rendering wins (no double-mark).\n\t */\n\tprivate confirmedIndex: number | undefined = undefined;\n\t/**\n\t * When set together with `confirmedIndex`, replaces the row's static label at render time.\n\t * Used for the `kind: \"other\"` sentinel — its label is \"Type something.\" but if the user's\n\t * prior answer was custom text, we render that text instead (e.g. `4. Hello ✔`).\n\t */\n\tprivate confirmedLabelOverride: string | undefined = undefined;\n\n\tconstructor(\n\t\titems: readonly WrappingSelectItem[],\n\t\tmaxVisible: number,\n\t\ttheme: WrappingSelectTheme,\n\t\toptions: WrappingSelectOptions = {},\n\t) {\n\t\tthis.items = items;\n\t\tthis.maxVisible = Math.max(1, maxVisible);\n\t\tthis.theme = theme;\n\t\tthis.inlineInputEnabled = options.inlineInputEnabled !== false;\n\t\tthis.numberStartOffset = options.numberStartOffset ?? 0;\n\t\tthis.totalItemsForNumbering = options.totalItemsForNumbering ?? items.length;\n\t}\n\n\t/**\n\t * Update the numbering offset + total padding width without rebuilding the component.\n\t * Used by the host to keep the chat-row WrappingSelect's number aligned with the active tab's\n\t * options list when the user switches tabs (each tab can have a different items count).\n\t */\n\tsetNumbering(numberStartOffset: number, totalItemsForNumbering: number): void {\n\t\tthis.numberStartOffset = numberStartOffset;\n\t\tthis.totalItemsForNumbering = Math.max(1, totalItemsForNumbering);\n\t}\n\n\tsetSelectedIndex(index: number): void {\n\t\tthis.selectedIndex = Math.max(0, Math.min(index, this.items.length - 1));\n\t}\n\n\tsetFocused(focused: boolean): void {\n\t\tthis.focused = focused;\n\t}\n\n\t/**\n\t * Mark a previously-confirmed row. Pass `undefined` to clear. `labelOverride` replaces\n\t * the row's static `item.label` at render time — used for the `kind: \"other\"` sentinel so\n\t * the row reads `Hello ✔` instead of `Type something. ✔` when the prior answer was custom\n\t * text.\n\t */\n\tsetConfirmedIndex(index: number | undefined, labelOverride?: string): void {\n\t\tif (index === undefined) {\n\t\t\tthis.confirmedIndex = undefined;\n\t\t\tthis.confirmedLabelOverride = undefined;\n\t\t\treturn;\n\t\t}\n\t\tthis.confirmedIndex = Math.max(0, Math.min(index, this.items.length - 1));\n\t\tthis.confirmedLabelOverride = labelOverride;\n\t}\n\n\tsetInputBuffer(text: string): void {\n\t\tthis.inputBuffer = text;\n\t\tif (this.inputCursor !== undefined) this.inputCursor = this.clampInputCursor(this.inputCursor);\n\t}\n\n\tsetInputCursor(cursor: number): void {\n\t\tthis.inputCursor = this.clampInputCursor(cursor);\n\t}\n\n\t/** Intentionally empty — input is routed at the container level. */\n\thandleInput(_data: string): void {}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tif (this.items.length === 0) return [];\n\n\t\tconst { startIndex, endIndex } = this.computeVisibleWindow();\n\t\tconst numberWidth = String(Math.max(1, this.totalItemsForNumbering)).length;\n\t\tconst lines: string[] = [];\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.items[i];\n\t\t\tif (!item) continue;\n\t\t\tconst isActive = i === this.selectedIndex && this.focused;\n\t\t\tconst itemLines = this.renderItem(item, i, isActive, width, numberWidth);\n\t\t\t// Tell a bounding host which row it must not crop away (#2378). The mark\n\t\t\t// is zero-width and the host strips it; see OVERLAY_ACTIVE_ROW_MARKER.\n\t\t\tif (isActive && itemLines.length > 0) {\n\t\t\t\titemLines[0] = `${itemLines[0] ?? \"\"}${OVERLAY_ACTIVE_ROW_MARKER}`;\n\t\t\t}\n\t\t\tlines.push(...itemLines);\n\t\t}\n\n\t\tif (this.hasItemsOutsideWindow(startIndex, endIndex)) {\n\t\t\tlines.push(this.theme.scrollInfo(` (${this.selectedIndex + 1}/${this.items.length})`));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate computeVisibleWindow(): { startIndex: number; endIndex: number } {\n\t\tconst half = Math.floor(this.maxVisible / 2);\n\t\tconst startIndex = Math.max(0, Math.min(this.selectedIndex - half, this.items.length - this.maxVisible));\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.items.length);\n\t\treturn { startIndex, endIndex };\n\t}\n\n\tprivate hasItemsOutsideWindow(startIndex: number, endIndex: number): boolean {\n\t\treturn startIndex > 0 || endIndex < this.items.length;\n\t}\n\n\tprivate renderItem(\n\t\titem: WrappingSelectItem,\n\t\tindex: number,\n\t\tisActive: boolean,\n\t\twidth: number,\n\t\tnumberWidth: number,\n\t): string[] {\n\t\tconst rowPrefix = this.buildRowPrefix(index, isActive, numberWidth);\n\t\tconst continuationPrefix = \" \".repeat(visibleWidth(rowPrefix));\n\t\tconst contentWidth = Math.max(WrappingSelect.MIN_CONTENT_WIDTH, width - visibleWidth(rowPrefix));\n\n\t\tif (this.shouldRenderAsInlineInput(item, isActive)) {\n\t\t\treturn this.renderInlineInputRow(rowPrefix, continuationPrefix, contentWidth);\n\t\t}\n\n\t\t// Confirmed row gets a trailing ` ✔` and accent+bold styling; pointer is independent\n\t\t// (still ❯ when active). When `index === confirmedIndex` AND `isActive`, both `❯` and\n\t\t// `✔` appear on the same row — load-bearing for the case where the prior answer was\n\t\t// row 0 (cursor resets to 0 on tab-back, so the confirmed row IS the active row).\n\t\t// Optional `confirmedLabelOverride` replaces the static label (used for `kind: \"other\"`\n\t\t// + `kind: \"custom\"` answer); the inline-input branch above still wins for `kind: \"other\" + isActive`.\n\t\tconst isConfirmed = index === this.confirmedIndex;\n\t\tconst label = isConfirmed\n\t\t\t? `${this.confirmedLabelOverride ?? item.label}${WrappingSelect.CONFIRMED_MARK}`\n\t\t\t: item.label;\n\t\tconst applySelectedStyle = isActive || isConfirmed;\n\n\t\treturn [\n\t\t\t...this.renderLabelBlock(label, rowPrefix, continuationPrefix, contentWidth, applySelectedStyle),\n\t\t\t...this.renderDescriptionBlock(item.description, continuationPrefix, contentWidth),\n\t\t];\n\t}\n\n\tprivate buildRowPrefix(index: number, isActive: boolean, numberWidth: number): string {\n\t\tconst pointer = isActive ? WrappingSelect.ACTIVE_POINTER : WrappingSelect.INACTIVE_POINTER;\n\t\tconst displayNumber = this.numberStartOffset + index + 1;\n\t\tconst paddedNumber = String(displayNumber).padStart(numberWidth, \" \");\n\t\treturn `${pointer}${paddedNumber}${WrappingSelect.NUMBER_SEPARATOR}`;\n\t}\n\n\tprivate shouldRenderAsInlineInput(item: WrappingSelectItem, isActive: boolean): boolean {\n\t\treturn this.inlineInputEnabled && isActive && ROW_INTENT_META[item.kind].activatesInputMode;\n\t}\n\n\t/**\n\t * Render the inline input row across one or more lines, wrapping at `contentWidth`\n\t * so long input doesn't run off the right edge or trip the parent renderer's\n\t * width invariant. Mirrors `renderLabelBlock`'s contract: first line carries\n\t * `rowPrefix`, continuation lines carry `continuationPrefix` (spaces), and every\n\t * emitted line passes through `theme.selectedText`. The cursor mirrors the\n\t * main chat editor: inverse-video over the character at the caret, or an\n\t * inverse-video space at end-of-line.\n\t */\n\tprivate renderInlineInputRow(rowPrefix: string, continuationPrefix: string, contentWidth: number): string[] {\n\t\tconst raw = this.inputTextWithCursor();\n\t\tconst wrapped = wrapTextWithAnsi(raw, contentWidth);\n\t\treturn wrapped.map((segment, index) => {\n\t\t\tconst prefix = index === 0 ? rowPrefix : continuationPrefix;\n\t\t\treturn this.theme.selectedText(`${prefix}${segment}`);\n\t\t});\n\t}\n\n\tprivate inputTextWithCursor(): string {\n\t\tconst cursor = this.clampInputCursor(this.inputCursor ?? this.inputBuffer.length);\n\t\tconst before = this.inputBuffer.slice(0, cursor);\n\t\tconst after = this.inputBuffer.slice(cursor);\n\t\tconst [at = \"\"] = Array.from(after);\n\t\tif (at === \"\") {\n\t\t\treturn `${before}${WrappingSelect.CURSOR_INVERSE_START} ${WrappingSelect.CURSOR_INVERSE_END}`;\n\t\t}\n\t\tconst rest = after.slice(at.length);\n\t\treturn `${before}${WrappingSelect.CURSOR_INVERSE_START}${at}${WrappingSelect.CURSOR_INVERSE_END}${rest}`;\n\t}\n\n\tprivate clampInputCursor(cursor: number): number {\n\t\tif (!Number.isFinite(cursor)) return this.inputBuffer.length;\n\t\treturn Math.max(0, Math.min(cursor, this.inputBuffer.length));\n\t}\n\n\tprivate renderLabelBlock(\n\t\tlabel: string,\n\t\trowPrefix: string,\n\t\tcontinuationPrefix: string,\n\t\tcontentWidth: number,\n\t\tapplySelectedStyle: boolean,\n\t): string[] {\n\t\tconst wrapped = wrapTextWithAnsi(label, contentWidth);\n\t\treturn wrapped.map((segment, index) => {\n\t\t\tconst prefix = index === 0 ? rowPrefix : continuationPrefix;\n\t\t\tconst line = `${prefix}${segment}`;\n\t\t\treturn applySelectedStyle ? this.theme.selectedText(line) : line;\n\t\t});\n\t}\n\n\tprivate renderDescriptionBlock(\n\t\tdescription: string | undefined,\n\t\tcontinuationPrefix: string,\n\t\tcontentWidth: number,\n\t): string[] {\n\t\tif (!description) return [];\n\t\tconst wrapped = wrapTextWithAnsi(description, contentWidth);\n\t\treturn wrapped.map((segment) => `${continuationPrefix}${this.theme.description(segment)}`);\n\t}\n}\n"]}
1
+ {"version":3,"file":"wrapping-select.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/view/components/wrapping-select.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from \"@earendil-works/pi-tui\";\nimport { visibleWidth, wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport { OVERLAY_ACTIVE_ROW_MARKER } from \"../../../../extensions/ui-types.js\";\nimport { ROW_INTENT_META } from \"../../state/row-intent.ts\";\n\n/**\n * Row-intent discriminated union. `kind` is the single discriminator —\n * pre-1.0.3 boolean flags have been removed (see `banned-flags.test.ts`).\n * Modeled after `QuestionnaireAction` (`key-router.ts:13-32`) and `Effect`\n * (`state-reducer.ts:26-32`) — pure literal-tagged variants, no shared base,\n * exhaustive-`switch` enforcement via non-`void` returns.\n *\n * Variant semantics:\n * - `option`: a regular author-defined option row.\n * - `other`: the inline free-text input row appended to single-select questions\n * (label is \"Type something.\"). Renders as inline `Input` when active.\n * - `chat`: the abandon-questionnaire escape-hatch row (label is \"Chat about this\").\n * Renders as inline `Input` when active.\n * - `next`: the explicit commit-and-advance row appended to multi-select questions\n * (label is \"Next\"). Renders without a number / checkbox.\n */\nexport type WrappingSelectItem =\n\t| { kind: \"option\"; label: string; description?: string }\n\t| { kind: \"other\"; label: string; description?: string }\n\t| { kind: \"chat\"; label: string; description?: string }\n\t| { kind: \"next\"; label: string; description?: string };\n\nexport interface WrappingSelectTheme {\n\tselectedText: (text: string) => string;\n\tdescription: (text: string) => string;\n\tscrollInfo: (text: string) => string;\n}\n\n/**\n * Numbering controls.\n *\n * Use `numberStartOffset` + `totalItemsForNumbering` when a list is logically a slice of a\n * larger numbered sequence — e.g. the chat row lives in its own WrappingSelect but should\n * render as `(N+1).` where N is the previous list's item count, with the column padded as\n * if both lists were one continuous numbered sequence.\n */\nexport interface WrappingSelectOptions {\n\t/** Start numbering at this offset + 1 (default 0 → rows labeled 1, 2, 3 …). */\n\tnumberStartOffset?: number;\n\t/** Override the total used to pad the number column (useful when items span multiple lists). */\n\ttotalItemsForNumbering?: number;\n\t/** When false, rows that normally open an inline editor stay ordinary labeled rows. */\n\tinlineInputEnabled?: boolean;\n}\n\nexport class WrappingSelect implements Component {\n\tprivate static readonly ACTIVE_POINTER = \"❯ \";\n\tprivate static readonly INACTIVE_POINTER = \" \";\n\tprivate static readonly NUMBER_SEPARATOR = \". \";\n\tprivate static readonly CURSOR_INVERSE_START = \"\\x1b[7m\";\n\tprivate static readonly CURSOR_INVERSE_END = \"\\x1b[0m\";\n\tprivate static readonly CONFIRMED_MARK = \" ✔\";\n\tprivate static readonly MIN_CONTENT_WIDTH = 1;\n\n\tprivate readonly items: readonly WrappingSelectItem[];\n\tprivate readonly maxVisible: number;\n\tprivate readonly theme: WrappingSelectTheme;\n\tprivate readonly inlineInputEnabled: boolean;\n\tprivate numberStartOffset: number;\n\tprivate totalItemsForNumbering: number;\n\n\tprivate selectedIndex = 0;\n\tprivate focused = true;\n\tprivate inputBuffer = \"\";\n\tprivate inputCursor: number | undefined = undefined;\n\t/**\n\t * Index of the row that was previously confirmed for this list (e.g. the user's prior\n\t * answer when re-entering a multi-question tab). Renders `<label> ✔` in the active-row\n\t * styling but WITHOUT the `❯` pointer — pointer is reserved for the live cursor. When\n\t * `selectedIndex === confirmedIndex && focused`, the active rendering wins (no double-mark).\n\t */\n\tprivate confirmedIndex: number | undefined = undefined;\n\t/**\n\t * When set together with `confirmedIndex`, replaces the row's static label at render time.\n\t * Used for the `kind: \"other\"` sentinel — its label is \"Type something.\" but if the user's\n\t * prior answer was custom text, we render that text instead (e.g. `4. Hello ✔`).\n\t */\n\tprivate confirmedLabelOverride: string | undefined = undefined;\n\n\tconstructor(\n\t\titems: readonly WrappingSelectItem[],\n\t\tmaxVisible: number,\n\t\ttheme: WrappingSelectTheme,\n\t\toptions: WrappingSelectOptions = {},\n\t) {\n\t\tthis.items = items;\n\t\tthis.maxVisible = Math.max(1, maxVisible);\n\t\tthis.theme = theme;\n\t\tthis.inlineInputEnabled = options.inlineInputEnabled !== false;\n\t\tthis.numberStartOffset = options.numberStartOffset ?? 0;\n\t\tthis.totalItemsForNumbering = options.totalItemsForNumbering ?? items.length;\n\t}\n\n\t/**\n\t * Update the numbering offset + total padding width without rebuilding the component.\n\t * Used by the host to keep the chat-row WrappingSelect's number aligned with the active tab's\n\t * options list when the user switches tabs (each tab can have a different items count).\n\t */\n\tsetNumbering(numberStartOffset: number, totalItemsForNumbering: number): void {\n\t\tthis.numberStartOffset = numberStartOffset;\n\t\tthis.totalItemsForNumbering = Math.max(1, totalItemsForNumbering);\n\t}\n\n\tsetSelectedIndex(index: number): void {\n\t\tthis.selectedIndex = Math.max(0, Math.min(index, this.items.length - 1));\n\t}\n\n\tsetFocused(focused: boolean): void {\n\t\tthis.focused = focused;\n\t}\n\n\t/**\n\t * Mark a previously-confirmed row. Pass `undefined` to clear. `labelOverride` replaces\n\t * the row's static `item.label` at render time — used for the `kind: \"other\"` sentinel so\n\t * the row reads `Hello ✔` instead of `Type something. ✔` when the prior answer was custom\n\t * text.\n\t */\n\tsetConfirmedIndex(index: number | undefined, labelOverride?: string): void {\n\t\tif (index === undefined) {\n\t\t\tthis.confirmedIndex = undefined;\n\t\t\tthis.confirmedLabelOverride = undefined;\n\t\t\treturn;\n\t\t}\n\t\tthis.confirmedIndex = Math.max(0, Math.min(index, this.items.length - 1));\n\t\tthis.confirmedLabelOverride = labelOverride;\n\t}\n\n\tsetInputBuffer(text: string): void {\n\t\tthis.inputBuffer = text;\n\t\tif (this.inputCursor !== undefined) this.inputCursor = this.clampInputCursor(this.inputCursor);\n\t}\n\n\tsetInputCursor(cursor: number): void {\n\t\tthis.inputCursor = this.clampInputCursor(cursor);\n\t}\n\n\t/** Intentionally empty — input is routed at the container level. */\n\thandleInput(_data: string): void {}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tif (this.items.length === 0) return [];\n\n\t\tconst { startIndex, endIndex } = this.computeVisibleWindow();\n\t\tconst numberWidth = String(Math.max(1, this.totalItemsForNumbering)).length;\n\t\tconst lines: string[] = [];\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.items[i];\n\t\t\tif (!item) continue;\n\t\t\tconst isActive = i === this.selectedIndex && this.focused;\n\t\t\tconst itemLines = this.renderItem(item, i, isActive, width, numberWidth);\n\t\t\t// Tell a bounding host which row it must not crop away (#2378). The mark\n\t\t\t// is zero-width and the host strips it; see OVERLAY_ACTIVE_ROW_MARKER.\n\t\t\tif (isActive && itemLines.length > 0) {\n\t\t\t\titemLines[0] = `${itemLines[0] ?? \"\"}${OVERLAY_ACTIVE_ROW_MARKER}`;\n\t\t\t}\n\t\t\tlines.push(...itemLines);\n\t\t}\n\n\t\tif (this.hasItemsOutsideWindow(startIndex, endIndex)) {\n\t\t\tlines.push(this.theme.scrollInfo(` (${this.selectedIndex + 1}/${this.items.length})`));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate computeVisibleWindow(): { startIndex: number; endIndex: number } {\n\t\tconst half = Math.floor(this.maxVisible / 2);\n\t\tconst startIndex = Math.max(0, Math.min(this.selectedIndex - half, this.items.length - this.maxVisible));\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.items.length);\n\t\treturn { startIndex, endIndex };\n\t}\n\n\tprivate hasItemsOutsideWindow(startIndex: number, endIndex: number): boolean {\n\t\treturn startIndex > 0 || endIndex < this.items.length;\n\t}\n\n\tprivate renderItem(\n\t\titem: WrappingSelectItem,\n\t\tindex: number,\n\t\tisActive: boolean,\n\t\twidth: number,\n\t\tnumberWidth: number,\n\t): string[] {\n\t\tconst rowPrefix = this.buildRowPrefix(index, isActive, numberWidth);\n\t\tconst continuationPrefix = \" \".repeat(visibleWidth(rowPrefix));\n\t\tconst contentWidth = Math.max(WrappingSelect.MIN_CONTENT_WIDTH, width - visibleWidth(rowPrefix));\n\n\t\tif (this.shouldRenderAsInlineInput(item, isActive)) {\n\t\t\treturn this.renderInlineInputRow(rowPrefix, continuationPrefix, contentWidth);\n\t\t}\n\n\t\t// Confirmed row gets a trailing ` ✔` and accent+bold styling; pointer is independent\n\t\t// (still ❯ when active). When `index === confirmedIndex` AND `isActive`, both `❯` and\n\t\t// `✔` appear on the same row — load-bearing for the case where the prior answer was\n\t\t// row 0 (cursor resets to 0 on tab-back, so the confirmed row IS the active row).\n\t\t// Optional `confirmedLabelOverride` replaces the static label (used for `kind: \"other\"`\n\t\t// + `kind: \"custom\"` answer); the inline-input branch above still wins for `kind: \"other\" + isActive`.\n\t\tconst isConfirmed = index === this.confirmedIndex;\n\t\tconst label = isConfirmed\n\t\t\t? `${this.confirmedLabelOverride ?? item.label}${WrappingSelect.CONFIRMED_MARK}`\n\t\t\t: item.label;\n\t\tconst applySelectedStyle = isActive || isConfirmed;\n\n\t\treturn [\n\t\t\t...this.renderLabelBlock(label, rowPrefix, continuationPrefix, contentWidth, applySelectedStyle),\n\t\t\t...this.renderDescriptionBlock(item.description, continuationPrefix, contentWidth),\n\t\t];\n\t}\n\n\tprivate buildRowPrefix(index: number, isActive: boolean, numberWidth: number): string {\n\t\tconst pointer = isActive ? WrappingSelect.ACTIVE_POINTER : WrappingSelect.INACTIVE_POINTER;\n\t\tconst displayNumber = this.numberStartOffset + index + 1;\n\t\tconst paddedNumber = String(displayNumber).padStart(numberWidth, \" \");\n\t\treturn `${pointer}${paddedNumber}${WrappingSelect.NUMBER_SEPARATOR}`;\n\t}\n\n\tprivate shouldRenderAsInlineInput(item: WrappingSelectItem, isActive: boolean): boolean {\n\t\treturn this.inlineInputEnabled && isActive && ROW_INTENT_META[item.kind].activatesInputMode;\n\t}\n\n\t/**\n\t * Render the inline input row across one or more lines, wrapping at `contentWidth`\n\t * so long input doesn't run off the right edge or trip the parent renderer's\n\t * width invariant. Mirrors `renderLabelBlock`'s contract: first line carries\n\t * `rowPrefix`, continuation lines carry `continuationPrefix` (spaces), and every\n\t * emitted line passes through `theme.selectedText`. The cursor mirrors the\n\t * main chat editor: inverse-video over the character at the caret, or an\n\t * inverse-video space at end-of-line.\n\t */\n\tprivate renderInlineInputRow(rowPrefix: string, continuationPrefix: string, contentWidth: number): string[] {\n\t\tconst raw = this.inputTextWithCursor();\n\t\tconst wrapped = wrapTextWithAnsi(raw, contentWidth);\n\t\treturn wrapped.map((segment, index) => {\n\t\t\tconst prefix = index === 0 ? rowPrefix : continuationPrefix;\n\t\t\treturn this.theme.selectedText(`${prefix}${segment}`);\n\t\t});\n\t}\n\n\tprivate inputTextWithCursor(): string {\n\t\tconst cursor = this.clampInputCursor(this.inputCursor ?? this.inputBuffer.length);\n\t\tconst before = this.inputBuffer.slice(0, cursor);\n\t\tconst after = this.inputBuffer.slice(cursor);\n\t\tconst [at = \"\"] = Array.from(after);\n\t\tif (at === \"\") {\n\t\t\treturn `${before}${WrappingSelect.CURSOR_INVERSE_START} ${WrappingSelect.CURSOR_INVERSE_END}`;\n\t\t}\n\t\tconst rest = after.slice(at.length);\n\t\treturn `${before}${WrappingSelect.CURSOR_INVERSE_START}${at}${WrappingSelect.CURSOR_INVERSE_END}${rest}`;\n\t}\n\n\tprivate clampInputCursor(cursor: number): number {\n\t\tif (!Number.isFinite(cursor)) return this.inputBuffer.length;\n\t\treturn Math.max(0, Math.min(cursor, this.inputBuffer.length));\n\t}\n\n\tprivate renderLabelBlock(\n\t\tlabel: string,\n\t\trowPrefix: string,\n\t\tcontinuationPrefix: string,\n\t\tcontentWidth: number,\n\t\tapplySelectedStyle: boolean,\n\t): string[] {\n\t\tconst wrapped = wrapTextWithAnsi(label, contentWidth);\n\t\treturn wrapped.map((segment, index) => {\n\t\t\tconst prefix = index === 0 ? rowPrefix : continuationPrefix;\n\t\t\tconst line = `${prefix}${segment}`;\n\t\t\treturn applySelectedStyle ? this.theme.selectedText(line) : line;\n\t\t});\n\t}\n\n\tprivate renderDescriptionBlock(\n\t\tdescription: string | undefined,\n\t\tcontinuationPrefix: string,\n\t\tcontentWidth: number,\n\t): string[] {\n\t\tif (!description) return [];\n\t\tconst wrapped = wrapTextWithAnsi(description, contentWidth);\n\t\treturn wrapped.map((segment) => `${continuationPrefix}${this.theme.description(segment)}`);\n\t}\n}\n"]}
@@ -24,6 +24,11 @@ export const INCOMPLETE_WARNING_PREFIX = "⚠ Answer remaining questions before
24
24
  * itself does not derive it.
25
25
  */
26
26
  export class DialogView {
27
+ liveProps;
28
+ config;
29
+ questionStrategy;
30
+ submitStrategy;
31
+ maxFooterRowCount;
27
32
  constructor(config, initialProps) {
28
33
  this.config = config;
29
34
  this.liveProps = initialProps;
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-builder.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/view/dialog-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, type Input, Spacer } from \"@earendil-works/pi-tui\";\nimport { DynamicBorder } from \"../../../../modes/interactive/components/index.ts\";\nimport type { Theme } from \"../../../../modes/interactive/theme/theme.js\";\nimport type { QuestionnaireState } from \"../state/state.ts\";\nimport type { QuestionData } from \"../tool/types.js\";\nimport { BodyResidualSpacer } from \"./body-residual-spacer.ts\";\nimport type { ChatRowView } from \"./components/chat-row-view.ts\";\nimport type { PreviewPaneProps } from \"./components/preview/preview-pane.ts\";\nimport type { TabBar } from \"./components/tab-bar.ts\";\nimport type { StatefulView } from \"./stateful-view.ts\";\nimport type { TabComponents } from \"./tab-components.ts\";\nimport { QuestionTabStrategy, SubmitTabStrategy, type TabContentStrategy } from \"./tab-content-strategy.ts\";\n\nexport const HINT_PART_ENTER = \"enter select\";\nexport const HINT_PART_NAV = \"↑/↓ navigate\";\nexport const HINT_PART_TOGGLE = \"space toggle\";\nexport const HINT_PART_NOTES = \"n add notes\";\nexport const HINT_PART_TAB = \"tab switch questions\";\nexport const HINT_PART_CANCEL = \"esc cancel\";\nexport const HINT_SINGLE = [HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_CANCEL].join(\" · \");\nexport const HINT_MULTI = [HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_TAB, HINT_PART_CANCEL].join(\" · \");\nexport const HINT_MULTISELECT_SUFFIX = ` · ${HINT_PART_TOGGLE}`;\nexport const HINT_NOTES_SUFFIX = ` · ${HINT_PART_NOTES}`;\nexport const REVIEW_HEADING = \"Review your answers\";\nexport const READY_PROMPT = \"Ready to submit your answers?\";\nexport const INCOMPLETE_WARNING_PREFIX = \"⚠ Answer remaining questions before submitting:\";\n\nexport type DialogState = QuestionnaireState;\n\n/** Per-tick projection of dialog state. Written by the adapter; read by the strategy thunk. */\nexport interface DialogProps {\n\tstate: DialogState;\n\tactivePreviewPane: StatefulView<PreviewPaneProps>;\n}\n\n/** Construction-time config for `DialogView`. Frozen after construction. */\nexport interface DialogConfig {\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\ttabBar: TabBar | undefined;\n\tnotesInput: Input;\n\tchatRow: ChatRowView;\n\tisMulti: boolean;\n\ttabsByIndex: ReadonlyArray<TabComponents>;\n\t/** Optional so single-question mode and non-submit tests can omit it; SubmitTabStrategy falls back to Spacer rows. */\n\tsubmitPicker?: Component;\n\t/** Worst-case body height across all tabs/options. Determines the stable overall dialog footprint. */\n\tgetBodyHeight: (width: number) => number;\n\t/** Body height of the CURRENTLY active tab/option. The chrome subtracts this from `getBodyHeight` to absorb the residual OUTSIDE the bordered region. */\n\tgetCurrentBodyHeight: (width: number) => number;\n}\n\n/**\n * The 7th renderable, promoted from a structural literal to a named class so\n * all view-layer components share one explicit `implements StatefulView<P>`\n * contract. `setProps(DialogProps)` writes the live cell read by the\n * strategy thunk during `render()`. `liveProps.activePreviewPane` is a\n * resolved pane reference threaded by the adapter per tick — the dialog\n * itself does not derive it.\n */\nexport class DialogView implements StatefulView<DialogProps> {\n\tprivate liveProps: DialogProps;\n\tprivate readonly config: DialogConfig;\n\tprivate readonly questionStrategy: TabContentStrategy;\n\tprivate readonly submitStrategy: TabContentStrategy | undefined;\n\tprivate readonly maxFooterRowCount: number;\n\n\tconstructor(config: DialogConfig, initialProps: DialogProps) {\n\t\tthis.config = config;\n\t\tthis.liveProps = initialProps;\n\t\tthis.questionStrategy = new QuestionTabStrategy({\n\t\t\ttheme: config.theme,\n\t\t\tquestions: config.questions,\n\t\t\tgetPreviewPane: () => this.liveProps.activePreviewPane,\n\t\t\ttabsByIndex: config.tabsByIndex,\n\t\t\tnotesInput: config.notesInput,\n\t\t\tchatRow: config.chatRow,\n\t\t\tisMulti: config.isMulti,\n\t\t\tgetCurrentBodyHeight: config.getCurrentBodyHeight,\n\t\t});\n\t\tthis.submitStrategy = config.isMulti\n\t\t\t? new SubmitTabStrategy({\n\t\t\t\t\ttheme: config.theme,\n\t\t\t\t\tquestions: config.questions,\n\t\t\t\t\tsubmitPicker: config.submitPicker,\n\t\t\t\t})\n\t\t\t: undefined;\n\t\tthis.maxFooterRowCount = Math.max(this.questionStrategy.footerRowCount, this.submitStrategy?.footerRowCount ?? 0);\n\t}\n\n\tsetProps(props: DialogProps): void {\n\t\tthis.liveProps = props;\n\t}\n\n\thandleInput(_data: string): void {}\n\n\t// Invalidation is driven by `QuestionnairePropsAdapter.invalidate()`, which\n\t// owns the full set of renderables (binding registries + extras like\n\t// `notesInput`). DialogView has no cached layout of its own.\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst onSubmit = this.config.isMulti && this.liveProps.state.currentTab === this.config.questions.length;\n\t\tconst strategy = onSubmit && this.submitStrategy ? this.submitStrategy : this.questionStrategy;\n\t\treturn this.buildContainerFromStrategy(strategy).render(width);\n\t}\n\n\tprivate buildContainerFromStrategy(strategy: TabContentStrategy): Container {\n\t\tconst { theme, isMulti, tabBar } = this.config;\n\t\tconst state = this.liveProps.state;\n\t\tconst container = new Container();\n\t\tconst border = () => new DynamicBorder((s) => theme.fg(\"accent\", s));\n\n\t\tcontainer.addChild(border());\n\t\tif (isMulti && tabBar) container.addChild(tabBar);\n\t\tcontainer.addChild(new Spacer(1));\n\n\t\tfor (const c of strategy.headingRows(state)) container.addChild(c);\n\t\tcontainer.addChild(strategy.bodyComponent(state));\n\t\tcontainer.addChild(new Spacer(1));\n\t\tfor (const c of strategy.midRows(state)) container.addChild(c);\n\n\t\tcontainer.addChild(border());\n\t\tfor (const c of strategy.footerRows(state)) container.addChild(c);\n\n\t\t// Residual spacer equalizes total height across strategies; rendered AFTER the bottom border.\n\t\tcontainer.addChild(\n\t\t\tnew BodyResidualSpacer(\n\t\t\t\t(w) => this.config.getBodyHeight(w) + this.maxFooterRowCount,\n\t\t\t\t(w) => strategy.bodyHeight(w, state) + strategy.footerRowCount,\n\t\t\t),\n\t\t);\n\t\treturn container;\n\t}\n}\n"]}
1
+ {"version":3,"file":"dialog-builder.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/view/dialog-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, type Input, Spacer } from \"@earendil-works/pi-tui\";\nimport { DynamicBorder } from \"../../../../modes/interactive/components/index.ts\";\nimport type { Theme } from \"../../../../modes/interactive/theme/theme.js\";\nimport type { QuestionnaireState } from \"../state/state.ts\";\nimport type { QuestionData } from \"../tool/types.js\";\nimport { BodyResidualSpacer } from \"./body-residual-spacer.ts\";\nimport type { ChatRowView } from \"./components/chat-row-view.ts\";\nimport type { PreviewPaneProps } from \"./components/preview/preview-pane.ts\";\nimport type { TabBar } from \"./components/tab-bar.ts\";\nimport type { StatefulView } from \"./stateful-view.ts\";\nimport type { TabComponents } from \"./tab-components.ts\";\nimport { QuestionTabStrategy, SubmitTabStrategy, type TabContentStrategy } from \"./tab-content-strategy.ts\";\n\nexport const HINT_PART_ENTER = \"enter select\";\nexport const HINT_PART_NAV = \"↑/↓ navigate\";\nexport const HINT_PART_TOGGLE = \"space toggle\";\nexport const HINT_PART_NOTES = \"n add notes\";\nexport const HINT_PART_TAB = \"tab switch questions\";\nexport const HINT_PART_CANCEL = \"esc cancel\";\nexport const HINT_SINGLE = [HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_CANCEL].join(\" · \");\nexport const HINT_MULTI = [HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_TAB, HINT_PART_CANCEL].join(\" · \");\nexport const HINT_MULTISELECT_SUFFIX = ` · ${HINT_PART_TOGGLE}`;\nexport const HINT_NOTES_SUFFIX = ` · ${HINT_PART_NOTES}`;\nexport const REVIEW_HEADING = \"Review your answers\";\nexport const READY_PROMPT = \"Ready to submit your answers?\";\nexport const INCOMPLETE_WARNING_PREFIX = \"⚠ Answer remaining questions before submitting:\";\n\nexport type DialogState = QuestionnaireState;\n\n/** Per-tick projection of dialog state. Written by the adapter; read by the strategy thunk. */\nexport interface DialogProps {\n\tstate: DialogState;\n\tactivePreviewPane: StatefulView<PreviewPaneProps>;\n}\n\n/** Construction-time config for `DialogView`. Frozen after construction. */\nexport interface DialogConfig {\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\ttabBar: TabBar | undefined;\n\tnotesInput: Input;\n\tchatRow: ChatRowView;\n\tisMulti: boolean;\n\ttabsByIndex: ReadonlyArray<TabComponents>;\n\t/** Optional so single-question mode and non-submit tests can omit it; SubmitTabStrategy falls back to Spacer rows. */\n\tsubmitPicker?: Component;\n\t/** Worst-case body height across all tabs/options. Determines the stable overall dialog footprint. */\n\tgetBodyHeight: (width: number) => number;\n\t/** Body height of the CURRENTLY active tab/option. The chrome subtracts this from `getBodyHeight` to absorb the residual OUTSIDE the bordered region. */\n\tgetCurrentBodyHeight: (width: number) => number;\n}\n\n/**\n * The 7th renderable, promoted from a structural literal to a named class so\n * all view-layer components share one explicit `implements StatefulView<P>`\n * contract. `setProps(DialogProps)` writes the live cell read by the\n * strategy thunk during `render()`. `liveProps.activePreviewPane` is a\n * resolved pane reference threaded by the adapter per tick — the dialog\n * itself does not derive it.\n */\nexport class DialogView implements StatefulView<DialogProps> {\n\tprivate liveProps: DialogProps;\n\tprivate readonly config: DialogConfig;\n\tprivate readonly questionStrategy: TabContentStrategy;\n\tprivate readonly submitStrategy: TabContentStrategy | undefined;\n\tprivate readonly maxFooterRowCount: number;\n\n\tconstructor(config: DialogConfig, initialProps: DialogProps) {\n\t\tthis.config = config;\n\t\tthis.liveProps = initialProps;\n\t\tthis.questionStrategy = new QuestionTabStrategy({\n\t\t\ttheme: config.theme,\n\t\t\tquestions: config.questions,\n\t\t\tgetPreviewPane: () => this.liveProps.activePreviewPane,\n\t\t\ttabsByIndex: config.tabsByIndex,\n\t\t\tnotesInput: config.notesInput,\n\t\t\tchatRow: config.chatRow,\n\t\t\tisMulti: config.isMulti,\n\t\t\tgetCurrentBodyHeight: config.getCurrentBodyHeight,\n\t\t});\n\t\tthis.submitStrategy = config.isMulti\n\t\t\t? new SubmitTabStrategy({\n\t\t\t\t\ttheme: config.theme,\n\t\t\t\t\tquestions: config.questions,\n\t\t\t\t\tsubmitPicker: config.submitPicker,\n\t\t\t\t})\n\t\t\t: undefined;\n\t\tthis.maxFooterRowCount = Math.max(this.questionStrategy.footerRowCount, this.submitStrategy?.footerRowCount ?? 0);\n\t}\n\n\tsetProps(props: DialogProps): void {\n\t\tthis.liveProps = props;\n\t}\n\n\thandleInput(_data: string): void {}\n\n\t// Invalidation is driven by `QuestionnairePropsAdapter.invalidate()`, which\n\t// owns the full set of renderables (binding registries + extras like\n\t// `notesInput`). DialogView has no cached layout of its own.\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst onSubmit = this.config.isMulti && this.liveProps.state.currentTab === this.config.questions.length;\n\t\tconst strategy = onSubmit && this.submitStrategy ? this.submitStrategy : this.questionStrategy;\n\t\treturn this.buildContainerFromStrategy(strategy).render(width);\n\t}\n\n\tprivate buildContainerFromStrategy(strategy: TabContentStrategy): Container {\n\t\tconst { theme, isMulti, tabBar } = this.config;\n\t\tconst state = this.liveProps.state;\n\t\tconst container = new Container();\n\t\tconst border = () => new DynamicBorder((s) => theme.fg(\"accent\", s));\n\n\t\tcontainer.addChild(border());\n\t\tif (isMulti && tabBar) container.addChild(tabBar);\n\t\tcontainer.addChild(new Spacer(1));\n\n\t\tfor (const c of strategy.headingRows(state)) container.addChild(c);\n\t\tcontainer.addChild(strategy.bodyComponent(state));\n\t\tcontainer.addChild(new Spacer(1));\n\t\tfor (const c of strategy.midRows(state)) container.addChild(c);\n\n\t\tcontainer.addChild(border());\n\t\tfor (const c of strategy.footerRows(state)) container.addChild(c);\n\n\t\t// Residual spacer equalizes total height across strategies; rendered AFTER the bottom border.\n\t\tcontainer.addChild(\n\t\t\tnew BodyResidualSpacer(\n\t\t\t\t(w) => this.config.getBodyHeight(w) + this.maxFooterRowCount,\n\t\t\t\t(w) => strategy.bodyHeight(w, state) + strategy.footerRowCount,\n\t\t\t),\n\t\t);\n\t\treturn container;\n\t}\n}\n"]}
@@ -10,6 +10,14 @@ import { selectActiveView } from "../state/selectors/focus.js";
10
10
  * chat footer never display each other's in-flight text.
11
11
  */
12
12
  export class QuestionnairePropsAdapter {
13
+ tui;
14
+ questions;
15
+ itemsByTab;
16
+ tabsByIndex;
17
+ inlineInput;
18
+ globalBindings;
19
+ perTabBindings;
20
+ extraInvalidatables;
13
21
  constructor(config) {
14
22
  this.tui = config.tui;
15
23
  this.questions = config.questions;
@@ -1 +1 @@
1
- {"version":3,"file":"props-adapter.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/view/props-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AA4B/D;;;;;;;;GAQG;AACH,MAAM,OAAO,yBAAyB;IAUrC,YAAY,MAAuC;QAClD,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,KAAyB;QAC9B,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QAC7C,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,4BAA4B,CAAC,KAAK,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACjF,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC;QAE/F,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;QACpD,MAAM,WAAW,GAChB,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7G,MAAM,UAAU,GAAG,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC;QACtF,MAAM,eAAe,GACpB,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1G,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,eAAe,CAAC,MAAM,CAAC;QAC5F,MAAM,GAAG,GAAmB;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc;YACd,UAAU;YACV,WAAW;YACX,UAAU;YACV,eAAe;YACf,cAAc;YACd,iBAAiB;SACjB,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;YACjC,MAAM,MAAM,GAAyB,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;YACxD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC;IAED;;;;;;OAMG;IACH,UAAU;QACT,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,cAAc;YAAE,CAAC,CAAC,UAAU,EAAE,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACpC,GAAG,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAC5B,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACzB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC;QAC/B,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,mBAAmB;YAAE,CAAC,CAAC,UAAU,EAAE,CAAC;IAC1D,CAAC;CACD","sourcesContent":["import type { Input } from \"@earendil-works/pi-tui\";\nimport type { BindingContext, PerTabBindingContext } from \"../state/selectors/contract.ts\";\nimport { selectActivePreviewPaneIndex } from \"../state/selectors/derivations.ts\";\nimport { selectActiveView } from \"../state/selectors/focus.ts\";\nimport type { QuestionnaireState } from \"../state/state.ts\";\nimport type { QuestionData } from \"../tool/types.js\";\nimport type { BoundGlobalBinding, BoundPerTabBinding } from \"./component-binding.ts\";\nimport type { WrappingSelectItem } from \"./components/wrapping-select.ts\";\nimport type { TabComponents } from \"./tab-components.ts\";\n\n/** Cache-invalidation contract used by the adapter. `pi-tui` `Component` already satisfies it. */\ninterface Invalidatable {\n\tinvalidate(): void;\n}\n\nexport interface QuestionnairePropsAdapterConfig {\n\ttui: { requestRender(): void };\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\ttabsByIndex: ReadonlyArray<TabComponents>;\n\tinlineInput: Input;\n\tglobalBindings: ReadonlyArray<BoundGlobalBinding>;\n\tperTabBindings: ReadonlyArray<BoundPerTabBinding>;\n\t/**\n\t * Renderables not reached by the binding registries (e.g. the notes\n\t * `Input`, which is typed into directly and has no props). Walked by\n\t * `invalidate()` after the binding-driven components.\n\t */\n\textraInvalidatables?: ReadonlyArray<Invalidatable>;\n}\n\n/**\n * View fan-out: drives every component setter from the canonical state via\n * two binding registries. `globalBindings` covers the cross-tab components\n * (chatRow, dialog, submitPicker?, tabBar?); `perTabBindings` covers the\n * per-tab kinds (optionList, preview, multiSelect?). The hand-coded fan-out\n * collapses to one global loop + one nested per-tab loop. The shared inline\n * input is projected through owner-specific draft slots so the option list and\n * chat footer never display each other's in-flight text.\n */\nexport class QuestionnairePropsAdapter {\n\tprivate readonly tui: QuestionnairePropsAdapterConfig[\"tui\"];\n\tprivate readonly questions: readonly QuestionData[];\n\tprivate readonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\tprivate readonly tabsByIndex: ReadonlyArray<TabComponents>;\n\tprivate readonly inlineInput: Input;\n\tprivate readonly globalBindings: ReadonlyArray<BoundGlobalBinding>;\n\tprivate readonly perTabBindings: ReadonlyArray<BoundPerTabBinding>;\n\tprivate readonly extraInvalidatables: ReadonlyArray<Invalidatable>;\n\n\tconstructor(config: QuestionnairePropsAdapterConfig) {\n\t\tthis.tui = config.tui;\n\t\tthis.questions = config.questions;\n\t\tthis.itemsByTab = config.itemsByTab;\n\t\tthis.tabsByIndex = config.tabsByIndex;\n\t\tthis.inlineInput = config.inlineInput;\n\t\tthis.globalBindings = config.globalBindings;\n\t\tthis.perTabBindings = config.perTabBindings;\n\t\tthis.extraInvalidatables = config.extraInvalidatables ?? [];\n\t}\n\n\tapply(state: QuestionnaireState): void {\n\t\tconst totalQuestions = this.questions.length;\n\t\tconst activeView = selectActiveView(state, totalQuestions);\n\t\tconst paneIndex = selectActivePreviewPaneIndex(state.currentTab, totalQuestions);\n\t\tconst activePreviewPane = this.tabsByIndex[paneIndex]?.preview ?? this.tabsByIndex[0]!.preview;\n\n\t\tconst liveInlineValue = this.inlineInput.getValue();\n\t\tconst inputBuffer =\n\t\t\tstate.customDraftByTab.get(state.currentTab) ?? (state.inlineInputOwner === \"other\" ? liveInlineValue : \"\");\n\t\tconst inputCaret = state.customCaretByTab.get(state.currentTab) ?? inputBuffer.length;\n\t\tconst chatInputBuffer =\n\t\t\tstate.chatDraftByTab.get(state.currentTab) ?? (state.inlineInputOwner === \"chat\" ? liveInlineValue : \"\");\n\t\tconst chatInputCaret = state.chatCaretByTab.get(state.currentTab) ?? chatInputBuffer.length;\n\t\tconst ctx: BindingContext = {\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t\ttotalQuestions,\n\t\t\tactiveView,\n\t\t\tinputBuffer,\n\t\t\tinputCaret,\n\t\t\tchatInputBuffer,\n\t\t\tchatInputCaret,\n\t\t\tactivePreviewPane,\n\t\t};\n\n\t\tfor (const binding of this.globalBindings) {\n\t\t\tbinding.apply(state, ctx);\n\t\t}\n\n\t\tfor (let i = 0; i < this.tabsByIndex.length; i++) {\n\t\t\tconst tab = this.tabsByIndex[i]!;\n\t\t\tconst tabCtx: PerTabBindingContext = { ...ctx, tab, i };\n\t\t\tfor (const binding of this.perTabBindings) {\n\t\t\t\tbinding.apply(state, tabCtx);\n\t\t\t}\n\t\t}\n\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Invalidates every owned renderable. Called by the session in place of\n\t * the old `dialog.invalidate()` forwarding chain — DialogView no longer\n\t * reaches into siblings (chatRow, tabBar, notesInput, activePreviewPane).\n\t * Iterates the same registries used by `apply()` plus\n\t * `extraInvalidatables` for components outside the binding system.\n\t */\n\tinvalidate(): void {\n\t\tfor (const b of this.globalBindings) b.invalidate();\n\t\tfor (const tab of this.tabsByIndex) {\n\t\t\ttab.optionList.invalidate();\n\t\t\ttab.preview.invalidate();\n\t\t\ttab.multiSelect?.invalidate();\n\t\t}\n\t\tfor (const x of this.extraInvalidatables) x.invalidate();\n\t}\n}\n"]}
1
+ {"version":3,"file":"props-adapter.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/view/props-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AA4B/D;;;;;;;;GAQG;AACH,MAAM,OAAO,yBAAyB;IACpB,GAAG,CAAyC;IAC5C,SAAS,CAA0B;IACnC,UAAU,CAA+C;IACzD,WAAW,CAA+B;IAC1C,WAAW,CAAQ;IACnB,cAAc,CAAoC;IAClD,cAAc,CAAoC;IAClD,mBAAmB,CAA+B;IAEnE,YAAY,MAAuC;QAClD,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC5C,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,KAAyB;QAC9B,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QAC7C,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,4BAA4B,CAAC,KAAK,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACjF,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC;QAE/F,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;QACpD,MAAM,WAAW,GAChB,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7G,MAAM,UAAU,GAAG,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC;QACtF,MAAM,eAAe,GACpB,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,KAAK,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1G,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,eAAe,CAAC,MAAM,CAAC;QAC5F,MAAM,GAAG,GAAmB;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc;YACd,UAAU;YACV,WAAW;YACX,UAAU;YACV,eAAe;YACf,cAAc;YACd,iBAAiB;SACjB,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;YACjC,MAAM,MAAM,GAAyB,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;YACxD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC3C,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC;IAED;;;;;;OAMG;IACH,UAAU;QACT,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,cAAc;YAAE,CAAC,CAAC,UAAU,EAAE,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACpC,GAAG,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAC5B,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACzB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,CAAC;QAC/B,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,mBAAmB;YAAE,CAAC,CAAC,UAAU,EAAE,CAAC;IAC1D,CAAC;CACD","sourcesContent":["import type { Input } from \"@earendil-works/pi-tui\";\nimport type { BindingContext, PerTabBindingContext } from \"../state/selectors/contract.ts\";\nimport { selectActivePreviewPaneIndex } from \"../state/selectors/derivations.ts\";\nimport { selectActiveView } from \"../state/selectors/focus.ts\";\nimport type { QuestionnaireState } from \"../state/state.ts\";\nimport type { QuestionData } from \"../tool/types.js\";\nimport type { BoundGlobalBinding, BoundPerTabBinding } from \"./component-binding.ts\";\nimport type { WrappingSelectItem } from \"./components/wrapping-select.ts\";\nimport type { TabComponents } from \"./tab-components.ts\";\n\n/** Cache-invalidation contract used by the adapter. `pi-tui` `Component` already satisfies it. */\ninterface Invalidatable {\n\tinvalidate(): void;\n}\n\nexport interface QuestionnairePropsAdapterConfig {\n\ttui: { requestRender(): void };\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\ttabsByIndex: ReadonlyArray<TabComponents>;\n\tinlineInput: Input;\n\tglobalBindings: ReadonlyArray<BoundGlobalBinding>;\n\tperTabBindings: ReadonlyArray<BoundPerTabBinding>;\n\t/**\n\t * Renderables not reached by the binding registries (e.g. the notes\n\t * `Input`, which is typed into directly and has no props). Walked by\n\t * `invalidate()` after the binding-driven components.\n\t */\n\textraInvalidatables?: ReadonlyArray<Invalidatable>;\n}\n\n/**\n * View fan-out: drives every component setter from the canonical state via\n * two binding registries. `globalBindings` covers the cross-tab components\n * (chatRow, dialog, submitPicker?, tabBar?); `perTabBindings` covers the\n * per-tab kinds (optionList, preview, multiSelect?). The hand-coded fan-out\n * collapses to one global loop + one nested per-tab loop. The shared inline\n * input is projected through owner-specific draft slots so the option list and\n * chat footer never display each other's in-flight text.\n */\nexport class QuestionnairePropsAdapter {\n\tprivate readonly tui: QuestionnairePropsAdapterConfig[\"tui\"];\n\tprivate readonly questions: readonly QuestionData[];\n\tprivate readonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\tprivate readonly tabsByIndex: ReadonlyArray<TabComponents>;\n\tprivate readonly inlineInput: Input;\n\tprivate readonly globalBindings: ReadonlyArray<BoundGlobalBinding>;\n\tprivate readonly perTabBindings: ReadonlyArray<BoundPerTabBinding>;\n\tprivate readonly extraInvalidatables: ReadonlyArray<Invalidatable>;\n\n\tconstructor(config: QuestionnairePropsAdapterConfig) {\n\t\tthis.tui = config.tui;\n\t\tthis.questions = config.questions;\n\t\tthis.itemsByTab = config.itemsByTab;\n\t\tthis.tabsByIndex = config.tabsByIndex;\n\t\tthis.inlineInput = config.inlineInput;\n\t\tthis.globalBindings = config.globalBindings;\n\t\tthis.perTabBindings = config.perTabBindings;\n\t\tthis.extraInvalidatables = config.extraInvalidatables ?? [];\n\t}\n\n\tapply(state: QuestionnaireState): void {\n\t\tconst totalQuestions = this.questions.length;\n\t\tconst activeView = selectActiveView(state, totalQuestions);\n\t\tconst paneIndex = selectActivePreviewPaneIndex(state.currentTab, totalQuestions);\n\t\tconst activePreviewPane = this.tabsByIndex[paneIndex]?.preview ?? this.tabsByIndex[0]!.preview;\n\n\t\tconst liveInlineValue = this.inlineInput.getValue();\n\t\tconst inputBuffer =\n\t\t\tstate.customDraftByTab.get(state.currentTab) ?? (state.inlineInputOwner === \"other\" ? liveInlineValue : \"\");\n\t\tconst inputCaret = state.customCaretByTab.get(state.currentTab) ?? inputBuffer.length;\n\t\tconst chatInputBuffer =\n\t\t\tstate.chatDraftByTab.get(state.currentTab) ?? (state.inlineInputOwner === \"chat\" ? liveInlineValue : \"\");\n\t\tconst chatInputCaret = state.chatCaretByTab.get(state.currentTab) ?? chatInputBuffer.length;\n\t\tconst ctx: BindingContext = {\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t\ttotalQuestions,\n\t\t\tactiveView,\n\t\t\tinputBuffer,\n\t\t\tinputCaret,\n\t\t\tchatInputBuffer,\n\t\t\tchatInputCaret,\n\t\t\tactivePreviewPane,\n\t\t};\n\n\t\tfor (const binding of this.globalBindings) {\n\t\t\tbinding.apply(state, ctx);\n\t\t}\n\n\t\tfor (let i = 0; i < this.tabsByIndex.length; i++) {\n\t\t\tconst tab = this.tabsByIndex[i]!;\n\t\t\tconst tabCtx: PerTabBindingContext = { ...ctx, tab, i };\n\t\t\tfor (const binding of this.perTabBindings) {\n\t\t\t\tbinding.apply(state, tabCtx);\n\t\t\t}\n\t\t}\n\n\t\tthis.tui.requestRender();\n\t}\n\n\t/**\n\t * Invalidates every owned renderable. Called by the session in place of\n\t * the old `dialog.invalidate()` forwarding chain — DialogView no longer\n\t * reaches into siblings (chatRow, tabBar, notesInput, activePreviewPane).\n\t * Iterates the same registries used by `apply()` plus\n\t * `extraInvalidatables` for components outside the binding system.\n\t */\n\tinvalidate(): void {\n\t\tfor (const b of this.globalBindings) b.invalidate();\n\t\tfor (const tab of this.tabsByIndex) {\n\t\t\ttab.optionList.invalidate();\n\t\t\ttab.preview.invalidate();\n\t\t\ttab.multiSelect?.invalidate();\n\t\t}\n\t\tfor (const x of this.extraInvalidatables) x.invalidate();\n\t}\n}\n"]}
@@ -3,9 +3,9 @@ import { formatAnswerScalar } from "../tool/format-answer.js";
3
3
  import { HINT_PART_CANCEL, HINT_PART_ENTER, HINT_PART_NAV, HINT_PART_NOTES, HINT_PART_TAB, HINT_PART_TOGGLE, INCOMPLETE_WARNING_PREFIX, READY_PROMPT, REVIEW_HEADING, } from "./dialog-builder.js";
4
4
  const NOTES_HEADER = "Notes:";
5
5
  export class QuestionTabStrategy {
6
+ /** Spacer(1) + chatRow(1) + Spacer(1) + Text(hint, 1) = 4 rendered rows. */
7
+ footerRowCount = 4;
6
8
  constructor(config) {
7
- /** Spacer(1) + chatRow(1) + Spacer(1) + Text(hint, 1) = 4 rendered rows. */
8
- this.footerRowCount = 4;
9
9
  this.config = config;
10
10
  }
11
11
  headingRows(state) {
@@ -48,9 +48,9 @@ export class QuestionTabStrategy {
48
48
  }
49
49
  }
50
50
  export class SubmitTabStrategy {
51
+ /** Spacer(1) + Text(prompt, 1) + Spacer(1) + submitPicker(2) = 5 rendered rows. Fallback path lands at 5 via 2 trailing Spacer(1)s. */
52
+ footerRowCount = 5;
51
53
  constructor(config) {
52
- /** Spacer(1) + Text(prompt, 1) + Spacer(1) + submitPicker(2) = 5 rendered rows. Fallback path lands at 5 via 2 trailing Spacer(1)s. */
53
- this.footerRowCount = 5;
54
54
  this.config = config;
55
55
  }
56
56
  headingRows(_state) {
@@ -1 +1 @@
1
- {"version":3,"file":"tab-content-strategy.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/view/tab-content-strategy.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, type Input, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../../../modes/interactive/theme/theme.js\";\nimport { formatAnswerScalar } from \"../tool/format-answer.ts\";\nimport type { QuestionData } from \"../tool/types.js\";\nimport type { ChatRowView } from \"./components/chat-row-view.ts\";\nimport type { PreviewPaneProps } from \"./components/preview/preview-pane.ts\";\nimport {\n\ttype DialogState,\n\tHINT_PART_CANCEL,\n\tHINT_PART_ENTER,\n\tHINT_PART_NAV,\n\tHINT_PART_NOTES,\n\tHINT_PART_TAB,\n\tHINT_PART_TOGGLE,\n\tINCOMPLETE_WARNING_PREFIX,\n\tREADY_PROMPT,\n\tREVIEW_HEADING,\n} from \"./dialog-builder.ts\";\nimport type { StatefulView } from \"./stateful-view.ts\";\nimport type { TabComponents } from \"./tab-components.ts\";\n\nconst NOTES_HEADER = \"Notes:\";\n\n/**\n * Per-tab content provider. Pure functional — closes over construction-time\n * config; per-tick state threads through method args. The chrome wrapper\n * enforces height equality across tabs via `bodyHeight + footerRowCount`.\n */\nexport interface TabContentStrategy {\n\t/** Total RENDERED footer rows — MUST equal what `footerRows()` actually emits. Drives residual math. */\n\treadonly footerRowCount: number;\n\n\t/** Variable rows above the body, after top chrome (border + tabBar + Spacer). */\n\theadingRows(state: DialogState): Component[];\n\n\t/** Body Component placed at the body slot. */\n\tbodyComponent(state: DialogState): Component;\n\n\t/** Natural rendered height of `bodyComponent(state)` at given width. */\n\tbodyHeight(width: number, state: DialogState): number;\n\n\t/** Optional rows between body's trailing Spacer and the bottom border. */\n\tmidRows(state: DialogState): Component[];\n\n\t/** Footer rows below the bottom border. Rendered row count MUST equal `footerRowCount`. */\n\tfooterRows(state: DialogState): Component[];\n}\n\nexport interface QuestionTabStrategyConfig {\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\tgetPreviewPane: () => StatefulView<PreviewPaneProps>;\n\ttabsByIndex: ReadonlyArray<TabComponents>;\n\tnotesInput: Input;\n\tchatRow: ChatRowView;\n\tisMulti: boolean;\n\tgetCurrentBodyHeight: (width: number) => number;\n}\n\nexport class QuestionTabStrategy implements TabContentStrategy {\n\t/** Spacer(1) + chatRow(1) + Spacer(1) + Text(hint, 1) = 4 rendered rows. */\n\treadonly footerRowCount = 4;\n\n\tprivate declare readonly config: QuestionTabStrategyConfig;\n\n\tconstructor(config: QuestionTabStrategyConfig) {\n\t\tthis.config = config;\n\t}\n\n\theadingRows(state: DialogState): Component[] {\n\t\tconst out: Component[] = [];\n\t\tconst question = this.config.questions[state.currentTab];\n\t\t// In multi-question mode the tab bar already shows the header; suppress the inline badge.\n\t\tif (!this.config.isMulti && question?.header && question.header.length > 0) {\n\t\t\tout.push(new Text(this.config.theme.bg(\"selectedBg\", ` ${question.header} `), 1, 0));\n\t\t\tout.push(new Spacer(1));\n\t\t}\n\t\tif (question) {\n\t\t\tout.push(new Text(this.config.theme.bold(question.question), 1, 0));\n\t\t\tout.push(new Spacer(1));\n\t\t}\n\t\treturn out;\n\t}\n\n\tbodyComponent(state: DialogState): Component {\n\t\tconst question = this.config.questions[state.currentTab];\n\t\tconst mso = this.config.tabsByIndex[state.currentTab]?.multiSelect;\n\t\tif (question?.multiSelect === true && mso) return mso;\n\t\treturn this.config.getPreviewPane();\n\t}\n\n\tbodyHeight(width: number, _state: DialogState): number {\n\t\treturn this.config.getCurrentBodyHeight(width);\n\t}\n\n\tmidRows(state: DialogState): Component[] {\n\t\tif (!state.notesVisible) return [];\n\t\treturn [new Text(this.config.theme.fg(\"muted\", NOTES_HEADER), 1, 0), this.config.notesInput, new Spacer(1)];\n\t}\n\n\tfooterRows(state: DialogState): Component[] {\n\t\tconst question = this.config.questions[state.currentTab];\n\t\treturn [\n\t\t\tnew Spacer(1),\n\t\t\tthis.config.chatRow,\n\t\t\tnew Spacer(1),\n\t\t\tnew Text(this.config.theme.fg(\"dim\", buildHintText(question, this.config.isMulti, state)), 1, 0),\n\t\t];\n\t}\n}\n\nexport interface SubmitTabStrategyConfig {\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\tsubmitPicker: Component | undefined;\n}\n\nexport class SubmitTabStrategy implements TabContentStrategy {\n\t/** Spacer(1) + Text(prompt, 1) + Spacer(1) + submitPicker(2) = 5 rendered rows. Fallback path lands at 5 via 2 trailing Spacer(1)s. */\n\treadonly footerRowCount = 5;\n\n\tprivate declare readonly config: SubmitTabStrategyConfig;\n\n\tconstructor(config: SubmitTabStrategyConfig) {\n\t\tthis.config = config;\n\t}\n\n\theadingRows(_state: DialogState): Component[] {\n\t\treturn [new Text(this.config.theme.bold(this.config.theme.fg(\"accent\", REVIEW_HEADING)), 1, 0), new Spacer(1)];\n\t}\n\n\tbodyComponent(state: DialogState): Component {\n\t\tconst c = new Container();\n\t\tfor (let i = 0; i < this.config.questions.length; i++) {\n\t\t\tconst q = this.config.questions[i];\n\t\t\tconst a = state.answers.get(i);\n\t\t\tif (!a) continue;\n\t\t\tconst label = q.header && q.header.length > 0 ? q.header : `Q${i + 1}`;\n\t\t\tconst answerText = formatAnswerScalar(a, \"summary\");\n\t\t\tc.addChild(new Text(this.config.theme.fg(\"muted\", ` ● ${label}`), 1, 0));\n\t\t\tc.addChild(\n\t\t\t\tnew Text(` ${this.config.theme.fg(\"muted\", \"→\")} ${this.config.theme.fg(\"text\", answerText)}`, 1, 0),\n\t\t\t);\n\t\t\tif (a.notes && a.notes.length > 0) {\n\t\t\t\tc.addChild(new Text(this.config.theme.fg(\"dim\", ` notes: ${a.notes}`), 1, 0));\n\t\t\t}\n\t\t}\n\t\treturn c;\n\t}\n\n\tbodyHeight(width: number, state: DialogState): number {\n\t\treturn this.bodyComponent(state).render(width).length;\n\t}\n\n\tmidRows(_state: DialogState): Component[] {\n\t\treturn [];\n\t}\n\n\tfooterRows(state: DialogState): Component[] {\n\t\tconst missing: string[] = [];\n\t\tfor (let i = 0; i < this.config.questions.length; i++) {\n\t\t\tconst q = this.config.questions[i];\n\t\t\tif (!state.answers.has(i)) {\n\t\t\t\tmissing.push(q.header && q.header.length > 0 ? q.header : `Q${i + 1}`);\n\t\t\t}\n\t\t}\n\t\tconst promptText =\n\t\t\tmissing.length === 0\n\t\t\t\t? this.config.theme.fg(\"muted\", READY_PROMPT)\n\t\t\t\t: this.config.theme.fg(\"warning\", `${INCOMPLETE_WARNING_PREFIX} ${missing.join(\", \")}`);\n\t\tconst out: Component[] = [new Spacer(1), new Text(promptText, 1, 0), new Spacer(1)];\n\t\tif (this.config.submitPicker) {\n\t\t\tout.push(this.config.submitPicker);\n\t\t} else {\n\t\t\t// Padding when the picker isn't wired — keeps rendered row count at footerRowCount=5.\n\t\t\tout.push(new Spacer(1));\n\t\t\tout.push(new Spacer(1));\n\t\t}\n\t\treturn out;\n\t}\n}\n\n/**\n * Build the controls hint line. Order is fixed so `HINT_SINGLE` / `HINT_MULTI`\n * remain contiguous substrings of the result:\n * Enter · ↑/↓ [· Space toggle] [· n notes] [· Tab switch] · Esc\n */\nexport function buildHintText(question: QuestionData | undefined, isMulti: boolean, state: DialogState): string {\n\tconst parts: string[] = [HINT_PART_ENTER, HINT_PART_NAV];\n\tif (question?.multiSelect === true) parts.push(HINT_PART_TOGGLE);\n\tif (question && question.multiSelect !== true && state.focusedOptionHasPreview && !state.notesVisible) {\n\t\tparts.push(HINT_PART_NOTES);\n\t}\n\tif (isMulti) parts.push(HINT_PART_TAB);\n\tparts.push(HINT_PART_CANCEL);\n\treturn parts.join(\" · \");\n}\n"]}
1
+ {"version":3,"file":"tab-content-strategy.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/view/tab-content-strategy.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, type Input, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../../../modes/interactive/theme/theme.js\";\nimport { formatAnswerScalar } from \"../tool/format-answer.ts\";\nimport type { QuestionData } from \"../tool/types.js\";\nimport type { ChatRowView } from \"./components/chat-row-view.ts\";\nimport type { PreviewPaneProps } from \"./components/preview/preview-pane.ts\";\nimport {\n\ttype DialogState,\n\tHINT_PART_CANCEL,\n\tHINT_PART_ENTER,\n\tHINT_PART_NAV,\n\tHINT_PART_NOTES,\n\tHINT_PART_TAB,\n\tHINT_PART_TOGGLE,\n\tINCOMPLETE_WARNING_PREFIX,\n\tREADY_PROMPT,\n\tREVIEW_HEADING,\n} from \"./dialog-builder.ts\";\nimport type { StatefulView } from \"./stateful-view.ts\";\nimport type { TabComponents } from \"./tab-components.ts\";\n\nconst NOTES_HEADER = \"Notes:\";\n\n/**\n * Per-tab content provider. Pure functional — closes over construction-time\n * config; per-tick state threads through method args. The chrome wrapper\n * enforces height equality across tabs via `bodyHeight + footerRowCount`.\n */\nexport interface TabContentStrategy {\n\t/** Total RENDERED footer rows — MUST equal what `footerRows()` actually emits. Drives residual math. */\n\treadonly footerRowCount: number;\n\n\t/** Variable rows above the body, after top chrome (border + tabBar + Spacer). */\n\theadingRows(state: DialogState): Component[];\n\n\t/** Body Component placed at the body slot. */\n\tbodyComponent(state: DialogState): Component;\n\n\t/** Natural rendered height of `bodyComponent(state)` at given width. */\n\tbodyHeight(width: number, state: DialogState): number;\n\n\t/** Optional rows between body's trailing Spacer and the bottom border. */\n\tmidRows(state: DialogState): Component[];\n\n\t/** Footer rows below the bottom border. Rendered row count MUST equal `footerRowCount`. */\n\tfooterRows(state: DialogState): Component[];\n}\n\nexport interface QuestionTabStrategyConfig {\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\tgetPreviewPane: () => StatefulView<PreviewPaneProps>;\n\ttabsByIndex: ReadonlyArray<TabComponents>;\n\tnotesInput: Input;\n\tchatRow: ChatRowView;\n\tisMulti: boolean;\n\tgetCurrentBodyHeight: (width: number) => number;\n}\n\nexport class QuestionTabStrategy implements TabContentStrategy {\n\t/** Spacer(1) + chatRow(1) + Spacer(1) + Text(hint, 1) = 4 rendered rows. */\n\treadonly footerRowCount = 4;\n\n\tprivate declare readonly config: QuestionTabStrategyConfig;\n\n\tconstructor(config: QuestionTabStrategyConfig) {\n\t\tthis.config = config;\n\t}\n\n\theadingRows(state: DialogState): Component[] {\n\t\tconst out: Component[] = [];\n\t\tconst question = this.config.questions[state.currentTab];\n\t\t// In multi-question mode the tab bar already shows the header; suppress the inline badge.\n\t\tif (!this.config.isMulti && question?.header && question.header.length > 0) {\n\t\t\tout.push(new Text(this.config.theme.bg(\"selectedBg\", ` ${question.header} `), 1, 0));\n\t\t\tout.push(new Spacer(1));\n\t\t}\n\t\tif (question) {\n\t\t\tout.push(new Text(this.config.theme.bold(question.question), 1, 0));\n\t\t\tout.push(new Spacer(1));\n\t\t}\n\t\treturn out;\n\t}\n\n\tbodyComponent(state: DialogState): Component {\n\t\tconst question = this.config.questions[state.currentTab];\n\t\tconst mso = this.config.tabsByIndex[state.currentTab]?.multiSelect;\n\t\tif (question?.multiSelect === true && mso) return mso;\n\t\treturn this.config.getPreviewPane();\n\t}\n\n\tbodyHeight(width: number, _state: DialogState): number {\n\t\treturn this.config.getCurrentBodyHeight(width);\n\t}\n\n\tmidRows(state: DialogState): Component[] {\n\t\tif (!state.notesVisible) return [];\n\t\treturn [new Text(this.config.theme.fg(\"muted\", NOTES_HEADER), 1, 0), this.config.notesInput, new Spacer(1)];\n\t}\n\n\tfooterRows(state: DialogState): Component[] {\n\t\tconst question = this.config.questions[state.currentTab];\n\t\treturn [\n\t\t\tnew Spacer(1),\n\t\t\tthis.config.chatRow,\n\t\t\tnew Spacer(1),\n\t\t\tnew Text(this.config.theme.fg(\"dim\", buildHintText(question, this.config.isMulti, state)), 1, 0),\n\t\t];\n\t}\n}\n\nexport interface SubmitTabStrategyConfig {\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\tsubmitPicker: Component | undefined;\n}\n\nexport class SubmitTabStrategy implements TabContentStrategy {\n\t/** Spacer(1) + Text(prompt, 1) + Spacer(1) + submitPicker(2) = 5 rendered rows. Fallback path lands at 5 via 2 trailing Spacer(1)s. */\n\treadonly footerRowCount = 5;\n\n\tprivate declare readonly config: SubmitTabStrategyConfig;\n\n\tconstructor(config: SubmitTabStrategyConfig) {\n\t\tthis.config = config;\n\t}\n\n\theadingRows(_state: DialogState): Component[] {\n\t\treturn [new Text(this.config.theme.bold(this.config.theme.fg(\"accent\", REVIEW_HEADING)), 1, 0), new Spacer(1)];\n\t}\n\n\tbodyComponent(state: DialogState): Component {\n\t\tconst c = new Container();\n\t\tfor (let i = 0; i < this.config.questions.length; i++) {\n\t\t\tconst q = this.config.questions[i];\n\t\t\tconst a = state.answers.get(i);\n\t\t\tif (!a) continue;\n\t\t\tconst label = q.header && q.header.length > 0 ? q.header : `Q${i + 1}`;\n\t\t\tconst answerText = formatAnswerScalar(a, \"summary\");\n\t\t\tc.addChild(new Text(this.config.theme.fg(\"muted\", ` ● ${label}`), 1, 0));\n\t\t\tc.addChild(\n\t\t\t\tnew Text(` ${this.config.theme.fg(\"muted\", \"→\")} ${this.config.theme.fg(\"text\", answerText)}`, 1, 0),\n\t\t\t);\n\t\t\tif (a.notes && a.notes.length > 0) {\n\t\t\t\tc.addChild(new Text(this.config.theme.fg(\"dim\", ` notes: ${a.notes}`), 1, 0));\n\t\t\t}\n\t\t}\n\t\treturn c;\n\t}\n\n\tbodyHeight(width: number, state: DialogState): number {\n\t\treturn this.bodyComponent(state).render(width).length;\n\t}\n\n\tmidRows(_state: DialogState): Component[] {\n\t\treturn [];\n\t}\n\n\tfooterRows(state: DialogState): Component[] {\n\t\tconst missing: string[] = [];\n\t\tfor (let i = 0; i < this.config.questions.length; i++) {\n\t\t\tconst q = this.config.questions[i];\n\t\t\tif (!state.answers.has(i)) {\n\t\t\t\tmissing.push(q.header && q.header.length > 0 ? q.header : `Q${i + 1}`);\n\t\t\t}\n\t\t}\n\t\tconst promptText =\n\t\t\tmissing.length === 0\n\t\t\t\t? this.config.theme.fg(\"muted\", READY_PROMPT)\n\t\t\t\t: this.config.theme.fg(\"warning\", `${INCOMPLETE_WARNING_PREFIX} ${missing.join(\", \")}`);\n\t\tconst out: Component[] = [new Spacer(1), new Text(promptText, 1, 0), new Spacer(1)];\n\t\tif (this.config.submitPicker) {\n\t\t\tout.push(this.config.submitPicker);\n\t\t} else {\n\t\t\t// Padding when the picker isn't wired — keeps rendered row count at footerRowCount=5.\n\t\t\tout.push(new Spacer(1));\n\t\t\tout.push(new Spacer(1));\n\t\t}\n\t\treturn out;\n\t}\n}\n\n/**\n * Build the controls hint line. Order is fixed so `HINT_SINGLE` / `HINT_MULTI`\n * remain contiguous substrings of the result:\n * Enter · ↑/↓ [· Space toggle] [· n notes] [· Tab switch] · Esc\n */\nexport function buildHintText(question: QuestionData | undefined, isMulti: boolean, state: DialogState): string {\n\tconst parts: string[] = [HINT_PART_ENTER, HINT_PART_NAV];\n\tif (question?.multiSelect === true) parts.push(HINT_PART_TOGGLE);\n\tif (question && question.multiSelect !== true && state.focusedOptionHasPreview && !state.notesVisible) {\n\t\tparts.push(HINT_PART_NOTES);\n\t}\n\tif (isMulti) parts.push(HINT_PART_TAB);\n\tparts.push(HINT_PART_CANCEL);\n\treturn parts.join(\" · \");\n}\n"]}
@@ -221,14 +221,11 @@ function bashResultToToolResult(result) {
221
221
  return { content: [{ type: "text", text }], details };
222
222
  }
223
223
  class BashResultRenderComponent extends Container {
224
- constructor() {
225
- super(...arguments);
226
- this.state = {
227
- cachedWidth: undefined,
228
- cachedLines: undefined,
229
- cachedSkipped: undefined,
230
- };
231
- }
224
+ state = {
225
+ cachedWidth: undefined,
226
+ cachedLines: undefined,
227
+ cachedSkipped: undefined,
228
+ };
232
229
  }
233
230
  function formatDuration(ms) {
234
231
  const seconds = Math.max(0, ms) / 1000;