@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(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),n=require(`../../container/types.cjs`),r=require(`../../shared/configDir.cjs`),i=require(`../../adapters/atomicJson.cjs`);require(`../../shared/atomicJson.cjs`);const a=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),o=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`);let s=require(`node:fs`);s=e.__toESM(s,1);let c=require(`node:path`);c=e.__toESM(c,1);let l=require(`inversify`),u=require(`node:crypto`);process.platform;const d=`steer-acks`,f=128*1024,p=1e6,m=1e3;function h(e){return c.join(e,`control`)}function g(e){return c.join(h(e),`interrupt.json`)}function _(e){return c.join(h(e),`timeout.json`)}function v(e){return c.join(h(e),`stop.json`)}function y(e){return c.join(h(e),`steer-requests`)}function b(e){return c.join(h(e),`steer-inbox-closed.json`)}function x(e,t){return D(t),c.join(h(e),`steer-targets`,String(t))}function S(e){return c.join(h(e),`steer-capabilities`)}function C(e,t){return D(t),c.join(S(e),`${t}.json`)}function w(e,t){return D(t),c.join(h(e),d,String(t))}function T(e){return`${Buffer.from(e).toString(`base64url`)}.json`}function E(e,t){if(!/^[^\s]+$/.test(t)||t.length>256)throw Error(`steer acknowledgment requestId is invalid.`);return c.join(e,T(t))}function D(e){if(!Number.isInteger(e)||e<0||e>p)throw Error(`steer child index must be a non-negative integer.`)}function O(e){return`${String(e.ts).padStart(13,`0`)}-${Buffer.from(e.id).toString(`base64url`)}.json`}function k(e){return e.type===`steer`&&typeof e.id==`string`&&/^[^\s]+$/.test(e.id)&&e.id.length<=256&&typeof e.ts==`number`&&Number.isFinite(e.ts)&&e.ts>0&&typeof e.message==`string`&&!!e.message.trim()&&Buffer.byteLength(e.message,`utf8`)<=f&&(e.targetIndex===void 0||Number.isInteger(e.targetIndex)&&e.targetIndex>=0&&e.targetIndex<=p)&&(e.targetIndexes===void 0||e.targetIndex===void 0&&Array.isArray(e.targetIndexes)&&e.targetIndexes.length>0&&e.targetIndexes.length<=m&&e.targetIndexes.every(e=>Number.isInteger(e)&&e>=0&&e<=p)&&new Set(e.targetIndexes).size===e.targetIndexes.length)&&(e.source===void 0||typeof e.source==`string`&&!!e.source.trim()&&e.source.length<=256)}function A(e,t){if(!k(t))throw Error(`steer request is malformed or exceeds transport limits.`);let n=c.join(e,O(t));return i.writeAtomicJson(n,t),n}function j(e,t){if(D(t.index),!Number.isInteger(t.pid)||t.pid<=0)throw Error(`steer capability pid must be a positive integer.`);if(!Number.isFinite(t.readyAt)||t.readyAt<=0)throw Error(`steer capability readyAt must be a finite timestamp.`);return i.writeAtomicJson(e,{type:`steer-capability`,protocolVersion:1,...t}),e}function M(e,t){if(D(t.index),!/^[^\s]+$/.test(t.requestId)||t.requestId.length>256)throw Error(`steer acknowledgment requestId is invalid.`);if(!Number.isFinite(t.ts)||t.ts<=0)throw Error(`steer acknowledgment ts must be a finite timestamp.`);if(!t.message.trim()||t.message.length>1e3)throw Error(`steer acknowledgment message is invalid.`);return i.writeAtomicJson(e,{type:`steer-ack`,protocolVersion:1,...t,message:t.message.trim()}),e}function N(e,t={},n={}){let r=g(e);return i.writeAtomicJson(r,{...t,ts:t.ts??n.now?.()??Date.now(),type:`interrupt`}),r}function P(e,t={},n={}){let r=v(e);return i.writeAtomicJson(r,{...t,ts:t.ts??n.now?.()??Date.now(),type:`stop`}),r}function F(e,t,n={}){let r=t.message.trim();if(!r)throw Error(`steer message must not be empty.`);if(Buffer.byteLength(r,`utf8`)>f)throw Error(`steer message exceeds ${f} UTF-8 bytes.`);if(t.targetIndex!==void 0&&(!Number.isInteger(t.targetIndex)||t.targetIndex<0||t.targetIndex>p))throw Error(`steer targetIndex must be an integer between 0 and 1000000.`);if(t.targetIndexes!==void 0&&(!Array.isArray(t.targetIndexes)||t.targetIndex!==void 0||t.targetIndexes.length===0||t.targetIndexes.length>m||t.targetIndexes.some(e=>!Number.isInteger(e)||e<0||e>p)||new Set(t.targetIndexes).size!==t.targetIndexes.length))throw Error(`steer targetIndexes must contain 1-1000 unique non-negative integers and cannot be combined with targetIndex.`);let i=b(e);if(s.existsSync(i))throw Error(`Async run no longer accepts steering requests.`);let a={type:`steer`,id:t.id??n.randomId?.()??(0,u.randomUUID)(),ts:t.ts??n.now?.()??Date.now(),message:r,...t.targetIndex===void 0?{}:{targetIndex:t.targetIndex},...t.targetIndexes===void 0?{}:{targetIndexes:[...t.targetIndexes]},...t.source?{source:t.source}:{}},o=A(y(e),a);if(s.existsSync(i))throw s.rmSync(o,{force:!0}),Error(`Async run stopped accepting steering before the request was committed.`);return o}function I(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(t.type!==`steer-capability`||t.protocolVersion!==1)return;let n=t.index,r=t.pid,i=t.readyAt;if(!(typeof n!=`number`||!Number.isInteger(n)||n<0||n>p)&&!(typeof r!=`number`||!Number.isInteger(r)||r<=0)&&!(typeof i!=`number`||!Number.isFinite(i)||i<=0)&&typeof t.supported==`boolean`)return{type:`steer-capability`,protocolVersion:1,index:n,pid:r,readyAt:i,supported:t.supported}}function L(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(t.type!==`steer-ack`||t.protocolVersion!==1||typeof t.requestId!=`string`||!/^[^\s]+$/.test(t.requestId)||t.requestId.length>256)return;let n=t.index,r=t.ts;if(!(typeof n!=`number`||!Number.isInteger(n)||n<0||n>p)&&!(typeof r!=`number`||!Number.isFinite(r)||r<=0)&&!(t.state!==`delivered`&&t.state!==`failed`)&&!(typeof t.message!=`string`||!t.message.trim()||t.message.length>1e3))return{type:`steer-ack`,protocolVersion:1,requestId:t.requestId,index:n,ts:r,state:t.state,message:t.message.trim()}}function R(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(k(t))return{type:`steer`,id:t.id.trim(),ts:t.ts,message:t.message.trim(),...t.targetIndex===void 0?{}:{targetIndex:t.targetIndex},...t.targetIndexes===void 0?{}:{targetIndexes:[...t.targetIndexes]},...typeof t.source==`string`&&t.source.trim()?{source:t.source}:{}}}function z(e,t){try{t.rmSync(e,{recursive:!0})}catch(e){if(e.code===`ENOENT`)return;throw e}}function B(e,t=s){let n=S(e);if(!t.existsSync(n))return[];let r=[];for(let e of t.readdirSync(n).filter(e=>/^\d+\.json$/.test(e)).sort())try{let i=I(JSON.parse(t.readFileSync(c.join(n,e),`utf-8`)));i&&r.push(i)}catch{}return r}function V(e,t=s){let n=c.join(h(e),d);if(!t.existsSync(n))return[];let r=[],i;try{i=t.readdirSync(n).filter(e=>/^\d+$/.test(e))}catch{return[]}for(let e of i){let i=c.join(n,e),a;try{a=t.readdirSync(i).filter(e=>e.endsWith(`.json`)).sort()}catch{continue}for(let e of a){let n=c.join(i,e),a;try{a=L(JSON.parse(t.readFileSync(n,`utf-8`)))}catch{a=void 0}z(n,t),a&&r.push(a)}}return r}function H(e,t,n,r=s){let i=E(w(e,t),n),a;try{a=L(JSON.parse(r.readFileSync(i,`utf-8`)))}catch(e){if(e.code===`ENOENT`)return;throw e}if(z(i,r),!(!a||a.requestId!==n||a.index!==t))return a}function U(e,t=s){let n=g(e);return t.existsSync(n)?(z(n,t),!0):!1}function W(e,t=s){let n=_(e);return t.existsSync(n)?(z(n,t),!0):!1}function G(e,t=s){let n=v(e);return t.existsSync(n)?(z(n,t),!0):!1}function K(e,t,n,r){let i=c.join(e,t),a=`${i}.claim-${n}`;try{return r.renameSync(i,a),a}catch(e){if(e.code===`ENOENT`)return;throw e}}function q(e,t=s,n=(0,u.randomUUID)()){if(!t.existsSync(e))return[];let r;try{r=t.readdirSync(e).filter(e=>e.endsWith(`.json`)).sort()}catch{return[]}let i=[];for(let a of r){let r=K(e,a,n,t);if(!r)continue;let o=c.join(e,a),s;try{s=R(JSON.parse(t.readFileSync(r,`utf-8`)))}catch{s=void 0}if(!s){z(r,t);continue}let l=!1;i.push({request:s,commit:()=>{l||(l=!0,z(r,t))},release:()=>{if(!l){l=!0;try{t.renameSync(r,o)}catch{z(r,t)}}}})}return i.sort((e,t)=>e.request.ts-t.request.ts||e.request.id.localeCompare(t.request.id))}function J(e,t=s,n=(0,u.randomUUID)()){return q(y(e),t,n)}let Y=class{intervalMs=1e3;constructor(e){this.scheduler=e}watch(e,t,n={}){let i=n.fs??s,a=h(e);try{i.mkdirSync(a,{recursive:!0})}catch{}let o=`${process.pid}-${(0,u.randomUUID)()}`,c=!1,l=()=>c?!1:this.check(e,t,i,o);l();let d=this.scheduler.register({id:`control-channel:${e}`,intervalMs:n.intervalMs??this.intervalMs,run:l}),f;try{f=i.watch(r.resolveWatchPath(a,i.realpathSync.native),()=>{c||this.scheduler.wake()}),f.on?.(`error`,()=>{})}catch{f=void 0}return()=>{if(!c){c=!0;try{f?.close()}catch{}d()}}}check(e,t,n,r){let i=!1;G(e,n)&&(t.onStop?.(),i=!0),W(e,n)&&(t.onTimeout?.(),i=!0),U(e,n)&&(t.onInterrupt(),i=!0);let a;for(let o of J(e,n,r))try{t.onSteer?.(o.request),o.commit(),i=!0}catch(e){o.release(),a??=e}for(let r of B(e,n))t.onSteerCapability?.(r);if(t.onSteerAck)for(let r of V(e,n))t.onSteerAck(r),i=!0;if(a!==void 0)throw a;return i}};Y=t.__decorate([(0,l.injectable)(),o.__decorateParam(0,(0,l.inject)(n.DOOM_TEAM_TYPES.PollScheduler)),a.__decorateMetadata(`design:paramtypes`,[Object])],Y),Object.defineProperty(exports,`ControlChannelWatcher`,{enumerable:!0,get:function(){return Y}}),exports.claimSteerRequestsFromDir=q,exports.consumeSteerAck=H,exports.requestAsyncInterrupt=N,exports.requestAsyncSteer=F,exports.requestAsyncStop=P,exports.steerAckPathFromDir=E,exports.steerAcksDir=w,exports.steerCapabilityPath=C,exports.stepSteerInboxDir=x,exports.writeSteerAckAt=M,exports.writeSteerCapabilityAt=j;
2
+ //# sourceMappingURL=supervisorControlChannel.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisorControlChannel.cjs","names":["path","fs","resolveWatchPath","DOOM_TEAM_TYPES"],"sources":["../../../src/services/intercom/supervisorControlChannel.ts"],"sourcesContent":["/**\n * Cross-OS control channel for async subagent runs.\n *\n * Background runs are detached OS processes. A signal-based interrupt\n * (`process.kill(pid, SIGUSR2|SIGBREAK)`) cannot be delivered cross-process on\n * Windows and throws `ENOSYS`, which would leave async runs uninterruptible\n * (no stop, no live steer) on that platform. This module is a portable,\n * file-based control inbox inside the run directory instead: the parent drops\n * a request file, the runner watches the inbox and routes it into its own\n * interrupt handling, identically on every platform. The OS signal is kept\n * only as an opportunistic fast-path; its failure is non-fatal because the\n * file inbox is authoritative.\n *\n * FIX 1 - steer messages must survive a failed dispatch:\n * The predecessor (`doom-pi-subagents/src/runs/background/control-channel.ts`)\n * deleted a steer request file BEFORE dispatching it. A throw during dispatch\n * then lost the instruction with no trace: the user's steer vanished and\n * nothing on disk or in memory recorded that it had ever arrived. Steer\n * requests here are claimed by rename instead: `claimSteerRequestsFromDir`\n * atomically moves a request out of the queue (deciding a single winner among\n * any concurrent consumers in the same step), the caller dispatches what it\n * claimed, and only `commit()` - called after dispatch returns - deletes it.\n * A dispatch that throws calls `release()`, which renames the file back to\n * its original name so the next scan retries it. This package's own delivery\n * loop (`ControlChannelWatcher.check`) follows exactly this claim -> dispatch\n * -> commit/release shape; see `src/intercom/nativeTeamChannel.ts`'s\n * \"deliver, then mark seen\" for the same principle applied to team messages.\n *\n * Residual gap: if the process dies between claim and release (not a thrown\n * error, a hard kill), the claimed file is left under its `.claim-<id>` name\n * and no longer matches a normal directory scan. Nothing here sweeps it back.\n * That is a real gap, not an oversight - recovering from a hard process kill\n * needs a second, independent process to notice, which does not exist yet in\n * this package. What this module guarantees is the fix that was asked for and\n * that a live process can retry: a message is never lost to a dispatch that\n * merely throws.\n *\n * FIX 2 - a missing file and a permission failure are different situations:\n * one is the routine \"someone else already consumed this\" case, harmless and\n * expected; the other means this run's control channel cannot be trusted and\n * must be surfaced, not swallowed. `removeIfPresent` below is the one place\n * this module deletes a control file, and it draws exactly that line: `ENOENT`\n * is absorbed, anything else is rethrown.\n *\n * FIX 3/4 - watch-first, `PollScheduler` as the bounded safety net:\n * `ControlChannelWatcher` registers one subscription per watched run with the\n * shared `PollScheduler` (see its header) instead of owning a `setInterval`,\n * the same \"watch-first, poll as a bounded safety net\" shape `PollScheduler`\n * was built for: `fs.watch` on the inbox directory calls `wake()` for low\n * latency, and the registered subscription's own `intervalMs` is deliberately\n * loose because it exists only to cover platforms and mount types where\n * watches are unreliable, not to carry normal-case latency. This was NOT\n * given the same treatment as `SpawnHandshake` (see that module's header),\n * which explicitly opts out of `PollScheduler`: a spawn handshake is a\n * per-spawn, sub-second, self-terminating wait, where sharing the scheduler's\n * idle backoff would either pin the whole scheduler near its floor for its\n * duration or starve the wait of the low latency it needs. A control-inbox\n * watch is the opposite shape - one long-lived subscriber per run, alive for\n * the run's whole lifetime, checking infrequently - which is exactly the\n * \"channels, watchers, inspectors\" category `PollScheduler` exists to\n * coordinate.\n *\n * A subscriber's `run()` throwing is not swallowed here: it is left to\n * propagate out of `check()` so `PollScheduler.tick()` catches it and records\n * it as `lastSubscriberError`, which is what makes FIX 2's rethrown\n * permission failures actually visible instead of merely \"not silently\n * deleted\".\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { inject, injectable } from 'inversify';\n\nimport { DOOM_TEAM_TYPES } from '../../container/types.ts';\nimport { writeAtomicJson } from '../../shared/atomicJson.ts';\nimport { resolveWatchPath } from '../../shared/configDir.ts';\nimport type { IPollScheduler } from '../../shared/pollScheduler.ts';\n\n/**\n * Opportunistic fast-path interrupt signal. On Unix `SIGUSR2` is trapped by\n * the runner; on Windows `process.kill(pid, \"SIGBREAK\")` is not deliverable\n * cross-process and throws `ENOSYS`, so the file inbox below is the real\n * channel there.\n */\nexport const INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === 'win32' ? 'SIGBREAK' : 'SIGUSR2';\n\n/** How generously the poll safety net is spaced. `fs.watch` is the fast path; see the module header. */\nconst DEFAULT_CONTROL_CHANNEL_POLL_INTERVAL_MS = 1_000;\n\nexport type ControlChannelFs = Pick<\n typeof fs,\n 'mkdirSync' | 'existsSync' | 'rmSync' | 'renameSync' | 'watch' | 'readdirSync' | 'readFileSync' | 'realpathSync'\n>;\ntype KillFn = (pid: number, signal?: NodeJS.Signals | 0) => unknown;\n\nexport interface InterruptRequest {\n type: 'interrupt';\n ts?: number;\n source?: string;\n reason?: string;\n}\n\nexport interface TimeoutRequest {\n type: 'timeout';\n ts?: number;\n source?: string;\n reason?: string;\n}\n\nexport interface StopRequest {\n type: 'stop';\n ts?: number;\n source?: string;\n reason?: string;\n}\n\nexport interface SteerRequest {\n type: 'steer';\n id: string;\n ts: number;\n message: string;\n targetIndex?: number;\n targetIndexes?: number[];\n source?: string;\n}\n\nexport interface SteerCapability {\n type: 'steer-capability';\n protocolVersion: 1;\n index: number;\n pid: number;\n readyAt: number;\n supported: boolean;\n}\n\nexport interface SteerAck {\n type: 'steer-ack';\n protocolVersion: 1;\n requestId: string;\n index: number;\n ts: number;\n state: 'delivered' | 'failed';\n message: string;\n}\n\nconst STEER_REQUESTS_DIR = 'steer-requests';\nconst STEER_TARGETS_DIR = 'steer-targets';\nconst STEER_CAPABILITIES_DIR = 'steer-capabilities';\nconst STEER_ACKS_DIR = 'steer-acks';\nconst STEER_INBOX_CLOSED_FILE = 'steer-inbox-closed.json';\nconst MAX_STEER_MESSAGE_BYTES = 128 * 1024;\n/**\n * Highest child index a steer may address.\n *\n * A bound rather than a real limit: it exists so a malformed or hostile\n * request cannot make the runner allocate or iterate over an absurd range.\n */\nconst MAX_STEER_TARGET_INDEX = 1_000_000;\n/** Most children one steer may address at once, for the same reason. */\nconst MAX_STEER_TARGET_COUNT = 1_000;\nconst MAX_STEER_REQUEST_ID_LENGTH = 256;\nconst MAX_STEER_ACK_MESSAGE_LENGTH = 1_000;\n/** Suffix appended to a steer request's file name while a consumer is dispatching it. */\nconst CLAIM_SUFFIX_PREFIX = '.claim-';\n\n// ---------------------------------------------------------------------------\n// Paths\n// ---------------------------------------------------------------------------\n\n/** Control inbox directory inside an async run dir. */\nexport function controlInboxDir(asyncDir: string): string {\n return path.join(asyncDir, 'control');\n}\n\n/** Path of the portable interrupt request file. */\nexport function interruptRequestPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), 'interrupt.json');\n}\n\n/** Path of the portable timeout request file. */\nexport function timeoutRequestPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), 'timeout.json');\n}\n\n/** Path of the portable manual stop request file. */\nexport function stopRequestPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), 'stop.json');\n}\n\n/** Directory of parent-to-runner steering requests. */\nexport function steerRequestsDir(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), STEER_REQUESTS_DIR);\n}\n\nexport function steerInboxClosedPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), STEER_INBOX_CLOSED_FILE);\n}\n\nexport function closeSteerInbox(asyncDir: string, state: string): void {\n writeAtomicJson(steerInboxClosedPath(asyncDir), { version: 1, closedAt: Date.now(), state });\n}\n\n/** Per-child inbox consumed by the child prompt runtime inside the Pi process. */\nexport function stepSteerInboxDir(asyncDir: string, index: number): string {\n assertChildIndex(index);\n return path.join(controlInboxDir(asyncDir), STEER_TARGETS_DIR, String(index));\n}\n\nexport function steerCapabilitiesDir(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), STEER_CAPABILITIES_DIR);\n}\n\nexport function steerCapabilityPath(asyncDir: string, index: number): string {\n assertChildIndex(index);\n return path.join(steerCapabilitiesDir(asyncDir), `${index}.json`);\n}\n\nexport function steerAcksDir(asyncDir: string, index: number): string {\n assertChildIndex(index);\n return path.join(controlInboxDir(asyncDir), STEER_ACKS_DIR, String(index));\n}\n\nfunction steerAckFileName(requestId: string): string {\n return `${Buffer.from(requestId).toString('base64url')}.json`;\n}\n\nexport function steerAckPathFromDir(dir: string, requestId: string): string {\n if (!/^[^\\s]+$/.test(requestId) || requestId.length > MAX_STEER_REQUEST_ID_LENGTH)\n throw new Error('steer acknowledgment requestId is invalid.');\n return path.join(dir, steerAckFileName(requestId));\n}\n\nfunction assertChildIndex(index: number): void {\n if (!Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX)\n throw new Error('steer child index must be a non-negative integer.');\n}\n\nfunction steerRequestFileName(request: SteerRequest): string {\n return `${String(request.ts).padStart(13, '0')}-${Buffer.from(request.id).toString('base64url')}.json`;\n}\n\nfunction validSteerRequest(request: Partial<SteerRequest>): request is SteerRequest {\n return (\n request.type === 'steer' &&\n typeof request.id === 'string' &&\n /^[^\\s]+$/.test(request.id) &&\n request.id.length <= MAX_STEER_REQUEST_ID_LENGTH &&\n typeof request.ts === 'number' &&\n Number.isFinite(request.ts) &&\n request.ts > 0 &&\n typeof request.message === 'string' &&\n Boolean(request.message.trim()) &&\n Buffer.byteLength(request.message, 'utf8') <= MAX_STEER_MESSAGE_BYTES &&\n (request.targetIndex === undefined ||\n (Number.isInteger(request.targetIndex) &&\n request.targetIndex >= 0 &&\n request.targetIndex <= MAX_STEER_TARGET_INDEX)) &&\n (request.targetIndexes === undefined ||\n (request.targetIndex === undefined &&\n Array.isArray(request.targetIndexes) &&\n request.targetIndexes.length > 0 &&\n request.targetIndexes.length <= MAX_STEER_TARGET_COUNT &&\n request.targetIndexes.every(\n (index) => Number.isInteger(index) && index >= 0 && index <= MAX_STEER_TARGET_INDEX,\n ) &&\n new Set(request.targetIndexes).size === request.targetIndexes.length)) &&\n (request.source === undefined ||\n (typeof request.source === 'string' && Boolean(request.source.trim()) && request.source.length <= 256))\n );\n}\n\nexport function writeSteerRequestToDir(dir: string, request: SteerRequest): string {\n if (!validSteerRequest(request)) throw new Error('steer request is malformed or exceeds transport limits.');\n const requestPath = path.join(dir, steerRequestFileName(request));\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function writeSteerCapabilityAt(\n filePath: string,\n capability: Omit<SteerCapability, 'type' | 'protocolVersion'>,\n): string {\n assertChildIndex(capability.index);\n if (!Number.isInteger(capability.pid) || capability.pid <= 0)\n throw new Error('steer capability pid must be a positive integer.');\n if (!Number.isFinite(capability.readyAt) || capability.readyAt <= 0)\n throw new Error('steer capability readyAt must be a finite timestamp.');\n const record: SteerCapability = { type: 'steer-capability', protocolVersion: 1, ...capability };\n writeAtomicJson(filePath, record);\n return filePath;\n}\n\nexport function writeSteerCapability(\n asyncDir: string,\n capability: Omit<SteerCapability, 'type' | 'protocolVersion'>,\n): string {\n return writeSteerCapabilityAt(steerCapabilityPath(asyncDir, capability.index), capability);\n}\n\nexport function writeSteerAckAt(filePath: string, ack: Omit<SteerAck, 'type' | 'protocolVersion'>): string {\n assertChildIndex(ack.index);\n if (!/^[^\\s]+$/.test(ack.requestId) || ack.requestId.length > MAX_STEER_REQUEST_ID_LENGTH)\n throw new Error('steer acknowledgment requestId is invalid.');\n if (!Number.isFinite(ack.ts) || ack.ts <= 0) throw new Error('steer acknowledgment ts must be a finite timestamp.');\n if (!ack.message.trim() || ack.message.length > MAX_STEER_ACK_MESSAGE_LENGTH)\n throw new Error('steer acknowledgment message is invalid.');\n const record: SteerAck = { type: 'steer-ack', protocolVersion: 1, ...ack, message: ack.message.trim() };\n writeAtomicJson(filePath, record);\n return filePath;\n}\n\nexport function writeSteerAck(asyncDir: string, ack: Omit<SteerAck, 'type' | 'protocolVersion'>): string {\n return writeSteerAckAt(path.join(steerAcksDir(asyncDir, ack.index), steerAckFileName(ack.requestId)), ack);\n}\n\n/**\n * Parent side: drop a portable interrupt request the runner's inbox watcher\n * will pick up regardless of OS. Written atomically (temp + rename), dir\n * auto-created.\n */\nexport function requestAsyncInterrupt(\n asyncDir: string,\n payload: Omit<InterruptRequest, 'type'> = {},\n deps: { now?: () => number } = {},\n): string {\n const requestPath = interruptRequestPath(asyncDir);\n const request: InterruptRequest = { ...payload, ts: payload.ts ?? deps.now?.() ?? Date.now(), type: 'interrupt' };\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function requestAsyncTimeout(\n asyncDir: string,\n payload: Omit<TimeoutRequest, 'type'> = {},\n deps: { now?: () => number } = {},\n): string {\n const requestPath = timeoutRequestPath(asyncDir);\n const request: TimeoutRequest = { ...payload, ts: payload.ts ?? deps.now?.() ?? Date.now(), type: 'timeout' };\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function requestAsyncStop(\n asyncDir: string,\n payload: Omit<StopRequest, 'type'> = {},\n deps: { now?: () => number } = {},\n): string {\n const requestPath = stopRequestPath(asyncDir);\n const request: StopRequest = { ...payload, ts: payload.ts ?? deps.now?.() ?? Date.now(), type: 'stop' };\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function requestAsyncSteer(\n asyncDir: string,\n payload: {\n message: string;\n targetIndex?: number;\n targetIndexes?: number[];\n source?: string;\n id?: string;\n ts?: number;\n },\n deps: { now?: () => number; randomId?: () => string } = {},\n): string {\n const message = payload.message.trim();\n if (!message) throw new Error('steer message must not be empty.');\n if (Buffer.byteLength(message, 'utf8') > MAX_STEER_MESSAGE_BYTES)\n throw new Error(`steer message exceeds ${MAX_STEER_MESSAGE_BYTES} UTF-8 bytes.`);\n if (\n payload.targetIndex !== undefined &&\n (!Number.isInteger(payload.targetIndex) || payload.targetIndex < 0 || payload.targetIndex > MAX_STEER_TARGET_INDEX)\n ) {\n throw new Error('steer targetIndex must be an integer between 0 and 1000000.');\n }\n if (\n payload.targetIndexes !== undefined &&\n (!Array.isArray(payload.targetIndexes) ||\n payload.targetIndex !== undefined ||\n payload.targetIndexes.length === 0 ||\n payload.targetIndexes.length > MAX_STEER_TARGET_COUNT ||\n payload.targetIndexes.some((index) => !Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX) ||\n new Set(payload.targetIndexes).size !== payload.targetIndexes.length)\n ) {\n throw new Error(\n 'steer targetIndexes must contain 1-1000 unique non-negative integers and cannot be combined with targetIndex.',\n );\n }\n const closedPath = steerInboxClosedPath(asyncDir);\n if (fs.existsSync(closedPath)) throw new Error('Async run no longer accepts steering requests.');\n const request: SteerRequest = {\n type: 'steer',\n id: payload.id ?? deps.randomId?.() ?? randomUUID(),\n ts: payload.ts ?? deps.now?.() ?? Date.now(),\n message,\n ...(payload.targetIndex !== undefined ? { targetIndex: payload.targetIndex } : {}),\n ...(payload.targetIndexes !== undefined ? { targetIndexes: [...payload.targetIndexes] } : {}),\n ...(payload.source ? { source: payload.source } : {}),\n };\n const requestPath = writeSteerRequestToDir(steerRequestsDir(asyncDir), request);\n if (fs.existsSync(closedPath)) {\n fs.rmSync(requestPath, { force: true });\n throw new Error('Async run stopped accepting steering before the request was committed.');\n }\n return requestPath;\n}\n\nexport function enqueueStepSteer(asyncDir: string, index: number, request: SteerRequest): string {\n assertChildIndex(index);\n const { targetIndexes: _targetIndexes, ...singleTargetRequest } = request;\n return writeSteerRequestToDir(stepSteerInboxDir(asyncDir, index), {\n ...singleTargetRequest,\n targetIndex: index,\n type: 'steer',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Parsing. Everything read off disk arrives as `unknown` and is narrowed here;\n// nothing is asserted into shape.\n// ---------------------------------------------------------------------------\n\nfunction parseSteerCapability(raw: unknown): SteerCapability | undefined {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const input = raw as Partial<SteerCapability>;\n if (input.type !== 'steer-capability' || input.protocolVersion !== 1) return undefined;\n const index = input.index;\n const pid = input.pid;\n const readyAt = input.readyAt;\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX)\n return undefined;\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) return undefined;\n if (typeof readyAt !== 'number' || !Number.isFinite(readyAt) || readyAt <= 0) return undefined;\n if (typeof input.supported !== 'boolean') return undefined;\n return {\n type: 'steer-capability',\n protocolVersion: 1,\n index,\n pid,\n readyAt,\n supported: input.supported,\n };\n}\n\nfunction parseSteerAck(raw: unknown): SteerAck | undefined {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const input = raw as Partial<SteerAck>;\n if (\n input.type !== 'steer-ack' ||\n input.protocolVersion !== 1 ||\n typeof input.requestId !== 'string' ||\n !/^[^\\s]+$/.test(input.requestId) ||\n input.requestId.length > MAX_STEER_REQUEST_ID_LENGTH\n )\n return undefined;\n const index = input.index;\n const ts = input.ts;\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX)\n return undefined;\n if (typeof ts !== 'number' || !Number.isFinite(ts) || ts <= 0) return undefined;\n if (input.state !== 'delivered' && input.state !== 'failed') return undefined;\n if (typeof input.message !== 'string' || !input.message.trim() || input.message.length > 1000) return undefined;\n return {\n type: 'steer-ack',\n protocolVersion: 1,\n requestId: input.requestId,\n index,\n ts,\n state: input.state,\n message: input.message.trim(),\n };\n}\n\nfunction parseSteerRequest(raw: unknown): SteerRequest | undefined {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const input = raw as Partial<SteerRequest>;\n if (!validSteerRequest(input)) return undefined;\n return {\n type: 'steer',\n id: input.id.trim(),\n ts: input.ts,\n message: input.message.trim(),\n ...(input.targetIndex !== undefined ? { targetIndex: input.targetIndex } : {}),\n ...(input.targetIndexes !== undefined ? { targetIndexes: [...input.targetIndexes] } : {}),\n ...(typeof input.source === 'string' && input.source.trim() ? { source: input.source } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Deletion. `removeIfPresent` is the one place this module deletes a control\n// file, and it is FIX 2 in one function: `ENOENT` is the routine \"someone\n// else already consumed this\" case and is absorbed; anything else means this\n// run's control channel is broken and must be surfaced to the caller.\n// ---------------------------------------------------------------------------\n\nfunction removeIfPresent(target: string, fsImpl: Pick<typeof fs, 'rmSync'>): void {\n try {\n fsImpl.rmSync(target, { recursive: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n}\n\nexport function consumeSteerCapabilities(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'readdirSync' | 'readFileSync'> = fs,\n): SteerCapability[] {\n const dir = steerCapabilitiesDir(asyncDir);\n if (!fsImpl.existsSync(dir)) return [];\n const capabilities: SteerCapability[] = [];\n for (const entry of fsImpl\n .readdirSync(dir)\n .filter((name) => /^\\d+\\.json$/.test(name))\n .sort()) {\n try {\n const capability = parseSteerCapability(JSON.parse(fsImpl.readFileSync(path.join(dir, entry), 'utf-8')));\n if (capability) capabilities.push(capability);\n } catch {\n // A partially written or malformed capability is ignored until a valid one arrives.\n }\n }\n return capabilities;\n}\n\nexport function consumeSteerAcks(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'readdirSync' | 'readFileSync' | 'rmSync'> = fs,\n): SteerAck[] {\n const root = path.join(controlInboxDir(asyncDir), STEER_ACKS_DIR);\n if (!fsImpl.existsSync(root)) return [];\n const acks: SteerAck[] = [];\n let indexNames: string[];\n try {\n indexNames = fsImpl.readdirSync(root).filter((name) => /^\\d+$/.test(name));\n } catch {\n return [];\n }\n for (const indexName of indexNames) {\n const dir = path.join(root, indexName);\n let entries: string[];\n try {\n entries = fsImpl\n .readdirSync(dir)\n .filter((name) => name.endsWith('.json'))\n .sort();\n } catch {\n continue;\n }\n for (const entry of entries) {\n const target = path.join(dir, entry);\n let ack: SteerAck | undefined;\n try {\n ack = parseSteerAck(JSON.parse(fsImpl.readFileSync(target, 'utf-8')));\n } catch {\n ack = undefined;\n }\n // FIX 2: a missing ack file just means another reader already took it;\n // any other failure means this ack's fate is unknown and must not be\n // reported as delivered, so it is not pushed and the error propagates.\n removeIfPresent(target, fsImpl);\n if (ack) acks.push(ack);\n }\n }\n return acks;\n}\n\n/**\n * Consume one request-specific acknowledgment without touching concurrent\n * callers' files. The request id determines the exact file name, so two\n * parents waiting on different steering requests cannot steal each other's\n * result.\n */\nexport function consumeSteerAck(\n asyncDir: string,\n index: number,\n requestId: string,\n fsImpl: Pick<typeof fs, 'readFileSync' | 'rmSync'> = fs,\n): SteerAck | undefined {\n const target = steerAckPathFromDir(steerAcksDir(asyncDir, index), requestId);\n let ack: SteerAck | undefined;\n try {\n ack = parseSteerAck(JSON.parse(fsImpl.readFileSync(target, 'utf-8')));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n removeIfPresent(target, fsImpl);\n if (!ack || ack.requestId !== requestId || ack.index !== index) return undefined;\n return ack;\n}\n\nexport function consumeInterruptRequest(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'rmSync'> = fs,\n): boolean {\n const requestPath = interruptRequestPath(asyncDir);\n if (!fsImpl.existsSync(requestPath)) return false;\n removeIfPresent(requestPath, fsImpl);\n return true;\n}\n\nexport function consumeTimeoutRequest(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'rmSync'> = fs,\n): boolean {\n const requestPath = timeoutRequestPath(asyncDir);\n if (!fsImpl.existsSync(requestPath)) return false;\n removeIfPresent(requestPath, fsImpl);\n return true;\n}\n\nexport function consumeStopRequest(asyncDir: string, fsImpl: Pick<typeof fs, 'existsSync' | 'rmSync'> = fs): boolean {\n const requestPath = stopRequestPath(asyncDir);\n if (!fsImpl.existsSync(requestPath)) return false;\n removeIfPresent(requestPath, fsImpl);\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// FIX 1: claim by rename, dispatch what was claimed, commit or release.\n// ---------------------------------------------------------------------------\n\n/** A steer request removed from the queue by an atomic rename, awaiting dispatch. */\nexport interface ClaimedSteerRequest {\n request: SteerRequest;\n /** Call once dispatch has returned successfully. Permanently deletes the claimed file. */\n commit: () => void;\n /** Call when dispatch threw. Renames the file back so the next scan retries it. */\n release: () => void;\n}\n\n/**\n * Atomically move one queued request out of `dir`, or report the loss to\n * another consumer.\n *\n * `renameSync` on `original` is what decides a single winner: if two\n * consumers both listed `dir` and both attempt this for the same\n * `entryName`, exactly one rename succeeds and the other's source no longer\n * exists, which surfaces as `ENOENT` here regardless of what destination name\n * either consumer chose.\n */\nfunction claimSteerRequestFile(\n dir: string,\n entryName: string,\n claimant: string,\n fsImpl: Pick<typeof fs, 'renameSync'>,\n): string | undefined {\n const original = path.join(dir, entryName);\n const claimed = `${original}${CLAIM_SUFFIX_PREFIX}${claimant}`;\n try {\n fsImpl.renameSync(original, claimed);\n return claimed;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\n/**\n * Claim every currently queued, parseable steer request in `dir`.\n *\n * Each returned entry has already been renamed out of the queue, so nothing\n * else will claim it again; it is the caller's obligation to call exactly one\n * of `commit()` (dispatch succeeded) or `release()` (dispatch threw) for\n * every entry returned, so nothing is left claimed and stranded.\n */\nexport function claimSteerRequestsFromDir(\n dir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'renameSync' | 'rmSync' | 'readdirSync' | 'readFileSync'> = fs,\n claimant: string = randomUUID(),\n): ClaimedSteerRequest[] {\n if (!fsImpl.existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = fsImpl\n .readdirSync(dir)\n .filter((name) => name.endsWith('.json'))\n .sort();\n } catch {\n // Leave requests in place so the next scan can retry the listing.\n return [];\n }\n const claims: ClaimedSteerRequest[] = [];\n for (const entryName of entries) {\n const claimedPath = claimSteerRequestFile(dir, entryName, claimant, fsImpl);\n if (!claimedPath) continue; // Lost the race to another consumer, or already gone.\n const originalPath = path.join(dir, entryName);\n let parsed: SteerRequest | undefined;\n try {\n parsed = parseSteerRequest(JSON.parse(fsImpl.readFileSync(claimedPath, 'utf-8')));\n } catch {\n parsed = undefined;\n }\n if (!parsed) {\n // Corrupt or unparseable: nothing can dispatch it, and it is not\n // something a future poll should keep retrying forever.\n removeIfPresent(claimedPath, fsImpl);\n continue;\n }\n let settled = false;\n claims.push({\n request: parsed,\n commit: () => {\n if (settled) return;\n settled = true;\n removeIfPresent(claimedPath, fsImpl);\n },\n release: () => {\n if (settled) return;\n settled = true;\n try {\n fsImpl.renameSync(claimedPath, originalPath);\n } catch {\n // The original name is occupied (astronomically unlikely - it is\n // keyed by timestamp and id) or the directory is gone. Either way\n // there is nothing left to preserve by retrying the rename; drop\n // the claimed copy rather than leave an unreachable file on disk.\n removeIfPresent(claimedPath, fsImpl);\n }\n },\n });\n }\n return claims.sort(\n (left, right) => left.request.ts - right.request.ts || left.request.id.localeCompare(right.request.id),\n );\n}\n\nexport function claimSteerRequests(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'renameSync' | 'rmSync' | 'readdirSync' | 'readFileSync'> = fs,\n claimant: string = randomUUID(),\n): ClaimedSteerRequest[] {\n return claimSteerRequestsFromDir(steerRequestsDir(asyncDir), fsImpl, claimant);\n}\n\n// ---------------------------------------------------------------------------\n// Parent-side portable delivery. Authoritative file request + best-effort OS\n// signal; the signal is only a latency optimization on Unix, and `ENOSYS` on\n// Windows is expected and swallowed because the file inbox is authoritative\n// there. Other signal failures are surfaced because they usually mean the\n// runner is not alive to consume the request.\n// ---------------------------------------------------------------------------\n\nexport function deliverInterruptRequest(input: {\n asyncDir: string;\n pid?: number;\n kill?: KillFn;\n signal?: NodeJS.Signals;\n now?: () => number;\n source?: string;\n}): void {\n const requestPath = requestAsyncInterrupt(input.asyncDir, input.source ? { source: input.source } : {}, {\n now: input.now,\n });\n if (typeof input.pid === 'number' && input.pid > 0) {\n try {\n const kill = input.kill ?? ((pid: number, signal?: NodeJS.Signals | 0) => process.kill(pid, signal));\n kill(input.pid, input.signal ?? INTERRUPT_SIGNAL);\n } catch (error) {\n if ((error as NodeJS.ErrnoException | undefined)?.code === 'ENOSYS') {\n // File inbox is authoritative when custom cross-process signals are unavailable.\n return;\n }\n try {\n fs.rmSync(requestPath, { force: true });\n } catch {\n // Best effort cleanup; the caller still gets the signal failure.\n }\n throw error;\n }\n }\n}\n\nexport function deliverTimeoutRequest(input: {\n asyncDir: string;\n pid?: number;\n kill?: KillFn;\n signal?: NodeJS.Signals;\n now?: () => number;\n source?: string;\n}): void {\n requestAsyncTimeout(input.asyncDir, input.source ? { source: input.source } : {}, { now: input.now });\n}\n\nexport function deliverStopRequest(input: {\n asyncDir: string;\n pid?: number;\n kill?: KillFn;\n signal?: NodeJS.Signals;\n now?: () => number;\n source?: string;\n}): void {\n requestAsyncStop(input.asyncDir, input.source ? { source: input.source } : {}, { now: input.now });\n}\n\n// ---------------------------------------------------------------------------\n// Runner side: watch the inbox and route requests into caller-supplied\n// handlers. See the module header for why this is a `PollScheduler`\n// subscriber rather than an owned timer.\n// ---------------------------------------------------------------------------\n\nexport interface ControlChannelWatchHandlers {\n onInterrupt: () => void;\n onTimeout?: () => void;\n onStop?: () => void;\n onSteer?: (request: SteerRequest) => void;\n onSteerCapability?: (capability: SteerCapability) => void;\n onSteerAck?: (ack: SteerAck) => void;\n}\n\nexport interface ControlChannelWatchOptions {\n /** Poll safety-net cadence for this watch, overriding the service default. */\n intervalMs?: number;\n fs?: ControlChannelFs;\n}\n\nexport interface IControlChannelWatcher {\n /**\n * Start watching `asyncDir`'s control inbox. Fires the matching handler for\n * each distinct request, once. Returns a disposer.\n */\n watch(asyncDir: string, handlers: ControlChannelWatchHandlers, options?: ControlChannelWatchOptions): () => void;\n}\n\n@injectable()\nexport class ControlChannelWatcher implements IControlChannelWatcher {\n /**\n * Seam for tests, as a protected member rather than a constructor\n * argument: inversify cannot resolve a primitive. See `pollScheduler.ts`\n * and `agents/discovery.ts` for the same pattern.\n */\n protected readonly intervalMs: number = DEFAULT_CONTROL_CHANNEL_POLL_INTERVAL_MS;\n\n constructor(@inject(DOOM_TEAM_TYPES.PollScheduler) private readonly scheduler: IPollScheduler) {}\n\n watch(asyncDir: string, handlers: ControlChannelWatchHandlers, options: ControlChannelWatchOptions = {}): () => void {\n const fsImpl = options.fs ?? fs;\n const dir = controlInboxDir(asyncDir);\n try {\n fsImpl.mkdirSync(dir, { recursive: true });\n } catch {\n // Best effort - check() below tolerates a missing dir.\n }\n\n const claimant = `${process.pid}-${randomUUID()}`;\n let disposed = false;\n\n const run = (): boolean => {\n if (disposed) return false;\n return this.check(asyncDir, handlers, fsImpl, claimant);\n };\n\n // A request may already be waiting before this watcher starts. Its error,\n // if any, is allowed to throw out of `watch()` here: the scheduled\n // subscription below is not registered yet to report it, and a control\n // channel broken before the first check ever runs should fail loudly\n // rather than start silently degraded.\n run();\n\n const unregister = this.scheduler.register({\n id: `control-channel:${asyncDir}`,\n intervalMs: options.intervalMs ?? this.intervalMs,\n run,\n });\n\n let watcher: fs.FSWatcher | undefined;\n try {\n watcher = fsImpl.watch(resolveWatchPath(dir, fsImpl.realpathSync.native), () => {\n if (!disposed) this.scheduler.wake();\n });\n watcher.on?.('error', () => {\n // fs.watch can emit on transient FS errors; the poll subscription\n // above keeps this live regardless.\n });\n } catch {\n watcher = undefined;\n }\n\n return () => {\n if (disposed) return;\n disposed = true;\n try {\n watcher?.close();\n } catch {\n // ignore\n }\n unregister();\n };\n }\n\n /**\n * One pass over every request kind. Returns whether anything was actually\n * consumed, which is what lets `PollScheduler`'s idle backoff reset.\n *\n * Steer capabilities are deliberately excluded from that signal: unlike\n * every other request kind, a capability file is not consumed here (it\n * represents current state, not a one-time event), so counting its mere\n * presence as \"work\" would pin this subscription at its floor interval for\n * as long as any child has ever registered one.\n *\n * A steer dispatch that throws does not abort the pass: every claim is\n * either committed or released before this returns (FIX 1), and any error\n * is collected and rethrown last so one failing message cannot starve the\n * others claimed in the same pass.\n */\n private check(\n asyncDir: string,\n handlers: ControlChannelWatchHandlers,\n fsImpl: ControlChannelFs,\n claimant: string,\n ): boolean {\n let workHappened = false;\n\n if (consumeStopRequest(asyncDir, fsImpl)) {\n handlers.onStop?.();\n workHappened = true;\n }\n if (consumeTimeoutRequest(asyncDir, fsImpl)) {\n handlers.onTimeout?.();\n workHappened = true;\n }\n if (consumeInterruptRequest(asyncDir, fsImpl)) {\n handlers.onInterrupt();\n workHappened = true;\n }\n\n let firstError: unknown;\n for (const claim of claimSteerRequests(asyncDir, fsImpl, claimant)) {\n try {\n handlers.onSteer?.(claim.request);\n claim.commit();\n workHappened = true;\n } catch (error) {\n claim.release();\n firstError ??= error;\n }\n }\n\n for (const capability of consumeSteerCapabilities(asyncDir, fsImpl)) handlers.onSteerCapability?.(capability);\n // The child runner writes acknowledgments for its parent. A watcher that\n // has no acknowledgment handler must leave those files untouched, or it\n // races the parent and consumes its own outbound acknowledgment.\n if (handlers.onSteerAck) {\n for (const ack of consumeSteerAcks(asyncDir, fsImpl)) {\n handlers.onSteerAck(ack);\n workHappened = true;\n }\n }\n\n if (firstError !== undefined) throw firstError;\n return workHappened;\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{__esmMin as e}from"../_virtual/_rolldown/runtime.mjs";import{init_configDir as t,resolveWatchPath as n}from"../shared/configDir.mjs";import{init_atomicJson as r,writeAtomicJson as i}from"../shared/atomicJson.mjs";import{__decorate as a,init_decorate as o}from"../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs";import{DOOM_TEAM_TYPES as s,init_types as c}from"../container/types.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 ee}from"../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.mjs";import*as f from"node:fs";import*as p from"node:path";import{inject as m,injectable as h}from"inversify";import{randomUUID as g}from"node:crypto";function _(e){return p.join(e,`control`)}function v(e){return p.join(_(e),`interrupt.json`)}function te(e){return p.join(_(e),`timeout.json`)}function y(e){return p.join(_(e),`stop.json`)}function b(e){return p.join(_(e),V)}function x(e){return p.join(_(e),G)}function ne(e,t){return E(t),p.join(_(e),H,String(t))}function S(e){return p.join(_(e),U)}function re(e,t){return E(t),p.join(S(e),`${t}.json`)}function C(e,t){return E(t),p.join(_(e),W,String(t))}function w(e){return`${Buffer.from(e).toString(`base64url`)}.json`}function T(e,t){if(!/^[^\s]+$/.test(t)||t.length>Y)throw Error(`steer acknowledgment requestId is invalid.`);return p.join(e,w(t))}function E(e){if(!Number.isInteger(e)||e<0||e>q)throw Error(`steer child index must be a non-negative integer.`)}function ie(e){return`${String(e.ts).padStart(13,`0`)}-${Buffer.from(e.id).toString(`base64url`)}.json`}function D(e){return e.type===`steer`&&typeof e.id==`string`&&/^[^\s]+$/.test(e.id)&&e.id.length<=Y&&typeof e.ts==`number`&&Number.isFinite(e.ts)&&e.ts>0&&typeof e.message==`string`&&!!e.message.trim()&&Buffer.byteLength(e.message,`utf8`)<=K&&(e.targetIndex===void 0||Number.isInteger(e.targetIndex)&&e.targetIndex>=0&&e.targetIndex<=q)&&(e.targetIndexes===void 0||e.targetIndex===void 0&&Array.isArray(e.targetIndexes)&&e.targetIndexes.length>0&&e.targetIndexes.length<=J&&e.targetIndexes.every(e=>Number.isInteger(e)&&e>=0&&e<=q)&&new Set(e.targetIndexes).size===e.targetIndexes.length)&&(e.source===void 0||typeof e.source==`string`&&!!e.source.trim()&&e.source.length<=256)}function ae(e,t){if(!D(t))throw Error(`steer request is malformed or exceeds transport limits.`);let n=p.join(e,ie(t));return i(n,t),n}function oe(e,t){if(E(t.index),!Number.isInteger(t.pid)||t.pid<=0)throw Error(`steer capability pid must be a positive integer.`);if(!Number.isFinite(t.readyAt)||t.readyAt<=0)throw Error(`steer capability readyAt must be a finite timestamp.`);return i(e,{type:`steer-capability`,protocolVersion:1,...t}),e}function se(e,t){if(E(t.index),!/^[^\s]+$/.test(t.requestId)||t.requestId.length>Y)throw Error(`steer acknowledgment requestId is invalid.`);if(!Number.isFinite(t.ts)||t.ts<=0)throw Error(`steer acknowledgment ts must be a finite timestamp.`);if(!t.message.trim()||t.message.length>X)throw Error(`steer acknowledgment message is invalid.`);return i(e,{type:`steer-ack`,protocolVersion:1,...t,message:t.message.trim()}),e}function ce(e,t={},n={}){let r=v(e);return i(r,{...t,ts:t.ts??n.now?.()??Date.now(),type:`interrupt`}),r}function le(e,t={},n={}){let r=y(e);return i(r,{...t,ts:t.ts??n.now?.()??Date.now(),type:`stop`}),r}function ue(e,t,n={}){let r=t.message.trim();if(!r)throw Error(`steer message must not be empty.`);if(Buffer.byteLength(r,`utf8`)>K)throw Error(`steer message exceeds ${K} UTF-8 bytes.`);if(t.targetIndex!==void 0&&(!Number.isInteger(t.targetIndex)||t.targetIndex<0||t.targetIndex>q))throw Error(`steer targetIndex must be an integer between 0 and 1000000.`);if(t.targetIndexes!==void 0&&(!Array.isArray(t.targetIndexes)||t.targetIndex!==void 0||t.targetIndexes.length===0||t.targetIndexes.length>J||t.targetIndexes.some(e=>!Number.isInteger(e)||e<0||e>q)||new Set(t.targetIndexes).size!==t.targetIndexes.length))throw Error(`steer targetIndexes must contain 1-1000 unique non-negative integers and cannot be combined with targetIndex.`);let i=x(e);if(f.existsSync(i))throw Error(`Async run no longer accepts steering requests.`);let a={type:`steer`,id:t.id??n.randomId?.()??g(),ts:t.ts??n.now?.()??Date.now(),message:r,...t.targetIndex===void 0?{}:{targetIndex:t.targetIndex},...t.targetIndexes===void 0?{}:{targetIndexes:[...t.targetIndexes]},...t.source?{source:t.source}:{}},o=ae(b(e),a);if(f.existsSync(i))throw f.rmSync(o,{force:!0}),Error(`Async run stopped accepting steering before the request was committed.`);return o}function de(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(t.type!==`steer-capability`||t.protocolVersion!==1)return;let n=t.index,r=t.pid,i=t.readyAt;if(!(typeof n!=`number`||!Number.isInteger(n)||n<0||n>q)&&!(typeof r!=`number`||!Number.isInteger(r)||r<=0)&&!(typeof i!=`number`||!Number.isFinite(i)||i<=0)&&typeof t.supported==`boolean`)return{type:`steer-capability`,protocolVersion:1,index:n,pid:r,readyAt:i,supported:t.supported}}function O(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(t.type!==`steer-ack`||t.protocolVersion!==1||typeof t.requestId!=`string`||!/^[^\s]+$/.test(t.requestId)||t.requestId.length>Y)return;let n=t.index,r=t.ts;if(!(typeof n!=`number`||!Number.isInteger(n)||n<0||n>q)&&!(typeof r!=`number`||!Number.isFinite(r)||r<=0)&&!(t.state!==`delivered`&&t.state!==`failed`)&&!(typeof t.message!=`string`||!t.message.trim()||t.message.length>1e3))return{type:`steer-ack`,protocolVersion:1,requestId:t.requestId,index:n,ts:r,state:t.state,message:t.message.trim()}}function k(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(D(t))return{type:`steer`,id:t.id.trim(),ts:t.ts,message:t.message.trim(),...t.targetIndex===void 0?{}:{targetIndex:t.targetIndex},...t.targetIndexes===void 0?{}:{targetIndexes:[...t.targetIndexes]},...typeof t.source==`string`&&t.source.trim()?{source:t.source}:{}}}function A(e,t){try{t.rmSync(e,{recursive:!0})}catch(e){if(e.code===`ENOENT`)return;throw e}}function j(e,t=f){let n=S(e);if(!t.existsSync(n))return[];let r=[];for(let e of t.readdirSync(n).filter(e=>/^\d+\.json$/.test(e)).sort())try{let i=de(JSON.parse(t.readFileSync(p.join(n,e),`utf-8`)));i&&r.push(i)}catch{}return r}function M(e,t=f){let n=p.join(_(e),W);if(!t.existsSync(n))return[];let r=[],i;try{i=t.readdirSync(n).filter(e=>/^\d+$/.test(e))}catch{return[]}for(let e of i){let i=p.join(n,e),a;try{a=t.readdirSync(i).filter(e=>e.endsWith(`.json`)).sort()}catch{continue}for(let e of a){let n=p.join(i,e),a;try{a=O(JSON.parse(t.readFileSync(n,`utf-8`)))}catch{a=void 0}A(n,t),a&&r.push(a)}}return r}function N(e,t,n,r=f){let i=T(C(e,t),n),a;try{a=O(JSON.parse(r.readFileSync(i,`utf-8`)))}catch(e){if(e.code===`ENOENT`)return;throw e}if(A(i,r),!(!a||a.requestId!==n||a.index!==t))return a}function P(e,t=f){let n=v(e);return t.existsSync(n)?(A(n,t),!0):!1}function F(e,t=f){let n=te(e);return t.existsSync(n)?(A(n,t),!0):!1}function I(e,t=f){let n=y(e);return t.existsSync(n)?(A(n,t),!0):!1}function L(e,t,n,r){let i=p.join(e,t),a=`${i}${Z}${n}`;try{return r.renameSync(i,a),a}catch(e){if(e.code===`ENOENT`)return;throw e}}function R(e,t=f,n=g()){if(!t.existsSync(e))return[];let r;try{r=t.readdirSync(e).filter(e=>e.endsWith(`.json`)).sort()}catch{return[]}let i=[];for(let a of r){let r=L(e,a,n,t);if(!r)continue;let o=p.join(e,a),s;try{s=k(JSON.parse(t.readFileSync(r,`utf-8`)))}catch{s=void 0}if(!s){A(r,t);continue}let c=!1;i.push({request:s,commit:()=>{c||(c=!0,A(r,t))},release:()=>{if(!c){c=!0;try{t.renameSync(r,o)}catch{A(r,t)}}}})}return i.sort((e,t)=>e.request.ts-t.request.ts||e.request.id.localeCompare(t.request.id))}function z(e,t=f,n=g()){return R(b(e),t,n)}var B,V,H,U,W,G,K,q,J,Y,X,Z,Q,$=e((()=>{c(),t(),r(),u(),ee(),o(),process.platform,B=1e3,V=`steer-requests`,H=`steer-targets`,U=`steer-capabilities`,W=`steer-acks`,G=`steer-inbox-closed.json`,K=128*1024,q=1e6,J=1e3,Y=256,X=1e3,Z=`.claim-`,Q=class{intervalMs=B;constructor(e){this.scheduler=e}watch(e,t,r={}){let i=r.fs??f,a=_(e);try{i.mkdirSync(a,{recursive:!0})}catch{}let o=`${process.pid}-${g()}`,s=!1,c=()=>s?!1:this.check(e,t,i,o);c();let l=this.scheduler.register({id:`control-channel:${e}`,intervalMs:r.intervalMs??this.intervalMs,run:c}),u;try{u=i.watch(n(a,i.realpathSync.native),()=>{s||this.scheduler.wake()}),u.on?.(`error`,()=>{})}catch{u=void 0}return()=>{if(!s){s=!0;try{u?.close()}catch{}l()}}}check(e,t,n,r){let i=!1;I(e,n)&&(t.onStop?.(),i=!0),F(e,n)&&(t.onTimeout?.(),i=!0),P(e,n)&&(t.onInterrupt(),i=!0);let a;for(let o of z(e,n,r))try{t.onSteer?.(o.request),o.commit(),i=!0}catch(e){o.release(),a??=e}for(let r of j(e,n))t.onSteerCapability?.(r);if(t.onSteerAck)for(let r of M(e,n))t.onSteerAck(r),i=!0;if(a!==void 0)throw a;return i}},Q=a([h(),d(0,m(s.PollScheduler)),l(`design:paramtypes`,[Object])],Q)}));$();export{Q as ControlChannelWatcher,R as claimSteerRequestsFromDir,N as consumeSteerAck,$ as init_supervisorControlChannel,ce as requestAsyncInterrupt,ue as requestAsyncSteer,le as requestAsyncStop,T as steerAckPathFromDir,C as steerAcksDir,re as steerCapabilityPath,ne as stepSteerInboxDir,se as writeSteerAckAt,oe as writeSteerCapabilityAt};
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{init_configDir as a,resolveWatchPath as o}from"../../shared/configDir.mjs";import{writeAtomicJson as s}from"../../adapters/atomicJson.mjs";import{init_atomicJson as c}from"../../shared/atomicJson.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 ee}from"../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.mjs";import*as f from"node:fs";import*as p from"node:path";import{inject as m,injectable as h}from"inversify";import{randomUUID as g}from"node:crypto";function _(e){return p.join(e,`control`)}function v(e){return p.join(_(e),`interrupt.json`)}function te(e){return p.join(_(e),`timeout.json`)}function y(e){return p.join(_(e),`stop.json`)}function b(e){return p.join(_(e),V)}function x(e){return p.join(_(e),G)}function ne(e,t){return E(t),p.join(_(e),H,String(t))}function S(e){return p.join(_(e),U)}function re(e,t){return E(t),p.join(S(e),`${t}.json`)}function C(e,t){return E(t),p.join(_(e),W,String(t))}function w(e){return`${Buffer.from(e).toString(`base64url`)}.json`}function T(e,t){if(!/^[^\s]+$/.test(t)||t.length>Y)throw Error(`steer acknowledgment requestId is invalid.`);return p.join(e,w(t))}function E(e){if(!Number.isInteger(e)||e<0||e>q)throw Error(`steer child index must be a non-negative integer.`)}function ie(e){return`${String(e.ts).padStart(13,`0`)}-${Buffer.from(e.id).toString(`base64url`)}.json`}function D(e){return e.type===`steer`&&typeof e.id==`string`&&/^[^\s]+$/.test(e.id)&&e.id.length<=Y&&typeof e.ts==`number`&&Number.isFinite(e.ts)&&e.ts>0&&typeof e.message==`string`&&!!e.message.trim()&&Buffer.byteLength(e.message,`utf8`)<=K&&(e.targetIndex===void 0||Number.isInteger(e.targetIndex)&&e.targetIndex>=0&&e.targetIndex<=q)&&(e.targetIndexes===void 0||e.targetIndex===void 0&&Array.isArray(e.targetIndexes)&&e.targetIndexes.length>0&&e.targetIndexes.length<=J&&e.targetIndexes.every(e=>Number.isInteger(e)&&e>=0&&e<=q)&&new Set(e.targetIndexes).size===e.targetIndexes.length)&&(e.source===void 0||typeof e.source==`string`&&!!e.source.trim()&&e.source.length<=256)}function ae(e,t){if(!D(t))throw Error(`steer request is malformed or exceeds transport limits.`);let n=p.join(e,ie(t));return s(n,t),n}function oe(e,t){if(E(t.index),!Number.isInteger(t.pid)||t.pid<=0)throw Error(`steer capability pid must be a positive integer.`);if(!Number.isFinite(t.readyAt)||t.readyAt<=0)throw Error(`steer capability readyAt must be a finite timestamp.`);return s(e,{type:`steer-capability`,protocolVersion:1,...t}),e}function se(e,t){if(E(t.index),!/^[^\s]+$/.test(t.requestId)||t.requestId.length>Y)throw Error(`steer acknowledgment requestId is invalid.`);if(!Number.isFinite(t.ts)||t.ts<=0)throw Error(`steer acknowledgment ts must be a finite timestamp.`);if(!t.message.trim()||t.message.length>X)throw Error(`steer acknowledgment message is invalid.`);return s(e,{type:`steer-ack`,protocolVersion:1,...t,message:t.message.trim()}),e}function ce(e,t={},n={}){let r=v(e);return s(r,{...t,ts:t.ts??n.now?.()??Date.now(),type:`interrupt`}),r}function le(e,t={},n={}){let r=y(e);return s(r,{...t,ts:t.ts??n.now?.()??Date.now(),type:`stop`}),r}function ue(e,t,n={}){let r=t.message.trim();if(!r)throw Error(`steer message must not be empty.`);if(Buffer.byteLength(r,`utf8`)>K)throw Error(`steer message exceeds ${K} UTF-8 bytes.`);if(t.targetIndex!==void 0&&(!Number.isInteger(t.targetIndex)||t.targetIndex<0||t.targetIndex>q))throw Error(`steer targetIndex must be an integer between 0 and 1000000.`);if(t.targetIndexes!==void 0&&(!Array.isArray(t.targetIndexes)||t.targetIndex!==void 0||t.targetIndexes.length===0||t.targetIndexes.length>J||t.targetIndexes.some(e=>!Number.isInteger(e)||e<0||e>q)||new Set(t.targetIndexes).size!==t.targetIndexes.length))throw Error(`steer targetIndexes must contain 1-1000 unique non-negative integers and cannot be combined with targetIndex.`);let i=x(e);if(f.existsSync(i))throw Error(`Async run no longer accepts steering requests.`);let a={type:`steer`,id:t.id??n.randomId?.()??g(),ts:t.ts??n.now?.()??Date.now(),message:r,...t.targetIndex===void 0?{}:{targetIndex:t.targetIndex},...t.targetIndexes===void 0?{}:{targetIndexes:[...t.targetIndexes]},...t.source?{source:t.source}:{}},o=ae(b(e),a);if(f.existsSync(i))throw f.rmSync(o,{force:!0}),Error(`Async run stopped accepting steering before the request was committed.`);return o}function de(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(t.type!==`steer-capability`||t.protocolVersion!==1)return;let n=t.index,r=t.pid,i=t.readyAt;if(!(typeof n!=`number`||!Number.isInteger(n)||n<0||n>q)&&!(typeof r!=`number`||!Number.isInteger(r)||r<=0)&&!(typeof i!=`number`||!Number.isFinite(i)||i<=0)&&typeof t.supported==`boolean`)return{type:`steer-capability`,protocolVersion:1,index:n,pid:r,readyAt:i,supported:t.supported}}function O(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(t.type!==`steer-ack`||t.protocolVersion!==1||typeof t.requestId!=`string`||!/^[^\s]+$/.test(t.requestId)||t.requestId.length>Y)return;let n=t.index,r=t.ts;if(!(typeof n!=`number`||!Number.isInteger(n)||n<0||n>q)&&!(typeof r!=`number`||!Number.isFinite(r)||r<=0)&&!(t.state!==`delivered`&&t.state!==`failed`)&&!(typeof t.message!=`string`||!t.message.trim()||t.message.length>1e3))return{type:`steer-ack`,protocolVersion:1,requestId:t.requestId,index:n,ts:r,state:t.state,message:t.message.trim()}}function k(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(D(t))return{type:`steer`,id:t.id.trim(),ts:t.ts,message:t.message.trim(),...t.targetIndex===void 0?{}:{targetIndex:t.targetIndex},...t.targetIndexes===void 0?{}:{targetIndexes:[...t.targetIndexes]},...typeof t.source==`string`&&t.source.trim()?{source:t.source}:{}}}function A(e,t){try{t.rmSync(e,{recursive:!0})}catch(e){if(e.code===`ENOENT`)return;throw e}}function j(e,t=f){let n=S(e);if(!t.existsSync(n))return[];let r=[];for(let e of t.readdirSync(n).filter(e=>/^\d+\.json$/.test(e)).sort())try{let i=de(JSON.parse(t.readFileSync(p.join(n,e),`utf-8`)));i&&r.push(i)}catch{}return r}function M(e,t=f){let n=p.join(_(e),W);if(!t.existsSync(n))return[];let r=[],i;try{i=t.readdirSync(n).filter(e=>/^\d+$/.test(e))}catch{return[]}for(let e of i){let i=p.join(n,e),a;try{a=t.readdirSync(i).filter(e=>e.endsWith(`.json`)).sort()}catch{continue}for(let e of a){let n=p.join(i,e),a;try{a=O(JSON.parse(t.readFileSync(n,`utf-8`)))}catch{a=void 0}A(n,t),a&&r.push(a)}}return r}function N(e,t,n,r=f){let i=T(C(e,t),n),a;try{a=O(JSON.parse(r.readFileSync(i,`utf-8`)))}catch(e){if(e.code===`ENOENT`)return;throw e}if(A(i,r),!(!a||a.requestId!==n||a.index!==t))return a}function P(e,t=f){let n=v(e);return t.existsSync(n)?(A(n,t),!0):!1}function F(e,t=f){let n=te(e);return t.existsSync(n)?(A(n,t),!0):!1}function I(e,t=f){let n=y(e);return t.existsSync(n)?(A(n,t),!0):!1}function L(e,t,n,r){let i=p.join(e,t),a=`${i}${Z}${n}`;try{return r.renameSync(i,a),a}catch(e){if(e.code===`ENOENT`)return;throw e}}function R(e,t=f,n=g()){if(!t.existsSync(e))return[];let r;try{r=t.readdirSync(e).filter(e=>e.endsWith(`.json`)).sort()}catch{return[]}let i=[];for(let a of r){let r=L(e,a,n,t);if(!r)continue;let o=p.join(e,a),s;try{s=k(JSON.parse(t.readFileSync(r,`utf-8`)))}catch{s=void 0}if(!s){A(r,t);continue}let c=!1;i.push({request:s,commit:()=>{c||(c=!0,A(r,t))},release:()=>{if(!c){c=!0;try{t.renameSync(r,o)}catch{A(r,t)}}}})}return i.sort((e,t)=>e.request.ts-t.request.ts||e.request.id.localeCompare(t.request.id))}function z(e,t=f,n=g()){return R(b(e),t,n)}var B,V,H,U,W,G,K,q,J,Y,X,Z,Q,$=e((()=>{i(),c(),a(),u(),ee(),n(),process.platform,B=1e3,V=`steer-requests`,H=`steer-targets`,U=`steer-capabilities`,W=`steer-acks`,G=`steer-inbox-closed.json`,K=128*1024,q=1e6,J=1e3,Y=256,X=1e3,Z=`.claim-`,Q=class{intervalMs=B;constructor(e){this.scheduler=e}watch(e,t,n={}){let r=n.fs??f,i=_(e);try{r.mkdirSync(i,{recursive:!0})}catch{}let a=`${process.pid}-${g()}`,s=!1,c=()=>s?!1:this.check(e,t,r,a);c();let l=this.scheduler.register({id:`control-channel:${e}`,intervalMs:n.intervalMs??this.intervalMs,run:c}),u;try{u=r.watch(o(i,r.realpathSync.native),()=>{s||this.scheduler.wake()}),u.on?.(`error`,()=>{})}catch{u=void 0}return()=>{if(!s){s=!0;try{u?.close()}catch{}l()}}}check(e,t,n,r){let i=!1;I(e,n)&&(t.onStop?.(),i=!0),F(e,n)&&(t.onTimeout?.(),i=!0),P(e,n)&&(t.onInterrupt(),i=!0);let a;for(let o of z(e,n,r))try{t.onSteer?.(o.request),o.commit(),i=!0}catch(e){o.release(),a??=e}for(let r of j(e,n))t.onSteerCapability?.(r);if(t.onSteerAck)for(let r of M(e,n))t.onSteerAck(r),i=!0;if(a!==void 0)throw a;return i}},Q=t([h(),d(0,m(r.PollScheduler)),l(`design:paramtypes`,[Object])],Q)}));$();export{Q as ControlChannelWatcher,R as claimSteerRequestsFromDir,N as consumeSteerAck,$ as init_supervisorControlChannel,ce as requestAsyncInterrupt,ue as requestAsyncSteer,le as requestAsyncStop,T as steerAckPathFromDir,C as steerAcksDir,re as steerCapabilityPath,ne as stepSteerInboxDir,se as writeSteerAckAt,oe as writeSteerCapabilityAt};
2
2
  //# sourceMappingURL=supervisorControlChannel.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisorControlChannel.mjs","names":[],"sources":["../../../src/services/intercom/supervisorControlChannel.ts"],"sourcesContent":["/**\n * Cross-OS control channel for async subagent runs.\n *\n * Background runs are detached OS processes. A signal-based interrupt\n * (`process.kill(pid, SIGUSR2|SIGBREAK)`) cannot be delivered cross-process on\n * Windows and throws `ENOSYS`, which would leave async runs uninterruptible\n * (no stop, no live steer) on that platform. This module is a portable,\n * file-based control inbox inside the run directory instead: the parent drops\n * a request file, the runner watches the inbox and routes it into its own\n * interrupt handling, identically on every platform. The OS signal is kept\n * only as an opportunistic fast-path; its failure is non-fatal because the\n * file inbox is authoritative.\n *\n * FIX 1 - steer messages must survive a failed dispatch:\n * The predecessor (`doom-pi-subagents/src/runs/background/control-channel.ts`)\n * deleted a steer request file BEFORE dispatching it. A throw during dispatch\n * then lost the instruction with no trace: the user's steer vanished and\n * nothing on disk or in memory recorded that it had ever arrived. Steer\n * requests here are claimed by rename instead: `claimSteerRequestsFromDir`\n * atomically moves a request out of the queue (deciding a single winner among\n * any concurrent consumers in the same step), the caller dispatches what it\n * claimed, and only `commit()` - called after dispatch returns - deletes it.\n * A dispatch that throws calls `release()`, which renames the file back to\n * its original name so the next scan retries it. This package's own delivery\n * loop (`ControlChannelWatcher.check`) follows exactly this claim -> dispatch\n * -> commit/release shape; see `src/intercom/nativeTeamChannel.ts`'s\n * \"deliver, then mark seen\" for the same principle applied to team messages.\n *\n * Residual gap: if the process dies between claim and release (not a thrown\n * error, a hard kill), the claimed file is left under its `.claim-<id>` name\n * and no longer matches a normal directory scan. Nothing here sweeps it back.\n * That is a real gap, not an oversight - recovering from a hard process kill\n * needs a second, independent process to notice, which does not exist yet in\n * this package. What this module guarantees is the fix that was asked for and\n * that a live process can retry: a message is never lost to a dispatch that\n * merely throws.\n *\n * FIX 2 - a missing file and a permission failure are different situations:\n * one is the routine \"someone else already consumed this\" case, harmless and\n * expected; the other means this run's control channel cannot be trusted and\n * must be surfaced, not swallowed. `removeIfPresent` below is the one place\n * this module deletes a control file, and it draws exactly that line: `ENOENT`\n * is absorbed, anything else is rethrown.\n *\n * FIX 3/4 - watch-first, `PollScheduler` as the bounded safety net:\n * `ControlChannelWatcher` registers one subscription per watched run with the\n * shared `PollScheduler` (see its header) instead of owning a `setInterval`,\n * the same \"watch-first, poll as a bounded safety net\" shape `PollScheduler`\n * was built for: `fs.watch` on the inbox directory calls `wake()` for low\n * latency, and the registered subscription's own `intervalMs` is deliberately\n * loose because it exists only to cover platforms and mount types where\n * watches are unreliable, not to carry normal-case latency. This was NOT\n * given the same treatment as `SpawnHandshake` (see that module's header),\n * which explicitly opts out of `PollScheduler`: a spawn handshake is a\n * per-spawn, sub-second, self-terminating wait, where sharing the scheduler's\n * idle backoff would either pin the whole scheduler near its floor for its\n * duration or starve the wait of the low latency it needs. A control-inbox\n * watch is the opposite shape - one long-lived subscriber per run, alive for\n * the run's whole lifetime, checking infrequently - which is exactly the\n * \"channels, watchers, inspectors\" category `PollScheduler` exists to\n * coordinate.\n *\n * A subscriber's `run()` throwing is not swallowed here: it is left to\n * propagate out of `check()` so `PollScheduler.tick()` catches it and records\n * it as `lastSubscriberError`, which is what makes FIX 2's rethrown\n * permission failures actually visible instead of merely \"not silently\n * deleted\".\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { inject, injectable } from 'inversify';\n\nimport { DOOM_TEAM_TYPES } from '../../container/types.ts';\nimport { writeAtomicJson } from '../../shared/atomicJson.ts';\nimport { resolveWatchPath } from '../../shared/configDir.ts';\nimport type { IPollScheduler } from '../../shared/pollScheduler.ts';\n\n/**\n * Opportunistic fast-path interrupt signal. On Unix `SIGUSR2` is trapped by\n * the runner; on Windows `process.kill(pid, \"SIGBREAK\")` is not deliverable\n * cross-process and throws `ENOSYS`, so the file inbox below is the real\n * channel there.\n */\nexport const INTERRUPT_SIGNAL: NodeJS.Signals = process.platform === 'win32' ? 'SIGBREAK' : 'SIGUSR2';\n\n/** How generously the poll safety net is spaced. `fs.watch` is the fast path; see the module header. */\nconst DEFAULT_CONTROL_CHANNEL_POLL_INTERVAL_MS = 1_000;\n\nexport type ControlChannelFs = Pick<\n typeof fs,\n 'mkdirSync' | 'existsSync' | 'rmSync' | 'renameSync' | 'watch' | 'readdirSync' | 'readFileSync' | 'realpathSync'\n>;\ntype KillFn = (pid: number, signal?: NodeJS.Signals | 0) => unknown;\n\nexport interface InterruptRequest {\n type: 'interrupt';\n ts?: number;\n source?: string;\n reason?: string;\n}\n\nexport interface TimeoutRequest {\n type: 'timeout';\n ts?: number;\n source?: string;\n reason?: string;\n}\n\nexport interface StopRequest {\n type: 'stop';\n ts?: number;\n source?: string;\n reason?: string;\n}\n\nexport interface SteerRequest {\n type: 'steer';\n id: string;\n ts: number;\n message: string;\n targetIndex?: number;\n targetIndexes?: number[];\n source?: string;\n}\n\nexport interface SteerCapability {\n type: 'steer-capability';\n protocolVersion: 1;\n index: number;\n pid: number;\n readyAt: number;\n supported: boolean;\n}\n\nexport interface SteerAck {\n type: 'steer-ack';\n protocolVersion: 1;\n requestId: string;\n index: number;\n ts: number;\n state: 'delivered' | 'failed';\n message: string;\n}\n\nconst STEER_REQUESTS_DIR = 'steer-requests';\nconst STEER_TARGETS_DIR = 'steer-targets';\nconst STEER_CAPABILITIES_DIR = 'steer-capabilities';\nconst STEER_ACKS_DIR = 'steer-acks';\nconst STEER_INBOX_CLOSED_FILE = 'steer-inbox-closed.json';\nconst MAX_STEER_MESSAGE_BYTES = 128 * 1024;\n/**\n * Highest child index a steer may address.\n *\n * A bound rather than a real limit: it exists so a malformed or hostile\n * request cannot make the runner allocate or iterate over an absurd range.\n */\nconst MAX_STEER_TARGET_INDEX = 1_000_000;\n/** Most children one steer may address at once, for the same reason. */\nconst MAX_STEER_TARGET_COUNT = 1_000;\nconst MAX_STEER_REQUEST_ID_LENGTH = 256;\nconst MAX_STEER_ACK_MESSAGE_LENGTH = 1_000;\n/** Suffix appended to a steer request's file name while a consumer is dispatching it. */\nconst CLAIM_SUFFIX_PREFIX = '.claim-';\n\n// ---------------------------------------------------------------------------\n// Paths\n// ---------------------------------------------------------------------------\n\n/** Control inbox directory inside an async run dir. */\nexport function controlInboxDir(asyncDir: string): string {\n return path.join(asyncDir, 'control');\n}\n\n/** Path of the portable interrupt request file. */\nexport function interruptRequestPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), 'interrupt.json');\n}\n\n/** Path of the portable timeout request file. */\nexport function timeoutRequestPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), 'timeout.json');\n}\n\n/** Path of the portable manual stop request file. */\nexport function stopRequestPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), 'stop.json');\n}\n\n/** Directory of parent-to-runner steering requests. */\nexport function steerRequestsDir(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), STEER_REQUESTS_DIR);\n}\n\nexport function steerInboxClosedPath(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), STEER_INBOX_CLOSED_FILE);\n}\n\nexport function closeSteerInbox(asyncDir: string, state: string): void {\n writeAtomicJson(steerInboxClosedPath(asyncDir), { version: 1, closedAt: Date.now(), state });\n}\n\n/** Per-child inbox consumed by the child prompt runtime inside the Pi process. */\nexport function stepSteerInboxDir(asyncDir: string, index: number): string {\n assertChildIndex(index);\n return path.join(controlInboxDir(asyncDir), STEER_TARGETS_DIR, String(index));\n}\n\nexport function steerCapabilitiesDir(asyncDir: string): string {\n return path.join(controlInboxDir(asyncDir), STEER_CAPABILITIES_DIR);\n}\n\nexport function steerCapabilityPath(asyncDir: string, index: number): string {\n assertChildIndex(index);\n return path.join(steerCapabilitiesDir(asyncDir), `${index}.json`);\n}\n\nexport function steerAcksDir(asyncDir: string, index: number): string {\n assertChildIndex(index);\n return path.join(controlInboxDir(asyncDir), STEER_ACKS_DIR, String(index));\n}\n\nfunction steerAckFileName(requestId: string): string {\n return `${Buffer.from(requestId).toString('base64url')}.json`;\n}\n\nexport function steerAckPathFromDir(dir: string, requestId: string): string {\n if (!/^[^\\s]+$/.test(requestId) || requestId.length > MAX_STEER_REQUEST_ID_LENGTH)\n throw new Error('steer acknowledgment requestId is invalid.');\n return path.join(dir, steerAckFileName(requestId));\n}\n\nfunction assertChildIndex(index: number): void {\n if (!Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX)\n throw new Error('steer child index must be a non-negative integer.');\n}\n\nfunction steerRequestFileName(request: SteerRequest): string {\n return `${String(request.ts).padStart(13, '0')}-${Buffer.from(request.id).toString('base64url')}.json`;\n}\n\nfunction validSteerRequest(request: Partial<SteerRequest>): request is SteerRequest {\n return (\n request.type === 'steer' &&\n typeof request.id === 'string' &&\n /^[^\\s]+$/.test(request.id) &&\n request.id.length <= MAX_STEER_REQUEST_ID_LENGTH &&\n typeof request.ts === 'number' &&\n Number.isFinite(request.ts) &&\n request.ts > 0 &&\n typeof request.message === 'string' &&\n Boolean(request.message.trim()) &&\n Buffer.byteLength(request.message, 'utf8') <= MAX_STEER_MESSAGE_BYTES &&\n (request.targetIndex === undefined ||\n (Number.isInteger(request.targetIndex) &&\n request.targetIndex >= 0 &&\n request.targetIndex <= MAX_STEER_TARGET_INDEX)) &&\n (request.targetIndexes === undefined ||\n (request.targetIndex === undefined &&\n Array.isArray(request.targetIndexes) &&\n request.targetIndexes.length > 0 &&\n request.targetIndexes.length <= MAX_STEER_TARGET_COUNT &&\n request.targetIndexes.every(\n (index) => Number.isInteger(index) && index >= 0 && index <= MAX_STEER_TARGET_INDEX,\n ) &&\n new Set(request.targetIndexes).size === request.targetIndexes.length)) &&\n (request.source === undefined ||\n (typeof request.source === 'string' && Boolean(request.source.trim()) && request.source.length <= 256))\n );\n}\n\nexport function writeSteerRequestToDir(dir: string, request: SteerRequest): string {\n if (!validSteerRequest(request)) throw new Error('steer request is malformed or exceeds transport limits.');\n const requestPath = path.join(dir, steerRequestFileName(request));\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function writeSteerCapabilityAt(\n filePath: string,\n capability: Omit<SteerCapability, 'type' | 'protocolVersion'>,\n): string {\n assertChildIndex(capability.index);\n if (!Number.isInteger(capability.pid) || capability.pid <= 0)\n throw new Error('steer capability pid must be a positive integer.');\n if (!Number.isFinite(capability.readyAt) || capability.readyAt <= 0)\n throw new Error('steer capability readyAt must be a finite timestamp.');\n const record: SteerCapability = { type: 'steer-capability', protocolVersion: 1, ...capability };\n writeAtomicJson(filePath, record);\n return filePath;\n}\n\nexport function writeSteerCapability(\n asyncDir: string,\n capability: Omit<SteerCapability, 'type' | 'protocolVersion'>,\n): string {\n return writeSteerCapabilityAt(steerCapabilityPath(asyncDir, capability.index), capability);\n}\n\nexport function writeSteerAckAt(filePath: string, ack: Omit<SteerAck, 'type' | 'protocolVersion'>): string {\n assertChildIndex(ack.index);\n if (!/^[^\\s]+$/.test(ack.requestId) || ack.requestId.length > MAX_STEER_REQUEST_ID_LENGTH)\n throw new Error('steer acknowledgment requestId is invalid.');\n if (!Number.isFinite(ack.ts) || ack.ts <= 0) throw new Error('steer acknowledgment ts must be a finite timestamp.');\n if (!ack.message.trim() || ack.message.length > MAX_STEER_ACK_MESSAGE_LENGTH)\n throw new Error('steer acknowledgment message is invalid.');\n const record: SteerAck = { type: 'steer-ack', protocolVersion: 1, ...ack, message: ack.message.trim() };\n writeAtomicJson(filePath, record);\n return filePath;\n}\n\nexport function writeSteerAck(asyncDir: string, ack: Omit<SteerAck, 'type' | 'protocolVersion'>): string {\n return writeSteerAckAt(path.join(steerAcksDir(asyncDir, ack.index), steerAckFileName(ack.requestId)), ack);\n}\n\n/**\n * Parent side: drop a portable interrupt request the runner's inbox watcher\n * will pick up regardless of OS. Written atomically (temp + rename), dir\n * auto-created.\n */\nexport function requestAsyncInterrupt(\n asyncDir: string,\n payload: Omit<InterruptRequest, 'type'> = {},\n deps: { now?: () => number } = {},\n): string {\n const requestPath = interruptRequestPath(asyncDir);\n const request: InterruptRequest = { ...payload, ts: payload.ts ?? deps.now?.() ?? Date.now(), type: 'interrupt' };\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function requestAsyncTimeout(\n asyncDir: string,\n payload: Omit<TimeoutRequest, 'type'> = {},\n deps: { now?: () => number } = {},\n): string {\n const requestPath = timeoutRequestPath(asyncDir);\n const request: TimeoutRequest = { ...payload, ts: payload.ts ?? deps.now?.() ?? Date.now(), type: 'timeout' };\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function requestAsyncStop(\n asyncDir: string,\n payload: Omit<StopRequest, 'type'> = {},\n deps: { now?: () => number } = {},\n): string {\n const requestPath = stopRequestPath(asyncDir);\n const request: StopRequest = { ...payload, ts: payload.ts ?? deps.now?.() ?? Date.now(), type: 'stop' };\n writeAtomicJson(requestPath, request);\n return requestPath;\n}\n\nexport function requestAsyncSteer(\n asyncDir: string,\n payload: {\n message: string;\n targetIndex?: number;\n targetIndexes?: number[];\n source?: string;\n id?: string;\n ts?: number;\n },\n deps: { now?: () => number; randomId?: () => string } = {},\n): string {\n const message = payload.message.trim();\n if (!message) throw new Error('steer message must not be empty.');\n if (Buffer.byteLength(message, 'utf8') > MAX_STEER_MESSAGE_BYTES)\n throw new Error(`steer message exceeds ${MAX_STEER_MESSAGE_BYTES} UTF-8 bytes.`);\n if (\n payload.targetIndex !== undefined &&\n (!Number.isInteger(payload.targetIndex) || payload.targetIndex < 0 || payload.targetIndex > MAX_STEER_TARGET_INDEX)\n ) {\n throw new Error('steer targetIndex must be an integer between 0 and 1000000.');\n }\n if (\n payload.targetIndexes !== undefined &&\n (!Array.isArray(payload.targetIndexes) ||\n payload.targetIndex !== undefined ||\n payload.targetIndexes.length === 0 ||\n payload.targetIndexes.length > MAX_STEER_TARGET_COUNT ||\n payload.targetIndexes.some((index) => !Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX) ||\n new Set(payload.targetIndexes).size !== payload.targetIndexes.length)\n ) {\n throw new Error(\n 'steer targetIndexes must contain 1-1000 unique non-negative integers and cannot be combined with targetIndex.',\n );\n }\n const closedPath = steerInboxClosedPath(asyncDir);\n if (fs.existsSync(closedPath)) throw new Error('Async run no longer accepts steering requests.');\n const request: SteerRequest = {\n type: 'steer',\n id: payload.id ?? deps.randomId?.() ?? randomUUID(),\n ts: payload.ts ?? deps.now?.() ?? Date.now(),\n message,\n ...(payload.targetIndex !== undefined ? { targetIndex: payload.targetIndex } : {}),\n ...(payload.targetIndexes !== undefined ? { targetIndexes: [...payload.targetIndexes] } : {}),\n ...(payload.source ? { source: payload.source } : {}),\n };\n const requestPath = writeSteerRequestToDir(steerRequestsDir(asyncDir), request);\n if (fs.existsSync(closedPath)) {\n fs.rmSync(requestPath, { force: true });\n throw new Error('Async run stopped accepting steering before the request was committed.');\n }\n return requestPath;\n}\n\nexport function enqueueStepSteer(asyncDir: string, index: number, request: SteerRequest): string {\n assertChildIndex(index);\n const { targetIndexes: _targetIndexes, ...singleTargetRequest } = request;\n return writeSteerRequestToDir(stepSteerInboxDir(asyncDir, index), {\n ...singleTargetRequest,\n targetIndex: index,\n type: 'steer',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Parsing. Everything read off disk arrives as `unknown` and is narrowed here;\n// nothing is asserted into shape.\n// ---------------------------------------------------------------------------\n\nfunction parseSteerCapability(raw: unknown): SteerCapability | undefined {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const input = raw as Partial<SteerCapability>;\n if (input.type !== 'steer-capability' || input.protocolVersion !== 1) return undefined;\n const index = input.index;\n const pid = input.pid;\n const readyAt = input.readyAt;\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX)\n return undefined;\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) return undefined;\n if (typeof readyAt !== 'number' || !Number.isFinite(readyAt) || readyAt <= 0) return undefined;\n if (typeof input.supported !== 'boolean') return undefined;\n return {\n type: 'steer-capability',\n protocolVersion: 1,\n index,\n pid,\n readyAt,\n supported: input.supported,\n };\n}\n\nfunction parseSteerAck(raw: unknown): SteerAck | undefined {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const input = raw as Partial<SteerAck>;\n if (\n input.type !== 'steer-ack' ||\n input.protocolVersion !== 1 ||\n typeof input.requestId !== 'string' ||\n !/^[^\\s]+$/.test(input.requestId) ||\n input.requestId.length > MAX_STEER_REQUEST_ID_LENGTH\n )\n return undefined;\n const index = input.index;\n const ts = input.ts;\n if (typeof index !== 'number' || !Number.isInteger(index) || index < 0 || index > MAX_STEER_TARGET_INDEX)\n return undefined;\n if (typeof ts !== 'number' || !Number.isFinite(ts) || ts <= 0) return undefined;\n if (input.state !== 'delivered' && input.state !== 'failed') return undefined;\n if (typeof input.message !== 'string' || !input.message.trim() || input.message.length > 1000) return undefined;\n return {\n type: 'steer-ack',\n protocolVersion: 1,\n requestId: input.requestId,\n index,\n ts,\n state: input.state,\n message: input.message.trim(),\n };\n}\n\nfunction parseSteerRequest(raw: unknown): SteerRequest | undefined {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;\n const input = raw as Partial<SteerRequest>;\n if (!validSteerRequest(input)) return undefined;\n return {\n type: 'steer',\n id: input.id.trim(),\n ts: input.ts,\n message: input.message.trim(),\n ...(input.targetIndex !== undefined ? { targetIndex: input.targetIndex } : {}),\n ...(input.targetIndexes !== undefined ? { targetIndexes: [...input.targetIndexes] } : {}),\n ...(typeof input.source === 'string' && input.source.trim() ? { source: input.source } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Deletion. `removeIfPresent` is the one place this module deletes a control\n// file, and it is FIX 2 in one function: `ENOENT` is the routine \"someone\n// else already consumed this\" case and is absorbed; anything else means this\n// run's control channel is broken and must be surfaced to the caller.\n// ---------------------------------------------------------------------------\n\nfunction removeIfPresent(target: string, fsImpl: Pick<typeof fs, 'rmSync'>): void {\n try {\n fsImpl.rmSync(target, { recursive: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n}\n\nexport function consumeSteerCapabilities(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'readdirSync' | 'readFileSync'> = fs,\n): SteerCapability[] {\n const dir = steerCapabilitiesDir(asyncDir);\n if (!fsImpl.existsSync(dir)) return [];\n const capabilities: SteerCapability[] = [];\n for (const entry of fsImpl\n .readdirSync(dir)\n .filter((name) => /^\\d+\\.json$/.test(name))\n .sort()) {\n try {\n const capability = parseSteerCapability(JSON.parse(fsImpl.readFileSync(path.join(dir, entry), 'utf-8')));\n if (capability) capabilities.push(capability);\n } catch {\n // A partially written or malformed capability is ignored until a valid one arrives.\n }\n }\n return capabilities;\n}\n\nexport function consumeSteerAcks(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'readdirSync' | 'readFileSync' | 'rmSync'> = fs,\n): SteerAck[] {\n const root = path.join(controlInboxDir(asyncDir), STEER_ACKS_DIR);\n if (!fsImpl.existsSync(root)) return [];\n const acks: SteerAck[] = [];\n let indexNames: string[];\n try {\n indexNames = fsImpl.readdirSync(root).filter((name) => /^\\d+$/.test(name));\n } catch {\n return [];\n }\n for (const indexName of indexNames) {\n const dir = path.join(root, indexName);\n let entries: string[];\n try {\n entries = fsImpl\n .readdirSync(dir)\n .filter((name) => name.endsWith('.json'))\n .sort();\n } catch {\n continue;\n }\n for (const entry of entries) {\n const target = path.join(dir, entry);\n let ack: SteerAck | undefined;\n try {\n ack = parseSteerAck(JSON.parse(fsImpl.readFileSync(target, 'utf-8')));\n } catch {\n ack = undefined;\n }\n // FIX 2: a missing ack file just means another reader already took it;\n // any other failure means this ack's fate is unknown and must not be\n // reported as delivered, so it is not pushed and the error propagates.\n removeIfPresent(target, fsImpl);\n if (ack) acks.push(ack);\n }\n }\n return acks;\n}\n\n/**\n * Consume one request-specific acknowledgment without touching concurrent\n * callers' files. The request id determines the exact file name, so two\n * parents waiting on different steering requests cannot steal each other's\n * result.\n */\nexport function consumeSteerAck(\n asyncDir: string,\n index: number,\n requestId: string,\n fsImpl: Pick<typeof fs, 'readFileSync' | 'rmSync'> = fs,\n): SteerAck | undefined {\n const target = steerAckPathFromDir(steerAcksDir(asyncDir, index), requestId);\n let ack: SteerAck | undefined;\n try {\n ack = parseSteerAck(JSON.parse(fsImpl.readFileSync(target, 'utf-8')));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n removeIfPresent(target, fsImpl);\n if (!ack || ack.requestId !== requestId || ack.index !== index) return undefined;\n return ack;\n}\n\nexport function consumeInterruptRequest(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'rmSync'> = fs,\n): boolean {\n const requestPath = interruptRequestPath(asyncDir);\n if (!fsImpl.existsSync(requestPath)) return false;\n removeIfPresent(requestPath, fsImpl);\n return true;\n}\n\nexport function consumeTimeoutRequest(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'rmSync'> = fs,\n): boolean {\n const requestPath = timeoutRequestPath(asyncDir);\n if (!fsImpl.existsSync(requestPath)) return false;\n removeIfPresent(requestPath, fsImpl);\n return true;\n}\n\nexport function consumeStopRequest(asyncDir: string, fsImpl: Pick<typeof fs, 'existsSync' | 'rmSync'> = fs): boolean {\n const requestPath = stopRequestPath(asyncDir);\n if (!fsImpl.existsSync(requestPath)) return false;\n removeIfPresent(requestPath, fsImpl);\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// FIX 1: claim by rename, dispatch what was claimed, commit or release.\n// ---------------------------------------------------------------------------\n\n/** A steer request removed from the queue by an atomic rename, awaiting dispatch. */\nexport interface ClaimedSteerRequest {\n request: SteerRequest;\n /** Call once dispatch has returned successfully. Permanently deletes the claimed file. */\n commit: () => void;\n /** Call when dispatch threw. Renames the file back so the next scan retries it. */\n release: () => void;\n}\n\n/**\n * Atomically move one queued request out of `dir`, or report the loss to\n * another consumer.\n *\n * `renameSync` on `original` is what decides a single winner: if two\n * consumers both listed `dir` and both attempt this for the same\n * `entryName`, exactly one rename succeeds and the other's source no longer\n * exists, which surfaces as `ENOENT` here regardless of what destination name\n * either consumer chose.\n */\nfunction claimSteerRequestFile(\n dir: string,\n entryName: string,\n claimant: string,\n fsImpl: Pick<typeof fs, 'renameSync'>,\n): string | undefined {\n const original = path.join(dir, entryName);\n const claimed = `${original}${CLAIM_SUFFIX_PREFIX}${claimant}`;\n try {\n fsImpl.renameSync(original, claimed);\n return claimed;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n}\n\n/**\n * Claim every currently queued, parseable steer request in `dir`.\n *\n * Each returned entry has already been renamed out of the queue, so nothing\n * else will claim it again; it is the caller's obligation to call exactly one\n * of `commit()` (dispatch succeeded) or `release()` (dispatch threw) for\n * every entry returned, so nothing is left claimed and stranded.\n */\nexport function claimSteerRequestsFromDir(\n dir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'renameSync' | 'rmSync' | 'readdirSync' | 'readFileSync'> = fs,\n claimant: string = randomUUID(),\n): ClaimedSteerRequest[] {\n if (!fsImpl.existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = fsImpl\n .readdirSync(dir)\n .filter((name) => name.endsWith('.json'))\n .sort();\n } catch {\n // Leave requests in place so the next scan can retry the listing.\n return [];\n }\n const claims: ClaimedSteerRequest[] = [];\n for (const entryName of entries) {\n const claimedPath = claimSteerRequestFile(dir, entryName, claimant, fsImpl);\n if (!claimedPath) continue; // Lost the race to another consumer, or already gone.\n const originalPath = path.join(dir, entryName);\n let parsed: SteerRequest | undefined;\n try {\n parsed = parseSteerRequest(JSON.parse(fsImpl.readFileSync(claimedPath, 'utf-8')));\n } catch {\n parsed = undefined;\n }\n if (!parsed) {\n // Corrupt or unparseable: nothing can dispatch it, and it is not\n // something a future poll should keep retrying forever.\n removeIfPresent(claimedPath, fsImpl);\n continue;\n }\n let settled = false;\n claims.push({\n request: parsed,\n commit: () => {\n if (settled) return;\n settled = true;\n removeIfPresent(claimedPath, fsImpl);\n },\n release: () => {\n if (settled) return;\n settled = true;\n try {\n fsImpl.renameSync(claimedPath, originalPath);\n } catch {\n // The original name is occupied (astronomically unlikely - it is\n // keyed by timestamp and id) or the directory is gone. Either way\n // there is nothing left to preserve by retrying the rename; drop\n // the claimed copy rather than leave an unreachable file on disk.\n removeIfPresent(claimedPath, fsImpl);\n }\n },\n });\n }\n return claims.sort(\n (left, right) => left.request.ts - right.request.ts || left.request.id.localeCompare(right.request.id),\n );\n}\n\nexport function claimSteerRequests(\n asyncDir: string,\n fsImpl: Pick<typeof fs, 'existsSync' | 'renameSync' | 'rmSync' | 'readdirSync' | 'readFileSync'> = fs,\n claimant: string = randomUUID(),\n): ClaimedSteerRequest[] {\n return claimSteerRequestsFromDir(steerRequestsDir(asyncDir), fsImpl, claimant);\n}\n\n// ---------------------------------------------------------------------------\n// Parent-side portable delivery. Authoritative file request + best-effort OS\n// signal; the signal is only a latency optimization on Unix, and `ENOSYS` on\n// Windows is expected and swallowed because the file inbox is authoritative\n// there. Other signal failures are surfaced because they usually mean the\n// runner is not alive to consume the request.\n// ---------------------------------------------------------------------------\n\nexport function deliverInterruptRequest(input: {\n asyncDir: string;\n pid?: number;\n kill?: KillFn;\n signal?: NodeJS.Signals;\n now?: () => number;\n source?: string;\n}): void {\n const requestPath = requestAsyncInterrupt(input.asyncDir, input.source ? { source: input.source } : {}, {\n now: input.now,\n });\n if (typeof input.pid === 'number' && input.pid > 0) {\n try {\n const kill = input.kill ?? ((pid: number, signal?: NodeJS.Signals | 0) => process.kill(pid, signal));\n kill(input.pid, input.signal ?? INTERRUPT_SIGNAL);\n } catch (error) {\n if ((error as NodeJS.ErrnoException | undefined)?.code === 'ENOSYS') {\n // File inbox is authoritative when custom cross-process signals are unavailable.\n return;\n }\n try {\n fs.rmSync(requestPath, { force: true });\n } catch {\n // Best effort cleanup; the caller still gets the signal failure.\n }\n throw error;\n }\n }\n}\n\nexport function deliverTimeoutRequest(input: {\n asyncDir: string;\n pid?: number;\n kill?: KillFn;\n signal?: NodeJS.Signals;\n now?: () => number;\n source?: string;\n}): void {\n requestAsyncTimeout(input.asyncDir, input.source ? { source: input.source } : {}, { now: input.now });\n}\n\nexport function deliverStopRequest(input: {\n asyncDir: string;\n pid?: number;\n kill?: KillFn;\n signal?: NodeJS.Signals;\n now?: () => number;\n source?: string;\n}): void {\n requestAsyncStop(input.asyncDir, input.source ? { source: input.source } : {}, { now: input.now });\n}\n\n// ---------------------------------------------------------------------------\n// Runner side: watch the inbox and route requests into caller-supplied\n// handlers. See the module header for why this is a `PollScheduler`\n// subscriber rather than an owned timer.\n// ---------------------------------------------------------------------------\n\nexport interface ControlChannelWatchHandlers {\n onInterrupt: () => void;\n onTimeout?: () => void;\n onStop?: () => void;\n onSteer?: (request: SteerRequest) => void;\n onSteerCapability?: (capability: SteerCapability) => void;\n onSteerAck?: (ack: SteerAck) => void;\n}\n\nexport interface ControlChannelWatchOptions {\n /** Poll safety-net cadence for this watch, overriding the service default. */\n intervalMs?: number;\n fs?: ControlChannelFs;\n}\n\nexport interface IControlChannelWatcher {\n /**\n * Start watching `asyncDir`'s control inbox. Fires the matching handler for\n * each distinct request, once. Returns a disposer.\n */\n watch(asyncDir: string, handlers: ControlChannelWatchHandlers, options?: ControlChannelWatchOptions): () => void;\n}\n\n@injectable()\nexport class ControlChannelWatcher implements IControlChannelWatcher {\n /**\n * Seam for tests, as a protected member rather than a constructor\n * argument: inversify cannot resolve a primitive. See `pollScheduler.ts`\n * and `agents/discovery.ts` for the same pattern.\n */\n protected readonly intervalMs: number = DEFAULT_CONTROL_CHANNEL_POLL_INTERVAL_MS;\n\n constructor(@inject(DOOM_TEAM_TYPES.PollScheduler) private readonly scheduler: IPollScheduler) {}\n\n watch(asyncDir: string, handlers: ControlChannelWatchHandlers, options: ControlChannelWatchOptions = {}): () => void {\n const fsImpl = options.fs ?? fs;\n const dir = controlInboxDir(asyncDir);\n try {\n fsImpl.mkdirSync(dir, { recursive: true });\n } catch {\n // Best effort - check() below tolerates a missing dir.\n }\n\n const claimant = `${process.pid}-${randomUUID()}`;\n let disposed = false;\n\n const run = (): boolean => {\n if (disposed) return false;\n return this.check(asyncDir, handlers, fsImpl, claimant);\n };\n\n // A request may already be waiting before this watcher starts. Its error,\n // if any, is allowed to throw out of `watch()` here: the scheduled\n // subscription below is not registered yet to report it, and a control\n // channel broken before the first check ever runs should fail loudly\n // rather than start silently degraded.\n run();\n\n const unregister = this.scheduler.register({\n id: `control-channel:${asyncDir}`,\n intervalMs: options.intervalMs ?? this.intervalMs,\n run,\n });\n\n let watcher: fs.FSWatcher | undefined;\n try {\n watcher = fsImpl.watch(resolveWatchPath(dir, fsImpl.realpathSync.native), () => {\n if (!disposed) this.scheduler.wake();\n });\n watcher.on?.('error', () => {\n // fs.watch can emit on transient FS errors; the poll subscription\n // above keeps this live regardless.\n });\n } catch {\n watcher = undefined;\n }\n\n return () => {\n if (disposed) return;\n disposed = true;\n try {\n watcher?.close();\n } catch {\n // ignore\n }\n unregister();\n };\n }\n\n /**\n * One pass over every request kind. Returns whether anything was actually\n * consumed, which is what lets `PollScheduler`'s idle backoff reset.\n *\n * Steer capabilities are deliberately excluded from that signal: unlike\n * every other request kind, a capability file is not consumed here (it\n * represents current state, not a one-time event), so counting its mere\n * presence as \"work\" would pin this subscription at its floor interval for\n * as long as any child has ever registered one.\n *\n * A steer dispatch that throws does not abort the pass: every claim is\n * either committed or released before this returns (FIX 1), and any error\n * is collected and rethrown last so one failing message cannot starve the\n * others claimed in the same pass.\n */\n private check(\n asyncDir: string,\n handlers: ControlChannelWatchHandlers,\n fsImpl: ControlChannelFs,\n claimant: string,\n ): boolean {\n let workHappened = false;\n\n if (consumeStopRequest(asyncDir, fsImpl)) {\n handlers.onStop?.();\n workHappened = true;\n }\n if (consumeTimeoutRequest(asyncDir, fsImpl)) {\n handlers.onTimeout?.();\n workHappened = true;\n }\n if (consumeInterruptRequest(asyncDir, fsImpl)) {\n handlers.onInterrupt();\n workHappened = true;\n }\n\n let firstError: unknown;\n for (const claim of claimSteerRequests(asyncDir, fsImpl, claimant)) {\n try {\n handlers.onSteer?.(claim.request);\n claim.commit();\n workHappened = true;\n } catch (error) {\n claim.release();\n firstError ??= error;\n }\n }\n\n for (const capability of consumeSteerCapabilities(asyncDir, fsImpl)) handlers.onSteerCapability?.(capability);\n // The child runner writes acknowledgments for its parent. A watcher that\n // has no acknowledgment handler must leave those files untouched, or it\n // races the parent and consumes its own outbound acknowledgment.\n if (handlers.onSteerAck) {\n for (const ack of consumeSteerAcks(asyncDir, fsImpl)) {\n handlers.onSteerAck(ack);\n workHappened = true;\n }\n }\n\n if (firstError !== undefined) throw firstError;\n return workHappened;\n }\n}\n"],"mappings":"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"}
@@ -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(`../../intercom/supervisorControlChannel.cjs`),c=require(`../../../shared/paths.cjs`),l=require(`./statusWriter.cjs`),u=require(`../shared/runtimeRegistry.cjs`),d=require(`../../../adapters/asyncJobTracker.cjs`);require(`./asyncJobTracker.cjs`);const f=require(`../../intercom/nativeTeamChannel.cjs`),p=require(`../../../shared/artifacts.cjs`),m=require(`../../../adapters/runRegistry.cjs`);require(`../registry/runRegistry.cjs`);const h=require(`../shared/claudeFableProfile.cjs`),g=require(`../shared/piArgs.cjs`),_=require(`./spawnHandshake.cjs`);let v=require(`node:fs`);v=e.__toESM(v,1);let y=require(`node:path`);y=e.__toESM(y,1);let b=require(`inversify`),x=require(`@agimon-ai/doompi-config`),S=require(`@agimon-ai/doompi-extension-contracts/child-process`),C=require(`node:child_process`),w=require(`node:url`);function T(e){return y.join(c.currentRunsDir(),e)}function E(e){return y.join(T(e),`handshake.json`)}function D(e){return y.join(T(e),`fable-profile-result.json`)}function O(e){return y.join(T(e),`system-prompt.md`)}function k(e,t){let n=y.dirname((0,w.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)),r=y.resolve(n,`../..`),i=y.join(r,e,`${t}.mjs`);if(v.existsSync(i))return i;let a=y.join(r,e,`${t}.ts`);if(v.existsSync(a))return a;throw Error(`Doom Team runner '${t}' is unavailable at '${i}' or '${a}'.`)}function A(){return k(`runs`,`sdkRunnerEntry`)}function j(){return k(`runs/background`,`cliRunnerEntry`)}let M=class{constructor(e,t){this.jobTracker=e,this.terminalPersistence=t}defaultHandshakeTimeoutMs=1e4;now(){return Date.now()}readCurrentTeamRoot(){return f.readNativeTeamRootFromEnvironment()}createStatusWriter(){return new l.CoalescedStatusWriter}createSpawnHandshake(){return new _.SpawnHandshake}writeLaunchConfig(e,t){r.writePrivateAtomicJson(e,t)}removeLaunchConfig(e){v.rmSync(e,{force:!0})}readRunState(e){try{let t=JSON.parse(v.readFileSync(y.join(T(e),l.STATUS_FILE_NAME),`utf8`));return typeof t.state==`string`?t.state:void 0}catch{return}}buildLaunchArgs(e){return g.buildPiArgs(e)}spawnChild(e,t,n){let r=n.env[i.SUBAGENT_RUN_ID_ENV],a,o;if(r){let e=T(r);v.mkdirSync(e,{recursive:!0}),a=v.openSync(y.join(e,`runner.stdout.log`),`a`,384);try{o=v.openSync(y.join(e,`runner.stderr.log`),`a`,384)}catch(e){throw v.closeSync(a),Error(`Could not open runner stderr for '${r}'.`,{cause:e})}}let s;try{s=(0,C.spawn)(e,t,{cwd:n.cwd,detached:!0,stdio:[`ignore`,a??`ignore`,o??`ignore`],windowsHide:!0,env:n.env})}finally{a!==void 0&&v.closeSync(a),o!==void 0&&v.closeSync(o)}return s.unref(),{pid:s.pid,onError:e=>s.on(`error`,e),onExit:e=>s.on(`exit`,e)}}async spawn(e){let{runId:t,agent:n,task:r,cwd:i}=e,a=e.fanout?e.childIndex:void 0,o=E(t),l=c.currentRunConfigPath(t),g=e.artifacts===!1?void 0:p.getArtifactPaths(p.getArtifactsDir(e.parentSessionFile??null,i,e.artifactDir??`session`),t,n).transcriptPath,_=T(t),b=e.childIndex??0,C=this.readCurrentTeamRoot(),{args:w,env:k,sdk:M}=this.buildLaunchArgs({...e.piArgs,runId:t,task:r,childIndex:e.childIndex,steerInboxDir:s.stepSteerInboxDir(_,b),steerCapabilityPath:s.steerCapabilityPath(_,b),steerAckDir:s.steerAcksDir(_,b),teamToolEnabled:!!C});(0,x.createHarnessSession)({...(0,x.getHarnessState)(),childExtensions:M.extensions},{directory:_,environment:k,unclaimed:!0});let N={...process.env,...k,...c.sessionScopeEnvironment(c.requireCurrentSessionScope()),...C?f.nativeTeamRootEnvironment(C):{}};u.isPiRuntime(e.runtime)&&(M.extensionsProvidedExternally?N[S.DOOMPI_EXTENSIONS_PROVIDED_ENV]=`1`:delete N[S.DOOMPI_EXTENSIONS_PROVIDED_ENV]);let P;if(u.isPiRuntime(e.runtime)&&M.systemPrompt)try{v.mkdirSync(_,{recursive:!0});let e=O(t);v.writeFileSync(e,M.systemPrompt,{mode:384}),P=e}catch{P=void 0}let F=this.now(),I=this.createStatusWriter();I.open(t,{version:1,runId:t,...e.operationId?{operationId:e.operationId}:{},agent:n,...e.sensitiveTask?{}:{task:r},cwd:i,...e.piArgs.model?{model:e.piArgs.model}:{},...e.inlineAgent?{inlineAgent:e.inlineAgent}:{},state:`queued`,startedAt:F,lastUpdate:F,...a===void 0?{}:{fanoutIndex:a},...e.internal?{internal:!0}:{},...u.isPiRuntime(e.runtime)?{}:{runtime:e.runtime},...g?{transcriptPath:g}:{},...P?{systemPromptPath:P}:{},...P&&M.systemPromptMode?{systemPromptMode:M.systemPromptMode}:{},...M.tools?{tools:M.tools}:{},...M.excludeTools?.length?{excludeTools:M.excludeTools}:{},...M.noTools?{noTools:!0}:{}}),u.isPiRuntime(e.runtime)&&this.writeLaunchConfig(l,{runId:t,agent:n,task:r,cwd:i,childIndex:e.childIndex,handshakePath:o,sdk:M,...g?{transcriptPath:g}:{},args:w,env:N});let L,R=e=>{throw this.removeLaunchConfig(l),L&&h.cleanupClaudeFableLaunch(L),v.rmSync(D(t),{force:!0}),I.updateSync(t=>{t.state=`failed`,t.error=e,t.lastUpdate=this.now()}),Error(e)},z=u.isPiRuntime(e.runtime);if(!z){let a=e.piArgs.capabilityCeiling;if(a&&(!e.externalProfile||!a.allowedExternalProfiles.includes(e.externalProfile)))return R(`External profile '${e.externalProfile??`none`}' is denied by the active capability ceiling.`);if(e.externalProfile!==void 0&&e.externalProfile!==h.CLAUDE_FABLE_PROFILE)return R(`External profile '${e.externalProfile}' is not trusted.`);if(e.externalProfile===h.CLAUDE_FABLE_PROFILE){if(e.runtime!==`claude`||e.piArgs.model!==`fable`)return R(`The Fable profile requires runtime claude and model fable.`);if(e.inlineAgent||e.piArgs.sessionFile||e.piArgs.parentSessionId)return R(`The Fable profile requires a fresh isolated context.`);L=h.prepareClaudeFableLaunch({runId:t,prompt:r,repositoryCwd:i,privateRoot:_}),this.writeLaunchConfig(l,{runId:t,...e.operationId?{operationId:e.operationId}:{},agent:n,runtime:`claude`,command:L.command,args:L.args,cwd:L.cwd,env:L.env,profile:L.profile,stdinPath:L.stdinPath,cleanupPaths:L.cleanupPaths,profileResultPath:D(t),internal:e.internal===!0,handshakePath:o,resultPath:y.join(c.currentResultsDir(),`${t}.json`)})}else this.writeLaunchConfig(l,{runId:t,...e.operationId?{operationId:e.operationId}:{},agent:n,...u.resolveRuntimeLaunch(e.runtime,e.runtimes??{},{prompt:r,model:e.piArgs.model,cwd:i}),cwd:i,env:k,handshakePath:o,resultPath:y.join(c.currentResultsDir(),`${t}.json`)})}let{pid:B,onError:V,onExit:H}=this.spawnChild(process.execPath,[z?A():j()],{cwd:i,env:N});if(B===void 0)return R(`Async spawn for '${n}' (run '${t}') did not produce a pid.`);let U;V(e=>{U=e}),m.registerRun(c.requireCurrentSessionScope(),{runId:t,pid:B,agent:n,runtime:e.runtime??`pi`,startedAt:F}),this.terminalPersistence.trackChild(B),H((e,n)=>{this.terminalPersistence.untrackChild(B),m.releaseRun(c.requireCurrentSessionScope(),t),!(e===0&&n===null)&&(I.updateSync(t=>{t.state&&d.TERMINAL_ASYNC_JOB_STATES.has(t.state)||(t.state=`failed`,t.error=`SDK runner process ${B} exited unexpectedly (${n??`code ${e??`unknown`}`}).`,t.lastUpdate=this.now(),t.endedAt=this.now())}),this.jobTracker.track(t))});let W=await this.createSpawnHandshake().waitForHandshake({path:o,timeoutMs:e.handshakeTimeoutMs??this.defaultHandshakeTimeoutMs}).promise;if(W.status!==`signalled`)return this.terminalPersistence.untrackChild(B),R(W.status===`failed`?W.error:U?.message??`Timed out waiting for '${n}' (run '${t}') to start.`);this.removeLaunchConfig(l);let G=this.readRunState(t);return(!G||!d.TERMINAL_ASYNC_JOB_STATES.has(G))&&I.updateSync(e=>{e.state=`running`,e.lastUpdate=this.now()}),this.jobTracker.track(t),{runId:t,pid:B}}};M=t.__decorate([(0,b.injectable)(),o.__decorateParam(0,(0,b.inject)(n.DOOM_TEAM_TYPES.AsyncJobTracker)),o.__decorateParam(1,(0,b.inject)(n.DOOM_TEAM_TYPES.TerminalPersistenceService)),a.__decorateMetadata(`design:paramtypes`,[Object,Object])],M),Object.defineProperty(exports,`AsyncSubagentSpawner`,{enumerable:!0,get:function(){return M}}),exports.fableProfileResultPathFor=D,exports.handshakePathFor=E,exports.runDirFor=T;
2
+ //# sourceMappingURL=asyncExecution.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncExecution.cjs","names":["path","currentRunsDir","fs","readNativeTeamRootFromEnvironment","CoalescedStatusWriter","SpawnHandshake","STATUS_FILE_NAME","buildPiArgs","SUBAGENT_RUN_ID_ENV","currentRunConfigPath","getArtifactPaths","getArtifactsDir","stepSteerInboxDir","steerCapabilityPath","steerAcksDir","sessionScopeEnvironment","requireCurrentSessionScope","nativeTeamRootEnvironment","isPiRuntime","DOOMPI_EXTENSIONS_PROVIDED_ENV","CLAUDE_FABLE_PROFILE","prepareClaudeFableLaunch","currentResultsDir","resolveRuntimeLaunch","TERMINAL_ASYNC_JOB_STATES","DOOM_TEAM_TYPES"],"sources":["../../../../src/services/runs/background/asyncExecution.ts"],"sourcesContent":["/**\n * The async-only spawn executor: launches exactly one subagent child process\n * and returns a run handle immediately, without waiting for the run to\n * finish.\n *\n * SCOPE - PARENT SIDE ONLY, SINGLE SPAWN:\n * `doom-pi-subagents/src/runs/background/asyncExecution.ts` is 1698 lines\n * doing far more than spawning: chain/parallel-group orchestration (building\n * `AgentConfig[]` sequences, dynamic fan-out expansion, workflow-graph\n * snapshots), session revival (a 3-way ready/ack/proceed handshake distinct\n * from the plain started-signal this module uses), and the foreground\n * (synchronous, blocking) code path. None of that is ported here:\n * - Chain/fan-out ORCHESTRATION (deciding how many children to spawn, in\n * what order, from what step list) is `port-steering`'s concurrent work on\n * the resolved-step and workflow-graph types. This module is the\n * PRIMITIVE that orchestration calls once per child - `childIndex` and\n * `fanout` arrive as inputs, already decided by the caller, not derived\n * here (see the child-index section below for why that is safe)\n * - Session revival (`revivalLease`, the 3-way ready/ack/proceed dance at\n * predecessor lines 498-509) is a materially different operation - resuming\n * an existing transcript, not spawning a fresh child - and is not ported.\n * `session-lease.ts` already exists in this package for whoever builds that\n * path later\n * - The foreground (synchronous) branch is dropped entirely, per the async-\n * only requirement below; there is no `async` parameter, only this\n *\n * WHAT THIS DOES NOT BUILD (compose, don't reimplement):\n * `CoalescedStatusWriter`, `TerminalPersistenceService`, `AsyncJobTracker`,\n * `SpawnHandshake`, `ResultWatcher`, `CompletionNotifier` all already exist\n * in this directory and are used here, not reimplemented. In particular, the\n * predecessor's process-exit tracking is reduced to the child handle's exact\n * exit signal: an abnormal exit marks that run failed immediately, while the\n * crash-marker path (`TerminalPersistenceService` +\n * `ProcessTerminalInspector`) remains the recovery path after parent loss.\n * `trackChild(pid)` on the caller's own already-active\n * `TerminalPersistenceService` is what makes a spawned child get killed if\n * the run that spawned it dies, which is the same guarantee the predecessor\n * used its own mechanism for.\n *\n * SDK RUNNER BOUNDARY:\n * `sdkRunnerEntry.ts` is the detached child process target. It reads the\n * launch config, creates the child through Pi's SDK, and loads\n * `subagent-prompt-runtime-entry` as an explicit child extension. That\n * extension owns the handshake, status, steering, and terminal result\n * lifecycle through the existing runner services. The real Pi CLI remains\n * the parent host used by system tests and DoomPi, not the child launcher.\n *\n * WHY SpawnHandshake, NOT `Atomics.wait`:\n * The predecessor blocks the parent's event loop for up to 10 seconds per\n * spawn (`asyncExecution.ts:376-380`, `Atomics.wait` on a shared buffer).\n * That codepath only actually ran for session revival there (a fresh spawn\n * had no `startupPath` and returned immediately) - but this package has no\n * synchronous/foreground path left to hide the cost behind, so a busy-wait\n * would block every single async spawn, not just revivals. `SpawnHandshake`\n * (already in this directory) replaces it: a real `fs.watch` on the\n * handshake file's directory, with a short poll as the safety net, and it\n * never blocks the event loop.\n *\n * LAUNCH CONFIG FILE LIFECYCLE (fix):\n * The predecessor writes the launch config with `fs.writeFileSync(cfgPath,\n * ...)` - no `mode` option, so it lands at the umask default - and never\n * unlinks it on any path, successful or failed\n * (`asyncExecution.ts:491-495`). Both are fixed here: `writeLaunchConfig`\n * writes 0600 (`writePrivateAtomicJson`, already in this package), and\n * `removeLaunchConfig` runs on every exit path - success (once the handshake\n * confirms the child has read it), and every failure (no pid, spawn error,\n * handshake failure or timeout) - so nothing is ever left behind holding the\n * full task text and resolved secrets/tokens at world-readable-adjacent\n * permissions.\n *\n * CHILD INDEX (fix - `DeliverableGuard` had no way to get one):\n * `DeliverableGuard.deliverNudge` requires an explicit `nudgeTarget` of\n * `{kind:'child', index}` for a fan-out run specifically so it cannot\n * broadcast a nudge to every sibling over one child's missing deliverable\n * (see that module's header). Nothing in this package maps a team member id\n * to a fan-out child index (verified: neither `nativeTeamChannel.ts` nor\n * `parallel-groups.ts` does this). This module needs no such mapping either\n * - `childIndex` is simply which spawn call this is, a fact the caller (a\n * single spawn, or a fan-out loop calling this once per child) already knows\n * without looking anything up, exactly like a flat index into\n * `status.steps[]` is decided by whoever builds that array. `nudgeTarget` is\n * derived from `childIndex`/`fanout` and persisted onto the run's own\n * `status.json` (`nudgeTarget` field) for whatever later evaluates\n * `DeliverableGuardInput` to read back, rather than re-derived at that point.\n *\n * DELIVERABLE EXPECTATION (fix - `DeliverableGuard` had no policy):\n * Derived here, at the one point this module already has the task text:\n * `classifyTaskMutationIntent` (used AS-IS, per its own header's warning\n * against widening its vocabulary for a third caller) distinguishes\n * `'implementation'` intent from `'read-only'`/`'unknown'`. Implementation\n * intent gets a real expectation (`{kind:'summary'}` by default - the\n * minimum a run can be asked to prove it did something, when no more\n * specific expectation like a structured-output schema or artifact path was\n * supplied); read-only or unknown intent gets none at all. This is\n * deliberately NOT `{kind:'summary'}` unconditionally: a guard that flags\n * every research run for an empty summary gets ignored, and an ignored guard\n * misses the run that actually needed it.\n *\n * TEAM MEMBERSHIP ENV FORWARDING (fix - a spawned child had no way to join\n * the team):\n * If THIS process (the one calling `spawn()`) is itself part of a native\n * team - `readNativeTeamRootFromEnvironment()` resolves a root context off\n * its own `process.env` - the same root vars\n * (`nativeTeamRootEnvironment(root)`, already in `nativeTeamChannel.ts`,\n * not reimplemented here) are folded into the child's env alongside\n * whatever `buildPiArgs` produced. Only the ROOT vars travel this way, never\n * a member id/token: those are per-member secrets the CHILD mints for\n * itself when it registers (see `runnerBootstrap.ts` and\n * `runnerTeamMembership.ts`), not something safe to hand down from the\n * parent's own identity. When this process has no team root (a standalone\n * spawn outside any team), nothing is forwarded and the child simply has\n * none to register against.\n */\n\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createHarnessSession, getHarnessState } from '@agimon-ai/doompi-config';\nimport { DOOMPI_EXTENSIONS_PROVIDED_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport type { InlineAgent } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport { inject, injectable } from 'inversify';\nimport { PI_RUNTIME_NAME, SUBAGENT_RUN_ID_ENV } from '../../../adapters/process/env.ts';\nimport { DOOM_TEAM_TYPES } from '../../../container/types.ts';\nimport { getArtifactPaths, getArtifactsDir } from '../../../shared/artifacts.ts';\nimport { writePrivateAtomicJson } from '../../../shared/atomicJson.ts';\nimport {\n currentResultsDir,\n currentRunConfigPath,\n currentRunsDir,\n requireCurrentSessionScope,\n sessionScopeEnvironment,\n} from '../../../shared/paths.ts';\nimport type { ActivityState, ArtifactDirPreference } from '../../../types/index.ts';\nimport {\n nativeTeamRootEnvironment,\n readNativeTeamRootFromEnvironment,\n type TeamRootContext,\n} from '../../intercom/nativeTeamChannel.ts';\nimport { steerAcksDir, steerCapabilityPath, stepSteerInboxDir } from '../../intercom/supervisorControlChannel.ts';\nimport { registerRun, releaseRun } from '../registry/runRegistry.ts';\nimport {\n CLAUDE_FABLE_PROFILE,\n type ClaudeFableLaunch,\n cleanupClaudeFableLaunch,\n prepareClaudeFableLaunch,\n} from '../shared/claudeFableProfile.ts';\nimport {\n type BuildPiArgsInput,\n type BuildPiArgsResult,\n buildPiArgs,\n type PiSdkLaunchSettings,\n} from '../shared/piArgs.ts';\nimport { isPiRuntime, type RuntimeTable, resolveRuntimeLaunch } from '../shared/runtimeRegistry.ts';\nimport { type IAsyncJobTracker, TERMINAL_ASYNC_JOB_STATES } from './asyncJobTracker.ts';\nimport { type ISpawnHandshake, SpawnHandshake } from './spawnHandshake.ts';\nimport {\n CoalescedStatusWriter,\n type ICoalescedStatusWriter,\n STATUS_FILE_NAME,\n type StatusWithRecentEntries,\n} from './statusWriter.ts';\nimport type { ITerminalPersistenceService } from './terminalPersistence.ts';\n\n/** Leaf name of the started-signal file `SpawnHandshake` watches for, under `currentRunsDir()/<runId>/`. Exported so the child-side runner can compose the same convention rather than duplicate it. */\nexport const HANDSHAKE_FILE_NAME = 'handshake.json';\nexport const RUNNER_STDOUT_FILE_NAME = 'runner.stdout.log';\nexport const RUNNER_STDERR_FILE_NAME = 'runner.stderr.log';\nexport const FABLE_PROFILE_RESULT_FILE_NAME = 'fable-profile-result.json';\n/**\n * The effective system prompt this run launched with, kept for the fleet\n * inspector's agent view.\n *\n * A SIDECAR RATHER THAN A FIELD ON status.json: `CoalescedStatusWriter`\n * rewrites the whole status file on every coalesced flush, and a system prompt\n * is kilobytes of text that never changes after spawn. Inlining it would put\n * that payload through every status write for the life of the run. This file\n * is written once, next to the status it belongs to.\n *\n * Written 0600 for the same reason `piArgs.ts` writes its prompt file that\n * way: a resolved prompt can carry inherited project context.\n */\nexport const SYSTEM_PROMPT_FILE_NAME = 'system-prompt.md';\nconst SYSTEM_PROMPT_FILE_MODE = 0o600;\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;\n\n/**\n * `state`/`steps`/`parallelGroups`/`chainStepCount`/`workflowGraph`/\n * `pendingAppends` are declared as optional-and-widened, rather than a\n * runner-owned status type, so this SAME status shape is what\n * `chain-append.ts`'s `applyChainAppendRequest` (which expects\n * `AppendableChainStatus`, an object with exactly these optional fields) can\n * mutate directly - one status type for the whole spawn-through-finalize\n * lifecycle, not a parent-side one and a child-side one that have to be kept\n * in sync by hand.\n */\nexport interface AsyncRunStatus extends StatusWithRecentEntries {\n /** Version 1 is emitted by current writers; absent is accepted only by the compatibility reader. */\n version?: 1;\n runId: string;\n operationId?: string;\n agent: string;\n /** Original task text required to restore a suspended run. */\n task?: string;\n cwd?: string;\n /** Resolved model selected for this run, when one was requested. */\n model?: string;\n /** One-shot agent definition required to restore an inline agent. */\n inlineAgent?: InlineAgent;\n state: 'queued' | 'running' | 'complete' | 'completed' | 'failed' | 'paused' | 'stopped';\n startedAt: number;\n lastUpdate: number;\n endedAt?: number;\n /** This run's position among its fan-out siblings, when it has any. Absent for a standalone run. */\n fanoutIndex?: number;\n /** Bridge-owned runs are consumed internally and never rendered as generic completion chat. */\n internal?: boolean;\n /** Which runtime executes this run. Absent means the default in-process `pi` path. */\n runtime?: string;\n activityState?: ActivityState;\n attentionReason?: string;\n error?: string;\n /**\n * Set once, at finalize, by `RunnerReporting.mutateTerminalStatus` - the\n * SAME value it puts in the terminal result file, truncated to a bounded\n * length (see that module's header for why). Lets a caller (chain mode,\n * in particular) learn a completed run's own summary through the status\n * file it already reads to learn the run finished, rather than needing a\n * second read of a claimed, single-consumer result file.\n */\n summary?: string;\n /**\n * This run's own Pi session transcript path, written during child bootstrap\n * and retained by `RunnerReporting.mutateTerminalStatus` at finalize. See\n * that module's header for where the value comes from and why it is bounded\n * by omission, not truncation. Absent for a run that either never reported\n * a session file (headless, no persisted transcript) or reported one too\n * long to trust. This is what `action='resume'` reads to know which\n * transcript a later revival should reopen.\n */\n sessionFile?: string;\n /** Child-owned Pi SDK event transcript consumed by the fleet detail pane. */\n transcriptPath?: string;\n /**\n * Sidecar holding this run's effective system prompt, and the resolved tool\n * plan it launched with. Recorded at spawn purely so the fleet inspector can\n * show what an agent was actually told: the launch config that carried them\n * is deleted as soon as the child handshakes, and the agent definition on\n * disk can change while a run is still going.\n *\n * All absent for a non-`pi` runtime, which has no SDK launch settings, and\n * for any run started before this was recorded.\n */\n systemPromptPath?: string;\n systemPromptMode?: 'append' | 'replace';\n /** Effective tool allowlist. Absent means \"whatever the child defaults to\". */\n tools?: string[];\n excludeTools?: string[];\n noTools?: boolean;\n /** Cumulative tokens observed from finalized child messages. */\n tokens?: number;\n /** Most recently started child tool. */\n currentTool?: string;\n /** Number of child tool executions observed so far. */\n toolCount?: number;\n}\n\n/** The parent-written contract a child-side runner reads via `currentRunConfigPath(runId)`. */\nexport interface LaunchConfig {\n runId: string;\n agent: string;\n task: string;\n cwd: string;\n childIndex: number;\n handshakePath: string;\n sdk: PiSdkLaunchSettings;\n transcriptPath?: string;\n /** Retained during the SDK cutover for compatibility diagnostics only. */\n args: string[];\n env: Record<string, string | undefined>;\n}\n\nexport interface AsyncSubagentSpawnInput {\n runId: string;\n operationId?: string;\n agent: string;\n /** One-shot agent definition retained only for explicit suspension restore. */\n inlineAgent?: InlineAgent;\n task: string;\n cwd: string;\n /** Persisted parent transcript used to place child artifacts beside the parent session. */\n parentSessionFile?: string;\n /** This spawn's position among its siblings. 0 for a standalone (non-fan-out) run. */\n childIndex: number;\n /** Whether this spawn is one of several children under a fan-out parent. */\n fanout: boolean;\n /** Everything `buildPiArgs` needs, minus what this spawner supplies itself (`runId`/`task`/`childIndex`). */\n piArgs: Omit<BuildPiArgsInput, 'runId' | 'task' | 'childIndex'>;\n /** False disables the child event transcript. Defaults to enabled. */\n artifacts?: boolean;\n /** Artifact root policy inherited from the parent Doom Team config. */\n artifactDir?: ArtifactDirPreference;\n handshakeTimeoutMs?: number;\n /**\n * Which runtime executes this run. Defaults to the in-process Pi SDK path.\n * Anything else is an external CLI resolved through `runtimeRegistry.ts`.\n */\n runtime?: string;\n /** Fixed trusted external profile. Only Doom Team internal bridges may set this. */\n externalProfile?: string;\n /** Prevent sensitive task text from being persisted in status.json. */\n sensitiveTask?: boolean;\n /** Suppress the generic completion notifier for an internal bridge run. */\n internal?: boolean;\n /** Runtimes available to this spawn, already merged with the shipped defaults. */\n runtimes?: RuntimeTable;\n}\n\nexport interface AsyncSubagentSpawnResult {\n runId: string;\n pid: number;\n}\n\nexport interface IAsyncSubagentSpawner {\n /** Spawn one child and return once it has confirmed it started. Throws on any failure to reach that point. */\n spawn(input: AsyncSubagentSpawnInput): Promise<AsyncSubagentSpawnResult>;\n}\n\n/** `currentRunsDir()/<runId>`. Exported so the child-side runner resolves the same directory, not a parallel one. */\nexport function runDirFor(runId: string): string {\n return path.join(currentRunsDir(), runId);\n}\n\n/** Exported so the child-side runner writes its ready/error signal at the exact path this parent half waits on. */\nexport function handshakePathFor(runId: string): string {\n return path.join(runDirFor(runId), HANDSHAKE_FILE_NAME);\n}\n\nexport function fableProfileResultPathFor(runId: string): string {\n return path.join(runDirFor(runId), FABLE_PROFILE_RESULT_FILE_NAME);\n}\n\n/** Where `spawn()` records this run's effective system prompt. See `SYSTEM_PROMPT_FILE_NAME`. */\nexport function systemPromptPathFor(runId: string): string {\n return path.join(runDirFor(runId), SYSTEM_PROMPT_FILE_NAME);\n}\n\n/**\n * Locate a child entry point on disk, built or source.\n *\n * The child is a separate process loading this by path, so the path has to be\n * the one that exists now: `.mjs` under `dist` when this bundle is built, the\n * original source file when it is not. `relativeDir` is where the entry sits\n * relative to `src/` - the SDK runner is one level up from this module, the\n * CLI runner is beside it.\n */\nfunction resolveRunnerEntry(relativeDir: string, stem: string): string {\n const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));\n const packageRoot = path.resolve(moduleDirectory, '../..');\n const builtCandidate = path.join(packageRoot, relativeDir, `${stem}.mjs`);\n if (fs.existsSync(builtCandidate)) return builtCandidate;\n const sourceCandidate = path.join(packageRoot, relativeDir, `${stem}.ts`);\n if (fs.existsSync(sourceCandidate)) return sourceCandidate;\n throw new Error(`Doom Team runner '${stem}' is unavailable at '${builtCandidate}' or '${sourceCandidate}'.`);\n}\n\nfunction resolveSdkRunnerEntry(): string {\n return resolveRunnerEntry('runs', 'sdkRunnerEntry');\n}\n\nfunction resolveCliRunnerEntry(): string {\n return resolveRunnerEntry('runs/background', 'cliRunnerEntry');\n}\n\n@injectable()\nexport class AsyncSubagentSpawner implements IAsyncSubagentSpawner {\n constructor(\n @inject(DOOM_TEAM_TYPES.AsyncJobTracker) private readonly jobTracker: IAsyncJobTracker,\n @inject(DOOM_TEAM_TYPES.TerminalPersistenceService)\n private readonly terminalPersistence: ITerminalPersistenceService,\n ) {}\n\n /**\n * Seam for tests, as a protected member rather than a constructor\n * argument: inversify cannot resolve a primitive. See `pollScheduler.ts`\n * for the same pattern.\n */\n protected readonly defaultHandshakeTimeoutMs: number = DEFAULT_HANDSHAKE_TIMEOUT_MS;\n\n protected now(): number {\n return Date.now();\n }\n\n /**\n * This process's own team root context, read fresh per spawn. Protected\n * so a test can supply one without writing real team files to disk - see\n * the module header's TEAM MEMBERSHIP ENV FORWARDING section for why this\n * is read from `process.env` rather than accepted as a constructor\n * argument (inversify cannot resolve a primitive either way).\n */\n protected readCurrentTeamRoot(): TeamRootContext | undefined {\n return readNativeTeamRootFromEnvironment();\n }\n\n /**\n * A fresh writer per spawn, deliberately never the container's shared\n * singleton - the same reasoning as `StaleRunReconciler.createStatusWriter`\n * (see that class's header): the singleton may simultaneously be the live\n * write path for a run THIS process is itself running, and bootstrapping\n * someone else's (the spawned child's) initial status is a different\n * writer's job.\n */\n protected createStatusWriter(): ICoalescedStatusWriter<AsyncRunStatus> {\n return new CoalescedStatusWriter<AsyncRunStatus>();\n }\n\n /**\n * A fresh handshake wait per spawn. `SpawnHandshake` is bound transient in\n * the container for exactly this reason (each `waitForHandshake()` owns\n * its own timers and watcher for exactly one spawn); resolving it via\n * constructor injection would hand every spawn the same, already-used\n * instance, so this seam constructs one directly instead.\n */\n protected createSpawnHandshake(): ISpawnHandshake {\n return new SpawnHandshake();\n }\n\n protected writeLaunchConfig(filePath: string, config: object): void {\n writePrivateAtomicJson(filePath, config);\n }\n\n protected removeLaunchConfig(filePath: string): void {\n fs.rmSync(filePath, { force: true });\n }\n\n protected readRunState(runId: string): string | undefined {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(runDirFor(runId), STATUS_FILE_NAME), 'utf8')) as {\n state?: unknown;\n };\n return typeof parsed.state === 'string' ? parsed.state : undefined;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Resolves the child's CLI args/env. Protected so a test can bypass\n * `buildPiArgs`'s own real filesystem resolution (it locates a runtime\n * extension script on disk via `resolvePiLaunchToolPlan`, which is\n * environment-dependent and not something a unit test for THIS module's\n * orchestration logic should depend on).\n */\n protected buildLaunchArgs(input: BuildPiArgsInput): BuildPiArgsResult {\n return buildPiArgs(input);\n }\n\n /**\n * The actual `child_process.spawn`. Detached and unref'd immediately. Output\n * goes to per-run files so a startup failure is diagnosable without keeping\n * parent-owned pipes alive.\n */\n protected spawnChild(\n command: string,\n args: string[],\n options: { cwd: string; env: NodeJS.ProcessEnv },\n ): {\n pid: number | undefined;\n onError: (handler: (error: Error) => void) => void;\n onExit: (handler: (code: number | null, signal: NodeJS.Signals | null) => void) => void;\n } {\n const runId = options.env[SUBAGENT_RUN_ID_ENV];\n let stdoutFd: number | undefined;\n let stderrFd: number | undefined;\n if (runId) {\n const runDir = runDirFor(runId);\n fs.mkdirSync(runDir, { recursive: true });\n stdoutFd = fs.openSync(path.join(runDir, RUNNER_STDOUT_FILE_NAME), 'a', 0o600);\n try {\n stderrFd = fs.openSync(path.join(runDir, RUNNER_STDERR_FILE_NAME), 'a', 0o600);\n } catch (error) {\n fs.closeSync(stdoutFd);\n throw new Error(`Could not open runner stderr for '${runId}'.`, { cause: error });\n }\n }\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(command, args, {\n cwd: options.cwd,\n detached: true,\n stdio: ['ignore', stdoutFd ?? 'ignore', stderrFd ?? 'ignore'],\n windowsHide: true,\n env: options.env,\n });\n } finally {\n if (stdoutFd !== undefined) fs.closeSync(stdoutFd);\n if (stderrFd !== undefined) fs.closeSync(stderrFd);\n }\n child.unref();\n return {\n pid: child.pid,\n onError: (handler) => child.on('error', handler),\n onExit: (handler) => child.on('exit', handler),\n };\n }\n\n async spawn(input: AsyncSubagentSpawnInput): Promise<AsyncSubagentSpawnResult> {\n const { runId, agent, task, cwd } = input;\n const fanoutIndex = input.fanout ? input.childIndex : undefined;\n const handshakePath = handshakePathFor(runId);\n const configPath = currentRunConfigPath(runId);\n const transcriptPath =\n input.artifacts === false\n ? undefined\n : getArtifactPaths(\n getArtifactsDir(input.parentSessionFile ?? null, cwd, input.artifactDir ?? 'session'),\n runId,\n agent,\n ).transcriptPath;\n\n const runDir = runDirFor(runId);\n const steerIndex = input.childIndex ?? 0;\n const teamRoot = this.readCurrentTeamRoot();\n const {\n args,\n env: builtEnv,\n sdk,\n } = this.buildLaunchArgs({\n ...input.piArgs,\n runId,\n task,\n childIndex: input.childIndex,\n steerInboxDir: stepSteerInboxDir(runDir, steerIndex),\n steerCapabilityPath: steerCapabilityPath(runDir, steerIndex),\n steerAckDir: steerAcksDir(runDir, steerIndex),\n teamToolEnabled: Boolean(teamRoot),\n });\n // The child gets its own harness state, in this run's directory, which this\n // package owns. Sharing the parent's file would let a detached child rewrite\n // a session it does not own, and pointing at the parent's directory would\n // lose the file the moment the parent cleaned up its own session: a child\n // is detached and can outlive it. Pi 0.84 SDK launches consume the resolved\n // extension list directly, so preserve that same list in the child harness\n // snapshot instead of projecting the parent's stale childExtensions value.\n createHarnessSession(\n { ...getHarnessState(), childExtensions: sdk.extensions },\n { directory: runDir, environment: builtEnv, unclaimed: true },\n );\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n ...builtEnv,\n // The child resolves the same filesystem tree from this, independently of\n // whether it also joins a team.\n ...sessionScopeEnvironment(requireCurrentSessionScope()),\n ...(teamRoot ? nativeTeamRootEnvironment(teamRoot) : {}),\n };\n if (isPiRuntime(input.runtime)) {\n if (sdk.extensionsProvidedExternally) env[DOOMPI_EXTENSIONS_PROVIDED_ENV] = '1';\n else delete env[DOOMPI_EXTENSIONS_PROVIDED_ENV];\n }\n\n // Recorded before open() so the status never advertises a sidecar that is\n // not on disk yet. A failure here is not worth failing a spawn over: the\n // prompt is an inspection aid, so the run proceeds without it.\n let systemPromptPath: string | undefined;\n if (isPiRuntime(input.runtime) && sdk.systemPrompt) {\n try {\n fs.mkdirSync(runDir, { recursive: true });\n const target = systemPromptPathFor(runId);\n fs.writeFileSync(target, sdk.systemPrompt, { mode: SYSTEM_PROMPT_FILE_MODE });\n systemPromptPath = target;\n } catch {\n systemPromptPath = undefined;\n }\n }\n\n const now = this.now();\n const statusWriter = this.createStatusWriter();\n statusWriter.open(runId, {\n version: 1,\n runId,\n ...(input.operationId ? { operationId: input.operationId } : {}),\n agent,\n ...(input.sensitiveTask ? {} : { task }),\n cwd,\n ...(input.piArgs.model ? { model: input.piArgs.model } : {}),\n ...(input.inlineAgent ? { inlineAgent: input.inlineAgent } : {}),\n state: 'queued',\n startedAt: now,\n lastUpdate: now,\n ...(fanoutIndex === undefined ? {} : { fanoutIndex }),\n ...(input.internal ? { internal: true } : {}),\n ...(isPiRuntime(input.runtime) ? {} : { runtime: input.runtime }),\n ...(transcriptPath ? { transcriptPath } : {}),\n ...(systemPromptPath ? { systemPromptPath } : {}),\n ...(systemPromptPath && sdk.systemPromptMode ? { systemPromptMode: sdk.systemPromptMode } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.excludeTools?.length ? { excludeTools: sdk.excludeTools } : {}),\n ...(sdk.noTools ? { noTools: true } : {}),\n });\n\n if (isPiRuntime(input.runtime)) {\n this.writeLaunchConfig(configPath, {\n runId,\n agent,\n task,\n cwd,\n childIndex: input.childIndex,\n handshakePath,\n sdk,\n ...(transcriptPath ? { transcriptPath } : {}),\n args,\n env,\n });\n }\n\n let fableLaunch: ClaudeFableLaunch | undefined;\n const fail = (message: string): never => {\n this.removeLaunchConfig(configPath);\n if (fableLaunch) cleanupClaudeFableLaunch(fableLaunch);\n fs.rmSync(fableProfileResultPathFor(runId), { force: true });\n statusWriter.updateSync((status) => {\n status.state = 'failed';\n status.error = message;\n status.lastUpdate = this.now();\n });\n throw new Error(message);\n };\n\n // One branch, and only one: `pi` runs in-process through the SDK runner and\n // gets the team channel, steering and structured output that go with it.\n // Every other runtime is an external CLI, spawned through the generic\n // runner, which deliberately knows nothing about the vendor.\n const usePi = isPiRuntime(input.runtime);\n if (!usePi) {\n const ceiling = input.piArgs.capabilityCeiling;\n if (ceiling && (!input.externalProfile || !ceiling.allowedExternalProfiles.includes(input.externalProfile))) {\n return fail(\n `External profile '${input.externalProfile ?? 'none'}' is denied by the active capability ceiling.`,\n );\n }\n if (input.externalProfile !== undefined && input.externalProfile !== CLAUDE_FABLE_PROFILE) {\n return fail(`External profile '${input.externalProfile}' is not trusted.`);\n }\n if (input.externalProfile === CLAUDE_FABLE_PROFILE) {\n if (input.runtime !== 'claude' || input.piArgs.model !== 'fable') {\n return fail('The Fable profile requires runtime claude and model fable.');\n }\n if (input.inlineAgent || input.piArgs.sessionFile || input.piArgs.parentSessionId) {\n return fail('The Fable profile requires a fresh isolated context.');\n }\n fableLaunch = prepareClaudeFableLaunch({\n runId,\n prompt: task,\n repositoryCwd: cwd,\n privateRoot: runDir,\n });\n this.writeLaunchConfig(configPath, {\n runId,\n ...(input.operationId ? { operationId: input.operationId } : {}),\n agent,\n runtime: 'claude',\n command: fableLaunch.command,\n args: fableLaunch.args,\n cwd: fableLaunch.cwd,\n env: fableLaunch.env,\n profile: fableLaunch.profile,\n stdinPath: fableLaunch.stdinPath,\n cleanupPaths: fableLaunch.cleanupPaths,\n profileResultPath: fableProfileResultPathFor(runId),\n internal: input.internal === true,\n handshakePath,\n resultPath: path.join(currentResultsDir(), `${runId}.json`),\n });\n } else {\n this.writeLaunchConfig(configPath, {\n runId,\n ...(input.operationId ? { operationId: input.operationId } : {}),\n agent,\n ...resolveRuntimeLaunch(input.runtime as string, input.runtimes ?? {}, {\n prompt: task,\n model: input.piArgs.model,\n cwd,\n }),\n cwd,\n env: builtEnv as Record<string, string>,\n handshakePath,\n resultPath: path.join(currentResultsDir(), `${runId}.json`),\n });\n }\n }\n\n const { pid, onError, onExit } = this.spawnChild(\n process.execPath,\n [usePi ? resolveSdkRunnerEntry() : resolveCliRunnerEntry()],\n { cwd, env: env as NodeJS.ProcessEnv },\n );\n if (pid === undefined) {\n return fail(`Async spawn for '${agent}' (run '${runId}') did not produce a pid.`);\n }\n let spawnError: Error | undefined;\n onError((error) => {\n spawnError = error;\n });\n\n // Recorded before the handshake: a parent that dies between spawn and\n // handshake must still leave a record a later sweep can act on.\n registerRun(requireCurrentSessionScope(), {\n runId,\n pid,\n agent,\n runtime: input.runtime ?? PI_RUNTIME_NAME,\n startedAt: now,\n });\n this.terminalPersistence.trackChild(pid);\n onExit((code, signal) => {\n this.terminalPersistence.untrackChild(pid);\n releaseRun(requireCurrentSessionScope(), runId);\n if (code === 0 && signal === null) return;\n statusWriter.updateSync((status) => {\n if (status.state && TERMINAL_ASYNC_JOB_STATES.has(status.state)) return;\n status.state = 'failed';\n status.error = `SDK runner process ${pid} exited unexpectedly (${signal ?? `code ${code ?? 'unknown'}`}).`;\n status.lastUpdate = this.now();\n status.endedAt = this.now();\n });\n this.jobTracker.track(runId);\n });\n\n const handshake = this.createSpawnHandshake();\n const outcome = await handshake.waitForHandshake({\n path: handshakePath,\n timeoutMs: input.handshakeTimeoutMs ?? this.defaultHandshakeTimeoutMs,\n }).promise;\n\n if (outcome.status !== 'signalled') {\n this.terminalPersistence.untrackChild(pid);\n const message =\n outcome.status === 'failed'\n ? outcome.error\n : (spawnError?.message ?? `Timed out waiting for '${agent}' (run '${runId}') to start.`);\n return fail(message);\n }\n\n // The child has confirmed it read the launch config; the parent's copy\n // is no longer needed (see the module header's LAUNCH CONFIG FILE\n // LIFECYCLE section).\n this.removeLaunchConfig(configPath);\n const observedState = this.readRunState(runId);\n if (!observedState || !TERMINAL_ASYNC_JOB_STATES.has(observedState)) {\n statusWriter.updateSync((status) => {\n status.state = 'running';\n status.lastUpdate = this.now();\n });\n }\n this.jobTracker.track(runId);\n\n return { runId, pid };\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{writePrivateAtomicJson 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{init_supervisorControlChannel as p,steerAcksDir as ee,steerCapabilityPath as te,stepSteerInboxDir as m}from"../../intercom/supervisorControlChannel.mjs";import{currentResultsDir as h,currentRunConfigPath as ne,currentRunsDir as g,init_paths as _,requireCurrentSessionScope as v,sessionScopeEnvironment as re}from"../../../shared/paths.mjs";import{CoalescedStatusWriter as y,STATUS_FILE_NAME as b,init_statusWriter as x}from"./statusWriter.mjs";import{init_runtimeRegistry as S,isPiRuntime as C,resolveRuntimeLaunch as ie}from"../shared/runtimeRegistry.mjs";import{TERMINAL_ASYNC_JOB_STATES as w}from"../../../adapters/asyncJobTracker.mjs";import{init_asyncJobTracker as T}from"./asyncJobTracker.mjs";import{init_nativeTeamChannel as E,nativeTeamRootEnvironment as ae,readNativeTeamRootFromEnvironment as D}from"../../intercom/nativeTeamChannel.mjs";import{getArtifactPaths as O,getArtifactsDir as oe,init_artifacts as k}from"../../../shared/artifacts.mjs";import{registerRun as se,releaseRun as ce}from"../../../adapters/runRegistry.mjs";import{init_runRegistry as A}from"../registry/runRegistry.mjs";import{CLAUDE_FABLE_PROFILE as j,cleanupClaudeFableLaunch as le,init_claudeFableProfile as M,prepareClaudeFableLaunch as ue}from"../shared/claudeFableProfile.mjs";import{buildPiArgs as N,init_piArgs as P}from"../shared/piArgs.mjs";import{SpawnHandshake as de,init_spawnHandshake as fe}from"./spawnHandshake.mjs";import*as F from"node:fs";import*as I from"node:path";import{inject as L,injectable as pe}from"inversify";import{createHarnessSession as R,getHarnessState as z}from"@agimon-ai/doompi-config";import{DOOMPI_EXTENSIONS_PROVIDED_ENV as B}from"@agimon-ai/doompi-extension-contracts/child-process";import{spawn as me}from"node:child_process";import{fileURLToPath as he}from"node:url";function V(e){return I.join(g(),e)}function H(e){return I.join(V(e),G)}function U(e){return I.join(V(e),J)}function ge(e){return I.join(V(e),Y)}function W(e,t){let n=I.dirname(he(import.meta.url)),r=I.resolve(n,`../..`),i=I.join(r,e,`${t}.mjs`);if(F.existsSync(i))return i;let a=I.join(r,e,`${t}.ts`);if(F.existsSync(a))return a;throw Error(`Doom Team runner '${t}' is unavailable at '${i}' or '${a}'.`)}function _e(){return W(`runs`,`sdkRunnerEntry`)}function ve(){return W(`runs/background`,`cliRunnerEntry`)}var G,K,q,J,Y,X,Z,Q,$=e((()=>{c(),i(),k(),o(),_(),E(),p(),A(),M(),P(),S(),T(),fe(),x(),u(),f(),n(),G=`handshake.json`,K=`runner.stdout.log`,q=`runner.stderr.log`,J=`fable-profile-result.json`,Y=`system-prompt.md`,X=384,Z=1e4,Q=class{constructor(e,t){this.jobTracker=e,this.terminalPersistence=t}defaultHandshakeTimeoutMs=Z;now(){return Date.now()}readCurrentTeamRoot(){return D()}createStatusWriter(){return new y}createSpawnHandshake(){return new de}writeLaunchConfig(e,t){a(e,t)}removeLaunchConfig(e){F.rmSync(e,{force:!0})}readRunState(e){try{let t=JSON.parse(F.readFileSync(I.join(V(e),b),`utf8`));return typeof t.state==`string`?t.state:void 0}catch{return}}buildLaunchArgs(e){return N(e)}spawnChild(e,t,n){let r=n.env[s],i,a;if(r){let e=V(r);F.mkdirSync(e,{recursive:!0}),i=F.openSync(I.join(e,K),`a`,384);try{a=F.openSync(I.join(e,q),`a`,384)}catch(e){throw F.closeSync(i),Error(`Could not open runner stderr for '${r}'.`,{cause:e})}}let o;try{o=me(e,t,{cwd:n.cwd,detached:!0,stdio:[`ignore`,i??`ignore`,a??`ignore`],windowsHide:!0,env:n.env})}finally{i!==void 0&&F.closeSync(i),a!==void 0&&F.closeSync(a)}return o.unref(),{pid:o.pid,onError:e=>o.on(`error`,e),onExit:e=>o.on(`exit`,e)}}async spawn(e){let{runId:t,agent:n,task:r,cwd:i}=e,a=e.fanout?e.childIndex:void 0,o=H(t),s=ne(t),c=e.artifacts===!1?void 0:O(oe(e.parentSessionFile??null,i,e.artifactDir??`session`),t,n).transcriptPath,l=V(t),u=e.childIndex??0,d=this.readCurrentTeamRoot(),{args:f,env:p,sdk:g}=this.buildLaunchArgs({...e.piArgs,runId:t,task:r,childIndex:e.childIndex,steerInboxDir:m(l,u),steerCapabilityPath:te(l,u),steerAckDir:ee(l,u),teamToolEnabled:!!d});R({...z(),childExtensions:g.extensions},{directory:l,environment:p,unclaimed:!0});let _={...process.env,...p,...re(v()),...d?ae(d):{}};C(e.runtime)&&(g.extensionsProvidedExternally?_[B]=`1`:delete _[B]);let y;if(C(e.runtime)&&g.systemPrompt)try{F.mkdirSync(l,{recursive:!0});let e=ge(t);F.writeFileSync(e,g.systemPrompt,{mode:X}),y=e}catch{y=void 0}let b=this.now(),x=this.createStatusWriter();x.open(t,{version:1,runId:t,...e.operationId?{operationId:e.operationId}:{},agent:n,...e.sensitiveTask?{}:{task:r},cwd:i,...e.piArgs.model?{model:e.piArgs.model}:{},...e.inlineAgent?{inlineAgent:e.inlineAgent}:{},state:`queued`,startedAt:b,lastUpdate:b,...a===void 0?{}:{fanoutIndex:a},...e.internal?{internal:!0}:{},...C(e.runtime)?{}:{runtime:e.runtime},...c?{transcriptPath:c}:{},...y?{systemPromptPath:y}:{},...y&&g.systemPromptMode?{systemPromptMode:g.systemPromptMode}:{},...g.tools?{tools:g.tools}:{},...g.excludeTools?.length?{excludeTools:g.excludeTools}:{},...g.noTools?{noTools:!0}:{}}),C(e.runtime)&&this.writeLaunchConfig(s,{runId:t,agent:n,task:r,cwd:i,childIndex:e.childIndex,handshakePath:o,sdk:g,...c?{transcriptPath:c}:{},args:f,env:_});let S,T=e=>{throw this.removeLaunchConfig(s),S&&le(S),F.rmSync(U(t),{force:!0}),x.updateSync(t=>{t.state=`failed`,t.error=e,t.lastUpdate=this.now()}),Error(e)},E=C(e.runtime);if(!E){let a=e.piArgs.capabilityCeiling;if(a&&(!e.externalProfile||!a.allowedExternalProfiles.includes(e.externalProfile)))return T(`External profile '${e.externalProfile??`none`}' is denied by the active capability ceiling.`);if(e.externalProfile!==void 0&&e.externalProfile!==j)return T(`External profile '${e.externalProfile}' is not trusted.`);if(e.externalProfile===j){if(e.runtime!==`claude`||e.piArgs.model!==`fable`)return T(`The Fable profile requires runtime claude and model fable.`);if(e.inlineAgent||e.piArgs.sessionFile||e.piArgs.parentSessionId)return T(`The Fable profile requires a fresh isolated context.`);S=ue({runId:t,prompt:r,repositoryCwd:i,privateRoot:l}),this.writeLaunchConfig(s,{runId:t,...e.operationId?{operationId:e.operationId}:{},agent:n,runtime:`claude`,command:S.command,args:S.args,cwd:S.cwd,env:S.env,profile:S.profile,stdinPath:S.stdinPath,cleanupPaths:S.cleanupPaths,profileResultPath:U(t),internal:e.internal===!0,handshakePath:o,resultPath:I.join(h(),`${t}.json`)})}else this.writeLaunchConfig(s,{runId:t,...e.operationId?{operationId:e.operationId}:{},agent:n,...ie(e.runtime,e.runtimes??{},{prompt:r,model:e.piArgs.model,cwd:i}),cwd:i,env:p,handshakePath:o,resultPath:I.join(h(),`${t}.json`)})}let{pid:D,onError:k,onExit:A}=this.spawnChild(process.execPath,[E?_e():ve()],{cwd:i,env:_});if(D===void 0)return T(`Async spawn for '${n}' (run '${t}') did not produce a pid.`);let M;k(e=>{M=e}),se(v(),{runId:t,pid:D,agent:n,runtime:e.runtime??`pi`,startedAt:b}),this.terminalPersistence.trackChild(D),A((e,n)=>{this.terminalPersistence.untrackChild(D),ce(v(),t),!(e===0&&n===null)&&(x.updateSync(t=>{t.state&&w.has(t.state)||(t.state=`failed`,t.error=`SDK runner process ${D} exited unexpectedly (${n??`code ${e??`unknown`}`}).`,t.lastUpdate=this.now(),t.endedAt=this.now())}),this.jobTracker.track(t))});let N=await this.createSpawnHandshake().waitForHandshake({path:o,timeoutMs:e.handshakeTimeoutMs??this.defaultHandshakeTimeoutMs}).promise;if(N.status!==`signalled`)return this.terminalPersistence.untrackChild(D),T(N.status===`failed`?N.error:M?.message??`Timed out waiting for '${n}' (run '${t}') to start.`);this.removeLaunchConfig(s);let P=this.readRunState(t);return(!P||!w.has(P))&&x.updateSync(e=>{e.state=`running`,e.lastUpdate=this.now()}),this.jobTracker.track(t),{runId:t,pid:D}}},Q=t([pe(),d(0,L(r.AsyncJobTracker)),d(1,L(r.TerminalPersistenceService)),l(`design:paramtypes`,[Object,Object])],Q)}));$();export{Q as AsyncSubagentSpawner,U as fableProfileResultPathFor,H as handshakePathFor,$ as init_asyncExecution,V as runDirFor};
2
+ //# sourceMappingURL=asyncExecution.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncExecution.mjs","names":[],"sources":["../../../../src/services/runs/background/asyncExecution.ts"],"sourcesContent":["/**\n * The async-only spawn executor: launches exactly one subagent child process\n * and returns a run handle immediately, without waiting for the run to\n * finish.\n *\n * SCOPE - PARENT SIDE ONLY, SINGLE SPAWN:\n * `doom-pi-subagents/src/runs/background/asyncExecution.ts` is 1698 lines\n * doing far more than spawning: chain/parallel-group orchestration (building\n * `AgentConfig[]` sequences, dynamic fan-out expansion, workflow-graph\n * snapshots), session revival (a 3-way ready/ack/proceed handshake distinct\n * from the plain started-signal this module uses), and the foreground\n * (synchronous, blocking) code path. None of that is ported here:\n * - Chain/fan-out ORCHESTRATION (deciding how many children to spawn, in\n * what order, from what step list) is `port-steering`'s concurrent work on\n * the resolved-step and workflow-graph types. This module is the\n * PRIMITIVE that orchestration calls once per child - `childIndex` and\n * `fanout` arrive as inputs, already decided by the caller, not derived\n * here (see the child-index section below for why that is safe)\n * - Session revival (`revivalLease`, the 3-way ready/ack/proceed dance at\n * predecessor lines 498-509) is a materially different operation - resuming\n * an existing transcript, not spawning a fresh child - and is not ported.\n * `session-lease.ts` already exists in this package for whoever builds that\n * path later\n * - The foreground (synchronous) branch is dropped entirely, per the async-\n * only requirement below; there is no `async` parameter, only this\n *\n * WHAT THIS DOES NOT BUILD (compose, don't reimplement):\n * `CoalescedStatusWriter`, `TerminalPersistenceService`, `AsyncJobTracker`,\n * `SpawnHandshake`, `ResultWatcher`, `CompletionNotifier` all already exist\n * in this directory and are used here, not reimplemented. In particular, the\n * predecessor's process-exit tracking is reduced to the child handle's exact\n * exit signal: an abnormal exit marks that run failed immediately, while the\n * crash-marker path (`TerminalPersistenceService` +\n * `ProcessTerminalInspector`) remains the recovery path after parent loss.\n * `trackChild(pid)` on the caller's own already-active\n * `TerminalPersistenceService` is what makes a spawned child get killed if\n * the run that spawned it dies, which is the same guarantee the predecessor\n * used its own mechanism for.\n *\n * SDK RUNNER BOUNDARY:\n * `sdkRunnerEntry.ts` is the detached child process target. It reads the\n * launch config, creates the child through Pi's SDK, and loads\n * `subagent-prompt-runtime-entry` as an explicit child extension. That\n * extension owns the handshake, status, steering, and terminal result\n * lifecycle through the existing runner services. The real Pi CLI remains\n * the parent host used by system tests and DoomPi, not the child launcher.\n *\n * WHY SpawnHandshake, NOT `Atomics.wait`:\n * The predecessor blocks the parent's event loop for up to 10 seconds per\n * spawn (`asyncExecution.ts:376-380`, `Atomics.wait` on a shared buffer).\n * That codepath only actually ran for session revival there (a fresh spawn\n * had no `startupPath` and returned immediately) - but this package has no\n * synchronous/foreground path left to hide the cost behind, so a busy-wait\n * would block every single async spawn, not just revivals. `SpawnHandshake`\n * (already in this directory) replaces it: a real `fs.watch` on the\n * handshake file's directory, with a short poll as the safety net, and it\n * never blocks the event loop.\n *\n * LAUNCH CONFIG FILE LIFECYCLE (fix):\n * The predecessor writes the launch config with `fs.writeFileSync(cfgPath,\n * ...)` - no `mode` option, so it lands at the umask default - and never\n * unlinks it on any path, successful or failed\n * (`asyncExecution.ts:491-495`). Both are fixed here: `writeLaunchConfig`\n * writes 0600 (`writePrivateAtomicJson`, already in this package), and\n * `removeLaunchConfig` runs on every exit path - success (once the handshake\n * confirms the child has read it), and every failure (no pid, spawn error,\n * handshake failure or timeout) - so nothing is ever left behind holding the\n * full task text and resolved secrets/tokens at world-readable-adjacent\n * permissions.\n *\n * CHILD INDEX (fix - `DeliverableGuard` had no way to get one):\n * `DeliverableGuard.deliverNudge` requires an explicit `nudgeTarget` of\n * `{kind:'child', index}` for a fan-out run specifically so it cannot\n * broadcast a nudge to every sibling over one child's missing deliverable\n * (see that module's header). Nothing in this package maps a team member id\n * to a fan-out child index (verified: neither `nativeTeamChannel.ts` nor\n * `parallel-groups.ts` does this). This module needs no such mapping either\n * - `childIndex` is simply which spawn call this is, a fact the caller (a\n * single spawn, or a fan-out loop calling this once per child) already knows\n * without looking anything up, exactly like a flat index into\n * `status.steps[]` is decided by whoever builds that array. `nudgeTarget` is\n * derived from `childIndex`/`fanout` and persisted onto the run's own\n * `status.json` (`nudgeTarget` field) for whatever later evaluates\n * `DeliverableGuardInput` to read back, rather than re-derived at that point.\n *\n * DELIVERABLE EXPECTATION (fix - `DeliverableGuard` had no policy):\n * Derived here, at the one point this module already has the task text:\n * `classifyTaskMutationIntent` (used AS-IS, per its own header's warning\n * against widening its vocabulary for a third caller) distinguishes\n * `'implementation'` intent from `'read-only'`/`'unknown'`. Implementation\n * intent gets a real expectation (`{kind:'summary'}` by default - the\n * minimum a run can be asked to prove it did something, when no more\n * specific expectation like a structured-output schema or artifact path was\n * supplied); read-only or unknown intent gets none at all. This is\n * deliberately NOT `{kind:'summary'}` unconditionally: a guard that flags\n * every research run for an empty summary gets ignored, and an ignored guard\n * misses the run that actually needed it.\n *\n * TEAM MEMBERSHIP ENV FORWARDING (fix - a spawned child had no way to join\n * the team):\n * If THIS process (the one calling `spawn()`) is itself part of a native\n * team - `readNativeTeamRootFromEnvironment()` resolves a root context off\n * its own `process.env` - the same root vars\n * (`nativeTeamRootEnvironment(root)`, already in `nativeTeamChannel.ts`,\n * not reimplemented here) are folded into the child's env alongside\n * whatever `buildPiArgs` produced. Only the ROOT vars travel this way, never\n * a member id/token: those are per-member secrets the CHILD mints for\n * itself when it registers (see `runnerBootstrap.ts` and\n * `runnerTeamMembership.ts`), not something safe to hand down from the\n * parent's own identity. When this process has no team root (a standalone\n * spawn outside any team), nothing is forwarded and the child simply has\n * none to register against.\n */\n\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createHarnessSession, getHarnessState } from '@agimon-ai/doompi-config';\nimport { DOOMPI_EXTENSIONS_PROVIDED_ENV } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport type { InlineAgent } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport { inject, injectable } from 'inversify';\nimport { PI_RUNTIME_NAME, SUBAGENT_RUN_ID_ENV } from '../../../adapters/process/env.ts';\nimport { DOOM_TEAM_TYPES } from '../../../container/types.ts';\nimport { getArtifactPaths, getArtifactsDir } from '../../../shared/artifacts.ts';\nimport { writePrivateAtomicJson } from '../../../shared/atomicJson.ts';\nimport {\n currentResultsDir,\n currentRunConfigPath,\n currentRunsDir,\n requireCurrentSessionScope,\n sessionScopeEnvironment,\n} from '../../../shared/paths.ts';\nimport type { ActivityState, ArtifactDirPreference } from '../../../types/index.ts';\nimport {\n nativeTeamRootEnvironment,\n readNativeTeamRootFromEnvironment,\n type TeamRootContext,\n} from '../../intercom/nativeTeamChannel.ts';\nimport { steerAcksDir, steerCapabilityPath, stepSteerInboxDir } from '../../intercom/supervisorControlChannel.ts';\nimport { registerRun, releaseRun } from '../registry/runRegistry.ts';\nimport {\n CLAUDE_FABLE_PROFILE,\n type ClaudeFableLaunch,\n cleanupClaudeFableLaunch,\n prepareClaudeFableLaunch,\n} from '../shared/claudeFableProfile.ts';\nimport {\n type BuildPiArgsInput,\n type BuildPiArgsResult,\n buildPiArgs,\n type PiSdkLaunchSettings,\n} from '../shared/piArgs.ts';\nimport { isPiRuntime, type RuntimeTable, resolveRuntimeLaunch } from '../shared/runtimeRegistry.ts';\nimport { type IAsyncJobTracker, TERMINAL_ASYNC_JOB_STATES } from './asyncJobTracker.ts';\nimport { type ISpawnHandshake, SpawnHandshake } from './spawnHandshake.ts';\nimport {\n CoalescedStatusWriter,\n type ICoalescedStatusWriter,\n STATUS_FILE_NAME,\n type StatusWithRecentEntries,\n} from './statusWriter.ts';\nimport type { ITerminalPersistenceService } from './terminalPersistence.ts';\n\n/** Leaf name of the started-signal file `SpawnHandshake` watches for, under `currentRunsDir()/<runId>/`. Exported so the child-side runner can compose the same convention rather than duplicate it. */\nexport const HANDSHAKE_FILE_NAME = 'handshake.json';\nexport const RUNNER_STDOUT_FILE_NAME = 'runner.stdout.log';\nexport const RUNNER_STDERR_FILE_NAME = 'runner.stderr.log';\nexport const FABLE_PROFILE_RESULT_FILE_NAME = 'fable-profile-result.json';\n/**\n * The effective system prompt this run launched with, kept for the fleet\n * inspector's agent view.\n *\n * A SIDECAR RATHER THAN A FIELD ON status.json: `CoalescedStatusWriter`\n * rewrites the whole status file on every coalesced flush, and a system prompt\n * is kilobytes of text that never changes after spawn. Inlining it would put\n * that payload through every status write for the life of the run. This file\n * is written once, next to the status it belongs to.\n *\n * Written 0600 for the same reason `piArgs.ts` writes its prompt file that\n * way: a resolved prompt can carry inherited project context.\n */\nexport const SYSTEM_PROMPT_FILE_NAME = 'system-prompt.md';\nconst SYSTEM_PROMPT_FILE_MODE = 0o600;\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 10_000;\n\n/**\n * `state`/`steps`/`parallelGroups`/`chainStepCount`/`workflowGraph`/\n * `pendingAppends` are declared as optional-and-widened, rather than a\n * runner-owned status type, so this SAME status shape is what\n * `chain-append.ts`'s `applyChainAppendRequest` (which expects\n * `AppendableChainStatus`, an object with exactly these optional fields) can\n * mutate directly - one status type for the whole spawn-through-finalize\n * lifecycle, not a parent-side one and a child-side one that have to be kept\n * in sync by hand.\n */\nexport interface AsyncRunStatus extends StatusWithRecentEntries {\n /** Version 1 is emitted by current writers; absent is accepted only by the compatibility reader. */\n version?: 1;\n runId: string;\n operationId?: string;\n agent: string;\n /** Original task text required to restore a suspended run. */\n task?: string;\n cwd?: string;\n /** Resolved model selected for this run, when one was requested. */\n model?: string;\n /** One-shot agent definition required to restore an inline agent. */\n inlineAgent?: InlineAgent;\n state: 'queued' | 'running' | 'complete' | 'completed' | 'failed' | 'paused' | 'stopped';\n startedAt: number;\n lastUpdate: number;\n endedAt?: number;\n /** This run's position among its fan-out siblings, when it has any. Absent for a standalone run. */\n fanoutIndex?: number;\n /** Bridge-owned runs are consumed internally and never rendered as generic completion chat. */\n internal?: boolean;\n /** Which runtime executes this run. Absent means the default in-process `pi` path. */\n runtime?: string;\n activityState?: ActivityState;\n attentionReason?: string;\n error?: string;\n /**\n * Set once, at finalize, by `RunnerReporting.mutateTerminalStatus` - the\n * SAME value it puts in the terminal result file, truncated to a bounded\n * length (see that module's header for why). Lets a caller (chain mode,\n * in particular) learn a completed run's own summary through the status\n * file it already reads to learn the run finished, rather than needing a\n * second read of a claimed, single-consumer result file.\n */\n summary?: string;\n /**\n * This run's own Pi session transcript path, written during child bootstrap\n * and retained by `RunnerReporting.mutateTerminalStatus` at finalize. See\n * that module's header for where the value comes from and why it is bounded\n * by omission, not truncation. Absent for a run that either never reported\n * a session file (headless, no persisted transcript) or reported one too\n * long to trust. This is what `action='resume'` reads to know which\n * transcript a later revival should reopen.\n */\n sessionFile?: string;\n /** Child-owned Pi SDK event transcript consumed by the fleet detail pane. */\n transcriptPath?: string;\n /**\n * Sidecar holding this run's effective system prompt, and the resolved tool\n * plan it launched with. Recorded at spawn purely so the fleet inspector can\n * show what an agent was actually told: the launch config that carried them\n * is deleted as soon as the child handshakes, and the agent definition on\n * disk can change while a run is still going.\n *\n * All absent for a non-`pi` runtime, which has no SDK launch settings, and\n * for any run started before this was recorded.\n */\n systemPromptPath?: string;\n systemPromptMode?: 'append' | 'replace';\n /** Effective tool allowlist. Absent means \"whatever the child defaults to\". */\n tools?: string[];\n excludeTools?: string[];\n noTools?: boolean;\n /** Cumulative tokens observed from finalized child messages. */\n tokens?: number;\n /** Most recently started child tool. */\n currentTool?: string;\n /** Number of child tool executions observed so far. */\n toolCount?: number;\n}\n\n/** The parent-written contract a child-side runner reads via `currentRunConfigPath(runId)`. */\nexport interface LaunchConfig {\n runId: string;\n agent: string;\n task: string;\n cwd: string;\n childIndex: number;\n handshakePath: string;\n sdk: PiSdkLaunchSettings;\n transcriptPath?: string;\n /** Retained during the SDK cutover for compatibility diagnostics only. */\n args: string[];\n env: Record<string, string | undefined>;\n}\n\nexport interface AsyncSubagentSpawnInput {\n runId: string;\n operationId?: string;\n agent: string;\n /** One-shot agent definition retained only for explicit suspension restore. */\n inlineAgent?: InlineAgent;\n task: string;\n cwd: string;\n /** Persisted parent transcript used to place child artifacts beside the parent session. */\n parentSessionFile?: string;\n /** This spawn's position among its siblings. 0 for a standalone (non-fan-out) run. */\n childIndex: number;\n /** Whether this spawn is one of several children under a fan-out parent. */\n fanout: boolean;\n /** Everything `buildPiArgs` needs, minus what this spawner supplies itself (`runId`/`task`/`childIndex`). */\n piArgs: Omit<BuildPiArgsInput, 'runId' | 'task' | 'childIndex'>;\n /** False disables the child event transcript. Defaults to enabled. */\n artifacts?: boolean;\n /** Artifact root policy inherited from the parent Doom Team config. */\n artifactDir?: ArtifactDirPreference;\n handshakeTimeoutMs?: number;\n /**\n * Which runtime executes this run. Defaults to the in-process Pi SDK path.\n * Anything else is an external CLI resolved through `runtimeRegistry.ts`.\n */\n runtime?: string;\n /** Fixed trusted external profile. Only Doom Team internal bridges may set this. */\n externalProfile?: string;\n /** Prevent sensitive task text from being persisted in status.json. */\n sensitiveTask?: boolean;\n /** Suppress the generic completion notifier for an internal bridge run. */\n internal?: boolean;\n /** Runtimes available to this spawn, already merged with the shipped defaults. */\n runtimes?: RuntimeTable;\n}\n\nexport interface AsyncSubagentSpawnResult {\n runId: string;\n pid: number;\n}\n\nexport interface IAsyncSubagentSpawner {\n /** Spawn one child and return once it has confirmed it started. Throws on any failure to reach that point. */\n spawn(input: AsyncSubagentSpawnInput): Promise<AsyncSubagentSpawnResult>;\n}\n\n/** `currentRunsDir()/<runId>`. Exported so the child-side runner resolves the same directory, not a parallel one. */\nexport function runDirFor(runId: string): string {\n return path.join(currentRunsDir(), runId);\n}\n\n/** Exported so the child-side runner writes its ready/error signal at the exact path this parent half waits on. */\nexport function handshakePathFor(runId: string): string {\n return path.join(runDirFor(runId), HANDSHAKE_FILE_NAME);\n}\n\nexport function fableProfileResultPathFor(runId: string): string {\n return path.join(runDirFor(runId), FABLE_PROFILE_RESULT_FILE_NAME);\n}\n\n/** Where `spawn()` records this run's effective system prompt. See `SYSTEM_PROMPT_FILE_NAME`. */\nexport function systemPromptPathFor(runId: string): string {\n return path.join(runDirFor(runId), SYSTEM_PROMPT_FILE_NAME);\n}\n\n/**\n * Locate a child entry point on disk, built or source.\n *\n * The child is a separate process loading this by path, so the path has to be\n * the one that exists now: `.mjs` under `dist` when this bundle is built, the\n * original source file when it is not. `relativeDir` is where the entry sits\n * relative to `src/` - the SDK runner is one level up from this module, the\n * CLI runner is beside it.\n */\nfunction resolveRunnerEntry(relativeDir: string, stem: string): string {\n const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));\n const packageRoot = path.resolve(moduleDirectory, '../..');\n const builtCandidate = path.join(packageRoot, relativeDir, `${stem}.mjs`);\n if (fs.existsSync(builtCandidate)) return builtCandidate;\n const sourceCandidate = path.join(packageRoot, relativeDir, `${stem}.ts`);\n if (fs.existsSync(sourceCandidate)) return sourceCandidate;\n throw new Error(`Doom Team runner '${stem}' is unavailable at '${builtCandidate}' or '${sourceCandidate}'.`);\n}\n\nfunction resolveSdkRunnerEntry(): string {\n return resolveRunnerEntry('runs', 'sdkRunnerEntry');\n}\n\nfunction resolveCliRunnerEntry(): string {\n return resolveRunnerEntry('runs/background', 'cliRunnerEntry');\n}\n\n@injectable()\nexport class AsyncSubagentSpawner implements IAsyncSubagentSpawner {\n constructor(\n @inject(DOOM_TEAM_TYPES.AsyncJobTracker) private readonly jobTracker: IAsyncJobTracker,\n @inject(DOOM_TEAM_TYPES.TerminalPersistenceService)\n private readonly terminalPersistence: ITerminalPersistenceService,\n ) {}\n\n /**\n * Seam for tests, as a protected member rather than a constructor\n * argument: inversify cannot resolve a primitive. See `pollScheduler.ts`\n * for the same pattern.\n */\n protected readonly defaultHandshakeTimeoutMs: number = DEFAULT_HANDSHAKE_TIMEOUT_MS;\n\n protected now(): number {\n return Date.now();\n }\n\n /**\n * This process's own team root context, read fresh per spawn. Protected\n * so a test can supply one without writing real team files to disk - see\n * the module header's TEAM MEMBERSHIP ENV FORWARDING section for why this\n * is read from `process.env` rather than accepted as a constructor\n * argument (inversify cannot resolve a primitive either way).\n */\n protected readCurrentTeamRoot(): TeamRootContext | undefined {\n return readNativeTeamRootFromEnvironment();\n }\n\n /**\n * A fresh writer per spawn, deliberately never the container's shared\n * singleton - the same reasoning as `StaleRunReconciler.createStatusWriter`\n * (see that class's header): the singleton may simultaneously be the live\n * write path for a run THIS process is itself running, and bootstrapping\n * someone else's (the spawned child's) initial status is a different\n * writer's job.\n */\n protected createStatusWriter(): ICoalescedStatusWriter<AsyncRunStatus> {\n return new CoalescedStatusWriter<AsyncRunStatus>();\n }\n\n /**\n * A fresh handshake wait per spawn. `SpawnHandshake` is bound transient in\n * the container for exactly this reason (each `waitForHandshake()` owns\n * its own timers and watcher for exactly one spawn); resolving it via\n * constructor injection would hand every spawn the same, already-used\n * instance, so this seam constructs one directly instead.\n */\n protected createSpawnHandshake(): ISpawnHandshake {\n return new SpawnHandshake();\n }\n\n protected writeLaunchConfig(filePath: string, config: object): void {\n writePrivateAtomicJson(filePath, config);\n }\n\n protected removeLaunchConfig(filePath: string): void {\n fs.rmSync(filePath, { force: true });\n }\n\n protected readRunState(runId: string): string | undefined {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(runDirFor(runId), STATUS_FILE_NAME), 'utf8')) as {\n state?: unknown;\n };\n return typeof parsed.state === 'string' ? parsed.state : undefined;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Resolves the child's CLI args/env. Protected so a test can bypass\n * `buildPiArgs`'s own real filesystem resolution (it locates a runtime\n * extension script on disk via `resolvePiLaunchToolPlan`, which is\n * environment-dependent and not something a unit test for THIS module's\n * orchestration logic should depend on).\n */\n protected buildLaunchArgs(input: BuildPiArgsInput): BuildPiArgsResult {\n return buildPiArgs(input);\n }\n\n /**\n * The actual `child_process.spawn`. Detached and unref'd immediately. Output\n * goes to per-run files so a startup failure is diagnosable without keeping\n * parent-owned pipes alive.\n */\n protected spawnChild(\n command: string,\n args: string[],\n options: { cwd: string; env: NodeJS.ProcessEnv },\n ): {\n pid: number | undefined;\n onError: (handler: (error: Error) => void) => void;\n onExit: (handler: (code: number | null, signal: NodeJS.Signals | null) => void) => void;\n } {\n const runId = options.env[SUBAGENT_RUN_ID_ENV];\n let stdoutFd: number | undefined;\n let stderrFd: number | undefined;\n if (runId) {\n const runDir = runDirFor(runId);\n fs.mkdirSync(runDir, { recursive: true });\n stdoutFd = fs.openSync(path.join(runDir, RUNNER_STDOUT_FILE_NAME), 'a', 0o600);\n try {\n stderrFd = fs.openSync(path.join(runDir, RUNNER_STDERR_FILE_NAME), 'a', 0o600);\n } catch (error) {\n fs.closeSync(stdoutFd);\n throw new Error(`Could not open runner stderr for '${runId}'.`, { cause: error });\n }\n }\n let child: ReturnType<typeof spawn>;\n try {\n child = spawn(command, args, {\n cwd: options.cwd,\n detached: true,\n stdio: ['ignore', stdoutFd ?? 'ignore', stderrFd ?? 'ignore'],\n windowsHide: true,\n env: options.env,\n });\n } finally {\n if (stdoutFd !== undefined) fs.closeSync(stdoutFd);\n if (stderrFd !== undefined) fs.closeSync(stderrFd);\n }\n child.unref();\n return {\n pid: child.pid,\n onError: (handler) => child.on('error', handler),\n onExit: (handler) => child.on('exit', handler),\n };\n }\n\n async spawn(input: AsyncSubagentSpawnInput): Promise<AsyncSubagentSpawnResult> {\n const { runId, agent, task, cwd } = input;\n const fanoutIndex = input.fanout ? input.childIndex : undefined;\n const handshakePath = handshakePathFor(runId);\n const configPath = currentRunConfigPath(runId);\n const transcriptPath =\n input.artifacts === false\n ? undefined\n : getArtifactPaths(\n getArtifactsDir(input.parentSessionFile ?? null, cwd, input.artifactDir ?? 'session'),\n runId,\n agent,\n ).transcriptPath;\n\n const runDir = runDirFor(runId);\n const steerIndex = input.childIndex ?? 0;\n const teamRoot = this.readCurrentTeamRoot();\n const {\n args,\n env: builtEnv,\n sdk,\n } = this.buildLaunchArgs({\n ...input.piArgs,\n runId,\n task,\n childIndex: input.childIndex,\n steerInboxDir: stepSteerInboxDir(runDir, steerIndex),\n steerCapabilityPath: steerCapabilityPath(runDir, steerIndex),\n steerAckDir: steerAcksDir(runDir, steerIndex),\n teamToolEnabled: Boolean(teamRoot),\n });\n // The child gets its own harness state, in this run's directory, which this\n // package owns. Sharing the parent's file would let a detached child rewrite\n // a session it does not own, and pointing at the parent's directory would\n // lose the file the moment the parent cleaned up its own session: a child\n // is detached and can outlive it. Pi 0.84 SDK launches consume the resolved\n // extension list directly, so preserve that same list in the child harness\n // snapshot instead of projecting the parent's stale childExtensions value.\n createHarnessSession(\n { ...getHarnessState(), childExtensions: sdk.extensions },\n { directory: runDir, environment: builtEnv, unclaimed: true },\n );\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n ...builtEnv,\n // The child resolves the same filesystem tree from this, independently of\n // whether it also joins a team.\n ...sessionScopeEnvironment(requireCurrentSessionScope()),\n ...(teamRoot ? nativeTeamRootEnvironment(teamRoot) : {}),\n };\n if (isPiRuntime(input.runtime)) {\n if (sdk.extensionsProvidedExternally) env[DOOMPI_EXTENSIONS_PROVIDED_ENV] = '1';\n else delete env[DOOMPI_EXTENSIONS_PROVIDED_ENV];\n }\n\n // Recorded before open() so the status never advertises a sidecar that is\n // not on disk yet. A failure here is not worth failing a spawn over: the\n // prompt is an inspection aid, so the run proceeds without it.\n let systemPromptPath: string | undefined;\n if (isPiRuntime(input.runtime) && sdk.systemPrompt) {\n try {\n fs.mkdirSync(runDir, { recursive: true });\n const target = systemPromptPathFor(runId);\n fs.writeFileSync(target, sdk.systemPrompt, { mode: SYSTEM_PROMPT_FILE_MODE });\n systemPromptPath = target;\n } catch {\n systemPromptPath = undefined;\n }\n }\n\n const now = this.now();\n const statusWriter = this.createStatusWriter();\n statusWriter.open(runId, {\n version: 1,\n runId,\n ...(input.operationId ? { operationId: input.operationId } : {}),\n agent,\n ...(input.sensitiveTask ? {} : { task }),\n cwd,\n ...(input.piArgs.model ? { model: input.piArgs.model } : {}),\n ...(input.inlineAgent ? { inlineAgent: input.inlineAgent } : {}),\n state: 'queued',\n startedAt: now,\n lastUpdate: now,\n ...(fanoutIndex === undefined ? {} : { fanoutIndex }),\n ...(input.internal ? { internal: true } : {}),\n ...(isPiRuntime(input.runtime) ? {} : { runtime: input.runtime }),\n ...(transcriptPath ? { transcriptPath } : {}),\n ...(systemPromptPath ? { systemPromptPath } : {}),\n ...(systemPromptPath && sdk.systemPromptMode ? { systemPromptMode: sdk.systemPromptMode } : {}),\n ...(sdk.tools ? { tools: sdk.tools } : {}),\n ...(sdk.excludeTools?.length ? { excludeTools: sdk.excludeTools } : {}),\n ...(sdk.noTools ? { noTools: true } : {}),\n });\n\n if (isPiRuntime(input.runtime)) {\n this.writeLaunchConfig(configPath, {\n runId,\n agent,\n task,\n cwd,\n childIndex: input.childIndex,\n handshakePath,\n sdk,\n ...(transcriptPath ? { transcriptPath } : {}),\n args,\n env,\n });\n }\n\n let fableLaunch: ClaudeFableLaunch | undefined;\n const fail = (message: string): never => {\n this.removeLaunchConfig(configPath);\n if (fableLaunch) cleanupClaudeFableLaunch(fableLaunch);\n fs.rmSync(fableProfileResultPathFor(runId), { force: true });\n statusWriter.updateSync((status) => {\n status.state = 'failed';\n status.error = message;\n status.lastUpdate = this.now();\n });\n throw new Error(message);\n };\n\n // One branch, and only one: `pi` runs in-process through the SDK runner and\n // gets the team channel, steering and structured output that go with it.\n // Every other runtime is an external CLI, spawned through the generic\n // runner, which deliberately knows nothing about the vendor.\n const usePi = isPiRuntime(input.runtime);\n if (!usePi) {\n const ceiling = input.piArgs.capabilityCeiling;\n if (ceiling && (!input.externalProfile || !ceiling.allowedExternalProfiles.includes(input.externalProfile))) {\n return fail(\n `External profile '${input.externalProfile ?? 'none'}' is denied by the active capability ceiling.`,\n );\n }\n if (input.externalProfile !== undefined && input.externalProfile !== CLAUDE_FABLE_PROFILE) {\n return fail(`External profile '${input.externalProfile}' is not trusted.`);\n }\n if (input.externalProfile === CLAUDE_FABLE_PROFILE) {\n if (input.runtime !== 'claude' || input.piArgs.model !== 'fable') {\n return fail('The Fable profile requires runtime claude and model fable.');\n }\n if (input.inlineAgent || input.piArgs.sessionFile || input.piArgs.parentSessionId) {\n return fail('The Fable profile requires a fresh isolated context.');\n }\n fableLaunch = prepareClaudeFableLaunch({\n runId,\n prompt: task,\n repositoryCwd: cwd,\n privateRoot: runDir,\n });\n this.writeLaunchConfig(configPath, {\n runId,\n ...(input.operationId ? { operationId: input.operationId } : {}),\n agent,\n runtime: 'claude',\n command: fableLaunch.command,\n args: fableLaunch.args,\n cwd: fableLaunch.cwd,\n env: fableLaunch.env,\n profile: fableLaunch.profile,\n stdinPath: fableLaunch.stdinPath,\n cleanupPaths: fableLaunch.cleanupPaths,\n profileResultPath: fableProfileResultPathFor(runId),\n internal: input.internal === true,\n handshakePath,\n resultPath: path.join(currentResultsDir(), `${runId}.json`),\n });\n } else {\n this.writeLaunchConfig(configPath, {\n runId,\n ...(input.operationId ? { operationId: input.operationId } : {}),\n agent,\n ...resolveRuntimeLaunch(input.runtime as string, input.runtimes ?? {}, {\n prompt: task,\n model: input.piArgs.model,\n cwd,\n }),\n cwd,\n env: builtEnv as Record<string, string>,\n handshakePath,\n resultPath: path.join(currentResultsDir(), `${runId}.json`),\n });\n }\n }\n\n const { pid, onError, onExit } = this.spawnChild(\n process.execPath,\n [usePi ? resolveSdkRunnerEntry() : resolveCliRunnerEntry()],\n { cwd, env: env as NodeJS.ProcessEnv },\n );\n if (pid === undefined) {\n return fail(`Async spawn for '${agent}' (run '${runId}') did not produce a pid.`);\n }\n let spawnError: Error | undefined;\n onError((error) => {\n spawnError = error;\n });\n\n // Recorded before the handshake: a parent that dies between spawn and\n // handshake must still leave a record a later sweep can act on.\n registerRun(requireCurrentSessionScope(), {\n runId,\n pid,\n agent,\n runtime: input.runtime ?? PI_RUNTIME_NAME,\n startedAt: now,\n });\n this.terminalPersistence.trackChild(pid);\n onExit((code, signal) => {\n this.terminalPersistence.untrackChild(pid);\n releaseRun(requireCurrentSessionScope(), runId);\n if (code === 0 && signal === null) return;\n statusWriter.updateSync((status) => {\n if (status.state && TERMINAL_ASYNC_JOB_STATES.has(status.state)) return;\n status.state = 'failed';\n status.error = `SDK runner process ${pid} exited unexpectedly (${signal ?? `code ${code ?? 'unknown'}`}).`;\n status.lastUpdate = this.now();\n status.endedAt = this.now();\n });\n this.jobTracker.track(runId);\n });\n\n const handshake = this.createSpawnHandshake();\n const outcome = await handshake.waitForHandshake({\n path: handshakePath,\n timeoutMs: input.handshakeTimeoutMs ?? this.defaultHandshakeTimeoutMs,\n }).promise;\n\n if (outcome.status !== 'signalled') {\n this.terminalPersistence.untrackChild(pid);\n const message =\n outcome.status === 'failed'\n ? outcome.error\n : (spawnError?.message ?? `Timed out waiting for '${agent}' (run '${runId}') to start.`);\n return fail(message);\n }\n\n // The child has confirmed it read the launch config; the parent's copy\n // is no longer needed (see the module header's LAUNCH CONFIG FILE\n // LIFECYCLE section).\n this.removeLaunchConfig(configPath);\n const observedState = this.readRunState(runId);\n if (!observedState || !TERMINAL_ASYNC_JOB_STATES.has(observedState)) {\n statusWriter.updateSync((status) => {\n status.state = 'running';\n status.lastUpdate = this.now();\n });\n }\n this.jobTracker.track(runId);\n\n return { runId, pid };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ require(`../../../adapters/asyncJobTracker.cjs`);
@@ -0,0 +1,2 @@
1
+ import{__esmMin as e}from"../../../_virtual/_rolldown/runtime.mjs";import{init_asyncJobTracker as t}from"../../../adapters/asyncJobTracker.mjs";var n=e((()=>{t()}));n();export{n as init_asyncJobTracker};
2
+ //# sourceMappingURL=asyncJobTracker.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncJobTracker.mjs","names":[],"sources":["../../../../src/services/runs/background/asyncJobTracker.ts"],"sourcesContent":["export {\n AsyncJobTracker,\n type IAsyncJobTracker,\n type ITrackedAsyncJobs,\n resolveTrackedRunId,\n TERMINAL_ASYNC_JOB_STATES,\n type TrackedAsyncJob,\n} from '../../../adapters/asyncJobTracker.ts';\n"],"mappings":"iKAO8C"}