@agimon-ai/doompi-team 0.0.1-alpha.2 → 0.0.1-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (727) hide show
  1. package/README.md +33 -17
  2. package/dist/adapters/asyncJobTracker.cjs +2 -0
  3. package/dist/adapters/asyncJobTracker.cjs.map +1 -0
  4. package/dist/adapters/asyncJobTracker.mjs +2 -0
  5. package/dist/adapters/asyncJobTracker.mjs.map +1 -0
  6. package/dist/adapters/atomicJson.cjs +2 -0
  7. package/dist/adapters/atomicJson.cjs.map +1 -0
  8. package/dist/adapters/atomicJson.mjs +2 -0
  9. package/dist/adapters/atomicJson.mjs.map +1 -0
  10. package/dist/adapters/pi/extension.cjs +2 -0
  11. package/dist/adapters/pi/extension.cjs.map +1 -0
  12. package/dist/adapters/pi/extension.mjs +2 -0
  13. package/dist/adapters/pi/extension.mjs.map +1 -0
  14. package/dist/adapters/pollScheduler.cjs +2 -0
  15. package/dist/adapters/pollScheduler.cjs.map +1 -0
  16. package/dist/adapters/pollScheduler.mjs +2 -0
  17. package/dist/adapters/pollScheduler.mjs.map +1 -0
  18. package/dist/adapters/process/childTranscript.cjs +5 -0
  19. package/dist/adapters/process/childTranscript.cjs.map +1 -0
  20. package/dist/adapters/process/childTranscript.mjs +5 -0
  21. package/dist/adapters/process/childTranscript.mjs.map +1 -0
  22. package/dist/adapters/process/env.cjs +2 -0
  23. package/dist/adapters/process/env.cjs.map +1 -0
  24. package/dist/adapters/process/env.d.cts +69 -0
  25. package/dist/adapters/process/env.d.cts.map +1 -0
  26. package/dist/adapters/process/env.d.mts +69 -0
  27. package/dist/adapters/process/env.d.mts.map +1 -0
  28. package/dist/adapters/process/env.mjs +2 -0
  29. package/dist/adapters/process/env.mjs.map +1 -0
  30. package/dist/adapters/process/sdkRunnerEntry.cjs +2 -0
  31. package/dist/adapters/process/sdkRunnerEntry.cjs.map +1 -0
  32. package/dist/adapters/process/sdkRunnerEntry.d.cts +5 -0
  33. package/dist/adapters/process/sdkRunnerEntry.d.cts.map +1 -0
  34. package/dist/adapters/process/sdkRunnerEntry.d.mts +5 -0
  35. package/dist/adapters/process/sdkRunnerEntry.d.mts.map +1 -0
  36. package/dist/adapters/process/sdkRunnerEntry.mjs +2 -0
  37. package/dist/adapters/process/sdkRunnerEntry.mjs.map +1 -0
  38. package/dist/adapters/processTerminal.cjs +2 -0
  39. package/dist/adapters/processTerminal.cjs.map +1 -0
  40. package/dist/adapters/processTerminal.mjs +2 -0
  41. package/dist/adapters/processTerminal.mjs.map +1 -0
  42. package/dist/adapters/resultWatcher.cjs +2 -0
  43. package/dist/adapters/resultWatcher.cjs.map +1 -0
  44. package/dist/adapters/resultWatcher.mjs +2 -0
  45. package/dist/adapters/resultWatcher.mjs.map +1 -0
  46. package/dist/adapters/runIdResolver.cjs +2 -0
  47. package/dist/adapters/runIdResolver.cjs.map +1 -0
  48. package/dist/adapters/runIdResolver.mjs +2 -0
  49. package/dist/adapters/runIdResolver.mjs.map +1 -0
  50. package/dist/adapters/runRegistry.cjs +2 -0
  51. package/dist/adapters/runRegistry.cjs.map +1 -0
  52. package/dist/adapters/runRegistry.mjs +2 -0
  53. package/dist/adapters/runRegistry.mjs.map +1 -0
  54. package/dist/adapters/scopeOwner.cjs +2 -0
  55. package/dist/adapters/scopeOwner.cjs.map +1 -0
  56. package/dist/adapters/scopeOwner.mjs +2 -0
  57. package/dist/adapters/scopeOwner.mjs.map +1 -0
  58. package/dist/adapters/staleRunReconciler.cjs +2 -0
  59. package/dist/adapters/staleRunReconciler.cjs.map +1 -0
  60. package/dist/adapters/staleRunReconciler.mjs +2 -0
  61. package/dist/adapters/staleRunReconciler.mjs.map +1 -0
  62. package/dist/adapters/statusReader.cjs +2 -0
  63. package/dist/adapters/statusReader.cjs.map +1 -0
  64. package/dist/adapters/statusReader.mjs +2 -0
  65. package/dist/adapters/statusReader.mjs.map +1 -0
  66. package/dist/adapters/suspendedRuns.cjs +6 -0
  67. package/dist/adapters/suspendedRuns.cjs.map +1 -0
  68. package/dist/adapters/suspendedRuns.mjs +6 -0
  69. package/dist/adapters/suspendedRuns.mjs.map +1 -0
  70. package/dist/api/backgroundWork.cjs +1 -1
  71. package/dist/api/backgroundWork.d.cts +2 -2
  72. package/dist/api/backgroundWork.d.mts +2 -2
  73. package/dist/api/backgroundWork.mjs +1 -1
  74. package/dist/api/capabilityCeiling.cjs +1 -1
  75. package/dist/api/capabilityCeiling.d.cts +3 -3
  76. package/dist/api/capabilityCeiling.d.mts +3 -3
  77. package/dist/api/capabilityCeiling.mjs +1 -2
  78. package/dist/api/delegation.cjs +1 -1
  79. package/dist/api/delegation.d.cts +1 -1
  80. package/dist/api/delegation.d.mts +1 -1
  81. package/dist/api/delegation.mjs +1 -1
  82. package/dist/api/teamSnapshot.cjs +1 -1
  83. package/dist/api/teamSnapshot.d.cts +2 -2
  84. package/dist/api/teamSnapshot.d.mts +2 -2
  85. package/dist/api/teamSnapshot.mjs +1 -2
  86. package/dist/commands/slash/chainExpression.cjs.map +1 -0
  87. package/dist/commands/slash/chainExpression.mjs.map +1 -0
  88. package/dist/commands/slash/doctor.cjs +5 -0
  89. package/dist/commands/slash/doctor.cjs.map +1 -0
  90. package/dist/commands/slash/doctor.mjs +5 -0
  91. package/dist/{slash/doctor.cjs.map → commands/slash/doctor.mjs.map} +1 -1
  92. package/dist/{slash → commands/slash}/slashCommands.cjs +1 -1
  93. package/dist/commands/slash/slashCommands.cjs.map +1 -0
  94. package/dist/{slash → commands/slash}/slashCommands.mjs +2 -2
  95. package/dist/commands/slash/slashCommands.mjs.map +1 -0
  96. package/dist/commands/slash/spawnRequestMapping.cjs.map +1 -0
  97. package/dist/commands/slash/spawnRequestMapping.mjs.map +1 -0
  98. package/dist/commands/slash/subagentLaunch.cjs +2 -0
  99. package/dist/commands/slash/subagentLaunch.cjs.map +1 -0
  100. package/dist/commands/slash/subagentLaunch.mjs +2 -0
  101. package/dist/commands/slash/subagentLaunch.mjs.map +1 -0
  102. package/dist/container/globalBridge.cjs.map +1 -1
  103. package/dist/container/globalBridge.d.cts +1 -1
  104. package/dist/container/globalBridge.d.mts +1 -1
  105. package/dist/container/globalBridge.mjs.map +1 -1
  106. package/dist/container/index.cjs +1 -1
  107. package/dist/container/index.cjs.map +1 -1
  108. package/dist/container/index.d.cts +2 -1
  109. package/dist/container/index.d.cts.map +1 -1
  110. package/dist/container/index.d.mts +2 -1
  111. package/dist/container/index.d.mts.map +1 -1
  112. package/dist/container/index.mjs +1 -1
  113. package/dist/container/index.mjs.map +1 -1
  114. package/dist/container/modules/agents.cjs +1 -1
  115. package/dist/container/modules/agents.cjs.map +1 -1
  116. package/dist/container/modules/agents.mjs +1 -1
  117. package/dist/container/modules/agents.mjs.map +1 -1
  118. package/dist/container/modules/core.cjs +1 -1
  119. package/dist/container/modules/core.cjs.map +1 -1
  120. package/dist/container/modules/core.mjs +1 -1
  121. package/dist/container/modules/core.mjs.map +1 -1
  122. package/dist/container/modules/extensions.cjs +1 -1
  123. package/dist/container/modules/extensions.cjs.map +1 -1
  124. package/dist/container/modules/extensions.mjs +1 -1
  125. package/dist/container/modules/extensions.mjs.map +1 -1
  126. package/dist/container/modules/intercom.cjs +1 -1
  127. package/dist/container/modules/intercom.cjs.map +1 -1
  128. package/dist/container/modules/intercom.mjs +1 -1
  129. package/dist/container/modules/intercom.mjs.map +1 -1
  130. package/dist/container/modules/runs.cjs +1 -1
  131. package/dist/container/modules/runs.cjs.map +1 -1
  132. package/dist/container/modules/runs.mjs +1 -1
  133. package/dist/container/modules/runs.mjs.map +1 -1
  134. package/dist/container/types.cjs +1 -1
  135. package/dist/container/types.cjs.map +1 -1
  136. package/dist/container/types.d.cts +1 -0
  137. package/dist/container/types.d.cts.map +1 -1
  138. package/dist/container/types.d.mts +1 -0
  139. package/dist/container/types.d.mts.map +1 -1
  140. package/dist/container/types.mjs +1 -1
  141. package/dist/container/types.mjs.map +1 -1
  142. package/dist/env.cjs +1 -2
  143. package/dist/env.d.cts +2 -65
  144. package/dist/env.d.mts +2 -65
  145. package/dist/env.mjs +1 -1
  146. package/dist/env.mjs.map +1 -1
  147. package/dist/extensions/config.cjs.map +1 -1
  148. package/dist/extensions/config.mjs.map +1 -1
  149. package/dist/extensions/delegationBridge.cjs.map +1 -1
  150. package/dist/extensions/delegationBridge.mjs.map +1 -1
  151. package/dist/extensions/doom.cjs +1 -1
  152. package/dist/extensions/doom.cjs.map +1 -1
  153. package/dist/extensions/doom.mjs +1 -1
  154. package/dist/extensions/doom.mjs.map +1 -1
  155. package/dist/extensions/fablePlanBridge.cjs +1 -1
  156. package/dist/extensions/fablePlanBridge.cjs.map +1 -1
  157. package/dist/extensions/fablePlanBridge.mjs +1 -1
  158. package/dist/extensions/fablePlanBridge.mjs.map +1 -1
  159. package/dist/extensions/managementActions.cjs +1 -1
  160. package/dist/extensions/managementActions.cjs.map +1 -1
  161. package/dist/extensions/managementActions.mjs +1 -1
  162. package/dist/extensions/managementActions.mjs.map +1 -1
  163. package/dist/extensions/operationJournal.cjs +1 -1
  164. package/dist/extensions/operationJournal.cjs.map +1 -1
  165. package/dist/extensions/operationJournal.mjs +1 -1
  166. package/dist/extensions/operationJournal.mjs.map +1 -1
  167. package/dist/extensions/orchestratorPrompt.cjs +5 -6
  168. package/dist/extensions/orchestratorPrompt.cjs.map +1 -1
  169. package/dist/extensions/orchestratorPrompt.mjs +5 -6
  170. package/dist/extensions/orchestratorPrompt.mjs.map +1 -1
  171. package/dist/extensions/schemas.mjs.map +1 -1
  172. package/dist/extensions/spawnPlan.cjs +3 -2
  173. package/dist/extensions/spawnPlan.cjs.map +1 -1
  174. package/dist/extensions/spawnPlan.mjs +3 -2
  175. package/dist/extensions/spawnPlan.mjs.map +1 -1
  176. package/dist/extensions/standard.cjs +1 -1
  177. package/dist/extensions/standard.cjs.map +1 -1
  178. package/dist/extensions/standard.mjs +1 -1
  179. package/dist/extensions/standard.mjs.map +1 -1
  180. package/dist/extensions/statusViews.cjs +1 -1
  181. package/dist/extensions/statusViews.cjs.map +1 -1
  182. package/dist/extensions/statusViews.mjs +2 -2
  183. package/dist/extensions/statusViews.mjs.map +1 -1
  184. package/dist/extensions/subagentPromptRuntime.cjs +11 -11
  185. package/dist/extensions/subagentPromptRuntime.cjs.map +1 -1
  186. package/dist/extensions/subagentPromptRuntime.d.cts.map +1 -1
  187. package/dist/extensions/subagentPromptRuntime.d.mts.map +1 -1
  188. package/dist/extensions/subagentPromptRuntime.mjs +5 -5
  189. package/dist/extensions/subagentPromptRuntime.mjs.map +1 -1
  190. package/dist/extensions/subagentTool.cjs +5 -6
  191. package/dist/extensions/subagentTool.cjs.map +1 -1
  192. package/dist/extensions/subagentTool.mjs +5 -6
  193. package/dist/extensions/subagentTool.mjs.map +1 -1
  194. package/dist/extensions/toolDescription.cjs +1 -1
  195. package/dist/extensions/toolDescription.cjs.map +1 -1
  196. package/dist/extensions/toolDescription.mjs +1 -1
  197. package/dist/extensions/toolDescription.mjs.map +1 -1
  198. package/dist/index.cjs +1 -1
  199. package/dist/index.cjs.map +1 -1
  200. package/dist/index.d.cts +2 -2
  201. package/dist/index.d.cts.map +1 -1
  202. package/dist/index.d.mts +2 -2
  203. package/dist/index.d.mts.map +1 -1
  204. package/dist/index.mjs +1 -1
  205. package/dist/index.mjs.map +1 -1
  206. package/dist/runs/background/cliRunnerEntry.cjs +1 -2
  207. package/dist/runs/background/cliRunnerEntry.mjs +1 -2
  208. package/dist/runs/sdkRunnerEntry.cjs +1 -2
  209. package/dist/runs/sdkRunnerEntry.d.cts +2 -1
  210. package/dist/runs/sdkRunnerEntry.d.mts +2 -1
  211. package/dist/runs/sdkRunnerEntry.mjs +1 -2
  212. package/dist/schemas/team/backgroundWork.cjs +2 -0
  213. package/dist/schemas/team/backgroundWork.cjs.map +1 -0
  214. package/dist/{protocol → schemas/team}/backgroundWork.d.cts +2 -2
  215. package/dist/schemas/team/backgroundWork.d.cts.map +1 -0
  216. package/dist/{protocol → schemas/team}/backgroundWork.d.mts +2 -2
  217. package/dist/schemas/team/backgroundWork.d.mts.map +1 -0
  218. package/dist/schemas/team/backgroundWork.mjs +2 -0
  219. package/dist/{protocol/backgroundWork.cjs.map → schemas/team/backgroundWork.mjs.map} +1 -1
  220. package/dist/schemas/team/capabilityCeiling.cjs +2 -0
  221. package/dist/schemas/team/capabilityCeiling.cjs.map +1 -0
  222. package/dist/{protocol → schemas/team}/capabilityCeiling.d.cts +3 -3
  223. package/dist/schemas/team/capabilityCeiling.d.cts.map +1 -0
  224. package/dist/{protocol → schemas/team}/capabilityCeiling.d.mts +3 -3
  225. package/dist/schemas/team/capabilityCeiling.d.mts.map +1 -0
  226. package/dist/schemas/team/capabilityCeiling.mjs +2 -0
  227. package/dist/schemas/team/capabilityCeiling.mjs.map +1 -0
  228. package/dist/schemas/team/delegation.cjs.map +1 -0
  229. package/dist/{protocol → schemas/team}/delegation.d.cts +1 -1
  230. package/dist/schemas/team/delegation.d.cts.map +1 -0
  231. package/dist/{protocol → schemas/team}/delegation.d.mts +1 -1
  232. package/dist/schemas/team/delegation.d.mts.map +1 -0
  233. package/dist/schemas/team/delegation.mjs.map +1 -0
  234. package/dist/schemas/team/packageConfig.cjs +2 -0
  235. package/dist/schemas/team/packageConfig.cjs.map +1 -0
  236. package/dist/schemas/team/packageConfig.mjs +2 -0
  237. package/dist/schemas/team/packageConfig.mjs.map +1 -0
  238. package/dist/services/agents/discovery.cjs +2 -0
  239. package/dist/services/agents/discovery.cjs.map +1 -0
  240. package/dist/services/agents/discovery.mjs +2 -0
  241. package/dist/services/agents/discovery.mjs.map +1 -0
  242. package/dist/services/agents/frontmatter.cjs.map +1 -0
  243. package/dist/{agents → services/agents}/frontmatter.mjs +1 -1
  244. package/dist/services/agents/frontmatter.mjs.map +1 -0
  245. package/dist/services/agents/loader.cjs +2 -0
  246. package/dist/services/agents/loader.cjs.map +1 -0
  247. package/dist/services/agents/loader.mjs +2 -0
  248. package/dist/services/agents/loader.mjs.map +1 -0
  249. package/dist/services/agents/memory.cjs +3 -0
  250. package/dist/services/agents/memory.cjs.map +1 -0
  251. package/dist/{agents → services/agents}/memory.mjs +1 -1
  252. package/dist/services/agents/memory.mjs.map +1 -0
  253. package/dist/services/agents/projectRoot.cjs +2 -0
  254. package/dist/services/agents/projectRoot.cjs.map +1 -0
  255. package/dist/services/agents/projectRoot.mjs +2 -0
  256. package/dist/services/agents/projectRoot.mjs.map +1 -0
  257. package/dist/services/agents/settings.cjs +2 -0
  258. package/dist/services/agents/settings.cjs.map +1 -0
  259. package/dist/services/agents/settings.mjs +2 -0
  260. package/dist/services/agents/settings.mjs.map +1 -0
  261. package/dist/services/agents/skills.cjs +0 -0
  262. package/dist/services/agents/skills.cjs.map +1 -0
  263. package/dist/services/agents/skills.mjs +5 -0
  264. package/dist/services/agents/skills.mjs.map +1 -0
  265. package/dist/{agents → services/agents}/types.d.cts +4 -4
  266. package/dist/services/agents/types.d.cts.map +1 -0
  267. package/dist/{agents → services/agents}/types.d.mts +4 -4
  268. package/dist/services/agents/types.d.mts.map +1 -0
  269. package/dist/services/api/backgroundWork.cjs +1 -0
  270. package/dist/services/api/backgroundWork.d.cts +1 -0
  271. package/dist/services/api/backgroundWork.d.mts +1 -0
  272. package/dist/services/api/backgroundWork.mjs +1 -0
  273. package/dist/services/api/capabilityCeiling.cjs +1 -0
  274. package/dist/services/api/capabilityCeiling.d.cts +2 -0
  275. package/dist/services/api/capabilityCeiling.d.mts +2 -0
  276. package/dist/services/api/capabilityCeiling.mjs +2 -0
  277. package/dist/services/api/capabilityCeiling.mjs.map +1 -0
  278. package/dist/services/api/teamSnapshot.cjs +1 -0
  279. package/dist/services/api/teamSnapshot.d.cts +1 -0
  280. package/dist/services/api/teamSnapshot.d.mts +1 -0
  281. package/dist/services/api/teamSnapshot.mjs +2 -0
  282. package/dist/services/api/teamSnapshot.mjs.map +1 -0
  283. package/dist/services/intercom/intercomBridge.cjs.map +1 -0
  284. package/dist/services/intercom/intercomBridge.mjs.map +1 -0
  285. package/dist/services/intercom/nativeTeamChannel.cjs +5 -0
  286. package/dist/services/intercom/nativeTeamChannel.cjs.map +1 -0
  287. package/dist/{intercom → services/intercom}/nativeTeamChannel.d.cts +1 -1
  288. package/dist/services/intercom/nativeTeamChannel.d.cts.map +1 -0
  289. package/dist/{intercom → services/intercom}/nativeTeamChannel.d.mts +1 -1
  290. package/dist/services/intercom/nativeTeamChannel.d.mts.map +1 -0
  291. package/dist/services/intercom/nativeTeamChannel.mjs +5 -0
  292. package/dist/services/intercom/nativeTeamChannel.mjs.map +1 -0
  293. package/dist/services/intercom/supervisorControlChannel.cjs +2 -0
  294. package/dist/services/intercom/supervisorControlChannel.cjs.map +1 -0
  295. package/dist/{intercom → services/intercom}/supervisorControlChannel.mjs +1 -1
  296. package/dist/services/intercom/supervisorControlChannel.mjs.map +1 -0
  297. package/dist/services/runs/background/asyncExecution.cjs +2 -0
  298. package/dist/services/runs/background/asyncExecution.cjs.map +1 -0
  299. package/dist/services/runs/background/asyncExecution.mjs +2 -0
  300. package/dist/services/runs/background/asyncExecution.mjs.map +1 -0
  301. package/dist/services/runs/background/asyncJobTracker.cjs +1 -0
  302. package/dist/services/runs/background/asyncJobTracker.mjs +2 -0
  303. package/dist/services/runs/background/asyncJobTracker.mjs.map +1 -0
  304. package/dist/services/runs/background/cliRunnerEntry.cjs +2 -0
  305. package/dist/services/runs/background/cliRunnerEntry.cjs.map +1 -0
  306. package/dist/services/runs/background/cliRunnerEntry.mjs +2 -0
  307. package/dist/services/runs/background/cliRunnerEntry.mjs.map +1 -0
  308. package/dist/services/runs/background/completionBatcher.cjs.map +1 -0
  309. package/dist/services/runs/background/completionBatcher.mjs +2 -0
  310. package/dist/services/runs/background/completionBatcher.mjs.map +1 -0
  311. package/dist/{runs → services/runs}/background/notify.cjs +1 -1
  312. package/dist/services/runs/background/notify.cjs.map +1 -0
  313. package/dist/{runs → services/runs}/background/notify.mjs +1 -1
  314. package/dist/services/runs/background/notify.mjs.map +1 -0
  315. package/dist/services/runs/background/parentWatchdog.cjs.map +1 -0
  316. package/dist/services/runs/background/parentWatchdog.mjs.map +1 -0
  317. package/dist/services/runs/background/processTerminal.cjs +1 -0
  318. package/dist/services/runs/background/processTerminal.mjs +2 -0
  319. package/dist/services/runs/background/processTerminal.mjs.map +1 -0
  320. package/dist/services/runs/background/resultWatcher.cjs +1 -0
  321. package/dist/services/runs/background/resultWatcher.mjs +2 -0
  322. package/dist/services/runs/background/resultWatcher.mjs.map +1 -0
  323. package/dist/services/runs/background/runIdResolver.cjs +1 -0
  324. package/dist/services/runs/background/runIdResolver.mjs +2 -0
  325. package/dist/services/runs/background/runIdResolver.mjs.map +1 -0
  326. package/dist/services/runs/background/runnerBootstrap.cjs +2 -0
  327. package/dist/services/runs/background/runnerBootstrap.cjs.map +1 -0
  328. package/dist/services/runs/background/runnerBootstrap.mjs +2 -0
  329. package/dist/services/runs/background/runnerBootstrap.mjs.map +1 -0
  330. package/dist/services/runs/background/runnerExecution.cjs +2 -0
  331. package/dist/services/runs/background/runnerExecution.cjs.map +1 -0
  332. package/dist/services/runs/background/runnerExecution.mjs +2 -0
  333. package/dist/services/runs/background/runnerExecution.mjs.map +1 -0
  334. package/dist/{runs → services/runs}/background/runnerReporting.cjs +2 -2
  335. package/dist/services/runs/background/runnerReporting.cjs.map +1 -0
  336. package/dist/{runs → services/runs}/background/runnerReporting.mjs +2 -2
  337. package/dist/services/runs/background/runnerReporting.mjs.map +1 -0
  338. package/dist/services/runs/background/runnerTeamMembership.cjs +2 -0
  339. package/dist/services/runs/background/runnerTeamMembership.cjs.map +1 -0
  340. package/dist/services/runs/background/runnerTeamMembership.mjs +2 -0
  341. package/dist/services/runs/background/runnerTeamMembership.mjs.map +1 -0
  342. package/dist/services/runs/background/spawnHandshake.cjs +2 -0
  343. package/dist/services/runs/background/spawnHandshake.cjs.map +1 -0
  344. package/dist/services/runs/background/spawnHandshake.mjs +2 -0
  345. package/dist/services/runs/background/spawnHandshake.mjs.map +1 -0
  346. package/dist/services/runs/background/staleRunReconciler.cjs +1 -0
  347. package/dist/services/runs/background/staleRunReconciler.mjs +2 -0
  348. package/dist/services/runs/background/staleRunReconciler.mjs.map +1 -0
  349. package/dist/services/runs/background/statusReader.cjs +1 -0
  350. package/dist/services/runs/background/statusReader.mjs +2 -0
  351. package/dist/services/runs/background/statusReader.mjs.map +1 -0
  352. package/dist/services/runs/background/statusWriter.cjs +2 -0
  353. package/dist/services/runs/background/statusWriter.cjs.map +1 -0
  354. package/dist/services/runs/background/statusWriter.mjs +2 -0
  355. package/dist/services/runs/background/statusWriter.mjs.map +1 -0
  356. package/dist/services/runs/background/subagentWait.cjs +2 -0
  357. package/dist/services/runs/background/subagentWait.cjs.map +1 -0
  358. package/dist/services/runs/background/subagentWait.mjs +2 -0
  359. package/dist/services/runs/background/subagentWait.mjs.map +1 -0
  360. package/dist/{runs/background/terminalPersistence.mjs → services/runs/background/terminalPersistence.cjs} +2 -2
  361. package/dist/services/runs/background/terminalPersistence.cjs.map +1 -0
  362. package/dist/services/runs/background/terminalPersistence.mjs +2 -0
  363. package/dist/services/runs/background/terminalPersistence.mjs.map +1 -0
  364. package/dist/services/runs/extensionErrorTelemetry.cjs +2 -0
  365. package/dist/services/runs/extensionErrorTelemetry.cjs.map +1 -0
  366. package/dist/services/runs/extensionErrorTelemetry.mjs +2 -0
  367. package/dist/services/runs/extensionErrorTelemetry.mjs.map +1 -0
  368. package/dist/services/runs/registry/processGroup.cjs.map +1 -0
  369. package/dist/services/runs/registry/processGroup.mjs.map +1 -0
  370. package/dist/services/runs/registry/runRegistry.cjs +1 -0
  371. package/dist/services/runs/registry/runRegistry.mjs +2 -0
  372. package/dist/services/runs/registry/runRegistry.mjs.map +1 -0
  373. package/dist/services/runs/registry/sessionLifecycle.cjs +2 -0
  374. package/dist/services/runs/registry/sessionLifecycle.cjs.map +1 -0
  375. package/dist/services/runs/registry/sessionLifecycle.mjs +2 -0
  376. package/dist/services/runs/registry/sessionLifecycle.mjs.map +1 -0
  377. package/dist/services/runs/registry/suspendedRuns.cjs +1 -0
  378. package/dist/services/runs/registry/suspendedRuns.mjs +2 -0
  379. package/dist/services/runs/registry/suspendedRuns.mjs.map +1 -0
  380. package/dist/services/runs/sdkRunnerEntry.cjs +1 -0
  381. package/dist/services/runs/sdkRunnerEntry.mjs +1 -0
  382. package/dist/services/runs/shared/claudeFableProfile.cjs +4 -0
  383. package/dist/services/runs/shared/claudeFableProfile.cjs.map +1 -0
  384. package/dist/services/runs/shared/claudeFableProfile.mjs +4 -0
  385. package/dist/services/runs/shared/claudeFableProfile.mjs.map +1 -0
  386. package/dist/services/runs/shared/depthGuard.cjs +2 -0
  387. package/dist/services/runs/shared/depthGuard.cjs.map +1 -0
  388. package/dist/services/runs/shared/depthGuard.mjs +2 -0
  389. package/dist/services/runs/shared/depthGuard.mjs.map +1 -0
  390. package/dist/services/runs/shared/mcpDirectToolAllowlist.cjs +2 -0
  391. package/dist/services/runs/shared/mcpDirectToolAllowlist.cjs.map +1 -0
  392. package/dist/services/runs/shared/mcpDirectToolAllowlist.mjs +2 -0
  393. package/dist/services/runs/shared/mcpDirectToolAllowlist.mjs.map +1 -0
  394. package/dist/services/runs/shared/modelFallback.cjs +2 -0
  395. package/dist/services/runs/shared/modelFallback.cjs.map +1 -0
  396. package/dist/services/runs/shared/modelFallback.mjs +2 -0
  397. package/dist/services/runs/shared/modelFallback.mjs.map +1 -0
  398. package/dist/services/runs/shared/modelScope.cjs +2 -0
  399. package/dist/services/runs/shared/modelScope.cjs.map +1 -0
  400. package/dist/services/runs/shared/modelScope.mjs +2 -0
  401. package/dist/services/runs/shared/modelScope.mjs.map +1 -0
  402. package/dist/services/runs/shared/nestedPath.cjs +2 -0
  403. package/dist/services/runs/shared/nestedPath.cjs.map +1 -0
  404. package/dist/services/runs/shared/nestedPath.mjs +2 -0
  405. package/dist/services/runs/shared/nestedPath.mjs.map +1 -0
  406. package/dist/services/runs/shared/piArgs.cjs +2 -0
  407. package/dist/services/runs/shared/piArgs.cjs.map +1 -0
  408. package/dist/services/runs/shared/piArgs.mjs +2 -0
  409. package/dist/services/runs/shared/piArgs.mjs.map +1 -0
  410. package/dist/services/runs/shared/piSpawn.cjs +2 -0
  411. package/dist/services/runs/shared/piSpawn.cjs.map +1 -0
  412. package/dist/services/runs/shared/piSpawn.mjs +2 -0
  413. package/dist/services/runs/shared/piSpawn.mjs.map +1 -0
  414. package/dist/services/runs/shared/runWithConcurrency.cjs +2 -0
  415. package/dist/services/runs/shared/runWithConcurrency.cjs.map +1 -0
  416. package/dist/services/runs/shared/runWithConcurrency.d.cts +25 -0
  417. package/dist/services/runs/shared/runWithConcurrency.d.cts.map +1 -0
  418. package/dist/services/runs/shared/runWithConcurrency.d.mts +25 -0
  419. package/dist/services/runs/shared/runWithConcurrency.d.mts.map +1 -0
  420. package/dist/services/runs/shared/runWithConcurrency.mjs +2 -0
  421. package/dist/services/runs/shared/runWithConcurrency.mjs.map +1 -0
  422. package/dist/services/runs/shared/runtimeRegistry.cjs +2 -0
  423. package/dist/services/runs/shared/runtimeRegistry.cjs.map +1 -0
  424. package/dist/services/runs/shared/runtimeRegistry.mjs +2 -0
  425. package/dist/services/runs/shared/runtimeRegistry.mjs.map +1 -0
  426. package/dist/services/runs/shared/structuredOutput.cjs +2 -0
  427. package/dist/{runs → services/runs}/shared/structuredOutput.cjs.map +1 -1
  428. package/dist/services/runs/shared/structuredOutput.mjs +2 -0
  429. package/dist/{runs → services/runs}/shared/structuredOutput.mjs.map +1 -1
  430. package/dist/services/runs/shared/toolAvailability.cjs +2 -0
  431. package/dist/services/runs/shared/toolAvailability.cjs.map +1 -0
  432. package/dist/services/runs/shared/toolAvailability.mjs +2 -0
  433. package/dist/services/runs/shared/toolAvailability.mjs.map +1 -0
  434. package/dist/services/runs/shared/toolBudget.cjs +2 -0
  435. package/dist/services/runs/shared/toolBudget.cjs.map +1 -0
  436. package/dist/services/runs/shared/toolBudget.mjs +2 -0
  437. package/dist/services/runs/shared/toolBudget.mjs.map +1 -0
  438. package/dist/shared/artifacts.cjs.map +1 -1
  439. package/dist/shared/artifacts.mjs.map +1 -1
  440. package/dist/shared/atomicJson.cjs +1 -2
  441. package/dist/shared/atomicJson.mjs +1 -1
  442. package/dist/shared/atomicJson.mjs.map +1 -1
  443. package/dist/shared/childTranscript.cjs +1 -5
  444. package/dist/shared/childTranscript.mjs +1 -4
  445. package/dist/shared/childTranscript.mjs.map +1 -1
  446. package/dist/shared/fileSystemRetry.cjs +1 -1
  447. package/dist/shared/fileSystemRetry.cjs.map +1 -1
  448. package/dist/shared/fileSystemRetry.mjs +1 -1
  449. package/dist/shared/fileSystemRetry.mjs.map +1 -1
  450. package/dist/shared/formatters.cjs.map +1 -1
  451. package/dist/shared/formatters.mjs.map +1 -1
  452. package/dist/shared/paths.cjs +1 -1
  453. package/dist/shared/paths.cjs.map +1 -1
  454. package/dist/shared/paths.mjs +1 -1
  455. package/dist/shared/paths.mjs.map +1 -1
  456. package/dist/shared/pollScheduler.cjs +1 -2
  457. package/dist/shared/pollScheduler.mjs +1 -1
  458. package/dist/shared/pollScheduler.mjs.map +1 -1
  459. package/dist/shared/scopeOwner.cjs +1 -2
  460. package/dist/shared/scopeOwner.mjs +1 -1
  461. package/dist/shared/scopeOwner.mjs.map +1 -1
  462. package/dist/tui/agentCatalog.cjs +1 -1
  463. package/dist/tui/agentCatalog.cjs.map +1 -1
  464. package/dist/tui/agentCatalog.mjs +1 -1
  465. package/dist/tui/agentCatalog.mjs.map +1 -1
  466. package/dist/tui/agentResourceProjection.cjs +1 -1
  467. package/dist/tui/agentResourceProjection.cjs.map +1 -1
  468. package/dist/tui/agentResourceProjection.mjs +1 -1
  469. package/dist/tui/agentResourceProjection.mjs.map +1 -1
  470. package/dist/tui/completionNotice.cjs +1 -1
  471. package/dist/tui/completionNotice.cjs.map +1 -1
  472. package/dist/tui/completionNotice.mjs +1 -1
  473. package/dist/tui/completionNotice.mjs.map +1 -1
  474. package/dist/tui/fleet.cjs +2 -2
  475. package/dist/tui/fleet.cjs.map +1 -1
  476. package/dist/tui/fleet.mjs +2 -2
  477. package/dist/tui/fleet.mjs.map +1 -1
  478. package/dist/tui/fleetAgentView.cjs.map +1 -1
  479. package/dist/tui/fleetAgentView.mjs.map +1 -1
  480. package/dist/tui/fleetStatus.cjs +1 -1
  481. package/dist/tui/fleetStatus.cjs.map +1 -1
  482. package/dist/tui/fleetStatus.mjs +1 -1
  483. package/dist/tui/fleetStatus.mjs.map +1 -1
  484. package/dist/tui/fleetTranscript.cjs +1 -1
  485. package/dist/tui/fleetTranscript.cjs.map +1 -1
  486. package/dist/tui/fleetTranscript.mjs +1 -1
  487. package/dist/tui/fleetTranscript.mjs.map +1 -1
  488. package/dist/tui/register.cjs +1 -1
  489. package/dist/tui/register.cjs.map +1 -1
  490. package/dist/tui/register.mjs +1 -1
  491. package/dist/tui/register.mjs.map +1 -1
  492. package/dist/tui/subagentToolRender.cjs +3 -0
  493. package/dist/tui/subagentToolRender.cjs.map +1 -0
  494. package/dist/tui/subagentToolRender.mjs +3 -0
  495. package/dist/tui/subagentToolRender.mjs.map +1 -0
  496. package/dist/{types.d.cts → types/index.d.cts} +2 -2
  497. package/dist/types/index.d.cts.map +1 -0
  498. package/dist/{types.d.mts → types/index.d.mts} +2 -2
  499. package/dist/types/index.d.mts.map +1 -0
  500. package/package.json +23 -16
  501. package/dist/agents/discovery.cjs +0 -2
  502. package/dist/agents/discovery.cjs.map +0 -1
  503. package/dist/agents/discovery.mjs +0 -2
  504. package/dist/agents/discovery.mjs.map +0 -1
  505. package/dist/agents/frontmatter.cjs.map +0 -1
  506. package/dist/agents/frontmatter.mjs.map +0 -1
  507. package/dist/agents/loader.cjs +0 -2
  508. package/dist/agents/loader.cjs.map +0 -1
  509. package/dist/agents/loader.mjs +0 -2
  510. package/dist/agents/loader.mjs.map +0 -1
  511. package/dist/agents/memory.cjs +0 -3
  512. package/dist/agents/memory.cjs.map +0 -1
  513. package/dist/agents/memory.mjs.map +0 -1
  514. package/dist/agents/projectRoot.cjs +0 -2
  515. package/dist/agents/projectRoot.cjs.map +0 -1
  516. package/dist/agents/projectRoot.mjs +0 -2
  517. package/dist/agents/projectRoot.mjs.map +0 -1
  518. package/dist/agents/settings.cjs +0 -2
  519. package/dist/agents/settings.cjs.map +0 -1
  520. package/dist/agents/settings.mjs +0 -2
  521. package/dist/agents/settings.mjs.map +0 -1
  522. package/dist/agents/skills.cjs +0 -0
  523. package/dist/agents/skills.cjs.map +0 -1
  524. package/dist/agents/skills.mjs +0 -5
  525. package/dist/agents/skills.mjs.map +0 -1
  526. package/dist/agents/types.d.cts.map +0 -1
  527. package/dist/agents/types.d.mts.map +0 -1
  528. package/dist/api/capabilityCeiling.mjs.map +0 -1
  529. package/dist/api/teamSnapshot.mjs.map +0 -1
  530. package/dist/env.cjs.map +0 -1
  531. package/dist/env.d.cts.map +0 -1
  532. package/dist/env.d.mts.map +0 -1
  533. package/dist/extension.cjs +0 -2
  534. package/dist/extension.cjs.map +0 -1
  535. package/dist/extension.mjs +0 -2
  536. package/dist/extension.mjs.map +0 -1
  537. package/dist/intercom/intercomBridge.cjs.map +0 -1
  538. package/dist/intercom/intercomBridge.mjs.map +0 -1
  539. package/dist/intercom/nativeTeamChannel.cjs +0 -5
  540. package/dist/intercom/nativeTeamChannel.cjs.map +0 -1
  541. package/dist/intercom/nativeTeamChannel.d.cts.map +0 -1
  542. package/dist/intercom/nativeTeamChannel.d.mts.map +0 -1
  543. package/dist/intercom/nativeTeamChannel.mjs +0 -5
  544. package/dist/intercom/nativeTeamChannel.mjs.map +0 -1
  545. package/dist/intercom/supervisorControlChannel.cjs +0 -2
  546. package/dist/intercom/supervisorControlChannel.cjs.map +0 -1
  547. package/dist/intercom/supervisorControlChannel.mjs.map +0 -1
  548. package/dist/protocol/backgroundWork.cjs +0 -2
  549. package/dist/protocol/backgroundWork.d.cts.map +0 -1
  550. package/dist/protocol/backgroundWork.d.mts.map +0 -1
  551. package/dist/protocol/backgroundWork.mjs +0 -2
  552. package/dist/protocol/backgroundWork.mjs.map +0 -1
  553. package/dist/protocol/capabilityCeiling.cjs +0 -2
  554. package/dist/protocol/capabilityCeiling.cjs.map +0 -1
  555. package/dist/protocol/capabilityCeiling.d.cts.map +0 -1
  556. package/dist/protocol/capabilityCeiling.d.mts.map +0 -1
  557. package/dist/protocol/capabilityCeiling.mjs +0 -2
  558. package/dist/protocol/capabilityCeiling.mjs.map +0 -1
  559. package/dist/protocol/delegation.cjs.map +0 -1
  560. package/dist/protocol/delegation.d.cts.map +0 -1
  561. package/dist/protocol/delegation.d.mts.map +0 -1
  562. package/dist/protocol/delegation.mjs.map +0 -1
  563. package/dist/runs/background/asyncExecution.cjs +0 -2
  564. package/dist/runs/background/asyncExecution.cjs.map +0 -1
  565. package/dist/runs/background/asyncExecution.mjs +0 -2
  566. package/dist/runs/background/asyncExecution.mjs.map +0 -1
  567. package/dist/runs/background/asyncJobTracker.cjs +0 -2
  568. package/dist/runs/background/asyncJobTracker.cjs.map +0 -1
  569. package/dist/runs/background/asyncJobTracker.mjs +0 -2
  570. package/dist/runs/background/asyncJobTracker.mjs.map +0 -1
  571. package/dist/runs/background/cliRunnerEntry.cjs.map +0 -1
  572. package/dist/runs/background/cliRunnerEntry.mjs.map +0 -1
  573. package/dist/runs/background/completionBatcher.cjs.map +0 -1
  574. package/dist/runs/background/completionBatcher.mjs +0 -2
  575. package/dist/runs/background/completionBatcher.mjs.map +0 -1
  576. package/dist/runs/background/notify.cjs.map +0 -1
  577. package/dist/runs/background/notify.mjs.map +0 -1
  578. package/dist/runs/background/parentWatchdog.cjs.map +0 -1
  579. package/dist/runs/background/parentWatchdog.mjs.map +0 -1
  580. package/dist/runs/background/processTerminal.cjs +0 -2
  581. package/dist/runs/background/processTerminal.cjs.map +0 -1
  582. package/dist/runs/background/processTerminal.mjs +0 -2
  583. package/dist/runs/background/processTerminal.mjs.map +0 -1
  584. package/dist/runs/background/resultWatcher.cjs +0 -2
  585. package/dist/runs/background/resultWatcher.cjs.map +0 -1
  586. package/dist/runs/background/resultWatcher.mjs +0 -2
  587. package/dist/runs/background/resultWatcher.mjs.map +0 -1
  588. package/dist/runs/background/runIdResolver.cjs +0 -2
  589. package/dist/runs/background/runIdResolver.cjs.map +0 -1
  590. package/dist/runs/background/runIdResolver.mjs +0 -2
  591. package/dist/runs/background/runIdResolver.mjs.map +0 -1
  592. package/dist/runs/background/runnerBootstrap.cjs +0 -2
  593. package/dist/runs/background/runnerBootstrap.cjs.map +0 -1
  594. package/dist/runs/background/runnerBootstrap.mjs +0 -2
  595. package/dist/runs/background/runnerBootstrap.mjs.map +0 -1
  596. package/dist/runs/background/runnerExecution.cjs +0 -2
  597. package/dist/runs/background/runnerExecution.cjs.map +0 -1
  598. package/dist/runs/background/runnerExecution.mjs +0 -2
  599. package/dist/runs/background/runnerExecution.mjs.map +0 -1
  600. package/dist/runs/background/runnerReporting.cjs.map +0 -1
  601. package/dist/runs/background/runnerReporting.mjs.map +0 -1
  602. package/dist/runs/background/runnerTeamMembership.cjs +0 -2
  603. package/dist/runs/background/runnerTeamMembership.cjs.map +0 -1
  604. package/dist/runs/background/runnerTeamMembership.mjs +0 -2
  605. package/dist/runs/background/runnerTeamMembership.mjs.map +0 -1
  606. package/dist/runs/background/spawnHandshake.cjs +0 -2
  607. package/dist/runs/background/spawnHandshake.cjs.map +0 -1
  608. package/dist/runs/background/spawnHandshake.mjs +0 -2
  609. package/dist/runs/background/spawnHandshake.mjs.map +0 -1
  610. package/dist/runs/background/staleRunReconciler.cjs +0 -2
  611. package/dist/runs/background/staleRunReconciler.cjs.map +0 -1
  612. package/dist/runs/background/staleRunReconciler.mjs +0 -2
  613. package/dist/runs/background/staleRunReconciler.mjs.map +0 -1
  614. package/dist/runs/background/statusReader.cjs +0 -2
  615. package/dist/runs/background/statusReader.cjs.map +0 -1
  616. package/dist/runs/background/statusReader.mjs +0 -2
  617. package/dist/runs/background/statusReader.mjs.map +0 -1
  618. package/dist/runs/background/statusWriter.cjs +0 -2
  619. package/dist/runs/background/statusWriter.cjs.map +0 -1
  620. package/dist/runs/background/statusWriter.mjs +0 -2
  621. package/dist/runs/background/statusWriter.mjs.map +0 -1
  622. package/dist/runs/background/subagentWait.cjs +0 -2
  623. package/dist/runs/background/subagentWait.cjs.map +0 -1
  624. package/dist/runs/background/subagentWait.mjs +0 -2
  625. package/dist/runs/background/subagentWait.mjs.map +0 -1
  626. package/dist/runs/background/terminalPersistence.cjs +0 -2
  627. package/dist/runs/background/terminalPersistence.cjs.map +0 -1
  628. package/dist/runs/background/terminalPersistence.mjs.map +0 -1
  629. package/dist/runs/registry/processGroup.cjs.map +0 -1
  630. package/dist/runs/registry/processGroup.mjs.map +0 -1
  631. package/dist/runs/registry/runRegistry.cjs +0 -2
  632. package/dist/runs/registry/runRegistry.cjs.map +0 -1
  633. package/dist/runs/registry/runRegistry.mjs +0 -2
  634. package/dist/runs/registry/runRegistry.mjs.map +0 -1
  635. package/dist/runs/registry/sessionLifecycle.cjs +0 -2
  636. package/dist/runs/registry/sessionLifecycle.cjs.map +0 -1
  637. package/dist/runs/registry/sessionLifecycle.mjs +0 -2
  638. package/dist/runs/registry/sessionLifecycle.mjs.map +0 -1
  639. package/dist/runs/registry/suspendedRuns.cjs +0 -4
  640. package/dist/runs/registry/suspendedRuns.cjs.map +0 -1
  641. package/dist/runs/registry/suspendedRuns.mjs +0 -4
  642. package/dist/runs/registry/suspendedRuns.mjs.map +0 -1
  643. package/dist/runs/sdkRunnerEntry.cjs.map +0 -1
  644. package/dist/runs/sdkRunnerEntry.mjs.map +0 -1
  645. package/dist/runs/shared/claudeFableProfile.cjs +0 -4
  646. package/dist/runs/shared/claudeFableProfile.cjs.map +0 -1
  647. package/dist/runs/shared/claudeFableProfile.mjs +0 -4
  648. package/dist/runs/shared/claudeFableProfile.mjs.map +0 -1
  649. package/dist/runs/shared/depthGuard.cjs +0 -2
  650. package/dist/runs/shared/depthGuard.cjs.map +0 -1
  651. package/dist/runs/shared/depthGuard.mjs +0 -2
  652. package/dist/runs/shared/depthGuard.mjs.map +0 -1
  653. package/dist/runs/shared/mcpDirectToolAllowlist.cjs +0 -2
  654. package/dist/runs/shared/mcpDirectToolAllowlist.cjs.map +0 -1
  655. package/dist/runs/shared/mcpDirectToolAllowlist.mjs +0 -2
  656. package/dist/runs/shared/mcpDirectToolAllowlist.mjs.map +0 -1
  657. package/dist/runs/shared/modelFallback.cjs +0 -2
  658. package/dist/runs/shared/modelFallback.cjs.map +0 -1
  659. package/dist/runs/shared/modelFallback.mjs +0 -2
  660. package/dist/runs/shared/modelFallback.mjs.map +0 -1
  661. package/dist/runs/shared/modelScope.cjs +0 -2
  662. package/dist/runs/shared/modelScope.cjs.map +0 -1
  663. package/dist/runs/shared/modelScope.mjs +0 -2
  664. package/dist/runs/shared/modelScope.mjs.map +0 -1
  665. package/dist/runs/shared/nestedPath.cjs +0 -2
  666. package/dist/runs/shared/nestedPath.cjs.map +0 -1
  667. package/dist/runs/shared/nestedPath.mjs +0 -2
  668. package/dist/runs/shared/nestedPath.mjs.map +0 -1
  669. package/dist/runs/shared/piArgs.cjs +0 -2
  670. package/dist/runs/shared/piArgs.cjs.map +0 -1
  671. package/dist/runs/shared/piArgs.mjs +0 -2
  672. package/dist/runs/shared/piArgs.mjs.map +0 -1
  673. package/dist/runs/shared/piSpawn.cjs +0 -2
  674. package/dist/runs/shared/piSpawn.cjs.map +0 -1
  675. package/dist/runs/shared/piSpawn.mjs +0 -2
  676. package/dist/runs/shared/piSpawn.mjs.map +0 -1
  677. package/dist/runs/shared/runWithConcurrency.cjs +0 -2
  678. package/dist/runs/shared/runWithConcurrency.cjs.map +0 -1
  679. package/dist/runs/shared/runWithConcurrency.mjs +0 -2
  680. package/dist/runs/shared/runWithConcurrency.mjs.map +0 -1
  681. package/dist/runs/shared/runtimeRegistry.cjs +0 -2
  682. package/dist/runs/shared/runtimeRegistry.cjs.map +0 -1
  683. package/dist/runs/shared/runtimeRegistry.mjs +0 -2
  684. package/dist/runs/shared/runtimeRegistry.mjs.map +0 -1
  685. package/dist/runs/shared/structuredOutput.cjs +0 -2
  686. package/dist/runs/shared/structuredOutput.mjs +0 -2
  687. package/dist/runs/shared/toolAvailability.cjs +0 -2
  688. package/dist/runs/shared/toolAvailability.cjs.map +0 -1
  689. package/dist/runs/shared/toolAvailability.mjs +0 -2
  690. package/dist/runs/shared/toolAvailability.mjs.map +0 -1
  691. package/dist/runs/shared/toolBudget.cjs +0 -2
  692. package/dist/runs/shared/toolBudget.cjs.map +0 -1
  693. package/dist/runs/shared/toolBudget.mjs +0 -2
  694. package/dist/runs/shared/toolBudget.mjs.map +0 -1
  695. package/dist/shared/atomicJson.cjs.map +0 -1
  696. package/dist/shared/childTranscript.cjs.map +0 -1
  697. package/dist/shared/pollScheduler.cjs.map +0 -1
  698. package/dist/shared/scopeOwner.cjs.map +0 -1
  699. package/dist/slash/chainExpression.cjs.map +0 -1
  700. package/dist/slash/chainExpression.mjs.map +0 -1
  701. package/dist/slash/doctor.cjs +0 -5
  702. package/dist/slash/doctor.mjs +0 -5
  703. package/dist/slash/doctor.mjs.map +0 -1
  704. package/dist/slash/slashCommands.cjs.map +0 -1
  705. package/dist/slash/slashCommands.mjs.map +0 -1
  706. package/dist/slash/spawnRequestMapping.cjs.map +0 -1
  707. package/dist/slash/spawnRequestMapping.mjs.map +0 -1
  708. package/dist/slash/subagentLaunch.cjs +0 -2
  709. package/dist/slash/subagentLaunch.cjs.map +0 -1
  710. package/dist/slash/subagentLaunch.mjs +0 -2
  711. package/dist/slash/subagentLaunch.mjs.map +0 -1
  712. package/dist/types.d.cts.map +0 -1
  713. package/dist/types.d.mts.map +0 -1
  714. /package/dist/{slash → commands/slash}/chainExpression.cjs +0 -0
  715. /package/dist/{slash → commands/slash}/chainExpression.mjs +0 -0
  716. /package/dist/{slash → commands/slash}/spawnRequestMapping.cjs +0 -0
  717. /package/dist/{slash → commands/slash}/spawnRequestMapping.mjs +0 -0
  718. /package/dist/{protocol → schemas/team}/delegation.cjs +0 -0
  719. /package/dist/{protocol → schemas/team}/delegation.mjs +0 -0
  720. /package/dist/{agents → services/agents}/frontmatter.cjs +0 -0
  721. /package/dist/{intercom → services/intercom}/intercomBridge.cjs +0 -0
  722. /package/dist/{intercom → services/intercom}/intercomBridge.mjs +0 -0
  723. /package/dist/{runs → services/runs}/background/completionBatcher.cjs +0 -0
  724. /package/dist/{runs → services/runs}/background/parentWatchdog.cjs +0 -0
  725. /package/dist/{runs → services/runs}/background/parentWatchdog.mjs +0 -0
  726. /package/dist/{runs → services/runs}/registry/processGroup.cjs +0 -0
  727. /package/dist/{runs → services/runs}/registry/processGroup.mjs +0 -0
@@ -0,0 +1,2 @@
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../adapters/atomicJson.cjs`);require(`../../../shared/atomicJson.cjs`);const n=require(`../../../adapters/process/env.cjs`),r=require(`../../../shared/paths.cjs`),i=require(`./statusWriter.cjs`),a=require(`../../../adapters/statusReader.cjs`);require(`./statusReader.cjs`);const o=require(`../shared/claudeFableProfile.cjs`),s=require(`./parentWatchdog.cjs`);let c=require(`node:fs`);c=e.__toESM(c,1);let l=require(`node:child_process`),u=require(`@agimon-ai/doompi-telemetry`),d=require(`@agimon-ai/doompi-extension-contracts/child-process`);const f=`Parent process was lost.`,p=`SIGKILL`;function m(e){return e instanceof Error?e.message:String(e)}function h(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function g(e){let t=JSON.parse(c.readFileSync(r.currentRunConfigPath(e),`utf8`));if(!h(t)||t.runId!==e||typeof t.command!=`string`)throw Error(`CLI launch config for run '${e}' is invalid.`);return t}function _(e,t,n){let r=e+t;for(;Buffer.byteLength(r,`utf8`)>n&&r.length>0;){let e=Buffer.byteLength(r,`utf8`)-n;r=r.slice(Math.max(1,Math.ceil(e/2)))}return r}let v;async function y(e,t,n){let r=v;v=void 0,r&&(n===void 0?await r.recordEvent(e,t):await r.recordError(e,n,t),await r.flush(),await r.shutdown())}async function b(){let e=Date.now();v=(0,u.createDoomTelemetry)({serviceName:`doom-team-cli-child`,packageName:`@agimon-ai/doompi-team`,env:process.env,enableLogs:!0,enableTraces:!0});let h=process.env[n.SUBAGENT_RUN_ID_ENV]?.trim();if(!h)throw Error(`${n.SUBAGENT_RUN_ID_ENV} is required.`);if(!r.adoptSessionScopeFromEnv())throw Error(`${d.SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);let b;try{b=g(h)}catch(e){throw b?.handshakePath&&!c.existsSync(b.handshakePath)&&t.writeAtomicJson(b.handshakePath,{state:`error`,error:m(e)}),e}let x=new i.CoalescedStatusWriter,S=Date.now();await v?.recordEvent(`doom_team.child_started`,{runtime:b.runtime,"agent.name":b.agent,outcome:`started`}),x.open(h,a.readAsyncRunStatus(h)??{version:1,runId:h,...b.operationId?{operationId:b.operationId}:{},agent:b.agent,cwd:b.cwd,runtime:b.runtime,state:`queued`,startedAt:S,lastUpdate:S});let C=b.profile===o.CLAUDE_FABLE_PROFILE;if(b.profile!==void 0&&!C)throw Error(`Untrusted external profile.`);if(C&&(!b.stdinPath||!b.profileResultPath))throw Error(`Fable profile launch config is incomplete.`);let w=C?c.openSync(b.stdinPath,`r`):void 0,T;try{T=(0,l.spawn)(b.command,b.args,{cwd:b.cwd,env:C?b.env:{...process.env,...b.env},stdio:[w??`ignore`,`pipe`,`pipe`],detached:!0,windowsHide:!0})}catch(e){throw C&&(o.cleanupClaudeFableLaunch({cleanupPaths:b.cleanupPaths??[]}),b.profileResultPath&&c.rmSync(b.profileResultPath,{force:!0})),e}finally{w!==void 0&&c.closeSync(w)}let E=e=>{C&&(o.cleanupClaudeFableLaunch({cleanupPaths:b.cleanupPaths??[]}),e&&b.profileResultPath&&c.rmSync(b.profileResultPath,{force:!0}))},D,O=e=>{if(D=e,T.pid)try{process.kill(-T.pid,e)}catch(e){process.stderr.write(`[doom-team cli runner] Could not signal vendor process: ${m(e)}\n`)}};process.once(`SIGTERM`,O),process.once(`SIGINT`,O);try{await new Promise((e,t)=>{T.once(`spawn`,e),T.once(`error`,t)}),t.writeAtomicJson(b.handshakePath,{state:`ready`}),x.updateSync(e=>{e.state=`running`,e.activityState=`working`,e.lastUpdate=Date.now()})}catch(n){let r=m(n);t.writeAtomicJson(b.handshakePath,{state:`error`,error:r}),x.updateSync(e=>{e.state=`failed`,e.error=r,e.lastUpdate=Date.now(),e.endedAt=Date.now()}),t.writeAtomicJson(b.resultPath,{runId:h,...b.internal?{internal:!0}:{},...b.operationId?{operationId:b.operationId}:{},agent:b.agent,runtime:b.runtime,success:!1,summary:C?`Fable Claude launch failed.`:r}),x.close(),E(!0),await y(`doom_team.child_failed`,{runtime:b.runtime,"agent.name":b.agent,duration_ms:Date.now()-e,outcome:`failed`},n),process.exit(1)}let k=s.startParentWatchdog({onParentLost:()=>{O(p);let n=Date.now();x.updateSync(e=>{e.state=`stopped`,e.error=f,e.lastUpdate=n,e.endedAt=n}),t.writeAtomicJson(b.resultPath,{runId:h,...b.internal?{internal:!0}:{},...b.operationId?{operationId:b.operationId}:{},agent:b.agent,runtime:b.runtime,success:!1,summary:f,signal:p}),x.close(),E(!0),y(`doom_team.child_finished`,{runtime:b.runtime,"agent.name":b.agent,duration_ms:Date.now()-e,outcome:`parent_lost`}).finally(()=>process.exit(0))}}),A=``,j=``;T.stdout?.on(`data`,e=>{A=_(A,e.toString(`utf8`),65536)}),T.stderr?.on(`data`,e=>{j=_(j,e.toString(`utf8`),8192)});let M=await new Promise(e=>{T.on(`error`,t=>e({code:null,signal:null,error:t})),T.on(`close`,(t,n)=>e({code:t,signal:n}))});k();let N=D!==void 0,P;if(C&&!N&&M.error===void 0&&M.code===0)try{let e=o.parseClaudeFableOutput(A);t.writePrivateAtomicJson(b.profileResultPath,{text:e.text,outputBytes:e.outputBytes})}catch(e){P=e instanceof Error?e:Error(String(e))}let F=!N&&M.error===void 0&&M.code===0&&P===void 0,I=C?P?.message??`Fable Claude launch failed.`:j.trim()||`${b.runtime} exited with ${M.signal??`code ${M.code??`unknown`}`}.`,L=N?`Stopped by ${D}.`:F?C?`Fable profile completed.`:A.trim():M.error?.message??I,R=Date.now();x.updateSync(e=>{e.state=N?`stopped`:F?`completed`:`failed`,e.activityState=`finalizing`,e.summary=L,F||(e.error=L),e.lastUpdate=R,e.endedAt=R}),t.writeAtomicJson(b.resultPath,{runId:h,...b.internal?{internal:!0}:{},...b.operationId?{operationId:b.operationId}:{},agent:b.agent,runtime:b.runtime,success:F,summary:L,...M.code===null?{}:{exitCode:M.code},...M.signal?{signal:M.signal}:{}}),x.close(),E(!F),await y(`doom_team.child_finished`,{runtime:b.runtime,"agent.name":b.agent,duration_ms:Date.now()-e,"runner.stdout_bytes":Buffer.byteLength(A,`utf8`),"runner.stderr_bytes":Buffer.byteLength(j,`utf8`),"runner.exit_code":M.code??0,outcome:N?`stopped`:F?`completed`:`failed`}),process.exit(0)}b().catch(async e=>{await y(`doom_team.child_failed`,{outcome:`failed`},e),process.stderr.write(`[doom-team cli runner] ${m(e)}\n`),process.exitCode=1});
2
+ //# sourceMappingURL=cliRunnerEntry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliRunnerEntry.cjs","names":["fs","currentRunConfigPath","SUBAGENT_RUN_ID_ENV","adoptSessionScopeFromEnv","SUBAGENT_ROOT_SESSION_ENV","CoalescedStatusWriter","readAsyncRunStatus","CLAUDE_FABLE_PROFILE","startParentWatchdog","parseClaudeFableOutput"],"sources":["../../../../src/services/runs/background/cliRunnerEntry.ts"],"sourcesContent":["/**\n * The detached child process for an external agent CLI.\n *\n * Counterpart to `sdkRunnerEntry.ts`, which does the same job for the\n * in-process Pi runtime. Both are spawned by `AsyncSubagentSpawner`, both write\n * the same `status.json` and the same terminal result, and both signal the same\n * handshake - so `AsyncJobTracker`, `ResultWatcher`, the fleet view, internal\n * completion monitors, and public `subagent` status handling cannot tell them apart.\n *\n * WHAT AN EXTERNAL CHILD DOES NOT GET, STATED PLAINLY:\n * No intercom, no steering, no structured output. Those\n * are delivered by `subagentPromptRuntime.ts`, which Pi loads in-process into\n * a Pi child; an arbitrary CLI has nowhere to load it. Team package tool\n * exclusions are therefore best effort for external runtimes. An external\n * child is a one-shot worker: it receives a prompt and returns output. Stop and interrupt\n * still work, because they are process-group signals rather than cooperative\n * file requests.\n *\n * WHY THE OUTPUT IS RECORDED, NOT PARSED:\n * A generic runner cannot know what a given CLI's output means. Trailing stdout\n * is the result; anything more specific would either be wrong for a CLI nobody\n * tested or lock the config to the two that were.\n *\n * AVOID:\n * - Vendor-specific parsing here. If a runtime needs it, that is a different\n * module and a deliberate decision\n */\n\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\n\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from '../../../adapters/process/env.ts';\nimport { writeAtomicJson, writePrivateAtomicJson } from '../../../shared/atomicJson.ts';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../../../shared/paths.ts';\nimport {\n CLAUDE_FABLE_PROFILE,\n cleanupClaudeFableLaunch,\n parseClaudeFableOutput,\n} from '../shared/claudeFableProfile.ts';\nimport type { AsyncRunStatus } from './asyncExecution.ts';\nimport type { CliLaunchConfig } from './cliLaunchConfig.ts';\nimport { startParentWatchdog } from './parentWatchdog.ts';\nimport { readAsyncRunStatus } from './statusReader.ts';\nimport { CoalescedStatusWriter } from './statusWriter.ts';\n\n/** How much trailing stdout is kept as the run's result. */\nconst MAX_RESULT_BYTES = 64 * 1024;\n/** How much stderr is kept for a failure message. */\nconst MAX_STDERR_BYTES = 8 * 1024;\nconst PARENT_LOST_MESSAGE = 'Parent process was lost.';\nconst FORCE_KILL_SIGNAL: NodeJS.Signals = 'SIGKILL';\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readLaunchConfig(runId: string): CliLaunchConfig {\n const parsed: unknown = JSON.parse(fs.readFileSync(currentRunConfigPath(runId), 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || typeof parsed.command !== 'string') {\n throw new Error(`CLI launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as CliLaunchConfig;\n}\n\n/** Keep only a UTF-8-safe trailing value within `limit` bytes, so a chatty CLI cannot exhaust memory. */\nfunction appendBounded(buffer: string, chunk: string, limit: number): string {\n let combined = buffer + chunk;\n while (Buffer.byteLength(combined, 'utf8') > limit && combined.length > 0) {\n const excess = Buffer.byteLength(combined, 'utf8') - limit;\n combined = combined.slice(Math.max(1, Math.ceil(excess / 2)));\n }\n return combined;\n}\n\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nasync function run(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-cli-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: CliLaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n // The vendor process emits its own spawn event before the ready handshake\n // is written below. Reading the config alone is not sufficient evidence\n // that the configured executable can start.\n } catch (error) {\n if (config?.handshakePath && !fs.existsSync(config.handshakePath)) {\n writeAtomicJson(config.handshakePath, { state: 'error', error: errorMessage(error) });\n }\n throw error;\n }\n\n const statusWriter = new CoalescedStatusWriter<AsyncRunStatus>();\n const now = Date.now();\n await childTelemetry?.recordEvent('doom_team.child_started', {\n runtime: config.runtime,\n 'agent.name': config.agent,\n outcome: 'started',\n });\n statusWriter.open(\n runId,\n readAsyncRunStatus(runId) ?? {\n version: 1,\n runId,\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n cwd: config.cwd,\n runtime: config.runtime,\n state: 'queued',\n startedAt: now,\n lastUpdate: now,\n },\n );\n\n const profileLaunch = config.profile === CLAUDE_FABLE_PROFILE;\n if (config.profile !== undefined && !profileLaunch) throw new Error('Untrusted external profile.');\n if (profileLaunch && (!config.stdinPath || !config.profileResultPath)) {\n throw new Error('Fable profile launch config is incomplete.');\n }\n const stdinFd = profileLaunch ? fs.openSync(config.stdinPath!, 'r') : undefined;\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(config.command, config.args, {\n cwd: config.cwd,\n env: profileLaunch ? config.env : { ...process.env, ...config.env },\n stdio: [stdinFd ?? 'ignore', 'pipe', 'pipe'],\n // Its own group, so the watchdog below can take the CLI and anything it\n // spawned down together.\n detached: true,\n windowsHide: true,\n });\n } catch (error) {\n if (profileLaunch) {\n cleanupClaudeFableLaunch({ cleanupPaths: config.cleanupPaths ?? [] });\n if (config.profileResultPath) fs.rmSync(config.profileResultPath, { force: true });\n }\n throw error;\n } finally {\n if (stdinFd !== undefined) fs.closeSync(stdinFd);\n }\n const cleanupProfile = (removeResult: boolean): void => {\n if (!profileLaunch) return;\n cleanupClaudeFableLaunch({ cleanupPaths: config.cleanupPaths ?? [] });\n if (removeResult && config.profileResultPath) fs.rmSync(config.profileResultPath, { force: true });\n };\n\n let requestedSignal: NodeJS.Signals | undefined;\n const stopVendor = (signal: NodeJS.Signals): void => {\n requestedSignal = signal;\n if (!child.pid) return;\n try {\n process.kill(-child.pid, signal);\n } catch (error) {\n process.stderr.write(`[doom-team cli runner] Could not signal vendor process: ${errorMessage(error)}\\n`);\n }\n };\n process.once('SIGTERM', stopVendor);\n process.once('SIGINT', stopVendor);\n\n try {\n await new Promise<void>((resolve, reject) => {\n child.once('spawn', resolve);\n child.once('error', reject);\n });\n writeAtomicJson(config.handshakePath, { state: 'ready' });\n statusWriter.updateSync((status) => {\n status.state = 'running';\n status.activityState = 'working';\n status.lastUpdate = Date.now();\n });\n } catch (error) {\n const message = errorMessage(error);\n writeAtomicJson(config.handshakePath, { state: 'error', error: message });\n statusWriter.updateSync((status) => {\n status.state = 'failed';\n status.error = message;\n status.lastUpdate = Date.now();\n status.endedAt = Date.now();\n });\n writeAtomicJson(config.resultPath, {\n runId,\n ...(config.internal ? { internal: true } : {}),\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n runtime: config.runtime,\n success: false,\n summary: profileLaunch ? 'Fable Claude launch failed.' : message,\n });\n statusWriter.close();\n cleanupProfile(true);\n await finishTelemetry(\n 'doom_team.child_failed',\n { runtime: config.runtime, 'agent.name': config.agent, duration_ms: Date.now() - startedAt, outcome: 'failed' },\n error,\n );\n process.exit(1);\n }\n\n // A SIGKILLed parent cannot signal us, so terminate the vendor tree and\n // persist a terminal record before leaving when the watchdog can observe it.\n const stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n stopVendor(FORCE_KILL_SIGNAL);\n const endedAt = Date.now();\n statusWriter.updateSync((status) => {\n status.state = 'stopped';\n status.error = PARENT_LOST_MESSAGE;\n status.lastUpdate = endedAt;\n status.endedAt = endedAt;\n });\n writeAtomicJson(config.resultPath, {\n runId,\n ...(config.internal ? { internal: true } : {}),\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n runtime: config.runtime,\n success: false,\n summary: PARENT_LOST_MESSAGE,\n signal: FORCE_KILL_SIGNAL,\n });\n statusWriter.close();\n cleanupProfile(true);\n void finishTelemetry('doom_team.child_finished', {\n runtime: config.runtime,\n 'agent.name': config.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout = appendBounded(stdout, chunk.toString('utf8'), MAX_RESULT_BYTES);\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr = appendBounded(stderr, chunk.toString('utf8'), MAX_STDERR_BYTES);\n });\n\n const exit = await new Promise<{ code: number | null; signal: NodeJS.Signals | null; error?: Error }>((resolve) => {\n child.on('error', (error) => resolve({ code: null, signal: null, error }));\n child.on('close', (code, signal) => resolve({ code, signal }));\n });\n\n stopWatchdog();\n\n const stopped = requestedSignal !== undefined;\n let profileError: Error | undefined;\n if (profileLaunch && !stopped && exit.error === undefined && exit.code === 0) {\n try {\n const parsed = parseClaudeFableOutput(stdout);\n writePrivateAtomicJson(config.profileResultPath!, { text: parsed.text, outputBytes: parsed.outputBytes });\n } catch (error) {\n profileError = error instanceof Error ? error : new Error(String(error));\n }\n }\n const success = !stopped && exit.error === undefined && exit.code === 0 && profileError === undefined;\n const failureDetail = profileLaunch\n ? (profileError?.message ?? 'Fable Claude launch failed.')\n : stderr.trim() || `${config.runtime} exited with ${exit.signal ?? `code ${exit.code ?? 'unknown'}`}.`;\n const summary = stopped\n ? `Stopped by ${requestedSignal}.`\n : success\n ? profileLaunch\n ? 'Fable profile completed.'\n : stdout.trim()\n : (exit.error?.message ?? failureDetail);\n const endedAt = Date.now();\n\n statusWriter.updateSync((status) => {\n status.state = stopped ? 'stopped' : success ? 'completed' : 'failed';\n status.activityState = 'finalizing';\n status.summary = summary;\n if (!success) status.error = summary;\n status.lastUpdate = endedAt;\n status.endedAt = endedAt;\n });\n writeAtomicJson(config.resultPath, {\n runId,\n ...(config.internal ? { internal: true } : {}),\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n runtime: config.runtime,\n success,\n summary,\n ...(exit.code === null ? {} : { exitCode: exit.code }),\n ...(exit.signal ? { signal: exit.signal } : {}),\n });\n\n statusWriter.close();\n cleanupProfile(!success);\n await finishTelemetry('doom_team.child_finished', {\n runtime: config.runtime,\n 'agent.name': config.agent,\n duration_ms: Date.now() - startedAt,\n 'runner.stdout_bytes': Buffer.byteLength(stdout, 'utf8'),\n 'runner.stderr_bytes': Buffer.byteLength(stderr, 'utf8'),\n 'runner.exit_code': exit.code ?? 0,\n outcome: stopped ? 'stopped' : success ? 'completed' : 'failed',\n });\n // The runner exit code reports transport health. Task success or failure is\n // encoded durably in status and result data before this process exits.\n process.exit(0);\n}\n\nvoid run().catch(async (error: unknown) => {\n await finishTelemetry('doom_team.child_failed', { outcome: 'failed' }, error);\n // Keep stdout reserved for vendor output. Stderr is captured in the run's\n // runner log and makes a transport failure diagnosable by the parent.\n process.stderr.write(`[doom-team cli runner] ${errorMessage(error)}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{writeAtomicJson as e,writePrivateAtomicJson as t}from"../../../adapters/atomicJson.mjs";import{init_atomicJson as n}from"../../../shared/atomicJson.mjs";import{SUBAGENT_ROOT_SESSION_ENV as r,SUBAGENT_RUN_ID_ENV as i,init_env as a}from"../../../adapters/process/env.mjs";import{adoptSessionScopeFromEnv as o,currentRunConfigPath as s,init_paths as c}from"../../../shared/paths.mjs";import{CoalescedStatusWriter as l,init_statusWriter as u}from"./statusWriter.mjs";import{readAsyncRunStatus as d}from"../../../adapters/statusReader.mjs";import{init_statusReader as f}from"./statusReader.mjs";import{CLAUDE_FABLE_PROFILE as p,cleanupClaudeFableLaunch as m,init_claudeFableProfile as h,parseClaudeFableOutput as g}from"../shared/claudeFableProfile.mjs";import{startParentWatchdog as _}from"./parentWatchdog.mjs";import*as v from"node:fs";import{spawn as y}from"node:child_process";import{createDoomTelemetry as b}from"@agimon-ai/doompi-telemetry";a(),n(),c(),h(),f(),u();const x=`Parent process was lost.`,S=`SIGKILL`;function C(e){return e instanceof Error?e.message:String(e)}function w(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function T(e){let t=JSON.parse(v.readFileSync(s(e),`utf8`));if(!w(t)||t.runId!==e||typeof t.command!=`string`)throw Error(`CLI launch config for run '${e}' is invalid.`);return t}function E(e,t,n){let r=e+t;for(;Buffer.byteLength(r,`utf8`)>n&&r.length>0;){let e=Buffer.byteLength(r,`utf8`)-n;r=r.slice(Math.max(1,Math.ceil(e/2)))}return r}let D;async function O(e,t,n){let r=D;D=void 0,r&&(n===void 0?await r.recordEvent(e,t):await r.recordError(e,n,t),await r.flush(),await r.shutdown())}async function k(){let n=Date.now();D=b({serviceName:`doom-team-cli-child`,packageName:`@agimon-ai/doompi-team`,env:process.env,enableLogs:!0,enableTraces:!0});let a=process.env[i]?.trim();if(!a)throw Error(`${i} is required.`);if(!o())throw Error(`${r} is required: a child cannot resolve its session scope without it.`);let s;try{s=T(a)}catch(t){throw s?.handshakePath&&!v.existsSync(s.handshakePath)&&e(s.handshakePath,{state:`error`,error:C(t)}),t}let c=new l,u=Date.now();await D?.recordEvent(`doom_team.child_started`,{runtime:s.runtime,"agent.name":s.agent,outcome:`started`}),c.open(a,d(a)??{version:1,runId:a,...s.operationId?{operationId:s.operationId}:{},agent:s.agent,cwd:s.cwd,runtime:s.runtime,state:`queued`,startedAt:u,lastUpdate:u});let f=s.profile===p;if(s.profile!==void 0&&!f)throw Error(`Untrusted external profile.`);if(f&&(!s.stdinPath||!s.profileResultPath))throw Error(`Fable profile launch config is incomplete.`);let h=f?v.openSync(s.stdinPath,`r`):void 0,w;try{w=y(s.command,s.args,{cwd:s.cwd,env:f?s.env:{...process.env,...s.env},stdio:[h??`ignore`,`pipe`,`pipe`],detached:!0,windowsHide:!0})}catch(e){throw f&&(m({cleanupPaths:s.cleanupPaths??[]}),s.profileResultPath&&v.rmSync(s.profileResultPath,{force:!0})),e}finally{h!==void 0&&v.closeSync(h)}let k=e=>{f&&(m({cleanupPaths:s.cleanupPaths??[]}),e&&s.profileResultPath&&v.rmSync(s.profileResultPath,{force:!0}))},A,j=e=>{if(A=e,w.pid)try{process.kill(-w.pid,e)}catch(e){process.stderr.write(`[doom-team cli runner] Could not signal vendor process: ${C(e)}\n`)}};process.once(`SIGTERM`,j),process.once(`SIGINT`,j);try{await new Promise((e,t)=>{w.once(`spawn`,e),w.once(`error`,t)}),e(s.handshakePath,{state:`ready`}),c.updateSync(e=>{e.state=`running`,e.activityState=`working`,e.lastUpdate=Date.now()})}catch(t){let r=C(t);e(s.handshakePath,{state:`error`,error:r}),c.updateSync(e=>{e.state=`failed`,e.error=r,e.lastUpdate=Date.now(),e.endedAt=Date.now()}),e(s.resultPath,{runId:a,...s.internal?{internal:!0}:{},...s.operationId?{operationId:s.operationId}:{},agent:s.agent,runtime:s.runtime,success:!1,summary:f?`Fable Claude launch failed.`:r}),c.close(),k(!0),await O(`doom_team.child_failed`,{runtime:s.runtime,"agent.name":s.agent,duration_ms:Date.now()-n,outcome:`failed`},t),process.exit(1)}let M=_({onParentLost:()=>{j(S);let t=Date.now();c.updateSync(e=>{e.state=`stopped`,e.error=x,e.lastUpdate=t,e.endedAt=t}),e(s.resultPath,{runId:a,...s.internal?{internal:!0}:{},...s.operationId?{operationId:s.operationId}:{},agent:s.agent,runtime:s.runtime,success:!1,summary:x,signal:S}),c.close(),k(!0),O(`doom_team.child_finished`,{runtime:s.runtime,"agent.name":s.agent,duration_ms:Date.now()-n,outcome:`parent_lost`}).finally(()=>process.exit(0))}}),N=``,P=``;w.stdout?.on(`data`,e=>{N=E(N,e.toString(`utf8`),65536)}),w.stderr?.on(`data`,e=>{P=E(P,e.toString(`utf8`),8192)});let F=await new Promise(e=>{w.on(`error`,t=>e({code:null,signal:null,error:t})),w.on(`close`,(t,n)=>e({code:t,signal:n}))});M();let I=A!==void 0,L;if(f&&!I&&F.error===void 0&&F.code===0)try{let e=g(N);t(s.profileResultPath,{text:e.text,outputBytes:e.outputBytes})}catch(e){L=e instanceof Error?e:Error(String(e))}let R=!I&&F.error===void 0&&F.code===0&&L===void 0,z=f?L?.message??`Fable Claude launch failed.`:P.trim()||`${s.runtime} exited with ${F.signal??`code ${F.code??`unknown`}`}.`,B=I?`Stopped by ${A}.`:R?f?`Fable profile completed.`:N.trim():F.error?.message??z,V=Date.now();c.updateSync(e=>{e.state=I?`stopped`:R?`completed`:`failed`,e.activityState=`finalizing`,e.summary=B,R||(e.error=B),e.lastUpdate=V,e.endedAt=V}),e(s.resultPath,{runId:a,...s.internal?{internal:!0}:{},...s.operationId?{operationId:s.operationId}:{},agent:s.agent,runtime:s.runtime,success:R,summary:B,...F.code===null?{}:{exitCode:F.code},...F.signal?{signal:F.signal}:{}}),c.close(),k(!R),await O(`doom_team.child_finished`,{runtime:s.runtime,"agent.name":s.agent,duration_ms:Date.now()-n,"runner.stdout_bytes":Buffer.byteLength(N,`utf8`),"runner.stderr_bytes":Buffer.byteLength(P,`utf8`),"runner.exit_code":F.code??0,outcome:I?`stopped`:R?`completed`:`failed`}),process.exit(0)}k().catch(async e=>{await O(`doom_team.child_failed`,{outcome:`failed`},e),process.stderr.write(`[doom-team cli runner] ${C(e)}\n`),process.exitCode=1});export{};
2
+ //# sourceMappingURL=cliRunnerEntry.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliRunnerEntry.mjs","names":[],"sources":["../../../../src/services/runs/background/cliRunnerEntry.ts"],"sourcesContent":["/**\n * The detached child process for an external agent CLI.\n *\n * Counterpart to `sdkRunnerEntry.ts`, which does the same job for the\n * in-process Pi runtime. Both are spawned by `AsyncSubagentSpawner`, both write\n * the same `status.json` and the same terminal result, and both signal the same\n * handshake - so `AsyncJobTracker`, `ResultWatcher`, the fleet view, internal\n * completion monitors, and public `subagent` status handling cannot tell them apart.\n *\n * WHAT AN EXTERNAL CHILD DOES NOT GET, STATED PLAINLY:\n * No intercom, no steering, no structured output. Those\n * are delivered by `subagentPromptRuntime.ts`, which Pi loads in-process into\n * a Pi child; an arbitrary CLI has nowhere to load it. Team package tool\n * exclusions are therefore best effort for external runtimes. An external\n * child is a one-shot worker: it receives a prompt and returns output. Stop and interrupt\n * still work, because they are process-group signals rather than cooperative\n * file requests.\n *\n * WHY THE OUTPUT IS RECORDED, NOT PARSED:\n * A generic runner cannot know what a given CLI's output means. Trailing stdout\n * is the result; anything more specific would either be wrong for a CLI nobody\n * tested or lock the config to the two that were.\n *\n * AVOID:\n * - Vendor-specific parsing here. If a runtime needs it, that is a different\n * module and a deliberate decision\n */\n\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\n\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { SUBAGENT_ROOT_SESSION_ENV, SUBAGENT_RUN_ID_ENV } from '../../../adapters/process/env.ts';\nimport { writeAtomicJson, writePrivateAtomicJson } from '../../../shared/atomicJson.ts';\nimport { adoptSessionScopeFromEnv, currentRunConfigPath } from '../../../shared/paths.ts';\nimport {\n CLAUDE_FABLE_PROFILE,\n cleanupClaudeFableLaunch,\n parseClaudeFableOutput,\n} from '../shared/claudeFableProfile.ts';\nimport type { AsyncRunStatus } from './asyncExecution.ts';\nimport type { CliLaunchConfig } from './cliLaunchConfig.ts';\nimport { startParentWatchdog } from './parentWatchdog.ts';\nimport { readAsyncRunStatus } from './statusReader.ts';\nimport { CoalescedStatusWriter } from './statusWriter.ts';\n\n/** How much trailing stdout is kept as the run's result. */\nconst MAX_RESULT_BYTES = 64 * 1024;\n/** How much stderr is kept for a failure message. */\nconst MAX_STDERR_BYTES = 8 * 1024;\nconst PARENT_LOST_MESSAGE = 'Parent process was lost.';\nconst FORCE_KILL_SIGNAL: NodeJS.Signals = 'SIGKILL';\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readLaunchConfig(runId: string): CliLaunchConfig {\n const parsed: unknown = JSON.parse(fs.readFileSync(currentRunConfigPath(runId), 'utf8'));\n if (!isRecord(parsed) || parsed.runId !== runId || typeof parsed.command !== 'string') {\n throw new Error(`CLI launch config for run '${runId}' is invalid.`);\n }\n return parsed as unknown as CliLaunchConfig;\n}\n\n/** Keep only a UTF-8-safe trailing value within `limit` bytes, so a chatty CLI cannot exhaust memory. */\nfunction appendBounded(buffer: string, chunk: string, limit: number): string {\n let combined = buffer + chunk;\n while (Buffer.byteLength(combined, 'utf8') > limit && combined.length > 0) {\n const excess = Buffer.byteLength(combined, 'utf8') - limit;\n combined = combined.slice(Math.max(1, Math.ceil(excess / 2)));\n }\n return combined;\n}\n\nlet childTelemetry: DoomTelemetry | undefined;\n\nasync function finishTelemetry(event: string, attributes: Record<string, unknown>, error?: unknown): Promise<void> {\n const telemetry = childTelemetry;\n childTelemetry = undefined;\n if (!telemetry) return;\n if (error === undefined) await telemetry.recordEvent(event, attributes);\n else await telemetry.recordError(event, error, attributes);\n await telemetry.flush();\n await telemetry.shutdown();\n}\n\nasync function run(): Promise<void> {\n const startedAt = Date.now();\n childTelemetry = createDoomTelemetry({\n serviceName: 'doom-team-cli-child',\n packageName: '@agimon-ai/doompi-team',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const runId = process.env[SUBAGENT_RUN_ID_ENV]?.trim();\n if (!runId) throw new Error(`${SUBAGENT_RUN_ID_ENV} is required.`);\n if (!adoptSessionScopeFromEnv()) {\n throw new Error(`${SUBAGENT_ROOT_SESSION_ENV} is required: a child cannot resolve its session scope without it.`);\n }\n\n let config: CliLaunchConfig | undefined;\n try {\n config = readLaunchConfig(runId);\n // The vendor process emits its own spawn event before the ready handshake\n // is written below. Reading the config alone is not sufficient evidence\n // that the configured executable can start.\n } catch (error) {\n if (config?.handshakePath && !fs.existsSync(config.handshakePath)) {\n writeAtomicJson(config.handshakePath, { state: 'error', error: errorMessage(error) });\n }\n throw error;\n }\n\n const statusWriter = new CoalescedStatusWriter<AsyncRunStatus>();\n const now = Date.now();\n await childTelemetry?.recordEvent('doom_team.child_started', {\n runtime: config.runtime,\n 'agent.name': config.agent,\n outcome: 'started',\n });\n statusWriter.open(\n runId,\n readAsyncRunStatus(runId) ?? {\n version: 1,\n runId,\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n cwd: config.cwd,\n runtime: config.runtime,\n state: 'queued',\n startedAt: now,\n lastUpdate: now,\n },\n );\n\n const profileLaunch = config.profile === CLAUDE_FABLE_PROFILE;\n if (config.profile !== undefined && !profileLaunch) throw new Error('Untrusted external profile.');\n if (profileLaunch && (!config.stdinPath || !config.profileResultPath)) {\n throw new Error('Fable profile launch config is incomplete.');\n }\n const stdinFd = profileLaunch ? fs.openSync(config.stdinPath!, 'r') : undefined;\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(config.command, config.args, {\n cwd: config.cwd,\n env: profileLaunch ? config.env : { ...process.env, ...config.env },\n stdio: [stdinFd ?? 'ignore', 'pipe', 'pipe'],\n // Its own group, so the watchdog below can take the CLI and anything it\n // spawned down together.\n detached: true,\n windowsHide: true,\n });\n } catch (error) {\n if (profileLaunch) {\n cleanupClaudeFableLaunch({ cleanupPaths: config.cleanupPaths ?? [] });\n if (config.profileResultPath) fs.rmSync(config.profileResultPath, { force: true });\n }\n throw error;\n } finally {\n if (stdinFd !== undefined) fs.closeSync(stdinFd);\n }\n const cleanupProfile = (removeResult: boolean): void => {\n if (!profileLaunch) return;\n cleanupClaudeFableLaunch({ cleanupPaths: config.cleanupPaths ?? [] });\n if (removeResult && config.profileResultPath) fs.rmSync(config.profileResultPath, { force: true });\n };\n\n let requestedSignal: NodeJS.Signals | undefined;\n const stopVendor = (signal: NodeJS.Signals): void => {\n requestedSignal = signal;\n if (!child.pid) return;\n try {\n process.kill(-child.pid, signal);\n } catch (error) {\n process.stderr.write(`[doom-team cli runner] Could not signal vendor process: ${errorMessage(error)}\\n`);\n }\n };\n process.once('SIGTERM', stopVendor);\n process.once('SIGINT', stopVendor);\n\n try {\n await new Promise<void>((resolve, reject) => {\n child.once('spawn', resolve);\n child.once('error', reject);\n });\n writeAtomicJson(config.handshakePath, { state: 'ready' });\n statusWriter.updateSync((status) => {\n status.state = 'running';\n status.activityState = 'working';\n status.lastUpdate = Date.now();\n });\n } catch (error) {\n const message = errorMessage(error);\n writeAtomicJson(config.handshakePath, { state: 'error', error: message });\n statusWriter.updateSync((status) => {\n status.state = 'failed';\n status.error = message;\n status.lastUpdate = Date.now();\n status.endedAt = Date.now();\n });\n writeAtomicJson(config.resultPath, {\n runId,\n ...(config.internal ? { internal: true } : {}),\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n runtime: config.runtime,\n success: false,\n summary: profileLaunch ? 'Fable Claude launch failed.' : message,\n });\n statusWriter.close();\n cleanupProfile(true);\n await finishTelemetry(\n 'doom_team.child_failed',\n { runtime: config.runtime, 'agent.name': config.agent, duration_ms: Date.now() - startedAt, outcome: 'failed' },\n error,\n );\n process.exit(1);\n }\n\n // A SIGKILLed parent cannot signal us, so terminate the vendor tree and\n // persist a terminal record before leaving when the watchdog can observe it.\n const stopWatchdog = startParentWatchdog({\n onParentLost: () => {\n stopVendor(FORCE_KILL_SIGNAL);\n const endedAt = Date.now();\n statusWriter.updateSync((status) => {\n status.state = 'stopped';\n status.error = PARENT_LOST_MESSAGE;\n status.lastUpdate = endedAt;\n status.endedAt = endedAt;\n });\n writeAtomicJson(config.resultPath, {\n runId,\n ...(config.internal ? { internal: true } : {}),\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n runtime: config.runtime,\n success: false,\n summary: PARENT_LOST_MESSAGE,\n signal: FORCE_KILL_SIGNAL,\n });\n statusWriter.close();\n cleanupProfile(true);\n void finishTelemetry('doom_team.child_finished', {\n runtime: config.runtime,\n 'agent.name': config.agent,\n duration_ms: Date.now() - startedAt,\n outcome: 'parent_lost',\n }).finally(() => process.exit(0));\n },\n });\n\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout = appendBounded(stdout, chunk.toString('utf8'), MAX_RESULT_BYTES);\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr = appendBounded(stderr, chunk.toString('utf8'), MAX_STDERR_BYTES);\n });\n\n const exit = await new Promise<{ code: number | null; signal: NodeJS.Signals | null; error?: Error }>((resolve) => {\n child.on('error', (error) => resolve({ code: null, signal: null, error }));\n child.on('close', (code, signal) => resolve({ code, signal }));\n });\n\n stopWatchdog();\n\n const stopped = requestedSignal !== undefined;\n let profileError: Error | undefined;\n if (profileLaunch && !stopped && exit.error === undefined && exit.code === 0) {\n try {\n const parsed = parseClaudeFableOutput(stdout);\n writePrivateAtomicJson(config.profileResultPath!, { text: parsed.text, outputBytes: parsed.outputBytes });\n } catch (error) {\n profileError = error instanceof Error ? error : new Error(String(error));\n }\n }\n const success = !stopped && exit.error === undefined && exit.code === 0 && profileError === undefined;\n const failureDetail = profileLaunch\n ? (profileError?.message ?? 'Fable Claude launch failed.')\n : stderr.trim() || `${config.runtime} exited with ${exit.signal ?? `code ${exit.code ?? 'unknown'}`}.`;\n const summary = stopped\n ? `Stopped by ${requestedSignal}.`\n : success\n ? profileLaunch\n ? 'Fable profile completed.'\n : stdout.trim()\n : (exit.error?.message ?? failureDetail);\n const endedAt = Date.now();\n\n statusWriter.updateSync((status) => {\n status.state = stopped ? 'stopped' : success ? 'completed' : 'failed';\n status.activityState = 'finalizing';\n status.summary = summary;\n if (!success) status.error = summary;\n status.lastUpdate = endedAt;\n status.endedAt = endedAt;\n });\n writeAtomicJson(config.resultPath, {\n runId,\n ...(config.internal ? { internal: true } : {}),\n ...(config.operationId ? { operationId: config.operationId } : {}),\n agent: config.agent,\n runtime: config.runtime,\n success,\n summary,\n ...(exit.code === null ? {} : { exitCode: exit.code }),\n ...(exit.signal ? { signal: exit.signal } : {}),\n });\n\n statusWriter.close();\n cleanupProfile(!success);\n await finishTelemetry('doom_team.child_finished', {\n runtime: config.runtime,\n 'agent.name': config.agent,\n duration_ms: Date.now() - startedAt,\n 'runner.stdout_bytes': Buffer.byteLength(stdout, 'utf8'),\n 'runner.stderr_bytes': Buffer.byteLength(stderr, 'utf8'),\n 'runner.exit_code': exit.code ?? 0,\n outcome: stopped ? 'stopped' : success ? 'completed' : 'failed',\n });\n // The runner exit code reports transport health. Task success or failure is\n // encoded durably in status and result data before this process exits.\n process.exit(0);\n}\n\nvoid run().catch(async (error: unknown) => {\n await finishTelemetry('doom_team.child_failed', { outcome: 'failed' }, error);\n // Keep stdout reserved for vendor output. Stderr is captured in the run's\n // runner log and makes a transport failure diagnosable by the parent.\n process.stderr.write(`[doom-team cli runner] ${errorMessage(error)}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completionBatcher.cjs","names":[],"sources":["../../../../src/services/runs/background/completionBatcher.ts"],"sourcesContent":["/**\n * Debounced grouping for successful completion notifications.\n *\n * WHY THIS EXISTS:\n * A fan-out run's children tend to finish within milliseconds of each other.\n * Notifying once per child turns a five-way parallel run into five separate\n * interruptions for the operator instead of one. This holds a *successful*\n * completion briefly so siblings finishing in the same short window arrive as\n * a single grouped message.\n *\n * DESIGN PATTERNS (ported as-is from\n * `doom-pi-subagents/src/runs/background/completionBatcher.ts` - this\n * module's logic was not one of the flagged predecessor bugs):\n * - A hard `maxWaitMs` cap, measured from the first item in the group, means\n * a debounce that keeps getting reset by new arrivals cannot hold a group\n * open forever\n * - After a group emits, arrivals within `stragglerWindowMs` join a shorter\n * \"straggler\" group (`stragglerDebounceMs`/`stragglerMaxWaitMs`): a single\n * slow sibling still gets grouped with whoever else trails in soon after,\n * rather than waiting out the full debounce alone\n * - `push()` is the only entry point that arms timers; `flush()` and\n * `dispose()` both go through the same `clearTimers`/emit path, so there is\n * one place a leak could be introduced\n * - Disabled mode (`config.enabled === false`) degrades to \"emit immediately,\n * one item at a time\" rather than a special code path elsewhere: every\n * caller of `push()` behaves the same regardless of whether batching is on\n *\n * WHY THIS OWNS ITS OWN TIMERS RATHER THAN REGISTERING WITH `PollScheduler`:\n * Same reasoning as `spawnHandshake.ts`'s documented exception, and for the\n * same underlying reason: `PollScheduler`'s floor is 200ms, and this\n * batcher's default `debounceMs` is 150ms - below the floor before backoff\n * even starts growing it. Coupling a sub-200ms debounce to a shared tick that\n * is explicitly designed to back off toward 5s while idle would make the\n * debounce it exists to provide unreliable. A completion batcher is also\n * short-lived and per-group (bounded by `maxWaitMs`, at most ~1s), the same\n * shape as a handshake wait, not a long-lived background subscriber.\n *\n * AVOID:\n * - Calling `push()` for a failed or paused completion; this batcher has no\n * opinion on what should bypass it; that decision belongs to the caller\n * (`notify.ts`), which flushes and emits those immediately instead\n */\n\nexport interface CompletionBatchConfig {\n enabled?: boolean;\n /** Idle window after each arrival; resets on every new item. */\n debounceMs?: number;\n /** Hard cap measured from the first item in a group. */\n maxWaitMs?: number;\n /** Shorter idle window for straggler groups. */\n stragglerDebounceMs?: number;\n /** Shorter hard cap for straggler groups. */\n stragglerMaxWaitMs?: number;\n /** Arrivals within this window after an emit join a straggler group. */\n stragglerWindowMs?: number;\n}\n\nexport interface ResolvedCompletionBatchConfig {\n enabled: boolean;\n debounceMs: number;\n maxWaitMs: number;\n stragglerDebounceMs: number;\n stragglerMaxWaitMs: number;\n stragglerWindowMs: number;\n}\n\nexport const DEFAULT_COMPLETION_BATCH_CONFIG: ResolvedCompletionBatchConfig = {\n enabled: true,\n debounceMs: 150,\n maxWaitMs: 1000,\n stragglerDebounceMs: 75,\n stragglerMaxWaitMs: 400,\n stragglerWindowMs: 2000,\n};\n\nfunction parsePositiveInt(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value) || value < 1) return undefined;\n return value;\n}\n\nexport function resolveCompletionBatchConfig(override?: CompletionBatchConfig): ResolvedCompletionBatchConfig {\n return {\n enabled: typeof override?.enabled === 'boolean' ? override.enabled : DEFAULT_COMPLETION_BATCH_CONFIG.enabled,\n debounceMs: parsePositiveInt(override?.debounceMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.debounceMs,\n maxWaitMs: parsePositiveInt(override?.maxWaitMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.maxWaitMs,\n stragglerDebounceMs:\n parsePositiveInt(override?.stragglerDebounceMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.stragglerDebounceMs,\n stragglerMaxWaitMs:\n parsePositiveInt(override?.stragglerMaxWaitMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.stragglerMaxWaitMs,\n stragglerWindowMs:\n parsePositiveInt(override?.stragglerWindowMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.stragglerWindowMs,\n };\n}\n\ntype TimerHandle = ReturnType<typeof setTimeout>;\n\ninterface TimerApi {\n setTimeout(handler: () => void, delayMs: number): TimerHandle;\n clearTimeout(handle: TimerHandle): void;\n}\n\nconst defaultTimers: TimerApi = {\n setTimeout: (handler, delayMs) => setTimeout(handler, delayMs),\n clearTimeout: (handle) => clearTimeout(handle),\n};\n\nexport interface CompletionBatcherOptions<T> {\n config: ResolvedCompletionBatchConfig;\n emit: (items: T[]) => void;\n timers?: TimerApi;\n now?: () => number;\n}\n\nexport interface CompletionBatcher<T> {\n /** Add a batchable item. Emits immediately, alone, when batching is disabled. */\n push(item: T): void;\n /** Emit any held items immediately as a single group. No-op when nothing is held. */\n flush(): void;\n /** Clear timers and return items that were never emitted, without emitting them. */\n dispose(): T[];\n}\n\n/**\n * Create a completion batcher. Single-use per registration: it holds at most\n * one open group at a time. `flush()` forces emission (used by the caller to\n * drain a group before an immediate, unbatched emit for a failure/pause);\n * `dispose()` tears down timers for reload/shutdown without emitting.\n */\nexport function createCompletionBatcher<T>(options: CompletionBatcherOptions<T>): CompletionBatcher<T> {\n const timers = options.timers ?? defaultTimers;\n const now = options.now ?? Date.now;\n const config = options.config;\n\n if (!config.enabled) {\n return {\n push(item: T) {\n options.emit([item]);\n },\n flush() {\n /* nothing is ever held when disabled */\n },\n dispose() {\n return [];\n },\n };\n }\n\n let pending: T[] = [];\n let debounceTimer: TimerHandle | undefined;\n let maxWaitTimer: TimerHandle | undefined;\n let straggler = false;\n let lastEmitAt: number | undefined;\n\n const clearTimers = (): void => {\n if (debounceTimer !== undefined) {\n timers.clearTimeout(debounceTimer);\n debounceTimer = undefined;\n }\n if (maxWaitTimer !== undefined) {\n timers.clearTimeout(maxWaitTimer);\n maxWaitTimer = undefined;\n }\n };\n\n const emitGroup = (): void => {\n clearTimers();\n if (pending.length === 0) return;\n const items = pending;\n pending = [];\n lastEmitAt = now();\n options.emit(items);\n };\n\n return {\n push(item: T) {\n if (pending.length === 0) {\n straggler = lastEmitAt !== undefined && now() - lastEmitAt < config.stragglerWindowMs;\n }\n pending.push(item);\n\n if (debounceTimer !== undefined) timers.clearTimeout(debounceTimer);\n const debounceDelay = straggler ? config.stragglerDebounceMs : config.debounceMs;\n debounceTimer = timers.setTimeout(emitGroup, debounceDelay);\n debounceTimer.unref?.();\n\n if (maxWaitTimer === undefined) {\n const maxWaitDelay = straggler ? config.stragglerMaxWaitMs : config.maxWaitMs;\n maxWaitTimer = timers.setTimeout(emitGroup, maxWaitDelay);\n maxWaitTimer.unref?.();\n }\n },\n flush: emitGroup,\n dispose() {\n clearTimers();\n const abandoned = pending;\n pending = [];\n return abandoned;\n },\n };\n}\n"],"mappings":"AAkEA,MAAa,EAAiE,CAC5E,QAAS,GACT,WAAY,IACZ,UAAW,IACX,oBAAqB,GACrB,mBAAoB,IACpB,kBAAmB,IACpB,CAED,SAAS,EAAiB,EAAoC,CACxD,YAAO,GAAU,UAAY,CAAC,OAAO,SAAS,EAAM,EAAI,CAAC,OAAO,UAAU,EAAM,EAAI,EAAQ,GAChG,OAAO,EAGT,SAAgB,EAA6B,EAAiE,CAC5G,MAAO,CACL,QAAS,OAAO,GAAU,SAAY,UAAY,EAAS,QAAU,EAAgC,QACrG,WAAY,EAAiB,GAAU,WAAW,EAAI,EAAgC,WACtF,UAAW,EAAiB,GAAU,UAAU,EAAI,EAAgC,UACpF,oBACE,EAAiB,GAAU,oBAAoB,EAAI,EAAgC,oBACrF,mBACE,EAAiB,GAAU,mBAAmB,EAAI,EAAgC,mBACpF,kBACE,EAAiB,GAAU,kBAAkB,EAAI,EAAgC,kBACpF,CAUH,MAAM,EAA0B,CAC9B,YAAa,EAAS,IAAY,WAAW,EAAS,EAAQ,CAC9D,aAAe,GAAW,aAAa,EAAO,CAC/C,CAwBD,SAAgB,EAA2B,EAA4D,CACrG,IAAM,EAAS,EAAQ,QAAU,EAC3B,EAAM,EAAQ,KAAO,KAAK,IAC1B,EAAS,EAAQ,OAEvB,GAAI,CAAC,EAAO,QACV,MAAO,CACL,KAAK,EAAS,CACZ,EAAQ,KAAK,CAAC,EAAK,CAAC,EAEtB,OAAQ,GAGR,SAAU,CACR,MAAO,EAAE,EAEZ,CAGH,IAAI,EAAe,EAAE,CACjB,EACA,EACA,EAAY,GACZ,EAEE,MAA0B,CAC1B,IAAkB,IAAA,KACpB,EAAO,aAAa,EAAc,CAClC,EAAgB,IAAA,IAEd,IAAiB,IAAA,KACnB,EAAO,aAAa,EAAa,CACjC,EAAe,IAAA,KAIb,MAAwB,CAE5B,GADA,GAAa,CACT,EAAQ,SAAW,EAAG,OAC1B,IAAM,EAAQ,EACd,EAAU,EAAE,CACZ,EAAa,GAAK,CAClB,EAAQ,KAAK,EAAM,EAGrB,MAAO,CACL,KAAK,EAAS,CACR,EAAQ,SAAW,IACrB,EAAY,IAAe,IAAA,IAAa,GAAK,CAAG,EAAa,EAAO,mBAEtE,EAAQ,KAAK,EAAK,CAEd,IAAkB,IAAA,IAAW,EAAO,aAAa,EAAc,CACnE,IAAM,EAAgB,EAAY,EAAO,oBAAsB,EAAO,WAItE,GAHA,EAAgB,EAAO,WAAW,EAAW,EAAc,CAC3D,EAAc,SAAS,CAEnB,IAAiB,IAAA,GAAW,CAC9B,IAAM,EAAe,EAAY,EAAO,mBAAqB,EAAO,UACpE,EAAe,EAAO,WAAW,EAAW,EAAa,CACzD,EAAa,SAAS,GAG1B,MAAO,EACP,SAAU,CACR,GAAa,CACb,IAAM,EAAY,EAElB,MADA,GAAU,EAAE,CACL,GAEV"}
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";function t(e){if(!(typeof e!=`number`||!Number.isFinite(e)||!Number.isInteger(e)||e<1))return e}function n(e){return{enabled:typeof e?.enabled==`boolean`?e.enabled:i.enabled,debounceMs:t(e?.debounceMs)??i.debounceMs,maxWaitMs:t(e?.maxWaitMs)??i.maxWaitMs,stragglerDebounceMs:t(e?.stragglerDebounceMs)??i.stragglerDebounceMs,stragglerMaxWaitMs:t(e?.stragglerMaxWaitMs)??i.stragglerMaxWaitMs,stragglerWindowMs:t(e?.stragglerWindowMs)??i.stragglerWindowMs}}function r(e){let t=e.timers??a,n=e.now??Date.now,r=e.config;if(!r.enabled)return{push(t){e.emit([t])},flush(){},dispose(){return[]}};let i=[],o,s,c=!1,l,u=()=>{o!==void 0&&(t.clearTimeout(o),o=void 0),s!==void 0&&(t.clearTimeout(s),s=void 0)},d=()=>{if(u(),i.length===0)return;let t=i;i=[],l=n(),e.emit(t)};return{push(e){i.length===0&&(c=l!==void 0&&n()-l<r.stragglerWindowMs),i.push(e),o!==void 0&&t.clearTimeout(o);let a=c?r.stragglerDebounceMs:r.debounceMs;if(o=t.setTimeout(d,a),o.unref?.(),s===void 0){let e=c?r.stragglerMaxWaitMs:r.maxWaitMs;s=t.setTimeout(d,e),s.unref?.()}},flush:d,dispose(){u();let e=i;return i=[],e}}}var i,a,o=e((()=>{i={enabled:!0,debounceMs:150,maxWaitMs:1e3,stragglerDebounceMs:75,stragglerMaxWaitMs:400,stragglerWindowMs:2e3},a={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e)}}));o();export{r as createCompletionBatcher,o as init_completionBatcher,n as resolveCompletionBatchConfig};
2
+ //# sourceMappingURL=completionBatcher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completionBatcher.mjs","names":[],"sources":["../../../../src/services/runs/background/completionBatcher.ts"],"sourcesContent":["/**\n * Debounced grouping for successful completion notifications.\n *\n * WHY THIS EXISTS:\n * A fan-out run's children tend to finish within milliseconds of each other.\n * Notifying once per child turns a five-way parallel run into five separate\n * interruptions for the operator instead of one. This holds a *successful*\n * completion briefly so siblings finishing in the same short window arrive as\n * a single grouped message.\n *\n * DESIGN PATTERNS (ported as-is from\n * `doom-pi-subagents/src/runs/background/completionBatcher.ts` - this\n * module's logic was not one of the flagged predecessor bugs):\n * - A hard `maxWaitMs` cap, measured from the first item in the group, means\n * a debounce that keeps getting reset by new arrivals cannot hold a group\n * open forever\n * - After a group emits, arrivals within `stragglerWindowMs` join a shorter\n * \"straggler\" group (`stragglerDebounceMs`/`stragglerMaxWaitMs`): a single\n * slow sibling still gets grouped with whoever else trails in soon after,\n * rather than waiting out the full debounce alone\n * - `push()` is the only entry point that arms timers; `flush()` and\n * `dispose()` both go through the same `clearTimers`/emit path, so there is\n * one place a leak could be introduced\n * - Disabled mode (`config.enabled === false`) degrades to \"emit immediately,\n * one item at a time\" rather than a special code path elsewhere: every\n * caller of `push()` behaves the same regardless of whether batching is on\n *\n * WHY THIS OWNS ITS OWN TIMERS RATHER THAN REGISTERING WITH `PollScheduler`:\n * Same reasoning as `spawnHandshake.ts`'s documented exception, and for the\n * same underlying reason: `PollScheduler`'s floor is 200ms, and this\n * batcher's default `debounceMs` is 150ms - below the floor before backoff\n * even starts growing it. Coupling a sub-200ms debounce to a shared tick that\n * is explicitly designed to back off toward 5s while idle would make the\n * debounce it exists to provide unreliable. A completion batcher is also\n * short-lived and per-group (bounded by `maxWaitMs`, at most ~1s), the same\n * shape as a handshake wait, not a long-lived background subscriber.\n *\n * AVOID:\n * - Calling `push()` for a failed or paused completion; this batcher has no\n * opinion on what should bypass it; that decision belongs to the caller\n * (`notify.ts`), which flushes and emits those immediately instead\n */\n\nexport interface CompletionBatchConfig {\n enabled?: boolean;\n /** Idle window after each arrival; resets on every new item. */\n debounceMs?: number;\n /** Hard cap measured from the first item in a group. */\n maxWaitMs?: number;\n /** Shorter idle window for straggler groups. */\n stragglerDebounceMs?: number;\n /** Shorter hard cap for straggler groups. */\n stragglerMaxWaitMs?: number;\n /** Arrivals within this window after an emit join a straggler group. */\n stragglerWindowMs?: number;\n}\n\nexport interface ResolvedCompletionBatchConfig {\n enabled: boolean;\n debounceMs: number;\n maxWaitMs: number;\n stragglerDebounceMs: number;\n stragglerMaxWaitMs: number;\n stragglerWindowMs: number;\n}\n\nexport const DEFAULT_COMPLETION_BATCH_CONFIG: ResolvedCompletionBatchConfig = {\n enabled: true,\n debounceMs: 150,\n maxWaitMs: 1000,\n stragglerDebounceMs: 75,\n stragglerMaxWaitMs: 400,\n stragglerWindowMs: 2000,\n};\n\nfunction parsePositiveInt(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value) || value < 1) return undefined;\n return value;\n}\n\nexport function resolveCompletionBatchConfig(override?: CompletionBatchConfig): ResolvedCompletionBatchConfig {\n return {\n enabled: typeof override?.enabled === 'boolean' ? override.enabled : DEFAULT_COMPLETION_BATCH_CONFIG.enabled,\n debounceMs: parsePositiveInt(override?.debounceMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.debounceMs,\n maxWaitMs: parsePositiveInt(override?.maxWaitMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.maxWaitMs,\n stragglerDebounceMs:\n parsePositiveInt(override?.stragglerDebounceMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.stragglerDebounceMs,\n stragglerMaxWaitMs:\n parsePositiveInt(override?.stragglerMaxWaitMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.stragglerMaxWaitMs,\n stragglerWindowMs:\n parsePositiveInt(override?.stragglerWindowMs) ?? DEFAULT_COMPLETION_BATCH_CONFIG.stragglerWindowMs,\n };\n}\n\ntype TimerHandle = ReturnType<typeof setTimeout>;\n\ninterface TimerApi {\n setTimeout(handler: () => void, delayMs: number): TimerHandle;\n clearTimeout(handle: TimerHandle): void;\n}\n\nconst defaultTimers: TimerApi = {\n setTimeout: (handler, delayMs) => setTimeout(handler, delayMs),\n clearTimeout: (handle) => clearTimeout(handle),\n};\n\nexport interface CompletionBatcherOptions<T> {\n config: ResolvedCompletionBatchConfig;\n emit: (items: T[]) => void;\n timers?: TimerApi;\n now?: () => number;\n}\n\nexport interface CompletionBatcher<T> {\n /** Add a batchable item. Emits immediately, alone, when batching is disabled. */\n push(item: T): void;\n /** Emit any held items immediately as a single group. No-op when nothing is held. */\n flush(): void;\n /** Clear timers and return items that were never emitted, without emitting them. */\n dispose(): T[];\n}\n\n/**\n * Create a completion batcher. Single-use per registration: it holds at most\n * one open group at a time. `flush()` forces emission (used by the caller to\n * drain a group before an immediate, unbatched emit for a failure/pause);\n * `dispose()` tears down timers for reload/shutdown without emitting.\n */\nexport function createCompletionBatcher<T>(options: CompletionBatcherOptions<T>): CompletionBatcher<T> {\n const timers = options.timers ?? defaultTimers;\n const now = options.now ?? Date.now;\n const config = options.config;\n\n if (!config.enabled) {\n return {\n push(item: T) {\n options.emit([item]);\n },\n flush() {\n /* nothing is ever held when disabled */\n },\n dispose() {\n return [];\n },\n };\n }\n\n let pending: T[] = [];\n let debounceTimer: TimerHandle | undefined;\n let maxWaitTimer: TimerHandle | undefined;\n let straggler = false;\n let lastEmitAt: number | undefined;\n\n const clearTimers = (): void => {\n if (debounceTimer !== undefined) {\n timers.clearTimeout(debounceTimer);\n debounceTimer = undefined;\n }\n if (maxWaitTimer !== undefined) {\n timers.clearTimeout(maxWaitTimer);\n maxWaitTimer = undefined;\n }\n };\n\n const emitGroup = (): void => {\n clearTimers();\n if (pending.length === 0) return;\n const items = pending;\n pending = [];\n lastEmitAt = now();\n options.emit(items);\n };\n\n return {\n push(item: T) {\n if (pending.length === 0) {\n straggler = lastEmitAt !== undefined && now() - lastEmitAt < config.stragglerWindowMs;\n }\n pending.push(item);\n\n if (debounceTimer !== undefined) timers.clearTimeout(debounceTimer);\n const debounceDelay = straggler ? config.stragglerDebounceMs : config.debounceMs;\n debounceTimer = timers.setTimeout(emitGroup, debounceDelay);\n debounceTimer.unref?.();\n\n if (maxWaitTimer === undefined) {\n const maxWaitDelay = straggler ? config.stragglerMaxWaitMs : config.maxWaitMs;\n maxWaitTimer = timers.setTimeout(emitGroup, maxWaitDelay);\n maxWaitTimer.unref?.();\n }\n },\n flush: emitGroup,\n dispose() {\n clearTimers();\n const abandoned = pending;\n pending = [];\n return abandoned;\n },\n };\n}\n"],"mappings":"mEA2EA,SAAS,EAAiB,EAAoC,CACxD,YAAO,GAAU,UAAY,CAAC,OAAO,SAAS,EAAM,EAAI,CAAC,OAAO,UAAU,EAAM,EAAI,EAAQ,GAChG,OAAO,EAGT,SAAgB,EAA6B,EAAiE,CAC5G,MAAO,CACL,QAAS,OAAO,GAAU,SAAY,UAAY,EAAS,QAAU,EAAgC,QACrG,WAAY,EAAiB,GAAU,WAAW,EAAI,EAAgC,WACtF,UAAW,EAAiB,GAAU,UAAU,EAAI,EAAgC,UACpF,oBACE,EAAiB,GAAU,oBAAoB,EAAI,EAAgC,oBACrF,mBACE,EAAiB,GAAU,mBAAmB,EAAI,EAAgC,mBACpF,kBACE,EAAiB,GAAU,kBAAkB,EAAI,EAAgC,kBACpF,CAqCH,SAAgB,EAA2B,EAA4D,CACrG,IAAM,EAAS,EAAQ,QAAU,EAC3B,EAAM,EAAQ,KAAO,KAAK,IAC1B,EAAS,EAAQ,OAEvB,GAAI,CAAC,EAAO,QACV,MAAO,CACL,KAAK,EAAS,CACZ,EAAQ,KAAK,CAAC,EAAK,CAAC,EAEtB,OAAQ,GAGR,SAAU,CACR,MAAO,EAAE,EAEZ,CAGH,IAAI,EAAe,EAAE,CACjB,EACA,EACA,EAAY,GACZ,EAEE,MAA0B,CAC1B,IAAkB,IAAA,KACpB,EAAO,aAAa,EAAc,CAClC,EAAgB,IAAA,IAEd,IAAiB,IAAA,KACnB,EAAO,aAAa,EAAa,CACjC,EAAe,IAAA,KAIb,MAAwB,CAE5B,GADA,GAAa,CACT,EAAQ,SAAW,EAAG,OAC1B,IAAM,EAAQ,EACd,EAAU,EAAE,CACZ,EAAa,GAAK,CAClB,EAAQ,KAAK,EAAM,EAGrB,MAAO,CACL,KAAK,EAAS,CACR,EAAQ,SAAW,IACrB,EAAY,IAAe,IAAA,IAAa,GAAK,CAAG,EAAa,EAAO,mBAEtE,EAAQ,KAAK,EAAK,CAEd,IAAkB,IAAA,IAAW,EAAO,aAAa,EAAc,CACnE,IAAM,EAAgB,EAAY,EAAO,oBAAsB,EAAO,WAItE,GAHA,EAAgB,EAAO,WAAW,EAAW,EAAc,CAC3D,EAAc,SAAS,CAEnB,IAAiB,IAAA,GAAW,CAC9B,IAAM,EAAe,EAAY,EAAO,mBAAqB,EAAO,UACpE,EAAe,EAAO,WAAW,EAAW,EAAa,CACzD,EAAa,SAAS,GAG1B,MAAO,EACP,SAAU,CACR,GAAa,CACb,IAAM,EAAY,EAElB,MADA,GAAU,EAAE,CACL,GAEV,mBApIU,EAAiE,CAC5E,QAAS,GACT,WAAY,IACZ,UAAW,IACX,oBAAqB,GACrB,mBAAoB,IACpB,kBAAmB,IACpB,CA4BK,EAA0B,CAC9B,YAAa,EAAS,IAAY,WAAW,EAAS,EAAQ,CAC9D,aAAe,GAAW,aAAa,EAAO,CAC/C"}
@@ -1,4 +1,4 @@
1
- require(`../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),t=require(`./completionBatcher.cjs`);let n=require(`inversify`);const r=`(no output)`,i=`unknown`;function a(e){let t=e.resultPreview.trim().length>0;return e.status===`completed`?t?`Read this result now and incorporate, reject, or mark it irrelevant before replying to the user.`:`No summary was produced. Call { action: "status", id: "${e.runId}", view: "transcript" } before replying.`:e.status===`paused`?`Run is paused and resumable. Inspect it with { action: "status", id: "${e.runId}" }, then decide whether to resume or abandon it.`:`Review this failure and tell the user whether it affects the current work. Full output: { action: "status", id: "${e.runId}", view: "transcript" }.`}function o(e){if(e.sessionValue)return e.sessionLabel?`${e.sessionLabel}: ${e.sessionValue}`:e.sessionValue}function s(e){let t=o(e);return[`Background task ${e.status}: **${e.agent}**${e.taskInfo??``}`,`run id: ${e.runId}`,``,e.resultPreview.trim()?e.resultPreview:r,e.handoffPath?``:void 0,e.handoffPath?`Parallel handoff: ${e.handoffPath}`:void 0,t?``:void 0,t,``,a(e)].filter(e=>e!==void 0).join(`
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),t=require(`./completionBatcher.cjs`);let n=require(`inversify`);const r=`(no output)`,i=`unknown`;function a(e){let t=e.resultPreview.trim().length>0;return e.status===`completed`?t?`Read this result now and incorporate, reject, or mark it irrelevant before replying to the user.`:`No summary was produced. Call { action: "status", id: "${e.runId}", view: "transcript" } before replying.`:e.status===`paused`?`Run is paused and resumable. Inspect it with { action: "status", id: "${e.runId}" }, then decide whether to resume or abandon it.`:`Review this failure and tell the user whether it affects the current work. Full output: { action: "status", id: "${e.runId}", view: "transcript" }.`}function o(e){if(e.sessionValue)return e.sessionLabel?`${e.sessionLabel}: ${e.sessionValue}`:e.sessionValue}function s(e){let t=o(e);return[`Background task ${e.status}: **${e.agent}**${e.taskInfo??``}`,`run id: ${e.runId}`,``,e.resultPreview.trim()?e.resultPreview:r,e.handoffPath?``:void 0,e.handoffPath?`Parallel handoff: ${e.handoffPath}`:void 0,t?``:void 0,t,``,a(e)].filter(e=>e!==void 0).join(`
2
2
  `)}function c(e){let t=[`Background tasks completed (${e.length}): ${e.map(e=>`**${e.agent}**${e.taskInfo??``}`).join(`, `)}`,``];for(let n=0;n<e.length;n++){let i=e[n];if(!i)continue;let s=o(i);t.push(`${n+1}. ${i.agent}${i.taskInfo??``} - run id: ${i.runId}`),t.push(i.resultPreview.trim()?i.resultPreview:r),i.handoffPath&&t.push(`Parallel handoff: ${i.handoffPath}`),s&&t.push(s),t.push(a(i)),t.push(``)}return t.join(`
3
3
  `).trimEnd()}function l(e){return typeof e==`string`?e:void 0}function u(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function d(e){let t=l(e.sessionId)?.trim();if(t)return`session:${t}`;let n=l(e.cwd)?.trim();return n?`cwd:${n}`:i}function f(e){let t=l(e.agent)??i,n=l(e.summary)??``,r=typeof e.success==`boolean`?e.success:void 0,a=l(e.state),o=r===!1&&(a===`paused`||n.startsWith(`Paused after interrupt.`))?`paused`:r===!1?`failed`:`completed`,s=u(e.taskIndex),c=u(e.totalTasks),d=s!==void 0&&c!==void 0?` (${s+1}/${c})`:void 0,f=l((typeof e.parallelHandoff==`object`&&e.parallelHandoff!==null?e.parallelHandoff:void 0)?.path),p=l(e.shareUrl),m=l(e.shareError),h=l(e.sessionFile),g=p?{label:`Session`,value:p}:m?{label:`Session share error`,value:m}:h?{label:`Session file`,value:h}:void 0;return{agent:t,runId:e.runId,status:o,resultPreview:n,...d?{taskInfo:d}:{},...u(e.durationMs)===void 0?{}:{durationMs:u(e.durationMs)},...f?{handoffPath:f}:{},...g?{sessionLabel:g.label,sessionValue:g.value}:{}}}const p=`subagent-notify`;let m=class{batchConfig=void 0;batchers=new Map;disposed=!1;host;attachHost(e){this.host=e}sendMessage(e,t){if(!this.host)return!1;try{return this.host.sendMessage({customType:p,content:e,display:!0,details:t.details},{triggerTurn:t.triggerTurn,deliverAs:`steer`}),!0}catch{return!1}}async deliver(e){if(e.internal===!0)return!0;if(this.disposed)return!1;let t=f(e),n=e.triggerTurn!==!1;return new Promise(r=>{let i={details:t,triggerTurn:n,resolve:r},a=this.getBatcher(e);if(t.status!==`completed`){a.flush(),this.emit([i]);return}a.push(i)})}dispose(){if(!this.disposed){this.disposed=!0;for(let e of this.batchers.values())for(let t of e.dispose())t.resolve(!1);this.batchers.clear()}}getBatcher(e){let n=d(e),r=this.batchers.get(n);return r||(r=t.createCompletionBatcher({config:t.resolveCompletionBatchConfig(this.batchConfig),emit:e=>this.emit(e)}),this.batchers.set(n,r)),r}emit(e){if(e.length===0)return;let t=e.map(e=>e.details),n=t.length===1?s(t[0]):c(t),r=this.sendMessage(n,{triggerTurn:e.some(e=>e.triggerTurn),details:t});for(let t of e)t.resolve(r)}};m=e.__decorate([(0,n.injectable)()],m),Object.defineProperty(exports,`CompletionNotifier`,{enumerable:!0,get:function(){return m}}),exports.SUBAGENT_NOTIFY_MESSAGE_TYPE=p;
4
4
  //# sourceMappingURL=notify.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify.cjs","names":["createCompletionBatcher","resolveCompletionBatchConfig"],"sources":["../../../../src/services/runs/background/notify.ts"],"sourcesContent":["/**\n * Formats a run's terminal result into a completion notification and hands\n * it to `ResultWatcher` as its `ResultConsumer`, batching successful\n * completions and bypassing that batching for anything that needs the\n * operator's attention right away.\n *\n * WHY `completion-dedupe.ts` IS NOT PORTED:\n * The predecessor deduped completion notifications with its own TTL-keyed\n * map (`completion-dedupe.ts`), independently of the identically-shaped TTL\n * dedupe `resultWatcher.ts` already does before it ever calls a consumer.\n * Those two copies could disagree - the exact bug class `resultWatcher.ts`'s\n * header now documents fixing. This package has exactly one producer of\n * completions today: `ResultWatcher`, which only calls its consumer once per\n * `runId` per TTL window. `CompletionNotifier.deliver()` is that consumer, so\n * it trusts that guarantee instead of re-implementing it. The predecessor\n * needed its own copy because it had two independent producers (async result\n * files AND a synchronous foreground-run event); this package is async-only\n * (see `spawnHandshake.ts`'s header) and has not ported foreground runs. IF\n * a second completion producer is added later, `deliver()` can no longer\n * assume `ResultWatcher` already deduped for it, and this module will need\n * its own dedupe again at that point - not before.\n *\n * DESIGN PATTERNS:\n * - `deliver()` matches `ResultConsumer`'s exact shape\n * (`(result: RunResultFile) => boolean | Promise<boolean>`), so this class\n * is meant to be registered directly as `ResultWatcher`'s consumer, not\n * subscribed to a separate event bus the way the predecessor's notifier\n * subscribed to two\n * - Batching (`completionBatcher.ts`) only ever holds a *successful*\n * completion. A failure or a pause is exactly the situation batching's\n * debounce would otherwise delay reporting, so those flush whatever is\n * already held for the same group and emit immediately, unbatched\n * - One batcher per group key (by `sessionId`, falling back to `cwd`, then a\n * shared `'unknown'` bucket), created lazily and kept for the process\n * lifetime: siblings of the same run share a group, unrelated runs never\n * hold each other up\n * - `deliver()`'s returned promise resolves only once the item's group\n * actually emits (immediately for a bypass, after the batcher's debounce\n * for a grouped success). `ResultWatcher` awaits this before deciding\n * whether to release the claim, so a claim legitimately stays in flight for\n * as long as its group is held open - that is intended, not a stall\n *\n * WHY `sendMessage` IS INERT UNTIL A HOST IS ATTACHED:\n * The host channel arrives at runtime, not at construction: this is a\n * container singleton, and the `ExtensionAPI` that owns the chat surface only\n * exists once `extensions/pi.ts` is activated. `attachHost` is what closes\n * that gap, and until it is called - in the runner child, in a test, or in\n * any process with no TUI - returning `false` rather than claiming success is\n * deliberate. It is the honest answer (\"this was not actually shown to\n * anyone\"), and it is what lets `ResultWatcher`'s retry keep the claim around\n * to be flushed later instead of dropping the completion on the floor.\n *\n * AVOID:\n * - Reintroducing a dedupe map here \"just in case\"; see the header note above\n * - Calling `batcher.push()` for anything whose status is not `'completed'`\n */\n\nimport { injectable } from 'inversify';\nimport {\n type CompletionBatchConfig,\n type CompletionBatcher,\n createCompletionBatcher,\n resolveCompletionBatchConfig,\n} from './completionBatcher.ts';\nimport type { RunResultFile } from './resultWatcher.ts';\n\nexport type CompletionStatus = 'completed' | 'failed' | 'paused';\n\nconst EMPTY_OUTPUT = '(no output)';\nconst UNKNOWN_VALUE = 'unknown';\n\n/** What a completion actually renders as, independent of the raw result shape. */\nexport interface CompletionNotifyDetails {\n agent: string;\n /**\n * The run this completion belongs to.\n *\n * Load-bearing, not decoration: a completion is the ONLY message the model\n * gets when a background run ends, and every follow-up it might want -\n * `{action:'status', id}`, `steer`, `resume`, tailing a transcript - is\n * keyed by run id. Without it the model has to re-list every run and guess\n * which one just finished, which is exactly the wasted turn the sibling\n * implementation avoids by putting `<task-id>` in its own notification.\n */\n runId: string;\n status: CompletionStatus;\n resultPreview: string;\n taskInfo?: string;\n durationMs?: number;\n sessionLabel?: string;\n sessionValue?: string;\n handoffPath?: string;\n}\n\n/**\n * What the model is expected to DO about this completion, stated in the\n * message rather than left to inference.\n *\n * A bare \"Background task completed\" invites a passive acknowledgement. Naming\n * the required handling - and, for the empty-summary case, naming the exact\n * call that recovers the output - is what turns a notification into an\n * instruction. Mirrors the sibling implementation's `<coordinator-action>`.\n */\nfunction completionAction(details: CompletionNotifyDetails): string {\n const hasPreview = details.resultPreview.trim().length > 0;\n if (details.status === 'completed') {\n return hasPreview\n ? 'Read this result now and incorporate, reject, or mark it irrelevant before replying to the user.'\n : `No summary was produced. Call { action: \"status\", id: \"${details.runId}\", view: \"transcript\" } before replying.`;\n }\n if (details.status === 'paused') {\n return `Run is paused and resumable. Inspect it with { action: \"status\", id: \"${details.runId}\" }, then decide whether to resume or abandon it.`;\n }\n return `Review this failure and tell the user whether it affects the current work. Full output: { action: \"status\", id: \"${details.runId}\", view: \"transcript\" }.`;\n}\n\nfunction formatSessionLine(details: CompletionNotifyDetails): string | undefined {\n if (!details.sessionValue) return undefined;\n return details.sessionLabel ? `${details.sessionLabel}: ${details.sessionValue}` : details.sessionValue;\n}\n\nexport function formatSingleCompletion(details: CompletionNotifyDetails): string {\n const sessionLine = formatSessionLine(details);\n return [\n `Background task ${details.status}: **${details.agent}**${details.taskInfo ?? ''}`,\n `run id: ${details.runId}`,\n '',\n details.resultPreview.trim() ? details.resultPreview : EMPTY_OUTPUT,\n details.handoffPath ? '' : undefined,\n details.handoffPath ? `Parallel handoff: ${details.handoffPath}` : undefined,\n sessionLine ? '' : undefined,\n sessionLine,\n '',\n completionAction(details),\n ]\n .filter((line) => line !== undefined)\n .join('\\n');\n}\n\nexport function formatGroupedCompletion(details: CompletionNotifyDetails[]): string {\n const header = `Background tasks completed (${details.length}): ${details.map((d) => `**${d.agent}**${d.taskInfo ?? ''}`).join(', ')}`;\n const blocks: string[] = [header, ''];\n for (let index = 0; index < details.length; index++) {\n const detail = details[index];\n if (!detail) continue;\n const sessionLine = formatSessionLine(detail);\n blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ''} - run id: ${detail.runId}`);\n blocks.push(detail.resultPreview.trim() ? detail.resultPreview : EMPTY_OUTPUT);\n if (detail.handoffPath) blocks.push(`Parallel handoff: ${detail.handoffPath}`);\n if (sessionLine) blocks.push(sessionLine);\n blocks.push(completionAction(detail));\n blocks.push('');\n }\n return blocks.join('\\n').trimEnd();\n}\n\n/** Narrow an opaque `RunResultFile` field to a string, the same defensive read used throughout. */\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction completionGroupKey(result: RunResultFile): string {\n const sessionId = asString(result.sessionId)?.trim();\n if (sessionId) return `session:${sessionId}`;\n const cwd = asString(result.cwd)?.trim();\n return cwd ? `cwd:${cwd}` : UNKNOWN_VALUE;\n}\n\n/** Turn a raw, opaque result record into what `formatSingleCompletion`/`formatGroupedCompletion` render. */\nexport function buildCompletionDetails(result: RunResultFile): CompletionNotifyDetails {\n const agent = asString(result.agent) ?? UNKNOWN_VALUE;\n const summary = asString(result.summary) ?? '';\n const success = typeof result.success === 'boolean' ? result.success : undefined;\n const state = asString(result.state);\n const paused = success === false && (state === 'paused' || summary.startsWith('Paused after interrupt.'));\n const status: CompletionStatus = paused ? 'paused' : success === false ? 'failed' : 'completed';\n\n const taskIndex = asNumber(result.taskIndex);\n const totalTasks = asNumber(result.totalTasks);\n const taskInfo =\n taskIndex !== undefined && totalTasks !== undefined ? ` (${taskIndex + 1}/${totalTasks})` : undefined;\n\n const parallelHandoff =\n typeof result.parallelHandoff === 'object' && result.parallelHandoff !== null\n ? (result.parallelHandoff as { path?: unknown })\n : undefined;\n const handoffPath = asString(parallelHandoff?.path);\n\n const shareUrl = asString(result.shareUrl);\n const shareError = asString(result.shareError);\n const sessionFile = asString(result.sessionFile);\n const session = shareUrl\n ? { label: 'Session', value: shareUrl }\n : shareError\n ? { label: 'Session share error', value: shareError }\n : sessionFile\n ? { label: 'Session file', value: sessionFile }\n : undefined;\n\n return {\n agent,\n // `RunResultFile` guarantees `runId` (see `resultWatcher.ts`), so there is\n // no honest fallback to invent here - an empty string would be a run id the\n // model could not use, dressed up as one it could.\n runId: result.runId,\n status,\n resultPreview: summary,\n ...(taskInfo ? { taskInfo } : {}),\n ...(asNumber(result.durationMs) !== undefined ? { durationMs: asNumber(result.durationMs) } : {}),\n ...(handoffPath ? { handoffPath } : {}),\n ...(session ? { sessionLabel: session.label, sessionValue: session.value } : {}),\n };\n}\n\ninterface PendingCompletion {\n details: CompletionNotifyDetails;\n triggerTurn: boolean;\n resolve(delivered: boolean): void;\n}\n\n/**\n * The host capability this notifier needs, narrowed to the one method it\n * calls. Structural rather than `ExtensionAPI` itself so the runs domain does\n * not take a dependency on the host type for a single call, and so a test can\n * supply a recorder without constructing a whole extension API.\n */\nexport interface CompletionNotifyHost {\n sendMessage(\n message: { customType: string; content: string; display: boolean; details?: CompletionNotifyDetails[] },\n options?: { triggerTurn?: boolean; deliverAs?: 'steer' },\n ): void;\n}\n\nexport interface ICompletionNotifier {\n /** Matches `ResultConsumer` exactly; register this directly with `ResultWatcher.start()`. */\n deliver(result: RunResultFile): Promise<boolean>;\n /**\n * Give the notifier the host channel to render into. Called by the parent\n * composition root (`extensions/pi.ts`); until it is, `sendMessage` stays\n * inert and honestly reports non-delivery - see the module header.\n */\n attachHost(host: CompletionNotifyHost): void;\n /** Flush every held batch immediately (unemitted items resolve `false`) and stop accepting new ones. */\n dispose(): void;\n}\n\n/**\n * The custom-message type the parent renders completions under. Cross-process\n * significant in the same way the nested-event tokens are: the child-side\n * prompt runtime strips messages of this type out of a child's inherited\n * history (`stripParentOnlySubagentMessages`), so the two sides must agree on\n * the literal.\n */\nexport const SUBAGENT_NOTIFY_MESSAGE_TYPE = 'subagent-notify';\n\n@injectable()\nexport class CompletionNotifier implements ICompletionNotifier {\n /**\n * Seam for tests, as a protected member rather than a constructor\n * argument: inversify cannot resolve a primitive-shaped config object. See\n * `pollScheduler.ts` for the same pattern.\n */\n protected readonly batchConfig: CompletionBatchConfig | undefined = undefined;\n\n private readonly batchers = new Map<string, CompletionBatcher<PendingCompletion>>();\n private disposed = false;\n private host: CompletionNotifyHost | undefined;\n\n /**\n * Last host attachment wins. A reload that rebuilds the extension against a\n * fresh `ExtensionAPI` re-attaches rather than stacking channels, matching\n * how every other registration in `extensions/pi.ts` is idempotent.\n */\n attachHost(host: CompletionNotifyHost): void {\n this.host = host;\n }\n\n /**\n * Deliver a formatted completion message. Inert until `attachHost` supplies\n * a host (see the module header for why non-delivery is reported honestly\n * rather than optimistically). Not `async`: `emit()` below does not await it\n * either way - see its doc comment for why.\n *\n * A throw from the host is caught and reported as non-delivery rather than\n * propagated: `emit()` is a batcher callback running on a timer with no\n * caller to catch for it, and a failed render must leave `ResultWatcher`'s\n * claim in place for a retry, which is exactly what `false` does.\n */\n protected sendMessage(\n content: string,\n options: { triggerTurn: boolean; details: CompletionNotifyDetails[] },\n ): boolean {\n if (!this.host) return false;\n try {\n this.host.sendMessage(\n { customType: SUBAGENT_NOTIFY_MESSAGE_TYPE, content, display: true, details: options.details },\n { triggerTurn: options.triggerTurn, deliverAs: 'steer' },\n );\n return true;\n } catch {\n return false;\n }\n }\n\n async deliver(result: RunResultFile): Promise<boolean> {\n if (result.internal === true) return true;\n if (this.disposed) return false;\n const details = buildCompletionDetails(result);\n const triggerTurn = result.triggerTurn !== false;\n\n return new Promise<boolean>((resolve) => {\n const item: PendingCompletion = { details, triggerTurn, resolve };\n const batcher = this.getBatcher(result);\n if (details.status !== 'completed') {\n // A failure or a pause must not sit behind a debounce meant for\n // grouping good news; flush whatever this group was already holding,\n // then emit this one immediately, unbatched.\n batcher.flush();\n this.emit([item]);\n return;\n }\n batcher.push(item);\n });\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const batcher of this.batchers.values()) {\n for (const item of batcher.dispose()) item.resolve(false);\n }\n this.batchers.clear();\n }\n\n private getBatcher(result: RunResultFile): CompletionBatcher<PendingCompletion> {\n const key = completionGroupKey(result);\n let batcher = this.batchers.get(key);\n if (!batcher) {\n batcher = createCompletionBatcher<PendingCompletion>({\n config: resolveCompletionBatchConfig(this.batchConfig),\n emit: (items) => this.emit(items),\n });\n this.batchers.set(key, batcher);\n }\n return batcher;\n }\n\n /**\n * The batcher's `emit` callback: format the group (single vs. grouped\n * rendering, `formatSingleCompletion`/`formatGroupedCompletion`) and hand\n * it to `sendMessage`. Deliberately not `async` and does not await\n * `sendMessage`: `createCompletionBatcher`'s `emit` option is a synchronous\n * callback (see its own contract), and every item's promise still resolves\n * correctly here regardless, since `sendMessage`'s result is available\n * synchronously to whichever implementation is active.\n */\n private emit(items: PendingCompletion[]): void {\n if (items.length === 0) return;\n const details = items.map((item) => item.details);\n const content = details.length === 1 ? formatSingleCompletion(details[0]!) : formatGroupedCompletion(details);\n const delivered = this.sendMessage(content, {\n triggerTurn: items.some((item) => item.triggerTurn),\n details,\n });\n for (const item of items) item.resolve(delivered);\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import{__esmMin as e}from"../../_virtual/_rolldown/runtime.mjs";import{__decorate as t,init_decorate as n}from"../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs";import{createCompletionBatcher as r,init_completionBatcher as i,resolveCompletionBatchConfig as a}from"./completionBatcher.mjs";import{injectable as o}from"inversify";function s(e){let t=e.resultPreview.trim().length>0;return e.status===`completed`?t?`Read this result now and incorporate, reject, or mark it irrelevant before replying to the user.`:`No summary was produced. Call { action: "status", id: "${e.runId}", view: "transcript" } before replying.`:e.status===`paused`?`Run is paused and resumable. Inspect it with { action: "status", id: "${e.runId}" }, then decide whether to resume or abandon it.`:`Review this failure and tell the user whether it affects the current work. Full output: { action: "status", id: "${e.runId}", view: "transcript" }.`}function c(e){if(e.sessionValue)return e.sessionLabel?`${e.sessionLabel}: ${e.sessionValue}`:e.sessionValue}function l(e){let t=c(e);return[`Background task ${e.status}: **${e.agent}**${e.taskInfo??``}`,`run id: ${e.runId}`,``,e.resultPreview.trim()?e.resultPreview:h,e.handoffPath?``:void 0,e.handoffPath?`Parallel handoff: ${e.handoffPath}`:void 0,t?``:void 0,t,``,s(e)].filter(e=>e!==void 0).join(`
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{__decorate as t,init_decorate as n}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs";import{createCompletionBatcher as r,init_completionBatcher as i,resolveCompletionBatchConfig as a}from"./completionBatcher.mjs";import{injectable as o}from"inversify";function s(e){let t=e.resultPreview.trim().length>0;return e.status===`completed`?t?`Read this result now and incorporate, reject, or mark it irrelevant before replying to the user.`:`No summary was produced. Call { action: "status", id: "${e.runId}", view: "transcript" } before replying.`:e.status===`paused`?`Run is paused and resumable. Inspect it with { action: "status", id: "${e.runId}" }, then decide whether to resume or abandon it.`:`Review this failure and tell the user whether it affects the current work. Full output: { action: "status", id: "${e.runId}", view: "transcript" }.`}function c(e){if(e.sessionValue)return e.sessionLabel?`${e.sessionLabel}: ${e.sessionValue}`:e.sessionValue}function l(e){let t=c(e);return[`Background task ${e.status}: **${e.agent}**${e.taskInfo??``}`,`run id: ${e.runId}`,``,e.resultPreview.trim()?e.resultPreview:h,e.handoffPath?``:void 0,e.handoffPath?`Parallel handoff: ${e.handoffPath}`:void 0,t?``:void 0,t,``,s(e)].filter(e=>e!==void 0).join(`
2
2
  `)}function u(e){let t=[`Background tasks completed (${e.length}): ${e.map(e=>`**${e.agent}**${e.taskInfo??``}`).join(`, `)}`,``];for(let n=0;n<e.length;n++){let r=e[n];if(!r)continue;let i=c(r);t.push(`${n+1}. ${r.agent}${r.taskInfo??``} - run id: ${r.runId}`),t.push(r.resultPreview.trim()?r.resultPreview:h),r.handoffPath&&t.push(`Parallel handoff: ${r.handoffPath}`),i&&t.push(i),t.push(s(r)),t.push(``)}return t.join(`
3
3
  `).trimEnd()}function d(e){return typeof e==`string`?e:void 0}function f(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function p(e){let t=d(e.sessionId)?.trim();if(t)return`session:${t}`;let n=d(e.cwd)?.trim();return n?`cwd:${n}`:g}function m(e){let t=d(e.agent)??g,n=d(e.summary)??``,r=typeof e.success==`boolean`?e.success:void 0,i=d(e.state),a=r===!1&&(i===`paused`||n.startsWith(`Paused after interrupt.`))?`paused`:r===!1?`failed`:`completed`,o=f(e.taskIndex),s=f(e.totalTasks),c=o!==void 0&&s!==void 0?` (${o+1}/${s})`:void 0,l=d((typeof e.parallelHandoff==`object`&&e.parallelHandoff!==null?e.parallelHandoff:void 0)?.path),u=d(e.shareUrl),p=d(e.shareError),m=d(e.sessionFile),h=u?{label:`Session`,value:u}:p?{label:`Session share error`,value:p}:m?{label:`Session file`,value:m}:void 0;return{agent:t,runId:e.runId,status:a,resultPreview:n,...c?{taskInfo:c}:{},...f(e.durationMs)===void 0?{}:{durationMs:f(e.durationMs)},...l?{handoffPath:l}:{},...h?{sessionLabel:h.label,sessionValue:h.value}:{}}}var h,g,_,v,y=e((()=>{i(),n(),h=`(no output)`,g=`unknown`,_=`subagent-notify`,v=class{batchConfig=void 0;batchers=new Map;disposed=!1;host;attachHost(e){this.host=e}sendMessage(e,t){if(!this.host)return!1;try{return this.host.sendMessage({customType:_,content:e,display:!0,details:t.details},{triggerTurn:t.triggerTurn,deliverAs:`steer`}),!0}catch{return!1}}async deliver(e){if(e.internal===!0)return!0;if(this.disposed)return!1;let t=m(e),n=e.triggerTurn!==!1;return new Promise(r=>{let i={details:t,triggerTurn:n,resolve:r},a=this.getBatcher(e);if(t.status!==`completed`){a.flush(),this.emit([i]);return}a.push(i)})}dispose(){if(!this.disposed){this.disposed=!0;for(let e of this.batchers.values())for(let t of e.dispose())t.resolve(!1);this.batchers.clear()}}getBatcher(e){let t=p(e),n=this.batchers.get(t);return n||(n=r({config:a(this.batchConfig),emit:e=>this.emit(e)}),this.batchers.set(t,n)),n}emit(e){if(e.length===0)return;let t=e.map(e=>e.details),n=t.length===1?l(t[0]):u(t),r=this.sendMessage(n,{triggerTurn:e.some(e=>e.triggerTurn),details:t});for(let t of e)t.resolve(r)}},v=t([o()],v)}));y();export{v as CompletionNotifier,_ as SUBAGENT_NOTIFY_MESSAGE_TYPE,y as init_notify};
4
4
  //# sourceMappingURL=notify.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notify.mjs","names":[],"sources":["../../../../src/services/runs/background/notify.ts"],"sourcesContent":["/**\n * Formats a run's terminal result into a completion notification and hands\n * it to `ResultWatcher` as its `ResultConsumer`, batching successful\n * completions and bypassing that batching for anything that needs the\n * operator's attention right away.\n *\n * WHY `completion-dedupe.ts` IS NOT PORTED:\n * The predecessor deduped completion notifications with its own TTL-keyed\n * map (`completion-dedupe.ts`), independently of the identically-shaped TTL\n * dedupe `resultWatcher.ts` already does before it ever calls a consumer.\n * Those two copies could disagree - the exact bug class `resultWatcher.ts`'s\n * header now documents fixing. This package has exactly one producer of\n * completions today: `ResultWatcher`, which only calls its consumer once per\n * `runId` per TTL window. `CompletionNotifier.deliver()` is that consumer, so\n * it trusts that guarantee instead of re-implementing it. The predecessor\n * needed its own copy because it had two independent producers (async result\n * files AND a synchronous foreground-run event); this package is async-only\n * (see `spawnHandshake.ts`'s header) and has not ported foreground runs. IF\n * a second completion producer is added later, `deliver()` can no longer\n * assume `ResultWatcher` already deduped for it, and this module will need\n * its own dedupe again at that point - not before.\n *\n * DESIGN PATTERNS:\n * - `deliver()` matches `ResultConsumer`'s exact shape\n * (`(result: RunResultFile) => boolean | Promise<boolean>`), so this class\n * is meant to be registered directly as `ResultWatcher`'s consumer, not\n * subscribed to a separate event bus the way the predecessor's notifier\n * subscribed to two\n * - Batching (`completionBatcher.ts`) only ever holds a *successful*\n * completion. A failure or a pause is exactly the situation batching's\n * debounce would otherwise delay reporting, so those flush whatever is\n * already held for the same group and emit immediately, unbatched\n * - One batcher per group key (by `sessionId`, falling back to `cwd`, then a\n * shared `'unknown'` bucket), created lazily and kept for the process\n * lifetime: siblings of the same run share a group, unrelated runs never\n * hold each other up\n * - `deliver()`'s returned promise resolves only once the item's group\n * actually emits (immediately for a bypass, after the batcher's debounce\n * for a grouped success). `ResultWatcher` awaits this before deciding\n * whether to release the claim, so a claim legitimately stays in flight for\n * as long as its group is held open - that is intended, not a stall\n *\n * WHY `sendMessage` IS INERT UNTIL A HOST IS ATTACHED:\n * The host channel arrives at runtime, not at construction: this is a\n * container singleton, and the `ExtensionAPI` that owns the chat surface only\n * exists once `extensions/pi.ts` is activated. `attachHost` is what closes\n * that gap, and until it is called - in the runner child, in a test, or in\n * any process with no TUI - returning `false` rather than claiming success is\n * deliberate. It is the honest answer (\"this was not actually shown to\n * anyone\"), and it is what lets `ResultWatcher`'s retry keep the claim around\n * to be flushed later instead of dropping the completion on the floor.\n *\n * AVOID:\n * - Reintroducing a dedupe map here \"just in case\"; see the header note above\n * - Calling `batcher.push()` for anything whose status is not `'completed'`\n */\n\nimport { injectable } from 'inversify';\nimport {\n type CompletionBatchConfig,\n type CompletionBatcher,\n createCompletionBatcher,\n resolveCompletionBatchConfig,\n} from './completionBatcher.ts';\nimport type { RunResultFile } from './resultWatcher.ts';\n\nexport type CompletionStatus = 'completed' | 'failed' | 'paused';\n\nconst EMPTY_OUTPUT = '(no output)';\nconst UNKNOWN_VALUE = 'unknown';\n\n/** What a completion actually renders as, independent of the raw result shape. */\nexport interface CompletionNotifyDetails {\n agent: string;\n /**\n * The run this completion belongs to.\n *\n * Load-bearing, not decoration: a completion is the ONLY message the model\n * gets when a background run ends, and every follow-up it might want -\n * `{action:'status', id}`, `steer`, `resume`, tailing a transcript - is\n * keyed by run id. Without it the model has to re-list every run and guess\n * which one just finished, which is exactly the wasted turn the sibling\n * implementation avoids by putting `<task-id>` in its own notification.\n */\n runId: string;\n status: CompletionStatus;\n resultPreview: string;\n taskInfo?: string;\n durationMs?: number;\n sessionLabel?: string;\n sessionValue?: string;\n handoffPath?: string;\n}\n\n/**\n * What the model is expected to DO about this completion, stated in the\n * message rather than left to inference.\n *\n * A bare \"Background task completed\" invites a passive acknowledgement. Naming\n * the required handling - and, for the empty-summary case, naming the exact\n * call that recovers the output - is what turns a notification into an\n * instruction. Mirrors the sibling implementation's `<coordinator-action>`.\n */\nfunction completionAction(details: CompletionNotifyDetails): string {\n const hasPreview = details.resultPreview.trim().length > 0;\n if (details.status === 'completed') {\n return hasPreview\n ? 'Read this result now and incorporate, reject, or mark it irrelevant before replying to the user.'\n : `No summary was produced. Call { action: \"status\", id: \"${details.runId}\", view: \"transcript\" } before replying.`;\n }\n if (details.status === 'paused') {\n return `Run is paused and resumable. Inspect it with { action: \"status\", id: \"${details.runId}\" }, then decide whether to resume or abandon it.`;\n }\n return `Review this failure and tell the user whether it affects the current work. Full output: { action: \"status\", id: \"${details.runId}\", view: \"transcript\" }.`;\n}\n\nfunction formatSessionLine(details: CompletionNotifyDetails): string | undefined {\n if (!details.sessionValue) return undefined;\n return details.sessionLabel ? `${details.sessionLabel}: ${details.sessionValue}` : details.sessionValue;\n}\n\nexport function formatSingleCompletion(details: CompletionNotifyDetails): string {\n const sessionLine = formatSessionLine(details);\n return [\n `Background task ${details.status}: **${details.agent}**${details.taskInfo ?? ''}`,\n `run id: ${details.runId}`,\n '',\n details.resultPreview.trim() ? details.resultPreview : EMPTY_OUTPUT,\n details.handoffPath ? '' : undefined,\n details.handoffPath ? `Parallel handoff: ${details.handoffPath}` : undefined,\n sessionLine ? '' : undefined,\n sessionLine,\n '',\n completionAction(details),\n ]\n .filter((line) => line !== undefined)\n .join('\\n');\n}\n\nexport function formatGroupedCompletion(details: CompletionNotifyDetails[]): string {\n const header = `Background tasks completed (${details.length}): ${details.map((d) => `**${d.agent}**${d.taskInfo ?? ''}`).join(', ')}`;\n const blocks: string[] = [header, ''];\n for (let index = 0; index < details.length; index++) {\n const detail = details[index];\n if (!detail) continue;\n const sessionLine = formatSessionLine(detail);\n blocks.push(`${index + 1}. ${detail.agent}${detail.taskInfo ?? ''} - run id: ${detail.runId}`);\n blocks.push(detail.resultPreview.trim() ? detail.resultPreview : EMPTY_OUTPUT);\n if (detail.handoffPath) blocks.push(`Parallel handoff: ${detail.handoffPath}`);\n if (sessionLine) blocks.push(sessionLine);\n blocks.push(completionAction(detail));\n blocks.push('');\n }\n return blocks.join('\\n').trimEnd();\n}\n\n/** Narrow an opaque `RunResultFile` field to a string, the same defensive read used throughout. */\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction completionGroupKey(result: RunResultFile): string {\n const sessionId = asString(result.sessionId)?.trim();\n if (sessionId) return `session:${sessionId}`;\n const cwd = asString(result.cwd)?.trim();\n return cwd ? `cwd:${cwd}` : UNKNOWN_VALUE;\n}\n\n/** Turn a raw, opaque result record into what `formatSingleCompletion`/`formatGroupedCompletion` render. */\nexport function buildCompletionDetails(result: RunResultFile): CompletionNotifyDetails {\n const agent = asString(result.agent) ?? UNKNOWN_VALUE;\n const summary = asString(result.summary) ?? '';\n const success = typeof result.success === 'boolean' ? result.success : undefined;\n const state = asString(result.state);\n const paused = success === false && (state === 'paused' || summary.startsWith('Paused after interrupt.'));\n const status: CompletionStatus = paused ? 'paused' : success === false ? 'failed' : 'completed';\n\n const taskIndex = asNumber(result.taskIndex);\n const totalTasks = asNumber(result.totalTasks);\n const taskInfo =\n taskIndex !== undefined && totalTasks !== undefined ? ` (${taskIndex + 1}/${totalTasks})` : undefined;\n\n const parallelHandoff =\n typeof result.parallelHandoff === 'object' && result.parallelHandoff !== null\n ? (result.parallelHandoff as { path?: unknown })\n : undefined;\n const handoffPath = asString(parallelHandoff?.path);\n\n const shareUrl = asString(result.shareUrl);\n const shareError = asString(result.shareError);\n const sessionFile = asString(result.sessionFile);\n const session = shareUrl\n ? { label: 'Session', value: shareUrl }\n : shareError\n ? { label: 'Session share error', value: shareError }\n : sessionFile\n ? { label: 'Session file', value: sessionFile }\n : undefined;\n\n return {\n agent,\n // `RunResultFile` guarantees `runId` (see `resultWatcher.ts`), so there is\n // no honest fallback to invent here - an empty string would be a run id the\n // model could not use, dressed up as one it could.\n runId: result.runId,\n status,\n resultPreview: summary,\n ...(taskInfo ? { taskInfo } : {}),\n ...(asNumber(result.durationMs) !== undefined ? { durationMs: asNumber(result.durationMs) } : {}),\n ...(handoffPath ? { handoffPath } : {}),\n ...(session ? { sessionLabel: session.label, sessionValue: session.value } : {}),\n };\n}\n\ninterface PendingCompletion {\n details: CompletionNotifyDetails;\n triggerTurn: boolean;\n resolve(delivered: boolean): void;\n}\n\n/**\n * The host capability this notifier needs, narrowed to the one method it\n * calls. Structural rather than `ExtensionAPI` itself so the runs domain does\n * not take a dependency on the host type for a single call, and so a test can\n * supply a recorder without constructing a whole extension API.\n */\nexport interface CompletionNotifyHost {\n sendMessage(\n message: { customType: string; content: string; display: boolean; details?: CompletionNotifyDetails[] },\n options?: { triggerTurn?: boolean; deliverAs?: 'steer' },\n ): void;\n}\n\nexport interface ICompletionNotifier {\n /** Matches `ResultConsumer` exactly; register this directly with `ResultWatcher.start()`. */\n deliver(result: RunResultFile): Promise<boolean>;\n /**\n * Give the notifier the host channel to render into. Called by the parent\n * composition root (`extensions/pi.ts`); until it is, `sendMessage` stays\n * inert and honestly reports non-delivery - see the module header.\n */\n attachHost(host: CompletionNotifyHost): void;\n /** Flush every held batch immediately (unemitted items resolve `false`) and stop accepting new ones. */\n dispose(): void;\n}\n\n/**\n * The custom-message type the parent renders completions under. Cross-process\n * significant in the same way the nested-event tokens are: the child-side\n * prompt runtime strips messages of this type out of a child's inherited\n * history (`stripParentOnlySubagentMessages`), so the two sides must agree on\n * the literal.\n */\nexport const SUBAGENT_NOTIFY_MESSAGE_TYPE = 'subagent-notify';\n\n@injectable()\nexport class CompletionNotifier implements ICompletionNotifier {\n /**\n * Seam for tests, as a protected member rather than a constructor\n * argument: inversify cannot resolve a primitive-shaped config object. See\n * `pollScheduler.ts` for the same pattern.\n */\n protected readonly batchConfig: CompletionBatchConfig | undefined = undefined;\n\n private readonly batchers = new Map<string, CompletionBatcher<PendingCompletion>>();\n private disposed = false;\n private host: CompletionNotifyHost | undefined;\n\n /**\n * Last host attachment wins. A reload that rebuilds the extension against a\n * fresh `ExtensionAPI` re-attaches rather than stacking channels, matching\n * how every other registration in `extensions/pi.ts` is idempotent.\n */\n attachHost(host: CompletionNotifyHost): void {\n this.host = host;\n }\n\n /**\n * Deliver a formatted completion message. Inert until `attachHost` supplies\n * a host (see the module header for why non-delivery is reported honestly\n * rather than optimistically). Not `async`: `emit()` below does not await it\n * either way - see its doc comment for why.\n *\n * A throw from the host is caught and reported as non-delivery rather than\n * propagated: `emit()` is a batcher callback running on a timer with no\n * caller to catch for it, and a failed render must leave `ResultWatcher`'s\n * claim in place for a retry, which is exactly what `false` does.\n */\n protected sendMessage(\n content: string,\n options: { triggerTurn: boolean; details: CompletionNotifyDetails[] },\n ): boolean {\n if (!this.host) return false;\n try {\n this.host.sendMessage(\n { customType: SUBAGENT_NOTIFY_MESSAGE_TYPE, content, display: true, details: options.details },\n { triggerTurn: options.triggerTurn, deliverAs: 'steer' },\n );\n return true;\n } catch {\n return false;\n }\n }\n\n async deliver(result: RunResultFile): Promise<boolean> {\n if (result.internal === true) return true;\n if (this.disposed) return false;\n const details = buildCompletionDetails(result);\n const triggerTurn = result.triggerTurn !== false;\n\n return new Promise<boolean>((resolve) => {\n const item: PendingCompletion = { details, triggerTurn, resolve };\n const batcher = this.getBatcher(result);\n if (details.status !== 'completed') {\n // A failure or a pause must not sit behind a debounce meant for\n // grouping good news; flush whatever this group was already holding,\n // then emit this one immediately, unbatched.\n batcher.flush();\n this.emit([item]);\n return;\n }\n batcher.push(item);\n });\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const batcher of this.batchers.values()) {\n for (const item of batcher.dispose()) item.resolve(false);\n }\n this.batchers.clear();\n }\n\n private getBatcher(result: RunResultFile): CompletionBatcher<PendingCompletion> {\n const key = completionGroupKey(result);\n let batcher = this.batchers.get(key);\n if (!batcher) {\n batcher = createCompletionBatcher<PendingCompletion>({\n config: resolveCompletionBatchConfig(this.batchConfig),\n emit: (items) => this.emit(items),\n });\n this.batchers.set(key, batcher);\n }\n return batcher;\n }\n\n /**\n * The batcher's `emit` callback: format the group (single vs. grouped\n * rendering, `formatSingleCompletion`/`formatGroupedCompletion`) and hand\n * it to `sendMessage`. Deliberately not `async` and does not await\n * `sendMessage`: `createCompletionBatcher`'s `emit` option is a synchronous\n * callback (see its own contract), and every item's promise still resolves\n * correctly here regardless, since `sendMessage`'s result is available\n * synchronously to whichever implementation is active.\n */\n private emit(items: PendingCompletion[]): void {\n if (items.length === 0) return;\n const details = items.map((item) => item.details);\n const content = details.length === 1 ? formatSingleCompletion(details[0]!) : formatGroupedCompletion(details);\n const delivered = this.sendMessage(content, {\n triggerTurn: items.some((item) => item.triggerTurn),\n details,\n });\n for (const item of items) item.resolve(delivered);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parentWatchdog.cjs","names":[],"sources":["../../../../src/services/runs/background/parentWatchdog.ts"],"sourcesContent":["/**\n * A child's own check that its parent is still there.\n *\n * WHY THIS EXISTS WHEN THE PARENT ALREADY SWEEPS AT SHUTDOWN:\n * The parent's `session_shutdown` sweep covers every case where the parent gets\n * to run code: quit, reload, `/new`, `/resume`, `/fork`. It cannot cover\n * `SIGKILL`, an OOM kill, or a host crash - no handler runs, and because every\n * child is spawned `detached: true` it is in its own process group, so the\n * terminal's Ctrl-C never reaches it either. Without this, exactly those cases\n * leave an agent running and spending tokens with nothing left to manage it.\n *\n * WHY POLLING AND NOT AN IPC CHANNEL:\n * A detached child has no inherited channel to watch, and adding one would\n * couple the child's liveness to a socket that can fail on its own. `kill(pid, 0)`\n * is the cheapest possible question and has no failure mode of its own.\n *\n * WHY IT DOES NOT JUST `process.exit`:\n * Exiting would leave the run reporting `running` forever and orphan the\n * agent's own subprocesses. The whole point is to reach the same terminal path\n * a clean stop takes, so `onParentLost` is expected to be\n * `TerminalPersistenceService.finalize()`, which persists a terminal status and\n * kills tracked children before the process goes.\n *\n * AVOID:\n * - A short interval. This is a safety net for a rare event, not a heartbeat;\n * polling hard buys nothing and costs a syscall per child per tick\n */\n\nconst DEFAULT_INTERVAL_MS = 5_000;\n\nexport interface ParentWatchdogOptions {\n /** Pid to watch. Defaults to this process's parent. */\n parentPid?: number;\n intervalMs?: number;\n /** Liveness as a port, so a test never probes a real pid. */\n isAlive?: (pid: number) => boolean;\n /** What to do once the parent is gone. Expected to finalize and exit. */\n onParentLost: () => void;\n}\n\nfunction defaultIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\n/**\n * Start watching. Returns a disposer.\n *\n * A `parentPid` of 1 means this process has already been reparented to init -\n * the parent is gone and nothing is coming back - so the callback fires\n * immediately rather than after one interval.\n */\nexport function startParentWatchdog(options: ParentWatchdogOptions): () => void {\n const isAlive = options.isAlive ?? defaultIsAlive;\n const parentPid = options.parentPid ?? process.ppid;\n let fired = false;\n\n const check = (): void => {\n if (fired) return;\n if (parentPid > 1 && isAlive(parentPid)) return;\n fired = true;\n options.onParentLost();\n };\n\n if (parentPid <= 1) {\n check();\n return () => {};\n }\n\n const timer = setInterval(check, options.intervalMs ?? DEFAULT_INTERVAL_MS);\n // Unref'd so this never by itself keeps a finished child alive.\n timer.unref?.();\n return () => clearInterval(timer);\n}\n"],"mappings":"AAwCA,SAAS,EAAe,EAAsB,CAC5C,GAAI,CAEF,OADA,QAAQ,KAAK,EAAK,EAAE,CACb,SACA,EAAO,CACd,OAAQ,EAAgC,OAAS,SAWrD,SAAgB,EAAoB,EAA4C,CAC9E,IAAM,EAAU,EAAQ,SAAW,EAC7B,EAAY,EAAQ,WAAa,QAAQ,KAC3C,EAAQ,GAEN,MAAoB,CACpB,GACA,EAAY,GAAK,EAAQ,EAAU,GACvC,EAAQ,GACR,EAAQ,cAAc,GAGxB,GAAI,GAAa,EAEf,OADA,GAAO,KACM,GAGf,IAAM,EAAQ,YAAY,EAAO,EAAQ,YAAc,IAAoB,CAG3E,OADA,EAAM,SAAS,KACF,cAAc,EAAM"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parentWatchdog.mjs","names":[],"sources":["../../../../src/services/runs/background/parentWatchdog.ts"],"sourcesContent":["/**\n * A child's own check that its parent is still there.\n *\n * WHY THIS EXISTS WHEN THE PARENT ALREADY SWEEPS AT SHUTDOWN:\n * The parent's `session_shutdown` sweep covers every case where the parent gets\n * to run code: quit, reload, `/new`, `/resume`, `/fork`. It cannot cover\n * `SIGKILL`, an OOM kill, or a host crash - no handler runs, and because every\n * child is spawned `detached: true` it is in its own process group, so the\n * terminal's Ctrl-C never reaches it either. Without this, exactly those cases\n * leave an agent running and spending tokens with nothing left to manage it.\n *\n * WHY POLLING AND NOT AN IPC CHANNEL:\n * A detached child has no inherited channel to watch, and adding one would\n * couple the child's liveness to a socket that can fail on its own. `kill(pid, 0)`\n * is the cheapest possible question and has no failure mode of its own.\n *\n * WHY IT DOES NOT JUST `process.exit`:\n * Exiting would leave the run reporting `running` forever and orphan the\n * agent's own subprocesses. The whole point is to reach the same terminal path\n * a clean stop takes, so `onParentLost` is expected to be\n * `TerminalPersistenceService.finalize()`, which persists a terminal status and\n * kills tracked children before the process goes.\n *\n * AVOID:\n * - A short interval. This is a safety net for a rare event, not a heartbeat;\n * polling hard buys nothing and costs a syscall per child per tick\n */\n\nconst DEFAULT_INTERVAL_MS = 5_000;\n\nexport interface ParentWatchdogOptions {\n /** Pid to watch. Defaults to this process's parent. */\n parentPid?: number;\n intervalMs?: number;\n /** Liveness as a port, so a test never probes a real pid. */\n isAlive?: (pid: number) => boolean;\n /** What to do once the parent is gone. Expected to finalize and exit. */\n onParentLost: () => void;\n}\n\nfunction defaultIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === 'EPERM';\n }\n}\n\n/**\n * Start watching. Returns a disposer.\n *\n * A `parentPid` of 1 means this process has already been reparented to init -\n * the parent is gone and nothing is coming back - so the callback fires\n * immediately rather than after one interval.\n */\nexport function startParentWatchdog(options: ParentWatchdogOptions): () => void {\n const isAlive = options.isAlive ?? defaultIsAlive;\n const parentPid = options.parentPid ?? process.ppid;\n let fired = false;\n\n const check = (): void => {\n if (fired) return;\n if (parentPid > 1 && isAlive(parentPid)) return;\n fired = true;\n options.onParentLost();\n };\n\n if (parentPid <= 1) {\n check();\n return () => {};\n }\n\n const timer = setInterval(check, options.intervalMs ?? DEFAULT_INTERVAL_MS);\n // Unref'd so this never by itself keeps a finished child alive.\n timer.unref?.();\n return () => clearInterval(timer);\n}\n"],"mappings":"AAwCA,SAAS,EAAe,EAAsB,CAC5C,GAAI,CAEF,OADA,QAAQ,KAAK,EAAK,EAAE,CACb,SACA,EAAO,CACd,OAAQ,EAAgC,OAAS,SAWrD,SAAgB,EAAoB,EAA4C,CAC9E,IAAM,EAAU,EAAQ,SAAW,EAC7B,EAAY,EAAQ,WAAa,QAAQ,KAC3C,EAAQ,GAEN,MAAoB,CACpB,GACA,EAAY,GAAK,EAAQ,EAAU,GACvC,EAAQ,GACR,EAAQ,cAAc,GAGxB,GAAI,GAAa,EAEf,OADA,GAAO,KACM,GAGf,IAAM,EAAQ,YAAY,EAAO,EAAQ,YAAc,IAAoB,CAG3E,OADA,EAAM,SAAS,KACF,cAAc,EAAM"}
@@ -0,0 +1 @@
1
+ require(`../../../adapters/processTerminal.cjs`);
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{init_processTerminal as t}from"../../../adapters/processTerminal.mjs";var n=e((()=>{t()}));n();export{n as init_processTerminal};
2
+ //# sourceMappingURL=processTerminal.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processTerminal.mjs","names":[],"sources":["../../../../src/services/runs/background/processTerminal.ts"],"sourcesContent":["export {\n type CrashMarkerRecord,\n checkPidLiveness,\n type IProcessTerminalInspector,\n type PidProbe,\n type ProcessLiveness,\n ProcessTerminalInspector,\n type ProcessTerminalVerdict,\n} from '../../../adapters/processTerminal.ts';\n"],"mappings":"iKAQ8C"}
@@ -0,0 +1 @@
1
+ require(`../../../adapters/resultWatcher.cjs`);
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{init_resultWatcher as t}from"../../../adapters/resultWatcher.mjs";var n=e((()=>{t()}));n();export{n as init_resultWatcher};
2
+ //# sourceMappingURL=resultWatcher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resultWatcher.mjs","names":[],"sources":["../../../../src/services/runs/background/resultWatcher.ts"],"sourcesContent":["export {\n CLAIMED_RESULT_FILE_NAME,\n type IResultWatcher,\n RESULT_FILE_SUFFIX,\n type ResultConsumer,\n ResultWatcher,\n type RunResultFile,\n} from '../../../adapters/resultWatcher.ts';\n"],"mappings":"6JAO4C"}
@@ -0,0 +1 @@
1
+ require(`../../../adapters/runIdResolver.cjs`);
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{init_runIdResolver as t}from"../../../adapters/runIdResolver.mjs";var n=e((()=>{t()}));n();export{n as init_runIdResolver};
2
+ //# sourceMappingURL=runIdResolver.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runIdResolver.mjs","names":[],"sources":["../../../../src/services/runs/background/runIdResolver.ts"],"sourcesContent":["export { type IRunIdResolver, type ResolvedRunLocation, RunIdResolver } from '../../../adapters/runIdResolver.ts';\n"],"mappings":"6JAAkH"}
@@ -0,0 +1,2 @@
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),n=require(`../../../container/types.cjs`),r=require(`../../../adapters/atomicJson.cjs`);require(`../../../shared/atomicJson.cjs`);const i=require(`../../../adapters/process/env.cjs`),a=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),o=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),s=require(`../../../shared/paths.cjs`),c=require(`./asyncExecution.cjs`);let l=require(`node:fs`);l=e.__toESM(l,1);let u=require(`node:path`);u=e.__toESM(u,1);let d=require(`inversify`);function f(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function p(e){return typeof e==`object`&&e&&`code`in e?e.code:void 0}let m=class{constructor(e,t,n,r){this.statusWriter=e,this.terminalPersistence=t,this.reporting=n,this.teamMembership=r}now(){return Date.now()}resolveRunIdFromEnv(){let e=process.env[i.SUBAGENT_RUN_ID_ENV];return e?.trim()?e:void 0}readFile(e){try{return l.readFileSync(e,`utf-8`)}catch(e){if(p(e)===`ENOENT`)return;throw e}}writeHandshake(e,t){r.writeAtomicJson(e,t)}lastTeamRegistrationError;onTeamRegistrationFailed(e,t){this.lastTeamRegistrationError={runId:e,error:t,at:this.now()}}registerTeamMembership(e,t){let n=this.teamMembership.readRoot();if(n)return this.teamMembership.register({root:n,role:`subagent`,agent:e.agent,runId:e.runId,childIndex:e.childIndex,fanoutIndex:t,task:{id:e.runId,subject:e.task},pid:process.pid})}readExistingStatus(e){let t=this.readFile(u.join(s.currentRunsDir(),e,`status.json`));if(t!==void 0)try{let e=JSON.parse(t);return f(e)?e:void 0}catch{return}}readLaunchConfig(e){let t=s.currentRunConfigPath(e),n=this.readFile(t);if(n===void 0)throw Error(`No launch config found for run '${e}' at '${t}'.`);let r;try{r=JSON.parse(n)}catch(t){throw Error(`Launch config for run '${e}' is not valid JSON: ${t.message}`)}if(!f(r)||typeof r.runId!=`string`||r.runId!==e)throw Error(`Launch config for run '${e}' is missing or has a mismatched 'runId'.`);return r}bootstrap(e,t){let n=e??this.resolveRunIdFromEnv();if(!n)throw Error(`No run id available: '${i.SUBAGENT_RUN_ID_ENV}' is not set and none was supplied.`);let r;try{r=this.readLaunchConfig(n)}catch(e){throw this.writeHandshake(c.handshakePathFor(n),{state:`error`,error:e instanceof Error?e.message:String(e)}),e}try{let e=this.now(),i=this.readExistingStatus(n),a=i?.fanoutIndex;this.statusWriter.open(n,{...i,version:1,runId:n,agent:r.agent,state:`running`,startedAt:i?.startedAt??e,lastUpdate:e,...t?{sessionFile:t}:{},...a===void 0?{}:{fanoutIndex:a}});let o;try{o=this.registerTeamMembership(r,a)}catch(e){this.onTeamRegistrationFailed(n,e)}return this.terminalPersistence.begin(n,(e,t)=>{this.reporting.mutateTerminalStatus(e,t),o?.dispose()}),this.writeHandshake(r.handshakePath,{state:`ready`}),{runId:n,launchConfig:r,teamContext:o?.context}}catch(e){throw this.writeHandshake(r.handshakePath,{state:`error`,error:e instanceof Error?e.message:String(e)}),e}}};m=t.__decorate([(0,d.injectable)(),o.__decorateParam(0,(0,d.inject)(n.DOOM_TEAM_TYPES.CoalescedStatusWriter)),o.__decorateParam(1,(0,d.inject)(n.DOOM_TEAM_TYPES.TerminalPersistenceService)),o.__decorateParam(2,(0,d.inject)(n.DOOM_TEAM_TYPES.RunnerReporting)),o.__decorateParam(3,(0,d.inject)(n.DOOM_TEAM_TYPES.RunnerTeamMembership)),a.__decorateMetadata(`design:paramtypes`,[Object,Object,Object,Object])],m),Object.defineProperty(exports,`RunnerBootstrap`,{enumerable:!0,get:function(){return m}});
2
+ //# sourceMappingURL=runnerBootstrap.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runnerBootstrap.cjs","names":["SUBAGENT_RUN_ID_ENV","fs","path","currentRunsDir","currentRunConfigPath","handshakePathFor","DOOM_TEAM_TYPES"],"sources":["../../../../src/services/runs/background/runnerBootstrap.ts"],"sourcesContent":["/**\n * The child-side half of the spawn handshake: reads the launch config the\n * parent (`AsyncSubagentSpawner`) wrote, opens this run's status, wires\n * `RunnerReporting`'s finalize callback into `TerminalPersistenceService`,\n * and signals the parent that this process is ready to proceed.\n *\n * \"Nothing works until this exists\" (per the task brief): `SpawnHandshake`\n * on the parent side blocks on exactly the file this class writes at the\n * end of `bootstrap()`.\n *\n * WHY THE RUN ID COMES FROM THE ENVIRONMENT, NOT AN ARGUMENT:\n * `SUBAGENT_RUN_ID_ENV` is already the wire contract `buildPiArgs` encodes a\n * run's id into (see `env.ts`); this process discovers its own identity the\n * same way every other piece of this package's child-side machinery would\n * (`SUBAGENT_CHILD_INDEX_ENV`, etc.), rather than requiring whatever calls\n * `bootstrap()` to already know it and pass it in redundantly. An explicit\n * override is still accepted for tests and for a caller that has a genuine\n * reason to know better.\n *\n * WHY A BOOTSTRAP FAILURE REPORTS THROUGH THE HANDSHAKE'S `error` FIELD\n * ONLY:\n * The predecessor invented a second file (`runner-startup.json`, `state:\n * 'error'`) for exactly this case, which is part of why a reader had to\n * check three separate files to know whether a run was actually finished\n * (see `asyncExecution.ts`'s finalization diagnosis). `SpawnHandshake`\n * already has a vocabulary for this - `{state:'error', error}` at the SAME\n * path it watches for `{state:'ready'}` - so a bootstrap failure uses that,\n * not a parallel channel.\n *\n * WHAT REMAINS UNPROVEN UNTIL `subagentPromptRuntime.ts` LANDS:\n * This class is complete and independently testable, but nothing in this\n * package yet calls it for a real spawned child - that entry point is a\n * separate, concurrent port (see `asyncExecution.ts`'s header). Until then,\n * `bootstrap()`'s only proof of correctness is its own unit tests against\n * the documented contract, not an end-to-end run.\n *\n * TEAM MEMBERSHIP IS ADDITIVE, NEVER FATAL:\n * `bootstrap()` also joins this run's `runId` to the native team as a new\n * member (`RunnerTeamMembership`), when the parent forwarded a team root\n * (see `asyncExecution.ts`'s TEAM MEMBERSHIP ENV FORWARDING section) - a\n * child that cannot be messaged, asked, or seen on the shared task board by\n * its siblings is a real gap, but it is not a reason to fail the run itself.\n * A registration failure is recorded (`onTeamRegistrationFailed`), not\n * thrown, and everything else proceeds exactly as if no team root had been\n * present at all.\n *\n * DISPOSAL RIDES THE ONE FINALIZE PATH, NOT A SECOND ONE:\n * The registration's `dispose()` is called from inside the SAME callback\n * passed to `terminalPersistence.begin()` that `RunnerReporting` already\n * owns, immediately after `mutateTerminalStatus` - not from a second,\n * independent cleanup site. `TerminalPersistenceService`'s own `finalized`\n * boolean is still the only thing deciding whether that callback runs at\n * all, so a child that finalizes for any reason (completion, signal,\n * uncaught exception) also leaves the team exactly once, for the same\n * reason there is exactly one finalize.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { inject, injectable } from 'inversify';\nimport { SUBAGENT_RUN_ID_ENV } from '../../../adapters/process/env.ts';\nimport { DOOM_TEAM_TYPES } from '../../../container/types.ts';\nimport { writeAtomicJson } from '../../../shared/atomicJson.ts';\nimport { currentRunConfigPath, currentRunsDir } from '../../../shared/paths.ts';\nimport type { TeamMemberContext } from '../../intercom/nativeTeamChannel.ts';\nimport { type AsyncRunStatus, handshakePathFor, type LaunchConfig } from './asyncExecution.ts';\nimport type { IRunnerReporting } from './runnerReporting.ts';\nimport type { IRunnerTeamMembership, RunnerTeamRegistration } from './runnerTeamMembership.ts';\nimport { type ICoalescedStatusWriter } from './statusWriter.ts';\nimport type { ITerminalPersistenceService } from './terminalPersistence.ts';\n\nconst STATUS_FILE_NAME = 'status.json';\n\nexport type RunnerLaunchConfig = LaunchConfig;\n\nexport interface RunnerBootstrapResult {\n runId: string;\n launchConfig: RunnerLaunchConfig;\n /** This run's own bound team membership, when it joined one. Same instance `registerTeamMembership` already holds. */\n teamContext: TeamMemberContext | undefined;\n}\n\nexport interface IRunnerBootstrap {\n /**\n * Read the launch config, open status, wire finalize, and signal ready.\n * Throws (after writing an error handshake) on any failure to reach that\n * point - a bootstrap that cannot even establish this run's identity has\n * nothing else it can safely do.\n */\n bootstrap(runId?: string, sessionFile?: string): RunnerBootstrapResult;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return typeof error === 'object' && error !== null && 'code' in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\n@injectable()\nexport class RunnerBootstrap implements IRunnerBootstrap {\n constructor(\n @inject(DOOM_TEAM_TYPES.CoalescedStatusWriter)\n private readonly statusWriter: ICoalescedStatusWriter<AsyncRunStatus>,\n @inject(DOOM_TEAM_TYPES.TerminalPersistenceService)\n private readonly terminalPersistence: ITerminalPersistenceService<AsyncRunStatus>,\n @inject(DOOM_TEAM_TYPES.RunnerReporting) private readonly reporting: IRunnerReporting,\n @inject(DOOM_TEAM_TYPES.RunnerTeamMembership) private readonly teamMembership: IRunnerTeamMembership,\n ) {}\n\n protected now(): number {\n return Date.now();\n }\n\n protected resolveRunIdFromEnv(): string | undefined {\n const value = process.env[SUBAGENT_RUN_ID_ENV];\n return value?.trim() ? value : undefined;\n }\n\n protected readFile(filePath: string): string | undefined {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch (error) {\n if (errorCode(error) === 'ENOENT') return undefined;\n throw error;\n }\n }\n\n protected writeHandshake(filePath: string, payload: { state: 'ready' } | { state: 'error'; error: string }): void {\n writeAtomicJson(filePath, payload);\n }\n\n /** Recorded, not thrown - see the module header's TEAM MEMBERSHIP IS ADDITIVE section. */\n lastTeamRegistrationError: { runId: string; error: unknown; at: number } | undefined;\n\n protected onTeamRegistrationFailed(runId: string, error: unknown): void {\n this.lastTeamRegistrationError = { runId, error, at: this.now() };\n }\n\n /**\n * Join the native team as a new member for this run, if the parent\n * forwarded a team root. `undefined` when this run is not part of a team\n * - a silent no-op, not a failure (see `asyncExecution.ts`'s TEAM\n * MEMBERSHIP ENV FORWARDING section).\n */\n protected registerTeamMembership(\n launchConfig: RunnerLaunchConfig,\n fanoutIndex: number | undefined,\n ): RunnerTeamRegistration | undefined {\n const root = this.teamMembership.readRoot();\n if (!root) return undefined;\n return this.teamMembership.register({\n root,\n role: 'subagent',\n agent: launchConfig.agent,\n runId: launchConfig.runId,\n childIndex: launchConfig.childIndex,\n // Only a fan-out child gets a `-N` suffix on its member name; a\n // standalone run has no sibling to disambiguate against.\n fanoutIndex,\n task: { id: launchConfig.runId, subject: launchConfig.task },\n pid: process.pid,\n });\n }\n\n protected readExistingStatus(runId: string): AsyncRunStatus | undefined {\n // Best-effort: the parent already wrote an initial status.json for this\n // run (`AsyncSubagentSpawner.spawn()`); reading it back preserves\n // parent-decided fields (`fanoutIndex`) rather than this process\n // reconstructing them from nothing.\n const raw = this.readFile(path.join(currentRunsDir(), runId, STATUS_FILE_NAME));\n if (raw === undefined) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? (parsed as unknown as AsyncRunStatus) : undefined;\n } catch {\n return undefined;\n }\n }\n\n private readLaunchConfig(runId: string): RunnerLaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const raw = this.readFile(configPath);\n if (raw === undefined) {\n throw new Error(`No launch config found for run '${runId}' at '${configPath}'.`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(`Launch config for run '${runId}' is not valid JSON: ${(error as Error).message}`);\n }\n if (!isRecord(parsed) || typeof parsed.runId !== 'string' || parsed.runId !== runId) {\n throw new Error(`Launch config for run '${runId}' is missing or has a mismatched 'runId'.`);\n }\n return parsed as unknown as RunnerLaunchConfig;\n }\n\n bootstrap(runId?: string, sessionFile?: string): RunnerBootstrapResult {\n const resolvedRunId = runId ?? this.resolveRunIdFromEnv();\n if (!resolvedRunId) {\n // Nothing identifies this run yet, so there is no handshake path to\n // write an error to either; this can only surface as a thrown error.\n throw new Error(`No run id available: '${SUBAGENT_RUN_ID_ENV}' is not set and none was supplied.`);\n }\n\n let launchConfig: RunnerLaunchConfig;\n try {\n launchConfig = this.readLaunchConfig(resolvedRunId);\n } catch (error) {\n this.writeHandshake(handshakePathFor(resolvedRunId), {\n state: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n\n try {\n const now = this.now();\n const existing = this.readExistingStatus(resolvedRunId);\n const fanoutIndex = existing?.fanoutIndex;\n this.statusWriter.open(resolvedRunId, {\n ...existing,\n version: 1,\n runId: resolvedRunId,\n agent: launchConfig.agent,\n state: 'running',\n startedAt: existing?.startedAt ?? now,\n lastUpdate: now,\n ...(sessionFile ? { sessionFile } : {}),\n ...(fanoutIndex === undefined ? {} : { fanoutIndex }),\n });\n\n let teamRegistration: RunnerTeamRegistration | undefined;\n try {\n teamRegistration = this.registerTeamMembership(launchConfig, fanoutIndex);\n } catch (error) {\n // Additive, never fatal - see the module header's TEAM MEMBERSHIP\n // IS ADDITIVE section.\n this.onTeamRegistrationFailed(resolvedRunId, error);\n }\n\n this.terminalPersistence.begin(resolvedRunId, (status, trigger) => {\n this.reporting.mutateTerminalStatus(status, trigger);\n // Disposal rides this SAME callback, not a second cleanup site - see\n // the module header's DISPOSAL RIDES THE ONE FINALIZE PATH section.\n teamRegistration?.dispose();\n });\n\n this.writeHandshake(launchConfig.handshakePath, { state: 'ready' });\n\n return {\n runId: resolvedRunId,\n launchConfig,\n teamContext: teamRegistration?.context,\n };\n } catch (error) {\n this.writeHandshake(launchConfig.handshakePath, {\n state: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{__decorate as t,init_decorate as n}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs";import{DOOM_TEAM_TYPES as r,init_types as i}from"../../../container/types.mjs";import{writeAtomicJson as a}from"../../../adapters/atomicJson.mjs";import{init_atomicJson as o}from"../../../shared/atomicJson.mjs";import{SUBAGENT_RUN_ID_ENV as s,init_env as c}from"../../../adapters/process/env.mjs";import{__decorateMetadata as l,init_decorateMetadata as u}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.mjs";import{__decorateParam as d,init_decorateParam as f}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.mjs";import{currentRunConfigPath as p,currentRunsDir as m,init_paths as h}from"../../../shared/paths.mjs";import{handshakePathFor as g,init_asyncExecution as _}from"./asyncExecution.mjs";import*as v from"node:fs";import*as y from"node:path";import{inject as b,injectable as x}from"inversify";function S(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function C(e){return typeof e==`object`&&e&&`code`in e?e.code:void 0}var w,T,E=e((()=>{c(),i(),o(),h(),_(),u(),f(),n(),w=`status.json`,T=class{constructor(e,t,n,r){this.statusWriter=e,this.terminalPersistence=t,this.reporting=n,this.teamMembership=r}now(){return Date.now()}resolveRunIdFromEnv(){let e=process.env[s];return e?.trim()?e:void 0}readFile(e){try{return v.readFileSync(e,`utf-8`)}catch(e){if(C(e)===`ENOENT`)return;throw e}}writeHandshake(e,t){a(e,t)}lastTeamRegistrationError;onTeamRegistrationFailed(e,t){this.lastTeamRegistrationError={runId:e,error:t,at:this.now()}}registerTeamMembership(e,t){let n=this.teamMembership.readRoot();if(n)return this.teamMembership.register({root:n,role:`subagent`,agent:e.agent,runId:e.runId,childIndex:e.childIndex,fanoutIndex:t,task:{id:e.runId,subject:e.task},pid:process.pid})}readExistingStatus(e){let t=this.readFile(y.join(m(),e,w));if(t!==void 0)try{let e=JSON.parse(t);return S(e)?e:void 0}catch{return}}readLaunchConfig(e){let t=p(e),n=this.readFile(t);if(n===void 0)throw Error(`No launch config found for run '${e}' at '${t}'.`);let r;try{r=JSON.parse(n)}catch(t){throw Error(`Launch config for run '${e}' is not valid JSON: ${t.message}`)}if(!S(r)||typeof r.runId!=`string`||r.runId!==e)throw Error(`Launch config for run '${e}' is missing or has a mismatched 'runId'.`);return r}bootstrap(e,t){let n=e??this.resolveRunIdFromEnv();if(!n)throw Error(`No run id available: '${s}' is not set and none was supplied.`);let r;try{r=this.readLaunchConfig(n)}catch(e){throw this.writeHandshake(g(n),{state:`error`,error:e instanceof Error?e.message:String(e)}),e}try{let e=this.now(),i=this.readExistingStatus(n),a=i?.fanoutIndex;this.statusWriter.open(n,{...i,version:1,runId:n,agent:r.agent,state:`running`,startedAt:i?.startedAt??e,lastUpdate:e,...t?{sessionFile:t}:{},...a===void 0?{}:{fanoutIndex:a}});let o;try{o=this.registerTeamMembership(r,a)}catch(e){this.onTeamRegistrationFailed(n,e)}return this.terminalPersistence.begin(n,(e,t)=>{this.reporting.mutateTerminalStatus(e,t),o?.dispose()}),this.writeHandshake(r.handshakePath,{state:`ready`}),{runId:n,launchConfig:r,teamContext:o?.context}}catch(e){throw this.writeHandshake(r.handshakePath,{state:`error`,error:e instanceof Error?e.message:String(e)}),e}}},T=t([x(),d(0,b(r.CoalescedStatusWriter)),d(1,b(r.TerminalPersistenceService)),d(2,b(r.RunnerReporting)),d(3,b(r.RunnerTeamMembership)),l(`design:paramtypes`,[Object,Object,Object,Object])],T)}));E();export{T as RunnerBootstrap,E as init_runnerBootstrap};
2
+ //# sourceMappingURL=runnerBootstrap.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runnerBootstrap.mjs","names":[],"sources":["../../../../src/services/runs/background/runnerBootstrap.ts"],"sourcesContent":["/**\n * The child-side half of the spawn handshake: reads the launch config the\n * parent (`AsyncSubagentSpawner`) wrote, opens this run's status, wires\n * `RunnerReporting`'s finalize callback into `TerminalPersistenceService`,\n * and signals the parent that this process is ready to proceed.\n *\n * \"Nothing works until this exists\" (per the task brief): `SpawnHandshake`\n * on the parent side blocks on exactly the file this class writes at the\n * end of `bootstrap()`.\n *\n * WHY THE RUN ID COMES FROM THE ENVIRONMENT, NOT AN ARGUMENT:\n * `SUBAGENT_RUN_ID_ENV` is already the wire contract `buildPiArgs` encodes a\n * run's id into (see `env.ts`); this process discovers its own identity the\n * same way every other piece of this package's child-side machinery would\n * (`SUBAGENT_CHILD_INDEX_ENV`, etc.), rather than requiring whatever calls\n * `bootstrap()` to already know it and pass it in redundantly. An explicit\n * override is still accepted for tests and for a caller that has a genuine\n * reason to know better.\n *\n * WHY A BOOTSTRAP FAILURE REPORTS THROUGH THE HANDSHAKE'S `error` FIELD\n * ONLY:\n * The predecessor invented a second file (`runner-startup.json`, `state:\n * 'error'`) for exactly this case, which is part of why a reader had to\n * check three separate files to know whether a run was actually finished\n * (see `asyncExecution.ts`'s finalization diagnosis). `SpawnHandshake`\n * already has a vocabulary for this - `{state:'error', error}` at the SAME\n * path it watches for `{state:'ready'}` - so a bootstrap failure uses that,\n * not a parallel channel.\n *\n * WHAT REMAINS UNPROVEN UNTIL `subagentPromptRuntime.ts` LANDS:\n * This class is complete and independently testable, but nothing in this\n * package yet calls it for a real spawned child - that entry point is a\n * separate, concurrent port (see `asyncExecution.ts`'s header). Until then,\n * `bootstrap()`'s only proof of correctness is its own unit tests against\n * the documented contract, not an end-to-end run.\n *\n * TEAM MEMBERSHIP IS ADDITIVE, NEVER FATAL:\n * `bootstrap()` also joins this run's `runId` to the native team as a new\n * member (`RunnerTeamMembership`), when the parent forwarded a team root\n * (see `asyncExecution.ts`'s TEAM MEMBERSHIP ENV FORWARDING section) - a\n * child that cannot be messaged, asked, or seen on the shared task board by\n * its siblings is a real gap, but it is not a reason to fail the run itself.\n * A registration failure is recorded (`onTeamRegistrationFailed`), not\n * thrown, and everything else proceeds exactly as if no team root had been\n * present at all.\n *\n * DISPOSAL RIDES THE ONE FINALIZE PATH, NOT A SECOND ONE:\n * The registration's `dispose()` is called from inside the SAME callback\n * passed to `terminalPersistence.begin()` that `RunnerReporting` already\n * owns, immediately after `mutateTerminalStatus` - not from a second,\n * independent cleanup site. `TerminalPersistenceService`'s own `finalized`\n * boolean is still the only thing deciding whether that callback runs at\n * all, so a child that finalizes for any reason (completion, signal,\n * uncaught exception) also leaves the team exactly once, for the same\n * reason there is exactly one finalize.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { inject, injectable } from 'inversify';\nimport { SUBAGENT_RUN_ID_ENV } from '../../../adapters/process/env.ts';\nimport { DOOM_TEAM_TYPES } from '../../../container/types.ts';\nimport { writeAtomicJson } from '../../../shared/atomicJson.ts';\nimport { currentRunConfigPath, currentRunsDir } from '../../../shared/paths.ts';\nimport type { TeamMemberContext } from '../../intercom/nativeTeamChannel.ts';\nimport { type AsyncRunStatus, handshakePathFor, type LaunchConfig } from './asyncExecution.ts';\nimport type { IRunnerReporting } from './runnerReporting.ts';\nimport type { IRunnerTeamMembership, RunnerTeamRegistration } from './runnerTeamMembership.ts';\nimport { type ICoalescedStatusWriter } from './statusWriter.ts';\nimport type { ITerminalPersistenceService } from './terminalPersistence.ts';\n\nconst STATUS_FILE_NAME = 'status.json';\n\nexport type RunnerLaunchConfig = LaunchConfig;\n\nexport interface RunnerBootstrapResult {\n runId: string;\n launchConfig: RunnerLaunchConfig;\n /** This run's own bound team membership, when it joined one. Same instance `registerTeamMembership` already holds. */\n teamContext: TeamMemberContext | undefined;\n}\n\nexport interface IRunnerBootstrap {\n /**\n * Read the launch config, open status, wire finalize, and signal ready.\n * Throws (after writing an error handshake) on any failure to reach that\n * point - a bootstrap that cannot even establish this run's identity has\n * nothing else it can safely do.\n */\n bootstrap(runId?: string, sessionFile?: string): RunnerBootstrapResult;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return typeof error === 'object' && error !== null && 'code' in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\n@injectable()\nexport class RunnerBootstrap implements IRunnerBootstrap {\n constructor(\n @inject(DOOM_TEAM_TYPES.CoalescedStatusWriter)\n private readonly statusWriter: ICoalescedStatusWriter<AsyncRunStatus>,\n @inject(DOOM_TEAM_TYPES.TerminalPersistenceService)\n private readonly terminalPersistence: ITerminalPersistenceService<AsyncRunStatus>,\n @inject(DOOM_TEAM_TYPES.RunnerReporting) private readonly reporting: IRunnerReporting,\n @inject(DOOM_TEAM_TYPES.RunnerTeamMembership) private readonly teamMembership: IRunnerTeamMembership,\n ) {}\n\n protected now(): number {\n return Date.now();\n }\n\n protected resolveRunIdFromEnv(): string | undefined {\n const value = process.env[SUBAGENT_RUN_ID_ENV];\n return value?.trim() ? value : undefined;\n }\n\n protected readFile(filePath: string): string | undefined {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch (error) {\n if (errorCode(error) === 'ENOENT') return undefined;\n throw error;\n }\n }\n\n protected writeHandshake(filePath: string, payload: { state: 'ready' } | { state: 'error'; error: string }): void {\n writeAtomicJson(filePath, payload);\n }\n\n /** Recorded, not thrown - see the module header's TEAM MEMBERSHIP IS ADDITIVE section. */\n lastTeamRegistrationError: { runId: string; error: unknown; at: number } | undefined;\n\n protected onTeamRegistrationFailed(runId: string, error: unknown): void {\n this.lastTeamRegistrationError = { runId, error, at: this.now() };\n }\n\n /**\n * Join the native team as a new member for this run, if the parent\n * forwarded a team root. `undefined` when this run is not part of a team\n * - a silent no-op, not a failure (see `asyncExecution.ts`'s TEAM\n * MEMBERSHIP ENV FORWARDING section).\n */\n protected registerTeamMembership(\n launchConfig: RunnerLaunchConfig,\n fanoutIndex: number | undefined,\n ): RunnerTeamRegistration | undefined {\n const root = this.teamMembership.readRoot();\n if (!root) return undefined;\n return this.teamMembership.register({\n root,\n role: 'subagent',\n agent: launchConfig.agent,\n runId: launchConfig.runId,\n childIndex: launchConfig.childIndex,\n // Only a fan-out child gets a `-N` suffix on its member name; a\n // standalone run has no sibling to disambiguate against.\n fanoutIndex,\n task: { id: launchConfig.runId, subject: launchConfig.task },\n pid: process.pid,\n });\n }\n\n protected readExistingStatus(runId: string): AsyncRunStatus | undefined {\n // Best-effort: the parent already wrote an initial status.json for this\n // run (`AsyncSubagentSpawner.spawn()`); reading it back preserves\n // parent-decided fields (`fanoutIndex`) rather than this process\n // reconstructing them from nothing.\n const raw = this.readFile(path.join(currentRunsDir(), runId, STATUS_FILE_NAME));\n if (raw === undefined) return undefined;\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? (parsed as unknown as AsyncRunStatus) : undefined;\n } catch {\n return undefined;\n }\n }\n\n private readLaunchConfig(runId: string): RunnerLaunchConfig {\n const configPath = currentRunConfigPath(runId);\n const raw = this.readFile(configPath);\n if (raw === undefined) {\n throw new Error(`No launch config found for run '${runId}' at '${configPath}'.`);\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n throw new Error(`Launch config for run '${runId}' is not valid JSON: ${(error as Error).message}`);\n }\n if (!isRecord(parsed) || typeof parsed.runId !== 'string' || parsed.runId !== runId) {\n throw new Error(`Launch config for run '${runId}' is missing or has a mismatched 'runId'.`);\n }\n return parsed as unknown as RunnerLaunchConfig;\n }\n\n bootstrap(runId?: string, sessionFile?: string): RunnerBootstrapResult {\n const resolvedRunId = runId ?? this.resolveRunIdFromEnv();\n if (!resolvedRunId) {\n // Nothing identifies this run yet, so there is no handshake path to\n // write an error to either; this can only surface as a thrown error.\n throw new Error(`No run id available: '${SUBAGENT_RUN_ID_ENV}' is not set and none was supplied.`);\n }\n\n let launchConfig: RunnerLaunchConfig;\n try {\n launchConfig = this.readLaunchConfig(resolvedRunId);\n } catch (error) {\n this.writeHandshake(handshakePathFor(resolvedRunId), {\n state: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n\n try {\n const now = this.now();\n const existing = this.readExistingStatus(resolvedRunId);\n const fanoutIndex = existing?.fanoutIndex;\n this.statusWriter.open(resolvedRunId, {\n ...existing,\n version: 1,\n runId: resolvedRunId,\n agent: launchConfig.agent,\n state: 'running',\n startedAt: existing?.startedAt ?? now,\n lastUpdate: now,\n ...(sessionFile ? { sessionFile } : {}),\n ...(fanoutIndex === undefined ? {} : { fanoutIndex }),\n });\n\n let teamRegistration: RunnerTeamRegistration | undefined;\n try {\n teamRegistration = this.registerTeamMembership(launchConfig, fanoutIndex);\n } catch (error) {\n // Additive, never fatal - see the module header's TEAM MEMBERSHIP\n // IS ADDITIVE section.\n this.onTeamRegistrationFailed(resolvedRunId, error);\n }\n\n this.terminalPersistence.begin(resolvedRunId, (status, trigger) => {\n this.reporting.mutateTerminalStatus(status, trigger);\n // Disposal rides this SAME callback, not a second cleanup site - see\n // the module header's DISPOSAL RIDES THE ONE FINALIZE PATH section.\n teamRegistration?.dispose();\n });\n\n this.writeHandshake(launchConfig.handshakePath, { state: 'ready' });\n\n return {\n runId: resolvedRunId,\n launchConfig,\n teamContext: teamRegistration?.context,\n };\n } catch (error) {\n this.writeHandshake(launchConfig.handshakePath, {\n state: 'error',\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ require(`../../../_virtual/_rolldown/runtime.cjs`);const e=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),t=require(`../../../container/types.cjs`),n=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),r=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),i=require(`./asyncExecution.cjs`);let a=require(`inversify`),o=class{constructor(e,t,n,r){this.controlChannel=e,this.terminalPersistence=t,this.reporting=n,this.statusWriter=r}exitProcess(e){process.exit(e)}start(e,t={}){let n={onInterrupt:()=>this.interrupt(),onStop:()=>this.stop(),onTimeout:()=>this.timeout(),...t.onSteer?{onSteer:t.onSteer}:{}};return this.controlChannel.watch(i.runDirFor(e),n)}setActivity(e){this.statusWriter.update(t=>{t.activityState=e,t.lastUpdate=Date.now()})}setProgress(e){e.tokens===void 0&&e.currentTool===void 0&&e.toolCount===void 0||this.statusWriter.update(t=>{e.tokens!==void 0&&(t.tokens=e.tokens),e.currentTool!==void 0&&(t.currentTool=e.currentTool),e.toolCount!==void 0&&(t.toolCount=e.toolCount),t.lastUpdate=Date.now()})}complete(e,t){this.reporting.prepareResult({success:e,summary:t}),this.terminalPersistence.finalize()}interrupt(){this.reporting.prepareResult({success:!1,summary:`Interrupted before completion.`}),this.terminalPersistence.finalize()}stop(){this.reporting.prepareResult({success:!1,state:`stopped`,summary:`Stopped before completion.`});try{this.terminalPersistence.finalize()}finally{this.exitProcess(0)}}timeout(){this.reporting.prepareResult({success:!1,summary:`Timed out before completion.`}),this.terminalPersistence.finalize()}};o=e.__decorate([(0,a.injectable)(),r.__decorateParam(0,(0,a.inject)(t.DOOM_TEAM_TYPES.ControlChannelWatcher)),r.__decorateParam(1,(0,a.inject)(t.DOOM_TEAM_TYPES.TerminalPersistenceService)),r.__decorateParam(2,(0,a.inject)(t.DOOM_TEAM_TYPES.RunnerReporting)),r.__decorateParam(3,(0,a.inject)(t.DOOM_TEAM_TYPES.CoalescedStatusWriter)),n.__decorateMetadata(`design:paramtypes`,[Object,Object,Object,Object])],o),Object.defineProperty(exports,`RunnerExecution`,{enumerable:!0,get:function(){return o}});
2
+ //# sourceMappingURL=runnerExecution.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runnerExecution.cjs","names":["runDirFor","DOOM_TEAM_TYPES"],"sources":["../../../../src/services/runs/background/runnerExecution.ts"],"sourcesContent":["/**\n * The \"while running\" glue: consumes steer/interrupt/timeout/stop requests\n * via `ControlChannelWatcher`, and is the ONE place every terminal trigger\n * (interrupt/stop/timeout, and normal completion) funnels through\n * `TerminalPersistenceService.finalize()`.\n *\n * WHY EVERY TRIGGER CALLS THE SAME `finalize()`, INSTEAD OF EACH DOING ITS\n * OWN THING:\n * The predecessor's `interruptRunner`/`stopRunner`/`timeoutRunner` and its\n * post-loop completion tail each independently computed terminal state and\n * independently wrote it - four triggers, four write sites, each guarded\n * only by a LOCAL boolean that stopped re-entry of THAT SAME handler, none\n * of them aware of the others (see `asyncExecution.ts`'s header for the\n * full diagnosis, including why that made a stray control event able to\n * race the completion tail). Here, `interrupt()`/`stop()`/`timeout()`/\n * `complete()` each do exactly two things: record the outcome via\n * `reporting.prepareResult()`, then call `terminalPersistence.finalize()`.\n * `TerminalPersistenceService`'s own `finalized` boolean, checked and set\n * before anything else runs, is the ONLY thing that decides whether a given\n * call actually does anything. No new idempotency logic is added here -\n * every trigger is made to go through the one that already exists, rather\n * than rolling its own.\n *\n * WHY INTERRUPT/STOP/TIMEOUT EACH STILL CALL `prepareResult()`:\n * `RunnerReporting.mutateTerminalStatus`'s fallback derives a correct\n * outcome from `trigger` for real OS signals/exceptions - but interrupt/\n * stop/timeout are NOT `TerminalTrigger` values (those are this run's own\n * request-driven terminal reasons, not the signals/exceptions\n * `TerminalPersistenceService` itself watches for), and `finalize()` always\n * calls `mutateTerminalStatus` with `trigger === undefined` regardless of\n * WHY this class decided to call it. So each of `interrupt()`/`stop()`/\n * `timeout()` prepares its own result before calling `finalize()`, the same\n * as `complete()` does - `mutateTerminalStatus` cannot otherwise tell\n * interrupt apart from stop apart from normal completion.\n *\n */\n\nimport { inject, injectable } from 'inversify';\n\nimport { DOOM_TEAM_TYPES } from '../../../container/types.ts';\nimport type { ActivityState } from '../../../types/index.ts';\nimport type {\n ControlChannelWatchHandlers,\n IControlChannelWatcher,\n SteerRequest,\n} from '../../intercom/supervisorControlChannel.ts';\nimport type { AsyncRunStatus } from './asyncExecution.ts';\nimport { runDirFor } from './asyncExecution.ts';\nimport type { IRunnerReporting } from './runnerReporting.ts';\nimport type { ICoalescedStatusWriter } from './statusWriter.ts';\nimport type { ITerminalPersistenceService } from './terminalPersistence.ts';\n\nexport interface RunnerExecutionHandlers {\n /** Forwarded steer requests, for whatever delivers them to the running step (not this class's job). */\n onSteer?: (request: SteerRequest) => void;\n}\n\nexport interface RunnerProgress {\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nexport interface IRunnerExecution {\n /**\n * Start watching this run's control inbox and consuming any chain-append\n * requests already waiting. Returns a disposer that stops watching\n * without finalizing (used on a clean, already-finalized exit).\n */\n start(runId: string, handlers?: RunnerExecutionHandlers): () => void;\n /** Record a material, event-driven activity transition. */\n setActivity(activity: ActivityState): void;\n /** Record live child metrics in one coalesced status update. */\n setProgress(progress: RunnerProgress): void;\n /** This run finished normally. Idempotent via `TerminalPersistenceService`. */\n complete(success: boolean, summary: string): void;\n}\n\n@injectable()\nexport class RunnerExecution implements IRunnerExecution {\n constructor(\n @inject(DOOM_TEAM_TYPES.ControlChannelWatcher) private readonly controlChannel: IControlChannelWatcher,\n @inject(DOOM_TEAM_TYPES.TerminalPersistenceService)\n private readonly terminalPersistence: ITerminalPersistenceService<AsyncRunStatus>,\n @inject(DOOM_TEAM_TYPES.RunnerReporting) private readonly reporting: IRunnerReporting,\n @inject(DOOM_TEAM_TYPES.CoalescedStatusWriter)\n private readonly statusWriter: ICoalescedStatusWriter<AsyncRunStatus>,\n ) {}\n\n /** Dedicated runner processes own exactly one session, so a stop may exit after synchronous persistence. */\n protected exitProcess(code: number): void {\n process.exit(code);\n }\n\n start(runId: string, handlers: RunnerExecutionHandlers = {}): () => void {\n const controlHandlers: ControlChannelWatchHandlers = {\n onInterrupt: () => this.interrupt(),\n onStop: () => this.stop(),\n onTimeout: () => this.timeout(),\n ...(handlers.onSteer ? { onSteer: handlers.onSteer } : {}),\n };\n return this.controlChannel.watch(runDirFor(runId), controlHandlers);\n }\n\n setActivity(activity: ActivityState): void {\n this.statusWriter.update((status) => {\n status.activityState = activity;\n status.lastUpdate = Date.now();\n });\n }\n\n setProgress(progress: RunnerProgress): void {\n if (progress.tokens === undefined && progress.currentTool === undefined && progress.toolCount === undefined) {\n return;\n }\n this.statusWriter.update((status) => {\n if (progress.tokens !== undefined) status.tokens = progress.tokens;\n if (progress.currentTool !== undefined) status.currentTool = progress.currentTool;\n if (progress.toolCount !== undefined) status.toolCount = progress.toolCount;\n status.lastUpdate = Date.now();\n });\n }\n\n complete(success: boolean, summary: string): void {\n this.reporting.prepareResult({ success, summary });\n this.terminalPersistence.finalize();\n }\n\n interrupt(): void {\n this.reporting.prepareResult({ success: false, summary: 'Interrupted before completion.' });\n this.terminalPersistence.finalize();\n }\n\n stop(): void {\n this.reporting.prepareResult({ success: false, state: 'stopped', summary: 'Stopped before completion.' });\n try {\n this.terminalPersistence.finalize();\n } finally {\n this.exitProcess(0);\n }\n }\n\n timeout(): void {\n this.reporting.prepareResult({ success: false, summary: 'Timed out before completion.' });\n this.terminalPersistence.finalize();\n }\n}\n"],"mappings":"maA+EO,EAAA,KAAkD,CACvD,YACE,EACA,EAEA,EACA,EAEA,CANgE,KAAA,eAAA,EAE/C,KAAA,oBAAA,EACyC,KAAA,UAAA,EAEzC,KAAA,aAAA,EAInB,YAAsB,EAAoB,CACxC,QAAQ,KAAK,EAAK,CAGpB,MAAM,EAAe,EAAoC,EAAE,CAAc,CACvE,IAAM,EAA+C,CACnD,gBAAmB,KAAK,WAAW,CACnC,WAAc,KAAK,MAAM,CACzB,cAAiB,KAAK,SAAS,CAC/B,GAAI,EAAS,QAAU,CAAE,QAAS,EAAS,QAAS,CAAG,EAAE,CAC1D,CACD,OAAO,KAAK,eAAe,MAAMA,EAAAA,UAAU,EAAM,CAAE,EAAgB,CAGrE,YAAY,EAA+B,CACzC,KAAK,aAAa,OAAQ,GAAW,CACnC,EAAO,cAAgB,EACvB,EAAO,WAAa,KAAK,KAAK,EAC9B,CAGJ,YAAY,EAAgC,CACtC,EAAS,SAAW,IAAA,IAAa,EAAS,cAAgB,IAAA,IAAa,EAAS,YAAc,IAAA,IAGlG,KAAK,aAAa,OAAQ,GAAW,CAC/B,EAAS,SAAW,IAAA,KAAW,EAAO,OAAS,EAAS,QACxD,EAAS,cAAgB,IAAA,KAAW,EAAO,YAAc,EAAS,aAClE,EAAS,YAAc,IAAA,KAAW,EAAO,UAAY,EAAS,WAClE,EAAO,WAAa,KAAK,KAAK,EAC9B,CAGJ,SAAS,EAAkB,EAAuB,CAChD,KAAK,UAAU,cAAc,CAAE,UAAS,UAAS,CAAC,CAClD,KAAK,oBAAoB,UAAU,CAGrC,WAAkB,CAChB,KAAK,UAAU,cAAc,CAAE,QAAS,GAAO,QAAS,iCAAkC,CAAC,CAC3F,KAAK,oBAAoB,UAAU,CAGrC,MAAa,CACX,KAAK,UAAU,cAAc,CAAE,QAAS,GAAO,MAAO,UAAW,QAAS,6BAA8B,CAAC,CACzG,GAAI,CACF,KAAK,oBAAoB,UAAU,QAC3B,CACR,KAAK,YAAY,EAAE,EAIvB,SAAgB,CACd,KAAK,UAAU,cAAc,CAAE,QAAS,GAAO,QAAS,+BAAgC,CAAC,CACzF,KAAK,oBAAoB,UAAU,qCAlE1B,kCAGDC,EAAAA,gBAAgB,sBAAsB,CAAA,kCACtCA,EAAAA,gBAAgB,2BAA2B,CAAA,kCAE3CA,EAAAA,gBAAgB,gBAAgB,CAAA,kCAChCA,EAAAA,gBAAgB,sBAAsB,CAAA"}
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{__decorate as t,init_decorate as n}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs";import{DOOM_TEAM_TYPES as r,init_types as i}from"../../../container/types.mjs";import{__decorateMetadata as a,init_decorateMetadata as o}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.mjs";import{__decorateParam as s,init_decorateParam as c}from"../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.mjs";import{init_asyncExecution as l,runDirFor as u}from"./asyncExecution.mjs";import{inject as d,injectable as f}from"inversify";var p,m=e((()=>{i(),l(),o(),c(),n(),p=class{constructor(e,t,n,r){this.controlChannel=e,this.terminalPersistence=t,this.reporting=n,this.statusWriter=r}exitProcess(e){process.exit(e)}start(e,t={}){let n={onInterrupt:()=>this.interrupt(),onStop:()=>this.stop(),onTimeout:()=>this.timeout(),...t.onSteer?{onSteer:t.onSteer}:{}};return this.controlChannel.watch(u(e),n)}setActivity(e){this.statusWriter.update(t=>{t.activityState=e,t.lastUpdate=Date.now()})}setProgress(e){e.tokens===void 0&&e.currentTool===void 0&&e.toolCount===void 0||this.statusWriter.update(t=>{e.tokens!==void 0&&(t.tokens=e.tokens),e.currentTool!==void 0&&(t.currentTool=e.currentTool),e.toolCount!==void 0&&(t.toolCount=e.toolCount),t.lastUpdate=Date.now()})}complete(e,t){this.reporting.prepareResult({success:e,summary:t}),this.terminalPersistence.finalize()}interrupt(){this.reporting.prepareResult({success:!1,summary:`Interrupted before completion.`}),this.terminalPersistence.finalize()}stop(){this.reporting.prepareResult({success:!1,state:`stopped`,summary:`Stopped before completion.`});try{this.terminalPersistence.finalize()}finally{this.exitProcess(0)}}timeout(){this.reporting.prepareResult({success:!1,summary:`Timed out before completion.`}),this.terminalPersistence.finalize()}},p=t([f(),s(0,d(r.ControlChannelWatcher)),s(1,d(r.TerminalPersistenceService)),s(2,d(r.RunnerReporting)),s(3,d(r.CoalescedStatusWriter)),a(`design:paramtypes`,[Object,Object,Object,Object])],p)}));m();export{p as RunnerExecution,m as init_runnerExecution};
2
+ //# sourceMappingURL=runnerExecution.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runnerExecution.mjs","names":[],"sources":["../../../../src/services/runs/background/runnerExecution.ts"],"sourcesContent":["/**\n * The \"while running\" glue: consumes steer/interrupt/timeout/stop requests\n * via `ControlChannelWatcher`, and is the ONE place every terminal trigger\n * (interrupt/stop/timeout, and normal completion) funnels through\n * `TerminalPersistenceService.finalize()`.\n *\n * WHY EVERY TRIGGER CALLS THE SAME `finalize()`, INSTEAD OF EACH DOING ITS\n * OWN THING:\n * The predecessor's `interruptRunner`/`stopRunner`/`timeoutRunner` and its\n * post-loop completion tail each independently computed terminal state and\n * independently wrote it - four triggers, four write sites, each guarded\n * only by a LOCAL boolean that stopped re-entry of THAT SAME handler, none\n * of them aware of the others (see `asyncExecution.ts`'s header for the\n * full diagnosis, including why that made a stray control event able to\n * race the completion tail). Here, `interrupt()`/`stop()`/`timeout()`/\n * `complete()` each do exactly two things: record the outcome via\n * `reporting.prepareResult()`, then call `terminalPersistence.finalize()`.\n * `TerminalPersistenceService`'s own `finalized` boolean, checked and set\n * before anything else runs, is the ONLY thing that decides whether a given\n * call actually does anything. No new idempotency logic is added here -\n * every trigger is made to go through the one that already exists, rather\n * than rolling its own.\n *\n * WHY INTERRUPT/STOP/TIMEOUT EACH STILL CALL `prepareResult()`:\n * `RunnerReporting.mutateTerminalStatus`'s fallback derives a correct\n * outcome from `trigger` for real OS signals/exceptions - but interrupt/\n * stop/timeout are NOT `TerminalTrigger` values (those are this run's own\n * request-driven terminal reasons, not the signals/exceptions\n * `TerminalPersistenceService` itself watches for), and `finalize()` always\n * calls `mutateTerminalStatus` with `trigger === undefined` regardless of\n * WHY this class decided to call it. So each of `interrupt()`/`stop()`/\n * `timeout()` prepares its own result before calling `finalize()`, the same\n * as `complete()` does - `mutateTerminalStatus` cannot otherwise tell\n * interrupt apart from stop apart from normal completion.\n *\n */\n\nimport { inject, injectable } from 'inversify';\n\nimport { DOOM_TEAM_TYPES } from '../../../container/types.ts';\nimport type { ActivityState } from '../../../types/index.ts';\nimport type {\n ControlChannelWatchHandlers,\n IControlChannelWatcher,\n SteerRequest,\n} from '../../intercom/supervisorControlChannel.ts';\nimport type { AsyncRunStatus } from './asyncExecution.ts';\nimport { runDirFor } from './asyncExecution.ts';\nimport type { IRunnerReporting } from './runnerReporting.ts';\nimport type { ICoalescedStatusWriter } from './statusWriter.ts';\nimport type { ITerminalPersistenceService } from './terminalPersistence.ts';\n\nexport interface RunnerExecutionHandlers {\n /** Forwarded steer requests, for whatever delivers them to the running step (not this class's job). */\n onSteer?: (request: SteerRequest) => void;\n}\n\nexport interface RunnerProgress {\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nexport interface IRunnerExecution {\n /**\n * Start watching this run's control inbox and consuming any chain-append\n * requests already waiting. Returns a disposer that stops watching\n * without finalizing (used on a clean, already-finalized exit).\n */\n start(runId: string, handlers?: RunnerExecutionHandlers): () => void;\n /** Record a material, event-driven activity transition. */\n setActivity(activity: ActivityState): void;\n /** Record live child metrics in one coalesced status update. */\n setProgress(progress: RunnerProgress): void;\n /** This run finished normally. Idempotent via `TerminalPersistenceService`. */\n complete(success: boolean, summary: string): void;\n}\n\n@injectable()\nexport class RunnerExecution implements IRunnerExecution {\n constructor(\n @inject(DOOM_TEAM_TYPES.ControlChannelWatcher) private readonly controlChannel: IControlChannelWatcher,\n @inject(DOOM_TEAM_TYPES.TerminalPersistenceService)\n private readonly terminalPersistence: ITerminalPersistenceService<AsyncRunStatus>,\n @inject(DOOM_TEAM_TYPES.RunnerReporting) private readonly reporting: IRunnerReporting,\n @inject(DOOM_TEAM_TYPES.CoalescedStatusWriter)\n private readonly statusWriter: ICoalescedStatusWriter<AsyncRunStatus>,\n ) {}\n\n /** Dedicated runner processes own exactly one session, so a stop may exit after synchronous persistence. */\n protected exitProcess(code: number): void {\n process.exit(code);\n }\n\n start(runId: string, handlers: RunnerExecutionHandlers = {}): () => void {\n const controlHandlers: ControlChannelWatchHandlers = {\n onInterrupt: () => this.interrupt(),\n onStop: () => this.stop(),\n onTimeout: () => this.timeout(),\n ...(handlers.onSteer ? { onSteer: handlers.onSteer } : {}),\n };\n return this.controlChannel.watch(runDirFor(runId), controlHandlers);\n }\n\n setActivity(activity: ActivityState): void {\n this.statusWriter.update((status) => {\n status.activityState = activity;\n status.lastUpdate = Date.now();\n });\n }\n\n setProgress(progress: RunnerProgress): void {\n if (progress.tokens === undefined && progress.currentTool === undefined && progress.toolCount === undefined) {\n return;\n }\n this.statusWriter.update((status) => {\n if (progress.tokens !== undefined) status.tokens = progress.tokens;\n if (progress.currentTool !== undefined) status.currentTool = progress.currentTool;\n if (progress.toolCount !== undefined) status.toolCount = progress.toolCount;\n status.lastUpdate = Date.now();\n });\n }\n\n complete(success: boolean, summary: string): void {\n this.reporting.prepareResult({ success, summary });\n this.terminalPersistence.finalize();\n }\n\n interrupt(): void {\n this.reporting.prepareResult({ success: false, summary: 'Interrupted before completion.' });\n this.terminalPersistence.finalize();\n }\n\n stop(): void {\n this.reporting.prepareResult({ success: false, state: 'stopped', summary: 'Stopped before completion.' });\n try {\n this.terminalPersistence.finalize();\n } finally {\n this.exitProcess(0);\n }\n }\n\n timeout(): void {\n this.reporting.prepareResult({ success: false, summary: 'Timed out before completion.' });\n this.terminalPersistence.finalize();\n }\n}\n"],"mappings":"wqBAuC8D,IAQd,eAgCzC,KAAkD,CACvD,YACE,EACA,EAEA,EACA,EAEA,CANgE,KAAA,eAAA,EAE/C,KAAA,oBAAA,EACyC,KAAA,UAAA,EAEzC,KAAA,aAAA,EAInB,YAAsB,EAAoB,CACxC,QAAQ,KAAK,EAAK,CAGpB,MAAM,EAAe,EAAoC,EAAE,CAAc,CACvE,IAAM,EAA+C,CACnD,gBAAmB,KAAK,WAAW,CACnC,WAAc,KAAK,MAAM,CACzB,cAAiB,KAAK,SAAS,CAC/B,GAAI,EAAS,QAAU,CAAE,QAAS,EAAS,QAAS,CAAG,EAAE,CAC1D,CACD,OAAO,KAAK,eAAe,MAAM,EAAU,EAAM,CAAE,EAAgB,CAGrE,YAAY,EAA+B,CACzC,KAAK,aAAa,OAAQ,GAAW,CACnC,EAAO,cAAgB,EACvB,EAAO,WAAa,KAAK,KAAK,EAC9B,CAGJ,YAAY,EAAgC,CACtC,EAAS,SAAW,IAAA,IAAa,EAAS,cAAgB,IAAA,IAAa,EAAS,YAAc,IAAA,IAGlG,KAAK,aAAa,OAAQ,GAAW,CAC/B,EAAS,SAAW,IAAA,KAAW,EAAO,OAAS,EAAS,QACxD,EAAS,cAAgB,IAAA,KAAW,EAAO,YAAc,EAAS,aAClE,EAAS,YAAc,IAAA,KAAW,EAAO,UAAY,EAAS,WAClE,EAAO,WAAa,KAAK,KAAK,EAC9B,CAGJ,SAAS,EAAkB,EAAuB,CAChD,KAAK,UAAU,cAAc,CAAE,UAAS,UAAS,CAAC,CAClD,KAAK,oBAAoB,UAAU,CAGrC,WAAkB,CAChB,KAAK,UAAU,cAAc,CAAE,QAAS,GAAO,QAAS,iCAAkC,CAAC,CAC3F,KAAK,oBAAoB,UAAU,CAGrC,MAAa,CACX,KAAK,UAAU,cAAc,CAAE,QAAS,GAAO,MAAO,UAAW,QAAS,6BAA8B,CAAC,CACzG,GAAI,CACF,KAAK,oBAAoB,UAAU,QAC3B,CACR,KAAK,YAAY,EAAE,EAIvB,SAAgB,CACd,KAAK,UAAU,cAAc,CAAE,QAAS,GAAO,QAAS,+BAAgC,CAAC,CACzF,KAAK,oBAAoB,UAAU,QAlEtC,GAAY,KAGR,EAAO,EAAgB,sBAAsB,CAAA,KAC7C,EAAO,EAAgB,2BAA2B,CAAA,KAElD,EAAO,EAAgB,gBAAgB,CAAA,KACvC,EAAO,EAAgB,sBAAsB,CAAA"}
@@ -1,3 +1,3 @@
1
- const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../../shared/atomicJson.cjs`),n=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),r=require(`../../container/types.cjs`),i=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),a=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),o=require(`../../shared/paths.cjs`),s=require(`./resultWatcher.cjs`);let c=require(`node:path`);c=e.__toESM(c,1);let l=require(`inversify`);function u(e){return c.join(o.currentResultsDir(),`${e}${s.RESULT_FILE_SUFFIX}`)}const d=4e3;function f(e){return e.length<=d?e:e.slice(0,d-71)+`
2
- ... [truncated for status.json; see the result file for the full text]`}function p(e){return e instanceof Error?e.message:typeof e==`string`?e:`Unhandled rejection with no error message.`}let m=class{constructor(e){this.statusWriter=e}now(){return Date.now()}writeResultFile(e,n){t.writeAtomicJson(u(e),n)}prepared;recordedSessionFile;prepareResult(e){this.prepared=e}recordSessionFile(e){return this.recordedSessionFile=e.length<=4096?e:void 0,this.recordedSessionFile}resolveOutcome(e){return e?.kind===`signal`?{state:`stopped`,success:!1,error:`Terminated by signal ${e.signal}.`}:e?.kind===`uncaughtException`?{state:`failed`,success:!1,error:e.error.message}:e?.kind===`unhandledRejection`?{state:`failed`,success:!1,error:p(e.reason)}:this.prepared?{state:this.prepared.state??(this.prepared.success?`completed`:`failed`),success:this.prepared.success}:{state:`failed`,success:!1,error:`Run finalized without ever calling prepareResult().`}}mutateTerminalStatus(e,t){let n=this.now(),r=this.resolveOutcome(t),i=this.prepared?.summary??r.error??`(no summary)`;e.state=r.state,e.endedAt=n,e.lastUpdate=n,e.summary=f(i),r.error&&(e.error=r.error),this.recordedSessionFile&&(e.sessionFile=this.recordedSessionFile),this.statusWriter.updateSync(()=>{});let a={runId:e.runId,agent:e.agent,success:r.success,state:r.state,summary:i,startedAt:e.startedAt,endedAt:n,...r.error?{error:r.error}:{},...this.prepared?.acceptance?{acceptance:this.prepared.acceptance}:{}};this.writeResultFile(e.runId,a)}};m=n.__decorate([(0,l.injectable)(),a.__decorateParam(0,(0,l.inject)(r.DOOM_TEAM_TYPES.CoalescedStatusWriter)),i.__decorateMetadata(`design:paramtypes`,[Object])],m),Object.defineProperty(exports,`RunnerReporting`,{enumerable:!0,get:function(){return m}});
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),n=require(`../../../container/types.cjs`),r=require(`../../../adapters/atomicJson.cjs`);require(`../../../shared/atomicJson.cjs`);const i=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),a=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),o=require(`../../../shared/paths.cjs`),s=require(`../../../adapters/resultWatcher.cjs`);require(`./resultWatcher.cjs`);let c=require(`node:path`);c=e.__toESM(c,1);let l=require(`inversify`);function u(e){return c.join(o.currentResultsDir(),`${e}${s.RESULT_FILE_SUFFIX}`)}const d=4e3;function f(e){return e.length<=d?e:e.slice(0,d-71)+`
2
+ ... [truncated for status.json; see the result file for the full text]`}function p(e){return e instanceof Error?e.message:typeof e==`string`?e:`Unhandled rejection with no error message.`}let m=class{constructor(e){this.statusWriter=e}now(){return Date.now()}writeResultFile(e,t){r.writeAtomicJson(u(e),t)}prepared;recordedSessionFile;prepareResult(e){this.prepared=e}recordSessionFile(e){return this.recordedSessionFile=e.length<=4096?e:void 0,this.recordedSessionFile}resolveOutcome(e){return e?.kind===`signal`?{state:`stopped`,success:!1,error:`Terminated by signal ${e.signal}.`}:e?.kind===`uncaughtException`?{state:`failed`,success:!1,error:e.error.message}:e?.kind===`unhandledRejection`?{state:`failed`,success:!1,error:p(e.reason)}:this.prepared?{state:this.prepared.state??(this.prepared.success?`completed`:`failed`),success:this.prepared.success}:{state:`failed`,success:!1,error:`Run finalized without ever calling prepareResult().`}}mutateTerminalStatus(e,t){let n=this.now(),r=this.resolveOutcome(t),i=this.prepared?.summary??r.error??`(no summary)`;e.state=r.state,e.endedAt=n,e.lastUpdate=n,e.summary=f(i),r.error&&(e.error=r.error),this.recordedSessionFile&&(e.sessionFile=this.recordedSessionFile),this.statusWriter.updateSync(()=>{});let a={runId:e.runId,agent:e.agent,success:r.success,state:r.state,summary:i,startedAt:e.startedAt,endedAt:n,...r.error?{error:r.error}:{},...this.prepared?.acceptance?{acceptance:this.prepared.acceptance}:{}};this.writeResultFile(e.runId,a)}};m=t.__decorate([(0,l.injectable)(),a.__decorateParam(0,(0,l.inject)(n.DOOM_TEAM_TYPES.CoalescedStatusWriter)),i.__decorateMetadata(`design:paramtypes`,[Object])],m),Object.defineProperty(exports,`RunnerReporting`,{enumerable:!0,get:function(){return m}});
3
3
  //# sourceMappingURL=runnerReporting.cjs.map