@bastani/atomic 0.8.13-0 → 0.8.14-0

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 (355) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/host-html-template.ts +1 -1
  4. package/dist/builtin/mcp/init.ts +15 -2
  5. package/dist/builtin/mcp/mcp-callback-server.ts +10 -9
  6. package/dist/builtin/mcp/package.json +1 -1
  7. package/dist/builtin/mcp/ui-session.ts +9 -6
  8. package/dist/builtin/subagents/CHANGELOG.md +8 -1
  9. package/dist/builtin/subagents/README.md +39 -32
  10. package/dist/builtin/subagents/package.json +1 -1
  11. package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
  12. package/dist/builtin/subagents/src/agents/agent-management.ts +6 -1
  13. package/dist/builtin/subagents/src/agents/agent-serializer.ts +2 -0
  14. package/dist/builtin/subagents/src/agents/agents.ts +44 -19
  15. package/dist/builtin/subagents/src/extension/config.ts +16 -0
  16. package/dist/builtin/subagents/src/extension/fanout-child.ts +246 -0
  17. package/dist/builtin/subagents/src/extension/index.ts +466 -603
  18. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +6 -4
  19. package/dist/builtin/subagents/src/intercom/result-intercom.ts +109 -1
  20. package/dist/builtin/subagents/src/runs/background/async-execution.ts +124 -19
  21. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +41 -6
  22. package/dist/builtin/subagents/src/runs/background/async-resume.ts +28 -15
  23. package/dist/builtin/subagents/src/runs/background/async-status.ts +60 -30
  24. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +111 -54
  25. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +83 -0
  26. package/dist/builtin/subagents/src/runs/background/run-status.ts +79 -3
  27. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +46 -1
  28. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +66 -14
  29. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +10 -3
  30. package/dist/builtin/subagents/src/runs/foreground/execution.ts +14 -2
  31. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +320 -23
  32. package/dist/builtin/subagents/src/runs/shared/completion-guard.ts +23 -1
  33. package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +369 -0
  34. package/dist/builtin/subagents/src/runs/shared/nested-events.ts +935 -0
  35. package/dist/builtin/subagents/src/runs/shared/nested-path.ts +52 -0
  36. package/dist/builtin/subagents/src/runs/shared/nested-render.ts +115 -0
  37. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -0
  38. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +82 -9
  39. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +1 -1
  40. package/dist/builtin/subagents/src/runs/shared/single-output.ts +12 -2
  41. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +32 -10
  42. package/dist/builtin/subagents/src/runs/shared/worktree.ts +3 -2
  43. package/dist/builtin/subagents/src/shared/artifacts.ts +0 -1
  44. package/dist/builtin/subagents/src/shared/types.ts +96 -1
  45. package/dist/builtin/subagents/src/shared/utils.ts +10 -2
  46. package/dist/builtin/subagents/src/slash/slash-commands.ts +468 -625
  47. package/dist/builtin/subagents/src/tui/render.ts +1227 -2093
  48. package/dist/builtin/web-access/package.json +1 -1
  49. package/dist/builtin/workflows/CHANGELOG.md +24 -0
  50. package/dist/builtin/workflows/README.md +28 -11
  51. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +323 -40
  52. package/dist/builtin/workflows/builtin/ralph.ts +362 -176
  53. package/dist/builtin/workflows/package.json +2 -5
  54. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
  55. package/dist/builtin/workflows/skills/skill-creator/LICENSE.txt +202 -0
  56. package/dist/builtin/workflows/skills/skill-creator/SKILL.md +489 -0
  57. package/dist/builtin/workflows/skills/skill-creator/agents/analyzer.md +274 -0
  58. package/dist/builtin/workflows/skills/skill-creator/agents/comparator.md +202 -0
  59. package/dist/builtin/workflows/skills/skill-creator/agents/grader.md +223 -0
  60. package/dist/builtin/workflows/skills/skill-creator/assets/eval_review.html +146 -0
  61. package/dist/builtin/workflows/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  62. package/dist/builtin/workflows/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  63. package/dist/builtin/workflows/skills/skill-creator/references/schemas.md +430 -0
  64. package/dist/builtin/workflows/skills/skill-creator/scripts/__init__.py +0 -0
  65. package/dist/builtin/workflows/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  66. package/dist/builtin/workflows/skills/skill-creator/scripts/generate_report.py +326 -0
  67. package/dist/builtin/workflows/skills/skill-creator/scripts/improve_description.py +247 -0
  68. package/dist/builtin/workflows/skills/skill-creator/scripts/package_skill.py +136 -0
  69. package/dist/builtin/workflows/skills/skill-creator/scripts/quick_validate.py +103 -0
  70. package/dist/builtin/workflows/skills/skill-creator/scripts/run_eval.py +310 -0
  71. package/dist/builtin/workflows/skills/skill-creator/scripts/run_loop.py +328 -0
  72. package/dist/builtin/workflows/skills/skill-creator/scripts/utils.py +47 -0
  73. package/dist/builtin/workflows/src/extension/index.ts +869 -93
  74. package/dist/builtin/workflows/src/extension/render-call.ts +34 -1
  75. package/dist/builtin/workflows/src/extension/render-result.ts +126 -21
  76. package/dist/builtin/workflows/src/extension/runtime.ts +91 -3
  77. package/dist/builtin/workflows/src/extension/wiring.ts +38 -12
  78. package/dist/builtin/workflows/src/extension/workflow-schema.ts +62 -5
  79. package/dist/builtin/workflows/src/runs/background/runner.ts +3 -3
  80. package/dist/builtin/workflows/src/runs/background/status.ts +42 -8
  81. package/dist/builtin/workflows/src/runs/foreground/executor.ts +410 -95
  82. package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +5 -2
  83. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +8 -0
  84. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +6 -4
  85. package/dist/builtin/workflows/src/runs/shared/worktree.ts +3 -2
  86. package/dist/builtin/workflows/src/shared/persistence-restore.ts +138 -5
  87. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +30 -0
  88. package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +78 -120
  89. package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +193 -0
  90. package/dist/builtin/workflows/src/shared/store-types.ts +26 -1
  91. package/dist/builtin/workflows/src/shared/store.ts +145 -17
  92. package/dist/builtin/workflows/src/shared/timing.ts +6 -2
  93. package/dist/builtin/workflows/src/shared/workflow-failures.ts +375 -0
  94. package/dist/builtin/workflows/src/tui/chat-surface.ts +68 -17
  95. package/dist/builtin/workflows/src/tui/connectors.ts +2 -2
  96. package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +24 -26
  97. package/dist/builtin/workflows/src/tui/graph-canvas.ts +4 -8
  98. package/dist/builtin/workflows/src/tui/graph-view.ts +17 -14
  99. package/dist/builtin/workflows/src/tui/header.ts +38 -0
  100. package/dist/builtin/workflows/src/tui/inline-form-card.ts +161 -238
  101. package/dist/builtin/workflows/src/tui/inline-form-editor.ts +68 -73
  102. package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +2 -3
  103. package/dist/builtin/workflows/src/tui/inline-form-store.ts +2 -1
  104. package/dist/builtin/workflows/src/tui/inputs-overlay.ts +1 -3
  105. package/dist/builtin/workflows/src/tui/inputs-picker.ts +286 -399
  106. package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +11 -0
  107. package/dist/builtin/workflows/src/tui/node-card.ts +2 -1
  108. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +9 -1
  109. package/dist/builtin/workflows/src/tui/prompt-card.ts +46 -19
  110. package/dist/builtin/workflows/src/tui/run-detail.ts +63 -80
  111. package/dist/builtin/workflows/src/tui/session-confirm.ts +9 -3
  112. package/dist/builtin/workflows/src/tui/session-picker.ts +19 -16
  113. package/dist/builtin/workflows/src/tui/stage-chat-layout.ts +88 -0
  114. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +368 -879
  115. package/dist/builtin/workflows/src/tui/status-helpers.ts +4 -0
  116. package/dist/builtin/workflows/src/tui/status-list.ts +67 -75
  117. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +50 -12
  118. package/dist/builtin/workflows/src/tui/submit-pane.ts +164 -0
  119. package/dist/builtin/workflows/src/tui/switcher.ts +27 -4
  120. package/dist/builtin/workflows/src/tui/text-helpers.ts +98 -4
  121. package/dist/builtin/workflows/src/tui/widget.ts +90 -68
  122. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +23 -2
  123. package/dist/builtin/workflows/src/tui/workflow-list.ts +44 -68
  124. package/dist/cli/file-processor.d.ts.map +1 -1
  125. package/dist/cli/file-processor.js +2 -3
  126. package/dist/cli/file-processor.js.map +1 -1
  127. package/dist/config.d.ts.map +1 -1
  128. package/dist/config.js +3 -10
  129. package/dist/config.js.map +1 -1
  130. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  131. package/dist/core/agent-session-runtime.js +2 -1
  132. package/dist/core/agent-session-runtime.js.map +1 -1
  133. package/dist/core/agent-session-services.d.ts.map +1 -1
  134. package/dist/core/agent-session-services.js +3 -2
  135. package/dist/core/agent-session-services.js.map +1 -1
  136. package/dist/core/agent-session.d.ts +6 -0
  137. package/dist/core/agent-session.d.ts.map +1 -1
  138. package/dist/core/agent-session.js +16 -2
  139. package/dist/core/agent-session.js.map +1 -1
  140. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  141. package/dist/core/atomic-guide-command.js +8 -9
  142. package/dist/core/atomic-guide-command.js.map +1 -1
  143. package/dist/core/auth-storage.d.ts.map +1 -1
  144. package/dist/core/auth-storage.js +3 -2
  145. package/dist/core/auth-storage.js.map +1 -1
  146. package/dist/core/bash-executor.d.ts.map +1 -1
  147. package/dist/core/bash-executor.js +2 -1
  148. package/dist/core/bash-executor.js.map +1 -1
  149. package/dist/core/export-html/index.d.ts.map +1 -1
  150. package/dist/core/export-html/index.js +8 -6
  151. package/dist/core/export-html/index.js.map +1 -1
  152. package/dist/core/export-html/template.js +6 -3
  153. package/dist/core/extensions/loader.d.ts.map +1 -1
  154. package/dist/core/extensions/loader.js +12 -29
  155. package/dist/core/extensions/loader.js.map +1 -1
  156. package/dist/core/model-registry.d.ts.map +1 -1
  157. package/dist/core/model-registry.js +5 -1
  158. package/dist/core/model-registry.js.map +1 -1
  159. package/dist/core/package-manager.d.ts +8 -0
  160. package/dist/core/package-manager.d.ts.map +1 -1
  161. package/dist/core/package-manager.js +145 -58
  162. package/dist/core/package-manager.js.map +1 -1
  163. package/dist/core/prompt-templates.d.ts.map +1 -1
  164. package/dist/core/prompt-templates.js +6 -20
  165. package/dist/core/prompt-templates.js.map +1 -1
  166. package/dist/core/resource-loader.d.ts.map +1 -1
  167. package/dist/core/resource-loader.js +38 -31
  168. package/dist/core/resource-loader.js.map +1 -1
  169. package/dist/core/sdk.d.ts.map +1 -1
  170. package/dist/core/sdk.js +9 -4
  171. package/dist/core/sdk.js.map +1 -1
  172. package/dist/core/session-manager.d.ts.map +1 -1
  173. package/dist/core/session-manager.js +32 -24
  174. package/dist/core/session-manager.js.map +1 -1
  175. package/dist/core/settings-manager.d.ts.map +1 -1
  176. package/dist/core/settings-manager.js +8 -15
  177. package/dist/core/settings-manager.js.map +1 -1
  178. package/dist/core/skills.d.ts.map +1 -1
  179. package/dist/core/skills.js +8 -22
  180. package/dist/core/skills.js.map +1 -1
  181. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +5 -4
  182. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  183. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +34 -11
  184. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  185. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +1 -0
  186. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  187. package/dist/core/tools/ask-user-question/state/selectors/contract.js.map +1 -1
  188. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  189. package/dist/core/tools/ask-user-question/state/selectors/projections.js +1 -0
  190. package/dist/core/tools/ask-user-question/state/selectors/projections.js.map +1 -1
  191. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts +1 -2
  192. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  193. package/dist/core/tools/ask-user-question/state/state-reducer.js +26 -9
  194. package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
  195. package/dist/core/tools/ask-user-question/state/state.d.ts +4 -0
  196. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  197. package/dist/core/tools/ask-user-question/state/state.js.map +1 -1
  198. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts +1 -0
  199. package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
  200. package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
  201. package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
  202. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +9 -6
  203. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
  204. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +28 -7
  205. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  206. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  207. package/dist/core/tools/ask-user-question/view/props-adapter.js +4 -1
  208. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  209. package/dist/core/tools/bash.d.ts.map +1 -1
  210. package/dist/core/tools/bash.js +56 -53
  211. package/dist/core/tools/bash.js.map +1 -1
  212. package/dist/core/tools/edit-diff.d.ts +3 -1
  213. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  214. package/dist/core/tools/edit-diff.js +8 -1
  215. package/dist/core/tools/edit-diff.js.map +1 -1
  216. package/dist/core/tools/edit.d.ts +3 -1
  217. package/dist/core/tools/edit.d.ts.map +1 -1
  218. package/dist/core/tools/edit.js +44 -81
  219. package/dist/core/tools/edit.js.map +1 -1
  220. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  221. package/dist/core/tools/file-mutation-queue.js +27 -12
  222. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  223. package/dist/core/tools/find.d.ts.map +1 -1
  224. package/dist/core/tools/find.js +2 -3
  225. package/dist/core/tools/find.js.map +1 -1
  226. package/dist/core/tools/grep.d.ts.map +1 -1
  227. package/dist/core/tools/grep.js +3 -3
  228. package/dist/core/tools/grep.js.map +1 -1
  229. package/dist/core/tools/ls.d.ts.map +1 -1
  230. package/dist/core/tools/ls.js +5 -5
  231. package/dist/core/tools/ls.js.map +1 -1
  232. package/dist/core/tools/output-accumulator.d.ts +2 -0
  233. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  234. package/dist/core/tools/output-accumulator.js +11 -4
  235. package/dist/core/tools/output-accumulator.js.map +1 -1
  236. package/dist/core/tools/path-utils.d.ts +2 -0
  237. package/dist/core/tools/path-utils.d.ts.map +1 -1
  238. package/dist/core/tools/path-utils.js +39 -21
  239. package/dist/core/tools/path-utils.js.map +1 -1
  240. package/dist/core/tools/read.d.ts.map +1 -1
  241. package/dist/core/tools/read.js +9 -8
  242. package/dist/core/tools/read.js.map +1 -1
  243. package/dist/core/tools/truncate.d.ts.map +1 -1
  244. package/dist/core/tools/truncate.js +12 -2
  245. package/dist/core/tools/truncate.js.map +1 -1
  246. package/dist/core/tools/write.d.ts.map +1 -1
  247. package/dist/core/tools/write.js +20 -35
  248. package/dist/core/tools/write.js.map +1 -1
  249. package/dist/index.d.ts +2 -1
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js +4 -1
  252. package/dist/index.js.map +1 -1
  253. package/dist/main.d.ts.map +1 -1
  254. package/dist/main.js +5 -6
  255. package/dist/main.js.map +1 -1
  256. package/dist/modes/interactive/chat-input-actions.d.ts +24 -0
  257. package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -0
  258. package/dist/modes/interactive/chat-input-actions.js +179 -0
  259. package/dist/modes/interactive/chat-input-actions.js.map +1 -0
  260. package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -0
  261. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  262. package/dist/modes/interactive/components/chat-message-renderer.js +14 -3
  263. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  264. package/dist/modes/interactive/components/chat-session-host.d.ts +157 -0
  265. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -0
  266. package/dist/modes/interactive/components/chat-session-host.js +1007 -0
  267. package/dist/modes/interactive/components/chat-session-host.js.map +1 -0
  268. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  269. package/dist/modes/interactive/components/config-selector.js +1 -1
  270. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  271. package/dist/modes/interactive/components/footer.d.ts +1 -0
  272. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  273. package/dist/modes/interactive/components/footer.js +14 -5
  274. package/dist/modes/interactive/components/footer.js.map +1 -1
  275. package/dist/modes/interactive/components/index.d.ts +1 -0
  276. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  277. package/dist/modes/interactive/components/index.js +1 -0
  278. package/dist/modes/interactive/components/index.js.map +1 -1
  279. package/dist/modes/interactive/components/login-dialog.d.ts +9 -1
  280. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/login-dialog.js +29 -4
  282. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  283. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  284. package/dist/modes/interactive/interactive-mode.js +18 -67
  285. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  286. package/dist/utils/child-process.d.ts +1 -0
  287. package/dist/utils/child-process.d.ts.map +1 -1
  288. package/dist/utils/child-process.js +8 -0
  289. package/dist/utils/child-process.js.map +1 -1
  290. package/dist/utils/clipboard-native.d.ts +3 -1
  291. package/dist/utils/clipboard-native.d.ts.map +1 -1
  292. package/dist/utils/clipboard-native.js +14 -8
  293. package/dist/utils/clipboard-native.js.map +1 -1
  294. package/dist/utils/image-resize-core.d.ts +30 -0
  295. package/dist/utils/image-resize-core.d.ts.map +1 -0
  296. package/dist/utils/image-resize-core.js +124 -0
  297. package/dist/utils/image-resize-core.js.map +1 -0
  298. package/dist/utils/image-resize-worker.d.ts +2 -0
  299. package/dist/utils/image-resize-worker.d.ts.map +1 -0
  300. package/dist/utils/image-resize-worker.js +31 -0
  301. package/dist/utils/image-resize-worker.js.map +1 -0
  302. package/dist/utils/image-resize.d.ts +7 -27
  303. package/dist/utils/image-resize.d.ts.map +1 -1
  304. package/dist/utils/image-resize.js +75 -115
  305. package/dist/utils/image-resize.js.map +1 -1
  306. package/dist/utils/paths.d.ts +16 -1
  307. package/dist/utils/paths.d.ts.map +1 -1
  308. package/dist/utils/paths.js +49 -7
  309. package/dist/utils/paths.js.map +1 -1
  310. package/docs/changelog.mdx +29 -0
  311. package/docs/compaction.md +1 -1
  312. package/docs/custom-provider.md +2 -2
  313. package/docs/development.md +1 -1
  314. package/docs/docs.json +98 -143
  315. package/docs/extensions.md +29 -16
  316. package/docs/favicon.svg +29 -0
  317. package/docs/images/interactive-mode.png +0 -0
  318. package/docs/images/tree-view.png +0 -0
  319. package/docs/images/workflow-command.png +0 -0
  320. package/docs/images/workflow-graph.png +0 -0
  321. package/docs/images/workflow-input-picker.png +0 -0
  322. package/docs/images/workflow-list.png +0 -0
  323. package/docs/index.md +10 -1
  324. package/docs/logo.svg +59 -0
  325. package/docs/packages.md +3 -3
  326. package/docs/providers.md +1 -1
  327. package/docs/quickstart.md +98 -2
  328. package/docs/rpc.md +8 -8
  329. package/docs/sdk.md +23 -12
  330. package/docs/sessions.md +1 -1
  331. package/docs/skills.md +15 -1
  332. package/docs/termux.md +11 -1
  333. package/docs/themes.md +6 -6
  334. package/docs/tui.md +18 -18
  335. package/docs/usage.md +1 -1
  336. package/docs/workflows.md +172 -2
  337. package/examples/extensions/subagent/index.ts +2 -1
  338. package/package.json +6 -6
  339. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/SKILL.md +0 -0
  340. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/element-attributes.md +0 -0
  341. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/playwright-tests.md +0 -0
  342. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/request-mocking.md +0 -0
  343. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/running-code.md +0 -0
  344. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/session-management.md +0 -0
  345. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/spec-driven-testing.md +0 -0
  346. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/storage-state.md +0 -0
  347. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/test-generation.md +0 -0
  348. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/tracing.md +0 -0
  349. /package/dist/builtin/{workflows → subagents}/skills/playwright-cli/references/video-recording.md +0 -0
  350. /package/dist/builtin/{workflows → subagents}/skills/tdd/SKILL.md +0 -0
  351. /package/dist/builtin/{workflows → subagents}/skills/tdd/deep-modules.md +0 -0
  352. /package/dist/builtin/{workflows → subagents}/skills/tdd/interface-design.md +0 -0
  353. /package/dist/builtin/{workflows → subagents}/skills/tdd/mocking.md +0 -0
  354. /package/dist/builtin/{workflows → subagents}/skills/tdd/refactoring.md +0 -0
  355. /package/dist/builtin/{workflows → subagents}/skills/tdd/tests.md +0 -0
@@ -0,0 +1,1007 @@
1
+ import { Spacer, Text, matchesKey as tuiMatchesKey, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
2
+ import { SessionManager } from "../../../core/session-manager.js";
3
+ import { CustomEditor } from "./custom-editor.js";
4
+ import { LiveChatEntriesController, renderChatMessageEntry, } from "./chat-message-renderer.js";
5
+ import { ChatTranscriptComponent, ScrollableComponentViewport, } from "./chat-transcript.js";
6
+ import { UsageMeterComponent, FooterComponent } from "./footer.js";
7
+ import { WorkingStatusComponent } from "./working-status.js";
8
+ import { combineQueuedMessagesForEditor, openExternalEditorForText, pasteClipboardImageToEditor, } from "../chat-input-actions.js";
9
+ import { pickWhimsicalWorkingMessage } from "../whimsical-messages.js";
10
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
11
+ const ANIMATION_FRAME_MS = 80;
12
+ const STREAMING_RENDER_THROTTLE_MS = 80;
13
+ const STREAMING_TEXT_TAIL_LINES = 240;
14
+ const STREAMING_TEXT_TAIL_CHARS = 16_000;
15
+ export class ChatSessionHost {
16
+ constructor(opts) {
17
+ this.focused = true;
18
+ this.inputBuffer = "";
19
+ this.transcript = [];
20
+ this.statusMessage = "";
21
+ this.isBashMode = false;
22
+ this.localBashRunning = false;
23
+ this.sdkBusy = false;
24
+ this.pendingSteeringMessages = [];
25
+ this.pendingFollowUpMessages = [];
26
+ this.compactionQueuedMessages = [];
27
+ this.compacting = false;
28
+ this.bodyViewport = new ScrollableComponentViewport();
29
+ this.optimisticUserSignatureCounts = new Map();
30
+ this.style = opts.style;
31
+ this.commands = opts.commands ?? {};
32
+ this.requestRender = opts.requestRender;
33
+ this.getAgentSession = opts.getAgentSession;
34
+ this.isStreamingOverride = opts.isStreaming;
35
+ this.isPaused = opts.isPaused;
36
+ this.isDisabled = opts.isDisabled;
37
+ this.isBashRunningOverride = opts.isBashRunning;
38
+ this.showWarning = opts.showWarning;
39
+ this.showStatus = opts.showStatus;
40
+ this.actions = opts.actions;
41
+ this.getActionKeyDisplay = opts.getActionKeyDisplay;
42
+ this.getMarkdownTheme = opts.getMarkdownTheme;
43
+ this.getChatRenderSettings = opts.getChatRenderSettings;
44
+ this.getCwd = opts.getCwd;
45
+ this.footerData = opts.footerData;
46
+ this.renderExtraEntry = opts.renderExtraEntry;
47
+ this.tui = opts.tui;
48
+ this.liveChat = new LiveChatEntriesController(this.transcript);
49
+ this.editor = this.createEditor(opts.tui, opts.keybindings, opts.editorTheme, opts.editorFactory);
50
+ this.syncAnimationTick();
51
+ }
52
+ appendMessages(messages) {
53
+ this.liveChat.appendMessages(messages);
54
+ }
55
+ loadSessionFile(sessionFile) {
56
+ if (this.transcript.length > 0 || sessionFile === undefined)
57
+ return;
58
+ let messages;
59
+ try {
60
+ messages = SessionManager.open(sessionFile).buildSessionContext()
61
+ .messages;
62
+ }
63
+ catch {
64
+ return;
65
+ }
66
+ this.liveChat.appendMessages(messages);
67
+ }
68
+ appendExtraEntry(entry) {
69
+ this.transcript.push(entry);
70
+ }
71
+ entries() {
72
+ return this.transcript;
73
+ }
74
+ incrementOptimisticUserSignature(signature) {
75
+ this.optimisticUserSignatureCounts.set(signature, (this.optimisticUserSignatureCounts.get(signature) ?? 0) + 1);
76
+ }
77
+ decrementOptimisticUserSignature(signature) {
78
+ const count = this.optimisticUserSignatureCounts.get(signature) ?? 0;
79
+ if (count <= 1)
80
+ this.optimisticUserSignatureCounts.delete(signature);
81
+ else
82
+ this.optimisticUserSignatureCounts.set(signature, count - 1);
83
+ }
84
+ applyAgentEvent(event) {
85
+ const type = String(event.type ?? "");
86
+ if (type === "message_start") {
87
+ const message = event.message;
88
+ if (isUserMessageLike(message)) {
89
+ const signature = userMessageSignature(extractMessageText(message.content));
90
+ const count = this.optimisticUserSignatureCounts.get(signature) ?? 0;
91
+ if (count > 0) {
92
+ this.decrementOptimisticUserSignature(signature);
93
+ return false;
94
+ }
95
+ }
96
+ }
97
+ if (isSharedLiveChatEvent(type)) {
98
+ const changed = this.liveChat.applyEvent(event);
99
+ const toolCallEvent = assistantToolCallEvent(event);
100
+ const changedByToolCall = toolCallEvent !== undefined
101
+ ? this.liveChat.applyEvent(toolCallEvent)
102
+ : false;
103
+ this.afterEvent(changed || changedByToolCall);
104
+ return changed || changedByToolCall;
105
+ }
106
+ let changed = false;
107
+ switch (type) {
108
+ case "agent_start":
109
+ this.sdkBusy = true;
110
+ this.liveChat.clearPendingTools();
111
+ this.statusMessage = "";
112
+ changed = true;
113
+ break;
114
+ case "agent_end":
115
+ this.sdkBusy = false;
116
+ this.workingMessage = undefined;
117
+ this.liveChat.clearPendingTools();
118
+ this.statusMessage = "";
119
+ changed = true;
120
+ break;
121
+ case "turn_start":
122
+ this.workingMessage = pickWhimsicalWorkingMessage();
123
+ changed = true;
124
+ break;
125
+ case "turn_end":
126
+ this.workingMessage = undefined;
127
+ changed = true;
128
+ break;
129
+ case "queue_update": {
130
+ const queue = event;
131
+ this.pendingSteeringMessages = Array.isArray(queue.steering)
132
+ ? queue.steering.filter((item) => typeof item === "string")
133
+ : [];
134
+ this.pendingFollowUpMessages = Array.isArray(queue.followUp)
135
+ ? queue.followUp.filter((item) => typeof item === "string")
136
+ : [];
137
+ changed = true;
138
+ break;
139
+ }
140
+ case "tool_call":
141
+ case "tool_use":
142
+ changed = this.liveChat.applyEvent(legacyToolStartEvent(event));
143
+ break;
144
+ case "tool_result":
145
+ changed = this.liveChat.applyEvent(legacyToolResultEvent(event));
146
+ break;
147
+ case "thinking_delta":
148
+ case "thinking":
149
+ changed = this.liveChat.applyEvent(legacyThinkingEvent(event));
150
+ break;
151
+ case "compaction_start":
152
+ this.compacting = true;
153
+ this.sdkBusy = true;
154
+ this.statusMessage = "compacting context…";
155
+ changed = true;
156
+ break;
157
+ case "compaction_end": {
158
+ const compaction = event;
159
+ this.compacting = false;
160
+ this.sdkBusy = false;
161
+ this.statusMessage = compaction.errorMessage ?? "";
162
+ if (!compaction.aborted && !compaction.errorMessage && this.compactionQueuedMessages.length > 0) {
163
+ void this.flushCompactionQueue();
164
+ }
165
+ changed = true;
166
+ break;
167
+ }
168
+ case "auto_retry_start":
169
+ this.sdkBusy = true;
170
+ this.statusMessage = "retrying…";
171
+ changed = true;
172
+ break;
173
+ case "auto_retry_end": {
174
+ const retry = event;
175
+ this.statusMessage = "";
176
+ if (!retry.success) {
177
+ this.sdkBusy = false;
178
+ this.workingMessage = undefined;
179
+ }
180
+ changed = true;
181
+ break;
182
+ }
183
+ default:
184
+ changed = false;
185
+ }
186
+ this.afterEvent(changed);
187
+ return changed;
188
+ }
189
+ render(width) {
190
+ return this.renderBody(width, 1);
191
+ }
192
+ invalidate() { }
193
+ renderBody(width, budget) {
194
+ const components = [];
195
+ if (this.transcript.length > 0) {
196
+ components.push(new ChatTranscriptComponent(this.transcript, (entry) => this.renderEntry(entry)));
197
+ }
198
+ if (this.statusMessage) {
199
+ components.push(new Spacer(1));
200
+ components.push(new Text(this.style.dim(this.statusMessage), 2, 0));
201
+ }
202
+ this.bodyViewport.setVisibleRows(budget);
203
+ this.bodyViewport.setComponents(components);
204
+ return this.bodyViewport.render(width);
205
+ }
206
+ renderPendingMessages(width) {
207
+ if (this.pendingSteeringMessages.length === 0 &&
208
+ this.pendingFollowUpMessages.length === 0 &&
209
+ this.compactionQueuedMessages.length === 0) {
210
+ return [];
211
+ }
212
+ const lines = [this.style.blank(width)];
213
+ for (const message of this.pendingSteeringMessages) {
214
+ lines.push(...this.pendingMessageLine(width, "Steering", message));
215
+ }
216
+ for (const message of this.pendingFollowUpMessages) {
217
+ lines.push(...this.pendingMessageLine(width, "Follow-up", message));
218
+ }
219
+ for (const message of this.compactionQueuedMessages) {
220
+ lines.push(...this.pendingMessageLine(width, "Queued", message));
221
+ }
222
+ const hint = this.getActionKeyDisplay?.("app.message.dequeue") ?? "alt+up";
223
+ lines.push(...new Text(this.style.dim(`↳ ${hint} to edit all queued messages`), 1, 0).render(width));
224
+ return lines;
225
+ }
226
+ renderWorkingStatus(width) {
227
+ if (!this.isStreaming())
228
+ return [];
229
+ const message = this.workingMessage ?? "Working...";
230
+ return new WorkingStatusComponent({
231
+ spinner: spinnerFrame(),
232
+ message,
233
+ spinnerColor: (text) => this.style.accentBold(text),
234
+ messageColor: (text) => this.style.textMuted(text),
235
+ }).render(width);
236
+ }
237
+ renderUsage(width) {
238
+ const agentSession = this.getAgentSession?.();
239
+ if (!agentSession)
240
+ return [];
241
+ return new UsageMeterComponent(agentSession).render(width);
242
+ }
243
+ renderEditor(width) {
244
+ const disabled = this.isDisabled?.() === true;
245
+ const agentSession = this.getAgentSession?.();
246
+ const ruleHex = this.style.editorRuleColor(disabled, agentSession, {
247
+ isBashMode: this.isBashMode,
248
+ });
249
+ if (!disabled && this.editor) {
250
+ setEditorFocused(this.editor, this.focused);
251
+ setEditorPlaceholder(this.editor, undefined);
252
+ setEditorBorderColor(this.editor, (text) => this.style.rule(ruleHex, text));
253
+ return this.editor.render(width);
254
+ }
255
+ if (this.editor)
256
+ setEditorFocused(this.editor, false);
257
+ const rule = this.style.rule(ruleHex, "─".repeat(width));
258
+ const available = Math.max(1, width - 3);
259
+ const value = this.inputBuffer
260
+ ? this.style.text(truncateToWidth(this.inputBuffer, available)) + this.style.cursor()
261
+ : disabled
262
+ ? ""
263
+ : this.style.cursor();
264
+ const left = this.style.accentBold("❯") + " " + value;
265
+ const gap = Math.max(0, width - visibleWidth(stripAnsi(left)));
266
+ const body = left + " ".repeat(gap);
267
+ return [rule, body, rule];
268
+ }
269
+ renderFooter(width) {
270
+ const agentSession = this.getAgentSession?.();
271
+ if (agentSession && this.footerData) {
272
+ return new FooterComponent(agentSession, this.footerData).render(width);
273
+ }
274
+ return [];
275
+ }
276
+ handleScrollInput(data) {
277
+ return this.bodyViewport.handleInput(data);
278
+ }
279
+ handleInput(data) {
280
+ if (this.handleScrollInput(data))
281
+ return true;
282
+ if (matchesKey(data, "alt+up")) {
283
+ this.restoreQueuedMessagesToEditor();
284
+ return true;
285
+ }
286
+ if (matchesKey(data, "ctrl+f")) {
287
+ void this.submit("followUp");
288
+ return true;
289
+ }
290
+ if (matchesKey(data, "escape")) {
291
+ if (this.compacting) {
292
+ void this.abortCompaction();
293
+ return true;
294
+ }
295
+ if (this.isStreaming()) {
296
+ void this.interrupt();
297
+ return true;
298
+ }
299
+ if (this.isBashRunning()) {
300
+ void this.abortBash();
301
+ return true;
302
+ }
303
+ if (this.isBashMode) {
304
+ this.setEditorText("");
305
+ this.notifyStatus("Bash mode cleared");
306
+ return true;
307
+ }
308
+ }
309
+ if (this.editor) {
310
+ this.editor.handleInput(data);
311
+ return true;
312
+ }
313
+ if (matchesKey(data, "enter")) {
314
+ void this.submit("auto");
315
+ return true;
316
+ }
317
+ if (matchesKey(data, "backspace")) {
318
+ this.setEditorText(this.inputBuffer.slice(0, -1));
319
+ return true;
320
+ }
321
+ if (data.length === 1 && data >= " " && data <= "~") {
322
+ this.setEditorText(`${this.inputBuffer}${data}`);
323
+ return true;
324
+ }
325
+ return false;
326
+ }
327
+ async interrupt() {
328
+ try {
329
+ this.restoreQueuedMessagesToEditor();
330
+ this.sdkBusy = false;
331
+ this.workingMessage = undefined;
332
+ await this.commands.interrupt?.();
333
+ }
334
+ catch (err) {
335
+ this.statusMessage = errorMessage(err);
336
+ }
337
+ finally {
338
+ this.syncAnimationTick();
339
+ this.requestRender?.();
340
+ }
341
+ }
342
+ async submit(mode = "auto", submittedText) {
343
+ const text = (submittedText ?? this.inputBuffer).trim();
344
+ if (!text)
345
+ return;
346
+ if (text.startsWith("/") && this.commands.handleSlashCommand) {
347
+ const handled = await this.commands.handleSlashCommand(text);
348
+ if (handled) {
349
+ this.setEditorText("");
350
+ this.requestRender?.();
351
+ return;
352
+ }
353
+ }
354
+ if (this.compacting) {
355
+ this.setEditorText("");
356
+ this.compactionQueuedMessages = [...this.compactionQueuedMessages, text];
357
+ this.notifyStatus("Queued message until compaction completes");
358
+ return;
359
+ }
360
+ const bash = parseBashInput(text);
361
+ if (bash?.command) {
362
+ if (this.isBashRunning()) {
363
+ this.notifyWarning("A bash command is already running. esc cancel first.");
364
+ this.setEditorText(text);
365
+ return;
366
+ }
367
+ this.setEditorText("");
368
+ await this.runBashCommand(bash.command, bash.excludeFromContext);
369
+ return;
370
+ }
371
+ this.setEditorText("");
372
+ const isPaused = this.isPaused?.() === true;
373
+ const isStreaming = this.isStreaming();
374
+ const shouldAppendOptimisticUser = mode === "auto" && !isStreaming;
375
+ const optimisticSignature = shouldAppendOptimisticUser
376
+ ? userMessageSignature(text)
377
+ : undefined;
378
+ if (optimisticSignature !== undefined) {
379
+ this.liveChat.appendUserText(text);
380
+ this.bodyViewport.scrollToBottom();
381
+ this.incrementOptimisticUserSignature(optimisticSignature);
382
+ }
383
+ this.requestRender?.();
384
+ try {
385
+ if (isPaused) {
386
+ this.sdkBusy = true;
387
+ this.statusMessage = "resuming…";
388
+ this.syncAnimationTick();
389
+ this.requestRender?.();
390
+ await this.requiredCommand("resume")(text);
391
+ this.sdkBusy = false;
392
+ this.statusMessage = "";
393
+ this.syncAnimationTick();
394
+ return;
395
+ }
396
+ if (mode === "followUp" && isStreaming) {
397
+ await this.queueFollowUp(text);
398
+ return;
399
+ }
400
+ if (isStreaming) {
401
+ await this.queueSteer(text);
402
+ }
403
+ else {
404
+ this.sdkBusy = true;
405
+ this.syncAnimationTick();
406
+ await this.commands.ensureAttached?.();
407
+ await this.requiredCommand("prompt")(text);
408
+ this.sdkBusy = false;
409
+ this.syncAnimationTick();
410
+ }
411
+ }
412
+ catch (err) {
413
+ if (optimisticSignature !== undefined) {
414
+ this.decrementOptimisticUserSignature(optimisticSignature);
415
+ }
416
+ this.sdkBusy = false;
417
+ this.statusMessage = errorMessage(err);
418
+ this.syncAnimationTick();
419
+ this.requestRender?.();
420
+ }
421
+ }
422
+ isStreaming() {
423
+ return this.sdkBusy || this.isStreamingOverride?.() === true;
424
+ }
425
+ isBashRunning() {
426
+ return this.localBashRunning || this.isBashRunningOverride?.() === true;
427
+ }
428
+ isEditingBashCommand() {
429
+ return this.isBashMode;
430
+ }
431
+ hasInputText() {
432
+ return this.inputBuffer.length > 0;
433
+ }
434
+ hasAnimationTick() {
435
+ return this.animationTimer !== undefined;
436
+ }
437
+ bodyScrollFromBottom() {
438
+ return this.bodyViewport.getScrollFromBottom();
439
+ }
440
+ bodyMaxScroll() {
441
+ return this.bodyViewport.getMaxScroll();
442
+ }
443
+ inputText() {
444
+ return this.inputBuffer;
445
+ }
446
+ statusText() {
447
+ return this.statusMessage;
448
+ }
449
+ scrollToBottom() {
450
+ this.bodyViewport.scrollToBottom();
451
+ }
452
+ syncAnimationTick() {
453
+ const shouldAnimate = this.isStreaming() || (this.sdkBusy && this.liveChat.pendingToolIds().length > 0);
454
+ if (shouldAnimate && !this.animationTimer) {
455
+ this.animationTimer = setInterval(() => {
456
+ this.requestRender?.();
457
+ }, ANIMATION_FRAME_MS);
458
+ this.animationTimer.unref?.();
459
+ return;
460
+ }
461
+ if (!shouldAnimate && this.animationTimer) {
462
+ clearInterval(this.animationTimer);
463
+ this.animationTimer = undefined;
464
+ }
465
+ }
466
+ dispose() {
467
+ if (this.animationTimer) {
468
+ clearInterval(this.animationTimer);
469
+ this.animationTimer = undefined;
470
+ }
471
+ if (this.renderThrottleTimer) {
472
+ clearTimeout(this.renderThrottleTimer);
473
+ this.renderThrottleTimer = undefined;
474
+ }
475
+ this.editor = undefined;
476
+ }
477
+ createEditor(tui, keybindings, editorTheme, editorFactory) {
478
+ if (!tui || !keybindings)
479
+ return undefined;
480
+ const editor = this.createInheritedEditor(tui, editorTheme, keybindings, editorFactory) ??
481
+ new CustomEditor(tui, editorTheme, keybindings, { paddingX: 0, autocompleteMaxVisible: 5 });
482
+ editor.onChange = (text) => {
483
+ this.inputBuffer = text;
484
+ this.isBashMode = text.trimStart().startsWith("!");
485
+ };
486
+ editor.onSubmit = (text) => {
487
+ void this.submit("auto", text);
488
+ };
489
+ const actionEditor = editor;
490
+ actionEditor.onAction?.("app.message.followUp", () => {
491
+ void this.submit("followUp");
492
+ });
493
+ actionEditor.onAction?.("app.message.dequeue", () => {
494
+ this.restoreQueuedMessagesToEditor();
495
+ });
496
+ actionEditor.onAction?.("app.editor.external", () => {
497
+ this.openExternalEditor();
498
+ });
499
+ if (this.actions) {
500
+ for (const [action, handler] of Object.entries(this.actions)) {
501
+ actionEditor.onAction?.(action, () => {
502
+ void handler();
503
+ });
504
+ }
505
+ }
506
+ const previousPasteImage = actionEditor.onPasteImage;
507
+ actionEditor.onPasteImage = () => {
508
+ previousPasteImage?.();
509
+ void pasteClipboardImageToEditor(this.editorAccess(), () => this.requestRender?.(), { showWarning: (message) => this.notifyWarning(message) });
510
+ };
511
+ const previousEscape = actionEditor.onEscape;
512
+ actionEditor.onEscape = () => {
513
+ if (this.compacting) {
514
+ void this.abortCompaction();
515
+ return;
516
+ }
517
+ if (this.isStreaming()) {
518
+ void this.interrupt();
519
+ return;
520
+ }
521
+ if (this.isBashRunning()) {
522
+ void this.abortBash();
523
+ return;
524
+ }
525
+ if (this.isBashMode) {
526
+ this.setEditorText("");
527
+ this.notifyStatus("Bash mode cleared");
528
+ return;
529
+ }
530
+ previousEscape?.();
531
+ };
532
+ return editor;
533
+ }
534
+ createInheritedEditor(tui, editorTheme, keybindings, editorFactory) {
535
+ if (!editorFactory)
536
+ return undefined;
537
+ try {
538
+ return editorFactory(tui, editorTheme, keybindings);
539
+ }
540
+ catch {
541
+ return undefined;
542
+ }
543
+ }
544
+ editorAccess() {
545
+ return {
546
+ insertTextAtCursor: (text) => {
547
+ if (this.editor?.insertTextAtCursor) {
548
+ this.editor.insertTextAtCursor(text);
549
+ return;
550
+ }
551
+ this.setEditorText(`${this.inputBuffer}${text}`);
552
+ },
553
+ getText: () => this.inputBuffer,
554
+ setText: (text) => this.setEditorText(text),
555
+ };
556
+ }
557
+ openExternalEditor() {
558
+ if (!this.editor)
559
+ return;
560
+ const host = this.tuiHost();
561
+ if (!host)
562
+ return;
563
+ const currentText = this.editor.getExpandedText?.() ?? this.editor.getText();
564
+ const updated = openExternalEditorForText(currentText, host, {
565
+ showWarning: (message) => this.notifyWarning(message),
566
+ });
567
+ if (updated !== undefined)
568
+ this.setEditorText(updated);
569
+ }
570
+ tuiHost() {
571
+ return this.tui;
572
+ }
573
+ setEditorText(text) {
574
+ this.inputBuffer = text;
575
+ this.isBashMode = text.trimStart().startsWith("!");
576
+ this.editor?.setText(text);
577
+ }
578
+ renderEntry(entry) {
579
+ if (isChatMessageEntry(entry)) {
580
+ return renderChatMessageEntry(this.streamingWindowedEntry(entry), this.chatMessageRenderOptions());
581
+ }
582
+ if (!this.renderExtraEntry) {
583
+ return new Text("", 0, 0);
584
+ }
585
+ return this.renderExtraEntry(entry);
586
+ }
587
+ streamingWindowedEntry(entry) {
588
+ if (!this.isStreaming() || this.bodyViewport.getScrollFromBottom() !== 0) {
589
+ return entry;
590
+ }
591
+ if (entry.kind !== "assistant")
592
+ return entry;
593
+ const content = entry.message.content.map((item) => {
594
+ if (item.type === "text")
595
+ return { ...item, text: tailStreamingText(item.text) };
596
+ if (item.type === "thinking")
597
+ return { ...item, thinking: tailStreamingText(item.thinking) };
598
+ return item;
599
+ });
600
+ return { ...entry, message: { ...entry.message, content } };
601
+ }
602
+ chatMessageRenderOptions() {
603
+ const inherited = this.getChatRenderSettings?.();
604
+ return {
605
+ ...inherited,
606
+ ui: this.toolTui(),
607
+ cwd: this.getCwd?.() ?? this.getAgentSession?.()?.sessionManager.getCwd() ?? process.cwd(),
608
+ markdownTheme: inherited?.markdownTheme ?? this.getMarkdownTheme?.(),
609
+ showImages: inherited?.showImages ?? true,
610
+ };
611
+ }
612
+ toolTui() {
613
+ return { requestRender: () => this.requestRender?.() };
614
+ }
615
+ pendingMessageLine(width, label, message) {
616
+ const text = `${label}: ${message}`;
617
+ return new Text(this.style.dim(truncateToWidth(text, Math.max(1, width - 2))), 1, 0).render(width);
618
+ }
619
+ async abortCompaction() {
620
+ try {
621
+ await this.commands.abortCompaction?.();
622
+ this.compacting = false;
623
+ this.sdkBusy = false;
624
+ this.notifyStatus("Compaction cancelled");
625
+ }
626
+ catch (err) {
627
+ this.notifyWarning(errorMessage(err));
628
+ }
629
+ finally {
630
+ this.syncAnimationTick();
631
+ this.requestRender?.();
632
+ }
633
+ }
634
+ async abortBash() {
635
+ try {
636
+ await this.commands.abortBash?.();
637
+ this.localBashRunning = false;
638
+ this.notifyStatus("Bash command cancelled");
639
+ }
640
+ catch (err) {
641
+ this.notifyWarning(errorMessage(err));
642
+ }
643
+ finally {
644
+ this.requestRender?.();
645
+ }
646
+ }
647
+ async runBashCommand(command, excludeFromContext) {
648
+ const runBash = this.commands.runBash;
649
+ if (!runBash) {
650
+ this.notifyWarning("no bash command configured for this chat session");
651
+ return;
652
+ }
653
+ const bashMessage = {
654
+ role: "bashExecution",
655
+ command,
656
+ output: "",
657
+ exitCode: undefined,
658
+ cancelled: false,
659
+ truncated: false,
660
+ timestamp: Date.now(),
661
+ ...(excludeFromContext ? { excludeFromContext: true } : {}),
662
+ };
663
+ const bashEntry = {
664
+ role: "tool",
665
+ kind: "bashExecution",
666
+ message: bashMessage,
667
+ isPartial: true,
668
+ };
669
+ this.transcript.push(bashEntry);
670
+ this.localBashRunning = true;
671
+ this.bodyViewport.scrollToBottom();
672
+ this.requestRender?.();
673
+ try {
674
+ const result = await runBash({
675
+ command,
676
+ excludeFromContext,
677
+ onChunk: (chunk) => {
678
+ bashMessage.output += chunk;
679
+ this.requestRender?.();
680
+ },
681
+ });
682
+ bashMessage.output = result.output;
683
+ bashMessage.exitCode = result.exitCode;
684
+ bashMessage.cancelled = result.cancelled;
685
+ bashMessage.truncated = result.truncated;
686
+ if (result.fullOutputPath !== undefined) {
687
+ bashMessage.fullOutputPath = result.fullOutputPath;
688
+ }
689
+ }
690
+ catch (err) {
691
+ bashMessage.output = errorMessage(err);
692
+ bashMessage.exitCode = undefined;
693
+ bashMessage.cancelled = false;
694
+ bashMessage.truncated = false;
695
+ }
696
+ finally {
697
+ bashEntry.isPartial = false;
698
+ this.localBashRunning = false;
699
+ this.requestRender?.();
700
+ }
701
+ }
702
+ async flushCompactionQueue() {
703
+ const queued = [...this.compactionQueuedMessages];
704
+ this.compactionQueuedMessages = [];
705
+ if (queued.length === 0)
706
+ return;
707
+ let nextIndex = 0;
708
+ try {
709
+ const first = queued[0];
710
+ if (first !== undefined) {
711
+ await this.requiredCommand("prompt")(first);
712
+ nextIndex = 1;
713
+ }
714
+ for (; nextIndex < queued.length; nextIndex++) {
715
+ await this.queueFollowUp(queued[nextIndex]);
716
+ }
717
+ }
718
+ catch (err) {
719
+ this.compactionQueuedMessages = [
720
+ ...queued.slice(nextIndex),
721
+ ...this.compactionQueuedMessages,
722
+ ];
723
+ this.notifyWarning(errorMessage(err));
724
+ this.requestRender?.();
725
+ }
726
+ }
727
+ async queueSteer(text) {
728
+ const agentSession = this.getAgentSession?.();
729
+ if (agentSession?.isStreaming) {
730
+ await agentSession.prompt(text, { streamingBehavior: "steer" });
731
+ return;
732
+ }
733
+ await this.requiredCommand("steer")(text);
734
+ }
735
+ async queueFollowUp(text) {
736
+ const agentSession = this.getAgentSession?.();
737
+ if (agentSession?.isStreaming) {
738
+ await agentSession.prompt(text, { streamingBehavior: "followUp" });
739
+ return;
740
+ }
741
+ await this.requiredCommand("followUp")(text);
742
+ }
743
+ restoreQueuedMessagesToEditor() {
744
+ const queuedMessages = [
745
+ ...this.pendingSteeringMessages,
746
+ ...this.pendingFollowUpMessages,
747
+ ...this.compactionQueuedMessages,
748
+ ];
749
+ if (queuedMessages.length === 0) {
750
+ this.notifyStatus("No queued messages to restore");
751
+ return false;
752
+ }
753
+ const restoredText = combineQueuedMessagesForEditor(queuedMessages, this.inputBuffer);
754
+ this.pendingSteeringMessages = [];
755
+ this.pendingFollowUpMessages = [];
756
+ this.compactionQueuedMessages = [];
757
+ this.setEditorText(restoredText);
758
+ this.getAgentSession?.()?.clearQueue();
759
+ this.notifyStatus(`Restored ${queuedMessages.length} queued message${queuedMessages.length === 1 ? "" : "s"} to editor`);
760
+ this.requestRender?.();
761
+ return true;
762
+ }
763
+ notifyWarning(message) {
764
+ this.statusMessage = message;
765
+ this.showWarning?.(message);
766
+ this.requestRender?.();
767
+ }
768
+ notifyStatus(message) {
769
+ this.statusMessage = message;
770
+ this.showStatus?.(message);
771
+ this.requestRender?.();
772
+ }
773
+ requiredCommand(name) {
774
+ switch (name) {
775
+ case "prompt":
776
+ return async (text) => {
777
+ if (!this.commands.prompt)
778
+ throw new Error("no prompt command configured for this chat session");
779
+ await this.commands.prompt(text ?? "");
780
+ };
781
+ case "steer":
782
+ return async (text) => {
783
+ if (!this.commands.steer)
784
+ throw new Error("no steer command configured for this chat session");
785
+ await this.commands.steer(text ?? "");
786
+ };
787
+ case "followUp":
788
+ return async (text) => {
789
+ if (!this.commands.followUp)
790
+ throw new Error("no followUp command configured for this chat session");
791
+ await this.commands.followUp(text ?? "");
792
+ };
793
+ case "resume":
794
+ return async (text) => {
795
+ if (!this.commands.resume)
796
+ throw new Error("no resume command configured for this chat session");
797
+ await this.commands.resume(text);
798
+ };
799
+ }
800
+ }
801
+ afterEvent(changed) {
802
+ this.syncAnimationTick();
803
+ if (!changed)
804
+ return;
805
+ this.requestEventRender();
806
+ }
807
+ requestEventRender() {
808
+ if (!this.isStreaming()) {
809
+ this.requestRender?.();
810
+ return;
811
+ }
812
+ if (this.renderThrottleTimer)
813
+ return;
814
+ this.renderThrottleTimer = setTimeout(() => {
815
+ this.renderThrottleTimer = undefined;
816
+ this.requestRender?.();
817
+ }, STREAMING_RENDER_THROTTLE_MS);
818
+ this.renderThrottleTimer.unref?.();
819
+ }
820
+ }
821
+ function setEditorPlaceholder(editor, placeholder) {
822
+ const candidate = editor;
823
+ candidate.setPlaceholder?.(placeholder);
824
+ }
825
+ function setEditorBorderColor(editor, borderColor) {
826
+ const candidate = editor;
827
+ if (candidate.borderColor !== undefined)
828
+ candidate.borderColor = borderColor;
829
+ }
830
+ function setEditorFocused(editor, focused) {
831
+ const candidate = editor;
832
+ if ("focused" in candidate)
833
+ candidate.focused = focused;
834
+ }
835
+ function matchesKey(data, key) {
836
+ if (key === "enter" && (data === "\r" || data === "\n"))
837
+ return true;
838
+ if (key === "backspace" && (data === "\x7f" || data === "\b"))
839
+ return true;
840
+ if (key === "escape" && data === "\x1b")
841
+ return true;
842
+ if (key === "ctrl+f" && data === "\x06")
843
+ return true;
844
+ return tuiMatchesKey(data, key);
845
+ }
846
+ function parseBashInput(text) {
847
+ if (!text.startsWith("!"))
848
+ return undefined;
849
+ const excludeFromContext = text.startsWith("!!");
850
+ const command = text.slice(excludeFromContext ? 2 : 1).trim();
851
+ return { command, excludeFromContext };
852
+ }
853
+ function isSharedLiveChatEvent(type) {
854
+ return (type === "message_start" ||
855
+ type === "message_update" ||
856
+ type === "message_end" ||
857
+ type === "tool_execution_start" ||
858
+ type === "tool_execution_update" ||
859
+ type === "tool_execution_end");
860
+ }
861
+ function isChatMessageEntry(entry) {
862
+ if (!("role" in entry) || !("kind" in entry))
863
+ return false;
864
+ const candidate = entry;
865
+ switch (candidate.kind) {
866
+ case "assistant":
867
+ return candidate.role === "assistant" && candidate.message !== undefined;
868
+ case "tool":
869
+ return candidate.role === "tool" && "toolName" in candidate && "toolCallId" in candidate && "args" in candidate;
870
+ case "bashExecution":
871
+ return candidate.role === "tool" && candidate.message !== undefined;
872
+ case "user":
873
+ return candidate.role === "user" && typeof candidate.text === "string";
874
+ case "custom":
875
+ return candidate.role === "custom" && candidate.message !== undefined;
876
+ case "branchSummary":
877
+ case "compactionSummary":
878
+ return candidate.role === "summary" && candidate.message !== undefined;
879
+ case "system":
880
+ return candidate.role === "system" && candidate.message !== undefined;
881
+ default:
882
+ return false;
883
+ }
884
+ }
885
+ function isMessageLike(message) {
886
+ return message !== null && typeof message === "object" && "role" in message;
887
+ }
888
+ function isUserMessageLike(message) {
889
+ return isMessageLike(message) && message.role === "user";
890
+ }
891
+ function userMessageSignature(text) {
892
+ return text.trim();
893
+ }
894
+ function assistantToolCallEvent(event) {
895
+ const assistantEvent = event.assistantMessageEvent;
896
+ const streamType = String(assistantEvent?.type ?? "");
897
+ if (!streamType.startsWith("toolcall_"))
898
+ return undefined;
899
+ const explicit = toolCallPayload(assistantEvent?.toolCall);
900
+ if (explicit)
901
+ return explicit;
902
+ const contentIndex = typeof assistantEvent?.contentIndex === "number" ? assistantEvent.contentIndex : undefined;
903
+ if (contentIndex === undefined)
904
+ return undefined;
905
+ const partial = assistantEvent?.partial;
906
+ if (!isMessageLike(partial) || partial.role !== "assistant")
907
+ return undefined;
908
+ const content = partial.content;
909
+ if (!Array.isArray(content))
910
+ return undefined;
911
+ return toolCallPayload(content[contentIndex]);
912
+ }
913
+ function toolCallPayload(value) {
914
+ if (value === null || typeof value !== "object")
915
+ return undefined;
916
+ const candidate = value;
917
+ if (candidate.type !== "toolCall")
918
+ return undefined;
919
+ if (typeof candidate.id !== "string" || typeof candidate.name !== "string")
920
+ return undefined;
921
+ return {
922
+ type: "tool_execution_start",
923
+ toolCallId: candidate.id,
924
+ toolName: candidate.name,
925
+ args: candidate.arguments ?? {},
926
+ };
927
+ }
928
+ function legacyToolStartEvent(event) {
929
+ const payload = event;
930
+ const toolName = typeof payload.name === "string" ? payload.name : "tool";
931
+ const toolCallId = typeof payload.toolCallId === "string" ? payload.toolCallId : `live-${toolName}`;
932
+ return {
933
+ type: "tool_execution_start",
934
+ toolCallId,
935
+ toolName,
936
+ args: payload.input ?? payload.args ?? {},
937
+ };
938
+ }
939
+ function legacyToolResultEvent(event) {
940
+ const payload = event;
941
+ const toolName = typeof payload.name === "string" ? payload.name : "tool";
942
+ const toolCallId = typeof payload.toolCallId === "string" ? payload.toolCallId : `live-${toolName}`;
943
+ const output = payload.output;
944
+ return {
945
+ type: "tool_execution_end",
946
+ toolCallId,
947
+ toolName,
948
+ result: output !== null && typeof output === "object" && "content" in output
949
+ ? output
950
+ : { content: typeof output === "string" ? [{ type: "text", text: output }] : [] },
951
+ isError: payload.isError === true,
952
+ };
953
+ }
954
+ function legacyThinkingEvent(event) {
955
+ const delta = String(event.delta ??
956
+ event.text ??
957
+ "");
958
+ return {
959
+ type: "message_update",
960
+ assistantMessageEvent: { type: "thinking_delta", delta },
961
+ message: { role: "assistant", content: [] },
962
+ };
963
+ }
964
+ function extractMessageText(content) {
965
+ if (typeof content === "string")
966
+ return content;
967
+ if (!Array.isArray(content))
968
+ return "";
969
+ const parts = [];
970
+ for (const item of content) {
971
+ if (item == null)
972
+ continue;
973
+ if (typeof item === "string") {
974
+ parts.push(item);
975
+ continue;
976
+ }
977
+ const obj = item;
978
+ if (typeof obj.text === "string")
979
+ parts.push(obj.text);
980
+ else if (obj.type === "text" && typeof obj.text === "string")
981
+ parts.push(obj.text);
982
+ }
983
+ return parts.join("");
984
+ }
985
+ function tailStreamingText(text) {
986
+ if (text.length <= STREAMING_TEXT_TAIL_CHARS &&
987
+ text.split("\n").length <= STREAMING_TEXT_TAIL_LINES) {
988
+ return text;
989
+ }
990
+ const byChars = text.slice(-STREAMING_TEXT_TAIL_CHARS);
991
+ const lines = byChars.split("\n");
992
+ const tail = lines.length > STREAMING_TEXT_TAIL_LINES
993
+ ? lines.slice(-STREAMING_TEXT_TAIL_LINES).join("\n")
994
+ : byChars;
995
+ return `[earlier streaming output hidden while attached]\n\n${tail.trimStart()}`;
996
+ }
997
+ function spinnerFrame() {
998
+ const idx = Math.floor(Date.now() / 80) % SPINNER_FRAMES.length;
999
+ return SPINNER_FRAMES[idx];
1000
+ }
1001
+ function stripAnsi(s) {
1002
+ return s.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "");
1003
+ }
1004
+ function errorMessage(error) {
1005
+ return error instanceof Error ? error.message : String(error);
1006
+ }
1007
+ //# sourceMappingURL=chat-session-host.js.map