@bastani/atomic 0.9.13-alpha.2 → 0.9.13-alpha.4

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 (317) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/i-have-adhd/package.json +1 -1
  4. package/dist/builtin/intercom/CHANGELOG.md +14 -0
  5. package/dist/builtin/intercom/README.md +12 -12
  6. package/dist/builtin/intercom/incoming-message-delivery.ts +1 -1
  7. package/dist/builtin/intercom/index.ts +1 -1
  8. package/dist/builtin/intercom/intercom-tool.ts +1 -1
  9. package/dist/builtin/intercom/intercom-utils.ts +3 -6
  10. package/dist/builtin/intercom/package.json +1 -1
  11. package/dist/builtin/intercom/result-renderers.ts +1 -1
  12. package/dist/builtin/intercom/session-target.ts +1 -15
  13. package/dist/builtin/intercom/skills/intercom/SKILL.md +6 -6
  14. package/dist/builtin/intercom/terminal-ordering-barrier.ts +2 -2
  15. package/dist/builtin/intercom/ui/inline-message.ts +7 -5
  16. package/dist/builtin/intercom/ui/session-list.ts +23 -10
  17. package/dist/builtin/mcp/package.json +1 -1
  18. package/dist/builtin/subagents/CHANGELOG.md +19 -0
  19. package/dist/builtin/subagents/README.md +29 -73
  20. package/dist/builtin/subagents/package.json +2 -2
  21. package/dist/builtin/subagents/prompts/parallel-cleanup.md +1 -1
  22. package/dist/builtin/subagents/prompts/parallel-review.md +1 -1
  23. package/dist/builtin/subagents/prompts/review-loop.md +2 -2
  24. package/dist/builtin/subagents/skills/subagent/SKILL.md +23 -59
  25. package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
  26. package/dist/builtin/subagents/src/extension/control-notices.ts +2 -3
  27. package/dist/builtin/subagents/src/extension/doctor.ts +2 -14
  28. package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -17
  29. package/dist/builtin/subagents/src/extension/index.ts +9 -70
  30. package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
  31. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +2 -2
  32. package/dist/builtin/subagents/src/extension/schemas.ts +2 -8
  33. package/dist/builtin/subagents/src/extension/tool-description.ts +2 -3
  34. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +1 -1
  35. package/dist/builtin/subagents/src/intercom/result-intercom.ts +5 -46
  36. package/dist/builtin/subagents/src/runs/{background → foreground}/completion-notification.ts +2 -2
  37. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +25 -88
  38. package/dist/builtin/subagents/src/runs/{background → foreground}/notify.ts +5 -5
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +11 -28
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +3 -0
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +2 -0
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +0 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +30 -20
  44. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +4 -4
  45. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +0 -13
  46. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +104 -48
  47. package/dist/builtin/subagents/src/runs/inprocess/index.ts +1 -1
  48. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +5 -5
  49. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-api.ts +0 -7
  50. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-core.ts +0 -10
  51. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-projection.ts +3 -108
  52. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-sanitize.ts +0 -4
  53. package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +1 -1
  54. package/dist/builtin/subagents/src/shared/formatters.ts +3 -5
  55. package/dist/builtin/subagents/src/shared/model-resolution.ts +78 -0
  56. package/dist/builtin/subagents/src/shared/status-format.ts +4 -11
  57. package/dist/builtin/subagents/src/shared/types-config.ts +10 -9
  58. package/dist/builtin/subagents/src/shared/types-nested.ts +127 -0
  59. package/dist/builtin/subagents/src/shared/types-results.ts +2 -8
  60. package/dist/builtin/subagents/src/shared/types-runtime.ts +0 -9
  61. package/dist/builtin/subagents/src/shared/types.ts +1 -1
  62. package/dist/builtin/subagents/src/shared/utils.ts +1 -109
  63. package/dist/builtin/subagents/src/slash/slash-commands.ts +7 -17
  64. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -252
  65. package/dist/builtin/subagents/src/tui/render-layout.ts +4 -4
  66. package/dist/builtin/subagents/src/tui/render-result.ts +0 -9
  67. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -34
  68. package/dist/builtin/subagents/src/tui/render.ts +0 -2
  69. package/dist/builtin/web-access/package.json +1 -1
  70. package/dist/builtin/workflows/CHANGELOG.md +23 -0
  71. package/dist/builtin/workflows/README.md +3 -3
  72. package/dist/builtin/workflows/package.json +1 -1
  73. package/dist/builtin/workflows/src/durable/backend.ts +11 -0
  74. package/dist/builtin/workflows/src/durable/completed-catalog-stage-groups.ts +63 -25
  75. package/dist/builtin/workflows/src/durable/completed-catalog.ts +166 -25
  76. package/dist/builtin/workflows/src/durable/dbos-backend.ts +42 -24
  77. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +2 -1
  78. package/dist/builtin/workflows/src/durable/run-timing.ts +28 -7
  79. package/dist/builtin/workflows/src/durable/scoped-backend.ts +4 -0
  80. package/dist/builtin/workflows/src/durable/targeted-inspection.ts +110 -0
  81. package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +2 -2
  82. package/dist/builtin/workflows/src/engine/runtime.ts +19 -2
  83. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +3 -0
  84. package/dist/builtin/workflows/src/extension/index.bundle.mjs +750 -168
  85. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -0
  86. package/dist/builtin/workflows/src/extension/ui-surface.ts +4 -0
  87. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +6 -1
  88. package/dist/builtin/workflows/src/extension/workflow-targets.ts +18 -10
  89. package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +31 -16
  90. package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +75 -3
  91. package/dist/builtin/workflows/src/extension/workflow-tool.ts +53 -6
  92. package/dist/builtin/workflows/src/runs/background/run-inspect.ts +5 -1
  93. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +94 -60
  94. package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +1 -1
  95. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +7 -7
  96. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +25 -4
  97. package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +4 -1
  98. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +2 -0
  99. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +142 -4
  100. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +2 -0
  101. package/dist/builtin/workflows/src/runs/foreground/stage-session-heartbeat.ts +88 -0
  102. package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +1 -0
  103. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +1 -0
  104. package/dist/builtin/workflows/src/tui/run-detail.ts +25 -12
  105. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +27 -8
  106. package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +17 -1
  107. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +20 -3
  108. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +10 -1
  109. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +1 -0
  110. package/dist/core/agent-session-events.d.ts.map +1 -1
  111. package/dist/core/agent-session-events.js +22 -5
  112. package/dist/core/agent-session-events.js.map +1 -1
  113. package/dist/core/agent-session-export.d.ts.map +1 -1
  114. package/dist/core/agent-session-export.js +2 -1
  115. package/dist/core/agent-session-export.js.map +1 -1
  116. package/dist/core/agent-session-methods.d.ts +10 -4
  117. package/dist/core/agent-session-methods.d.ts.map +1 -1
  118. package/dist/core/agent-session-methods.js.map +1 -1
  119. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  120. package/dist/core/agent-session-prompt.js +68 -0
  121. package/dist/core/agent-session-prompt.js.map +1 -1
  122. package/dist/core/agent-session-queue-pause.d.ts.map +1 -1
  123. package/dist/core/agent-session-queue-pause.js +6 -0
  124. package/dist/core/agent-session-queue-pause.js.map +1 -1
  125. package/dist/core/agent-session-summary.d.ts +21 -0
  126. package/dist/core/agent-session-summary.d.ts.map +1 -0
  127. package/dist/core/agent-session-summary.js +156 -0
  128. package/dist/core/agent-session-summary.js.map +1 -0
  129. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  130. package/dist/core/agent-session-tool-registry.js +0 -4
  131. package/dist/core/agent-session-tool-registry.js.map +1 -1
  132. package/dist/core/agent-session-transfer.d.ts.map +1 -1
  133. package/dist/core/agent-session-transfer.js +0 -2
  134. package/dist/core/agent-session-transfer.js.map +1 -1
  135. package/dist/core/agent-session-tree.d.ts.map +1 -1
  136. package/dist/core/agent-session-tree.js +6 -0
  137. package/dist/core/agent-session-tree.js.map +1 -1
  138. package/dist/core/agent-session.d.ts +21 -3
  139. package/dist/core/agent-session.d.ts.map +1 -1
  140. package/dist/core/agent-session.js +22 -5
  141. package/dist/core/agent-session.js.map +1 -1
  142. package/dist/core/atomic-guide-command.js +2 -2
  143. package/dist/core/atomic-guide-command.js.map +1 -1
  144. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  145. package/dist/core/compaction/branch-summarization.js +1 -0
  146. package/dist/core/compaction/branch-summarization.js.map +1 -1
  147. package/dist/core/compaction/index.d.ts +1 -0
  148. package/dist/core/compaction/index.d.ts.map +1 -1
  149. package/dist/core/compaction/index.js +1 -0
  150. package/dist/core/compaction/index.js.map +1 -1
  151. package/dist/core/compaction/session-summarization.d.ts +41 -0
  152. package/dist/core/compaction/session-summarization.d.ts.map +1 -0
  153. package/dist/core/compaction/session-summarization.js +97 -0
  154. package/dist/core/compaction/session-summarization.js.map +1 -0
  155. package/dist/core/extensions/ui-types.d.ts +4 -0
  156. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  157. package/dist/core/extensions/ui-types.js.map +1 -1
  158. package/dist/core/keybindings.d.ts +0 -5
  159. package/dist/core/keybindings.d.ts.map +1 -1
  160. package/dist/core/keybindings.js +0 -2
  161. package/dist/core/keybindings.js.map +1 -1
  162. package/dist/core/session-manager-core.d.ts +3 -1
  163. package/dist/core/session-manager-core.d.ts.map +1 -1
  164. package/dist/core/session-manager-core.js +9 -1
  165. package/dist/core/session-manager-core.js.map +1 -1
  166. package/dist/core/session-manager-entries.d.ts +24 -1
  167. package/dist/core/session-manager-entries.d.ts.map +1 -1
  168. package/dist/core/session-manager-entries.js +48 -0
  169. package/dist/core/session-manager-entries.js.map +1 -1
  170. package/dist/core/session-manager-list.d.ts.map +1 -1
  171. package/dist/core/session-manager-list.js +10 -0
  172. package/dist/core/session-manager-list.js.map +1 -1
  173. package/dist/core/session-manager-types.d.ts +10 -1
  174. package/dist/core/session-manager-types.d.ts.map +1 -1
  175. package/dist/core/session-manager-types.js.map +1 -1
  176. package/dist/core/settings-manager-basic-accessors.d.ts +3 -0
  177. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  178. package/dist/core/settings-manager-basic-accessors.js +5 -0
  179. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  180. package/dist/core/settings-manager.d.ts +1 -1
  181. package/dist/core/settings-manager.d.ts.map +1 -1
  182. package/dist/core/settings-manager.js.map +1 -1
  183. package/dist/core/settings-types.d.ts +4 -0
  184. package/dist/core/settings-types.d.ts.map +1 -1
  185. package/dist/core/settings-types.js.map +1 -1
  186. package/dist/core/slash-commands.js +2 -2
  187. package/dist/core/slash-commands.js.map +1 -1
  188. package/dist/core/tools/bash.d.ts +0 -15
  189. package/dist/core/tools/bash.d.ts.map +1 -1
  190. package/dist/core/tools/bash.js +3 -81
  191. package/dist/core/tools/bash.js.map +1 -1
  192. package/dist/core/tools/fetch-url.d.ts +12 -0
  193. package/dist/core/tools/fetch-url.d.ts.map +1 -1
  194. package/dist/core/tools/fetch-url.js +76 -10
  195. package/dist/core/tools/fetch-url.js.map +1 -1
  196. package/dist/core/tools/index.js +4 -4
  197. package/dist/core/tools/index.js.map +1 -1
  198. package/dist/core/tools/session-temp-dir.d.ts +2 -2
  199. package/dist/core/tools/session-temp-dir.d.ts.map +1 -1
  200. package/dist/core/tools/session-temp-dir.js +6 -7
  201. package/dist/core/tools/session-temp-dir.js.map +1 -1
  202. package/dist/core/usage-totals.js +1 -1
  203. package/dist/core/usage-totals.js.map +1 -1
  204. package/dist/index.d.ts +1 -1
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +1 -1
  207. package/dist/index.js.map +1 -1
  208. package/dist/modes/interactive/components/footer.js +1 -1
  209. package/dist/modes/interactive/components/footer.js.map +1 -1
  210. package/dist/modes/interactive/components/host-session-picker.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/host-session-picker.js +1 -0
  212. package/dist/modes/interactive/components/host-session-picker.js.map +1 -1
  213. package/dist/modes/interactive/components/index.d.ts +1 -0
  214. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  215. package/dist/modes/interactive/components/index.js +1 -0
  216. package/dist/modes/interactive/components/index.js.map +1 -1
  217. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  218. package/dist/modes/interactive/components/session-selector-list.js +29 -4
  219. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  220. package/dist/modes/interactive/components/session-selector-search.js +1 -1
  221. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  222. package/dist/modes/interactive/components/transcript-follow-indicator.d.ts +14 -0
  223. package/dist/modes/interactive/components/transcript-follow-indicator.d.ts.map +1 -0
  224. package/dist/modes/interactive/components/transcript-follow-indicator.js +36 -0
  225. package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -0
  226. package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
  227. package/dist/modes/interactive/components/tree-selector-content.js +6 -0
  228. package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
  229. package/dist/modes/interactive/interactive-extension-custom-ui.js +3 -0
  230. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
  231. package/dist/modes/interactive/interactive-input-handling.js +0 -3
  232. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  233. package/dist/modes/interactive/interactive-mode-base.d.ts +1 -0
  234. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  235. package/dist/modes/interactive/interactive-mode-base.js +7 -1
  236. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  237. package/dist/modes/interactive/interactive-mode-surface.d.ts +3 -3
  238. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  239. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  240. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  241. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  242. package/dist/modes/interactive/interactive-mode.js +1 -0
  243. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  244. package/dist/modes/interactive/interactive-slash-commands.js +2 -5
  245. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
  246. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-startup.js +6 -0
  248. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  249. package/dist/modes/interactive/interactive-transcript-follow.d.ts +2 -0
  250. package/dist/modes/interactive/interactive-transcript-follow.d.ts.map +1 -0
  251. package/dist/modes/interactive/interactive-transcript-follow.js +6 -0
  252. package/dist/modes/interactive/interactive-transcript-follow.js.map +1 -0
  253. package/dist/modes/interactive/interactive-tui.d.ts +13 -1
  254. package/dist/modes/interactive/interactive-tui.d.ts.map +1 -1
  255. package/dist/modes/interactive/interactive-tui.js +59 -1
  256. package/dist/modes/interactive/interactive-tui.js.map +1 -1
  257. package/dist/modes/interactive-engine/engine-custom-ui.d.ts +2 -0
  258. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  259. package/dist/modes/interactive-engine/engine-custom-ui.js +1 -0
  260. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  261. package/dist/modes/interactive-engine/protocol.d.ts +1 -0
  262. package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
  263. package/dist/modes/interactive-engine/protocol.js +5 -1
  264. package/dist/modes/interactive-engine/protocol.js.map +1 -1
  265. package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
  266. package/dist/modes/interactive-engine/remote-component.js +21 -9
  267. package/dist/modes/interactive-engine/remote-component.js.map +1 -1
  268. package/docs/environment-variables.md +1 -1
  269. package/docs/intercom.md +20 -21
  270. package/docs/keybindings.md +2 -5
  271. package/docs/quickstart.md +5 -1
  272. package/docs/sdk.md +1 -1
  273. package/docs/session-format.md +15 -0
  274. package/docs/sessions.md +8 -0
  275. package/docs/settings.md +6 -0
  276. package/docs/subagents.md +19 -31
  277. package/docs/tools.md +3 -5
  278. package/docs/usage.md +3 -1
  279. package/docs/windows.md +1 -1
  280. package/docs/workflows.md +60 -32
  281. package/npm-shrinkwrap.json +29 -29
  282. package/package.json +2 -2
  283. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +0 -331
  284. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +0 -161
  285. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +0 -195
  286. package/dist/builtin/subagents/src/runs/inprocess/background.ts +0 -90
  287. package/dist/builtin/subagents/src/shared/types-async.ts +0 -247
  288. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -217
  289. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -366
  290. package/dist/core/async/format.d.ts +0 -3
  291. package/dist/core/async/format.d.ts.map +0 -1
  292. package/dist/core/async/format.js +0 -52
  293. package/dist/core/async/format.js.map +0 -1
  294. package/dist/core/async/job-manager.d.ts +0 -40
  295. package/dist/core/async/job-manager.d.ts.map +0 -1
  296. package/dist/core/async/job-manager.js +0 -293
  297. package/dist/core/async/job-manager.js.map +0 -1
  298. package/dist/core/async/session-manager.d.ts +0 -16
  299. package/dist/core/async/session-manager.d.ts.map +0 -1
  300. package/dist/core/async/session-manager.js +0 -34
  301. package/dist/core/async/session-manager.js.map +0 -1
  302. package/dist/core/async/types.d.ts +0 -23
  303. package/dist/core/async/types.d.ts.map +0 -1
  304. package/dist/core/async/types.js +0 -2
  305. package/dist/core/async/types.js.map +0 -1
  306. package/dist/core/tools/bash-async-execution.d.ts +0 -27
  307. package/dist/core/tools/bash-async-execution.d.ts.map +0 -1
  308. package/dist/core/tools/bash-async-execution.js +0 -81
  309. package/dist/core/tools/bash-async-execution.js.map +0 -1
  310. package/dist/core/tools/bash-async-jobs.d.ts +0 -30
  311. package/dist/core/tools/bash-async-jobs.d.ts.map +0 -1
  312. package/dist/core/tools/bash-async-jobs.js +0 -87
  313. package/dist/core/tools/bash-async-jobs.js.map +0 -1
  314. package/dist/core/tools/bash-async-output.d.ts +0 -13
  315. package/dist/core/tools/bash-async-output.d.ts.map +0 -1
  316. package/dist/core/tools/bash-async-output.js +0 -122
  317. package/dist/core/tools/bash-async-output.js.map +0 -1
@@ -1,87 +0,0 @@
1
- import { rmSync } from "node:fs";
2
- export const MAX_MANAGED_BASH_JOBS = 100;
3
- export const COMPLETED_JOB_TTL_MS = 30 * 60 * 1000;
4
- const managedBashJobs = new Map();
5
- export function formatAsyncJobError(error) {
6
- const message = error instanceof Error ? error.message : String(error);
7
- if (message.startsWith("timeout:"))
8
- return `Command timed out after ${message.slice("timeout:".length)} seconds`;
9
- return message;
10
- }
11
- function deleteJobOutput(job) {
12
- if (!job.fullOutputPath)
13
- return;
14
- try {
15
- rmSync(job.fullOutputPath, { force: true });
16
- }
17
- catch {
18
- /* best-effort temp cleanup */
19
- }
20
- }
21
- function cleanupManagedBashJobs(now = Date.now()) {
22
- for (const [jobId, job] of managedBashJobs)
23
- if (job.status !== "running" && job.endedAt !== undefined && now - job.endedAt > COMPLETED_JOB_TTL_MS) {
24
- deleteJobOutput(job);
25
- managedBashJobs.delete(jobId);
26
- }
27
- while (managedBashJobs.size > MAX_MANAGED_BASH_JOBS) {
28
- const oldest = [...managedBashJobs.values()].sort((a, b) => (a.endedAt ?? a.startedAt) - (b.endedAt ?? b.startedAt))[0];
29
- if (!oldest)
30
- break;
31
- if (oldest.status === "running")
32
- oldest.abortController?.abort();
33
- else
34
- deleteJobOutput(oldest);
35
- managedBashJobs.delete(oldest.jobId);
36
- }
37
- }
38
- export function createManagedBashJob(command, cwd, timeoutSeconds, requestedTimeoutSeconds) {
39
- cleanupManagedBashJobs();
40
- const jobId = `bash-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
41
- const job = {
42
- jobId,
43
- command,
44
- cwd,
45
- status: "running",
46
- output: "",
47
- startedAt: Date.now(),
48
- timeoutSeconds,
49
- requestedTimeoutSeconds,
50
- abortController: new AbortController(),
51
- };
52
- managedBashJobs.set(jobId, job);
53
- cleanupManagedBashJobs();
54
- return job;
55
- }
56
- /**
57
- * Remove a managed job that never actually started executing (for example when
58
- * async-manager registration fails after the map insert). Without this, the
59
- * entry would stay "running" forever: TTL cleanup only evicts settled jobs, so
60
- * the zombie would linger until the max-jobs overflow forcibly removed it.
61
- */
62
- export function discardManagedBashJob(jobId) {
63
- const job = managedBashJobs.get(jobId);
64
- if (!job)
65
- return;
66
- deleteJobOutput(job);
67
- managedBashJobs.delete(jobId);
68
- }
69
- export function listManagedBashJobIds() {
70
- return [...managedBashJobs.keys()];
71
- }
72
- export function getManagedBashJob(jobId) {
73
- cleanupManagedBashJobs();
74
- const job = managedBashJobs.get(jobId);
75
- if (!job)
76
- return undefined;
77
- const { abortController: _abortController, ...snapshot } = job;
78
- return { ...snapshot };
79
- }
80
- export function abortManagedBashJob(jobId) {
81
- const job = managedBashJobs.get(jobId);
82
- if (!job)
83
- return undefined;
84
- job.abortController?.abort();
85
- return job;
86
- }
87
- //# sourceMappingURL=bash-async-jobs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bash-async-jobs.js","sourceRoot":"","sources":["../../../src/core/tools/bash-async-jobs.ts"],"names":[],"mappings":"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","sourcesContent":["import { rmSync } from \"node:fs\";\n\nexport interface ManagedBashJob {\n\tjobId: string;\n\tcommand: string;\n\tcwd: string;\n\tstatus: \"running\" | \"completed\" | \"failed\";\n\toutput: string;\n\tfullOutputPath?: string;\n\texitCode?: number | null;\n\terror?: string;\n\tstartedAt: number;\n\tendedAt?: number;\n\ttimeoutSeconds?: number;\n\trequestedTimeoutSeconds?: number;\n\tabortController?: AbortController;\n}\n\nexport const MAX_MANAGED_BASH_JOBS = 100;\nexport const COMPLETED_JOB_TTL_MS = 30 * 60 * 1000;\nconst managedBashJobs = new Map<string, ManagedBashJob>();\nexport function formatAsyncJobError(error: unknown): string {\n\tconst message = error instanceof Error ? error.message : String(error);\n\tif (message.startsWith(\"timeout:\")) return `Command timed out after ${message.slice(\"timeout:\".length)} seconds`;\n\treturn message;\n}\nfunction deleteJobOutput(job: ManagedBashJob): void {\n\tif (!job.fullOutputPath) return;\n\ttry {\n\t\trmSync(job.fullOutputPath, { force: true });\n\t} catch {\n\t\t/* best-effort temp cleanup */\n\t}\n}\n\nfunction cleanupManagedBashJobs(now = Date.now()): void {\n\tfor (const [jobId, job] of managedBashJobs)\n\t\tif (job.status !== \"running\" && job.endedAt !== undefined && now - job.endedAt > COMPLETED_JOB_TTL_MS) {\n\t\t\tdeleteJobOutput(job);\n\t\t\tmanagedBashJobs.delete(jobId);\n\t\t}\n\twhile (managedBashJobs.size > MAX_MANAGED_BASH_JOBS) {\n\t\tconst oldest = [...managedBashJobs.values()].sort(\n\t\t\t(a, b) => (a.endedAt ?? a.startedAt) - (b.endedAt ?? b.startedAt),\n\t\t)[0];\n\t\tif (!oldest) break;\n\t\tif (oldest.status === \"running\") oldest.abortController?.abort();\n\t\telse deleteJobOutput(oldest);\n\t\tmanagedBashJobs.delete(oldest.jobId);\n\t}\n}\n\nexport function createManagedBashJob(\n\tcommand: string,\n\tcwd: string,\n\ttimeoutSeconds?: number,\n\trequestedTimeoutSeconds?: number,\n): ManagedBashJob {\n\tcleanupManagedBashJobs();\n\tconst jobId = `bash-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n\tconst job: ManagedBashJob = {\n\t\tjobId,\n\t\tcommand,\n\t\tcwd,\n\t\tstatus: \"running\",\n\t\toutput: \"\",\n\t\tstartedAt: Date.now(),\n\t\ttimeoutSeconds,\n\t\trequestedTimeoutSeconds,\n\t\tabortController: new AbortController(),\n\t};\n\tmanagedBashJobs.set(jobId, job);\n\tcleanupManagedBashJobs();\n\treturn job;\n}\n\n/**\n * Remove a managed job that never actually started executing (for example when\n * async-manager registration fails after the map insert). Without this, the\n * entry would stay \"running\" forever: TTL cleanup only evicts settled jobs, so\n * the zombie would linger until the max-jobs overflow forcibly removed it.\n */\nexport function discardManagedBashJob(jobId: string): void {\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return;\n\tdeleteJobOutput(job);\n\tmanagedBashJobs.delete(jobId);\n}\n\nexport function listManagedBashJobIds(): string[] {\n\treturn [...managedBashJobs.keys()];\n}\n\nexport function getManagedBashJob(jobId: string): ManagedBashJob | undefined {\n\tcleanupManagedBashJobs();\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return undefined;\n\tconst { abortController: _abortController, ...snapshot } = job;\n\treturn { ...snapshot };\n}\n\nexport function abortManagedBashJob(jobId: string): ManagedBashJob | undefined {\n\tconst job = managedBashJobs.get(jobId);\n\tif (!job) return undefined;\n\tjob.abortController?.abort();\n\treturn job;\n}\n"]}
@@ -1,13 +0,0 @@
1
- export interface BashAsyncOutputTarget {
2
- output: string;
3
- fullOutputPath?: string;
4
- }
5
- export interface BashAsyncOutputAppender {
6
- append(chunk: Buffer): void;
7
- close(): Promise<void>;
8
- }
9
- export declare function createAsyncOutputAppender(job: BashAsyncOutputTarget, options?: {
10
- persistAfterBytes?: number;
11
- sessionTempDir?: string;
12
- }): BashAsyncOutputAppender;
13
- //# sourceMappingURL=bash-async-output.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bash-async-output.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash-async-output.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACvC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAoBD,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,qBAAqB,EAC1B,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/D,uBAAuB,CAqFzB"}
@@ -1,122 +0,0 @@
1
- import { randomBytes } from "node:crypto";
2
- import { dirname, join } from "node:path";
3
- import { APP_NAME } from "../../config.js";
4
- import { stripAnsi } from "../../utils/ansi.js";
5
- import { sanitizeBinaryOutput } from "../../utils/shell.js";
6
- import { PersistedOutputFile } from "./persisted-output-file.js";
7
- import { acquireProtectedPaths, ensureSessionTempDir } from "./session-temp-dir.js";
8
- import { DEFAULT_MAX_BYTES, formatSize } from "./truncate.js";
9
- function outputPath(sessionTempDir) {
10
- const dir = ensureSessionTempDir(sessionTempDir);
11
- return join(dir, `${APP_NAME}-bash-async-${randomBytes(8).toString("hex")}.log`);
12
- }
13
- function byteLength(text) {
14
- return Buffer.byteLength(text, "utf8");
15
- }
16
- function sanitizeDecodedOutput(text) {
17
- return sanitizeBinaryOutput(stripAnsi(text)).replace(/\r/g, "");
18
- }
19
- function utf8Prefix(text, maxBytes) {
20
- if (byteLength(text) <= maxBytes)
21
- return text;
22
- let end = text.length;
23
- while (end > 0 && byteLength(text.slice(0, end)) > maxBytes)
24
- end--;
25
- return text.slice(0, end);
26
- }
27
- export function createAsyncOutputAppender(job, options) {
28
- const persistAfterBytes = options?.persistAfterBytes ?? DEFAULT_MAX_BYTES;
29
- let outputBytes = 0;
30
- let truncated = false;
31
- let fullOutputFile;
32
- let persistUnavailable = false;
33
- let writerLease;
34
- let bufferedChunks = [];
35
- const decoder = new TextDecoder();
36
- const ensureFullOutputFile = () => {
37
- if (fullOutputFile || persistUnavailable)
38
- return fullOutputFile;
39
- try {
40
- const path = outputPath(options?.sessionTempDir);
41
- // A background job outlives the session that started it, so this writer
42
- // holds its own protection claim rather than relying on the session's.
43
- writerLease = acquireProtectedPaths([dirname(path)]);
44
- fullOutputFile = new PersistedOutputFile(path);
45
- job.fullOutputPath = path;
46
- }
47
- catch {
48
- // The session temp directory was refused (see ensureTempDir), or the file
49
- // could not be created owner-only. Keep polling output flowing without
50
- // advertising a spill path we could not own.
51
- persistUnavailable = true;
52
- job.fullOutputPath = undefined;
53
- writerLease?.release();
54
- writerLease = undefined;
55
- bufferedChunks = [];
56
- return undefined;
57
- }
58
- for (const chunk of bufferedChunks)
59
- fullOutputFile.write(chunk);
60
- bufferedChunks = [];
61
- return fullOutputFile;
62
- };
63
- const appendDecodedText = (decoded) => {
64
- if (truncated || decoded.length === 0)
65
- return;
66
- const text = sanitizeDecodedOutput(decoded);
67
- if (text.length === 0)
68
- return;
69
- const bytes = byteLength(text);
70
- if (outputBytes + bytes > persistAfterBytes)
71
- ensureFullOutputFile();
72
- if (outputBytes + bytes > DEFAULT_MAX_BYTES) {
73
- ensureFullOutputFile();
74
- const remaining = Math.max(0, DEFAULT_MAX_BYTES - outputBytes);
75
- if (remaining > 0)
76
- job.output += utf8Prefix(text, remaining);
77
- const fullOutputNote = job.fullOutputPath ? ` Full output: ${job.fullOutputPath}` : "";
78
- job.output += `\n[Output truncated at ${formatSize(DEFAULT_MAX_BYTES)} for async job polling.${fullOutputNote}]`;
79
- outputBytes += bytes;
80
- truncated = true;
81
- return;
82
- }
83
- outputBytes += bytes;
84
- job.output += text;
85
- };
86
- return {
87
- append(chunk) {
88
- if (fullOutputFile)
89
- fullOutputFile.write(chunk);
90
- else if (!persistUnavailable)
91
- bufferedChunks.push(chunk);
92
- appendDecodedText(decoder.decode(chunk, { stream: true }));
93
- },
94
- async close() {
95
- appendDecodedText(decoder.decode());
96
- if (!fullOutputFile) {
97
- writerLease?.release();
98
- writerLease = undefined;
99
- return;
100
- }
101
- const file = fullOutputFile;
102
- fullOutputFile = undefined;
103
- try {
104
- await file.close();
105
- }
106
- catch {
107
- // A spill file that failed to flush must not be advertised — but it
108
- // must not fail the command either. The process already exited, and
109
- // reporting a storage fault as command failure invites the caller to
110
- // retry a side-effecting command that in fact succeeded. Dropping the
111
- // path matches the synchronous executor, which also declines to
112
- // advertise a spill it could not write.
113
- job.fullOutputPath = undefined;
114
- }
115
- finally {
116
- writerLease?.release();
117
- writerLease = undefined;
118
- }
119
- },
120
- };
121
- }
122
- //# sourceMappingURL=bash-async-output.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bash-async-output.js","sourceRoot":"","sources":["../../../src/core/tools/bash-async-output.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { dirname, join } from \"node:path\";\nimport { APP_NAME } from \"../../config.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport { PersistedOutputFile } from \"./persisted-output-file.ts\";\nimport { acquireProtectedPaths, ensureSessionTempDir, type ProtectedPathLease } from \"./session-temp-dir.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"./truncate.ts\";\n\nexport interface BashAsyncOutputTarget {\n\toutput: string;\n\tfullOutputPath?: string;\n}\n\nexport interface BashAsyncOutputAppender {\n\tappend(chunk: Buffer): void;\n\tclose(): Promise<void>;\n}\n\nfunction outputPath(sessionTempDir: string | undefined): string {\n\tconst dir = ensureSessionTempDir(sessionTempDir);\n\treturn join(dir, `${APP_NAME}-bash-async-${randomBytes(8).toString(\"hex\")}.log`);\n}\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf8\");\n}\nfunction sanitizeDecodedOutput(text: string): string {\n\treturn sanitizeBinaryOutput(stripAnsi(text)).replace(/\\r/g, \"\");\n}\nfunction utf8Prefix(text: string, maxBytes: number): string {\n\tif (byteLength(text) <= maxBytes) return text;\n\tlet end = text.length;\n\twhile (end > 0 && byteLength(text.slice(0, end)) > maxBytes) end--;\n\treturn text.slice(0, end);\n}\n\nexport function createAsyncOutputAppender(\n\tjob: BashAsyncOutputTarget,\n\toptions?: { persistAfterBytes?: number; sessionTempDir?: string },\n): BashAsyncOutputAppender {\n\tconst persistAfterBytes = options?.persistAfterBytes ?? DEFAULT_MAX_BYTES;\n\tlet outputBytes = 0;\n\tlet truncated = false;\n\tlet fullOutputFile: PersistedOutputFile | undefined;\n\tlet persistUnavailable = false;\n\tlet writerLease: ProtectedPathLease | undefined;\n\tlet bufferedChunks: Buffer[] = [];\n\tconst decoder = new TextDecoder();\n\n\tconst ensureFullOutputFile = (): PersistedOutputFile | undefined => {\n\t\tif (fullOutputFile || persistUnavailable) return fullOutputFile;\n\t\ttry {\n\t\t\tconst path = outputPath(options?.sessionTempDir);\n\t\t\t// A background job outlives the session that started it, so this writer\n\t\t\t// holds its own protection claim rather than relying on the session's.\n\t\t\twriterLease = acquireProtectedPaths([dirname(path)]);\n\t\t\tfullOutputFile = new PersistedOutputFile(path);\n\t\t\tjob.fullOutputPath = path;\n\t\t} catch {\n\t\t\t// The session temp directory was refused (see ensureTempDir), or the file\n\t\t\t// could not be created owner-only. Keep polling output flowing without\n\t\t\t// advertising a spill path we could not own.\n\t\t\tpersistUnavailable = true;\n\t\t\tjob.fullOutputPath = undefined;\n\t\t\twriterLease?.release();\n\t\t\twriterLease = undefined;\n\t\t\tbufferedChunks = [];\n\t\t\treturn undefined;\n\t\t}\n\t\tfor (const chunk of bufferedChunks) fullOutputFile.write(chunk);\n\t\tbufferedChunks = [];\n\t\treturn fullOutputFile;\n\t};\n\tconst appendDecodedText = (decoded: string): void => {\n\t\tif (truncated || decoded.length === 0) return;\n\t\tconst text = sanitizeDecodedOutput(decoded);\n\t\tif (text.length === 0) return;\n\t\tconst bytes = byteLength(text);\n\t\tif (outputBytes + bytes > persistAfterBytes) ensureFullOutputFile();\n\t\tif (outputBytes + bytes > DEFAULT_MAX_BYTES) {\n\t\t\tensureFullOutputFile();\n\t\t\tconst remaining = Math.max(0, DEFAULT_MAX_BYTES - outputBytes);\n\t\t\tif (remaining > 0) job.output += utf8Prefix(text, remaining);\n\t\t\tconst fullOutputNote = job.fullOutputPath ? ` Full output: ${job.fullOutputPath}` : \"\";\n\t\t\tjob.output += `\\n[Output truncated at ${formatSize(DEFAULT_MAX_BYTES)} for async job polling.${fullOutputNote}]`;\n\t\t\toutputBytes += bytes;\n\t\t\ttruncated = true;\n\t\t\treturn;\n\t\t}\n\t\toutputBytes += bytes;\n\t\tjob.output += text;\n\t};\n\n\treturn {\n\t\tappend(chunk) {\n\t\t\tif (fullOutputFile) fullOutputFile.write(chunk);\n\t\t\telse if (!persistUnavailable) bufferedChunks.push(chunk);\n\t\t\tappendDecodedText(decoder.decode(chunk, { stream: true }));\n\t\t},\n\t\tasync close() {\n\t\t\tappendDecodedText(decoder.decode());\n\t\t\tif (!fullOutputFile) {\n\t\t\t\twriterLease?.release();\n\t\t\t\twriterLease = undefined;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst file = fullOutputFile;\n\t\t\tfullOutputFile = undefined;\n\t\t\ttry {\n\t\t\t\tawait file.close();\n\t\t\t} catch {\n\t\t\t\t// A spill file that failed to flush must not be advertised — but it\n\t\t\t\t// must not fail the command either. The process already exited, and\n\t\t\t\t// reporting a storage fault as command failure invites the caller to\n\t\t\t\t// retry a side-effecting command that in fact succeeded. Dropping the\n\t\t\t\t// path matches the synchronous executor, which also declines to\n\t\t\t\t// advertise a spill it could not write.\n\t\t\t\tjob.fullOutputPath = undefined;\n\t\t\t} finally {\n\t\t\t\twriterLease?.release();\n\t\t\t\twriterLease = undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n"]}