@bastani/atomic 0.8.11 → 0.8.12

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 (514) hide show
  1. package/CHANGELOG.md +43 -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 +3 -0
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/subagents/src/agents/agent-serializer.ts +3 -2
  7. package/dist/builtin/subagents/src/agents/agents.ts +1 -1
  8. package/dist/builtin/subagents/src/extension/index.ts +597 -471
  9. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +16 -8
  10. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +9 -13
  11. package/dist/builtin/subagents/src/runs/foreground/execution.ts +7 -3
  12. package/dist/builtin/subagents/src/shared/formatters.ts +8 -3
  13. package/dist/builtin/subagents/src/slash/slash-commands.ts +625 -468
  14. package/dist/builtin/subagents/src/tui/render.ts +342 -158
  15. package/dist/builtin/web-access/package.json +1 -1
  16. package/dist/builtin/workflows/package.json +1 -1
  17. package/dist/builtin/workflows/src/runs/foreground/executor.ts +15 -4
  18. package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +75 -33
  19. package/dist/builtin/workflows/src/shared/store-types.ts +3 -4
  20. package/dist/builtin/workflows/src/shared/store.ts +2 -3
  21. package/dist/builtin/workflows/src/tui/graph-view.ts +12 -1
  22. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +1 -2
  23. package/dist/builtin/workflows/src/tui/status-helpers.ts +1 -1
  24. package/dist/bun/cli.d.ts.map +1 -1
  25. package/dist/bun/cli.js.map +1 -1
  26. package/dist/cli/args.d.ts +1 -1
  27. package/dist/cli/args.d.ts.map +1 -1
  28. package/dist/cli/args.js.map +1 -1
  29. package/dist/cli/config-selector.d.ts +2 -2
  30. package/dist/cli/config-selector.d.ts.map +1 -1
  31. package/dist/cli/config-selector.js.map +1 -1
  32. package/dist/cli/file-processor.d.ts.map +1 -1
  33. package/dist/cli/file-processor.js.map +1 -1
  34. package/dist/cli/initial-message.d.ts +1 -1
  35. package/dist/cli/initial-message.d.ts.map +1 -1
  36. package/dist/cli/initial-message.js.map +1 -1
  37. package/dist/cli/list-models.d.ts +1 -1
  38. package/dist/cli/list-models.d.ts.map +1 -1
  39. package/dist/cli/list-models.js.map +1 -1
  40. package/dist/cli/session-picker.d.ts +1 -1
  41. package/dist/cli/session-picker.d.ts.map +1 -1
  42. package/dist/cli/session-picker.js.map +1 -1
  43. package/dist/cli.d.ts.map +1 -1
  44. package/dist/cli.js +2 -6
  45. package/dist/cli.js.map +1 -1
  46. package/dist/config.d.ts.map +1 -1
  47. package/dist/config.js +45 -22
  48. package/dist/config.js.map +1 -1
  49. package/dist/core/agent-session-runtime.d.ts +9 -9
  50. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  51. package/dist/core/agent-session-runtime.js +2 -3
  52. package/dist/core/agent-session-runtime.js.map +1 -1
  53. package/dist/core/agent-session-services.d.ts +7 -7
  54. package/dist/core/agent-session-services.d.ts.map +1 -1
  55. package/dist/core/agent-session-services.js.map +1 -1
  56. package/dist/core/agent-session.d.ts +10 -10
  57. package/dist/core/agent-session.d.ts.map +1 -1
  58. package/dist/core/agent-session.js.map +1 -1
  59. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  60. package/dist/core/atomic-guide-command.js.map +1 -1
  61. package/dist/core/auth-guidance.d.ts.map +1 -1
  62. package/dist/core/auth-guidance.js.map +1 -1
  63. package/dist/core/auth-storage.d.ts +1 -1
  64. package/dist/core/auth-storage.d.ts.map +1 -1
  65. package/dist/core/auth-storage.js +1 -1
  66. package/dist/core/auth-storage.js.map +1 -1
  67. package/dist/core/bash-executor.d.ts +1 -1
  68. package/dist/core/bash-executor.d.ts.map +1 -1
  69. package/dist/core/bash-executor.js.map +1 -1
  70. package/dist/core/builtin-packages.d.ts.map +1 -1
  71. package/dist/core/builtin-packages.js.map +1 -1
  72. package/dist/core/compaction/branch-summarization.d.ts +3 -3
  73. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  74. package/dist/core/compaction/branch-summarization.js.map +1 -1
  75. package/dist/core/compaction/compaction.d.ts +2 -2
  76. package/dist/core/compaction/compaction.d.ts.map +1 -1
  77. package/dist/core/compaction/compaction.js.map +1 -1
  78. package/dist/core/compaction/index.d.ts +3 -3
  79. package/dist/core/compaction/index.d.ts.map +1 -1
  80. package/dist/core/compaction/index.js.map +1 -1
  81. package/dist/core/exec.d.ts.map +1 -1
  82. package/dist/core/exec.js.map +1 -1
  83. package/dist/core/export-html/index.d.ts +1 -1
  84. package/dist/core/export-html/index.d.ts.map +1 -1
  85. package/dist/core/export-html/index.js.map +1 -1
  86. package/dist/core/export-html/tool-renderer.d.ts +2 -2
  87. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  88. package/dist/core/export-html/tool-renderer.js.map +1 -1
  89. package/dist/core/extensions/index.d.ts +8 -8
  90. package/dist/core/extensions/index.d.ts.map +1 -1
  91. package/dist/core/extensions/index.js.map +1 -1
  92. package/dist/core/extensions/loader.d.ts +3 -3
  93. package/dist/core/extensions/loader.d.ts.map +1 -1
  94. package/dist/core/extensions/loader.js.map +1 -1
  95. package/dist/core/extensions/runner.d.ts +6 -6
  96. package/dist/core/extensions/runner.d.ts.map +1 -1
  97. package/dist/core/extensions/runner.js.map +1 -1
  98. package/dist/core/extensions/types.d.ts +20 -20
  99. package/dist/core/extensions/types.d.ts.map +1 -1
  100. package/dist/core/extensions/types.js.map +1 -1
  101. package/dist/core/extensions/wrapper.d.ts +2 -2
  102. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  103. package/dist/core/extensions/wrapper.js.map +1 -1
  104. package/dist/core/footer-data-provider.d.ts.map +1 -1
  105. package/dist/core/footer-data-provider.js.map +1 -1
  106. package/dist/core/http-dispatcher.d.ts +32 -0
  107. package/dist/core/http-dispatcher.d.ts.map +1 -0
  108. package/dist/core/http-dispatcher.js +43 -0
  109. package/dist/core/http-dispatcher.js.map +1 -0
  110. package/dist/core/index.d.ts +8 -8
  111. package/dist/core/index.d.ts.map +1 -1
  112. package/dist/core/index.js.map +1 -1
  113. package/dist/core/keybindings.d.ts.map +1 -1
  114. package/dist/core/keybindings.js.map +1 -1
  115. package/dist/core/model-registry.d.ts +4 -4
  116. package/dist/core/model-registry.d.ts.map +1 -1
  117. package/dist/core/model-registry.js +2 -2
  118. package/dist/core/model-registry.js.map +1 -1
  119. package/dist/core/model-resolver.d.ts +1 -1
  120. package/dist/core/model-resolver.d.ts.map +1 -1
  121. package/dist/core/model-resolver.js.map +1 -1
  122. package/dist/core/package-manager.d.ts +1 -1
  123. package/dist/core/package-manager.d.ts.map +1 -1
  124. package/dist/core/package-manager.js +10 -11
  125. package/dist/core/package-manager.js.map +1 -1
  126. package/dist/core/prompt-templates.d.ts +1 -1
  127. package/dist/core/prompt-templates.d.ts.map +1 -1
  128. package/dist/core/prompt-templates.js.map +1 -1
  129. package/dist/core/resolve-config-value.d.ts.map +1 -1
  130. package/dist/core/resolve-config-value.js.map +1 -1
  131. package/dist/core/resource-loader.d.ts +9 -9
  132. package/dist/core/resource-loader.d.ts.map +1 -1
  133. package/dist/core/resource-loader.js.map +1 -1
  134. package/dist/core/sdk.d.ts +13 -13
  135. package/dist/core/sdk.d.ts.map +1 -1
  136. package/dist/core/sdk.js.map +1 -1
  137. package/dist/core/session-manager.d.ts +1 -1
  138. package/dist/core/session-manager.d.ts.map +1 -1
  139. package/dist/core/session-manager.js.map +1 -1
  140. package/dist/core/settings-manager.d.ts +3 -0
  141. package/dist/core/settings-manager.d.ts.map +1 -1
  142. package/dist/core/settings-manager.js +21 -0
  143. package/dist/core/settings-manager.js.map +1 -1
  144. package/dist/core/skills.d.ts +2 -2
  145. package/dist/core/skills.d.ts.map +1 -1
  146. package/dist/core/skills.js.map +1 -1
  147. package/dist/core/slash-commands.d.ts +1 -1
  148. package/dist/core/slash-commands.d.ts.map +1 -1
  149. package/dist/core/slash-commands.js.map +1 -1
  150. package/dist/core/source-info.d.ts +1 -1
  151. package/dist/core/source-info.d.ts.map +1 -1
  152. package/dist/core/source-info.js.map +1 -1
  153. package/dist/core/system-prompt.d.ts +1 -1
  154. package/dist/core/system-prompt.d.ts.map +1 -1
  155. package/dist/core/system-prompt.js +7 -8
  156. package/dist/core/system-prompt.js.map +1 -1
  157. package/dist/core/telemetry.d.ts +1 -1
  158. package/dist/core/telemetry.d.ts.map +1 -1
  159. package/dist/core/telemetry.js.map +1 -1
  160. package/dist/core/timings.d.ts.map +1 -1
  161. package/dist/core/timings.js.map +1 -1
  162. package/dist/core/tools/ask-user-question/ask-user-question.d.ts +4 -4
  163. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  164. package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
  165. package/dist/core/tools/ask-user-question/index.d.ts +1 -1
  166. package/dist/core/tools/ask-user-question/index.d.ts.map +1 -1
  167. package/dist/core/tools/ask-user-question/index.js.map +1 -1
  168. package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts +5 -5
  169. package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts.map +1 -1
  170. package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
  171. package/dist/core/tools/ask-user-question/state/key-router.d.ts +2 -2
  172. package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
  173. package/dist/core/tools/ask-user-question/state/key-router.js.map +1 -1
  174. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +3 -3
  175. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  176. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  177. package/dist/core/tools/ask-user-question/state/row-intent.d.ts +2 -2
  178. package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
  179. package/dist/core/tools/ask-user-question/state/row-intent.js.map +1 -1
  180. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +6 -6
  181. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  182. package/dist/core/tools/ask-user-question/state/selectors/contract.js.map +1 -1
  183. package/dist/core/tools/ask-user-question/state/selectors/derivations.d.ts +2 -2
  184. package/dist/core/tools/ask-user-question/state/selectors/derivations.d.ts.map +1 -1
  185. package/dist/core/tools/ask-user-question/state/selectors/derivations.js.map +1 -1
  186. package/dist/core/tools/ask-user-question/state/selectors/focus.d.ts +1 -1
  187. package/dist/core/tools/ask-user-question/state/selectors/focus.d.ts.map +1 -1
  188. package/dist/core/tools/ask-user-question/state/selectors/focus.js.map +1 -1
  189. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts +8 -8
  190. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  191. package/dist/core/tools/ask-user-question/state/selectors/projections.js.map +1 -1
  192. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts +4 -4
  193. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  194. package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
  195. package/dist/core/tools/ask-user-question/state/state.d.ts +2 -2
  196. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  197. package/dist/core/tools/ask-user-question/state/state.js.map +1 -1
  198. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts +1 -1
  199. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  200. package/dist/core/tools/ask-user-question/tool/format-answer.js.map +1 -1
  201. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts +1 -1
  202. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  203. package/dist/core/tools/ask-user-question/tool/response-envelope.js.map +1 -1
  204. package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
  205. package/dist/core/tools/ask-user-question/tool/types.js.map +1 -1
  206. package/dist/core/tools/ask-user-question/tool/validate-questionnaire.d.ts +1 -1
  207. package/dist/core/tools/ask-user-question/tool/validate-questionnaire.d.ts.map +1 -1
  208. package/dist/core/tools/ask-user-question/tool/validate-questionnaire.js.map +1 -1
  209. package/dist/core/tools/ask-user-question/view/body-residual-spacer.d.ts.map +1 -1
  210. package/dist/core/tools/ask-user-question/view/body-residual-spacer.js.map +1 -1
  211. package/dist/core/tools/ask-user-question/view/component-binding.d.ts +4 -4
  212. package/dist/core/tools/ask-user-question/view/component-binding.d.ts.map +1 -1
  213. package/dist/core/tools/ask-user-question/view/component-binding.js.map +1 -1
  214. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts +2 -2
  215. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
  216. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
  217. package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts +4 -4
  218. package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts.map +1 -1
  219. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
  220. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts +2 -2
  221. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
  222. package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
  223. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts +2 -2
  224. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts.map +1 -1
  225. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
  226. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts +3 -3
  227. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts.map +1 -1
  228. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
  229. package/dist/core/tools/ask-user-question/view/components/preview/preview-layout-decider.d.ts +2 -2
  230. package/dist/core/tools/ask-user-question/view/components/preview/preview-layout-decider.d.ts.map +1 -1
  231. package/dist/core/tools/ask-user-question/view/components/preview/preview-layout-decider.js.map +1 -1
  232. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.d.ts +8 -8
  233. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.d.ts.map +1 -1
  234. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js.map +1 -1
  235. package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts +3 -3
  236. package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts.map +1 -1
  237. package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
  238. package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts +3 -3
  239. package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts.map +1 -1
  240. package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
  241. package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts +8 -8
  242. package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts.map +1 -1
  243. package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
  244. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts +5 -5
  245. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  246. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  247. package/dist/core/tools/ask-user-question/view/tab-components.d.ts +4 -4
  248. package/dist/core/tools/ask-user-question/view/tab-components.d.ts.map +1 -1
  249. package/dist/core/tools/ask-user-question/view/tab-components.js.map +1 -1
  250. package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts +9 -9
  251. package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts.map +1 -1
  252. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js +2 -2
  253. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
  254. package/dist/core/tools/bash.d.ts +2 -2
  255. package/dist/core/tools/bash.d.ts.map +1 -1
  256. package/dist/core/tools/bash.js +9 -1
  257. package/dist/core/tools/bash.js.map +1 -1
  258. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  259. package/dist/core/tools/edit-diff.js.map +1 -1
  260. package/dist/core/tools/edit.d.ts +2 -2
  261. package/dist/core/tools/edit.d.ts.map +1 -1
  262. package/dist/core/tools/edit.js.map +1 -1
  263. package/dist/core/tools/find.d.ts +2 -2
  264. package/dist/core/tools/find.d.ts.map +1 -1
  265. package/dist/core/tools/find.js.map +1 -1
  266. package/dist/core/tools/grep.d.ts +2 -2
  267. package/dist/core/tools/grep.d.ts.map +1 -1
  268. package/dist/core/tools/grep.js.map +1 -1
  269. package/dist/core/tools/index.d.ts +19 -19
  270. package/dist/core/tools/index.d.ts.map +1 -1
  271. package/dist/core/tools/index.js.map +1 -1
  272. package/dist/core/tools/ls.d.ts +2 -2
  273. package/dist/core/tools/ls.d.ts.map +1 -1
  274. package/dist/core/tools/ls.js.map +1 -1
  275. package/dist/core/tools/output-accumulator.d.ts +1 -1
  276. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  277. package/dist/core/tools/output-accumulator.js.map +1 -1
  278. package/dist/core/tools/read.d.ts +2 -2
  279. package/dist/core/tools/read.d.ts.map +1 -1
  280. package/dist/core/tools/read.js.map +1 -1
  281. package/dist/core/tools/render-utils.d.ts +1 -1
  282. package/dist/core/tools/render-utils.d.ts.map +1 -1
  283. package/dist/core/tools/render-utils.js.map +1 -1
  284. package/dist/core/tools/todos.d.ts +1 -1
  285. package/dist/core/tools/todos.d.ts.map +1 -1
  286. package/dist/core/tools/todos.js.map +1 -1
  287. package/dist/core/tools/tool-definition-wrapper.d.ts +1 -1
  288. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  289. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  290. package/dist/core/tools/write.d.ts +1 -1
  291. package/dist/core/tools/write.d.ts.map +1 -1
  292. package/dist/core/tools/write.js.map +1 -1
  293. package/dist/index.d.ts +30 -29
  294. package/dist/index.d.ts.map +1 -1
  295. package/dist/index.js +1 -0
  296. package/dist/index.js.map +1 -1
  297. package/dist/main.d.ts +1 -1
  298. package/dist/main.d.ts.map +1 -1
  299. package/dist/main.js +2 -0
  300. package/dist/main.js.map +1 -1
  301. package/dist/migrations.d.ts.map +1 -1
  302. package/dist/migrations.js.map +1 -1
  303. package/dist/modes/index.d.ts +5 -5
  304. package/dist/modes/index.d.ts.map +1 -1
  305. package/dist/modes/index.js.map +1 -1
  306. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  307. package/dist/modes/interactive/components/armin.js.map +1 -1
  308. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  309. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  310. package/dist/modes/interactive/components/atomic-banner.d.ts +1 -1
  311. package/dist/modes/interactive/components/atomic-banner.d.ts.map +1 -1
  312. package/dist/modes/interactive/components/atomic-banner.js.map +1 -1
  313. package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
  314. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  315. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  316. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  317. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  318. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  319. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
  320. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  321. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  322. package/dist/modes/interactive/components/chat-message-renderer.d.ts +3 -3
  323. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  324. package/dist/modes/interactive/components/chat-message-renderer.js +1 -1
  325. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  326. package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
  327. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  328. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
  329. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  331. package/dist/modes/interactive/components/config-selector.d.ts +2 -2
  332. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  333. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  334. package/dist/modes/interactive/components/countdown-timer.d.ts +2 -2
  335. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  336. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  337. package/dist/modes/interactive/components/custom-editor.d.ts +1 -1
  338. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  339. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  340. package/dist/modes/interactive/components/custom-message.d.ts +2 -2
  341. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  342. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  343. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  344. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  345. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/diff.js.map +1 -1
  347. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  348. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  349. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  351. package/dist/modes/interactive/components/extension-editor.d.ts +1 -1
  352. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  353. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  354. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  355. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  356. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  357. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  358. package/dist/modes/interactive/components/footer.d.ts +3 -3
  359. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  360. package/dist/modes/interactive/components/footer.js +1 -1
  361. package/dist/modes/interactive/components/footer.js.map +1 -1
  362. package/dist/modes/interactive/components/index.d.ts +34 -34
  363. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/index.js.map +1 -1
  365. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  366. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  367. package/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  368. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  369. package/dist/modes/interactive/components/login-dialog.js +1 -1
  370. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  371. package/dist/modes/interactive/components/model-selector.d.ts +2 -2
  372. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  373. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  374. package/dist/modes/interactive/components/oauth-selector.d.ts +1 -1
  375. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  376. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  377. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  378. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  379. package/dist/modes/interactive/components/session-selector-search.d.ts +1 -1
  380. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  381. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  382. package/dist/modes/interactive/components/session-selector.d.ts +3 -3
  383. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  384. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  385. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  386. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  387. package/dist/modes/interactive/components/settings-selector.js +13 -0
  388. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  389. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  390. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  391. package/dist/modes/interactive/components/skill-invocation-message.d.ts +1 -1
  392. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  393. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  394. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  395. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  396. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  398. package/dist/modes/interactive/components/tool-execution.d.ts +1 -1
  399. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  401. package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
  402. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  403. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  404. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  405. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  406. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  407. package/dist/modes/interactive/components/user-message.js.map +1 -1
  408. package/dist/modes/interactive/components/working-status.d.ts.map +1 -1
  409. package/dist/modes/interactive/components/working-status.js.map +1 -1
  410. package/dist/modes/interactive/interactive-mode.d.ts +2 -2
  411. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  412. package/dist/modes/interactive/interactive-mode.js +7 -1
  413. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  414. package/dist/modes/interactive/theme/theme.d.ts +1 -1
  415. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  416. package/dist/modes/interactive/theme/theme.js.map +1 -1
  417. package/dist/modes/print-mode.d.ts +1 -1
  418. package/dist/modes/print-mode.d.ts.map +1 -1
  419. package/dist/modes/print-mode.js.map +1 -1
  420. package/dist/modes/rpc/rpc-client.d.ts +5 -5
  421. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  422. package/dist/modes/rpc/rpc-client.js +1 -1
  423. package/dist/modes/rpc/rpc-client.js.map +1 -1
  424. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  425. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  426. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  427. package/dist/modes/rpc/rpc-types.d.ts +4 -4
  428. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  429. package/dist/modes/rpc/rpc-types.js.map +1 -1
  430. package/dist/package-manager-cli.d.ts.map +1 -1
  431. package/dist/package-manager-cli.js +22 -6
  432. package/dist/package-manager-cli.js.map +1 -1
  433. package/dist/utils/changelog.d.ts +1 -1
  434. package/dist/utils/changelog.d.ts.map +1 -1
  435. package/dist/utils/changelog.js.map +1 -1
  436. package/dist/utils/child-process.d.ts +5 -2
  437. package/dist/utils/child-process.d.ts.map +1 -1
  438. package/dist/utils/child-process.js +9 -7
  439. package/dist/utils/child-process.js.map +1 -1
  440. package/dist/utils/clipboard-image.d.ts.map +1 -1
  441. package/dist/utils/clipboard-image.js.map +1 -1
  442. package/dist/utils/clipboard.d.ts.map +1 -1
  443. package/dist/utils/clipboard.js.map +1 -1
  444. package/dist/utils/exif-orientation.d.ts +1 -1
  445. package/dist/utils/exif-orientation.d.ts.map +1 -1
  446. package/dist/utils/exif-orientation.js.map +1 -1
  447. package/dist/utils/image-convert.d.ts.map +1 -1
  448. package/dist/utils/image-convert.js.map +1 -1
  449. package/dist/utils/image-resize.d.ts.map +1 -1
  450. package/dist/utils/image-resize.js.map +1 -1
  451. package/dist/utils/shell.d.ts.map +1 -1
  452. package/dist/utils/shell.js.map +1 -1
  453. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  454. package/dist/utils/syntax-highlight.js.map +1 -1
  455. package/dist/utils/tools-manager.d.ts.map +1 -1
  456. package/dist/utils/tools-manager.js.map +1 -1
  457. package/dist/utils/version-check.d.ts.map +1 -1
  458. package/dist/utils/version-check.js.map +1 -1
  459. package/dist/utils/windows-self-update.d.ts +3 -0
  460. package/dist/utils/windows-self-update.d.ts.map +1 -0
  461. package/dist/utils/windows-self-update.js +78 -0
  462. package/dist/utils/windows-self-update.js.map +1 -0
  463. package/docs/compaction.md +5 -5
  464. package/docs/custom-provider.md +2 -2
  465. package/docs/development.md +22 -16
  466. package/docs/docs.json +6 -2
  467. package/docs/extensions.md +25 -25
  468. package/docs/index.md +11 -14
  469. package/docs/keybindings.md +5 -5
  470. package/docs/models.md +6 -6
  471. package/docs/packages.md +55 -48
  472. package/docs/prompt-templates.md +5 -5
  473. package/docs/providers.md +10 -10
  474. package/docs/quickstart.md +32 -30
  475. package/docs/rpc.md +9 -9
  476. package/docs/sdk.md +1 -1
  477. package/docs/session-format.md +3 -3
  478. package/docs/sessions.md +11 -11
  479. package/docs/settings.md +18 -15
  480. package/docs/shell-aliases.md +2 -2
  481. package/docs/skills.md +11 -11
  482. package/docs/terminal-setup.md +8 -8
  483. package/docs/termux.md +6 -6
  484. package/docs/themes.md +10 -10
  485. package/docs/tui.md +5 -4
  486. package/docs/usage.md +50 -50
  487. package/docs/windows.md +2 -2
  488. package/docs/workflows.md +695 -0
  489. package/examples/extensions/custom-provider-gitlab-duo/test.ts +1 -1
  490. package/examples/extensions/doom-overlay/doom-component.ts +2 -2
  491. package/examples/extensions/doom-overlay/index.ts +3 -3
  492. package/examples/extensions/overlay-qa-tests.ts +116 -33
  493. package/examples/extensions/overlay-test.ts +9 -3
  494. package/examples/extensions/plan-mode/index.ts +1 -1
  495. package/examples/extensions/subagent/index.ts +1159 -903
  496. package/package.json +6 -4
  497. package/dist/builtin/workflows/skills/workflow/SKILL.md +0 -322
  498. package/dist/builtin/workflows/skills/workflow/references/context-engineering/advanced-evaluation.md +0 -404
  499. package/dist/builtin/workflows/skills/workflow/references/context-engineering/bdi-mental-states.md +0 -313
  500. package/dist/builtin/workflows/skills/workflow/references/context-engineering/context-compression.md +0 -274
  501. package/dist/builtin/workflows/skills/workflow/references/context-engineering/context-degradation.md +0 -208
  502. package/dist/builtin/workflows/skills/workflow/references/context-engineering/context-fundamentals.md +0 -203
  503. package/dist/builtin/workflows/skills/workflow/references/context-engineering/context-optimization.md +0 -197
  504. package/dist/builtin/workflows/skills/workflow/references/context-engineering/evaluation.md +0 -253
  505. package/dist/builtin/workflows/skills/workflow/references/context-engineering/filesystem-context.md +0 -289
  506. package/dist/builtin/workflows/skills/workflow/references/context-engineering/hosted-agents.md +0 -262
  507. package/dist/builtin/workflows/skills/workflow/references/context-engineering/memory-systems.md +0 -221
  508. package/dist/builtin/workflows/skills/workflow/references/context-engineering/multi-agent-patterns.md +0 -259
  509. package/dist/builtin/workflows/skills/workflow/references/context-engineering/project-development.md +0 -293
  510. package/dist/builtin/workflows/skills/workflow/references/context-engineering/tool-design.md +0 -273
  511. package/dist/builtin/workflows/skills/workflow/references/context-engineering.md +0 -23
  512. package/dist/builtin/workflows/skills/workflow/references/design-checklist.md +0 -83
  513. package/dist/builtin/workflows/skills/workflow/references/running-workflows.md +0 -159
  514. package/dist/builtin/workflows/skills/workflow/references/sdk-authoring.md +0 -260
@@ -1 +1 @@
1
- {"version":3,"file":"questionnaire-session.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/questionnaire-session.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Theme } from \"../../../../modes/interactive/theme/theme.js\";\nimport { getKeybindings, type Input } from \"@earendil-works/pi-tui\";\nimport type { QuestionData, QuestionnaireResult, QuestionParams } from \"../tool/types.js\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.js\";\nimport type { QuestionnairePropsAdapter } from \"../view/props-adapter.js\";\nimport { buildQuestionnaire } from \"./build-questionnaire.js\";\nimport { ROW_INTENT_META } from \"./row-intent.js\";\nimport { type QuestionnaireAction, routeKey } from \"./key-router.js\";\nimport { computeFocusedOptionHasPreview } from \"./selectors/derivations.js\";\nimport type { QuestionnaireRuntime, QuestionnaireState } from \"./state.js\";\nimport { type ApplyContext, type Effect, reduce } from \"./state-reducer.js\";\n\n// Module-level constant; reused for cursor-end mutations after setValue rehydration.\n// Ctrl-E → tui.editor.cursorLineEnd (public path; pi-tui keybindings.js:25-28).\nconst CURSOR_END = \"\\x05\";\n\nexport interface QuestionnaireSessionConfig {\n\ttui: { terminal: { columns: number }; requestRender(): void };\n\ttheme: Theme;\n\tparams: QuestionParams;\n\titemsByTab: WrappingSelectItem[][];\n\tdone: (result: QuestionnaireResult) => void;\n}\n\nexport interface QuestionnaireSessionComponent {\n\trender(width: number): string[];\n\tinvalidate(): void;\n\thandleInput(data: string): void;\n}\n\nfunction initialState(): QuestionnaireState {\n\treturn {\n\t\tcurrentTab: 0,\n\t\toptionIndex: 0,\n\t\tinputMode: false,\n\t\tnotesVisible: false,\n\t\tchatFocused: false,\n\t\tanswers: new Map(),\n\t\tmultiSelectChecked: new Set(),\n\t\tnotesByTab: new Map(),\n\t\tfocusedOptionHasPreview: false,\n\t\tsubmitChoiceIndex: 0,\n\t\tnotesDraft: \"\",\n\t};\n}\n\n/**\n * Slim runtime: owns the canonical state cell, the input-buffer cell, the\n * two-pass `notesVisible` dispatch loop, and the effect runner. State\n * transitions go through the pure `reduce` reducer; UI fan-out goes through\n * the `QuestionnairePropsAdapter` produced by `buildQuestionnaire`.\n */\nexport class QuestionnaireSession {\n\tprivate state: QuestionnaireState = initialState();\n\n\tprivate readonly questions: readonly QuestionData[];\n\tprivate readonly isMulti: boolean;\n\tprivate readonly itemsByTab: WrappingSelectItem[][];\n\n\tprivate readonly notesInput: Input;\n\tprivate readonly inlineInput: Input;\n\tprivate readonly viewAdapter: QuestionnairePropsAdapter;\n\n\tprivate readonly tui: QuestionnaireSessionConfig[\"tui\"];\n\tprivate readonly done: QuestionnaireSessionConfig[\"done\"];\n\n\treadonly component: QuestionnaireSessionComponent;\n\n\tconstructor(config: QuestionnaireSessionConfig) {\n\t\tthis.tui = config.tui;\n\t\tthis.done = config.done;\n\t\tthis.questions = config.params.questions;\n\t\tthis.isMulti = this.questions.length > 1;\n\t\tthis.itemsByTab = config.itemsByTab;\n\t\t// Seed from the focused option at start; the reducer keeps it in sync via withFocusedOptionHasPreview.\n\t\tthis.state = { ...this.state, focusedOptionHasPreview: computeFocusedOptionHasPreview(this.questions, 0, 0) };\n\n\t\tconst built = buildQuestionnaire({\n\t\t\ttui: this.tui,\n\t\t\ttheme: config.theme,\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t\tisMulti: this.isMulti,\n\t\t\tinitialState: this.state,\n\t\t\tgetCurrentTab: () => this.state.currentTab,\n\t\t});\n\n\t\tthis.notesInput = built.notesInput;\n\t\tthis.inlineInput = built.inlineInput;\n\t\tthis.viewAdapter = built.adapter;\n\n\t\tthis.component = {\n\t\t\trender: built.render,\n\t\t\tinvalidate: built.invalidate,\n\t\t\thandleInput: (data) => this.dispatch(data),\n\t\t};\n\n\t\tthis.viewAdapter.apply(this.state);\n\t}\n\n\tdispatch(data: string): void {\n\t\tconst action = routeKey(data, this.state, this.runtime());\n\t\tif (action.kind === \"ignore\") {\n\t\t\tthis.handleIgnoreInline(data);\n\t\t\treturn;\n\t\t}\n\t\tthis.commit(action);\n\t}\n\n\tprivate commit(action: QuestionnaireAction): void {\n\t\tconst result = reduce(this.state, action, this.applyContext());\n\t\tthis.state = result.state;\n\t\tfor (const effect of result.effects) this.runEffect(effect);\n\t\tthis.state = this.mirrorNotesDraft(this.state);\n\t\tthis.viewAdapter.apply(this.state);\n\t}\n\n\tprivate mirrorNotesDraft(s: QuestionnaireState): QuestionnaireState {\n\t\tconst draft = this.notesInput.getValue();\n\t\treturn s.notesDraft === draft ? s : { ...s, notesDraft: draft };\n\t}\n\n\tprivate runEffect(effect: Effect): void {\n\t\tswitch (effect.kind) {\n\t\t\tcase \"set_input_buffer\":\n\t\t\t\tthis.inlineInput.setValue(effect.value);\n\t\t\t\tthis.inlineInput.handleInput(CURSOR_END);\n\t\t\t\treturn;\n\t\t\tcase \"clear_input_buffer\":\n\t\t\t\tthis.inlineInput.setValue(\"\");\n\t\t\t\treturn;\n\t\t\tcase \"set_notes_value\":\n\t\t\t\tthis.notesInput.setValue(effect.value);\n\t\t\t\treturn;\n\t\t\tcase \"set_notes_focused\":\n\t\t\t\tthis.notesInput.focused = effect.focused;\n\t\t\t\treturn;\n\t\t\tcase \"forward_notes_keystroke\":\n\t\t\t\tthis.notesInput.handleInput(effect.data);\n\t\t\t\treturn;\n\t\t\tcase \"done\":\n\t\t\t\tthis.done(effect.result);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\t/**\n\t * Per-keystroke `ignore` fast path: delegates to the headless `inlineInput`\n\t * Input so bracketed-paste accumulator (`input.js:33-63`) and Kitty CSI-u\n\t * decode (`input.js:155-163`) take effect. Cursor is NOT force-reset here —\n\t * doing so would corrupt split-chunk pastes (a `\\x05` byte mid-paste lands\n\t * verbatim in `pasteBuffer` and survives `handlePaste`'s narrow strip).\n\t * Cursor advances naturally via `insertCharacter` on typing/paste; cursor-\n\t * movement keys (Left/Right/Home/End/word-jumps) are now functional, with\n\t * the always-end visual cursor marker drawn independently by\n\t * `WrappingSelect.renderInlineInputRow`. `viewAdapter.apply` is called\n\t * directly without a reducer round-trip — preserves the D3 fast-path\n\t * latency profile from Phase 11.\n\t */\n\tprivate handleIgnoreInline(data: string): void {\n\t\tif (!this.state.inputMode) return;\n\t\tthis.inlineInput.handleInput(data);\n\t\tthis.viewAdapter.apply(this.state);\n\t}\n\n\tprivate runtime(): QuestionnaireRuntime {\n\t\treturn {\n\t\t\tkeybindings: getKeybindings(),\n\t\t\tinputBuffer: this.inlineInput.getValue(),\n\t\t\tquestions: this.questions,\n\t\t\tisMulti: this.isMulti,\n\t\t\tcurrentItem: this.currentItem(),\n\t\t\titems: this.itemsByTab[this.state.currentTab] ?? [],\n\t\t};\n\t}\n\n\tprivate applyContext(): ApplyContext {\n\t\treturn {\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t};\n\t}\n\n\tprivate currentItem(): WrappingSelectItem | undefined {\n\t\tif (this.state.chatFocused) return { kind: \"chat\", label: ROW_INTENT_META.chat.label };\n\t\tconst arr = this.itemsByTab[this.state.currentTab] ?? [];\n\t\tif (this.state.optionIndex < arr.length) return arr[this.state.optionIndex];\n\t\treturn { kind: \"chat\", label: ROW_INTENT_META.chat.label };\n\t}\n}\n"]}
1
+ {"version":3,"file":"questionnaire-session.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/questionnaire-session.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Theme } from \"../../../../modes/interactive/theme/theme.ts\";\nimport { getKeybindings, type Input } from \"@earendil-works/pi-tui\";\nimport type { QuestionData, QuestionnaireResult, QuestionParams } from \"../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.ts\";\nimport type { QuestionnairePropsAdapter } from \"../view/props-adapter.ts\";\nimport { buildQuestionnaire } from \"./build-questionnaire.ts\";\nimport { ROW_INTENT_META } from \"./row-intent.ts\";\nimport { type QuestionnaireAction, routeKey } from \"./key-router.ts\";\nimport { computeFocusedOptionHasPreview } from \"./selectors/derivations.ts\";\nimport type { QuestionnaireRuntime, QuestionnaireState } from \"./state.ts\";\nimport { type ApplyContext, type Effect, reduce } from \"./state-reducer.ts\";\n\n// Module-level constant; reused for cursor-end mutations after setValue rehydration.\n// Ctrl-E → tui.editor.cursorLineEnd (public path; pi-tui keybindings.js:25-28).\nconst CURSOR_END = \"\\x05\";\n\nexport interface QuestionnaireSessionConfig {\n\ttui: { terminal: { columns: number }; requestRender(): void };\n\ttheme: Theme;\n\tparams: QuestionParams;\n\titemsByTab: WrappingSelectItem[][];\n\tdone: (result: QuestionnaireResult) => void;\n}\n\nexport interface QuestionnaireSessionComponent {\n\trender(width: number): string[];\n\tinvalidate(): void;\n\thandleInput(data: string): void;\n}\n\nfunction initialState(): QuestionnaireState {\n\treturn {\n\t\tcurrentTab: 0,\n\t\toptionIndex: 0,\n\t\tinputMode: false,\n\t\tnotesVisible: false,\n\t\tchatFocused: false,\n\t\tanswers: new Map(),\n\t\tmultiSelectChecked: new Set(),\n\t\tnotesByTab: new Map(),\n\t\tfocusedOptionHasPreview: false,\n\t\tsubmitChoiceIndex: 0,\n\t\tnotesDraft: \"\",\n\t};\n}\n\n/**\n * Slim runtime: owns the canonical state cell, the input-buffer cell, the\n * two-pass `notesVisible` dispatch loop, and the effect runner. State\n * transitions go through the pure `reduce` reducer; UI fan-out goes through\n * the `QuestionnairePropsAdapter` produced by `buildQuestionnaire`.\n */\nexport class QuestionnaireSession {\n\tprivate state: QuestionnaireState = initialState();\n\n\tprivate readonly questions: readonly QuestionData[];\n\tprivate readonly isMulti: boolean;\n\tprivate readonly itemsByTab: WrappingSelectItem[][];\n\n\tprivate readonly notesInput: Input;\n\tprivate readonly inlineInput: Input;\n\tprivate readonly viewAdapter: QuestionnairePropsAdapter;\n\n\tprivate readonly tui: QuestionnaireSessionConfig[\"tui\"];\n\tprivate readonly done: QuestionnaireSessionConfig[\"done\"];\n\n\treadonly component: QuestionnaireSessionComponent;\n\n\tconstructor(config: QuestionnaireSessionConfig) {\n\t\tthis.tui = config.tui;\n\t\tthis.done = config.done;\n\t\tthis.questions = config.params.questions;\n\t\tthis.isMulti = this.questions.length > 1;\n\t\tthis.itemsByTab = config.itemsByTab;\n\t\t// Seed from the focused option at start; the reducer keeps it in sync via withFocusedOptionHasPreview.\n\t\tthis.state = { ...this.state, focusedOptionHasPreview: computeFocusedOptionHasPreview(this.questions, 0, 0) };\n\n\t\tconst built = buildQuestionnaire({\n\t\t\ttui: this.tui,\n\t\t\ttheme: config.theme,\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t\tisMulti: this.isMulti,\n\t\t\tinitialState: this.state,\n\t\t\tgetCurrentTab: () => this.state.currentTab,\n\t\t});\n\n\t\tthis.notesInput = built.notesInput;\n\t\tthis.inlineInput = built.inlineInput;\n\t\tthis.viewAdapter = built.adapter;\n\n\t\tthis.component = {\n\t\t\trender: built.render,\n\t\t\tinvalidate: built.invalidate,\n\t\t\thandleInput: (data) => this.dispatch(data),\n\t\t};\n\n\t\tthis.viewAdapter.apply(this.state);\n\t}\n\n\tdispatch(data: string): void {\n\t\tconst action = routeKey(data, this.state, this.runtime());\n\t\tif (action.kind === \"ignore\") {\n\t\t\tthis.handleIgnoreInline(data);\n\t\t\treturn;\n\t\t}\n\t\tthis.commit(action);\n\t}\n\n\tprivate commit(action: QuestionnaireAction): void {\n\t\tconst result = reduce(this.state, action, this.applyContext());\n\t\tthis.state = result.state;\n\t\tfor (const effect of result.effects) this.runEffect(effect);\n\t\tthis.state = this.mirrorNotesDraft(this.state);\n\t\tthis.viewAdapter.apply(this.state);\n\t}\n\n\tprivate mirrorNotesDraft(s: QuestionnaireState): QuestionnaireState {\n\t\tconst draft = this.notesInput.getValue();\n\t\treturn s.notesDraft === draft ? s : { ...s, notesDraft: draft };\n\t}\n\n\tprivate runEffect(effect: Effect): void {\n\t\tswitch (effect.kind) {\n\t\t\tcase \"set_input_buffer\":\n\t\t\t\tthis.inlineInput.setValue(effect.value);\n\t\t\t\tthis.inlineInput.handleInput(CURSOR_END);\n\t\t\t\treturn;\n\t\t\tcase \"clear_input_buffer\":\n\t\t\t\tthis.inlineInput.setValue(\"\");\n\t\t\t\treturn;\n\t\t\tcase \"set_notes_value\":\n\t\t\t\tthis.notesInput.setValue(effect.value);\n\t\t\t\treturn;\n\t\t\tcase \"set_notes_focused\":\n\t\t\t\tthis.notesInput.focused = effect.focused;\n\t\t\t\treturn;\n\t\t\tcase \"forward_notes_keystroke\":\n\t\t\t\tthis.notesInput.handleInput(effect.data);\n\t\t\t\treturn;\n\t\t\tcase \"done\":\n\t\t\t\tthis.done(effect.result);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\t/**\n\t * Per-keystroke `ignore` fast path: delegates to the headless `inlineInput`\n\t * Input so bracketed-paste accumulator (`input.js:33-63`) and Kitty CSI-u\n\t * decode (`input.js:155-163`) take effect. Cursor is NOT force-reset here —\n\t * doing so would corrupt split-chunk pastes (a `\\x05` byte mid-paste lands\n\t * verbatim in `pasteBuffer` and survives `handlePaste`'s narrow strip).\n\t * Cursor advances naturally via `insertCharacter` on typing/paste; cursor-\n\t * movement keys (Left/Right/Home/End/word-jumps) are now functional, with\n\t * the always-end visual cursor marker drawn independently by\n\t * `WrappingSelect.renderInlineInputRow`. `viewAdapter.apply` is called\n\t * directly without a reducer round-trip — preserves the D3 fast-path\n\t * latency profile from Phase 11.\n\t */\n\tprivate handleIgnoreInline(data: string): void {\n\t\tif (!this.state.inputMode) return;\n\t\tthis.inlineInput.handleInput(data);\n\t\tthis.viewAdapter.apply(this.state);\n\t}\n\n\tprivate runtime(): QuestionnaireRuntime {\n\t\treturn {\n\t\t\tkeybindings: getKeybindings(),\n\t\t\tinputBuffer: this.inlineInput.getValue(),\n\t\t\tquestions: this.questions,\n\t\t\tisMulti: this.isMulti,\n\t\t\tcurrentItem: this.currentItem(),\n\t\t\titems: this.itemsByTab[this.state.currentTab] ?? [],\n\t\t};\n\t}\n\n\tprivate applyContext(): ApplyContext {\n\t\treturn {\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t};\n\t}\n\n\tprivate currentItem(): WrappingSelectItem | undefined {\n\t\tif (this.state.chatFocused) return { kind: \"chat\", label: ROW_INTENT_META.chat.label };\n\t\tconst arr = this.itemsByTab[this.state.currentTab] ?? [];\n\t\tif (this.state.optionIndex < arr.length) return arr[this.state.optionIndex];\n\t\treturn { kind: \"chat\", label: ROW_INTENT_META.chat.label };\n\t}\n}\n"]}
@@ -1,5 +1,5 @@
1
- import type { QuestionData } from "../tool/types.js";
2
- import type { WrappingSelectItem } from "../view/components/wrapping-select.js";
1
+ import type { QuestionData } from "../tool/types.ts";
2
+ import type { WrappingSelectItem } from "../view/components/wrapping-select.ts";
3
3
  /**
4
4
  * Row kind discriminator. Single source of truth — derived from the runtime
5
5
  * `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new
@@ -1 +1 @@
1
- {"version":3,"file":"row-intent.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/row-intent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtD,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAA8B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iCAAiC,EAAE,OAAO,CAAC;IAC3C,uBAAuB,EAAE,OAAO,CAAC;CACjC;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,CA6C1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE;IAAE,QAAQ,EAAE,CAAC,IAAI,YAAY,GAAG,MAAM;CAIlE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAGjD,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,GAAG,YAAY,EAAE,CAYhG","sourcesContent":["import type { QuestionData } from \"../tool/types.js\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.js\";\n\n/**\n * Row kind discriminator. Single source of truth — derived from the runtime\n * `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new\n * variant there forces a `ROW_INTENT_META` entry here (compile-time\n * exhaustiveness via `Record<RowKind, …>`).\n */\nexport type RowKind = WrappingSelectItem[\"kind\"];\n\n/**\n * Sentinel kinds — the subset of `RowKind` representing protocol-driven rows\n * (vs author-defined `option` rows). The auto-append walker, the reserved-label\n * derivation, and `LABELS_BY_KIND` consumers iterate this list.\n */\nexport type SentinelKind = Exclude<RowKind, \"option\">;\nexport const SENTINEL_KINDS: readonly SentinelKind[] = [\"other\", \"chat\", \"next\"];\n\n/**\n * Per-kind static metadata. Pure data — no closures, no per-kind handler\n * functions. Behavior-bearing branches (answer construction in\n * `key-router.ts:69-99`, the Next-row render block in `multi-select-view.ts`,\n * and the inline-Input render branch in `wrapping-select.ts`) keep their\n * exhaustive switches and READ flags from this table.\n *\n * Adding a new sentinel:\n * 1. Add the variant to `WrappingSelectItem` (`wrapping-select.ts:18-22`).\n * 2. Add an entry here. Compile fails until both edits are present.\n * 3. (If user-facing) author wherever the row is synthesized — typically\n * `buildItemsForQuestion` for main-list residents, or the `chatList`\n * construction site for non-main-list rows.\n *\n * Field semantics:\n * - `label` — user-facing string. For `option` it's an empty placeholder\n * (per-instance labels come from `QuestionData.options[i].label`); every\n * sentinel uses its META entry as the single source of truth.\n * - `reserved` — author-facing labels matching this string trigger\n * `reserved_label` at validation time. `RESERVED_LABEL_SET` is derived.\n * - `livesInMainList` — true iff the row appears in `itemsByTab[i]`. Chat\n * lives in its own `chatList` (`questionnaire-session.ts:95`) so its row\n * never enters the main list.\n * - `numbered` — true iff the row contributes to the main-list numbering\n * offset that `chatNumberingFor` reads. Multi-select Next is the only\n * numberable=false row that lives in the list; chat is numbered=true but\n * `livesInMainList=false` so the flag is moot for chat.\n * - `activatesInputMode` — true iff focusing the row should toggle\n * `state.inputMode = true`. Read by `state-reducer.ts` `nav` /\n * `focus_options` cases.\n * - `blocksMultiToggle` — in multiSelect mode, Space (and Enter-as-toggle)\n * on this row is suppressed. The Next sentinel is the only true.\n * - `autoSubmitsInMulti` — in multiSelect mode, Enter on this row commits\n * the question (emits `multi_confirm`). The Next sentinel is the only true.\n * - `autoAppendOnSingleSelectNoPreview` — `buildItemsForQuestion` appends\n * this row when the question is single-select AND no option carries a\n * `preview`. The \"other\" sentinel is the only true.\n * - `autoAppendOnMultiSelect` — `buildItemsForQuestion` appends this row\n * when the question is multi-select. The Next sentinel is the only true.\n */\nexport interface RowIntentMeta {\n\tlabel: string;\n\treserved: boolean;\n\tlivesInMainList: boolean;\n\tnumbered: boolean;\n\tactivatesInputMode: boolean;\n\tblocksMultiToggle: boolean;\n\tautoSubmitsInMulti: boolean;\n\tautoAppendOnSingleSelectNoPreview: boolean;\n\tautoAppendOnMultiSelect: boolean;\n}\n\nexport const ROW_INTENT_META: Record<RowKind, RowIntentMeta> = {\n\toption: {\n\t\tlabel: \"\",\n\t\treserved: false,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tother: {\n\t\tlabel: \"Type something.\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: true,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: true,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tchat: {\n\t\tlabel: \"Chat about this\",\n\t\treserved: true,\n\t\tlivesInMainList: false,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tnext: {\n\t\tlabel: \"Next\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: false,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: true,\n\t\tautoSubmitsInMulti: true,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: true,\n\t},\n};\n\n/**\n * Kind-keyed label view. `option` is excluded — its label is per-instance,\n * not per-kind. `types.ts#SENTINEL_LABELS` re-sources from here.\n */\nexport const LABELS_BY_KIND: { readonly [K in SentinelKind]: string } = {\n\tother: ROW_INTENT_META.other.label,\n\tchat: ROW_INTENT_META.chat.label,\n\tnext: ROW_INTENT_META.next.label,\n};\n\n/**\n * Reserved-label set for runtime validation. Includes \"Other\" (a model-conditioned\n * label that has no runtime kind) plus every sentinel with `reserved: true`.\n */\nexport const RESERVED_LABEL_SET: ReadonlySet<string> = new Set<string>([\n\t\"Other\",\n\t...SENTINEL_KINDS.filter((k) => ROW_INTENT_META[k].reserved).map((k) => ROW_INTENT_META[k].label),\n]);\n\n/**\n * Walk the META table to synthesize sentinel rows for one question. The two\n * append predicates are mutually exclusive in practice (`multiSelect` vs\n * `!multiSelect && !hasAnyPreview`) but the walker doesn't enforce that —\n * adding a third bucket only requires a new META flag.\n *\n * Returns sentinel descriptors in declaration order of `SENTINEL_KINDS`. The\n * caller wraps each with the `WrappingSelectItem` shape (kind + label).\n */\nexport function sentinelsToAppend(question: QuestionData, hasAnyPreview: boolean): SentinelKind[] {\n\tconst out: SentinelKind[] = [];\n\tfor (const k of SENTINEL_KINDS) {\n\t\tconst meta = ROW_INTENT_META[k];\n\t\tif (!meta.livesInMainList) continue;\n\t\tif (question.multiSelect === true) {\n\t\t\tif (meta.autoAppendOnMultiSelect) out.push(k);\n\t\t} else {\n\t\t\tif (meta.autoAppendOnSingleSelectNoPreview && !hasAnyPreview) out.push(k);\n\t\t}\n\t}\n\treturn out;\n}\n"]}
1
+ {"version":3,"file":"row-intent.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/row-intent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AACtD,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAA8B,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iCAAiC,EAAE,OAAO,CAAC;IAC3C,uBAAuB,EAAE,OAAO,CAAC;CACjC;AAED,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,CA6C1D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE;IAAE,QAAQ,EAAE,CAAC,IAAI,YAAY,GAAG,MAAM;CAIlE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAGjD,CAAC;AAEH;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,GAAG,YAAY,EAAE,CAYhG","sourcesContent":["import type { QuestionData } from \"../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.ts\";\n\n/**\n * Row kind discriminator. Single source of truth — derived from the runtime\n * `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new\n * variant there forces a `ROW_INTENT_META` entry here (compile-time\n * exhaustiveness via `Record<RowKind, …>`).\n */\nexport type RowKind = WrappingSelectItem[\"kind\"];\n\n/**\n * Sentinel kinds — the subset of `RowKind` representing protocol-driven rows\n * (vs author-defined `option` rows). The auto-append walker, the reserved-label\n * derivation, and `LABELS_BY_KIND` consumers iterate this list.\n */\nexport type SentinelKind = Exclude<RowKind, \"option\">;\nexport const SENTINEL_KINDS: readonly SentinelKind[] = [\"other\", \"chat\", \"next\"];\n\n/**\n * Per-kind static metadata. Pure data — no closures, no per-kind handler\n * functions. Behavior-bearing branches (answer construction in\n * `key-router.ts:69-99`, the Next-row render block in `multi-select-view.ts`,\n * and the inline-Input render branch in `wrapping-select.ts`) keep their\n * exhaustive switches and READ flags from this table.\n *\n * Adding a new sentinel:\n * 1. Add the variant to `WrappingSelectItem` (`wrapping-select.ts:18-22`).\n * 2. Add an entry here. Compile fails until both edits are present.\n * 3. (If user-facing) author wherever the row is synthesized — typically\n * `buildItemsForQuestion` for main-list residents, or the `chatList`\n * construction site for non-main-list rows.\n *\n * Field semantics:\n * - `label` — user-facing string. For `option` it's an empty placeholder\n * (per-instance labels come from `QuestionData.options[i].label`); every\n * sentinel uses its META entry as the single source of truth.\n * - `reserved` — author-facing labels matching this string trigger\n * `reserved_label` at validation time. `RESERVED_LABEL_SET` is derived.\n * - `livesInMainList` — true iff the row appears in `itemsByTab[i]`. Chat\n * lives in its own `chatList` (`questionnaire-session.ts:95`) so its row\n * never enters the main list.\n * - `numbered` — true iff the row contributes to the main-list numbering\n * offset that `chatNumberingFor` reads. Multi-select Next is the only\n * numberable=false row that lives in the list; chat is numbered=true but\n * `livesInMainList=false` so the flag is moot for chat.\n * - `activatesInputMode` — true iff focusing the row should toggle\n * `state.inputMode = true`. Read by `state-reducer.ts` `nav` /\n * `focus_options` cases.\n * - `blocksMultiToggle` — in multiSelect mode, Space (and Enter-as-toggle)\n * on this row is suppressed. The Next sentinel is the only true.\n * - `autoSubmitsInMulti` — in multiSelect mode, Enter on this row commits\n * the question (emits `multi_confirm`). The Next sentinel is the only true.\n * - `autoAppendOnSingleSelectNoPreview` — `buildItemsForQuestion` appends\n * this row when the question is single-select AND no option carries a\n * `preview`. The \"other\" sentinel is the only true.\n * - `autoAppendOnMultiSelect` — `buildItemsForQuestion` appends this row\n * when the question is multi-select. The Next sentinel is the only true.\n */\nexport interface RowIntentMeta {\n\tlabel: string;\n\treserved: boolean;\n\tlivesInMainList: boolean;\n\tnumbered: boolean;\n\tactivatesInputMode: boolean;\n\tblocksMultiToggle: boolean;\n\tautoSubmitsInMulti: boolean;\n\tautoAppendOnSingleSelectNoPreview: boolean;\n\tautoAppendOnMultiSelect: boolean;\n}\n\nexport const ROW_INTENT_META: Record<RowKind, RowIntentMeta> = {\n\toption: {\n\t\tlabel: \"\",\n\t\treserved: false,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tother: {\n\t\tlabel: \"Type something.\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: true,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: true,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tchat: {\n\t\tlabel: \"Chat about this\",\n\t\treserved: true,\n\t\tlivesInMainList: false,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tnext: {\n\t\tlabel: \"Next\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: false,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: true,\n\t\tautoSubmitsInMulti: true,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: true,\n\t},\n};\n\n/**\n * Kind-keyed label view. `option` is excluded — its label is per-instance,\n * not per-kind. `types.ts#SENTINEL_LABELS` re-sources from here.\n */\nexport const LABELS_BY_KIND: { readonly [K in SentinelKind]: string } = {\n\tother: ROW_INTENT_META.other.label,\n\tchat: ROW_INTENT_META.chat.label,\n\tnext: ROW_INTENT_META.next.label,\n};\n\n/**\n * Reserved-label set for runtime validation. Includes \"Other\" (a model-conditioned\n * label that has no runtime kind) plus every sentinel with `reserved: true`.\n */\nexport const RESERVED_LABEL_SET: ReadonlySet<string> = new Set<string>([\n\t\"Other\",\n\t...SENTINEL_KINDS.filter((k) => ROW_INTENT_META[k].reserved).map((k) => ROW_INTENT_META[k].label),\n]);\n\n/**\n * Walk the META table to synthesize sentinel rows for one question. The two\n * append predicates are mutually exclusive in practice (`multiSelect` vs\n * `!multiSelect && !hasAnyPreview`) but the walker doesn't enforce that —\n * adding a third bucket only requires a new META flag.\n *\n * Returns sentinel descriptors in declaration order of `SENTINEL_KINDS`. The\n * caller wraps each with the `WrappingSelectItem` shape (kind + label).\n */\nexport function sentinelsToAppend(question: QuestionData, hasAnyPreview: boolean): SentinelKind[] {\n\tconst out: SentinelKind[] = [];\n\tfor (const k of SENTINEL_KINDS) {\n\t\tconst meta = ROW_INTENT_META[k];\n\t\tif (!meta.livesInMainList) continue;\n\t\tif (question.multiSelect === true) {\n\t\t\tif (meta.autoAppendOnMultiSelect) out.push(k);\n\t\t} else {\n\t\t\tif (meta.autoAppendOnSingleSelectNoPreview && !hasAnyPreview) out.push(k);\n\t\t}\n\t}\n\treturn out;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"row-intent.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/row-intent.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAsDjF,MAAM,CAAC,MAAM,eAAe,GAAmC;IAC9D,MAAM,EAAE;QACP,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,KAAK;QACf,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,iCAAiC,EAAE,KAAK;QACxC,uBAAuB,EAAE,KAAK;KAC9B;IACD,KAAK,EAAE;QACN,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,IAAI;QACxB,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,iCAAiC,EAAE,IAAI;QACvC,uBAAuB,EAAE,KAAK;KAC9B;IACD,IAAI,EAAE;QACL,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,KAAK;QACtB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,iCAAiC,EAAE,KAAK;QACxC,uBAAuB,EAAE,KAAK;KAC9B;IACD,IAAI,EAAE;QACL,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,KAAK;QACf,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,iCAAiC,EAAE,KAAK;QACxC,uBAAuB,EAAE,IAAI;KAC7B;CACD,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAA6C;IACvE,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK;IAClC,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK;IAChC,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK;CAChC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAS;IACtE,OAAO;IACP,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;CACjG,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAsB,EAAE,aAAsB;IAC/E,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,SAAS;QACpC,IAAI,QAAQ,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,uBAAuB;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,CAAC,iCAAiC,IAAI,CAAC,aAAa;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3E,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC","sourcesContent":["import type { QuestionData } from \"../tool/types.js\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.js\";\n\n/**\n * Row kind discriminator. Single source of truth — derived from the runtime\n * `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new\n * variant there forces a `ROW_INTENT_META` entry here (compile-time\n * exhaustiveness via `Record<RowKind, …>`).\n */\nexport type RowKind = WrappingSelectItem[\"kind\"];\n\n/**\n * Sentinel kinds — the subset of `RowKind` representing protocol-driven rows\n * (vs author-defined `option` rows). The auto-append walker, the reserved-label\n * derivation, and `LABELS_BY_KIND` consumers iterate this list.\n */\nexport type SentinelKind = Exclude<RowKind, \"option\">;\nexport const SENTINEL_KINDS: readonly SentinelKind[] = [\"other\", \"chat\", \"next\"];\n\n/**\n * Per-kind static metadata. Pure data — no closures, no per-kind handler\n * functions. Behavior-bearing branches (answer construction in\n * `key-router.ts:69-99`, the Next-row render block in `multi-select-view.ts`,\n * and the inline-Input render branch in `wrapping-select.ts`) keep their\n * exhaustive switches and READ flags from this table.\n *\n * Adding a new sentinel:\n * 1. Add the variant to `WrappingSelectItem` (`wrapping-select.ts:18-22`).\n * 2. Add an entry here. Compile fails until both edits are present.\n * 3. (If user-facing) author wherever the row is synthesized — typically\n * `buildItemsForQuestion` for main-list residents, or the `chatList`\n * construction site for non-main-list rows.\n *\n * Field semantics:\n * - `label` — user-facing string. For `option` it's an empty placeholder\n * (per-instance labels come from `QuestionData.options[i].label`); every\n * sentinel uses its META entry as the single source of truth.\n * - `reserved` — author-facing labels matching this string trigger\n * `reserved_label` at validation time. `RESERVED_LABEL_SET` is derived.\n * - `livesInMainList` — true iff the row appears in `itemsByTab[i]`. Chat\n * lives in its own `chatList` (`questionnaire-session.ts:95`) so its row\n * never enters the main list.\n * - `numbered` — true iff the row contributes to the main-list numbering\n * offset that `chatNumberingFor` reads. Multi-select Next is the only\n * numberable=false row that lives in the list; chat is numbered=true but\n * `livesInMainList=false` so the flag is moot for chat.\n * - `activatesInputMode` — true iff focusing the row should toggle\n * `state.inputMode = true`. Read by `state-reducer.ts` `nav` /\n * `focus_options` cases.\n * - `blocksMultiToggle` — in multiSelect mode, Space (and Enter-as-toggle)\n * on this row is suppressed. The Next sentinel is the only true.\n * - `autoSubmitsInMulti` — in multiSelect mode, Enter on this row commits\n * the question (emits `multi_confirm`). The Next sentinel is the only true.\n * - `autoAppendOnSingleSelectNoPreview` — `buildItemsForQuestion` appends\n * this row when the question is single-select AND no option carries a\n * `preview`. The \"other\" sentinel is the only true.\n * - `autoAppendOnMultiSelect` — `buildItemsForQuestion` appends this row\n * when the question is multi-select. The Next sentinel is the only true.\n */\nexport interface RowIntentMeta {\n\tlabel: string;\n\treserved: boolean;\n\tlivesInMainList: boolean;\n\tnumbered: boolean;\n\tactivatesInputMode: boolean;\n\tblocksMultiToggle: boolean;\n\tautoSubmitsInMulti: boolean;\n\tautoAppendOnSingleSelectNoPreview: boolean;\n\tautoAppendOnMultiSelect: boolean;\n}\n\nexport const ROW_INTENT_META: Record<RowKind, RowIntentMeta> = {\n\toption: {\n\t\tlabel: \"\",\n\t\treserved: false,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tother: {\n\t\tlabel: \"Type something.\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: true,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: true,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tchat: {\n\t\tlabel: \"Chat about this\",\n\t\treserved: true,\n\t\tlivesInMainList: false,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tnext: {\n\t\tlabel: \"Next\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: false,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: true,\n\t\tautoSubmitsInMulti: true,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: true,\n\t},\n};\n\n/**\n * Kind-keyed label view. `option` is excluded — its label is per-instance,\n * not per-kind. `types.ts#SENTINEL_LABELS` re-sources from here.\n */\nexport const LABELS_BY_KIND: { readonly [K in SentinelKind]: string } = {\n\tother: ROW_INTENT_META.other.label,\n\tchat: ROW_INTENT_META.chat.label,\n\tnext: ROW_INTENT_META.next.label,\n};\n\n/**\n * Reserved-label set for runtime validation. Includes \"Other\" (a model-conditioned\n * label that has no runtime kind) plus every sentinel with `reserved: true`.\n */\nexport const RESERVED_LABEL_SET: ReadonlySet<string> = new Set<string>([\n\t\"Other\",\n\t...SENTINEL_KINDS.filter((k) => ROW_INTENT_META[k].reserved).map((k) => ROW_INTENT_META[k].label),\n]);\n\n/**\n * Walk the META table to synthesize sentinel rows for one question. The two\n * append predicates are mutually exclusive in practice (`multiSelect` vs\n * `!multiSelect && !hasAnyPreview`) but the walker doesn't enforce that —\n * adding a third bucket only requires a new META flag.\n *\n * Returns sentinel descriptors in declaration order of `SENTINEL_KINDS`. The\n * caller wraps each with the `WrappingSelectItem` shape (kind + label).\n */\nexport function sentinelsToAppend(question: QuestionData, hasAnyPreview: boolean): SentinelKind[] {\n\tconst out: SentinelKind[] = [];\n\tfor (const k of SENTINEL_KINDS) {\n\t\tconst meta = ROW_INTENT_META[k];\n\t\tif (!meta.livesInMainList) continue;\n\t\tif (question.multiSelect === true) {\n\t\t\tif (meta.autoAppendOnMultiSelect) out.push(k);\n\t\t} else {\n\t\t\tif (meta.autoAppendOnSingleSelectNoPreview && !hasAnyPreview) out.push(k);\n\t\t}\n\t}\n\treturn out;\n}\n"]}
1
+ {"version":3,"file":"row-intent.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/row-intent.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAsDjF,MAAM,CAAC,MAAM,eAAe,GAAmC;IAC9D,MAAM,EAAE;QACP,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,KAAK;QACf,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,iCAAiC,EAAE,KAAK;QACxC,uBAAuB,EAAE,KAAK;KAC9B;IACD,KAAK,EAAE;QACN,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,IAAI;QACxB,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,iCAAiC,EAAE,IAAI;QACvC,uBAAuB,EAAE,KAAK;KAC9B;IACD,IAAI,EAAE;QACL,KAAK,EAAE,iBAAiB;QACxB,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,KAAK;QACtB,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,KAAK;QACxB,kBAAkB,EAAE,KAAK;QACzB,iCAAiC,EAAE,KAAK;QACxC,uBAAuB,EAAE,KAAK;KAC9B;IACD,IAAI,EAAE;QACL,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,KAAK;QACf,kBAAkB,EAAE,KAAK;QACzB,iBAAiB,EAAE,IAAI;QACvB,kBAAkB,EAAE,IAAI;QACxB,iCAAiC,EAAE,KAAK;QACxC,uBAAuB,EAAE,IAAI;KAC7B;CACD,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAA6C;IACvE,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK;IAClC,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK;IAChC,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK;CAChC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAS;IACtE,OAAO;IACP,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;CACjG,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAsB,EAAE,aAAsB;IAC/E,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,SAAS;QACpC,IAAI,QAAQ,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,uBAAuB;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,CAAC,iCAAiC,IAAI,CAAC,aAAa;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3E,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC","sourcesContent":["import type { QuestionData } from \"../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.ts\";\n\n/**\n * Row kind discriminator. Single source of truth — derived from the runtime\n * `WrappingSelectItem` union (`wrapping-select.ts:18-22`) so adding a new\n * variant there forces a `ROW_INTENT_META` entry here (compile-time\n * exhaustiveness via `Record<RowKind, …>`).\n */\nexport type RowKind = WrappingSelectItem[\"kind\"];\n\n/**\n * Sentinel kinds — the subset of `RowKind` representing protocol-driven rows\n * (vs author-defined `option` rows). The auto-append walker, the reserved-label\n * derivation, and `LABELS_BY_KIND` consumers iterate this list.\n */\nexport type SentinelKind = Exclude<RowKind, \"option\">;\nexport const SENTINEL_KINDS: readonly SentinelKind[] = [\"other\", \"chat\", \"next\"];\n\n/**\n * Per-kind static metadata. Pure data — no closures, no per-kind handler\n * functions. Behavior-bearing branches (answer construction in\n * `key-router.ts:69-99`, the Next-row render block in `multi-select-view.ts`,\n * and the inline-Input render branch in `wrapping-select.ts`) keep their\n * exhaustive switches and READ flags from this table.\n *\n * Adding a new sentinel:\n * 1. Add the variant to `WrappingSelectItem` (`wrapping-select.ts:18-22`).\n * 2. Add an entry here. Compile fails until both edits are present.\n * 3. (If user-facing) author wherever the row is synthesized — typically\n * `buildItemsForQuestion` for main-list residents, or the `chatList`\n * construction site for non-main-list rows.\n *\n * Field semantics:\n * - `label` — user-facing string. For `option` it's an empty placeholder\n * (per-instance labels come from `QuestionData.options[i].label`); every\n * sentinel uses its META entry as the single source of truth.\n * - `reserved` — author-facing labels matching this string trigger\n * `reserved_label` at validation time. `RESERVED_LABEL_SET` is derived.\n * - `livesInMainList` — true iff the row appears in `itemsByTab[i]`. Chat\n * lives in its own `chatList` (`questionnaire-session.ts:95`) so its row\n * never enters the main list.\n * - `numbered` — true iff the row contributes to the main-list numbering\n * offset that `chatNumberingFor` reads. Multi-select Next is the only\n * numberable=false row that lives in the list; chat is numbered=true but\n * `livesInMainList=false` so the flag is moot for chat.\n * - `activatesInputMode` — true iff focusing the row should toggle\n * `state.inputMode = true`. Read by `state-reducer.ts` `nav` /\n * `focus_options` cases.\n * - `blocksMultiToggle` — in multiSelect mode, Space (and Enter-as-toggle)\n * on this row is suppressed. The Next sentinel is the only true.\n * - `autoSubmitsInMulti` — in multiSelect mode, Enter on this row commits\n * the question (emits `multi_confirm`). The Next sentinel is the only true.\n * - `autoAppendOnSingleSelectNoPreview` — `buildItemsForQuestion` appends\n * this row when the question is single-select AND no option carries a\n * `preview`. The \"other\" sentinel is the only true.\n * - `autoAppendOnMultiSelect` — `buildItemsForQuestion` appends this row\n * when the question is multi-select. The Next sentinel is the only true.\n */\nexport interface RowIntentMeta {\n\tlabel: string;\n\treserved: boolean;\n\tlivesInMainList: boolean;\n\tnumbered: boolean;\n\tactivatesInputMode: boolean;\n\tblocksMultiToggle: boolean;\n\tautoSubmitsInMulti: boolean;\n\tautoAppendOnSingleSelectNoPreview: boolean;\n\tautoAppendOnMultiSelect: boolean;\n}\n\nexport const ROW_INTENT_META: Record<RowKind, RowIntentMeta> = {\n\toption: {\n\t\tlabel: \"\",\n\t\treserved: false,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tother: {\n\t\tlabel: \"Type something.\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: true,\n\t\tactivatesInputMode: true,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: true,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tchat: {\n\t\tlabel: \"Chat about this\",\n\t\treserved: true,\n\t\tlivesInMainList: false,\n\t\tnumbered: true,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: false,\n\t\tautoSubmitsInMulti: false,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: false,\n\t},\n\tnext: {\n\t\tlabel: \"Next\",\n\t\treserved: true,\n\t\tlivesInMainList: true,\n\t\tnumbered: false,\n\t\tactivatesInputMode: false,\n\t\tblocksMultiToggle: true,\n\t\tautoSubmitsInMulti: true,\n\t\tautoAppendOnSingleSelectNoPreview: false,\n\t\tautoAppendOnMultiSelect: true,\n\t},\n};\n\n/**\n * Kind-keyed label view. `option` is excluded — its label is per-instance,\n * not per-kind. `types.ts#SENTINEL_LABELS` re-sources from here.\n */\nexport const LABELS_BY_KIND: { readonly [K in SentinelKind]: string } = {\n\tother: ROW_INTENT_META.other.label,\n\tchat: ROW_INTENT_META.chat.label,\n\tnext: ROW_INTENT_META.next.label,\n};\n\n/**\n * Reserved-label set for runtime validation. Includes \"Other\" (a model-conditioned\n * label that has no runtime kind) plus every sentinel with `reserved: true`.\n */\nexport const RESERVED_LABEL_SET: ReadonlySet<string> = new Set<string>([\n\t\"Other\",\n\t...SENTINEL_KINDS.filter((k) => ROW_INTENT_META[k].reserved).map((k) => ROW_INTENT_META[k].label),\n]);\n\n/**\n * Walk the META table to synthesize sentinel rows for one question. The two\n * append predicates are mutually exclusive in practice (`multiSelect` vs\n * `!multiSelect && !hasAnyPreview`) but the walker doesn't enforce that —\n * adding a third bucket only requires a new META flag.\n *\n * Returns sentinel descriptors in declaration order of `SENTINEL_KINDS`. The\n * caller wraps each with the `WrappingSelectItem` shape (kind + label).\n */\nexport function sentinelsToAppend(question: QuestionData, hasAnyPreview: boolean): SentinelKind[] {\n\tconst out: SentinelKind[] = [];\n\tfor (const k of SENTINEL_KINDS) {\n\t\tconst meta = ROW_INTENT_META[k];\n\t\tif (!meta.livesInMainList) continue;\n\t\tif (question.multiSelect === true) {\n\t\t\tif (meta.autoAppendOnMultiSelect) out.push(k);\n\t\t} else {\n\t\t\tif (meta.autoAppendOnSingleSelectNoPreview && !hasAnyPreview) out.push(k);\n\t\t}\n\t}\n\treturn out;\n}\n"]}
@@ -1,9 +1,9 @@
1
- import type { QuestionData } from "../../tool/types.js";
2
- import type { PreviewPaneProps } from "../../view/components/preview/preview-pane.js";
3
- import type { WrappingSelectItem } from "../../view/components/wrapping-select.js";
4
- import type { ActiveView, StatefulView } from "../../view/stateful-view.js";
5
- import type { TabComponents } from "../../view/tab-components.js";
6
- import type { QuestionnaireState } from "../state.js";
1
+ import type { QuestionData } from "../../tool/types.ts";
2
+ import type { PreviewPaneProps } from "../../view/components/preview/preview-pane.ts";
3
+ import type { WrappingSelectItem } from "../../view/components/wrapping-select.ts";
4
+ import type { ActiveView, StatefulView } from "../../view/stateful-view.ts";
5
+ import type { TabComponents } from "../../view/tab-components.ts";
6
+ import type { QuestionnaireState } from "../state.ts";
7
7
  export interface BindingContext {
8
8
  readonly questions: readonly QuestionData[];
9
9
  readonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;IAClE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC3D,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,cAAc,KAAK,CAAC,CAAC;AACtF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,oBAAoB,KAAK,CAAC,CAAC","sourcesContent":["import type { QuestionData } from \"../../tool/types.js\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.js\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.js\";\nimport type { ActiveView, StatefulView } from \"../../view/stateful-view.js\";\nimport type { TabComponents } from \"../../view/tab-components.js\";\nimport type { QuestionnaireState } from \"../state.js\";\n\nexport interface BindingContext {\n\treadonly questions: readonly QuestionData[];\n\treadonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\treadonly totalQuestions: number;\n\treadonly activeView: ActiveView;\n\treadonly inputBuffer: string;\n\treadonly activePreviewPane: StatefulView<PreviewPaneProps>;\n}\n\nexport interface PerTabBindingContext extends BindingContext {\n\treadonly tab: TabComponents;\n\treadonly i: number;\n}\n\nexport type GlobalSelector<P> = (state: QuestionnaireState, ctx: BindingContext) => P;\nexport type PerTabSelector<P> = (state: QuestionnaireState, ctx: PerTabBindingContext) => P;\n"]}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;IAClE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC3D,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,cAAc,KAAK,CAAC,CAAC;AACtF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,oBAAoB,KAAK,CAAC,CAAC","sourcesContent":["import type { QuestionData } from \"../../tool/types.ts\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.ts\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.ts\";\nimport type { ActiveView, StatefulView } from \"../../view/stateful-view.ts\";\nimport type { TabComponents } from \"../../view/tab-components.ts\";\nimport type { QuestionnaireState } from \"../state.ts\";\n\nexport interface BindingContext {\n\treadonly questions: readonly QuestionData[];\n\treadonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\treadonly totalQuestions: number;\n\treadonly activeView: ActiveView;\n\treadonly inputBuffer: string;\n\treadonly activePreviewPane: StatefulView<PreviewPaneProps>;\n}\n\nexport interface PerTabBindingContext extends BindingContext {\n\treadonly tab: TabComponents;\n\treadonly i: number;\n}\n\nexport type GlobalSelector<P> = (state: QuestionnaireState, ctx: BindingContext) => P;\nexport type PerTabSelector<P> = (state: QuestionnaireState, ctx: PerTabBindingContext) => P;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/contract.ts"],"names":[],"mappings":"","sourcesContent":["import type { QuestionData } from \"../../tool/types.js\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.js\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.js\";\nimport type { ActiveView, StatefulView } from \"../../view/stateful-view.js\";\nimport type { TabComponents } from \"../../view/tab-components.js\";\nimport type { QuestionnaireState } from \"../state.js\";\n\nexport interface BindingContext {\n\treadonly questions: readonly QuestionData[];\n\treadonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\treadonly totalQuestions: number;\n\treadonly activeView: ActiveView;\n\treadonly inputBuffer: string;\n\treadonly activePreviewPane: StatefulView<PreviewPaneProps>;\n}\n\nexport interface PerTabBindingContext extends BindingContext {\n\treadonly tab: TabComponents;\n\treadonly i: number;\n}\n\nexport type GlobalSelector<P> = (state: QuestionnaireState, ctx: BindingContext) => P;\nexport type PerTabSelector<P> = (state: QuestionnaireState, ctx: PerTabBindingContext) => P;\n"]}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/contract.ts"],"names":[],"mappings":"","sourcesContent":["import type { QuestionData } from \"../../tool/types.ts\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.ts\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.ts\";\nimport type { ActiveView, StatefulView } from \"../../view/stateful-view.ts\";\nimport type { TabComponents } from \"../../view/tab-components.ts\";\nimport type { QuestionnaireState } from \"../state.ts\";\n\nexport interface BindingContext {\n\treadonly questions: readonly QuestionData[];\n\treadonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\treadonly totalQuestions: number;\n\treadonly activeView: ActiveView;\n\treadonly inputBuffer: string;\n\treadonly activePreviewPane: StatefulView<PreviewPaneProps>;\n}\n\nexport interface PerTabBindingContext extends BindingContext {\n\treadonly tab: TabComponents;\n\treadonly i: number;\n}\n\nexport type GlobalSelector<P> = (state: QuestionnaireState, ctx: BindingContext) => P;\nexport type PerTabSelector<P> = (state: QuestionnaireState, ctx: PerTabBindingContext) => P;\n"]}
@@ -1,5 +1,5 @@
1
- import type { QuestionAnswer, QuestionData } from "../../tool/types.js";
2
- import type { WrappingSelectItem } from "../../view/components/wrapping-select.js";
1
+ import type { QuestionAnswer, QuestionData } from "../../tool/types.ts";
2
+ import type { WrappingSelectItem } from "../../view/components/wrapping-select.ts";
3
3
  /**
4
4
  * Pure derivation: does the option focused by `(currentTab, optionIndex)` carry a
5
5
  * non-empty `preview` string? Mode gates (chat focus, notes mode, multiSelect) layer
@@ -1 +1 @@
1
- {"version":3,"file":"derivations.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/derivations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAGnF;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC7C,SAAS,EAAE,SAAS,YAAY,EAAE,EAClC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACjB,OAAO,CAKT;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,GAAG;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd,CAOA;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,SAAS,YAAY,EAAE,EAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAC5C,KAAK,EAAE,SAAS,kBAAkB,EAAE,GAClC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAcvD;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAG/F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,EACxD,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACpB,SAAS,kBAAkB,EAAE,CAG/B","sourcesContent":["import type { QuestionAnswer, QuestionData } from \"../../tool/types.js\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.js\";\nimport { ROW_INTENT_META } from \"../row-intent.js\";\n\n/**\n * Pure derivation: does the option focused by `(currentTab, optionIndex)` carry a\n * non-empty `preview` string? Mode gates (chat focus, notes mode, multiSelect) layer\n * on top via dispatch branches; this predicate is intentionally mode-agnostic.\n */\nexport function computeFocusedOptionHasPreview(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\toptionIndex: number,\n): boolean {\n\tconst q = questions[currentTab];\n\tif (!q) return false;\n\tconst opt = q.options[optionIndex];\n\treturn !!opt && typeof opt.preview === \"string\" && opt.preview.length > 0;\n}\n\n/**\n * Numbering for the chat row's WrappingSelect, computed from the active tab's items.\n *\n * The chat row lives in its own one-item WrappingSelect; the host calls this on every tab\n * switch / selection update to keep the chat row's `N. ` label continuous with the visible\n * numbered rows of the active tab. The shape `{ offset, total }` mirrors\n * `WrappingSelect.setNumbering(numberStartOffset, totalItemsForNumbering)` directly.\n */\nexport function chatNumberingFor(items: readonly WrappingSelectItem[]): {\n\toffset: number;\n\ttotal: number;\n} {\n\t// Count only the visible-numbered rows. The Next sentinel renders without a number\n\t// (see MultiSelectView), so it must NOT advance the chat row's number — otherwise\n\t// chat reads as \"6.\" next to options labeled 1-4. Sourced from `ROW_INTENT_META[kind].numbered`\n\t// so adding a new non-numbered kind is a single META edit.\n\tconst count = items.filter((i) => ROW_INTENT_META[i.kind].numbered).length;\n\treturn { offset: count, total: count + 1 };\n}\n\n/**\n * Which row in the active tab should be marked as \"previously confirmed\"? Drives the\n * `WrappingSelect` confirmed-row indicator (label + ` ✔`) when the user navigates back\n * to a question they already answered. Returns `undefined` when no marker should be drawn —\n * multi-select handles its own `[✔]` boxes via `multiSelectChecked`, `kind: \"chat\"` ends the\n * dialog so the row can never be re-entered, and a missing/non-matching answer (defensive)\n * silently skips the marker.\n */\nexport function selectConfirmedIndicator(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\titems: readonly WrappingSelectItem[],\n): { index: number; labelOverride?: string } | undefined {\n\tconst q = questions[currentTab];\n\tif (!q || q.multiSelect === true) return undefined;\n\tconst prior = answers.get(currentTab);\n\tif (!prior || prior.kind === \"chat\") return undefined;\n\tif (prior.kind === \"custom\") {\n\t\tconst otherIndex = items.findIndex((it) => it.kind === \"other\");\n\t\tif (otherIndex < 0) return undefined;\n\t\treturn { index: otherIndex, labelOverride: prior.answer ?? \"\" };\n\t}\n\tif (prior.kind !== \"option\" || typeof prior.answer !== \"string\") return undefined;\n\tconst index = items.findIndex((it) => it.kind === \"option\" && it.label === prior.answer);\n\tif (index < 0) return undefined;\n\treturn { index };\n}\n\n/**\n * Index of the preview pane to display for the current tab. The Submit tab (currentTab ===\n * questions.length) reuses the last question's pane purely for layout — the strategy\n * machinery picks the right body component independently. Defensive against `totalQuestions === 0`.\n */\nexport function selectActivePreviewPaneIndex(currentTab: number, totalQuestions: number): number {\n\tif (totalQuestions <= 0) return 0;\n\treturn Math.min(currentTab, totalQuestions - 1);\n}\n\n/**\n * Items array for the active tab, with the same Submit-tab clamp as `selectActivePreviewPaneIndex`.\n * Falls back to an empty array if the index lands outside the items array (defensive).\n */\nexport function selectActiveTabItems(\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>,\n\tcurrentTab: number,\n\ttotalQuestions: number,\n): readonly WrappingSelectItem[] {\n\tconst idx = selectActivePreviewPaneIndex(currentTab, totalQuestions);\n\treturn itemsByTab[idx] ?? [];\n}\n"]}
1
+ {"version":3,"file":"derivations.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/derivations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAGnF;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC7C,SAAS,EAAE,SAAS,YAAY,EAAE,EAClC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACjB,OAAO,CAKT;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,GAAG;IACvE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd,CAOA;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,SAAS,YAAY,EAAE,EAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAC5C,KAAK,EAAE,SAAS,kBAAkB,EAAE,GAClC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAcvD;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAG/F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CACnC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,EACxD,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACpB,SAAS,kBAAkB,EAAE,CAG/B","sourcesContent":["import type { QuestionAnswer, QuestionData } from \"../../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.ts\";\nimport { ROW_INTENT_META } from \"../row-intent.ts\";\n\n/**\n * Pure derivation: does the option focused by `(currentTab, optionIndex)` carry a\n * non-empty `preview` string? Mode gates (chat focus, notes mode, multiSelect) layer\n * on top via dispatch branches; this predicate is intentionally mode-agnostic.\n */\nexport function computeFocusedOptionHasPreview(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\toptionIndex: number,\n): boolean {\n\tconst q = questions[currentTab];\n\tif (!q) return false;\n\tconst opt = q.options[optionIndex];\n\treturn !!opt && typeof opt.preview === \"string\" && opt.preview.length > 0;\n}\n\n/**\n * Numbering for the chat row's WrappingSelect, computed from the active tab's items.\n *\n * The chat row lives in its own one-item WrappingSelect; the host calls this on every tab\n * switch / selection update to keep the chat row's `N. ` label continuous with the visible\n * numbered rows of the active tab. The shape `{ offset, total }` mirrors\n * `WrappingSelect.setNumbering(numberStartOffset, totalItemsForNumbering)` directly.\n */\nexport function chatNumberingFor(items: readonly WrappingSelectItem[]): {\n\toffset: number;\n\ttotal: number;\n} {\n\t// Count only the visible-numbered rows. The Next sentinel renders without a number\n\t// (see MultiSelectView), so it must NOT advance the chat row's number — otherwise\n\t// chat reads as \"6.\" next to options labeled 1-4. Sourced from `ROW_INTENT_META[kind].numbered`\n\t// so adding a new non-numbered kind is a single META edit.\n\tconst count = items.filter((i) => ROW_INTENT_META[i.kind].numbered).length;\n\treturn { offset: count, total: count + 1 };\n}\n\n/**\n * Which row in the active tab should be marked as \"previously confirmed\"? Drives the\n * `WrappingSelect` confirmed-row indicator (label + ` ✔`) when the user navigates back\n * to a question they already answered. Returns `undefined` when no marker should be drawn —\n * multi-select handles its own `[✔]` boxes via `multiSelectChecked`, `kind: \"chat\"` ends the\n * dialog so the row can never be re-entered, and a missing/non-matching answer (defensive)\n * silently skips the marker.\n */\nexport function selectConfirmedIndicator(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\titems: readonly WrappingSelectItem[],\n): { index: number; labelOverride?: string } | undefined {\n\tconst q = questions[currentTab];\n\tif (!q || q.multiSelect === true) return undefined;\n\tconst prior = answers.get(currentTab);\n\tif (!prior || prior.kind === \"chat\") return undefined;\n\tif (prior.kind === \"custom\") {\n\t\tconst otherIndex = items.findIndex((it) => it.kind === \"other\");\n\t\tif (otherIndex < 0) return undefined;\n\t\treturn { index: otherIndex, labelOverride: prior.answer ?? \"\" };\n\t}\n\tif (prior.kind !== \"option\" || typeof prior.answer !== \"string\") return undefined;\n\tconst index = items.findIndex((it) => it.kind === \"option\" && it.label === prior.answer);\n\tif (index < 0) return undefined;\n\treturn { index };\n}\n\n/**\n * Index of the preview pane to display for the current tab. The Submit tab (currentTab ===\n * questions.length) reuses the last question's pane purely for layout — the strategy\n * machinery picks the right body component independently. Defensive against `totalQuestions === 0`.\n */\nexport function selectActivePreviewPaneIndex(currentTab: number, totalQuestions: number): number {\n\tif (totalQuestions <= 0) return 0;\n\treturn Math.min(currentTab, totalQuestions - 1);\n}\n\n/**\n * Items array for the active tab, with the same Submit-tab clamp as `selectActivePreviewPaneIndex`.\n * Falls back to an empty array if the index lands outside the items array (defensive).\n */\nexport function selectActiveTabItems(\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>,\n\tcurrentTab: number,\n\ttotalQuestions: number,\n): readonly WrappingSelectItem[] {\n\tconst idx = selectActivePreviewPaneIndex(currentTab, totalQuestions);\n\treturn itemsByTab[idx] ?? [];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"derivations.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/derivations.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC7C,SAAkC,EAClC,UAAkB,EAClB,WAAmB;IAEnB,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAoC;IAIpE,mFAAmF;IACnF,kFAAkF;IAClF,gGAAgG;IAChG,2DAA2D;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC3E,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACvC,SAAkC,EAClC,UAAkB,EAClB,OAA4C,EAC5C,KAAoC;IAEpC,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QAChE,IAAI,UAAU,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QACrC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAClF,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,QAAQ,IAAI,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;IACzF,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,OAAO,EAAE,KAAK,EAAE,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,UAAkB,EAAE,cAAsB;IACtF,IAAI,cAAc,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CACnC,UAAwD,EACxD,UAAkB,EAClB,cAAsB;IAEtB,MAAM,GAAG,GAAG,4BAA4B,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACrE,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC","sourcesContent":["import type { QuestionAnswer, QuestionData } from \"../../tool/types.js\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.js\";\nimport { ROW_INTENT_META } from \"../row-intent.js\";\n\n/**\n * Pure derivation: does the option focused by `(currentTab, optionIndex)` carry a\n * non-empty `preview` string? Mode gates (chat focus, notes mode, multiSelect) layer\n * on top via dispatch branches; this predicate is intentionally mode-agnostic.\n */\nexport function computeFocusedOptionHasPreview(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\toptionIndex: number,\n): boolean {\n\tconst q = questions[currentTab];\n\tif (!q) return false;\n\tconst opt = q.options[optionIndex];\n\treturn !!opt && typeof opt.preview === \"string\" && opt.preview.length > 0;\n}\n\n/**\n * Numbering for the chat row's WrappingSelect, computed from the active tab's items.\n *\n * The chat row lives in its own one-item WrappingSelect; the host calls this on every tab\n * switch / selection update to keep the chat row's `N. ` label continuous with the visible\n * numbered rows of the active tab. The shape `{ offset, total }` mirrors\n * `WrappingSelect.setNumbering(numberStartOffset, totalItemsForNumbering)` directly.\n */\nexport function chatNumberingFor(items: readonly WrappingSelectItem[]): {\n\toffset: number;\n\ttotal: number;\n} {\n\t// Count only the visible-numbered rows. The Next sentinel renders without a number\n\t// (see MultiSelectView), so it must NOT advance the chat row's number — otherwise\n\t// chat reads as \"6.\" next to options labeled 1-4. Sourced from `ROW_INTENT_META[kind].numbered`\n\t// so adding a new non-numbered kind is a single META edit.\n\tconst count = items.filter((i) => ROW_INTENT_META[i.kind].numbered).length;\n\treturn { offset: count, total: count + 1 };\n}\n\n/**\n * Which row in the active tab should be marked as \"previously confirmed\"? Drives the\n * `WrappingSelect` confirmed-row indicator (label + ` ✔`) when the user navigates back\n * to a question they already answered. Returns `undefined` when no marker should be drawn —\n * multi-select handles its own `[✔]` boxes via `multiSelectChecked`, `kind: \"chat\"` ends the\n * dialog so the row can never be re-entered, and a missing/non-matching answer (defensive)\n * silently skips the marker.\n */\nexport function selectConfirmedIndicator(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\titems: readonly WrappingSelectItem[],\n): { index: number; labelOverride?: string } | undefined {\n\tconst q = questions[currentTab];\n\tif (!q || q.multiSelect === true) return undefined;\n\tconst prior = answers.get(currentTab);\n\tif (!prior || prior.kind === \"chat\") return undefined;\n\tif (prior.kind === \"custom\") {\n\t\tconst otherIndex = items.findIndex((it) => it.kind === \"other\");\n\t\tif (otherIndex < 0) return undefined;\n\t\treturn { index: otherIndex, labelOverride: prior.answer ?? \"\" };\n\t}\n\tif (prior.kind !== \"option\" || typeof prior.answer !== \"string\") return undefined;\n\tconst index = items.findIndex((it) => it.kind === \"option\" && it.label === prior.answer);\n\tif (index < 0) return undefined;\n\treturn { index };\n}\n\n/**\n * Index of the preview pane to display for the current tab. The Submit tab (currentTab ===\n * questions.length) reuses the last question's pane purely for layout — the strategy\n * machinery picks the right body component independently. Defensive against `totalQuestions === 0`.\n */\nexport function selectActivePreviewPaneIndex(currentTab: number, totalQuestions: number): number {\n\tif (totalQuestions <= 0) return 0;\n\treturn Math.min(currentTab, totalQuestions - 1);\n}\n\n/**\n * Items array for the active tab, with the same Submit-tab clamp as `selectActivePreviewPaneIndex`.\n * Falls back to an empty array if the index lands outside the items array (defensive).\n */\nexport function selectActiveTabItems(\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>,\n\tcurrentTab: number,\n\ttotalQuestions: number,\n): readonly WrappingSelectItem[] {\n\tconst idx = selectActivePreviewPaneIndex(currentTab, totalQuestions);\n\treturn itemsByTab[idx] ?? [];\n}\n"]}
1
+ {"version":3,"file":"derivations.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/derivations.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAC7C,SAAkC,EAClC,UAAkB,EAClB,WAAmB;IAEnB,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAoC;IAIpE,mFAAmF;IACnF,kFAAkF;IAClF,gGAAgG;IAChG,2DAA2D;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;IAC3E,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACvC,SAAkC,EAClC,UAAkB,EAClB,OAA4C,EAC5C,KAAoC;IAEpC,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACnD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QAChE,IAAI,UAAU,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QACrC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAClF,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,QAAQ,IAAI,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,CAAC,CAAC;IACzF,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,OAAO,EAAE,KAAK,EAAE,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,UAAkB,EAAE,cAAsB;IACtF,IAAI,cAAc,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CACnC,UAAwD,EACxD,UAAkB,EAClB,cAAsB;IAEtB,MAAM,GAAG,GAAG,4BAA4B,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACrE,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC","sourcesContent":["import type { QuestionAnswer, QuestionData } from \"../../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../../view/components/wrapping-select.ts\";\nimport { ROW_INTENT_META } from \"../row-intent.ts\";\n\n/**\n * Pure derivation: does the option focused by `(currentTab, optionIndex)` carry a\n * non-empty `preview` string? Mode gates (chat focus, notes mode, multiSelect) layer\n * on top via dispatch branches; this predicate is intentionally mode-agnostic.\n */\nexport function computeFocusedOptionHasPreview(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\toptionIndex: number,\n): boolean {\n\tconst q = questions[currentTab];\n\tif (!q) return false;\n\tconst opt = q.options[optionIndex];\n\treturn !!opt && typeof opt.preview === \"string\" && opt.preview.length > 0;\n}\n\n/**\n * Numbering for the chat row's WrappingSelect, computed from the active tab's items.\n *\n * The chat row lives in its own one-item WrappingSelect; the host calls this on every tab\n * switch / selection update to keep the chat row's `N. ` label continuous with the visible\n * numbered rows of the active tab. The shape `{ offset, total }` mirrors\n * `WrappingSelect.setNumbering(numberStartOffset, totalItemsForNumbering)` directly.\n */\nexport function chatNumberingFor(items: readonly WrappingSelectItem[]): {\n\toffset: number;\n\ttotal: number;\n} {\n\t// Count only the visible-numbered rows. The Next sentinel renders without a number\n\t// (see MultiSelectView), so it must NOT advance the chat row's number — otherwise\n\t// chat reads as \"6.\" next to options labeled 1-4. Sourced from `ROW_INTENT_META[kind].numbered`\n\t// so adding a new non-numbered kind is a single META edit.\n\tconst count = items.filter((i) => ROW_INTENT_META[i.kind].numbered).length;\n\treturn { offset: count, total: count + 1 };\n}\n\n/**\n * Which row in the active tab should be marked as \"previously confirmed\"? Drives the\n * `WrappingSelect` confirmed-row indicator (label + ` ✔`) when the user navigates back\n * to a question they already answered. Returns `undefined` when no marker should be drawn —\n * multi-select handles its own `[✔]` boxes via `multiSelectChecked`, `kind: \"chat\"` ends the\n * dialog so the row can never be re-entered, and a missing/non-matching answer (defensive)\n * silently skips the marker.\n */\nexport function selectConfirmedIndicator(\n\tquestions: readonly QuestionData[],\n\tcurrentTab: number,\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\titems: readonly WrappingSelectItem[],\n): { index: number; labelOverride?: string } | undefined {\n\tconst q = questions[currentTab];\n\tif (!q || q.multiSelect === true) return undefined;\n\tconst prior = answers.get(currentTab);\n\tif (!prior || prior.kind === \"chat\") return undefined;\n\tif (prior.kind === \"custom\") {\n\t\tconst otherIndex = items.findIndex((it) => it.kind === \"other\");\n\t\tif (otherIndex < 0) return undefined;\n\t\treturn { index: otherIndex, labelOverride: prior.answer ?? \"\" };\n\t}\n\tif (prior.kind !== \"option\" || typeof prior.answer !== \"string\") return undefined;\n\tconst index = items.findIndex((it) => it.kind === \"option\" && it.label === prior.answer);\n\tif (index < 0) return undefined;\n\treturn { index };\n}\n\n/**\n * Index of the preview pane to display for the current tab. The Submit tab (currentTab ===\n * questions.length) reuses the last question's pane purely for layout — the strategy\n * machinery picks the right body component independently. Defensive against `totalQuestions === 0`.\n */\nexport function selectActivePreviewPaneIndex(currentTab: number, totalQuestions: number): number {\n\tif (totalQuestions <= 0) return 0;\n\treturn Math.min(currentTab, totalQuestions - 1);\n}\n\n/**\n * Items array for the active tab, with the same Submit-tab clamp as `selectActivePreviewPaneIndex`.\n * Falls back to an empty array if the index lands outside the items array (defensive).\n */\nexport function selectActiveTabItems(\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>,\n\tcurrentTab: number,\n\ttotalQuestions: number,\n): readonly WrappingSelectItem[] {\n\tconst idx = selectActivePreviewPaneIndex(currentTab, totalQuestions);\n\treturn itemsByTab[idx] ?? [];\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ActiveView } from "../../view/stateful-view.js";
1
+ import type { ActiveView } from "../../view/stateful-view.ts";
2
2
  /**
3
3
  * Discriminated focus selector — single source of truth for "which view owns
4
4
  * focus this tick?" Priority order matches the dispatcher cascade
@@ -1 +1 @@
1
- {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE;IAAE,YAAY,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAC1E,cAAc,EAAE,MAAM,GACpB,UAAU,CAKZ","sourcesContent":["import type { ActiveView } from \"../../view/stateful-view.js\";\n\n/**\n * Discriminated focus selector — single source of truth for \"which view owns\n * focus this tick?\" Priority order matches the dispatcher cascade\n * (`key-router.ts:151-178`) and the reducer's defensive clears\n * (`state-reducer.ts:104-126`).\n *\n * Priority: notes > submit > chat > options.\n */\nexport function selectActiveView(\n\tstate: { notesVisible: boolean; chatFocused: boolean; currentTab: number },\n\ttotalQuestions: number,\n): ActiveView {\n\tif (state.notesVisible) return \"notes\";\n\tif (state.currentTab === totalQuestions) return \"submit\";\n\tif (state.chatFocused) return \"chat\";\n\treturn \"options\";\n}\n"]}
1
+ {"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE;IAAE,YAAY,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAC1E,cAAc,EAAE,MAAM,GACpB,UAAU,CAKZ","sourcesContent":["import type { ActiveView } from \"../../view/stateful-view.ts\";\n\n/**\n * Discriminated focus selector — single source of truth for \"which view owns\n * focus this tick?\" Priority order matches the dispatcher cascade\n * (`key-router.ts:151-178`) and the reducer's defensive clears\n * (`state-reducer.ts:104-126`).\n *\n * Priority: notes > submit > chat > options.\n */\nexport function selectActiveView(\n\tstate: { notesVisible: boolean; chatFocused: boolean; currentTab: number },\n\ttotalQuestions: number,\n): ActiveView {\n\tif (state.notesVisible) return \"notes\";\n\tif (state.currentTab === totalQuestions) return \"submit\";\n\tif (state.chatFocused) return \"chat\";\n\treturn \"options\";\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"focus.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/focus.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAA0E,EAC1E,cAAsB;IAEtB,IAAI,KAAK,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,KAAK,CAAC,UAAU,KAAK,cAAc;QAAE,OAAO,QAAQ,CAAC;IACzD,IAAI,KAAK,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IACrC,OAAO,SAAS,CAAC;AAClB,CAAC","sourcesContent":["import type { ActiveView } from \"../../view/stateful-view.js\";\n\n/**\n * Discriminated focus selector — single source of truth for \"which view owns\n * focus this tick?\" Priority order matches the dispatcher cascade\n * (`key-router.ts:151-178`) and the reducer's defensive clears\n * (`state-reducer.ts:104-126`).\n *\n * Priority: notes > submit > chat > options.\n */\nexport function selectActiveView(\n\tstate: { notesVisible: boolean; chatFocused: boolean; currentTab: number },\n\ttotalQuestions: number,\n): ActiveView {\n\tif (state.notesVisible) return \"notes\";\n\tif (state.currentTab === totalQuestions) return \"submit\";\n\tif (state.chatFocused) return \"chat\";\n\treturn \"options\";\n}\n"]}
1
+ {"version":3,"file":"focus.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/focus.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAA0E,EAC1E,cAAsB;IAEtB,IAAI,KAAK,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,KAAK,CAAC,UAAU,KAAK,cAAc;QAAE,OAAO,QAAQ,CAAC;IACzD,IAAI,KAAK,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IACrC,OAAO,SAAS,CAAC;AAClB,CAAC","sourcesContent":["import type { ActiveView } from \"../../view/stateful-view.ts\";\n\n/**\n * Discriminated focus selector — single source of truth for \"which view owns\n * focus this tick?\" Priority order matches the dispatcher cascade\n * (`key-router.ts:151-178`) and the reducer's defensive clears\n * (`state-reducer.ts:104-126`).\n *\n * Priority: notes > submit > chat > options.\n */\nexport function selectActiveView(\n\tstate: { notesVisible: boolean; chatFocused: boolean; currentTab: number },\n\ttotalQuestions: number,\n): ActiveView {\n\tif (state.notesVisible) return \"notes\";\n\tif (state.currentTab === totalQuestions) return \"submit\";\n\tif (state.chatFocused) return \"chat\";\n\treturn \"options\";\n}\n"]}
@@ -1,11 +1,11 @@
1
- import type { ChatRowViewProps } from "../../view/components/chat-row-view.js";
2
- import { type MultiSelectViewProps } from "../../view/components/multi-select-view.js";
3
- import type { OptionListViewProps } from "../../view/components/option-list-view.js";
4
- import type { PreviewPaneProps } from "../../view/components/preview/preview-pane.js";
5
- import type { SubmitPickerProps } from "../../view/components/submit-picker.js";
6
- import type { TabBarProps } from "../../view/components/tab-bar.js";
7
- import type { DialogProps } from "../../view/dialog-builder.js";
8
- import type { GlobalSelector, PerTabSelector } from "./contract.js";
1
+ import type { ChatRowViewProps } from "../../view/components/chat-row-view.ts";
2
+ import { type MultiSelectViewProps } from "../../view/components/multi-select-view.ts";
3
+ import type { OptionListViewProps } from "../../view/components/option-list-view.ts";
4
+ import type { PreviewPaneProps } from "../../view/components/preview/preview-pane.ts";
5
+ import type { SubmitPickerProps } from "../../view/components/submit-picker.ts";
6
+ import type { TabBarProps } from "../../view/components/tab-bar.ts";
7
+ import type { DialogProps } from "../../view/dialog-builder.ts";
8
+ import type { GlobalSelector, PerTabSelector } from "./contract.ts";
9
9
  export declare const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps>;
10
10
  export declare const selectOptionListProps: PerTabSelector<OptionListViewProps>;
11
11
  export declare const selectSubmitPickerProps: GlobalSelector<SubmitPickerProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"projections.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/projections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAC3G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpE,eAAO,MAAM,sBAAsB,EAAE,cAAc,CAAC,oBAAoB,CAevE,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,mBAAmB,CAUrE,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,cAAc,CAAC,iBAAiB,CAQrE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,cAAc,CAAC,gBAAgB,CAIlE,CAAC;AAEH,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,WAAW,CAazD,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,gBAAgB,CAM/D,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,WAAW,CAGxD,CAAC","sourcesContent":["import type { ChatRowViewProps } from \"../../view/components/chat-row-view.js\";\nimport { MULTI_SUBMIT_LABEL, type MultiSelectViewProps } from \"../../view/components/multi-select-view.js\";\nimport type { OptionListViewProps } from \"../../view/components/option-list-view.js\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.js\";\nimport type { SubmitPickerProps } from \"../../view/components/submit-picker.js\";\nimport type { TabBarProps } from \"../../view/components/tab-bar.js\";\nimport type { DialogProps } from \"../../view/dialog-builder.js\";\nimport { ROW_INTENT_META } from \"../row-intent.js\";\nimport type { GlobalSelector, PerTabSelector } from \"./contract.js\";\nimport { chatNumberingFor, selectActiveTabItems, selectConfirmedIndicator } from \"./derivations.js\";\n\nexport const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (state, ctx) => {\n\tconst question = ctx.questions[ctx.i];\n\tif (!question) return { rows: [], nextActive: false, nextLabel: ROW_INTENT_META.next.label };\n\tconst focused = ctx.activeView === \"options\";\n\tconst rows: { checked: boolean; active: boolean }[] = [];\n\tfor (let i = 0; i < question.options.length; i++) {\n\t\trows.push({\n\t\t\tchecked: state.multiSelectChecked.has(i),\n\t\t\tactive: focused && i === state.optionIndex,\n\t\t});\n\t}\n\tconst nextActive = focused && state.optionIndex === question.options.length;\n\tconst isLastQuestion = ctx.i === ctx.questions.length - 1;\n\tconst nextLabel = isLastQuestion ? MULTI_SUBMIT_LABEL : ROW_INTENT_META.next.label;\n\treturn { rows, nextActive, nextLabel };\n};\n\nexport const selectOptionListProps: PerTabSelector<OptionListViewProps> = (state, ctx) => {\n\tconst items = ctx.itemsByTab[ctx.i] ?? [];\n\tconst focused = ctx.activeView === \"options\";\n\tconst confirmed = selectConfirmedIndicator(ctx.questions, state.currentTab, state.answers, items);\n\treturn {\n\t\tselectedIndex: state.optionIndex,\n\t\tfocused,\n\t\tinputBuffer: ctx.inputBuffer,\n\t\t...(confirmed ? { confirmed } : {}),\n\t};\n};\n\nexport const selectSubmitPickerProps: GlobalSelector<SubmitPickerProps> = (state, ctx) => {\n\tconst focused = ctx.activeView === \"submit\";\n\treturn {\n\t\trows: [\n\t\t\t{ active: focused && state.submitChoiceIndex === 0 },\n\t\t\t{ active: focused && state.submitChoiceIndex === 1 },\n\t\t],\n\t};\n};\n\nexport const selectPreviewPaneProps: PerTabSelector<PreviewPaneProps> = (state, ctx) => ({\n\tnotesVisible: state.notesVisible,\n\tselectedIndex: state.optionIndex,\n\tfocused: ctx.activeView === \"options\",\n});\n\nexport const selectTabBarProps: GlobalSelector<TabBarProps> = (state, ctx) => {\n\tconst tabs = ctx.questions.map((q, i) => ({\n\t\tlabel: q.header && q.header.length > 0 ? q.header : `Q${i + 1}`,\n\t\tanswered: state.answers.has(i),\n\t\tactive: i === state.currentTab,\n\t}));\n\treturn {\n\t\ttabs,\n\t\tsubmit: {\n\t\t\tactive: state.currentTab === ctx.questions.length,\n\t\t\tallAnswered: state.answers.size === ctx.questions.length && ctx.questions.length > 0,\n\t\t},\n\t};\n};\n\nexport const selectChatRowProps: GlobalSelector<ChatRowViewProps> = (state, ctx) => {\n\tconst activeItems = selectActiveTabItems(ctx.itemsByTab, state.currentTab, ctx.totalQuestions);\n\treturn {\n\t\tfocused: ctx.activeView === \"chat\",\n\t\tnumbering: chatNumberingFor(activeItems),\n\t};\n};\n\nexport const selectDialogProps: GlobalSelector<DialogProps> = (state, ctx) => ({\n\tstate,\n\tactivePreviewPane: ctx.activePreviewPane,\n});\n"]}
1
+ {"version":3,"file":"projections.d.ts","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/projections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,4CAA4C,CAAC;AAC3G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpE,eAAO,MAAM,sBAAsB,EAAE,cAAc,CAAC,oBAAoB,CAevE,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,cAAc,CAAC,mBAAmB,CAUrE,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,cAAc,CAAC,iBAAiB,CAQrE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,cAAc,CAAC,gBAAgB,CAIlE,CAAC;AAEH,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,WAAW,CAazD,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,gBAAgB,CAM/D,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,WAAW,CAGxD,CAAC","sourcesContent":["import type { ChatRowViewProps } from \"../../view/components/chat-row-view.ts\";\nimport { MULTI_SUBMIT_LABEL, type MultiSelectViewProps } from \"../../view/components/multi-select-view.ts\";\nimport type { OptionListViewProps } from \"../../view/components/option-list-view.ts\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.ts\";\nimport type { SubmitPickerProps } from \"../../view/components/submit-picker.ts\";\nimport type { TabBarProps } from \"../../view/components/tab-bar.ts\";\nimport type { DialogProps } from \"../../view/dialog-builder.ts\";\nimport { ROW_INTENT_META } from \"../row-intent.ts\";\nimport type { GlobalSelector, PerTabSelector } from \"./contract.ts\";\nimport { chatNumberingFor, selectActiveTabItems, selectConfirmedIndicator } from \"./derivations.ts\";\n\nexport const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (state, ctx) => {\n\tconst question = ctx.questions[ctx.i];\n\tif (!question) return { rows: [], nextActive: false, nextLabel: ROW_INTENT_META.next.label };\n\tconst focused = ctx.activeView === \"options\";\n\tconst rows: { checked: boolean; active: boolean }[] = [];\n\tfor (let i = 0; i < question.options.length; i++) {\n\t\trows.push({\n\t\t\tchecked: state.multiSelectChecked.has(i),\n\t\t\tactive: focused && i === state.optionIndex,\n\t\t});\n\t}\n\tconst nextActive = focused && state.optionIndex === question.options.length;\n\tconst isLastQuestion = ctx.i === ctx.questions.length - 1;\n\tconst nextLabel = isLastQuestion ? MULTI_SUBMIT_LABEL : ROW_INTENT_META.next.label;\n\treturn { rows, nextActive, nextLabel };\n};\n\nexport const selectOptionListProps: PerTabSelector<OptionListViewProps> = (state, ctx) => {\n\tconst items = ctx.itemsByTab[ctx.i] ?? [];\n\tconst focused = ctx.activeView === \"options\";\n\tconst confirmed = selectConfirmedIndicator(ctx.questions, state.currentTab, state.answers, items);\n\treturn {\n\t\tselectedIndex: state.optionIndex,\n\t\tfocused,\n\t\tinputBuffer: ctx.inputBuffer,\n\t\t...(confirmed ? { confirmed } : {}),\n\t};\n};\n\nexport const selectSubmitPickerProps: GlobalSelector<SubmitPickerProps> = (state, ctx) => {\n\tconst focused = ctx.activeView === \"submit\";\n\treturn {\n\t\trows: [\n\t\t\t{ active: focused && state.submitChoiceIndex === 0 },\n\t\t\t{ active: focused && state.submitChoiceIndex === 1 },\n\t\t],\n\t};\n};\n\nexport const selectPreviewPaneProps: PerTabSelector<PreviewPaneProps> = (state, ctx) => ({\n\tnotesVisible: state.notesVisible,\n\tselectedIndex: state.optionIndex,\n\tfocused: ctx.activeView === \"options\",\n});\n\nexport const selectTabBarProps: GlobalSelector<TabBarProps> = (state, ctx) => {\n\tconst tabs = ctx.questions.map((q, i) => ({\n\t\tlabel: q.header && q.header.length > 0 ? q.header : `Q${i + 1}`,\n\t\tanswered: state.answers.has(i),\n\t\tactive: i === state.currentTab,\n\t}));\n\treturn {\n\t\ttabs,\n\t\tsubmit: {\n\t\t\tactive: state.currentTab === ctx.questions.length,\n\t\t\tallAnswered: state.answers.size === ctx.questions.length && ctx.questions.length > 0,\n\t\t},\n\t};\n};\n\nexport const selectChatRowProps: GlobalSelector<ChatRowViewProps> = (state, ctx) => {\n\tconst activeItems = selectActiveTabItems(ctx.itemsByTab, state.currentTab, ctx.totalQuestions);\n\treturn {\n\t\tfocused: ctx.activeView === \"chat\",\n\t\tnumbering: chatNumberingFor(activeItems),\n\t};\n};\n\nexport const selectDialogProps: GlobalSelector<DialogProps> = (state, ctx) => ({\n\tstate,\n\tactivePreviewPane: ctx.activePreviewPane,\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"projections.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/projections.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatRowViewProps } from \"../../view/components/chat-row-view.js\";\nimport { MULTI_SUBMIT_LABEL, type MultiSelectViewProps } from \"../../view/components/multi-select-view.js\";\nimport type { OptionListViewProps } from \"../../view/components/option-list-view.js\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.js\";\nimport type { SubmitPickerProps } from \"../../view/components/submit-picker.js\";\nimport type { TabBarProps } from \"../../view/components/tab-bar.js\";\nimport type { DialogProps } from \"../../view/dialog-builder.js\";\nimport { ROW_INTENT_META } from \"../row-intent.js\";\nimport type { GlobalSelector, PerTabSelector } from \"./contract.js\";\nimport { chatNumberingFor, selectActiveTabItems, selectConfirmedIndicator } from \"./derivations.js\";\n\nexport const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (state, ctx) => {\n\tconst question = ctx.questions[ctx.i];\n\tif (!question) return { rows: [], nextActive: false, nextLabel: ROW_INTENT_META.next.label };\n\tconst focused = ctx.activeView === \"options\";\n\tconst rows: { checked: boolean; active: boolean }[] = [];\n\tfor (let i = 0; i < question.options.length; i++) {\n\t\trows.push({\n\t\t\tchecked: state.multiSelectChecked.has(i),\n\t\t\tactive: focused && i === state.optionIndex,\n\t\t});\n\t}\n\tconst nextActive = focused && state.optionIndex === question.options.length;\n\tconst isLastQuestion = ctx.i === ctx.questions.length - 1;\n\tconst nextLabel = isLastQuestion ? MULTI_SUBMIT_LABEL : ROW_INTENT_META.next.label;\n\treturn { rows, nextActive, nextLabel };\n};\n\nexport const selectOptionListProps: PerTabSelector<OptionListViewProps> = (state, ctx) => {\n\tconst items = ctx.itemsByTab[ctx.i] ?? [];\n\tconst focused = ctx.activeView === \"options\";\n\tconst confirmed = selectConfirmedIndicator(ctx.questions, state.currentTab, state.answers, items);\n\treturn {\n\t\tselectedIndex: state.optionIndex,\n\t\tfocused,\n\t\tinputBuffer: ctx.inputBuffer,\n\t\t...(confirmed ? { confirmed } : {}),\n\t};\n};\n\nexport const selectSubmitPickerProps: GlobalSelector<SubmitPickerProps> = (state, ctx) => {\n\tconst focused = ctx.activeView === \"submit\";\n\treturn {\n\t\trows: [\n\t\t\t{ active: focused && state.submitChoiceIndex === 0 },\n\t\t\t{ active: focused && state.submitChoiceIndex === 1 },\n\t\t],\n\t};\n};\n\nexport const selectPreviewPaneProps: PerTabSelector<PreviewPaneProps> = (state, ctx) => ({\n\tnotesVisible: state.notesVisible,\n\tselectedIndex: state.optionIndex,\n\tfocused: ctx.activeView === \"options\",\n});\n\nexport const selectTabBarProps: GlobalSelector<TabBarProps> = (state, ctx) => {\n\tconst tabs = ctx.questions.map((q, i) => ({\n\t\tlabel: q.header && q.header.length > 0 ? q.header : `Q${i + 1}`,\n\t\tanswered: state.answers.has(i),\n\t\tactive: i === state.currentTab,\n\t}));\n\treturn {\n\t\ttabs,\n\t\tsubmit: {\n\t\t\tactive: state.currentTab === ctx.questions.length,\n\t\t\tallAnswered: state.answers.size === ctx.questions.length && ctx.questions.length > 0,\n\t\t},\n\t};\n};\n\nexport const selectChatRowProps: GlobalSelector<ChatRowViewProps> = (state, ctx) => {\n\tconst activeItems = selectActiveTabItems(ctx.itemsByTab, state.currentTab, ctx.totalQuestions);\n\treturn {\n\t\tfocused: ctx.activeView === \"chat\",\n\t\tnumbering: chatNumberingFor(activeItems),\n\t};\n};\n\nexport const selectDialogProps: GlobalSelector<DialogProps> = (state, ctx) => ({\n\tstate,\n\tactivePreviewPane: ctx.activePreviewPane,\n});\n"]}
1
+ {"version":3,"file":"projections.js","sourceRoot":"","sources":["../../../../../../src/core/tools/ask-user-question/state/selectors/projections.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ChatRowViewProps } from \"../../view/components/chat-row-view.ts\";\nimport { MULTI_SUBMIT_LABEL, type MultiSelectViewProps } from \"../../view/components/multi-select-view.ts\";\nimport type { OptionListViewProps } from \"../../view/components/option-list-view.ts\";\nimport type { PreviewPaneProps } from \"../../view/components/preview/preview-pane.ts\";\nimport type { SubmitPickerProps } from \"../../view/components/submit-picker.ts\";\nimport type { TabBarProps } from \"../../view/components/tab-bar.ts\";\nimport type { DialogProps } from \"../../view/dialog-builder.ts\";\nimport { ROW_INTENT_META } from \"../row-intent.ts\";\nimport type { GlobalSelector, PerTabSelector } from \"./contract.ts\";\nimport { chatNumberingFor, selectActiveTabItems, selectConfirmedIndicator } from \"./derivations.ts\";\n\nexport const selectMultiSelectProps: PerTabSelector<MultiSelectViewProps> = (state, ctx) => {\n\tconst question = ctx.questions[ctx.i];\n\tif (!question) return { rows: [], nextActive: false, nextLabel: ROW_INTENT_META.next.label };\n\tconst focused = ctx.activeView === \"options\";\n\tconst rows: { checked: boolean; active: boolean }[] = [];\n\tfor (let i = 0; i < question.options.length; i++) {\n\t\trows.push({\n\t\t\tchecked: state.multiSelectChecked.has(i),\n\t\t\tactive: focused && i === state.optionIndex,\n\t\t});\n\t}\n\tconst nextActive = focused && state.optionIndex === question.options.length;\n\tconst isLastQuestion = ctx.i === ctx.questions.length - 1;\n\tconst nextLabel = isLastQuestion ? MULTI_SUBMIT_LABEL : ROW_INTENT_META.next.label;\n\treturn { rows, nextActive, nextLabel };\n};\n\nexport const selectOptionListProps: PerTabSelector<OptionListViewProps> = (state, ctx) => {\n\tconst items = ctx.itemsByTab[ctx.i] ?? [];\n\tconst focused = ctx.activeView === \"options\";\n\tconst confirmed = selectConfirmedIndicator(ctx.questions, state.currentTab, state.answers, items);\n\treturn {\n\t\tselectedIndex: state.optionIndex,\n\t\tfocused,\n\t\tinputBuffer: ctx.inputBuffer,\n\t\t...(confirmed ? { confirmed } : {}),\n\t};\n};\n\nexport const selectSubmitPickerProps: GlobalSelector<SubmitPickerProps> = (state, ctx) => {\n\tconst focused = ctx.activeView === \"submit\";\n\treturn {\n\t\trows: [\n\t\t\t{ active: focused && state.submitChoiceIndex === 0 },\n\t\t\t{ active: focused && state.submitChoiceIndex === 1 },\n\t\t],\n\t};\n};\n\nexport const selectPreviewPaneProps: PerTabSelector<PreviewPaneProps> = (state, ctx) => ({\n\tnotesVisible: state.notesVisible,\n\tselectedIndex: state.optionIndex,\n\tfocused: ctx.activeView === \"options\",\n});\n\nexport const selectTabBarProps: GlobalSelector<TabBarProps> = (state, ctx) => {\n\tconst tabs = ctx.questions.map((q, i) => ({\n\t\tlabel: q.header && q.header.length > 0 ? q.header : `Q${i + 1}`,\n\t\tanswered: state.answers.has(i),\n\t\tactive: i === state.currentTab,\n\t}));\n\treturn {\n\t\ttabs,\n\t\tsubmit: {\n\t\t\tactive: state.currentTab === ctx.questions.length,\n\t\t\tallAnswered: state.answers.size === ctx.questions.length && ctx.questions.length > 0,\n\t\t},\n\t};\n};\n\nexport const selectChatRowProps: GlobalSelector<ChatRowViewProps> = (state, ctx) => {\n\tconst activeItems = selectActiveTabItems(ctx.itemsByTab, state.currentTab, ctx.totalQuestions);\n\treturn {\n\t\tfocused: ctx.activeView === \"chat\",\n\t\tnumbering: chatNumberingFor(activeItems),\n\t};\n};\n\nexport const selectDialogProps: GlobalSelector<DialogProps> = (state, ctx) => ({\n\tstate,\n\tactivePreviewPane: ctx.activePreviewPane,\n});\n"]}
@@ -1,7 +1,7 @@
1
- import type { QuestionData, QuestionnaireResult } from "../tool/types.js";
2
- import type { WrappingSelectItem } from "../view/components/wrapping-select.js";
3
- import type { QuestionnaireAction } from "./key-router.js";
4
- import type { QuestionnaireState } from "./state.js";
1
+ import type { QuestionData, QuestionnaireResult } from "../tool/types.ts";
2
+ import type { WrappingSelectItem } from "../view/components/wrapping-select.ts";
3
+ import type { QuestionnaireAction } from "./key-router.ts";
4
+ import type { QuestionnaireState } from "./state.ts";
5
5
  /** Session-lifetime constants. No live-component reads — peripheral values live on canonical state. */
6
6
  export interface ApplyContext {
7
7
  questions: readonly QuestionData[];
@@ -1 +1 @@
1
- {"version":3,"file":"state-reducer.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/state-reducer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,uGAAuG;AACvG,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IACnC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GACf;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AA2PD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,EAAE,YAAY,GAAG,WAAW,CAG7G","sourcesContent":["import type { QuestionAnswer, QuestionData, QuestionnaireResult } from \"../tool/types.js\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.js\";\nimport type { QuestionnaireAction } from \"./key-router.js\";\nimport { ROW_INTENT_META } from \"./row-intent.js\";\nimport { computeFocusedOptionHasPreview } from \"./selectors/derivations.js\";\nimport type { QuestionnaireState } from \"./state.js\";\n\n/** Session-lifetime constants. No live-component reads — peripheral values live on canonical state. */\nexport interface ApplyContext {\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n}\n\n/**\n * Declarative side-effects emitted by `reduce`. The runtime executes them after\n * committing the new state, then asks the props-adapter to re-project. Closed set —\n * adding an effect requires updating both the union AND the runtime's `runEffect` switch\n * (compiler-enforced exhaustive). No string-keyed escape hatch.\n */\nexport type Effect =\n\t| { kind: \"set_input_buffer\"; value: string }\n\t| { kind: \"clear_input_buffer\" }\n\t| { kind: \"set_notes_value\"; value: string }\n\t| { kind: \"set_notes_focused\"; focused: boolean }\n\t| { kind: \"forward_notes_keystroke\"; data: string }\n\t| { kind: \"done\"; result: QuestionnaireResult };\n\nexport interface ApplyResult {\n\tstate: QuestionnaireState;\n\teffects: readonly Effect[];\n}\n\nfunction orderedAnswers(state: QuestionnaireState, questions: readonly QuestionData[]): QuestionAnswer[] {\n\tconst out: QuestionAnswer[] = [];\n\tfor (let i = 0; i < questions.length; i++) {\n\t\tconst a = state.answers.get(i);\n\t\tif (a) out.push(a);\n\t}\n\treturn out;\n}\n\nfunction withFocusedOptionHasPreview(\n\tstate: QuestionnaireState,\n\tquestions: readonly QuestionData[],\n): QuestionnaireState {\n\tconst focusedOptionHasPreview = computeFocusedOptionHasPreview(questions, state.currentTab, state.optionIndex);\n\tif (state.focusedOptionHasPreview === focusedOptionHasPreview) return state;\n\treturn { ...state, focusedOptionHasPreview };\n}\n\nfunction syncMultiSelectFromAnswers(\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\tquestions: readonly QuestionData[],\n\ttab: number,\n): ReadonlySet<number> {\n\tconst q = questions[tab];\n\tif (!q?.multiSelect) return new Set();\n\tconst saved = answers.get(tab);\n\tconst labels = saved?.selected ?? [];\n\tconst indices = new Set<number>();\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (labels.includes(q.options[i]!.label)) indices.add(i);\n\t}\n\treturn indices;\n}\n\nfunction persistMultiSelectAnswer(state: QuestionnaireState, ctx: ApplyContext): ReadonlyMap<number, QuestionAnswer> {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q?.multiSelect) return state.answers;\n\tconst selected: string[] = [];\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (state.multiSelectChecked.has(i)) selected.push(q.options[i]!.label);\n\t}\n\tconst out = new Map(state.answers);\n\tif (selected.length === 0) {\n\t\tout.delete(state.currentTab);\n\t\treturn out;\n\t}\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tout.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\treturn out;\n}\n\nfunction switchTabResult(state: QuestionnaireState, nextTab: number, ctx: ApplyContext): ApplyResult {\n\tconst notesValue = state.notesByTab.get(nextTab) ?? state.answers.get(nextTab)?.notes ?? \"\";\n\tconst transitioned: QuestionnaireState = {\n\t\t...state,\n\t\tcurrentTab: nextTab,\n\t\toptionIndex: 0,\n\t\tinputMode: false,\n\t\tnotesVisible: false,\n\t\tchatFocused: false,\n\t\tsubmitChoiceIndex: 0,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(state.answers, ctx.questions, nextTab),\n\t\tnotesDraft: notesValue,\n\t};\n\tconst finalState = withFocusedOptionHasPreview(transitioned, ctx.questions);\n\treturn {\n\t\tstate: finalState,\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_focused\", focused: false },\n\t\t\t{ kind: \"set_notes_value\", value: notesValue },\n\t\t],\n\t};\n}\n\nfunction doneFor(state: QuestionnaireState, ctx: ApplyContext, cancelled: boolean): ApplyResult {\n\tconst result: QuestionnaireResult = { answers: orderedAnswers(state, ctx.questions), cancelled };\n\treturn { state, effects: [{ kind: \"done\", result }] };\n}\n\n/**\n * Per-kind handler signature: action payload narrows to the matching union member\n * via `Extract`, so handlers consume fully-typed actions without `as` casts.\n */\ntype Handler<K extends QuestionnaireAction[\"kind\"]> = (\n\tstate: QuestionnaireState,\n\taction: Extract<QuestionnaireAction, { kind: K }>,\n\tctx: ApplyContext,\n) => ApplyResult;\n\nconst navHandler: Handler<\"nav\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst item = items[action.nextIndex];\n\tconst inputMode = item ? ROW_INTENT_META[item.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview({ ...state, optionIndex: action.nextIndex, inputMode }, ctx.questions);\n\tif (!inputMode) {\n\t\treturn { state: next, effects: [{ kind: \"clear_input_buffer\" }] };\n\t}\n\tconst prior = state.answers.get(state.currentTab);\n\tif (prior?.kind === \"custom\" && typeof prior.answer === \"string\") {\n\t\treturn { state: next, effects: [{ kind: \"set_input_buffer\", value: prior.answer }] };\n\t}\n\treturn { state: next, effects: [] };\n};\n\nconst tabSwitchHandler: Handler<\"tab_switch\"> = (state, action, ctx) => switchTabResult(state, action.nextTab, ctx);\n\nconst confirmHandler: Handler<\"confirm\"> = (state, action, ctx) => {\n\tlet answer = action.answer;\n\tif (answer.kind === \"option\" && answer.answer) {\n\t\tconst q = ctx.questions[answer.questionIndex];\n\t\tconst matched = q?.options.find((o) => o.label === answer.answer);\n\t\tif (matched?.preview && matched.preview.length > 0) {\n\t\t\tanswer = { ...answer, preview: matched.preview };\n\t\t}\n\t}\n\tconst pendingNotes = state.notesByTab.get(answer.questionIndex);\n\tif (pendingNotes && pendingNotes.length > 0) {\n\t\tanswer = { ...answer, notes: pendingNotes };\n\t}\n\tconst answers = new Map(state.answers);\n\tanswers.set(answer.questionIndex, answer);\n\tconst next: QuestionnaireState = { ...state, answers };\n\tif (answer.kind === \"chat\") return doneFor(next, ctx, false);\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(next, action.autoAdvanceTab, ctx);\n\treturn doneFor(next, ctx, false);\n};\n\nconst toggleHandler: Handler<\"toggle\"> = (state, action, ctx) => {\n\tconst checked = new Set(state.multiSelectChecked);\n\tif (checked.has(action.index)) checked.delete(action.index);\n\telse checked.add(action.index);\n\tconst intermediate: QuestionnaireState = { ...state, multiSelectChecked: checked };\n\tconst answers = persistMultiSelectAnswer(intermediate, ctx);\n\treturn { state: { ...intermediate, answers }, effects: [] };\n};\n\nconst multiConfirmHandler: Handler<\"multi_confirm\"> = (state, action, ctx) => {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q) return { state, effects: [] };\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tconst answers = new Map(state.answers);\n\tanswers.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected: action.selected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\tconst synced: QuestionnaireState = {\n\t\t...state,\n\t\tanswers,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(answers, ctx.questions, state.currentTab),\n\t};\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(synced, action.autoAdvanceTab, ctx);\n\treturn doneFor(synced, ctx, false);\n};\n\nconst notesEnterHandler: Handler<\"notes_enter\"> = (state, _action, _ctx) => {\n\tconst value = state.answers.get(state.currentTab)?.notes ?? \"\";\n\treturn {\n\t\tstate: { ...state, notesVisible: true, notesDraft: value },\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_value\", value },\n\t\t\t{ kind: \"set_notes_focused\", focused: true },\n\t\t],\n\t};\n};\n\nconst notesExitHandler: Handler<\"notes_exit\"> = (state, _action, _ctx) => {\n\tconst trimmed = state.notesDraft.trim();\n\tconst notes = new Map(state.notesByTab);\n\tconst answers = new Map(state.answers);\n\tif (trimmed.length === 0) {\n\t\tnotes.delete(state.currentTab);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev?.notes) {\n\t\t\tconst stripped = { ...prev };\n\t\t\tdelete (stripped as { notes?: string }).notes;\n\t\t\tanswers.set(state.currentTab, stripped);\n\t\t}\n\t} else {\n\t\tnotes.set(state.currentTab, trimmed);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev) answers.set(state.currentTab, { ...prev, notes: trimmed });\n\t}\n\treturn {\n\t\tstate: { ...state, notesByTab: notes, answers, notesVisible: false },\n\t\teffects: [{ kind: \"set_notes_focused\", focused: false }],\n\t};\n};\n\nconst focusOptionsHandler: Handler<\"focus_options\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst focused = items[action.optionIndex];\n\tconst inputMode = focused ? ROW_INTENT_META[focused.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview(\n\t\t{ ...state, chatFocused: false, optionIndex: action.optionIndex, inputMode },\n\t\tctx.questions,\n\t);\n\treturn { state: next, effects: inputMode ? [] : [{ kind: \"clear_input_buffer\" }] };\n};\n\nconst cancelHandler: Handler<\"cancel\"> = (s, _a, c) => doneFor(s, c, true);\nconst submitHandler: Handler<\"submit\"> = (s, _a, c) => doneFor(s, c, false);\nconst submitNavHandler: Handler<\"submit_nav\"> = (s, a, _c) => ({\n\tstate: { ...s, submitChoiceIndex: a.nextIndex },\n\teffects: [],\n});\nconst focusChatHandler: Handler<\"focus_chat\"> = (s, _a, _c) => ({\n\tstate: { ...s, chatFocused: true },\n\teffects: [],\n});\nconst notesForwardHandler: Handler<\"notes_forward\"> = (s, a, _c) => ({\n\tstate: s,\n\teffects: [{ kind: \"forward_notes_keystroke\", data: a.data }],\n});\nconst ignoreHandler: Handler<\"ignore\"> = (s, _a, _c) => ({ state: s, effects: [] });\n\n/**\n * Compile-time-exhaustive dispatch table. `{ [K in Kind]: Handler<K> }` requires\n * an entry per union member — adding a new `QuestionnaireAction` variant fails to\n * compile here until a handler is registered, mirroring the `Record<RowKind, …>`\n * pattern used by `ROW_INTENT_META`.\n */\nconst HANDLERS: { [K in QuestionnaireAction[\"kind\"]]: Handler<K> } = {\n\tnav: navHandler,\n\ttab_switch: tabSwitchHandler,\n\tconfirm: confirmHandler,\n\ttoggle: toggleHandler,\n\tmulti_confirm: multiConfirmHandler,\n\tcancel: cancelHandler,\n\tnotes_enter: notesEnterHandler,\n\tnotes_exit: notesExitHandler,\n\tnotes_forward: notesForwardHandler,\n\tsubmit: submitHandler,\n\tsubmit_nav: submitNavHandler,\n\tfocus_chat: focusChatHandler,\n\tfocus_options: focusOptionsHandler,\n\tignore: ignoreHandler,\n};\n\n/**\n * Pure reducer: (state, action, ctx) → (state, Effect[]). Mirrors `rpiv-todo`'s `applyTaskMutation`.\n * Delegates to `HANDLERS` — per-kind handlers above are pure, named, and individually testable.\n * `ignore` is also handled outside the reducer by `handleIgnoreInline` in the runtime fast path.\n */\nexport function reduce(state: QuestionnaireState, action: QuestionnaireAction, ctx: ApplyContext): ApplyResult {\n\tconst handler = HANDLERS[action.kind] as Handler<typeof action.kind>;\n\treturn handler(state, action as never, ctx);\n}\n"]}
1
+ {"version":3,"file":"state-reducer.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/state-reducer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,uGAAuG;AACvG,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IACnC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GACf;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AA2PD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,mBAAmB,EAAE,GAAG,EAAE,YAAY,GAAG,WAAW,CAG7G","sourcesContent":["import type { QuestionAnswer, QuestionData, QuestionnaireResult } from \"../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.ts\";\nimport type { QuestionnaireAction } from \"./key-router.ts\";\nimport { ROW_INTENT_META } from \"./row-intent.ts\";\nimport { computeFocusedOptionHasPreview } from \"./selectors/derivations.ts\";\nimport type { QuestionnaireState } from \"./state.ts\";\n\n/** Session-lifetime constants. No live-component reads — peripheral values live on canonical state. */\nexport interface ApplyContext {\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n}\n\n/**\n * Declarative side-effects emitted by `reduce`. The runtime executes them after\n * committing the new state, then asks the props-adapter to re-project. Closed set —\n * adding an effect requires updating both the union AND the runtime's `runEffect` switch\n * (compiler-enforced exhaustive). No string-keyed escape hatch.\n */\nexport type Effect =\n\t| { kind: \"set_input_buffer\"; value: string }\n\t| { kind: \"clear_input_buffer\" }\n\t| { kind: \"set_notes_value\"; value: string }\n\t| { kind: \"set_notes_focused\"; focused: boolean }\n\t| { kind: \"forward_notes_keystroke\"; data: string }\n\t| { kind: \"done\"; result: QuestionnaireResult };\n\nexport interface ApplyResult {\n\tstate: QuestionnaireState;\n\teffects: readonly Effect[];\n}\n\nfunction orderedAnswers(state: QuestionnaireState, questions: readonly QuestionData[]): QuestionAnswer[] {\n\tconst out: QuestionAnswer[] = [];\n\tfor (let i = 0; i < questions.length; i++) {\n\t\tconst a = state.answers.get(i);\n\t\tif (a) out.push(a);\n\t}\n\treturn out;\n}\n\nfunction withFocusedOptionHasPreview(\n\tstate: QuestionnaireState,\n\tquestions: readonly QuestionData[],\n): QuestionnaireState {\n\tconst focusedOptionHasPreview = computeFocusedOptionHasPreview(questions, state.currentTab, state.optionIndex);\n\tif (state.focusedOptionHasPreview === focusedOptionHasPreview) return state;\n\treturn { ...state, focusedOptionHasPreview };\n}\n\nfunction syncMultiSelectFromAnswers(\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\tquestions: readonly QuestionData[],\n\ttab: number,\n): ReadonlySet<number> {\n\tconst q = questions[tab];\n\tif (!q?.multiSelect) return new Set();\n\tconst saved = answers.get(tab);\n\tconst labels = saved?.selected ?? [];\n\tconst indices = new Set<number>();\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (labels.includes(q.options[i]!.label)) indices.add(i);\n\t}\n\treturn indices;\n}\n\nfunction persistMultiSelectAnswer(state: QuestionnaireState, ctx: ApplyContext): ReadonlyMap<number, QuestionAnswer> {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q?.multiSelect) return state.answers;\n\tconst selected: string[] = [];\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (state.multiSelectChecked.has(i)) selected.push(q.options[i]!.label);\n\t}\n\tconst out = new Map(state.answers);\n\tif (selected.length === 0) {\n\t\tout.delete(state.currentTab);\n\t\treturn out;\n\t}\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tout.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\treturn out;\n}\n\nfunction switchTabResult(state: QuestionnaireState, nextTab: number, ctx: ApplyContext): ApplyResult {\n\tconst notesValue = state.notesByTab.get(nextTab) ?? state.answers.get(nextTab)?.notes ?? \"\";\n\tconst transitioned: QuestionnaireState = {\n\t\t...state,\n\t\tcurrentTab: nextTab,\n\t\toptionIndex: 0,\n\t\tinputMode: false,\n\t\tnotesVisible: false,\n\t\tchatFocused: false,\n\t\tsubmitChoiceIndex: 0,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(state.answers, ctx.questions, nextTab),\n\t\tnotesDraft: notesValue,\n\t};\n\tconst finalState = withFocusedOptionHasPreview(transitioned, ctx.questions);\n\treturn {\n\t\tstate: finalState,\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_focused\", focused: false },\n\t\t\t{ kind: \"set_notes_value\", value: notesValue },\n\t\t],\n\t};\n}\n\nfunction doneFor(state: QuestionnaireState, ctx: ApplyContext, cancelled: boolean): ApplyResult {\n\tconst result: QuestionnaireResult = { answers: orderedAnswers(state, ctx.questions), cancelled };\n\treturn { state, effects: [{ kind: \"done\", result }] };\n}\n\n/**\n * Per-kind handler signature: action payload narrows to the matching union member\n * via `Extract`, so handlers consume fully-typed actions without `as` casts.\n */\ntype Handler<K extends QuestionnaireAction[\"kind\"]> = (\n\tstate: QuestionnaireState,\n\taction: Extract<QuestionnaireAction, { kind: K }>,\n\tctx: ApplyContext,\n) => ApplyResult;\n\nconst navHandler: Handler<\"nav\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst item = items[action.nextIndex];\n\tconst inputMode = item ? ROW_INTENT_META[item.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview({ ...state, optionIndex: action.nextIndex, inputMode }, ctx.questions);\n\tif (!inputMode) {\n\t\treturn { state: next, effects: [{ kind: \"clear_input_buffer\" }] };\n\t}\n\tconst prior = state.answers.get(state.currentTab);\n\tif (prior?.kind === \"custom\" && typeof prior.answer === \"string\") {\n\t\treturn { state: next, effects: [{ kind: \"set_input_buffer\", value: prior.answer }] };\n\t}\n\treturn { state: next, effects: [] };\n};\n\nconst tabSwitchHandler: Handler<\"tab_switch\"> = (state, action, ctx) => switchTabResult(state, action.nextTab, ctx);\n\nconst confirmHandler: Handler<\"confirm\"> = (state, action, ctx) => {\n\tlet answer = action.answer;\n\tif (answer.kind === \"option\" && answer.answer) {\n\t\tconst q = ctx.questions[answer.questionIndex];\n\t\tconst matched = q?.options.find((o) => o.label === answer.answer);\n\t\tif (matched?.preview && matched.preview.length > 0) {\n\t\t\tanswer = { ...answer, preview: matched.preview };\n\t\t}\n\t}\n\tconst pendingNotes = state.notesByTab.get(answer.questionIndex);\n\tif (pendingNotes && pendingNotes.length > 0) {\n\t\tanswer = { ...answer, notes: pendingNotes };\n\t}\n\tconst answers = new Map(state.answers);\n\tanswers.set(answer.questionIndex, answer);\n\tconst next: QuestionnaireState = { ...state, answers };\n\tif (answer.kind === \"chat\") return doneFor(next, ctx, false);\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(next, action.autoAdvanceTab, ctx);\n\treturn doneFor(next, ctx, false);\n};\n\nconst toggleHandler: Handler<\"toggle\"> = (state, action, ctx) => {\n\tconst checked = new Set(state.multiSelectChecked);\n\tif (checked.has(action.index)) checked.delete(action.index);\n\telse checked.add(action.index);\n\tconst intermediate: QuestionnaireState = { ...state, multiSelectChecked: checked };\n\tconst answers = persistMultiSelectAnswer(intermediate, ctx);\n\treturn { state: { ...intermediate, answers }, effects: [] };\n};\n\nconst multiConfirmHandler: Handler<\"multi_confirm\"> = (state, action, ctx) => {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q) return { state, effects: [] };\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tconst answers = new Map(state.answers);\n\tanswers.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected: action.selected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\tconst synced: QuestionnaireState = {\n\t\t...state,\n\t\tanswers,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(answers, ctx.questions, state.currentTab),\n\t};\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(synced, action.autoAdvanceTab, ctx);\n\treturn doneFor(synced, ctx, false);\n};\n\nconst notesEnterHandler: Handler<\"notes_enter\"> = (state, _action, _ctx) => {\n\tconst value = state.answers.get(state.currentTab)?.notes ?? \"\";\n\treturn {\n\t\tstate: { ...state, notesVisible: true, notesDraft: value },\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_value\", value },\n\t\t\t{ kind: \"set_notes_focused\", focused: true },\n\t\t],\n\t};\n};\n\nconst notesExitHandler: Handler<\"notes_exit\"> = (state, _action, _ctx) => {\n\tconst trimmed = state.notesDraft.trim();\n\tconst notes = new Map(state.notesByTab);\n\tconst answers = new Map(state.answers);\n\tif (trimmed.length === 0) {\n\t\tnotes.delete(state.currentTab);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev?.notes) {\n\t\t\tconst stripped = { ...prev };\n\t\t\tdelete (stripped as { notes?: string }).notes;\n\t\t\tanswers.set(state.currentTab, stripped);\n\t\t}\n\t} else {\n\t\tnotes.set(state.currentTab, trimmed);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev) answers.set(state.currentTab, { ...prev, notes: trimmed });\n\t}\n\treturn {\n\t\tstate: { ...state, notesByTab: notes, answers, notesVisible: false },\n\t\teffects: [{ kind: \"set_notes_focused\", focused: false }],\n\t};\n};\n\nconst focusOptionsHandler: Handler<\"focus_options\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst focused = items[action.optionIndex];\n\tconst inputMode = focused ? ROW_INTENT_META[focused.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview(\n\t\t{ ...state, chatFocused: false, optionIndex: action.optionIndex, inputMode },\n\t\tctx.questions,\n\t);\n\treturn { state: next, effects: inputMode ? [] : [{ kind: \"clear_input_buffer\" }] };\n};\n\nconst cancelHandler: Handler<\"cancel\"> = (s, _a, c) => doneFor(s, c, true);\nconst submitHandler: Handler<\"submit\"> = (s, _a, c) => doneFor(s, c, false);\nconst submitNavHandler: Handler<\"submit_nav\"> = (s, a, _c) => ({\n\tstate: { ...s, submitChoiceIndex: a.nextIndex },\n\teffects: [],\n});\nconst focusChatHandler: Handler<\"focus_chat\"> = (s, _a, _c) => ({\n\tstate: { ...s, chatFocused: true },\n\teffects: [],\n});\nconst notesForwardHandler: Handler<\"notes_forward\"> = (s, a, _c) => ({\n\tstate: s,\n\teffects: [{ kind: \"forward_notes_keystroke\", data: a.data }],\n});\nconst ignoreHandler: Handler<\"ignore\"> = (s, _a, _c) => ({ state: s, effects: [] });\n\n/**\n * Compile-time-exhaustive dispatch table. `{ [K in Kind]: Handler<K> }` requires\n * an entry per union member — adding a new `QuestionnaireAction` variant fails to\n * compile here until a handler is registered, mirroring the `Record<RowKind, …>`\n * pattern used by `ROW_INTENT_META`.\n */\nconst HANDLERS: { [K in QuestionnaireAction[\"kind\"]]: Handler<K> } = {\n\tnav: navHandler,\n\ttab_switch: tabSwitchHandler,\n\tconfirm: confirmHandler,\n\ttoggle: toggleHandler,\n\tmulti_confirm: multiConfirmHandler,\n\tcancel: cancelHandler,\n\tnotes_enter: notesEnterHandler,\n\tnotes_exit: notesExitHandler,\n\tnotes_forward: notesForwardHandler,\n\tsubmit: submitHandler,\n\tsubmit_nav: submitNavHandler,\n\tfocus_chat: focusChatHandler,\n\tfocus_options: focusOptionsHandler,\n\tignore: ignoreHandler,\n};\n\n/**\n * Pure reducer: (state, action, ctx) → (state, Effect[]). Mirrors `rpiv-todo`'s `applyTaskMutation`.\n * Delegates to `HANDLERS` — per-kind handlers above are pure, named, and individually testable.\n * `ignore` is also handled outside the reducer by `handleIgnoreInline` in the runtime fast path.\n */\nexport function reduce(state: QuestionnaireState, action: QuestionnaireAction, ctx: ApplyContext): ApplyResult {\n\tconst handler = HANDLERS[action.kind] as Handler<typeof action.kind>;\n\treturn handler(state, action as never, ctx);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"state-reducer.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/state-reducer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,8BAA8B,EAAE,MAAM,4BAA4B,CAAC;AA4B5E,SAAS,cAAc,CAAC,KAAyB,EAAE,SAAkC;IACpF,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,2BAA2B,CACnC,KAAyB,EACzB,SAAkC;IAElC,MAAM,uBAAuB,GAAG,8BAA8B,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC/G,IAAI,KAAK,CAAC,uBAAuB,KAAK,uBAAuB;QAAE,OAAO,KAAK,CAAC;IAC5E,OAAO,EAAE,GAAG,KAAK,EAAE,uBAAuB,EAAE,CAAC;AAC9C,CAAC;AAED,SAAS,0BAA0B,CAClC,OAA4C,EAC5C,SAAkC,EAClC,GAAW;IAEX,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,CAAC,EAAE,WAAW;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,KAAK,EAAE,QAAQ,IAAI,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAyB,EAAE,GAAiB;IAC7E,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,EAAE,WAAW;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IAC1C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC7B,OAAO,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE;QACzB,aAAa,EAAE,KAAK,CAAC,UAAU;QAC/B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,IAAI;QACZ,QAAQ;QACR,GAAG,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3E,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,eAAe,CAAC,KAAyB,EAAE,OAAe,EAAE,GAAiB;IACrF,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;IAC5F,MAAM,YAAY,GAAuB;QACxC,GAAG,KAAK;QACR,UAAU,EAAE,OAAO;QACnB,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,KAAK;QACnB,WAAW,EAAE,KAAK;QAClB,iBAAiB,EAAE,CAAC;QACpB,kBAAkB,EAAE,0BAA0B,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC;QACrF,UAAU,EAAE,UAAU;KACtB,CAAC;IACF,MAAM,UAAU,GAAG,2BAA2B,CAAC,YAAY,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAC5E,OAAO;QACN,KAAK,EAAE,UAAU;QACjB,OAAO,EAAE;YACR,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE;YAC7C,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,EAAE;SAC9C;KACD,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAAyB,EAAE,GAAiB,EAAE,SAAkB;IAChF,MAAM,MAAM,GAAwB,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC;IACjG,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AACvD,CAAC;AAYD,MAAM,UAAU,GAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;IACzD,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/E,MAAM,IAAI,GAAG,2BAA2B,CAAC,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IAChH,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,EAAE,CAAC;IACnE,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAEpH,MAAM,cAAc,GAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;IACjE,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAC/C,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,OAAO,EAAE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAClD,CAAC;IACF,CAAC;IACD,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAChE,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAC7C,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAuB,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAC;IACvD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAClG,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,aAAa,GAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClD,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;;QACvD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,YAAY,GAAuB,EAAE,GAAG,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC;IACnF,MAAM,OAAO,GAAG,wBAAwB,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,YAAY,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC7D,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;IAC5E,MAAM,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtC,MAAM,YAAY,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE;QAC7B,aAAa,EAAE,KAAK,CAAC,UAAU;QAC/B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3E,CAAC,CAAC;IACH,MAAM,MAAM,GAAuB;QAClC,GAAG,KAAK;QACR,OAAO;QACP,kBAAkB,EAAE,0BAA0B,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC;KACxF,CAAC;IACF,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACpG,OAAO,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAC1E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;IAC/D,OAAO;QACN,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE;QAC1D,OAAO,EAAE;YACR,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE;YAClC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE;SAC5C;KACD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IACxE,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;YAC7B,OAAQ,QAA+B,CAAC,KAAK,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;SAAM,CAAC;QACP,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO;QACN,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE;QACpE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;KACxD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAA6B,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;IAC5E,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;IACrF,MAAM,IAAI,GAAG,2BAA2B,CACvC,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,EAC5E,GAAG,CAAC,SAAS,CACb,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,EAAE,CAAC;AACpF,CAAC,CAAC;AAEF,MAAM,aAAa,GAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AAC3E,MAAM,aAAa,GAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5E,MAAM,gBAAgB,GAA0B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9D,KAAK,EAAE,EAAE,GAAG,CAAC,EAAE,iBAAiB,EAAE,CAAC,CAAC,SAAS,EAAE;IAC/C,OAAO,EAAE,EAAE;CACX,CAAC,CAAC;AACH,MAAM,gBAAgB,GAA0B,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,KAAK,EAAE,EAAE,GAAG,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE;IAClC,OAAO,EAAE,EAAE;CACX,CAAC,CAAC;AACH,MAAM,mBAAmB,GAA6B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACpE,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;CAC5D,CAAC,CAAC;AACH,MAAM,aAAa,GAAsB,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,QAAQ,GAAuD;IACpE,GAAG,EAAE,UAAU;IACf,UAAU,EAAE,gBAAgB;IAC5B,OAAO,EAAE,cAAc;IACvB,MAAM,EAAE,aAAa;IACrB,aAAa,EAAE,mBAAmB;IAClC,MAAM,EAAE,aAAa;IACrB,WAAW,EAAE,iBAAiB;IAC9B,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,mBAAmB;IAClC,MAAM,EAAE,aAAa;IACrB,UAAU,EAAE,gBAAgB;IAC5B,UAAU,EAAE,gBAAgB;IAC5B,aAAa,EAAE,mBAAmB;IAClC,MAAM,EAAE,aAAa;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,KAAyB,EAAE,MAA2B,EAAE,GAAiB;IAC/F,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAgC,CAAC;IACrE,OAAO,OAAO,CAAC,KAAK,EAAE,MAAe,EAAE,GAAG,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["import type { QuestionAnswer, QuestionData, QuestionnaireResult } from \"../tool/types.js\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.js\";\nimport type { QuestionnaireAction } from \"./key-router.js\";\nimport { ROW_INTENT_META } from \"./row-intent.js\";\nimport { computeFocusedOptionHasPreview } from \"./selectors/derivations.js\";\nimport type { QuestionnaireState } from \"./state.js\";\n\n/** Session-lifetime constants. No live-component reads — peripheral values live on canonical state. */\nexport interface ApplyContext {\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n}\n\n/**\n * Declarative side-effects emitted by `reduce`. The runtime executes them after\n * committing the new state, then asks the props-adapter to re-project. Closed set —\n * adding an effect requires updating both the union AND the runtime's `runEffect` switch\n * (compiler-enforced exhaustive). No string-keyed escape hatch.\n */\nexport type Effect =\n\t| { kind: \"set_input_buffer\"; value: string }\n\t| { kind: \"clear_input_buffer\" }\n\t| { kind: \"set_notes_value\"; value: string }\n\t| { kind: \"set_notes_focused\"; focused: boolean }\n\t| { kind: \"forward_notes_keystroke\"; data: string }\n\t| { kind: \"done\"; result: QuestionnaireResult };\n\nexport interface ApplyResult {\n\tstate: QuestionnaireState;\n\teffects: readonly Effect[];\n}\n\nfunction orderedAnswers(state: QuestionnaireState, questions: readonly QuestionData[]): QuestionAnswer[] {\n\tconst out: QuestionAnswer[] = [];\n\tfor (let i = 0; i < questions.length; i++) {\n\t\tconst a = state.answers.get(i);\n\t\tif (a) out.push(a);\n\t}\n\treturn out;\n}\n\nfunction withFocusedOptionHasPreview(\n\tstate: QuestionnaireState,\n\tquestions: readonly QuestionData[],\n): QuestionnaireState {\n\tconst focusedOptionHasPreview = computeFocusedOptionHasPreview(questions, state.currentTab, state.optionIndex);\n\tif (state.focusedOptionHasPreview === focusedOptionHasPreview) return state;\n\treturn { ...state, focusedOptionHasPreview };\n}\n\nfunction syncMultiSelectFromAnswers(\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\tquestions: readonly QuestionData[],\n\ttab: number,\n): ReadonlySet<number> {\n\tconst q = questions[tab];\n\tif (!q?.multiSelect) return new Set();\n\tconst saved = answers.get(tab);\n\tconst labels = saved?.selected ?? [];\n\tconst indices = new Set<number>();\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (labels.includes(q.options[i]!.label)) indices.add(i);\n\t}\n\treturn indices;\n}\n\nfunction persistMultiSelectAnswer(state: QuestionnaireState, ctx: ApplyContext): ReadonlyMap<number, QuestionAnswer> {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q?.multiSelect) return state.answers;\n\tconst selected: string[] = [];\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (state.multiSelectChecked.has(i)) selected.push(q.options[i]!.label);\n\t}\n\tconst out = new Map(state.answers);\n\tif (selected.length === 0) {\n\t\tout.delete(state.currentTab);\n\t\treturn out;\n\t}\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tout.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\treturn out;\n}\n\nfunction switchTabResult(state: QuestionnaireState, nextTab: number, ctx: ApplyContext): ApplyResult {\n\tconst notesValue = state.notesByTab.get(nextTab) ?? state.answers.get(nextTab)?.notes ?? \"\";\n\tconst transitioned: QuestionnaireState = {\n\t\t...state,\n\t\tcurrentTab: nextTab,\n\t\toptionIndex: 0,\n\t\tinputMode: false,\n\t\tnotesVisible: false,\n\t\tchatFocused: false,\n\t\tsubmitChoiceIndex: 0,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(state.answers, ctx.questions, nextTab),\n\t\tnotesDraft: notesValue,\n\t};\n\tconst finalState = withFocusedOptionHasPreview(transitioned, ctx.questions);\n\treturn {\n\t\tstate: finalState,\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_focused\", focused: false },\n\t\t\t{ kind: \"set_notes_value\", value: notesValue },\n\t\t],\n\t};\n}\n\nfunction doneFor(state: QuestionnaireState, ctx: ApplyContext, cancelled: boolean): ApplyResult {\n\tconst result: QuestionnaireResult = { answers: orderedAnswers(state, ctx.questions), cancelled };\n\treturn { state, effects: [{ kind: \"done\", result }] };\n}\n\n/**\n * Per-kind handler signature: action payload narrows to the matching union member\n * via `Extract`, so handlers consume fully-typed actions without `as` casts.\n */\ntype Handler<K extends QuestionnaireAction[\"kind\"]> = (\n\tstate: QuestionnaireState,\n\taction: Extract<QuestionnaireAction, { kind: K }>,\n\tctx: ApplyContext,\n) => ApplyResult;\n\nconst navHandler: Handler<\"nav\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst item = items[action.nextIndex];\n\tconst inputMode = item ? ROW_INTENT_META[item.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview({ ...state, optionIndex: action.nextIndex, inputMode }, ctx.questions);\n\tif (!inputMode) {\n\t\treturn { state: next, effects: [{ kind: \"clear_input_buffer\" }] };\n\t}\n\tconst prior = state.answers.get(state.currentTab);\n\tif (prior?.kind === \"custom\" && typeof prior.answer === \"string\") {\n\t\treturn { state: next, effects: [{ kind: \"set_input_buffer\", value: prior.answer }] };\n\t}\n\treturn { state: next, effects: [] };\n};\n\nconst tabSwitchHandler: Handler<\"tab_switch\"> = (state, action, ctx) => switchTabResult(state, action.nextTab, ctx);\n\nconst confirmHandler: Handler<\"confirm\"> = (state, action, ctx) => {\n\tlet answer = action.answer;\n\tif (answer.kind === \"option\" && answer.answer) {\n\t\tconst q = ctx.questions[answer.questionIndex];\n\t\tconst matched = q?.options.find((o) => o.label === answer.answer);\n\t\tif (matched?.preview && matched.preview.length > 0) {\n\t\t\tanswer = { ...answer, preview: matched.preview };\n\t\t}\n\t}\n\tconst pendingNotes = state.notesByTab.get(answer.questionIndex);\n\tif (pendingNotes && pendingNotes.length > 0) {\n\t\tanswer = { ...answer, notes: pendingNotes };\n\t}\n\tconst answers = new Map(state.answers);\n\tanswers.set(answer.questionIndex, answer);\n\tconst next: QuestionnaireState = { ...state, answers };\n\tif (answer.kind === \"chat\") return doneFor(next, ctx, false);\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(next, action.autoAdvanceTab, ctx);\n\treturn doneFor(next, ctx, false);\n};\n\nconst toggleHandler: Handler<\"toggle\"> = (state, action, ctx) => {\n\tconst checked = new Set(state.multiSelectChecked);\n\tif (checked.has(action.index)) checked.delete(action.index);\n\telse checked.add(action.index);\n\tconst intermediate: QuestionnaireState = { ...state, multiSelectChecked: checked };\n\tconst answers = persistMultiSelectAnswer(intermediate, ctx);\n\treturn { state: { ...intermediate, answers }, effects: [] };\n};\n\nconst multiConfirmHandler: Handler<\"multi_confirm\"> = (state, action, ctx) => {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q) return { state, effects: [] };\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tconst answers = new Map(state.answers);\n\tanswers.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected: action.selected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\tconst synced: QuestionnaireState = {\n\t\t...state,\n\t\tanswers,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(answers, ctx.questions, state.currentTab),\n\t};\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(synced, action.autoAdvanceTab, ctx);\n\treturn doneFor(synced, ctx, false);\n};\n\nconst notesEnterHandler: Handler<\"notes_enter\"> = (state, _action, _ctx) => {\n\tconst value = state.answers.get(state.currentTab)?.notes ?? \"\";\n\treturn {\n\t\tstate: { ...state, notesVisible: true, notesDraft: value },\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_value\", value },\n\t\t\t{ kind: \"set_notes_focused\", focused: true },\n\t\t],\n\t};\n};\n\nconst notesExitHandler: Handler<\"notes_exit\"> = (state, _action, _ctx) => {\n\tconst trimmed = state.notesDraft.trim();\n\tconst notes = new Map(state.notesByTab);\n\tconst answers = new Map(state.answers);\n\tif (trimmed.length === 0) {\n\t\tnotes.delete(state.currentTab);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev?.notes) {\n\t\t\tconst stripped = { ...prev };\n\t\t\tdelete (stripped as { notes?: string }).notes;\n\t\t\tanswers.set(state.currentTab, stripped);\n\t\t}\n\t} else {\n\t\tnotes.set(state.currentTab, trimmed);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev) answers.set(state.currentTab, { ...prev, notes: trimmed });\n\t}\n\treturn {\n\t\tstate: { ...state, notesByTab: notes, answers, notesVisible: false },\n\t\teffects: [{ kind: \"set_notes_focused\", focused: false }],\n\t};\n};\n\nconst focusOptionsHandler: Handler<\"focus_options\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst focused = items[action.optionIndex];\n\tconst inputMode = focused ? ROW_INTENT_META[focused.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview(\n\t\t{ ...state, chatFocused: false, optionIndex: action.optionIndex, inputMode },\n\t\tctx.questions,\n\t);\n\treturn { state: next, effects: inputMode ? [] : [{ kind: \"clear_input_buffer\" }] };\n};\n\nconst cancelHandler: Handler<\"cancel\"> = (s, _a, c) => doneFor(s, c, true);\nconst submitHandler: Handler<\"submit\"> = (s, _a, c) => doneFor(s, c, false);\nconst submitNavHandler: Handler<\"submit_nav\"> = (s, a, _c) => ({\n\tstate: { ...s, submitChoiceIndex: a.nextIndex },\n\teffects: [],\n});\nconst focusChatHandler: Handler<\"focus_chat\"> = (s, _a, _c) => ({\n\tstate: { ...s, chatFocused: true },\n\teffects: [],\n});\nconst notesForwardHandler: Handler<\"notes_forward\"> = (s, a, _c) => ({\n\tstate: s,\n\teffects: [{ kind: \"forward_notes_keystroke\", data: a.data }],\n});\nconst ignoreHandler: Handler<\"ignore\"> = (s, _a, _c) => ({ state: s, effects: [] });\n\n/**\n * Compile-time-exhaustive dispatch table. `{ [K in Kind]: Handler<K> }` requires\n * an entry per union member — adding a new `QuestionnaireAction` variant fails to\n * compile here until a handler is registered, mirroring the `Record<RowKind, …>`\n * pattern used by `ROW_INTENT_META`.\n */\nconst HANDLERS: { [K in QuestionnaireAction[\"kind\"]]: Handler<K> } = {\n\tnav: navHandler,\n\ttab_switch: tabSwitchHandler,\n\tconfirm: confirmHandler,\n\ttoggle: toggleHandler,\n\tmulti_confirm: multiConfirmHandler,\n\tcancel: cancelHandler,\n\tnotes_enter: notesEnterHandler,\n\tnotes_exit: notesExitHandler,\n\tnotes_forward: notesForwardHandler,\n\tsubmit: submitHandler,\n\tsubmit_nav: submitNavHandler,\n\tfocus_chat: focusChatHandler,\n\tfocus_options: focusOptionsHandler,\n\tignore: ignoreHandler,\n};\n\n/**\n * Pure reducer: (state, action, ctx) → (state, Effect[]). Mirrors `rpiv-todo`'s `applyTaskMutation`.\n * Delegates to `HANDLERS` — per-kind handlers above are pure, named, and individually testable.\n * `ignore` is also handled outside the reducer by `handleIgnoreInline` in the runtime fast path.\n */\nexport function reduce(state: QuestionnaireState, action: QuestionnaireAction, ctx: ApplyContext): ApplyResult {\n\tconst handler = HANDLERS[action.kind] as Handler<typeof action.kind>;\n\treturn handler(state, action as never, ctx);\n}\n"]}
1
+ {"version":3,"file":"state-reducer.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/state-reducer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { QuestionAnswer, QuestionData, QuestionnaireResult } from \"../tool/types.ts\";\nimport type { WrappingSelectItem } from \"../view/components/wrapping-select.ts\";\nimport type { QuestionnaireAction } from \"./key-router.ts\";\nimport { ROW_INTENT_META } from \"./row-intent.ts\";\nimport { computeFocusedOptionHasPreview } from \"./selectors/derivations.ts\";\nimport type { QuestionnaireState } from \"./state.ts\";\n\n/** Session-lifetime constants. No live-component reads — peripheral values live on canonical state. */\nexport interface ApplyContext {\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n}\n\n/**\n * Declarative side-effects emitted by `reduce`. The runtime executes them after\n * committing the new state, then asks the props-adapter to re-project. Closed set —\n * adding an effect requires updating both the union AND the runtime's `runEffect` switch\n * (compiler-enforced exhaustive). No string-keyed escape hatch.\n */\nexport type Effect =\n\t| { kind: \"set_input_buffer\"; value: string }\n\t| { kind: \"clear_input_buffer\" }\n\t| { kind: \"set_notes_value\"; value: string }\n\t| { kind: \"set_notes_focused\"; focused: boolean }\n\t| { kind: \"forward_notes_keystroke\"; data: string }\n\t| { kind: \"done\"; result: QuestionnaireResult };\n\nexport interface ApplyResult {\n\tstate: QuestionnaireState;\n\teffects: readonly Effect[];\n}\n\nfunction orderedAnswers(state: QuestionnaireState, questions: readonly QuestionData[]): QuestionAnswer[] {\n\tconst out: QuestionAnswer[] = [];\n\tfor (let i = 0; i < questions.length; i++) {\n\t\tconst a = state.answers.get(i);\n\t\tif (a) out.push(a);\n\t}\n\treturn out;\n}\n\nfunction withFocusedOptionHasPreview(\n\tstate: QuestionnaireState,\n\tquestions: readonly QuestionData[],\n): QuestionnaireState {\n\tconst focusedOptionHasPreview = computeFocusedOptionHasPreview(questions, state.currentTab, state.optionIndex);\n\tif (state.focusedOptionHasPreview === focusedOptionHasPreview) return state;\n\treturn { ...state, focusedOptionHasPreview };\n}\n\nfunction syncMultiSelectFromAnswers(\n\tanswers: ReadonlyMap<number, QuestionAnswer>,\n\tquestions: readonly QuestionData[],\n\ttab: number,\n): ReadonlySet<number> {\n\tconst q = questions[tab];\n\tif (!q?.multiSelect) return new Set();\n\tconst saved = answers.get(tab);\n\tconst labels = saved?.selected ?? [];\n\tconst indices = new Set<number>();\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (labels.includes(q.options[i]!.label)) indices.add(i);\n\t}\n\treturn indices;\n}\n\nfunction persistMultiSelectAnswer(state: QuestionnaireState, ctx: ApplyContext): ReadonlyMap<number, QuestionAnswer> {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q?.multiSelect) return state.answers;\n\tconst selected: string[] = [];\n\tfor (let i = 0; i < q.options.length; i++) {\n\t\tif (state.multiSelectChecked.has(i)) selected.push(q.options[i]!.label);\n\t}\n\tconst out = new Map(state.answers);\n\tif (selected.length === 0) {\n\t\tout.delete(state.currentTab);\n\t\treturn out;\n\t}\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tout.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\treturn out;\n}\n\nfunction switchTabResult(state: QuestionnaireState, nextTab: number, ctx: ApplyContext): ApplyResult {\n\tconst notesValue = state.notesByTab.get(nextTab) ?? state.answers.get(nextTab)?.notes ?? \"\";\n\tconst transitioned: QuestionnaireState = {\n\t\t...state,\n\t\tcurrentTab: nextTab,\n\t\toptionIndex: 0,\n\t\tinputMode: false,\n\t\tnotesVisible: false,\n\t\tchatFocused: false,\n\t\tsubmitChoiceIndex: 0,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(state.answers, ctx.questions, nextTab),\n\t\tnotesDraft: notesValue,\n\t};\n\tconst finalState = withFocusedOptionHasPreview(transitioned, ctx.questions);\n\treturn {\n\t\tstate: finalState,\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_focused\", focused: false },\n\t\t\t{ kind: \"set_notes_value\", value: notesValue },\n\t\t],\n\t};\n}\n\nfunction doneFor(state: QuestionnaireState, ctx: ApplyContext, cancelled: boolean): ApplyResult {\n\tconst result: QuestionnaireResult = { answers: orderedAnswers(state, ctx.questions), cancelled };\n\treturn { state, effects: [{ kind: \"done\", result }] };\n}\n\n/**\n * Per-kind handler signature: action payload narrows to the matching union member\n * via `Extract`, so handlers consume fully-typed actions without `as` casts.\n */\ntype Handler<K extends QuestionnaireAction[\"kind\"]> = (\n\tstate: QuestionnaireState,\n\taction: Extract<QuestionnaireAction, { kind: K }>,\n\tctx: ApplyContext,\n) => ApplyResult;\n\nconst navHandler: Handler<\"nav\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst item = items[action.nextIndex];\n\tconst inputMode = item ? ROW_INTENT_META[item.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview({ ...state, optionIndex: action.nextIndex, inputMode }, ctx.questions);\n\tif (!inputMode) {\n\t\treturn { state: next, effects: [{ kind: \"clear_input_buffer\" }] };\n\t}\n\tconst prior = state.answers.get(state.currentTab);\n\tif (prior?.kind === \"custom\" && typeof prior.answer === \"string\") {\n\t\treturn { state: next, effects: [{ kind: \"set_input_buffer\", value: prior.answer }] };\n\t}\n\treturn { state: next, effects: [] };\n};\n\nconst tabSwitchHandler: Handler<\"tab_switch\"> = (state, action, ctx) => switchTabResult(state, action.nextTab, ctx);\n\nconst confirmHandler: Handler<\"confirm\"> = (state, action, ctx) => {\n\tlet answer = action.answer;\n\tif (answer.kind === \"option\" && answer.answer) {\n\t\tconst q = ctx.questions[answer.questionIndex];\n\t\tconst matched = q?.options.find((o) => o.label === answer.answer);\n\t\tif (matched?.preview && matched.preview.length > 0) {\n\t\t\tanswer = { ...answer, preview: matched.preview };\n\t\t}\n\t}\n\tconst pendingNotes = state.notesByTab.get(answer.questionIndex);\n\tif (pendingNotes && pendingNotes.length > 0) {\n\t\tanswer = { ...answer, notes: pendingNotes };\n\t}\n\tconst answers = new Map(state.answers);\n\tanswers.set(answer.questionIndex, answer);\n\tconst next: QuestionnaireState = { ...state, answers };\n\tif (answer.kind === \"chat\") return doneFor(next, ctx, false);\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(next, action.autoAdvanceTab, ctx);\n\treturn doneFor(next, ctx, false);\n};\n\nconst toggleHandler: Handler<\"toggle\"> = (state, action, ctx) => {\n\tconst checked = new Set(state.multiSelectChecked);\n\tif (checked.has(action.index)) checked.delete(action.index);\n\telse checked.add(action.index);\n\tconst intermediate: QuestionnaireState = { ...state, multiSelectChecked: checked };\n\tconst answers = persistMultiSelectAnswer(intermediate, ctx);\n\treturn { state: { ...intermediate, answers }, effects: [] };\n};\n\nconst multiConfirmHandler: Handler<\"multi_confirm\"> = (state, action, ctx) => {\n\tconst q = ctx.questions[state.currentTab];\n\tif (!q) return { state, effects: [] };\n\tconst pendingNotes = state.notesByTab.get(state.currentTab);\n\tconst answers = new Map(state.answers);\n\tanswers.set(state.currentTab, {\n\t\tquestionIndex: state.currentTab,\n\t\tquestion: q.question,\n\t\tkind: \"multi\",\n\t\tanswer: null,\n\t\tselected: action.selected,\n\t\t...(pendingNotes && pendingNotes.length > 0 ? { notes: pendingNotes } : {}),\n\t});\n\tconst synced: QuestionnaireState = {\n\t\t...state,\n\t\tanswers,\n\t\tmultiSelectChecked: syncMultiSelectFromAnswers(answers, ctx.questions, state.currentTab),\n\t};\n\tif (action.autoAdvanceTab !== undefined) return switchTabResult(synced, action.autoAdvanceTab, ctx);\n\treturn doneFor(synced, ctx, false);\n};\n\nconst notesEnterHandler: Handler<\"notes_enter\"> = (state, _action, _ctx) => {\n\tconst value = state.answers.get(state.currentTab)?.notes ?? \"\";\n\treturn {\n\t\tstate: { ...state, notesVisible: true, notesDraft: value },\n\t\teffects: [\n\t\t\t{ kind: \"set_notes_value\", value },\n\t\t\t{ kind: \"set_notes_focused\", focused: true },\n\t\t],\n\t};\n};\n\nconst notesExitHandler: Handler<\"notes_exit\"> = (state, _action, _ctx) => {\n\tconst trimmed = state.notesDraft.trim();\n\tconst notes = new Map(state.notesByTab);\n\tconst answers = new Map(state.answers);\n\tif (trimmed.length === 0) {\n\t\tnotes.delete(state.currentTab);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev?.notes) {\n\t\t\tconst stripped = { ...prev };\n\t\t\tdelete (stripped as { notes?: string }).notes;\n\t\t\tanswers.set(state.currentTab, stripped);\n\t\t}\n\t} else {\n\t\tnotes.set(state.currentTab, trimmed);\n\t\tconst prev = answers.get(state.currentTab);\n\t\tif (prev) answers.set(state.currentTab, { ...prev, notes: trimmed });\n\t}\n\treturn {\n\t\tstate: { ...state, notesByTab: notes, answers, notesVisible: false },\n\t\teffects: [{ kind: \"set_notes_focused\", focused: false }],\n\t};\n};\n\nconst focusOptionsHandler: Handler<\"focus_options\"> = (state, action, ctx) => {\n\tconst items = ctx.itemsByTab[state.currentTab] ?? [];\n\tconst focused = items[action.optionIndex];\n\tconst inputMode = focused ? ROW_INTENT_META[focused.kind].activatesInputMode : false;\n\tconst next = withFocusedOptionHasPreview(\n\t\t{ ...state, chatFocused: false, optionIndex: action.optionIndex, inputMode },\n\t\tctx.questions,\n\t);\n\treturn { state: next, effects: inputMode ? [] : [{ kind: \"clear_input_buffer\" }] };\n};\n\nconst cancelHandler: Handler<\"cancel\"> = (s, _a, c) => doneFor(s, c, true);\nconst submitHandler: Handler<\"submit\"> = (s, _a, c) => doneFor(s, c, false);\nconst submitNavHandler: Handler<\"submit_nav\"> = (s, a, _c) => ({\n\tstate: { ...s, submitChoiceIndex: a.nextIndex },\n\teffects: [],\n});\nconst focusChatHandler: Handler<\"focus_chat\"> = (s, _a, _c) => ({\n\tstate: { ...s, chatFocused: true },\n\teffects: [],\n});\nconst notesForwardHandler: Handler<\"notes_forward\"> = (s, a, _c) => ({\n\tstate: s,\n\teffects: [{ kind: \"forward_notes_keystroke\", data: a.data }],\n});\nconst ignoreHandler: Handler<\"ignore\"> = (s, _a, _c) => ({ state: s, effects: [] });\n\n/**\n * Compile-time-exhaustive dispatch table. `{ [K in Kind]: Handler<K> }` requires\n * an entry per union member — adding a new `QuestionnaireAction` variant fails to\n * compile here until a handler is registered, mirroring the `Record<RowKind, …>`\n * pattern used by `ROW_INTENT_META`.\n */\nconst HANDLERS: { [K in QuestionnaireAction[\"kind\"]]: Handler<K> } = {\n\tnav: navHandler,\n\ttab_switch: tabSwitchHandler,\n\tconfirm: confirmHandler,\n\ttoggle: toggleHandler,\n\tmulti_confirm: multiConfirmHandler,\n\tcancel: cancelHandler,\n\tnotes_enter: notesEnterHandler,\n\tnotes_exit: notesExitHandler,\n\tnotes_forward: notesForwardHandler,\n\tsubmit: submitHandler,\n\tsubmit_nav: submitNavHandler,\n\tfocus_chat: focusChatHandler,\n\tfocus_options: focusOptionsHandler,\n\tignore: ignoreHandler,\n};\n\n/**\n * Pure reducer: (state, action, ctx) → (state, Effect[]). Mirrors `rpiv-todo`'s `applyTaskMutation`.\n * Delegates to `HANDLERS` — per-kind handlers above are pure, named, and individually testable.\n * `ignore` is also handled outside the reducer by `handleIgnoreInline` in the runtime fast path.\n */\nexport function reduce(state: QuestionnaireState, action: QuestionnaireAction, ctx: ApplyContext): ApplyResult {\n\tconst handler = HANDLERS[action.kind] as Handler<typeof action.kind>;\n\treturn handler(state, action as never, ctx);\n}\n"]}