@bastani/atomic 0.9.21-alpha.1 → 0.9.21-alpha.2

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 +27 -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 +11 -0
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/subagents/src/extension/index.bundle.mjs +292 -60
  7. package/dist/builtin/web-access/package.json +1 -1
  8. package/dist/builtin/workflows/CHANGELOG.md +11 -0
  9. package/dist/builtin/workflows/builtin/adversarial-verification.js +3 -3
  10. package/dist/builtin/workflows/builtin/{chunk-cw86srkf.js → chunk-632fxeb8.js} +1 -1
  11. package/dist/builtin/workflows/builtin/{chunk-w18kbz63.js → chunk-94f8zfz1.js} +1 -1
  12. package/dist/builtin/workflows/builtin/{chunk-kspvwc24.js → chunk-9cm2ckq2.js} +1 -1
  13. package/dist/builtin/workflows/builtin/{chunk-jaj27rqc.js → chunk-a1ar035d.js} +1 -1
  14. package/dist/builtin/workflows/builtin/{chunk-wh19f5ee.js → chunk-d3xhj946.js} +5 -4
  15. package/dist/builtin/workflows/builtin/{chunk-crw7q5g1.js → chunk-gyjck9z8.js} +1 -1
  16. package/dist/builtin/workflows/builtin/{chunk-maqv731g.js → chunk-hj8mh07f.js} +10 -6
  17. package/dist/builtin/workflows/builtin/{chunk-0nrgfbag.js → chunk-kb7s3gx2.js} +1 -1
  18. package/dist/builtin/workflows/builtin/{chunk-73c5tayt.js → chunk-kgn5wz1c.js} +19 -1
  19. package/dist/builtin/workflows/builtin/{chunk-2hak3b7g.js → chunk-nkj4qhj6.js} +1 -1
  20. package/dist/builtin/workflows/builtin/{chunk-bzdvx2xr.js → chunk-r97ndfvt.js} +1 -1
  21. package/dist/builtin/workflows/builtin/{chunk-vkmpdat4.js → chunk-wf876n16.js} +1 -1
  22. package/dist/builtin/workflows/builtin/classify-and-act.js +3 -3
  23. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -3
  24. package/dist/builtin/workflows/builtin/generate-and-filter.js +3 -3
  25. package/dist/builtin/workflows/builtin/goal.js +4 -4
  26. package/dist/builtin/workflows/builtin/index.js +12 -12
  27. package/dist/builtin/workflows/builtin/loop-until-done.js +3 -3
  28. package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
  29. package/dist/builtin/workflows/builtin/ralph.js +4 -4
  30. package/dist/builtin/workflows/builtin/steering-context.js +1 -1
  31. package/dist/builtin/workflows/builtin/tournament.js +3 -3
  32. package/dist/builtin/workflows/package.json +1 -1
  33. package/dist/builtin/workflows/src/extension/index.bundle.mjs +40 -11
  34. package/dist/builtin/workflows/src/index.js +9 -3
  35. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +6 -1
  36. package/dist/cli/auth-command.js +5 -0
  37. package/dist/cli/auth-command.js.map +1 -1
  38. package/dist/cli/credential-print.js +2 -0
  39. package/dist/cli/credential-print.js.map +1 -1
  40. package/dist/cli/experimental/command.js +5 -2
  41. package/dist/cli/experimental/command.js.map +1 -1
  42. package/dist/cli.js +1 -1
  43. package/dist/cli.js.map +1 -1
  44. package/dist/config.d.ts +4 -4
  45. package/dist/config.js +4 -4
  46. package/dist/config.js.map +1 -1
  47. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  48. package/dist/core/agent-session-extension-bindings.js +9 -4
  49. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  50. package/dist/core/agent-session-methods.d.ts +4 -4
  51. package/dist/core/agent-session-methods.d.ts.map +1 -1
  52. package/dist/core/agent-session-methods.js.map +1 -1
  53. package/dist/core/agent-session-prompt.d.ts +4 -4
  54. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  55. package/dist/core/agent-session-prompt.js +38 -15
  56. package/dist/core/agent-session-prompt.js.map +1 -1
  57. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  58. package/dist/core/agent-session-runtime.js +14 -9
  59. package/dist/core/agent-session-runtime.js.map +1 -1
  60. package/dist/core/agent-session-types.d.ts +4 -1
  61. package/dist/core/agent-session-types.d.ts.map +1 -1
  62. package/dist/core/agent-session-types.js.map +1 -1
  63. package/dist/core/agent-session.d.ts +1 -1
  64. package/dist/core/agent-session.d.ts.map +1 -1
  65. package/dist/core/agent-session.js +140 -95
  66. package/dist/core/agent-session.js.map +1 -1
  67. package/dist/core/auth-storage-backends.js +2 -3
  68. package/dist/core/auth-storage-backends.js.map +1 -1
  69. package/dist/core/auth-storage.js +4 -1
  70. package/dist/core/auth-storage.js.map +1 -1
  71. package/dist/core/builtin-resource-loader.js +9 -0
  72. package/dist/core/builtin-resource-loader.js.map +1 -1
  73. package/dist/core/cache-warmer.js +8 -1
  74. package/dist/core/cache-warmer.js.map +1 -1
  75. package/dist/core/compaction/range-planner.js +6 -0
  76. package/dist/core/compaction/range-planner.js.map +1 -1
  77. package/dist/core/execution-model-router.d.ts +13 -3
  78. package/dist/core/execution-model-router.d.ts.map +1 -1
  79. package/dist/core/execution-model-router.js +227 -131
  80. package/dist/core/execution-model-router.js.map +1 -1
  81. package/dist/core/export-html/template-js/entries-navigation.js +16 -6
  82. package/dist/core/export-html/template-js/initialization.js +34 -11
  83. package/dist/core/export-html/template.css +10 -0
  84. package/dist/core/export-html/template.js +50 -17
  85. package/dist/core/extensions/context-types.d.ts +2 -0
  86. package/dist/core/extensions/context-types.d.ts.map +1 -1
  87. package/dist/core/extensions/context-types.js.map +1 -1
  88. package/dist/core/extensions/host-input.js +8 -4
  89. package/dist/core/extensions/host-input.js.map +1 -1
  90. package/dist/core/extensions/reactive-widget.js +1 -0
  91. package/dist/core/extensions/reactive-widget.js.map +1 -1
  92. package/dist/core/extensions/runner-context.d.ts +1 -0
  93. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  94. package/dist/core/extensions/runner-context.js +4 -0
  95. package/dist/core/extensions/runner-context.js.map +1 -1
  96. package/dist/core/extensions/runner.d.ts +1 -0
  97. package/dist/core/extensions/runner.d.ts.map +1 -1
  98. package/dist/core/extensions/runner.js +48 -30
  99. package/dist/core/extensions/runner.js.map +1 -1
  100. package/dist/core/extensions/runtime-types.d.ts +1 -0
  101. package/dist/core/extensions/runtime-types.d.ts.map +1 -1
  102. package/dist/core/extensions/runtime-types.js.map +1 -1
  103. package/dist/core/extensions/workflow-activity-hub.js +9 -7
  104. package/dist/core/extensions/workflow-activity-hub.js.map +1 -1
  105. package/dist/core/footer-data-provider.js +24 -23
  106. package/dist/core/footer-data-provider.js.map +1 -1
  107. package/dist/core/keybindings.js +1 -0
  108. package/dist/core/keybindings.js.map +1 -1
  109. package/dist/core/mandatory-resource-loader.js +4 -1
  110. package/dist/core/mandatory-resource-loader.js.map +1 -1
  111. package/dist/core/model-config.js +2 -0
  112. package/dist/core/model-config.js.map +1 -1
  113. package/dist/core/model-registry.js +1 -0
  114. package/dist/core/model-registry.js.map +1 -1
  115. package/dist/core/{model-routing-task.d.ts → model-routing-bytes.d.ts} +1 -4
  116. package/dist/core/model-routing-bytes.d.ts.map +1 -0
  117. package/dist/core/model-routing-bytes.js +33 -0
  118. package/dist/core/model-routing-bytes.js.map +1 -0
  119. package/dist/core/model-routing-candidates.d.ts +42 -0
  120. package/dist/core/model-routing-candidates.d.ts.map +1 -0
  121. package/dist/core/model-routing-candidates.js +309 -0
  122. package/dist/core/model-routing-candidates.js.map +1 -0
  123. package/dist/core/model-routing-constraints.d.ts +4 -0
  124. package/dist/core/model-routing-constraints.d.ts.map +1 -1
  125. package/dist/core/model-routing-constraints.js +13 -1
  126. package/dist/core/model-routing-constraints.js.map +1 -1
  127. package/dist/core/model-routing-debug.d.ts +9 -0
  128. package/dist/core/model-routing-debug.d.ts.map +1 -0
  129. package/dist/core/model-routing-debug.js +14 -0
  130. package/dist/core/model-routing-debug.js.map +1 -0
  131. package/dist/core/model-routing-evals.d.ts +50 -0
  132. package/dist/core/model-routing-evals.d.ts.map +1 -0
  133. package/dist/core/model-routing-evals.js +190 -0
  134. package/dist/core/model-routing-evals.js.map +1 -0
  135. package/dist/core/model-routing-needs.d.ts +75 -0
  136. package/dist/core/model-routing-needs.d.ts.map +1 -0
  137. package/dist/core/model-routing-needs.js +176 -0
  138. package/dist/core/model-routing-needs.js.map +1 -0
  139. package/dist/core/model-runtime-streaming.js +3 -0
  140. package/dist/core/model-runtime-streaming.js.map +1 -1
  141. package/dist/core/model-runtime.js +26 -14
  142. package/dist/core/model-runtime.js.map +1 -1
  143. package/dist/core/models-store.js +2 -3
  144. package/dist/core/models-store.js.map +1 -1
  145. package/dist/core/output-guard.js +1 -0
  146. package/dist/core/output-guard.js.map +1 -1
  147. package/dist/core/package-manager-paths.d.ts +2 -1
  148. package/dist/core/package-manager-paths.d.ts.map +1 -1
  149. package/dist/core/package-manager-paths.js +4 -3
  150. package/dist/core/package-manager-paths.js.map +1 -1
  151. package/dist/core/package-manager.js +1 -0
  152. package/dist/core/package-manager.js.map +1 -1
  153. package/dist/core/resource-loader-assets.d.ts.map +1 -1
  154. package/dist/core/resource-loader-assets.js +9 -7
  155. package/dist/core/resource-loader-assets.js.map +1 -1
  156. package/dist/core/resource-loader-core.js +49 -0
  157. package/dist/core/resource-loader-core.js.map +1 -1
  158. package/dist/core/runtime-credentials.js +2 -1
  159. package/dist/core/runtime-credentials.js.map +1 -1
  160. package/dist/core/session-cwd.js +1 -0
  161. package/dist/core/session-cwd.js.map +1 -1
  162. package/dist/core/session-manager-archive.d.ts.map +1 -1
  163. package/dist/core/session-manager-archive.js +4 -2
  164. package/dist/core/session-manager-archive.js.map +1 -1
  165. package/dist/core/session-manager-core.js +11 -7
  166. package/dist/core/session-manager-core.js.map +1 -1
  167. package/dist/core/session-manager-storage.d.ts +10 -4
  168. package/dist/core/session-manager-storage.d.ts.map +1 -1
  169. package/dist/core/session-manager-storage.js +12 -6
  170. package/dist/core/session-manager-storage.js.map +1 -1
  171. package/dist/core/settings-manager-basic-accessors.d.ts +2 -1
  172. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  173. package/dist/core/settings-manager-basic-accessors.js +21 -0
  174. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  175. package/dist/core/settings-manager-core.js +13 -7
  176. package/dist/core/settings-manager-core.js.map +1 -1
  177. package/dist/core/settings-manager.d.ts +1 -1
  178. package/dist/core/settings-manager.d.ts.map +1 -1
  179. package/dist/core/settings-manager.js.map +1 -1
  180. package/dist/core/settings-storage.js +6 -0
  181. package/dist/core/settings-storage.js.map +1 -1
  182. package/dist/core/settings-types.d.ts +8 -0
  183. package/dist/core/settings-types.d.ts.map +1 -1
  184. package/dist/core/settings-types.js.map +1 -1
  185. package/dist/core/structured-output/index.d.ts.map +1 -1
  186. package/dist/core/structured-output/index.js +4 -1
  187. package/dist/core/structured-output/index.js.map +1 -1
  188. package/dist/core/structured-output/invalid-output.js +1 -0
  189. package/dist/core/structured-output/invalid-output.js.map +1 -1
  190. package/dist/core/tasks/agent-adapter.js +5 -3
  191. package/dist/core/tasks/agent-adapter.js.map +1 -1
  192. package/dist/core/tasks/child-command-owner.js +3 -7
  193. package/dist/core/tasks/child-command-owner.js.map +1 -1
  194. package/dist/core/tasks/completion.js +5 -1
  195. package/dist/core/tasks/completion.js.map +1 -1
  196. package/dist/core/tasks/owner-store.js +12 -8
  197. package/dist/core/tasks/owner-store.js.map +1 -1
  198. package/dist/core/tasks/supervisor.js +14 -35
  199. package/dist/core/tasks/supervisor.js.map +1 -1
  200. package/dist/core/tools/ask-user-question/state/build-questionnaire.js +13 -4
  201. package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
  202. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +11 -1
  203. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  204. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +1 -0
  205. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
  206. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js +1 -0
  207. package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
  208. package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
  209. package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
  210. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js +5 -0
  211. package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
  212. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js +2 -0
  213. package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
  214. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js +13 -8
  215. package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js.map +1 -1
  216. package/dist/core/tools/ask-user-question/view/components/submit-picker.js +1 -0
  217. package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
  218. package/dist/core/tools/ask-user-question/view/components/tab-bar.js +1 -0
  219. package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
  220. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +30 -24
  221. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  222. package/dist/core/tools/ask-user-question/view/dialog-builder.js +5 -0
  223. package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
  224. package/dist/core/tools/ask-user-question/view/props-adapter.js +8 -0
  225. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  226. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js +4 -4
  227. package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
  228. package/dist/core/tools/bash.js +5 -8
  229. package/dist/core/tools/bash.js.map +1 -1
  230. package/dist/core/tools/edit-batch.js +4 -0
  231. package/dist/core/tools/edit-batch.js.map +1 -1
  232. package/dist/core/tools/edit.js +2 -0
  233. package/dist/core/tools/edit.js.map +1 -1
  234. package/dist/core/tools/file-mutation-coordinator.js +9 -0
  235. package/dist/core/tools/file-mutation-coordinator.js.map +1 -1
  236. package/dist/core/tools/find.js +1 -1
  237. package/dist/core/tools/find.js.map +1 -1
  238. package/dist/core/tools/hashline-engine/fs.js +1 -1
  239. package/dist/core/tools/hashline-engine/fs.js.map +1 -1
  240. package/dist/core/tools/hashline-engine/input.js +4 -0
  241. package/dist/core/tools/hashline-engine/input.js.map +1 -1
  242. package/dist/core/tools/hashline-engine/mismatch.js +6 -0
  243. package/dist/core/tools/hashline-engine/mismatch.js.map +1 -1
  244. package/dist/core/tools/hashline-engine/patcher.js +13 -0
  245. package/dist/core/tools/hashline-engine/patcher.js.map +1 -1
  246. package/dist/core/tools/hashline-engine/recovery.js +1 -0
  247. package/dist/core/tools/hashline-engine/recovery.js.map +1 -1
  248. package/dist/core/tools/output-accumulator.js +20 -13
  249. package/dist/core/tools/output-accumulator.js.map +1 -1
  250. package/dist/core/tools/persisted-output-file.js +9 -3
  251. package/dist/core/tools/persisted-output-file.js.map +1 -1
  252. package/dist/core/tools/resource-selectors.js +1 -0
  253. package/dist/core/tools/resource-selectors.js.map +1 -1
  254. package/dist/core/tools/write.js +1 -0
  255. package/dist/core/tools/write.js.map +1 -1
  256. package/dist/core/trust-manager.js +1 -0
  257. package/dist/core/trust-manager.js.map +1 -1
  258. package/dist/core/workflow-stage-admission.js +17 -10
  259. package/dist/core/workflow-stage-admission.js.map +1 -1
  260. package/dist/extensions/llama/client.js +2 -0
  261. package/dist/extensions/llama/client.js.map +1 -1
  262. package/dist/extensions/llama/huggingface-ui.js +17 -9
  263. package/dist/extensions/llama/huggingface-ui.js.map +1 -1
  264. package/dist/extensions/llama/huggingface.js +2 -0
  265. package/dist/extensions/llama/huggingface.js.map +1 -1
  266. package/dist/extensions/llama/ui.js +11 -3
  267. package/dist/extensions/llama/ui.js.map +1 -1
  268. package/dist/index.d.ts +4 -2
  269. package/dist/index.d.ts.map +1 -1
  270. package/dist/index.js +3 -1
  271. package/dist/index.js.map +1 -1
  272. package/dist/modes/interactive/components/armin.js +10 -6
  273. package/dist/modes/interactive/components/armin.js.map +1 -1
  274. package/dist/modes/interactive/components/assistant-message.js +10 -2
  275. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  276. package/dist/modes/interactive/components/atomic-working-status.js +10 -2
  277. package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
  278. package/dist/modes/interactive/components/bash-execution.js +9 -4
  279. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  280. package/dist/modes/interactive/components/bordered-loader.js +3 -0
  281. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  282. package/dist/modes/interactive/components/branch-summary-message.js +4 -1
  283. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  284. package/dist/modes/interactive/components/chat-message-renderer.js +2 -1
  285. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  286. package/dist/modes/interactive/components/chat-session-host-state.js +63 -31
  287. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
  288. package/dist/modes/interactive/components/chat-session-host.js +8 -1
  289. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  290. package/dist/modes/interactive/components/chat-transcript.js +24 -14
  291. package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
  292. package/dist/modes/interactive/components/compaction-boundary-message.js +2 -1
  293. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  294. package/dist/modes/interactive/components/config-selector-list.js +15 -6
  295. package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
  296. package/dist/modes/interactive/components/config-selector.js +7 -1
  297. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  298. package/dist/modes/interactive/components/countdown-timer.js +2 -0
  299. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  300. package/dist/modes/interactive/components/custom-editor.js +21 -1
  301. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  302. package/dist/modes/interactive/components/custom-entry.js +4 -1
  303. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  304. package/dist/modes/interactive/components/custom-message.js +9 -1
  305. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  306. package/dist/modes/interactive/components/daxnuts.js +8 -6
  307. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  308. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  309. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  310. package/dist/modes/interactive/components/extension-editor.js +7 -1
  311. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  312. package/dist/modes/interactive/components/extension-input.js +8 -2
  313. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  314. package/dist/modes/interactive/components/extension-selector.js +9 -1
  315. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  316. package/dist/modes/interactive/components/first-time-setup.js +4 -2
  317. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  318. package/dist/modes/interactive/components/footer.js +5 -2
  319. package/dist/modes/interactive/components/footer.js.map +1 -1
  320. package/dist/modes/interactive/components/host-input-form.js +13 -2
  321. package/dist/modes/interactive/components/host-input-form.js.map +1 -1
  322. package/dist/modes/interactive/components/login-dialog.js +9 -3
  323. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  324. package/dist/modes/interactive/components/model-selector.js +24 -12
  325. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  326. package/dist/modes/interactive/components/oauth-selector.js +12 -3
  327. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  328. package/dist/modes/interactive/components/reserved-bottom-overlay.js +11 -2
  329. package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
  330. package/dist/modes/interactive/components/scoped-models-selector.js +13 -8
  331. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  332. package/dist/modes/interactive/components/scroll-widget.js +4 -0
  333. package/dist/modes/interactive/components/scroll-widget.js.map +1 -1
  334. package/dist/modes/interactive/components/session-selector-header.js +11 -7
  335. package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
  336. package/dist/modes/interactive/components/session-selector-list.js +25 -12
  337. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  338. package/dist/modes/interactive/components/session-selector.js +23 -15
  339. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  340. package/dist/modes/interactive/components/settings-selector-submenus.js +19 -1
  341. package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
  342. package/dist/modes/interactive/components/settings-selector.js +1 -0
  343. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  344. package/dist/modes/interactive/components/show-images-selector.js +1 -0
  345. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  346. package/dist/modes/interactive/components/skill-invocation-message.js +4 -1
  347. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  348. package/dist/modes/interactive/components/startup-identity.js +8 -3
  349. package/dist/modes/interactive/components/startup-identity.js.map +1 -1
  350. package/dist/modes/interactive/components/task-completion-message.js +2 -0
  351. package/dist/modes/interactive/components/task-completion-message.js.map +1 -1
  352. package/dist/modes/interactive/components/task-detail.js +2 -0
  353. package/dist/modes/interactive/components/task-detail.js.map +1 -1
  354. package/dist/modes/interactive/components/task-inspector.js +22 -12
  355. package/dist/modes/interactive/components/task-inspector.js.map +1 -1
  356. package/dist/modes/interactive/components/task-list.js +2 -0
  357. package/dist/modes/interactive/components/task-list.js.map +1 -1
  358. package/dist/modes/interactive/components/task-live-transcript.js +8 -3
  359. package/dist/modes/interactive/components/task-live-transcript.js.map +1 -1
  360. package/dist/modes/interactive/components/task-navigation.js +5 -2
  361. package/dist/modes/interactive/components/task-navigation.js.map +1 -1
  362. package/dist/modes/interactive/components/task-row.js +2 -0
  363. package/dist/modes/interactive/components/task-row.js.map +1 -1
  364. package/dist/modes/interactive/components/theme-selector.js +2 -0
  365. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  366. package/dist/modes/interactive/components/thinking-selector.js +7 -1
  367. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  368. package/dist/modes/interactive/components/tool-execution.js +25 -10
  369. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  370. package/dist/modes/interactive/components/transcript-follow-indicator.js +1 -0
  371. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
  372. package/dist/modes/interactive/components/tree-selector-component.js +7 -3
  373. package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
  374. package/dist/modes/interactive/components/tree-selector-help.js +1 -0
  375. package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
  376. package/dist/modes/interactive/components/tree-selector-label-input.js +6 -2
  377. package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
  378. package/dist/modes/interactive/components/tree-selector-list.js +4 -0
  379. package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
  380. package/dist/modes/interactive/components/trust-selector.js +6 -0
  381. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/user-message-selector.js +6 -3
  383. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  384. package/dist/modes/interactive/components/user-message.js +5 -0
  385. package/dist/modes/interactive/components/user-message.js.map +1 -1
  386. package/dist/modes/interactive/components/working-status.js +1 -0
  387. package/dist/modes/interactive/components/working-status.js.map +1 -1
  388. package/dist/modes/interactive/interactive-autocomplete.js +2 -0
  389. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  390. package/dist/modes/interactive/interactive-extension-runtime.js +1 -0
  391. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
  392. package/dist/modes/interactive/interactive-mode-base.js +162 -120
  393. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  394. package/dist/modes/interactive/interactive-mode-helpers.js +3 -0
  395. package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -1
  396. package/dist/modes/interactive/interactive-mode-surface.d.ts +0 -6
  397. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  398. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  399. package/dist/modes/interactive/interactive-resource-disclosure.js +0 -4
  400. package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -1
  401. package/dist/modes/interactive/interactive-resource-rendering.js +0 -12
  402. package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -1
  403. package/dist/modes/interactive/interactive-startup-chat-container.js +1 -4
  404. package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
  405. package/dist/modes/interactive/model-catalog-refresh.js +1 -3
  406. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -1
  407. package/dist/modes/interactive/theme/color-utils.d.ts +5 -0
  408. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
  409. package/dist/modes/interactive/theme/color-utils.js +11 -0
  410. package/dist/modes/interactive/theme/color-utils.js.map +1 -1
  411. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
  412. package/dist/modes/interactive/theme/global-theme.js +4 -3
  413. package/dist/modes/interactive/theme/global-theme.js.map +1 -1
  414. package/dist/modes/interactive/theme/theme-class.js +7 -0
  415. package/dist/modes/interactive/theme/theme-class.js.map +1 -1
  416. package/dist/modes/interactive/theme/theme-controller.js +9 -2
  417. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  418. package/dist/modes/interactive-engine/activity-watchdog.js +8 -3
  419. package/dist/modes/interactive-engine/activity-watchdog.js.map +1 -1
  420. package/dist/modes/interactive-engine/engine-custom-ui.js +12 -8
  421. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  422. package/dist/modes/interactive-engine/engine-dialog-host.js +7 -3
  423. package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
  424. package/dist/modes/interactive-engine/engine-health.js +23 -13
  425. package/dist/modes/interactive-engine/engine-health.js.map +1 -1
  426. package/dist/modes/interactive-engine/engine-input-form.js +3 -2
  427. package/dist/modes/interactive-engine/engine-input-form.js.map +1 -1
  428. package/dist/modes/interactive-engine/engine-monitor.js +13 -1
  429. package/dist/modes/interactive-engine/engine-monitor.js.map +1 -1
  430. package/dist/modes/interactive-engine/engine-project-trust.js +2 -1
  431. package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -1
  432. package/dist/modes/interactive-engine/engine-render-service.js +7 -4
  433. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  434. package/dist/modes/interactive-engine/engine-session-picker.js +3 -2
  435. package/dist/modes/interactive-engine/engine-session-picker.js.map +1 -1
  436. package/dist/modes/interactive-engine/input-form-host.js +5 -1
  437. package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
  438. package/dist/modes/interactive-engine/isolated-runtime.js +37 -23
  439. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  440. package/dist/modes/interactive-engine/remote-command-catalog.js +4 -3
  441. package/dist/modes/interactive-engine/remote-command-catalog.js.map +1 -1
  442. package/dist/modes/interactive-engine/remote-component.js +24 -12
  443. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  444. package/dist/modes/interactive-engine/remote-frame-clamp.js +3 -3
  445. package/dist/modes/interactive-engine/remote-frame-clamp.js.map +1 -1
  446. package/dist/modes/interactive-engine/remote-model-catalog.js +5 -4
  447. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  448. package/dist/modes/interactive-engine/remote-queue-pause.js +3 -1
  449. package/dist/modes/interactive-engine/remote-queue-pause.js.map +1 -1
  450. package/dist/modes/interactive-engine/remote-renderer.js +24 -13
  451. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  452. package/dist/modes/interactive-engine/resource-readiness-error.js +1 -0
  453. package/dist/modes/interactive-engine/resource-readiness-error.js.map +1 -1
  454. package/dist/modes/interactive-engine/session-picker-host.js +5 -1
  455. package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
  456. package/dist/modes/interactive-engine/terminal-mode-controller.js +2 -1
  457. package/dist/modes/interactive-engine/terminal-mode-controller.js.map +1 -1
  458. package/dist/modes/rpc/queued-writer.js +13 -4
  459. package/dist/modes/rpc/queued-writer.js.map +1 -1
  460. package/dist/modes/rpc/rpc-bash-request-owners.js +2 -1
  461. package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
  462. package/dist/modes/rpc/rpc-client-api.d.ts +8 -4
  463. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  464. package/dist/modes/rpc/rpc-client-api.js +10 -3
  465. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  466. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  467. package/dist/modes/rpc/rpc-client.js +35 -22
  468. package/dist/modes/rpc/rpc-client.js.map +1 -1
  469. package/dist/modes/rpc/rpc-command-handler.js +6 -6
  470. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  471. package/dist/modes/rpc/rpc-event-buffer.js +3 -1
  472. package/dist/modes/rpc/rpc-event-buffer.js.map +1 -1
  473. package/dist/modes/rpc/rpc-generation-buffer.js +1 -3
  474. package/dist/modes/rpc/rpc-generation-buffer.js.map +1 -1
  475. package/dist/modes/rpc/rpc-keybindings-reload.js +4 -1
  476. package/dist/modes/rpc/rpc-keybindings-reload.js.map +1 -1
  477. package/dist/modes/rpc/rpc-output-buffer.js +3 -4
  478. package/dist/modes/rpc/rpc-output-buffer.js.map +1 -1
  479. package/dist/modes/rpc/rpc-pending-requests.js +1 -3
  480. package/dist/modes/rpc/rpc-pending-requests.js.map +1 -1
  481. package/dist/modes/rpc/rpc-provider-auth.js +3 -1
  482. package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
  483. package/dist/modes/rpc/rpc-resource-readiness.js +4 -5
  484. package/dist/modes/rpc/rpc-resource-readiness.js.map +1 -1
  485. package/dist/modes/rpc/rpc-session-binding.js +15 -0
  486. package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
  487. package/dist/modes/rpc/rpc-terminal-drain.js +3 -0
  488. package/dist/modes/rpc/rpc-terminal-drain.js.map +1 -1
  489. package/dist/modes/rpc/rpc-types.d.ts +10 -1
  490. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  491. package/dist/modes/rpc/rpc-types.js.map +1 -1
  492. package/docs/models/evals.md +883 -39
  493. package/docs/models/model-selection.md +7 -8
  494. package/docs/rpc/examples.md +1 -1
  495. package/docs/rpc/protocol.md +9 -3
  496. package/docs/sdk/structured-decisions.md +1 -1
  497. package/docs/sdk.md +3 -3
  498. package/docs/settings.md +24 -3
  499. package/docs/subagents/reference.md +22 -4
  500. package/docs/subagents.md +2 -0
  501. package/docs/usage.md +3 -3
  502. package/docs/workflows/api-reference.md +1 -1
  503. package/docs/workflows/authoring.md +1 -7
  504. package/docs/workflows/builtins.md +1 -1
  505. package/docs/workflows/reliable-design.md +1 -1
  506. package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
  507. package/examples/extensions/gondolin/package.json +1 -1
  508. package/examples/rpc-client.ts +1 -1
  509. package/examples/rpc-extension-ui.ts +1 -1
  510. package/npm-shrinkwrap.json +70 -33
  511. package/package.json +6 -7
  512. package/dist/core/model-routing-task.d.ts.map +0 -1
  513. package/dist/core/model-routing-task.js +0 -120
  514. package/dist/core/model-routing-task.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"engine-dialog-host.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-dialog-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionUIContext } from \"../../core/extensions/index.js\";\nimport type { RpcExtensionUIRequest, RpcExtensionUIResponse } from \"../rpc/rpc-types.ts\";\nimport type { IsolatedInteractiveRuntime } from \"./isolated-runtime.js\";\n\n/** Requests that mount a host dialog and therefore need generation ownership. */\nconst MOUNTING_METHODS: ReadonlySet<string> = new Set([\"select\", \"confirm\", \"input\", \"editor\"]);\n\nasync function handleRequest(\n\tui: ExtensionUIContext,\n\trequest: RpcExtensionUIRequest,\n\tsignal: AbortSignal | undefined,\n): Promise<RpcExtensionUIResponse | undefined> {\n\tswitch (request.method) {\n\t\tcase \"select\": {\n\t\t\tconst value = await ui.select(request.title, request.options, { timeout: request.timeout, signal });\n\t\t\treturn value === undefined\n\t\t\t\t? { type: \"extension_ui_response\", id: request.id, cancelled: true }\n\t\t\t\t: { type: \"extension_ui_response\", id: request.id, value };\n\t\t}\n\t\tcase \"confirm\": {\n\t\t\tconst confirmed = await ui.confirm(request.title, request.message, { timeout: request.timeout, signal });\n\t\t\treturn { type: \"extension_ui_response\", id: request.id, confirmed };\n\t\t}\n\t\tcase \"input\": {\n\t\t\tconst value = await ui.input(request.title, request.placeholder, { timeout: request.timeout, signal });\n\t\t\treturn value === undefined\n\t\t\t\t? { type: \"extension_ui_response\", id: request.id, cancelled: true }\n\t\t\t\t: { type: \"extension_ui_response\", id: request.id, value };\n\t\t}\n\t\tcase \"editor\": {\n\t\t\tconst value = await ui.editor(request.title, request.prefill, { signal });\n\t\t\treturn value === undefined\n\t\t\t\t? { type: \"extension_ui_response\", id: request.id, cancelled: true }\n\t\t\t\t: { type: \"extension_ui_response\", id: request.id, value };\n\t\t}\n\t\tcase \"notify\":\n\t\t\tui.notify(request.message, request.notifyType);\n\t\t\treturn undefined;\n\t\tcase \"setStatus\":\n\t\t\tui.setStatus(request.statusKey, request.statusText);\n\t\t\treturn undefined;\n\t\tcase \"setWidget\":\n\t\t\tui.setWidget(request.widgetKey, request.widgetLines, {\n\t\t\t\tplacement: request.widgetPlacement,\n\t\t\t\t...(request.widgetScroll ? { scroll: request.widgetScroll } : {}),\n\t\t\t});\n\t\t\treturn undefined;\n\t\tcase \"setTitle\":\n\t\t\tui.setTitle(request.title);\n\t\t\treturn undefined;\n\t\tcase \"set_editor_text\":\n\t\t\tui.setEditorText(request.text);\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Generation-owned host dialogs and line widgets for the isolated engine.\n *\n * `select`, `confirm`, `input`, and `editor` mount real host components and can\n * outlive the engine child that asked for them. Without ownership a dead\n * generation left its dialog on screen forever, its host promise unsettled, and\n * could answer through the replacement child's writer. Each request is recorded\n * with the generation that issued it; when that generation ends the mount is\n * aborted — closing only its own instance — and any answer is suppressed.\n *\n * Line widgets (`setWidget` with `string[]`) have the same problem without any\n * component to close: they are plain host state keyed by name, so the key is\n * tracked against its latest writer and released only if that writer's\n * generation is the one that died.\n */\nexport class EngineDialogHostController {\n\tprivate readonly runtime: IsolatedInteractiveRuntime;\n\tprivate readonly ui: ExtensionUIContext;\n\tprivate readonly records = new Map<string, { generation: number; abort: AbortController }>();\n\t/** Line-widget key -> generation that last wrote it. */\n\tprivate readonly widgetOwners = new Map<string, number>();\n\tprivate readonly unsubscribeHandler: () => void;\n\tprivate readonly unsubscribeGenerationEnded: () => void;\n\n\tconstructor(runtime: IsolatedInteractiveRuntime, ui: ExtensionUIContext) {\n\t\tthis.runtime = runtime;\n\t\tthis.ui = ui;\n\t\tthis.unsubscribeHandler = runtime.setExtensionUIHandler((request) => this.handle(request));\n\t\tthis.unsubscribeGenerationEnded = runtime.onGenerationEnded((event) => this.disposeGeneration(event.generation));\n\t}\n\n\tdispose(): void {\n\t\tthis.unsubscribeHandler();\n\t\tthis.unsubscribeGenerationEnded();\n\t\tthis.abortAll();\n\t\tfor (const key of [...this.widgetOwners.keys()]) this.ui.setWidget(key, undefined);\n\t\tthis.widgetOwners.clear();\n\t}\n\n\t/** Close every dialog and release every widget key owned by an ended generation. */\n\tdisposeGeneration(generation: number): void {\n\t\tfor (const [id, record] of [...this.records]) {\n\t\t\tif (record.generation !== generation) continue;\n\t\t\tthis.records.delete(id);\n\t\t\trecord.abort.abort();\n\t\t}\n\t\tfor (const [key, owner] of [...this.widgetOwners]) {\n\t\t\t// A newer generation that rewrote this key owns it now; clearing here\n\t\t\t// would wipe live content the replacement child just published.\n\t\t\tif (owner !== generation) continue;\n\t\t\tthis.widgetOwners.delete(key);\n\t\t\tthis.ui.setWidget(key, undefined);\n\t\t}\n\t}\n\n\tprivate abortAll(): void {\n\t\tfor (const [, record] of [...this.records]) record.abort.abort();\n\t\tthis.records.clear();\n\t}\n\n\tprivate async handle(request: RpcExtensionUIRequest): Promise<RpcExtensionUIResponse | undefined> {\n\t\tif (request.method === \"setWidget\") {\n\t\t\tif (request.widgetLines === undefined) this.widgetOwners.delete(request.widgetKey);\n\t\t\telse this.widgetOwners.set(request.widgetKey, this.runtime.getEngineGeneration());\n\t\t\treturn handleRequest(this.ui, request, undefined);\n\t\t}\n\t\tif (!MOUNTING_METHODS.has(request.method)) return handleRequest(this.ui, request, undefined);\n\t\tconst abort = new AbortController();\n\t\tconst generation = this.runtime.getEngineGeneration();\n\t\tthis.records.set(request.id, { generation, abort });\n\t\tlet response: RpcExtensionUIResponse | undefined;\n\t\ttry {\n\t\t\tresponse = await handleRequest(this.ui, request, abort.signal);\n\t\t} finally {\n\t\t\t// Only the owning record may be removed: a late settle must not delete a\n\t\t\t// newer record that happens to share this id.\n\t\t\tif (this.records.get(request.id)?.abort === abort) this.records.delete(request.id);\n\t\t}\n\t\t// The generation that asked is gone, so the writer now points at a\n\t\t// replacement child. Answering would deliver this reply to the wrong engine.\n\t\tif (abort.signal.aborted) return undefined;\n\t\treturn response;\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-dialog-host.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-dialog-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionUIContext } from \"../../core/extensions/index.js\";\nimport type { RpcExtensionUIRequest, RpcExtensionUIResponse } from \"../rpc/rpc-types.ts\";\nimport type { IsolatedInteractiveRuntime } from \"./isolated-runtime.js\";\n\n/** Requests that mount a host dialog and therefore need generation ownership. */\nconst MOUNTING_METHODS: ReadonlySet<string> = new Set([\"select\", \"confirm\", \"input\", \"editor\"]);\n\nasync function handleRequest(\n\tui: ExtensionUIContext,\n\trequest: RpcExtensionUIRequest,\n\tsignal: AbortSignal | undefined,\n): Promise<RpcExtensionUIResponse | undefined> {\n\tswitch (request.method) {\n\t\tcase \"select\": {\n\t\t\tconst value = await ui.select(request.title, request.options, { timeout: request.timeout, signal });\n\t\t\treturn value === undefined\n\t\t\t\t? { type: \"extension_ui_response\", id: request.id, cancelled: true }\n\t\t\t\t: { type: \"extension_ui_response\", id: request.id, value };\n\t\t}\n\t\tcase \"confirm\": {\n\t\t\tconst confirmed = await ui.confirm(request.title, request.message, { timeout: request.timeout, signal });\n\t\t\treturn { type: \"extension_ui_response\", id: request.id, confirmed };\n\t\t}\n\t\tcase \"input\": {\n\t\t\tconst value = await ui.input(request.title, request.placeholder, { timeout: request.timeout, signal });\n\t\t\treturn value === undefined\n\t\t\t\t? { type: \"extension_ui_response\", id: request.id, cancelled: true }\n\t\t\t\t: { type: \"extension_ui_response\", id: request.id, value };\n\t\t}\n\t\tcase \"editor\": {\n\t\t\tconst value = await ui.editor(request.title, request.prefill, { signal });\n\t\t\treturn value === undefined\n\t\t\t\t? { type: \"extension_ui_response\", id: request.id, cancelled: true }\n\t\t\t\t: { type: \"extension_ui_response\", id: request.id, value };\n\t\t}\n\t\tcase \"notify\":\n\t\t\tui.notify(request.message, request.notifyType);\n\t\t\treturn undefined;\n\t\tcase \"setStatus\":\n\t\t\tui.setStatus(request.statusKey, request.statusText);\n\t\t\treturn undefined;\n\t\tcase \"setWidget\":\n\t\t\tui.setWidget(request.widgetKey, request.widgetLines, {\n\t\t\t\tplacement: request.widgetPlacement,\n\t\t\t\t...(request.widgetScroll ? { scroll: request.widgetScroll } : {}),\n\t\t\t});\n\t\t\treturn undefined;\n\t\tcase \"setTitle\":\n\t\t\tui.setTitle(request.title);\n\t\t\treturn undefined;\n\t\tcase \"set_editor_text\":\n\t\t\tui.setEditorText(request.text);\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Generation-owned host dialogs and line widgets for the isolated engine.\n *\n * `select`, `confirm`, `input`, and `editor` mount real host components and can\n * outlive the engine child that asked for them. Without ownership a dead\n * generation left its dialog on screen forever, its host promise unsettled, and\n * could answer through the replacement child's writer. Each request is recorded\n * with the generation that issued it; when that generation ends the mount is\n * aborted — closing only its own instance — and any answer is suppressed.\n *\n * Line widgets (`setWidget` with `string[]`) have the same problem without any\n * component to close: they are plain host state keyed by name, so the key is\n * tracked against its latest writer and released only if that writer's\n * generation is the one that died.\n */\nexport class EngineDialogHostController {\n\tprivate readonly runtime: IsolatedInteractiveRuntime;\n\tprivate readonly ui: ExtensionUIContext;\n\tprivate readonly records = new Map<string, { generation: number; abort: AbortController }>();\n\t/** Line-widget key -> generation that last wrote it. */\n\tprivate readonly widgetOwners = new Map<string, number>();\n\tprivate readonly unsubscribeHandler: () => void;\n\tprivate readonly unsubscribeGenerationEnded: () => void;\n\n\tconstructor(runtime: IsolatedInteractiveRuntime, ui: ExtensionUIContext) {\n\t\tthis.runtime = runtime;\n\t\tthis.ui = ui;\n\t\tthis.unsubscribeHandler = runtime.setExtensionUIHandler((request) => this.handle(request));\n\t\tthis.unsubscribeGenerationEnded = runtime.onGenerationEnded((event) => this.disposeGeneration(event.generation));\n\t}\n\n\tdispose(): void {\n\t\tthis.unsubscribeHandler();\n\t\tthis.unsubscribeGenerationEnded();\n\t\tthis.abortAll();\n\t\tfor (const key of [...this.widgetOwners.keys()]) this.ui.setWidget(key, undefined);\n\t\tthis.widgetOwners.clear();\n\t}\n\n\t/** Close every dialog and release every widget key owned by an ended generation. */\n\tdisposeGeneration(generation: number): void {\n\t\tfor (const [id, record] of [...this.records]) {\n\t\t\tif (record.generation !== generation) continue;\n\t\t\tthis.records.delete(id);\n\t\t\trecord.abort.abort();\n\t\t}\n\t\tfor (const [key, owner] of [...this.widgetOwners]) {\n\t\t\t// A newer generation that rewrote this key owns it now; clearing here\n\t\t\t// would wipe live content the replacement child just published.\n\t\t\tif (owner !== generation) continue;\n\t\t\tthis.widgetOwners.delete(key);\n\t\t\tthis.ui.setWidget(key, undefined);\n\t\t}\n\t}\n\n\tprivate abortAll(): void {\n\t\tfor (const [, record] of [...this.records]) record.abort.abort();\n\t\tthis.records.clear();\n\t}\n\n\tprivate async handle(request: RpcExtensionUIRequest): Promise<RpcExtensionUIResponse | undefined> {\n\t\tif (request.method === \"setWidget\") {\n\t\t\tif (request.widgetLines === undefined) this.widgetOwners.delete(request.widgetKey);\n\t\t\telse this.widgetOwners.set(request.widgetKey, this.runtime.getEngineGeneration());\n\t\t\treturn handleRequest(this.ui, request, undefined);\n\t\t}\n\t\tif (!MOUNTING_METHODS.has(request.method)) return handleRequest(this.ui, request, undefined);\n\t\tconst abort = new AbortController();\n\t\tconst generation = this.runtime.getEngineGeneration();\n\t\tthis.records.set(request.id, { generation, abort });\n\t\tlet response: RpcExtensionUIResponse | undefined;\n\t\ttry {\n\t\t\tresponse = await handleRequest(this.ui, request, abort.signal);\n\t\t} finally {\n\t\t\t// Only the owning record may be removed: a late settle must not delete a\n\t\t\t// newer record that happens to share this id.\n\t\t\tif (this.records.get(request.id)?.abort === abort) this.records.delete(request.id);\n\t\t}\n\t\t// The generation that asked is gone, so the writer now points at a\n\t\t// replacement child. Answering would deliver this reply to the wrong engine.\n\t\tif (abort.signal.aborted) return undefined;\n\t\treturn response;\n\t}\n}\n"]}
@@ -31,20 +31,30 @@ export function formatUnexpectedEngineLossNotice(event) {
31
31
  * engine's own cooperative abort and waits for it.
32
32
  */
33
33
  export class EngineHealthController {
34
+ deps;
35
+ now;
36
+ listeners = new Set();
37
+ pending = [];
38
+ unresponsive = false;
39
+ abortStartedAt;
40
+ attempt;
41
+ /** When the current replacement attempt began; undefined once it settles. */
42
+ attemptStartedAt;
43
+ attemptId = 0;
44
+ forceStoppedAttemptId;
45
+ rescueRequested = false;
46
+ /**
47
+ * Latched when a replacement failed on its own. Automatic recovery stays
48
+ * single-shot, but the user's Ctrl+C must remain able to try again: without
49
+ * this the host would be left with no engine, no pending attempt, no overdue
50
+ * abort, and no watchdog flag, so nothing could arm the escape hatch.
51
+ */
52
+ replacementNeeded = false;
53
+ termination;
54
+ /** Set once disposal begins; joins the in-flight attempt and termination. */
55
+ shutdownPromise;
56
+ stopped = false;
34
57
  constructor(deps, options) {
35
- this.listeners = new Set();
36
- this.pending = [];
37
- this.unresponsive = false;
38
- this.attemptId = 0;
39
- this.rescueRequested = false;
40
- /**
41
- * Latched when a replacement failed on its own. Automatic recovery stays
42
- * single-shot, but the user's Ctrl+C must remain able to try again: without
43
- * this the host would be left with no engine, no pending attempt, no overdue
44
- * abort, and no watchdog flag, so nothing could arm the escape hatch.
45
- */
46
- this.replacementNeeded = false;
47
- this.stopped = false;
48
58
  this.deps = deps;
49
59
  this.now = options?.now ?? (() => performance.now());
50
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"engine-health.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAcjG,MAAM,CAAC,MAAM,6BAA6B,GAAG,sDAAsD,CAAC;AACpG,MAAM,CAAC,MAAM,0BAA0B,GAAG,mDAAmD,CAAC;AAE9F;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAAC,KAAuC;IACvF,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC1E,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChG,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACpE,OAAO,OAAO;QACb,CAAC,CAAC,GAAG,6BAA6B,WAAW,KAAK,CAAC,IAAI,MAAM,OAAO,GAAG;QACvE,CAAC,CAAC,GAAG,6BAA6B,WAAW,KAAK,CAAC,IAAI,GAAG,CAAC;AAC7D,CAAC;AAOD;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,sBAAsB;IAyBlC,YAAY,IAAsB,EAAE,OAA6B;QAtBhD,cAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;QACzD,YAAO,GAAiC,EAAE,CAAC;QAC3C,iBAAY,GAAG,KAAK,CAAC;QAKrB,cAAS,GAAG,CAAC,CAAC;QAEd,oBAAe,GAAG,KAAK,CAAC;QAChC;;;;;WAKG;QACK,sBAAiB,GAAG,KAAK,CAAC;QAI1B,YAAO,GAAG,KAAK,CAAC;QAGvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,YAAY,CAAC,QAAkC;QAC9C,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QACtE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,6EAA6E;IAC7E,OAAO,CAAC,UAAsC;QAC7C,IAAI,UAAU,CAAC,KAAK,KAAK,cAAc,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU;YAAE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACtG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IAED,kFAAkF;IAClF,iBAAiB;QAChB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED,2BAA2B;QAC1B,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,CAAC;IAED,2BAA2B;QAC1B,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;IACjC,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,wBAAwB;QACvB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,iBAAiB;YAAE,OAAO,IAAI,CAAC;QAC7D,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACrF,CAAC;IAEO,SAAS,CAAC,SAA6B;QAC9C,OAAO,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,sBAAsB,CAAC;IACpF,CAAC;IAED,YAAY;QACX,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC;IACrE,CAAC;IAED;;;;;;;OAOG;IACH,QAAQ;QACP,IAAI,IAAI,CAAC,eAAe;YAAE,OAAO,IAAI,CAAC,eAAe,CAAC;QACtD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,CAAC,KAAK,IAAI,EAAE;YAClC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACpC,MAAM,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAED,qBAAqB,CAAC,KAAuC;QAC5D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAC3C,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,yEAAyE;YACzE,yEAAyE;YACzE,wEAAwE;YACxE,4CAA4C;YAC5C,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAC9B,OAAO;QACR,CAAC;QACD,KAAK,IAAI,CAAC,OAAO,CAAC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,SAAS;QACR,sEAAsE;QACtE,0EAA0E;QAC1E,2EAA2E;QAC3E,uBAAuB;QACvB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,WAAW,CAAC;QACzB,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9B,6EAA6E;QAC7E,wDAAwD;QACxD,IAAI,QAAQ;YAAE,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1D,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;YACxC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,0EAA0E;YAC1E,qCAAqC;YACrC,IAAI,QAAQ;gBAAE,MAAM,QAAQ,CAAC;YAC7B,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC9B,yEAAyE;YACzE,sEAAsE;YACtE,OAAO,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC9C,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;gBACxC,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YACjB,IAAI,IAAI,CAAC,WAAW,KAAK,GAAG;gBAAE,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;QACvB,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,mEAAmE;IAC3D,oBAAoB;QAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC;YAAE,OAAO,KAAK,CAAC;QACzD,IAAI,IAAI,CAAC,qBAAqB,KAAK,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAChE,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC;QAC5C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,WAAW;QACxB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACR,qEAAqE;YACrE,mDAAmD;QACpD,CAAC;IACF,CAAC;IAEO,OAAO,CAAC,MAA0B;QACzC,0EAA0E;QAC1E,yCAAyC;QACzC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QACtC,IAAI,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,uEAAuE;QACvE,yEAAyE;QACzE,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,0EAA0E;QAC1E,uEAAuE;QACvE,2EAA2E;QAC3E,4EAA4E;QAC5E,uEAAuE;QACvE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;aACnB,OAAO,EAAE;aACT,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;YACvB,gEAAgE;YAChE,qCAAqC;YACrC,IAAI,IAAI,CAAC,qBAAqB,KAAK,EAAE,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO;YAC9D,qEAAqE;YACrE,gEAAgE;YAChE,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAC9B,mEAAmE;YACnE,IAAI,CAAC,OAAO,CAAC;gBACZ,QAAQ,EAAE,SAAS;gBACnB,SAAS,EAAE,CAAC;gBACZ,KAAK,EAAE,cAAc;gBACrB,OAAO,EAAE,sCAAsC,KAAK,CAAC,OAAO,EAAE;aAC9D,CAAC,CAAC;QACJ,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACb,IAAI,IAAI,CAAC,OAAO,KAAK,GAAG;gBAAE,OAAO;YACjC,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YACzB,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACnC,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,OAAO,GAAG,CAAC;IACZ,CAAC;IAEO,MAAM,CAAC,OAAe;QAC7B,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACrG,CAAC;IAEO,OAAO,CAAC,UAAsC;QACrD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7D,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7D,CAAC;CACD","sourcesContent":["import { type ActivityWatchdogDiagnostic, ENGINE_UNRESPONSIVE_MS } from \"./activity-watchdog.ts\";\nimport type { InteractiveEngineGenerationEnded } from \"./engine-generation.ts\";\n\nexport type EngineDiagnosticListener = (diagnostic: ActivityWatchdogDiagnostic) => void;\n\nexport interface EngineHealthDeps {\n\t/** Terminate the current (or hung replacement) engine child. */\n\tstop(): Promise<void>;\n\t/** Replace the engine child and reload host state from it. */\n\trestart(): Promise<void>;\n\t/** Drop streaming/compaction/callback activity owned by the dead generation. */\n\tclearActivity(): void;\n}\n\nexport const UNEXPECTED_ENGINE_LOSS_NOTICE = \"Interactive engine stopped unexpectedly; restarting.\";\nexport const UNRESPONSIVE_ENGINE_NOTICE = \"Interactive engine is not responding; restarting.\";\n\n/**\n * Keep the actionable transport cause in the recovery notice. Child stderr can\n * contain provider output or secrets, so only the bounded summary before the\n * RpcClient's `. Stderr:` suffix is safe to render.\n */\nexport function formatUnexpectedEngineLossNotice(event: InteractiveEngineGenerationEnded): string {\n\tconst firstLine = event.error.message.split(/\\r?\\n/u, 1)[0]?.trim() ?? \"\";\n\tconst stderrIndex = firstLine.indexOf(\". Stderr:\");\n\tconst withoutStderr = (stderrIndex === -1 ? firstLine : firstLine.slice(0, stderrIndex)).trim();\n\tconst summary = withoutStderr.slice(0, 240).replace(/[.!?]+$/u, \"\");\n\treturn summary\n\t\t? `${UNEXPECTED_ENGINE_LOSS_NOTICE} Cause (${event.kind}): ${summary}.`\n\t\t: `${UNEXPECTED_ENGINE_LOSS_NOTICE} Cause: ${event.kind}.`;\n}\n\nexport interface EngineHealthOptions {\n\t/** Injectable clock so tests can cross the unresponsive threshold instantly. */\n\tnow?: () => number;\n}\n\n/**\n * Engine health surface: diagnostic fan-out plus single-flight recovery.\n *\n * Recovery has exactly two entry points, deliberately separate:\n *\n * - {@link handleGenerationEnded} runs ONE automatic replacement attempt after\n * an unexpected loss of a generation. Expected losses (explicit stop,\n * deliberate generation replacement, host shutdown) never restart.\n * - {@link terminate} is the explicit user escape hatch (Ctrl+C). It force-stops\n * first, so it can rescue a replacement child that is hung waiting for\n * readiness instead of joining that pending promise.\n *\n * Neither path is reachable from an interrupt: pressing Escape only requests the\n * engine's own cooperative abort and waits for it.\n */\nexport class EngineHealthController {\n\tprivate readonly deps: EngineHealthDeps;\n\tprivate readonly now: () => number;\n\tprivate readonly listeners = new Set<EngineDiagnosticListener>();\n\tprivate pending: ActivityWatchdogDiagnostic[] = [];\n\tprivate unresponsive = false;\n\tprivate abortStartedAt: number | undefined;\n\tprivate attempt: Promise<void> | undefined;\n\t/** When the current replacement attempt began; undefined once it settles. */\n\tprivate attemptStartedAt: number | undefined;\n\tprivate attemptId = 0;\n\tprivate forceStoppedAttemptId: number | undefined;\n\tprivate rescueRequested = false;\n\t/**\n\t * Latched when a replacement failed on its own. Automatic recovery stays\n\t * single-shot, but the user's Ctrl+C must remain able to try again: without\n\t * this the host would be left with no engine, no pending attempt, no overdue\n\t * abort, and no watchdog flag, so nothing could arm the escape hatch.\n\t */\n\tprivate replacementNeeded = false;\n\tprivate termination: Promise<void> | undefined;\n\t/** Set once disposal begins; joins the in-flight attempt and termination. */\n\tprivate shutdownPromise: Promise<void> | undefined;\n\tprivate stopped = false;\n\n\tconstructor(deps: EngineHealthDeps, options?: EngineHealthOptions) {\n\t\tthis.deps = deps;\n\t\tthis.now = options?.now ?? (() => performance.now());\n\t}\n\n\tonDiagnostic(listener: EngineDiagnosticListener): () => void {\n\t\tfor (const diagnostic of this.pending.splice(0)) listener(diagnostic);\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/** Publish a diagnostic produced elsewhere (watchdog, transport, bridge). */\n\tpublish(diagnostic: ActivityWatchdogDiagnostic): void {\n\t\tif (diagnostic.level === \"unresponsive\" && diagnostic.source === \"watchdog\") this.unresponsive = true;\n\t\tthis.deliver(diagnostic);\n\t}\n\n\t/** A heartbeat proves the child's loop turns again, so clear a reported stall. */\n\tclearUnresponsive(): void {\n\t\tthis.unresponsive = false;\n\t}\n\n\tmarkCooperativeAbortStarted(): void {\n\t\tthis.abortStartedAt ??= this.now();\n\t}\n\n\tmarkCooperativeAbortSettled(): void {\n\t\tthis.abortStartedAt = undefined;\n\t}\n\n\t/**\n\t * True only when the engine is provably not answering:\n\t *\n\t * - the heartbeat watchdog declared it unresponsive;\n\t * - a replacement failed on its own and the host has no engine;\n\t * - a cooperative abort has been outstanding past the unresponsive threshold\n\t * (a child whose loop still turns but is deadlocked);\n\t * - a replacement has been waiting for `engine_ready` past that threshold.\n\t *\n\t * The readiness case has no watchdog coverage at all: a child stopped before\n\t * readiness emits no heartbeat and no diagnostic, and `start()` waits without\n\t * a deadline by design. Crossing a threshold arms nothing on its own — it\n\t * only decides whether a deliberate Ctrl+C escalates — and all of this stays\n\t * false for a healthy engine so a stray second Ctrl+C cannot replace one.\n\t */\n\tneedsExplicitTermination(): boolean {\n\t\tif (this.unresponsive || this.replacementNeeded) return true;\n\t\treturn this.isOverdue(this.abortStartedAt) || this.isOverdue(this.attemptStartedAt);\n\t}\n\n\tprivate isOverdue(startedAt: number | undefined): boolean {\n\t\treturn startedAt !== undefined && this.now() - startedAt >= ENGINE_UNRESPONSIVE_MS;\n\t}\n\n\tisRecovering(): boolean {\n\t\treturn this.attempt !== undefined || this.termination !== undefined;\n\t}\n\n\t/**\n\t * Stop accepting recovery work and join whatever is still running.\n\t *\n\t * Disposal must not return while a replacement is between its own stop and\n\t * its spawn: the client's restart permit is voided by `deps.stop()`, and the\n\t * attempt is then awaited so no child, and no host initialization, outlives\n\t * teardown. Idempotent, and bounded by the client's own stop deadlines.\n\t */\n\tshutdown(): Promise<void> {\n\t\tif (this.shutdownPromise) return this.shutdownPromise;\n\t\tthis.stopped = true;\n\t\tthis.rescueRequested = false;\n\t\tthis.replacementNeeded = false;\n\t\tthis.shutdownPromise = (async () => {\n\t\t\tawait this.stopQuietly();\n\t\t\tawait this.attempt?.catch(() => {});\n\t\t\tawait this.termination?.catch(() => {});\n\t\t})();\n\t\treturn this.shutdownPromise;\n\t}\n\n\thandleGenerationEnded(event: InteractiveEngineGenerationEnded): void {\n\t\tthis.deps.clearActivity();\n\t\tif (event.expected || this.stopped) return;\n\t\tif (this.attempt) {\n\t\t\t// A newer child died while the replacement attempt was still running, so\n\t\t\t// that attempt cannot leave a viable generation behind. Latch instead of\n\t\t\t// restarting again: automatic recovery stays single-shot, and Ctrl+C is\n\t\t\t// armed once the in-flight attempt settles.\n\t\t\tthis.replacementNeeded = true;\n\t\t\treturn;\n\t\t}\n\t\tvoid this.recover(formatUnexpectedEngineLossNotice(event)).catch(() => {});\n\t}\n\n\tterminate(): Promise<void> {\n\t\t// A repeat Ctrl+C must be able to rescue a replacement that is itself\n\t\t// overdue, instead of joining the in-flight termination forever. The stop\n\t\t// is fenced by attempt id so repeated presses cannot stack restarts onto a\n\t\t// healthy replacement.\n\t\tif (this.termination) {\n\t\t\tthis.rescueOverdueAttempt();\n\t\t\treturn this.termination;\n\t\t}\n\t\tconst inFlight = this.attempt;\n\t\t// The attempt this press supersedes fails by our own hand, so its failure is\n\t\t// expected rather than something to report to the user.\n\t\tif (inFlight) this.forceStoppedAttemptId = this.attemptId;\n\t\tconst run = (async () => {\n\t\t\tthis.deps.clearActivity();\n\t\t\tthis.notice(UNRESPONSIVE_ENGINE_NOTICE);\n\t\t\tawait this.stopQuietly();\n\t\t\t// An automatic attempt swallows its own errors, so this only waits for it\n\t\t\t// to release the single-flight slot.\n\t\t\tif (inFlight) await inFlight;\n\t\t\tawait this.recover(undefined);\n\t\t\t// Each user-forced stop of an overdue replacement earns exactly one more\n\t\t\t// replacement attempt, so the escape hatch stays usable indefinitely.\n\t\t\twhile (this.rescueRequested && !this.stopped) {\n\t\t\t\tthis.rescueRequested = false;\n\t\t\t\tthis.notice(UNRESPONSIVE_ENGINE_NOTICE);\n\t\t\t\tawait this.recover(undefined);\n\t\t\t}\n\t\t})().finally(() => {\n\t\t\tif (this.termination === run) this.termination = undefined;\n\t\t});\n\t\tthis.termination = run;\n\t\treturn run;\n\t}\n\n\t/** Force-stop an overdue replacement, at most once per attempt. */\n\tprivate rescueOverdueAttempt(): boolean {\n\t\tif (!this.isOverdue(this.attemptStartedAt)) return false;\n\t\tif (this.forceStoppedAttemptId === this.attemptId) return false;\n\t\tthis.forceStoppedAttemptId = this.attemptId;\n\t\tthis.rescueRequested = true;\n\t\tvoid this.stopQuietly();\n\t\treturn true;\n\t}\n\n\tprivate async stopQuietly(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.deps.stop();\n\t\t} catch {\n\t\t\t// A stop failure must not strand the escape hatch: the restart still\n\t\t\t// replaces the child and reports any real failure.\n\t\t}\n\t}\n\n\tprivate recover(notice: string | undefined): Promise<void> {\n\t\t// Order matters: after shutdown no caller may join, or revive, an attempt\n\t\t// that still happens to occupy the slot.\n\t\tif (this.stopped) return Promise.resolve();\n\t\tif (this.attempt) return this.attempt;\n\t\tif (notice) this.notice(notice);\n\t\tthis.attemptId += 1;\n\t\tconst id = this.attemptId;\n\t\tthis.attemptStartedAt = this.now();\n\t\tthis.rescueRequested = false;\n\t\t// A new attempt is under way, so the previous failure is no longer the\n\t\t// reason to arm Ctrl+C. It re-arms below only if this attempt fails too.\n\t\tthis.replacementNeeded = false;\n\t\t// The watchdog verdict belonged to the generation being replaced. A fresh\n\t\t// child emits no heartbeat until it is ready, so leaving the latch set\n\t\t// would keep `needsExplicitTermination()` true through the whole pre-ready\n\t\t// window and let the first Ctrl+C stop a replacement that never misbehaved.\n\t\t// Only this child's own heartbeat, or its own stall, may set it again.\n\t\tthis.unresponsive = false;\n\t\tconst run = this.deps\n\t\t\t.restart()\n\t\t\t.catch((error: Error) => {\n\t\t\t\t// An attempt the user deliberately stopped, or one cancelled by\n\t\t\t\t// disposal, did not fail on its own.\n\t\t\t\tif (this.forceStoppedAttemptId === id || this.stopped) return;\n\t\t\t\t// Keep Ctrl+C armed: automatic recovery is single-shot, but the user\n\t\t\t\t// must be able to ask for another attempt after a real failure.\n\t\t\t\tthis.replacementNeeded = true;\n\t\t\t\t// A concrete failure, so no operational source: this one surfaces.\n\t\t\t\tthis.deliver({\n\t\t\t\t\tactivity: undefined,\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\tlevel: \"unresponsive\",\n\t\t\t\t\tmessage: `Interactive engine restart failed: ${error.message}`,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (this.attempt !== run) return;\n\t\t\t\tthis.attempt = undefined;\n\t\t\t\tthis.attemptStartedAt = undefined;\n\t\t\t});\n\t\tthis.attempt = run;\n\t\treturn run;\n\t}\n\n\tprivate notice(message: string): void {\n\t\tthis.deliver({ activity: undefined, elapsedMs: 0, level: \"blocking\", message, source: \"recovery\" });\n\t}\n\n\tprivate deliver(diagnostic: ActivityWatchdogDiagnostic): void {\n\t\tif (this.listeners.size === 0) this.pending.push(diagnostic);\n\t\tfor (const listener of this.listeners) listener(diagnostic);\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-health.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAcjG,MAAM,CAAC,MAAM,6BAA6B,GAAG,sDAAsD,CAAC;AACpG,MAAM,CAAC,MAAM,0BAA0B,GAAG,mDAAmD,CAAC;AAE9F;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAAC,KAAuC;IACvF,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC1E,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChG,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACpE,OAAO,OAAO;QACb,CAAC,CAAC,GAAG,6BAA6B,WAAW,KAAK,CAAC,IAAI,MAAM,OAAO,GAAG;QACvE,CAAC,CAAC,GAAG,6BAA6B,WAAW,KAAK,CAAC,IAAI,GAAG,CAAC;AAC7D,CAAC;AAOD;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,sBAAsB;IACjB,IAAI,CAAmB;IACvB,GAAG,CAAe;IAClB,SAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;IACzD,OAAO,GAAiC,EAAE,CAAC;IAC3C,YAAY,GAAG,KAAK,CAAC;IACrB,cAAc,CAAqB;IACnC,OAAO,CAA4B;IAC3C,6EAA6E;IACrE,gBAAgB,CAAqB;IACrC,SAAS,GAAG,CAAC,CAAC;IACd,qBAAqB,CAAqB;IAC1C,eAAe,GAAG,KAAK,CAAC;IAChC;;;;;OAKG;IACK,iBAAiB,GAAG,KAAK,CAAC;IAC1B,WAAW,CAA4B;IAC/C,6EAA6E;IACrE,eAAe,CAA4B;IAC3C,OAAO,GAAG,KAAK,CAAC;IAExB,YAAY,IAAsB,EAAE,OAA6B;QAChE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,YAAY,CAAC,QAAkC;QAC9C,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QACtE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,6EAA6E;IAC7E,OAAO,CAAC,UAAsC;QAC7C,IAAI,UAAU,CAAC,KAAK,KAAK,cAAc,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU;YAAE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACtG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IAED,kFAAkF;IAClF,iBAAiB;QAChB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED,2BAA2B;QAC1B,IAAI,CAAC,cAAc,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,CAAC;IAED,2BAA2B;QAC1B,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;IACjC,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,wBAAwB;QACvB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,iBAAiB;YAAE,OAAO,IAAI,CAAC;QAC7D,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACrF,CAAC;IAEO,SAAS,CAAC,SAA6B;QAC9C,OAAO,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,sBAAsB,CAAC;IACpF,CAAC;IAED,YAAY;QACX,OAAO,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC;IACrE,CAAC;IAED;;;;;;;OAOG;IACH,QAAQ;QACP,IAAI,IAAI,CAAC,eAAe;YAAE,OAAO,IAAI,CAAC,eAAe,CAAC;QACtD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,IAAI,CAAC,eAAe,GAAG,CAAC,KAAK,IAAI,EAAE;YAClC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACpC,MAAM,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzC,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAED,qBAAqB,CAAC,KAAuC;QAC5D,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAC3C,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,yEAAyE;YACzE,yEAAyE;YACzE,wEAAwE;YACxE,4CAA4C;YAC5C,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAC9B,OAAO;QACR,CAAC;QACD,KAAK,IAAI,CAAC,OAAO,CAAC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,SAAS;QACR,sEAAsE;QACtE,0EAA0E;QAC1E,2EAA2E;QAC3E,uBAAuB;QACvB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,WAAW,CAAC;QACzB,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;QAC9B,6EAA6E;QAC7E,wDAAwD;QACxD,IAAI,QAAQ;YAAE,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1D,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE;YACvB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;YACxC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACzB,0EAA0E;YAC1E,qCAAqC;YACrC,IAAI,QAAQ;gBAAE,MAAM,QAAQ,CAAC;YAC7B,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC9B,yEAAyE;YACzE,sEAAsE;YACtE,OAAO,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC9C,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;gBACxC,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC/B,CAAC;QACF,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YACjB,IAAI,IAAI,CAAC,WAAW,KAAK,GAAG;gBAAE,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;QACvB,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,mEAAmE;IAC3D,oBAAoB;QAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC;YAAE,OAAO,KAAK,CAAC;QACzD,IAAI,IAAI,CAAC,qBAAqB,KAAK,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAChE,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,SAAS,CAAC;QAC5C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,WAAW;QACxB,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACR,qEAAqE;YACrE,mDAAmD;QACpD,CAAC;IACF,CAAC;IAEO,OAAO,CAAC,MAA0B;QACzC,0EAA0E;QAC1E,yCAAyC;QACzC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3C,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QACtC,IAAI,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACpB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,uEAAuE;QACvE,yEAAyE;QACzE,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;QAC/B,0EAA0E;QAC1E,uEAAuE;QACvE,2EAA2E;QAC3E,4EAA4E;QAC5E,uEAAuE;QACvE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;aACnB,OAAO,EAAE;aACT,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;YACvB,gEAAgE;YAChE,qCAAqC;YACrC,IAAI,IAAI,CAAC,qBAAqB,KAAK,EAAE,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO;YAC9D,qEAAqE;YACrE,gEAAgE;YAChE,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;YAC9B,mEAAmE;YACnE,IAAI,CAAC,OAAO,CAAC;gBACZ,QAAQ,EAAE,SAAS;gBACnB,SAAS,EAAE,CAAC;gBACZ,KAAK,EAAE,cAAc;gBACrB,OAAO,EAAE,sCAAsC,KAAK,CAAC,OAAO,EAAE;aAC9D,CAAC,CAAC;QACJ,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACb,IAAI,IAAI,CAAC,OAAO,KAAK,GAAG;gBAAE,OAAO;YACjC,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YACzB,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACnC,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,OAAO,GAAG,CAAC;IACZ,CAAC;IAEO,MAAM,CAAC,OAAe;QAC7B,IAAI,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACrG,CAAC;IAEO,OAAO,CAAC,UAAsC;QACrD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7D,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7D,CAAC;CACD","sourcesContent":["import { type ActivityWatchdogDiagnostic, ENGINE_UNRESPONSIVE_MS } from \"./activity-watchdog.ts\";\nimport type { InteractiveEngineGenerationEnded } from \"./engine-generation.ts\";\n\nexport type EngineDiagnosticListener = (diagnostic: ActivityWatchdogDiagnostic) => void;\n\nexport interface EngineHealthDeps {\n\t/** Terminate the current (or hung replacement) engine child. */\n\tstop(): Promise<void>;\n\t/** Replace the engine child and reload host state from it. */\n\trestart(): Promise<void>;\n\t/** Drop streaming/compaction/callback activity owned by the dead generation. */\n\tclearActivity(): void;\n}\n\nexport const UNEXPECTED_ENGINE_LOSS_NOTICE = \"Interactive engine stopped unexpectedly; restarting.\";\nexport const UNRESPONSIVE_ENGINE_NOTICE = \"Interactive engine is not responding; restarting.\";\n\n/**\n * Keep the actionable transport cause in the recovery notice. Child stderr can\n * contain provider output or secrets, so only the bounded summary before the\n * RpcClient's `. Stderr:` suffix is safe to render.\n */\nexport function formatUnexpectedEngineLossNotice(event: InteractiveEngineGenerationEnded): string {\n\tconst firstLine = event.error.message.split(/\\r?\\n/u, 1)[0]?.trim() ?? \"\";\n\tconst stderrIndex = firstLine.indexOf(\". Stderr:\");\n\tconst withoutStderr = (stderrIndex === -1 ? firstLine : firstLine.slice(0, stderrIndex)).trim();\n\tconst summary = withoutStderr.slice(0, 240).replace(/[.!?]+$/u, \"\");\n\treturn summary\n\t\t? `${UNEXPECTED_ENGINE_LOSS_NOTICE} Cause (${event.kind}): ${summary}.`\n\t\t: `${UNEXPECTED_ENGINE_LOSS_NOTICE} Cause: ${event.kind}.`;\n}\n\nexport interface EngineHealthOptions {\n\t/** Injectable clock so tests can cross the unresponsive threshold instantly. */\n\tnow?: () => number;\n}\n\n/**\n * Engine health surface: diagnostic fan-out plus single-flight recovery.\n *\n * Recovery has exactly two entry points, deliberately separate:\n *\n * - {@link handleGenerationEnded} runs ONE automatic replacement attempt after\n * an unexpected loss of a generation. Expected losses (explicit stop,\n * deliberate generation replacement, host shutdown) never restart.\n * - {@link terminate} is the explicit user escape hatch (Ctrl+C). It force-stops\n * first, so it can rescue a replacement child that is hung waiting for\n * readiness instead of joining that pending promise.\n *\n * Neither path is reachable from an interrupt: pressing Escape only requests the\n * engine's own cooperative abort and waits for it.\n */\nexport class EngineHealthController {\n\tprivate readonly deps: EngineHealthDeps;\n\tprivate readonly now: () => number;\n\tprivate readonly listeners = new Set<EngineDiagnosticListener>();\n\tprivate pending: ActivityWatchdogDiagnostic[] = [];\n\tprivate unresponsive = false;\n\tprivate abortStartedAt: number | undefined;\n\tprivate attempt: Promise<void> | undefined;\n\t/** When the current replacement attempt began; undefined once it settles. */\n\tprivate attemptStartedAt: number | undefined;\n\tprivate attemptId = 0;\n\tprivate forceStoppedAttemptId: number | undefined;\n\tprivate rescueRequested = false;\n\t/**\n\t * Latched when a replacement failed on its own. Automatic recovery stays\n\t * single-shot, but the user's Ctrl+C must remain able to try again: without\n\t * this the host would be left with no engine, no pending attempt, no overdue\n\t * abort, and no watchdog flag, so nothing could arm the escape hatch.\n\t */\n\tprivate replacementNeeded = false;\n\tprivate termination: Promise<void> | undefined;\n\t/** Set once disposal begins; joins the in-flight attempt and termination. */\n\tprivate shutdownPromise: Promise<void> | undefined;\n\tprivate stopped = false;\n\n\tconstructor(deps: EngineHealthDeps, options?: EngineHealthOptions) {\n\t\tthis.deps = deps;\n\t\tthis.now = options?.now ?? (() => performance.now());\n\t}\n\n\tonDiagnostic(listener: EngineDiagnosticListener): () => void {\n\t\tfor (const diagnostic of this.pending.splice(0)) listener(diagnostic);\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/** Publish a diagnostic produced elsewhere (watchdog, transport, bridge). */\n\tpublish(diagnostic: ActivityWatchdogDiagnostic): void {\n\t\tif (diagnostic.level === \"unresponsive\" && diagnostic.source === \"watchdog\") this.unresponsive = true;\n\t\tthis.deliver(diagnostic);\n\t}\n\n\t/** A heartbeat proves the child's loop turns again, so clear a reported stall. */\n\tclearUnresponsive(): void {\n\t\tthis.unresponsive = false;\n\t}\n\n\tmarkCooperativeAbortStarted(): void {\n\t\tthis.abortStartedAt ??= this.now();\n\t}\n\n\tmarkCooperativeAbortSettled(): void {\n\t\tthis.abortStartedAt = undefined;\n\t}\n\n\t/**\n\t * True only when the engine is provably not answering:\n\t *\n\t * - the heartbeat watchdog declared it unresponsive;\n\t * - a replacement failed on its own and the host has no engine;\n\t * - a cooperative abort has been outstanding past the unresponsive threshold\n\t * (a child whose loop still turns but is deadlocked);\n\t * - a replacement has been waiting for `engine_ready` past that threshold.\n\t *\n\t * The readiness case has no watchdog coverage at all: a child stopped before\n\t * readiness emits no heartbeat and no diagnostic, and `start()` waits without\n\t * a deadline by design. Crossing a threshold arms nothing on its own — it\n\t * only decides whether a deliberate Ctrl+C escalates — and all of this stays\n\t * false for a healthy engine so a stray second Ctrl+C cannot replace one.\n\t */\n\tneedsExplicitTermination(): boolean {\n\t\tif (this.unresponsive || this.replacementNeeded) return true;\n\t\treturn this.isOverdue(this.abortStartedAt) || this.isOverdue(this.attemptStartedAt);\n\t}\n\n\tprivate isOverdue(startedAt: number | undefined): boolean {\n\t\treturn startedAt !== undefined && this.now() - startedAt >= ENGINE_UNRESPONSIVE_MS;\n\t}\n\n\tisRecovering(): boolean {\n\t\treturn this.attempt !== undefined || this.termination !== undefined;\n\t}\n\n\t/**\n\t * Stop accepting recovery work and join whatever is still running.\n\t *\n\t * Disposal must not return while a replacement is between its own stop and\n\t * its spawn: the client's restart permit is voided by `deps.stop()`, and the\n\t * attempt is then awaited so no child, and no host initialization, outlives\n\t * teardown. Idempotent, and bounded by the client's own stop deadlines.\n\t */\n\tshutdown(): Promise<void> {\n\t\tif (this.shutdownPromise) return this.shutdownPromise;\n\t\tthis.stopped = true;\n\t\tthis.rescueRequested = false;\n\t\tthis.replacementNeeded = false;\n\t\tthis.shutdownPromise = (async () => {\n\t\t\tawait this.stopQuietly();\n\t\t\tawait this.attempt?.catch(() => {});\n\t\t\tawait this.termination?.catch(() => {});\n\t\t})();\n\t\treturn this.shutdownPromise;\n\t}\n\n\thandleGenerationEnded(event: InteractiveEngineGenerationEnded): void {\n\t\tthis.deps.clearActivity();\n\t\tif (event.expected || this.stopped) return;\n\t\tif (this.attempt) {\n\t\t\t// A newer child died while the replacement attempt was still running, so\n\t\t\t// that attempt cannot leave a viable generation behind. Latch instead of\n\t\t\t// restarting again: automatic recovery stays single-shot, and Ctrl+C is\n\t\t\t// armed once the in-flight attempt settles.\n\t\t\tthis.replacementNeeded = true;\n\t\t\treturn;\n\t\t}\n\t\tvoid this.recover(formatUnexpectedEngineLossNotice(event)).catch(() => {});\n\t}\n\n\tterminate(): Promise<void> {\n\t\t// A repeat Ctrl+C must be able to rescue a replacement that is itself\n\t\t// overdue, instead of joining the in-flight termination forever. The stop\n\t\t// is fenced by attempt id so repeated presses cannot stack restarts onto a\n\t\t// healthy replacement.\n\t\tif (this.termination) {\n\t\t\tthis.rescueOverdueAttempt();\n\t\t\treturn this.termination;\n\t\t}\n\t\tconst inFlight = this.attempt;\n\t\t// The attempt this press supersedes fails by our own hand, so its failure is\n\t\t// expected rather than something to report to the user.\n\t\tif (inFlight) this.forceStoppedAttemptId = this.attemptId;\n\t\tconst run = (async () => {\n\t\t\tthis.deps.clearActivity();\n\t\t\tthis.notice(UNRESPONSIVE_ENGINE_NOTICE);\n\t\t\tawait this.stopQuietly();\n\t\t\t// An automatic attempt swallows its own errors, so this only waits for it\n\t\t\t// to release the single-flight slot.\n\t\t\tif (inFlight) await inFlight;\n\t\t\tawait this.recover(undefined);\n\t\t\t// Each user-forced stop of an overdue replacement earns exactly one more\n\t\t\t// replacement attempt, so the escape hatch stays usable indefinitely.\n\t\t\twhile (this.rescueRequested && !this.stopped) {\n\t\t\t\tthis.rescueRequested = false;\n\t\t\t\tthis.notice(UNRESPONSIVE_ENGINE_NOTICE);\n\t\t\t\tawait this.recover(undefined);\n\t\t\t}\n\t\t})().finally(() => {\n\t\t\tif (this.termination === run) this.termination = undefined;\n\t\t});\n\t\tthis.termination = run;\n\t\treturn run;\n\t}\n\n\t/** Force-stop an overdue replacement, at most once per attempt. */\n\tprivate rescueOverdueAttempt(): boolean {\n\t\tif (!this.isOverdue(this.attemptStartedAt)) return false;\n\t\tif (this.forceStoppedAttemptId === this.attemptId) return false;\n\t\tthis.forceStoppedAttemptId = this.attemptId;\n\t\tthis.rescueRequested = true;\n\t\tvoid this.stopQuietly();\n\t\treturn true;\n\t}\n\n\tprivate async stopQuietly(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.deps.stop();\n\t\t} catch {\n\t\t\t// A stop failure must not strand the escape hatch: the restart still\n\t\t\t// replaces the child and reports any real failure.\n\t\t}\n\t}\n\n\tprivate recover(notice: string | undefined): Promise<void> {\n\t\t// Order matters: after shutdown no caller may join, or revive, an attempt\n\t\t// that still happens to occupy the slot.\n\t\tif (this.stopped) return Promise.resolve();\n\t\tif (this.attempt) return this.attempt;\n\t\tif (notice) this.notice(notice);\n\t\tthis.attemptId += 1;\n\t\tconst id = this.attemptId;\n\t\tthis.attemptStartedAt = this.now();\n\t\tthis.rescueRequested = false;\n\t\t// A new attempt is under way, so the previous failure is no longer the\n\t\t// reason to arm Ctrl+C. It re-arms below only if this attempt fails too.\n\t\tthis.replacementNeeded = false;\n\t\t// The watchdog verdict belonged to the generation being replaced. A fresh\n\t\t// child emits no heartbeat until it is ready, so leaving the latch set\n\t\t// would keep `needsExplicitTermination()` true through the whole pre-ready\n\t\t// window and let the first Ctrl+C stop a replacement that never misbehaved.\n\t\t// Only this child's own heartbeat, or its own stall, may set it again.\n\t\tthis.unresponsive = false;\n\t\tconst run = this.deps\n\t\t\t.restart()\n\t\t\t.catch((error: Error) => {\n\t\t\t\t// An attempt the user deliberately stopped, or one cancelled by\n\t\t\t\t// disposal, did not fail on its own.\n\t\t\t\tif (this.forceStoppedAttemptId === id || this.stopped) return;\n\t\t\t\t// Keep Ctrl+C armed: automatic recovery is single-shot, but the user\n\t\t\t\t// must be able to ask for another attempt after a real failure.\n\t\t\t\tthis.replacementNeeded = true;\n\t\t\t\t// A concrete failure, so no operational source: this one surfaces.\n\t\t\t\tthis.deliver({\n\t\t\t\t\tactivity: undefined,\n\t\t\t\t\telapsedMs: 0,\n\t\t\t\t\tlevel: \"unresponsive\",\n\t\t\t\t\tmessage: `Interactive engine restart failed: ${error.message}`,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (this.attempt !== run) return;\n\t\t\t\tthis.attempt = undefined;\n\t\t\t\tthis.attemptStartedAt = undefined;\n\t\t\t});\n\t\tthis.attempt = run;\n\t\treturn run;\n\t}\n\n\tprivate notice(message: string): void {\n\t\tthis.deliver({ activity: undefined, elapsedMs: 0, level: \"blocking\", message, source: \"recovery\" });\n\t}\n\n\tprivate deliver(diagnostic: ActivityWatchdogDiagnostic): void {\n\t\tif (this.listeners.size === 0) this.pending.push(diagnostic);\n\t\tfor (const listener of this.listeners) listener(diagnostic);\n\t}\n}\n"]}
@@ -1,9 +1,10 @@
1
1
  import { parseInteractiveEngineCommand, serializeInteractiveEngineMessage, } from "./protocol.js";
2
2
  /** Child-side owner for host-native input forms. */
3
3
  export class EngineInputFormService {
4
+ active = new Map();
5
+ write;
6
+ nextId = 0;
4
7
  constructor(write) {
5
- this.active = new Map();
6
- this.nextId = 0;
7
8
  this.write = write;
8
9
  }
9
10
  open(request, signal) {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-input-form.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-input-form.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HostInputFormRequest } from \"../../core/extensions/ui-types.js\";\nimport {\n\ttype InteractiveEngineMessage,\n\tparseInteractiveEngineCommand,\n\tserializeInteractiveEngineMessage,\n} from \"./protocol.ts\";\n\ninterface ActiveForm {\n\tsettled: boolean;\n\tresolve: (values: Record<string, string> | undefined) => void;\n}\n\n/** Child-side owner for host-native input forms. */\nexport class EngineInputFormService {\n\tprivate readonly active = new Map<string, ActiveForm>();\n\tprivate readonly write: (line: string) => void;\n\tprivate nextId = 0;\n\tconstructor(write: (line: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\topen(request: HostInputFormRequest, signal?: AbortSignal): Promise<Record<string, string> | undefined> {\n\t\tif (signal?.aborted) return Promise.resolve(undefined);\n\t\tconst componentId = `input_form_${++this.nextId}`;\n\t\tlet resolveResult!: (values: Record<string, string> | undefined) => void;\n\t\tconst result = new Promise<Record<string, string> | undefined>((resolve) => {\n\t\t\tresolveResult = resolve;\n\t\t});\n\t\tconst onAbort = () => {\n\t\t\tthis.send({ type: \"engine_input_form_close\", componentId });\n\t\t\trecord.resolve(undefined);\n\t\t};\n\t\tconst record: ActiveForm = {\n\t\t\tsettled: false,\n\t\t\tresolve: (values) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\trecord.settled = true;\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tthis.active.delete(componentId);\n\t\t\t\tresolveResult(values);\n\t\t\t},\n\t\t};\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tthis.active.set(componentId, record);\n\t\tthis.send({\n\t\t\ttype: \"engine_input_form_open\",\n\t\t\tcomponentId,\n\t\t\ttitle: request.title,\n\t\t\tfields: request.fields.map((field) => ({ ...field, choices: field.choices ? [...field.choices] : undefined })),\n\t\t\t...(request.heading !== undefined ? { heading: request.heading } : {}),\n\t\t\t...(request.submitLabel !== undefined ? { submitLabel: request.submitLabel } : {}),\n\t\t});\n\t\treturn result;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (!command?.type.startsWith(\"engine_input_form_\")) return false;\n\t\tconst record = this.active.get(command.componentId);\n\t\tif (!record) return true;\n\t\tif (command.type === \"engine_input_form_submit\") record.resolve(command.values);\n\t\telse if (command.type === \"engine_input_form_cancel\") record.resolve(undefined);\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const record of this.active.values()) record.resolve(undefined);\n\t\tthis.active.clear();\n\t}\n\n\tprivate send(message: InteractiveEngineMessage): void {\n\t\tthis.write(serializeInteractiveEngineMessage(message));\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-input-form.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-input-form.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HostInputFormRequest } from \"../../core/extensions/ui-types.js\";\nimport {\n\ttype InteractiveEngineMessage,\n\tparseInteractiveEngineCommand,\n\tserializeInteractiveEngineMessage,\n} from \"./protocol.ts\";\n\ninterface ActiveForm {\n\tsettled: boolean;\n\tresolve: (values: Record<string, string> | undefined) => void;\n}\n\n/** Child-side owner for host-native input forms. */\nexport class EngineInputFormService {\n\tprivate readonly active = new Map<string, ActiveForm>();\n\tprivate readonly write: (line: string) => void;\n\tprivate nextId = 0;\n\tconstructor(write: (line: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\topen(request: HostInputFormRequest, signal?: AbortSignal): Promise<Record<string, string> | undefined> {\n\t\tif (signal?.aborted) return Promise.resolve(undefined);\n\t\tconst componentId = `input_form_${++this.nextId}`;\n\t\tlet resolveResult!: (values: Record<string, string> | undefined) => void;\n\t\tconst result = new Promise<Record<string, string> | undefined>((resolve) => {\n\t\t\tresolveResult = resolve;\n\t\t});\n\t\tconst onAbort = () => {\n\t\t\tthis.send({ type: \"engine_input_form_close\", componentId });\n\t\t\trecord.resolve(undefined);\n\t\t};\n\t\tconst record: ActiveForm = {\n\t\t\tsettled: false,\n\t\t\tresolve: (values) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\trecord.settled = true;\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tthis.active.delete(componentId);\n\t\t\t\tresolveResult(values);\n\t\t\t},\n\t\t};\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tthis.active.set(componentId, record);\n\t\tthis.send({\n\t\t\ttype: \"engine_input_form_open\",\n\t\t\tcomponentId,\n\t\t\ttitle: request.title,\n\t\t\tfields: request.fields.map((field) => ({ ...field, choices: field.choices ? [...field.choices] : undefined })),\n\t\t\t...(request.heading !== undefined ? { heading: request.heading } : {}),\n\t\t\t...(request.submitLabel !== undefined ? { submitLabel: request.submitLabel } : {}),\n\t\t});\n\t\treturn result;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (!command?.type.startsWith(\"engine_input_form_\")) return false;\n\t\tconst record = this.active.get(command.componentId);\n\t\tif (!record) return true;\n\t\tif (command.type === \"engine_input_form_submit\") record.resolve(command.values);\n\t\telse if (command.type === \"engine_input_form_cancel\") record.resolve(undefined);\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const record of this.active.values()) record.resolve(undefined);\n\t\tthis.active.clear();\n\t}\n\n\tprivate send(message: InteractiveEngineMessage): void {\n\t\tthis.write(serializeInteractiveEngineMessage(message));\n\t}\n}\n"]}
@@ -2,8 +2,20 @@ import { markLifecycleTiming } from "../../core/lifecycle-timings.js";
2
2
  import { ActivityWatchdog } from "./activity-watchdog.js";
3
3
  import { parseInteractiveEngineMessage } from "./protocol.js";
4
4
  export class InteractiveEngineMonitor {
5
+ watchdog;
6
+ readiness;
7
+ resolveReady;
8
+ bound;
9
+ resolveBound;
10
+ rejectBound;
11
+ resourcesReady;
12
+ resolveResourcesReady;
13
+ rejectResourcesReady;
14
+ resourceState = "pending";
15
+ failure;
16
+ rejectFailure;
17
+ onMessage;
5
18
  constructor(onDiagnostic, onMessage) {
6
- this.resourceState = "pending";
7
19
  this.watchdog = new ActivityWatchdog({ onDiagnostic });
8
20
  this.onMessage = onMessage;
9
21
  this.readiness = new Promise((resolve) => {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-monitor.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import { markLifecycleTiming } from \"../../core/lifecycle-timings.ts\";\nimport { ActivityWatchdog, type ActivityWatchdogDiagnostic } from \"./activity-watchdog.ts\";\nimport { type InteractiveEngineMessage, parseInteractiveEngineMessage } from \"./protocol.ts\";\n\nexport class InteractiveEngineMonitor {\n\tprivate readonly watchdog: ActivityWatchdog;\n\tprivate readonly readiness: Promise<void>;\n\tprivate resolveReady!: () => void;\n\tprivate readonly bound: Promise<void>;\n\tprivate resolveBound!: () => void;\n\tprivate rejectBound!: (error: Error) => void;\n\tprivate resourcesReady: Promise<void>;\n\tprivate resolveResourcesReady!: () => void;\n\tprivate rejectResourcesReady!: (error: Error) => void;\n\tprivate resourceState: \"pending\" | \"ready\" | \"failed\" = \"pending\";\n\tprivate readonly failure: Promise<never>;\n\tprivate rejectFailure!: (error: Error) => void;\n\tprivate readonly onMessage: (message: InteractiveEngineMessage) => void;\n\n\tconstructor(\n\t\tonDiagnostic: (diagnostic: ActivityWatchdogDiagnostic) => void,\n\t\tonMessage: (message: InteractiveEngineMessage) => void,\n\t) {\n\t\tthis.watchdog = new ActivityWatchdog({ onDiagnostic });\n\t\tthis.onMessage = onMessage;\n\t\tthis.readiness = new Promise((resolve) => {\n\t\t\tthis.resolveReady = resolve;\n\t\t});\n\t\tthis.bound = new Promise((resolve, reject) => {\n\t\t\tthis.resolveBound = resolve;\n\t\t\tthis.rejectBound = reject;\n\t\t});\n\t\tthis.bound.catch(() => {});\n\t\tthis.resourcesReady = new Promise((resolve, reject) => {\n\t\t\tthis.resolveResourcesReady = resolve;\n\t\t\tthis.rejectResourcesReady = reject;\n\t\t});\n\t\tthis.resourcesReady.catch(() => {});\n\t\tthis.failure = new Promise((_, reject) => {\n\t\t\tthis.rejectFailure = reject;\n\t\t});\n\t\tthis.failure.catch(() => {});\n\t}\n\n\tstop(): void {\n\t\tthis.watchdog.stop();\n\t}\n\tfail(error: Error): void {\n\t\tthis.rejectBound(error);\n\t\tthis.rejectResourcesReady(error);\n\t\tthis.rejectFailure(error);\n\t}\n\n\t/**\n\t * Waits for the engine to announce readiness. There is deliberately no\n\t * deadline: slow starts (cold module loads on Windows) must not be treated\n\t * as failures. Engine exit or a transport error rejects via fail().\n\t */\n\tasync waitUntilReady(): Promise<void> {\n\t\tawait Promise.race([this.readiness, this.failure]);\n\t}\n\n\twaitUntilBound(): Promise<void> {\n\t\treturn this.bound;\n\t}\n\n\twaitUntilResourcesReady(): Promise<void> {\n\t\treturn this.resourcesReady;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst message = parseInteractiveEngineMessage(line);\n\t\tif (!message) return false;\n\t\tthis.onMessage(message);\n\t\tswitch (message.type) {\n\t\t\tcase \"engine_ready\":\n\t\t\t\tmarkLifecycleTiming(\"engine-ready\");\n\t\t\t\tthis.watchdog.heartbeat();\n\t\t\t\tthis.watchdog.start();\n\t\t\t\tthis.resolveReady();\n\t\t\t\tbreak;\n\t\t\tcase \"engine_bound\":\n\t\t\t\tmarkLifecycleTiming(\"engine-bound\");\n\t\t\t\tthis.resolveBound();\n\t\t\t\tbreak;\n\t\t\tcase \"engine_resources_ready\":\n\t\t\t\tif (this.resourceState === \"failed\") this.resourcesReady = Promise.resolve();\n\t\t\t\telse this.resolveResourcesReady();\n\t\t\t\tthis.resourceState = \"ready\";\n\t\t\t\tbreak;\n\t\t\tcase \"engine_resources_failed\":\n\t\t\t\tthis.resourceState = \"failed\";\n\t\t\t\tthis.rejectResourcesReady(new Error(`Interactive engine resource loading failed: ${message.message}`));\n\t\t\t\tbreak;\n\t\t\tcase \"engine_heartbeat\":\n\t\t\t\tthis.watchdog.heartbeat();\n\t\t\t\tthis.watchdog.start();\n\t\t\t\tbreak;\n\t\t\tcase \"engine_activity_started\":\n\t\t\t\tthis.watchdog.activityStarted(message.activity);\n\t\t\t\tbreak;\n\t\t\tcase \"engine_activity_finished\":\n\t\t\t\tthis.watchdog.activityFinished(message.activityId);\n\t\t\t\tbreak;\n\t\t}\n\t\treturn true;\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-monitor.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-monitor.ts"],"names":[],"mappings":"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","sourcesContent":["import { markLifecycleTiming } from \"../../core/lifecycle-timings.ts\";\nimport { ActivityWatchdog, type ActivityWatchdogDiagnostic } from \"./activity-watchdog.ts\";\nimport { type InteractiveEngineMessage, parseInteractiveEngineMessage } from \"./protocol.ts\";\n\nexport class InteractiveEngineMonitor {\n\tprivate readonly watchdog: ActivityWatchdog;\n\tprivate readonly readiness: Promise<void>;\n\tprivate resolveReady!: () => void;\n\tprivate readonly bound: Promise<void>;\n\tprivate resolveBound!: () => void;\n\tprivate rejectBound!: (error: Error) => void;\n\tprivate resourcesReady: Promise<void>;\n\tprivate resolveResourcesReady!: () => void;\n\tprivate rejectResourcesReady!: (error: Error) => void;\n\tprivate resourceState: \"pending\" | \"ready\" | \"failed\" = \"pending\";\n\tprivate readonly failure: Promise<never>;\n\tprivate rejectFailure!: (error: Error) => void;\n\tprivate readonly onMessage: (message: InteractiveEngineMessage) => void;\n\n\tconstructor(\n\t\tonDiagnostic: (diagnostic: ActivityWatchdogDiagnostic) => void,\n\t\tonMessage: (message: InteractiveEngineMessage) => void,\n\t) {\n\t\tthis.watchdog = new ActivityWatchdog({ onDiagnostic });\n\t\tthis.onMessage = onMessage;\n\t\tthis.readiness = new Promise((resolve) => {\n\t\t\tthis.resolveReady = resolve;\n\t\t});\n\t\tthis.bound = new Promise((resolve, reject) => {\n\t\t\tthis.resolveBound = resolve;\n\t\t\tthis.rejectBound = reject;\n\t\t});\n\t\tthis.bound.catch(() => {});\n\t\tthis.resourcesReady = new Promise((resolve, reject) => {\n\t\t\tthis.resolveResourcesReady = resolve;\n\t\t\tthis.rejectResourcesReady = reject;\n\t\t});\n\t\tthis.resourcesReady.catch(() => {});\n\t\tthis.failure = new Promise((_, reject) => {\n\t\t\tthis.rejectFailure = reject;\n\t\t});\n\t\tthis.failure.catch(() => {});\n\t}\n\n\tstop(): void {\n\t\tthis.watchdog.stop();\n\t}\n\tfail(error: Error): void {\n\t\tthis.rejectBound(error);\n\t\tthis.rejectResourcesReady(error);\n\t\tthis.rejectFailure(error);\n\t}\n\n\t/**\n\t * Waits for the engine to announce readiness. There is deliberately no\n\t * deadline: slow starts (cold module loads on Windows) must not be treated\n\t * as failures. Engine exit or a transport error rejects via fail().\n\t */\n\tasync waitUntilReady(): Promise<void> {\n\t\tawait Promise.race([this.readiness, this.failure]);\n\t}\n\n\twaitUntilBound(): Promise<void> {\n\t\treturn this.bound;\n\t}\n\n\twaitUntilResourcesReady(): Promise<void> {\n\t\treturn this.resourcesReady;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst message = parseInteractiveEngineMessage(line);\n\t\tif (!message) return false;\n\t\tthis.onMessage(message);\n\t\tswitch (message.type) {\n\t\t\tcase \"engine_ready\":\n\t\t\t\tmarkLifecycleTiming(\"engine-ready\");\n\t\t\t\tthis.watchdog.heartbeat();\n\t\t\t\tthis.watchdog.start();\n\t\t\t\tthis.resolveReady();\n\t\t\t\tbreak;\n\t\t\tcase \"engine_bound\":\n\t\t\t\tmarkLifecycleTiming(\"engine-bound\");\n\t\t\t\tthis.resolveBound();\n\t\t\t\tbreak;\n\t\t\tcase \"engine_resources_ready\":\n\t\t\t\tif (this.resourceState === \"failed\") this.resourcesReady = Promise.resolve();\n\t\t\t\telse this.resolveResourcesReady();\n\t\t\t\tthis.resourceState = \"ready\";\n\t\t\t\tbreak;\n\t\t\tcase \"engine_resources_failed\":\n\t\t\t\tthis.resourceState = \"failed\";\n\t\t\t\tthis.rejectResourcesReady(new Error(`Interactive engine resource loading failed: ${message.message}`));\n\t\t\t\tbreak;\n\t\t\tcase \"engine_heartbeat\":\n\t\t\t\tthis.watchdog.heartbeat();\n\t\t\t\tthis.watchdog.start();\n\t\t\t\tbreak;\n\t\t\tcase \"engine_activity_started\":\n\t\t\t\tthis.watchdog.activityStarted(message.activity);\n\t\t\t\tbreak;\n\t\t\tcase \"engine_activity_finished\":\n\t\t\t\tthis.watchdog.activityFinished(message.activityId);\n\t\t\t\tbreak;\n\t\t}\n\t\treturn true;\n\t}\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  import { parseInteractiveEngineCommand } from "./protocol.js";
2
2
  /** Child-side lifecycle tracking for trust dialogs owned by the terminal host. */
3
3
  export class EngineProjectTrustService {
4
+ active = new Map();
5
+ getRunner;
4
6
  constructor(getRunner) {
5
- this.active = new Map();
6
7
  this.getRunner = getRunner;
7
8
  }
8
9
  handleLine(line) {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-project-trust.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-project-trust.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAE9D,kFAAkF;AAClF,MAAM,OAAO,yBAAyB;IAKrC,YAAY,SAAgC;QAJ3B,WAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;QAKvD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED,UAAU,CAAC,IAAY;QACtB,MAAM,OAAO,GAAG,6BAA6B,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,OAAO,EAAE,IAAI,KAAK,0BAA0B,EAAE,CAAC;YAClD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,OAAO,EAAE,IAAI,KAAK,4BAA4B;YAAE,OAAO,KAAK,CAAC;QACjE,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,uBAAuB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5G,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO;QACN,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACD","sourcesContent":["import type { ExtensionRunner } from \"../../core/extensions/runner.ts\";\nimport { parseInteractiveEngineCommand } from \"./protocol.ts\";\n\n/** Child-side lifecycle tracking for trust dialogs owned by the terminal host. */\nexport class EngineProjectTrustService {\n\tprivate readonly active = new Map<string, () => void>();\n\n\tprivate readonly getRunner: () => ExtensionRunner;\n\n\tconstructor(getRunner: () => ExtensionRunner) {\n\t\tthis.getRunner = getRunner;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (command?.type === \"engine_project_trust_end\") {\n\t\t\tthis.active.get(command.componentId)?.();\n\t\t\tthis.active.delete(command.componentId);\n\t\t\treturn true;\n\t\t}\n\t\tif (command?.type !== \"engine_project_trust_start\") return false;\n\t\tif (this.active.has(command.componentId)) return true;\n\t\tthis.active.set(command.componentId, this.getRunner().beginProjectTrustPrompt(command.kind, command.title));\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const finish of this.active.values()) finish();\n\t\tthis.active.clear();\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-project-trust.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-project-trust.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAE9D,kFAAkF;AAClF,MAAM,OAAO,yBAAyB;IACpB,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEvC,SAAS,CAAwB;IAElD,YAAY,SAAgC;QAC3C,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED,UAAU,CAAC,IAAY;QACtB,MAAM,OAAO,GAAG,6BAA6B,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,OAAO,EAAE,IAAI,KAAK,0BAA0B,EAAE,CAAC;YAClD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,OAAO,EAAE,IAAI,KAAK,4BAA4B;YAAE,OAAO,KAAK,CAAC;QACjE,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC;YAAE,OAAO,IAAI,CAAC;QACtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,uBAAuB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5G,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO;QACN,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;YAAE,MAAM,EAAE,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACD","sourcesContent":["import type { ExtensionRunner } from \"../../core/extensions/runner.ts\";\nimport { parseInteractiveEngineCommand } from \"./protocol.ts\";\n\n/** Child-side lifecycle tracking for trust dialogs owned by the terminal host. */\nexport class EngineProjectTrustService {\n\tprivate readonly active = new Map<string, () => void>();\n\n\tprivate readonly getRunner: () => ExtensionRunner;\n\n\tconstructor(getRunner: () => ExtensionRunner) {\n\t\tthis.getRunner = getRunner;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (command?.type === \"engine_project_trust_end\") {\n\t\t\tthis.active.get(command.componentId)?.();\n\t\t\tthis.active.delete(command.componentId);\n\t\t\treturn true;\n\t\t}\n\t\tif (command?.type !== \"engine_project_trust_start\") return false;\n\t\tif (this.active.has(command.componentId)) return true;\n\t\tthis.active.set(command.componentId, this.getRunner().beginProjectTrustPrompt(command.kind, command.title));\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const finish of this.active.values()) finish();\n\t\tthis.active.clear();\n\t}\n}\n"]}
@@ -5,10 +5,11 @@ import { CustomMessageComponent } from "../interactive/components/custom-message
5
5
  import { ToolExecutionComponent } from "../interactive/components/tool-execution.js";
6
6
  import { parseInteractiveEngineCommand, serializeInteractiveEngineMessage, } from "./protocol.js";
7
7
  class RenderTerminal {
8
+ columns = 80;
9
+ rows = 24;
10
+ kittyProtocolActive = false;
11
+ requestRender;
8
12
  constructor(requestRender) {
9
- this.columns = 80;
10
- this.rows = 24;
11
- this.kittyProtocolActive = false;
12
13
  this.requestRender = requestRender;
13
14
  }
14
15
  start() { }
@@ -27,8 +28,10 @@ class RenderTerminal {
27
28
  setProgress() { }
28
29
  }
29
30
  export class EngineRenderService {
31
+ records = new Map();
32
+ session;
33
+ write;
30
34
  constructor(write) {
31
- this.records = new Map();
32
35
  this.write = write;
33
36
  }
34
37
  bindSession(session) {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-render-service.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-render-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Terminal } from \"@earendil-works/pi-tui\";\nimport { type TUI, TuiMainScreen } from \"@earendil-works/pi-tui\";\nimport { getAgentDir } from \"../../config.js\";\nimport type { AgentSession } from \"../../core/agent-session.js\";\nimport { runCallback } from \"../../core/callback-activity.ts\";\nimport type { CustomMessage } from \"../../core/messages.ts\";\nimport { CustomMessageComponent } from \"../interactive/components/custom-message.ts\";\nimport { ToolExecutionComponent } from \"../interactive/components/tool-execution.ts\";\nimport {\n\ttype InteractiveEngineCommand,\n\ttype InteractiveEngineMessage,\n\tparseInteractiveEngineCommand,\n\tserializeInteractiveEngineMessage,\n} from \"./protocol.ts\";\n\ntype ToolRenderCommand = Extract<InteractiveEngineCommand, { type: \"engine_tool_render\" }>;\ntype MessageRenderCommand = Extract<InteractiveEngineCommand, { type: \"engine_message_render\" }>;\n\n/**\n * Cached per-componentId render state. Records are REUSED across render\n * requests: recreating (and re-seeding) the component on every request made\n * the seeding setters call `ui.requestRender()` each time, whose eventual\n * terminal write emitted `engine_custom_invalidate` back to the host, which\n * re-sent the render request — a self-sustaining host⇄engine render\n * ping-pong that presented as full-screen TUI flicker (quit/pause while a\n * workflow stage streams). Reuse plus idempotent seeding setters lets the\n * loop converge after at most one round trip while still forwarding\n * legitimate async invalidations (e.g. image conversion).\n */\ntype RenderRecord =\n\t| { kind: \"message\"; component: CustomMessageComponent; terminal: RenderTerminal; tui: TUI }\n\t| { kind: \"tool\"; component: ToolExecutionComponent; terminal: RenderTerminal; tui: TUI };\n\nclass RenderTerminal implements Terminal {\n\tcolumns = 80;\n\trows = 24;\n\tkittyProtocolActive = false;\n\tprivate readonly requestRender: () => void;\n\tconstructor(requestRender: () => void) {\n\t\tthis.requestRender = requestRender;\n\t}\n\tstart(): void {}\n\tstop(): void {}\n\tasync drainInput(): Promise<void> {}\n\twrite(): void {\n\t\tthis.requestRender();\n\t}\n\tmoveBy(): void {}\n\thideCursor(): void {}\n\tshowCursor(): void {}\n\tclearLine(): void {}\n\tclearFromCursor(): void {}\n\tclearScreen(): void {}\n\tsetTitle(): void {}\n\tsetProgress(): void {}\n}\n\nexport class EngineRenderService {\n\tprivate readonly records = new Map<string, RenderRecord>();\n\tprivate session: AgentSession | undefined;\n\tprivate readonly write: (line: string) => void;\n\n\tconstructor(write: (line: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\tbindSession(session: AgentSession): void {\n\t\tthis.dispose();\n\t\tthis.session = session;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (!command?.type.startsWith(\"engine_\") || command.type.startsWith(\"engine_custom_\")) return false;\n\t\tif (command.type === \"engine_render_dispose\") {\n\t\t\tthis.disposeRecord(command.componentId);\n\t\t\treturn true;\n\t\t}\n\t\tif (command.type !== \"engine_tool_render\" && command.type !== \"engine_message_render\") return false;\n\t\tconst name =\n\t\t\tcommand.type === \"engine_tool_render\"\n\t\t\t\t? `tool:${command.toolName}`\n\t\t\t\t: `message:${command.message.customType ?? \"custom\"}`;\n\t\tvoid runCallback({ kind: \"renderer\", name }, async () => {\n\t\t\treturn command.type === \"engine_tool_render\" ? this.renderTool(command) : this.renderMessage(command);\n\t\t})\n\t\t\t.then((lines) =>\n\t\t\t\tthis.send({\n\t\t\t\t\ttype: \"engine_custom_frame\",\n\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\trequestId: command.requestId,\n\t\t\t\t\tlines,\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch((error: Error) =>\n\t\t\t\tthis.send({\n\t\t\t\t\ttype: \"engine_custom_frame\",\n\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\trequestId: command.requestId,\n\t\t\t\t\tlines: [`Remote renderer failed: ${error.message}`],\n\t\t\t\t}),\n\t\t\t);\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const id of [...this.records.keys()]) this.disposeRecord(id);\n\t}\n\n\tprivate boundSession(): AgentSession {\n\t\tconst session = this.session;\n\t\tif (!session) throw new Error(\"Renderer session is not bound\");\n\t\treturn session;\n\t}\n\n\tprivate createTerminal(componentId: string): RenderTerminal {\n\t\treturn new RenderTerminal(() => this.send({ type: \"engine_custom_invalidate\", componentId }));\n\t}\n\n\tprivate renderTool(command: ToolRenderCommand): string[] {\n\t\tlet record = this.records.get(command.componentId);\n\t\tif (record?.kind !== \"tool\") {\n\t\t\tconst session = this.boundSession();\n\t\t\tthis.disposeRecord(command.componentId);\n\t\t\tconst terminal = this.createTerminal(command.componentId);\n\t\t\tterminal.columns = Math.max(1, command.width);\n\t\t\tconst tui = new TuiMainScreen(terminal, undefined, getAgentDir());\n\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\tcommand.toolName,\n\t\t\t\tcommand.toolCallId,\n\t\t\t\tcommand.args,\n\t\t\t\t{ showImages: command.showImages, imageWidthCells: command.imageWidthCells },\n\t\t\t\tsession.getToolDefinition(command.toolName),\n\t\t\t\ttui,\n\t\t\t\tsession.sessionManager.getCwd(),\n\t\t\t);\n\t\t\ttui.addChild(component);\n\t\t\trecord = { kind: \"tool\", component, terminal, tui };\n\t\t\tthis.records.set(command.componentId, record);\n\t\t} else {\n\t\t\trecord.terminal.columns = Math.max(1, command.width);\n\t\t\trecord.component.updateArgs(command.args);\n\t\t\trecord.component.setShowImages(command.showImages);\n\t\t\trecord.component.setImageWidthCells(command.imageWidthCells);\n\t\t}\n\t\tconst tool = record.component;\n\t\tif (command.executionStarted) tool.markExecutionStarted();\n\t\tif (command.argsComplete) tool.setArgsComplete();\n\t\ttool.setExpanded(command.expanded);\n\t\tif (command.result) {\n\t\t\ttool.updateResult(\n\t\t\t\tcommand.result as unknown as Parameters<ToolExecutionComponent[\"updateResult\"]>[0],\n\t\t\t\tcommand.isPartial,\n\t\t\t);\n\t\t}\n\t\treturn tool.render(command.width);\n\t}\n\n\tprivate renderMessage(command: MessageRenderCommand): string[] {\n\t\tlet record = this.records.get(command.componentId);\n\t\tif (record?.kind !== \"message\") {\n\t\t\tconst session = this.boundSession();\n\t\t\tthis.disposeRecord(command.componentId);\n\t\t\tconst terminal = this.createTerminal(command.componentId);\n\t\t\tterminal.columns = Math.max(1, command.width);\n\t\t\tconst tui = new TuiMainScreen(terminal, undefined, getAgentDir());\n\t\t\tconst message = command.message as unknown as CustomMessage<object>;\n\t\t\tconst component = new CustomMessageComponent(\n\t\t\t\tmessage,\n\t\t\t\tsession.extensionRunner.getMessageRenderer(message.customType),\n\t\t\t\tundefined,\n\t\t\t\tcommand.outputPad,\n\t\t\t);\n\t\t\ttui.addChild(component);\n\t\t\trecord = { kind: \"message\", component, terminal, tui };\n\t\t\tthis.records.set(command.componentId, record);\n\t\t} else {\n\t\t\trecord.terminal.columns = Math.max(1, command.width);\n\t\t}\n\t\trecord.component.setExpanded(command.expanded);\n\t\trecord.component.setOutputPad(command.outputPad);\n\t\treturn record.component.render(command.width);\n\t}\n\n\tprivate disposeRecord(id: string): void {\n\t\tconst record = this.records.get(id);\n\t\tif (!record) return;\n\t\tthis.records.delete(id);\n\t\tif (record.kind === \"tool\") record.component.dispose();\n\t\trecord.tui.stop();\n\t}\n\n\tprivate send(message: InteractiveEngineMessage): void {\n\t\tthis.write(serializeInteractiveEngineMessage(message));\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-render-service.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-render-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Terminal } from \"@earendil-works/pi-tui\";\nimport { type TUI, TuiMainScreen } from \"@earendil-works/pi-tui\";\nimport { getAgentDir } from \"../../config.js\";\nimport type { AgentSession } from \"../../core/agent-session.js\";\nimport { runCallback } from \"../../core/callback-activity.ts\";\nimport type { CustomMessage } from \"../../core/messages.ts\";\nimport { CustomMessageComponent } from \"../interactive/components/custom-message.ts\";\nimport { ToolExecutionComponent } from \"../interactive/components/tool-execution.ts\";\nimport {\n\ttype InteractiveEngineCommand,\n\ttype InteractiveEngineMessage,\n\tparseInteractiveEngineCommand,\n\tserializeInteractiveEngineMessage,\n} from \"./protocol.ts\";\n\ntype ToolRenderCommand = Extract<InteractiveEngineCommand, { type: \"engine_tool_render\" }>;\ntype MessageRenderCommand = Extract<InteractiveEngineCommand, { type: \"engine_message_render\" }>;\n\n/**\n * Cached per-componentId render state. Records are REUSED across render\n * requests: recreating (and re-seeding) the component on every request made\n * the seeding setters call `ui.requestRender()` each time, whose eventual\n * terminal write emitted `engine_custom_invalidate` back to the host, which\n * re-sent the render request — a self-sustaining host⇄engine render\n * ping-pong that presented as full-screen TUI flicker (quit/pause while a\n * workflow stage streams). Reuse plus idempotent seeding setters lets the\n * loop converge after at most one round trip while still forwarding\n * legitimate async invalidations (e.g. image conversion).\n */\ntype RenderRecord =\n\t| { kind: \"message\"; component: CustomMessageComponent; terminal: RenderTerminal; tui: TUI }\n\t| { kind: \"tool\"; component: ToolExecutionComponent; terminal: RenderTerminal; tui: TUI };\n\nclass RenderTerminal implements Terminal {\n\tcolumns = 80;\n\trows = 24;\n\tkittyProtocolActive = false;\n\tprivate readonly requestRender: () => void;\n\tconstructor(requestRender: () => void) {\n\t\tthis.requestRender = requestRender;\n\t}\n\tstart(): void {}\n\tstop(): void {}\n\tasync drainInput(): Promise<void> {}\n\twrite(): void {\n\t\tthis.requestRender();\n\t}\n\tmoveBy(): void {}\n\thideCursor(): void {}\n\tshowCursor(): void {}\n\tclearLine(): void {}\n\tclearFromCursor(): void {}\n\tclearScreen(): void {}\n\tsetTitle(): void {}\n\tsetProgress(): void {}\n}\n\nexport class EngineRenderService {\n\tprivate readonly records = new Map<string, RenderRecord>();\n\tprivate session: AgentSession | undefined;\n\tprivate readonly write: (line: string) => void;\n\n\tconstructor(write: (line: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\tbindSession(session: AgentSession): void {\n\t\tthis.dispose();\n\t\tthis.session = session;\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (!command?.type.startsWith(\"engine_\") || command.type.startsWith(\"engine_custom_\")) return false;\n\t\tif (command.type === \"engine_render_dispose\") {\n\t\t\tthis.disposeRecord(command.componentId);\n\t\t\treturn true;\n\t\t}\n\t\tif (command.type !== \"engine_tool_render\" && command.type !== \"engine_message_render\") return false;\n\t\tconst name =\n\t\t\tcommand.type === \"engine_tool_render\"\n\t\t\t\t? `tool:${command.toolName}`\n\t\t\t\t: `message:${command.message.customType ?? \"custom\"}`;\n\t\tvoid runCallback({ kind: \"renderer\", name }, async () => {\n\t\t\treturn command.type === \"engine_tool_render\" ? this.renderTool(command) : this.renderMessage(command);\n\t\t})\n\t\t\t.then((lines) =>\n\t\t\t\tthis.send({\n\t\t\t\t\ttype: \"engine_custom_frame\",\n\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\trequestId: command.requestId,\n\t\t\t\t\tlines,\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.catch((error: Error) =>\n\t\t\t\tthis.send({\n\t\t\t\t\ttype: \"engine_custom_frame\",\n\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\trequestId: command.requestId,\n\t\t\t\t\tlines: [`Remote renderer failed: ${error.message}`],\n\t\t\t\t}),\n\t\t\t);\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const id of [...this.records.keys()]) this.disposeRecord(id);\n\t}\n\n\tprivate boundSession(): AgentSession {\n\t\tconst session = this.session;\n\t\tif (!session) throw new Error(\"Renderer session is not bound\");\n\t\treturn session;\n\t}\n\n\tprivate createTerminal(componentId: string): RenderTerminal {\n\t\treturn new RenderTerminal(() => this.send({ type: \"engine_custom_invalidate\", componentId }));\n\t}\n\n\tprivate renderTool(command: ToolRenderCommand): string[] {\n\t\tlet record = this.records.get(command.componentId);\n\t\tif (record?.kind !== \"tool\") {\n\t\t\tconst session = this.boundSession();\n\t\t\tthis.disposeRecord(command.componentId);\n\t\t\tconst terminal = this.createTerminal(command.componentId);\n\t\t\tterminal.columns = Math.max(1, command.width);\n\t\t\tconst tui = new TuiMainScreen(terminal, undefined, getAgentDir());\n\t\t\tconst component = new ToolExecutionComponent(\n\t\t\t\tcommand.toolName,\n\t\t\t\tcommand.toolCallId,\n\t\t\t\tcommand.args,\n\t\t\t\t{ showImages: command.showImages, imageWidthCells: command.imageWidthCells },\n\t\t\t\tsession.getToolDefinition(command.toolName),\n\t\t\t\ttui,\n\t\t\t\tsession.sessionManager.getCwd(),\n\t\t\t);\n\t\t\ttui.addChild(component);\n\t\t\trecord = { kind: \"tool\", component, terminal, tui };\n\t\t\tthis.records.set(command.componentId, record);\n\t\t} else {\n\t\t\trecord.terminal.columns = Math.max(1, command.width);\n\t\t\trecord.component.updateArgs(command.args);\n\t\t\trecord.component.setShowImages(command.showImages);\n\t\t\trecord.component.setImageWidthCells(command.imageWidthCells);\n\t\t}\n\t\tconst tool = record.component;\n\t\tif (command.executionStarted) tool.markExecutionStarted();\n\t\tif (command.argsComplete) tool.setArgsComplete();\n\t\ttool.setExpanded(command.expanded);\n\t\tif (command.result) {\n\t\t\ttool.updateResult(\n\t\t\t\tcommand.result as unknown as Parameters<ToolExecutionComponent[\"updateResult\"]>[0],\n\t\t\t\tcommand.isPartial,\n\t\t\t);\n\t\t}\n\t\treturn tool.render(command.width);\n\t}\n\n\tprivate renderMessage(command: MessageRenderCommand): string[] {\n\t\tlet record = this.records.get(command.componentId);\n\t\tif (record?.kind !== \"message\") {\n\t\t\tconst session = this.boundSession();\n\t\t\tthis.disposeRecord(command.componentId);\n\t\t\tconst terminal = this.createTerminal(command.componentId);\n\t\t\tterminal.columns = Math.max(1, command.width);\n\t\t\tconst tui = new TuiMainScreen(terminal, undefined, getAgentDir());\n\t\t\tconst message = command.message as unknown as CustomMessage<object>;\n\t\t\tconst component = new CustomMessageComponent(\n\t\t\t\tmessage,\n\t\t\t\tsession.extensionRunner.getMessageRenderer(message.customType),\n\t\t\t\tundefined,\n\t\t\t\tcommand.outputPad,\n\t\t\t);\n\t\t\ttui.addChild(component);\n\t\t\trecord = { kind: \"message\", component, terminal, tui };\n\t\t\tthis.records.set(command.componentId, record);\n\t\t} else {\n\t\t\trecord.terminal.columns = Math.max(1, command.width);\n\t\t}\n\t\trecord.component.setExpanded(command.expanded);\n\t\trecord.component.setOutputPad(command.outputPad);\n\t\treturn record.component.render(command.width);\n\t}\n\n\tprivate disposeRecord(id: string): void {\n\t\tconst record = this.records.get(id);\n\t\tif (!record) return;\n\t\tthis.records.delete(id);\n\t\tif (record.kind === \"tool\") record.component.dispose();\n\t\trecord.tui.stop();\n\t}\n\n\tprivate send(message: InteractiveEngineMessage): void {\n\t\tthis.write(serializeInteractiveEngineMessage(message));\n\t}\n}\n"]}
@@ -10,9 +10,10 @@ import { parseInteractiveEngineCommand, serializeInteractiveEngineMessage, } fro
10
10
  * messages, and select/cancel/delete travel host→child as engine commands.
11
11
  */
12
12
  export class EngineSessionPickerService {
13
+ active = new Map();
14
+ nextId = 0;
15
+ write;
13
16
  constructor(write) {
14
- this.active = new Map();
15
- this.nextId = 0;
16
17
  this.write = write;
17
18
  }
18
19
  open(request) {
@@ -1 +1 @@
1
- {"version":3,"file":"engine-session-picker.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-session-picker.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tHostSessionPickerHandle,\n\tHostSessionPickerRequest,\n\tHostSessionPickerRow,\n} from \"../../core/extensions/ui-types.js\";\nimport {\n\ttype InteractiveEngineMessage,\n\tparseInteractiveEngineCommand,\n\tserializeInteractiveEngineMessage,\n} from \"./protocol.ts\";\n\ninterface ActivePicker {\n\tsettled: boolean;\n\tresolve: (path: string | undefined) => void;\n\tonDelete?: (path: string) => void | Promise<void>;\n}\n\n/**\n * Child-side half of the host-native session picker channel.\n *\n * Runs in the interactive-engine child and backs the optional\n * `ctx.ui.hostSessionPicker()` capability: `open()` ships JSON-safe rows to the\n * terminal host, which mounts the REAL `SessionSelectorComponent` locally so\n * arrow-key navigation and search never cross the process boundary. Only the\n * semantic events do — open/update/error/close travel child→host as engine\n * messages, and select/cancel/delete travel host→child as engine commands.\n */\nexport class EngineSessionPickerService {\n\tprivate readonly active = new Map<string, ActivePicker>();\n\tprivate nextId = 0;\n\tprivate readonly write: (line: string) => void;\n\n\tconstructor(write: (line: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\topen(request: HostSessionPickerRequest): HostSessionPickerHandle {\n\t\tconst componentId = `session_picker_${++this.nextId}`;\n\t\tlet resolveResult!: (path: string | undefined) => void;\n\t\tconst result = new Promise<string | undefined>((resolve) => {\n\t\t\tresolveResult = resolve;\n\t\t});\n\t\tconst record: ActivePicker = {\n\t\t\tsettled: false,\n\t\t\tresolve: (path) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\trecord.settled = true;\n\t\t\t\tthis.active.delete(componentId);\n\t\t\t\tresolveResult(path);\n\t\t\t},\n\t\t\t...(request.onDelete ? { onDelete: request.onDelete } : {}),\n\t\t};\n\t\tthis.active.set(componentId, record);\n\t\tthis.send({\n\t\t\ttype: \"engine_session_picker_open\",\n\t\t\tcomponentId,\n\t\t\tsessions: [...request.sessions],\n\t\t\t...(request.showRenameHint !== undefined ? { showRenameHint: request.showRenameHint } : {}),\n\t\t});\n\t\treturn {\n\t\t\tresult,\n\t\t\tupdate: (sessions: HostSessionPickerRow[]) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\tthis.send({ type: \"engine_session_picker_update\", componentId, sessions: [...sessions] });\n\t\t\t},\n\t\t\terror: (message: string) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\tthis.send({ type: \"engine_session_picker_error\", componentId, message });\n\t\t\t},\n\t\t\tclose: () => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\tthis.send({ type: \"engine_session_picker_close\", componentId });\n\t\t\t\trecord.resolve(undefined);\n\t\t\t},\n\t\t};\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (!command?.type.startsWith(\"engine_session_picker_\")) return false;\n\t\tconst record = this.active.get(command.componentId);\n\t\tif (!record) return true;\n\t\tswitch (command.type) {\n\t\t\tcase \"engine_session_picker_select\":\n\t\t\t\trecord.resolve(command.path);\n\t\t\t\tbreak;\n\t\t\tcase \"engine_session_picker_cancel\":\n\t\t\t\trecord.resolve(undefined);\n\t\t\t\tbreak;\n\t\t\tcase \"engine_session_picker_delete\":\n\t\t\t\tif (!record.onDelete) {\n\t\t\t\t\tthis.send({\n\t\t\t\t\t\ttype: \"engine_session_picker_error\",\n\t\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\t\tmessage: \"Deletion is not supported for this picker\",\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tvoid Promise.resolve(record.onDelete(command.path)).catch((error: unknown) => {\n\t\t\t\t\tif (record.settled) return;\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tthis.send({\n\t\t\t\t\t\ttype: \"engine_session_picker_error\",\n\t\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\t\tmessage: `Failed to delete: ${message}`,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t}\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const record of [...this.active.values()]) record.resolve(undefined);\n\t\tthis.active.clear();\n\t}\n\n\tprivate send(message: InteractiveEngineMessage): void {\n\t\tthis.write(serializeInteractiveEngineMessage(message));\n\t}\n}\n"]}
1
+ {"version":3,"file":"engine-session-picker.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/engine-session-picker.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tHostSessionPickerHandle,\n\tHostSessionPickerRequest,\n\tHostSessionPickerRow,\n} from \"../../core/extensions/ui-types.js\";\nimport {\n\ttype InteractiveEngineMessage,\n\tparseInteractiveEngineCommand,\n\tserializeInteractiveEngineMessage,\n} from \"./protocol.ts\";\n\ninterface ActivePicker {\n\tsettled: boolean;\n\tresolve: (path: string | undefined) => void;\n\tonDelete?: (path: string) => void | Promise<void>;\n}\n\n/**\n * Child-side half of the host-native session picker channel.\n *\n * Runs in the interactive-engine child and backs the optional\n * `ctx.ui.hostSessionPicker()` capability: `open()` ships JSON-safe rows to the\n * terminal host, which mounts the REAL `SessionSelectorComponent` locally so\n * arrow-key navigation and search never cross the process boundary. Only the\n * semantic events do — open/update/error/close travel child→host as engine\n * messages, and select/cancel/delete travel host→child as engine commands.\n */\nexport class EngineSessionPickerService {\n\tprivate readonly active = new Map<string, ActivePicker>();\n\tprivate nextId = 0;\n\tprivate readonly write: (line: string) => void;\n\n\tconstructor(write: (line: string) => void) {\n\t\tthis.write = write;\n\t}\n\n\topen(request: HostSessionPickerRequest): HostSessionPickerHandle {\n\t\tconst componentId = `session_picker_${++this.nextId}`;\n\t\tlet resolveResult!: (path: string | undefined) => void;\n\t\tconst result = new Promise<string | undefined>((resolve) => {\n\t\t\tresolveResult = resolve;\n\t\t});\n\t\tconst record: ActivePicker = {\n\t\t\tsettled: false,\n\t\t\tresolve: (path) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\trecord.settled = true;\n\t\t\t\tthis.active.delete(componentId);\n\t\t\t\tresolveResult(path);\n\t\t\t},\n\t\t\t...(request.onDelete ? { onDelete: request.onDelete } : {}),\n\t\t};\n\t\tthis.active.set(componentId, record);\n\t\tthis.send({\n\t\t\ttype: \"engine_session_picker_open\",\n\t\t\tcomponentId,\n\t\t\tsessions: [...request.sessions],\n\t\t\t...(request.showRenameHint !== undefined ? { showRenameHint: request.showRenameHint } : {}),\n\t\t});\n\t\treturn {\n\t\t\tresult,\n\t\t\tupdate: (sessions: HostSessionPickerRow[]) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\tthis.send({ type: \"engine_session_picker_update\", componentId, sessions: [...sessions] });\n\t\t\t},\n\t\t\terror: (message: string) => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\tthis.send({ type: \"engine_session_picker_error\", componentId, message });\n\t\t\t},\n\t\t\tclose: () => {\n\t\t\t\tif (record.settled) return;\n\t\t\t\tthis.send({ type: \"engine_session_picker_close\", componentId });\n\t\t\t\trecord.resolve(undefined);\n\t\t\t},\n\t\t};\n\t}\n\n\thandleLine(line: string): boolean {\n\t\tconst command = parseInteractiveEngineCommand(line);\n\t\tif (!command?.type.startsWith(\"engine_session_picker_\")) return false;\n\t\tconst record = this.active.get(command.componentId);\n\t\tif (!record) return true;\n\t\tswitch (command.type) {\n\t\t\tcase \"engine_session_picker_select\":\n\t\t\t\trecord.resolve(command.path);\n\t\t\t\tbreak;\n\t\t\tcase \"engine_session_picker_cancel\":\n\t\t\t\trecord.resolve(undefined);\n\t\t\t\tbreak;\n\t\t\tcase \"engine_session_picker_delete\":\n\t\t\t\tif (!record.onDelete) {\n\t\t\t\t\tthis.send({\n\t\t\t\t\t\ttype: \"engine_session_picker_error\",\n\t\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\t\tmessage: \"Deletion is not supported for this picker\",\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tvoid Promise.resolve(record.onDelete(command.path)).catch((error: unknown) => {\n\t\t\t\t\tif (record.settled) return;\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\tthis.send({\n\t\t\t\t\t\ttype: \"engine_session_picker_error\",\n\t\t\t\t\t\tcomponentId: command.componentId,\n\t\t\t\t\t\tmessage: `Failed to delete: ${message}`,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t}\n\t\treturn true;\n\t}\n\n\tdispose(): void {\n\t\tfor (const record of [...this.active.values()]) record.resolve(undefined);\n\t\tthis.active.clear();\n\t}\n\n\tprivate send(message: InteractiveEngineMessage): void {\n\t\tthis.write(serializeInteractiveEngineMessage(message));\n\t}\n}\n"]}
@@ -1,8 +1,12 @@
1
1
  import { mountHostInputForm } from "../interactive/components/host-input-form-mount.js";
2
2
  /** Host-side controller that keeps form input/state entirely in the terminal process. */
3
3
  export class InputFormHostController {
4
+ mounted = new Map();
5
+ runtime;
6
+ ui;
7
+ unsubscribe;
8
+ unsubscribeGenerationEnded;
4
9
  constructor(runtime, ui) {
5
- this.mounted = new Map();
6
10
  this.runtime = runtime;
7
11
  this.ui = ui;
8
12
  this.unsubscribe = runtime.onEngineMessage((message) => this.handleMessage(message));
@@ -1 +1 @@
1
- {"version":3,"file":"input-form-host.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/input-form-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionUIContext, HostInputFormRequest } from \"../../core/extensions/index.js\";\nimport { type HostInputFormMount, mountHostInputForm } from \"../interactive/components/host-input-form-mount.ts\";\nimport type { IsolatedInteractiveRuntime } from \"./isolated-runtime.js\";\nimport type { InteractiveEngineMessage } from \"./protocol.ts\";\n\n/** Host-side controller that keeps form input/state entirely in the terminal process. */\nexport class InputFormHostController {\n\tprivate readonly mounted = new Map<string, HostInputFormMount>();\n\tprivate readonly runtime: IsolatedInteractiveRuntime;\n\tprivate readonly ui: ExtensionUIContext;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly unsubscribeGenerationEnded: () => void;\n\tconstructor(runtime: IsolatedInteractiveRuntime, ui: ExtensionUIContext) {\n\t\tthis.runtime = runtime;\n\t\tthis.ui = ui;\n\t\tthis.unsubscribe = runtime.onEngineMessage((message) => this.handleMessage(message));\n\t\t// A dead generation cannot answer a form, and its componentIds mean nothing\n\t\t// to a replacement child, so unmount on death rather than waiting for the\n\t\t// next `engine_ready` (which never arrives if the restart hangs or fails).\n\t\tthis.unsubscribeGenerationEnded = runtime.onGenerationEnded(() => this.disposeAll());\n\t}\n\n\tdispose(): void {\n\t\tthis.unsubscribe();\n\t\tthis.unsubscribeGenerationEnded();\n\t\tthis.disposeAll();\n\t}\n\n\tprivate handleMessage(message: InteractiveEngineMessage): void {\n\t\tif (message.type === \"engine_ready\") {\n\t\t\tthis.disposeAll();\n\t\t\treturn;\n\t\t}\n\t\tif (message.type === \"engine_input_form_close\") {\n\t\t\tthis.mounted.get(message.componentId)?.close();\n\t\t\tthis.mounted.delete(message.componentId);\n\t\t\treturn;\n\t\t}\n\t\tif (message.type === \"engine_input_form_open\") {\n\t\t\tthis.open(message.componentId, {\n\t\t\t\ttitle: message.title,\n\t\t\t\tfields: message.fields,\n\t\t\t\t...(message.heading !== undefined ? { heading: message.heading } : {}),\n\t\t\t\t...(message.submitLabel !== undefined ? { submitLabel: message.submitLabel } : {}),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate open(componentId: string, request: HostInputFormRequest): void {\n\t\tif (this.mounted.has(componentId)) return;\n\t\tconst mount = mountHostInputForm(this.ui, request, {\n\t\t\tonSubmit: (values) => {\n\t\t\t\tthis.mounted.delete(componentId);\n\t\t\t\tthis.runtime.sendEngineCommand({ type: \"engine_input_form_submit\", componentId, values });\n\t\t\t},\n\t\t\tonCancel: () => {\n\t\t\t\tthis.mounted.delete(componentId);\n\t\t\t\tthis.runtime.sendEngineCommand({ type: \"engine_input_form_cancel\", componentId });\n\t\t\t},\n\t\t});\n\t\tthis.mounted.set(componentId, mount);\n\t}\n\n\tprivate disposeAll(): void {\n\t\tfor (const mount of this.mounted.values()) mount.close();\n\t\tthis.mounted.clear();\n\t}\n}\n"]}
1
+ {"version":3,"file":"input-form-host.js","sourceRoot":"","sources":["../../../src/modes/interactive-engine/input-form-host.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionUIContext, HostInputFormRequest } from \"../../core/extensions/index.js\";\nimport { type HostInputFormMount, mountHostInputForm } from \"../interactive/components/host-input-form-mount.ts\";\nimport type { IsolatedInteractiveRuntime } from \"./isolated-runtime.js\";\nimport type { InteractiveEngineMessage } from \"./protocol.ts\";\n\n/** Host-side controller that keeps form input/state entirely in the terminal process. */\nexport class InputFormHostController {\n\tprivate readonly mounted = new Map<string, HostInputFormMount>();\n\tprivate readonly runtime: IsolatedInteractiveRuntime;\n\tprivate readonly ui: ExtensionUIContext;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly unsubscribeGenerationEnded: () => void;\n\tconstructor(runtime: IsolatedInteractiveRuntime, ui: ExtensionUIContext) {\n\t\tthis.runtime = runtime;\n\t\tthis.ui = ui;\n\t\tthis.unsubscribe = runtime.onEngineMessage((message) => this.handleMessage(message));\n\t\t// A dead generation cannot answer a form, and its componentIds mean nothing\n\t\t// to a replacement child, so unmount on death rather than waiting for the\n\t\t// next `engine_ready` (which never arrives if the restart hangs or fails).\n\t\tthis.unsubscribeGenerationEnded = runtime.onGenerationEnded(() => this.disposeAll());\n\t}\n\n\tdispose(): void {\n\t\tthis.unsubscribe();\n\t\tthis.unsubscribeGenerationEnded();\n\t\tthis.disposeAll();\n\t}\n\n\tprivate handleMessage(message: InteractiveEngineMessage): void {\n\t\tif (message.type === \"engine_ready\") {\n\t\t\tthis.disposeAll();\n\t\t\treturn;\n\t\t}\n\t\tif (message.type === \"engine_input_form_close\") {\n\t\t\tthis.mounted.get(message.componentId)?.close();\n\t\t\tthis.mounted.delete(message.componentId);\n\t\t\treturn;\n\t\t}\n\t\tif (message.type === \"engine_input_form_open\") {\n\t\t\tthis.open(message.componentId, {\n\t\t\t\ttitle: message.title,\n\t\t\t\tfields: message.fields,\n\t\t\t\t...(message.heading !== undefined ? { heading: message.heading } : {}),\n\t\t\t\t...(message.submitLabel !== undefined ? { submitLabel: message.submitLabel } : {}),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate open(componentId: string, request: HostInputFormRequest): void {\n\t\tif (this.mounted.has(componentId)) return;\n\t\tconst mount = mountHostInputForm(this.ui, request, {\n\t\t\tonSubmit: (values) => {\n\t\t\t\tthis.mounted.delete(componentId);\n\t\t\t\tthis.runtime.sendEngineCommand({ type: \"engine_input_form_submit\", componentId, values });\n\t\t\t},\n\t\t\tonCancel: () => {\n\t\t\t\tthis.mounted.delete(componentId);\n\t\t\t\tthis.runtime.sendEngineCommand({ type: \"engine_input_form_cancel\", componentId });\n\t\t\t},\n\t\t});\n\t\tthis.mounted.set(componentId, mount);\n\t}\n\n\tprivate disposeAll(): void {\n\t\tfor (const mount of this.mounted.values()) mount.close();\n\t\tthis.mounted.clear();\n\t}\n}\n"]}
@@ -41,29 +41,43 @@ function applyPersistedThinkingDefault(session, level, target) {
41
41
  * protocol lease lifecycle.
42
42
  */
43
43
  export class IsolatedInteractiveRuntime extends AgentSessionRuntime {
44
+ client;
45
+ patchedSessions = new WeakSet();
46
+ streaming = false;
47
+ compacting = false;
48
+ compactionReason;
49
+ activeBashRequestIds = new Map();
50
+ steeringMessages = [];
51
+ followUpMessages = [];
52
+ /** Bumped by every authoritative queue_update. */
53
+ queueUpdateGeneration = 0;
54
+ /** Bumped by local thinking mutations and thinking_level_changed events. */
55
+ thinkingEpoch = 0;
56
+ /** Clears started before the next queue_update share one rollback snapshot. */
57
+ pendingQueueClear;
58
+ engineCallbackActive = false;
59
+ queuePause;
60
+ autoCompactionEnabled = true;
61
+ autoRetryEnabled = true;
62
+ remoteSessionName;
63
+ remoteSessionFile;
64
+ health;
65
+ remoteCommands;
66
+ disposed = false;
67
+ disposePromise;
68
+ remoteModelCatalog;
69
+ resourceOverlaps = [];
70
+ resourceExtensionsListeners = [];
71
+ resourceExtensions = [];
72
+ resourcesInitializedGeneration = 0;
73
+ resourceInitialization;
74
+ retiredResourceGenerations = new Set();
75
+ reportedResourceFailureGenerations = new Set();
76
+ initializationTail;
77
+ engineRecoveryFailure;
78
+ promptCancellationEpoch = 0;
44
79
  constructor(localRuntime, createRuntime, client) {
45
80
  super(localRuntime.session, localRuntime.services, createRuntime, [...localRuntime.diagnostics], localRuntime.modelFallbackMessage, localRuntime.modelFallbackReason);
46
- this.patchedSessions = new WeakSet();
47
- this.streaming = false;
48
- this.compacting = false;
49
- this.activeBashRequestIds = new Map();
50
- this.steeringMessages = [];
51
- this.followUpMessages = [];
52
- /** Bumped by every authoritative queue_update. */
53
- this.queueUpdateGeneration = 0;
54
- /** Bumped by local thinking mutations and thinking_level_changed events. */
55
- this.thinkingEpoch = 0;
56
- this.engineCallbackActive = false;
57
- this.autoCompactionEnabled = true;
58
- this.autoRetryEnabled = true;
59
- this.disposed = false;
60
- this.resourceOverlaps = [];
61
- this.resourceExtensionsListeners = [];
62
- this.resourceExtensions = [];
63
- this.resourcesInitializedGeneration = 0;
64
- this.retiredResourceGenerations = new Set();
65
- this.reportedResourceFailureGenerations = new Set();
66
- this.promptCancellationEpoch = 0;
67
81
  this.client = client;
68
82
  this.remoteCommands = new RemoteCommandCatalog(client);
69
83
  this.remoteModelCatalog = new RemoteModelCatalog(client);
@@ -528,8 +542,8 @@ export class IsolatedInteractiveRuntime extends AgentSessionRuntime {
528
542
  await this.waitUntilResourcesReady();
529
543
  if (cancellationEpoch !== this.promptCancellationEpoch)
530
544
  return;
531
- await this.client.prompt(text, options?.images, options?.streamingBehavior);
532
- options?.preflightResult?.(true);
545
+ const disposition = await this.client.prompt(text, options?.images, options?.streamingBehavior);
546
+ options?.preflightResult?.(true, disposition);
533
547
  },
534
548
  },
535
549
  steer: { configurable: true, value: (text) => this.client.steer(text) },