@agimon-ai/doompi-team 0.0.1-alpha.24 → 0.0.1-alpha.26

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 (360) hide show
  1. package/README.md +3 -3
  2. package/dist/api/capabilityCeiling.cjs +1 -1
  3. package/dist/api/capabilityCeiling.d.cts +2 -2
  4. package/dist/api/capabilityCeiling.d.mts +2 -2
  5. package/dist/api/capabilityCeiling.mjs +1 -1
  6. package/dist/extensions/pi.cjs +1 -1
  7. package/dist/extensions/pi.d.cts +1 -1
  8. package/dist/extensions/pi.d.mts +1 -1
  9. package/dist/extensions/pi.mjs +1 -1
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.d.cts +1 -3
  12. package/dist/index.d.mts +1 -3
  13. package/dist/index.mjs +1 -2
  14. package/dist/src/adapters/asyncJobTracker.cjs +1 -1
  15. package/dist/src/adapters/asyncJobTracker.cjs.map +1 -1
  16. package/dist/src/adapters/asyncJobTracker.mjs +1 -1
  17. package/dist/src/adapters/asyncJobTracker.mjs.map +1 -1
  18. package/dist/src/adapters/intercom/nativeTeamChannel.cjs +4 -4
  19. package/dist/src/adapters/intercom/nativeTeamChannel.cjs.map +1 -1
  20. package/dist/src/adapters/intercom/nativeTeamChannel.d.cts.map +1 -1
  21. package/dist/src/adapters/intercom/nativeTeamChannel.d.mts.map +1 -1
  22. package/dist/src/adapters/intercom/nativeTeamChannel.mjs +4 -4
  23. package/dist/src/adapters/intercom/nativeTeamChannel.mjs.map +1 -1
  24. package/dist/src/adapters/pi/collaboration.cjs +2 -0
  25. package/dist/src/adapters/pi/collaboration.cjs.map +1 -0
  26. package/dist/src/adapters/pi/collaboration.mjs +2 -0
  27. package/dist/src/adapters/pi/collaboration.mjs.map +1 -0
  28. package/dist/src/adapters/pi/extension.cjs +1 -1
  29. package/dist/src/adapters/pi/extension.cjs.map +1 -1
  30. package/dist/src/adapters/pi/extension.mjs +1 -1
  31. package/dist/src/adapters/pi/extension.mjs.map +1 -1
  32. package/dist/src/adapters/pi/promptRuntime.cjs +2 -0
  33. package/dist/src/adapters/pi/promptRuntime.cjs.map +1 -0
  34. package/dist/src/adapters/pi/promptRuntime.mjs +2 -0
  35. package/dist/src/adapters/pi/promptRuntime.mjs.map +1 -0
  36. package/dist/src/adapters/pi/standard.cjs +2 -0
  37. package/dist/src/adapters/pi/standard.cjs.map +1 -0
  38. package/dist/src/adapters/pi/standard.d.cts +7 -0
  39. package/dist/src/adapters/pi/standard.d.cts.map +1 -0
  40. package/dist/src/adapters/pi/standard.d.mts +7 -0
  41. package/dist/src/adapters/pi/standard.d.mts.map +1 -0
  42. package/dist/src/adapters/pi/standard.mjs +2 -0
  43. package/dist/src/adapters/pi/standard.mjs.map +1 -0
  44. package/dist/src/adapters/pi/teamRuntime.cjs +2 -0
  45. package/dist/src/adapters/pi/teamRuntime.cjs.map +1 -0
  46. package/dist/src/adapters/pi/teamRuntime.mjs +2 -0
  47. package/dist/src/adapters/pi/teamRuntime.mjs.map +1 -0
  48. package/dist/src/adapters/pollScheduler.cjs +1 -1
  49. package/dist/src/adapters/pollScheduler.cjs.map +1 -1
  50. package/dist/src/adapters/pollScheduler.mjs +1 -1
  51. package/dist/src/adapters/pollScheduler.mjs.map +1 -1
  52. package/dist/src/adapters/process/sdkRunnerEntry.cjs +1 -1
  53. package/dist/src/adapters/process/sdkRunnerEntry.mjs +1 -1
  54. package/dist/src/adapters/processTerminal.cjs +1 -1
  55. package/dist/src/adapters/processTerminal.cjs.map +1 -1
  56. package/dist/src/adapters/processTerminal.mjs +1 -1
  57. package/dist/src/adapters/processTerminal.mjs.map +1 -1
  58. package/dist/src/adapters/resultWatcher.cjs +1 -1
  59. package/dist/src/adapters/resultWatcher.cjs.map +1 -1
  60. package/dist/src/adapters/resultWatcher.mjs +1 -1
  61. package/dist/src/adapters/resultWatcher.mjs.map +1 -1
  62. package/dist/src/adapters/runIdResolver.cjs +1 -1
  63. package/dist/src/adapters/runIdResolver.cjs.map +1 -1
  64. package/dist/src/adapters/runIdResolver.mjs +1 -1
  65. package/dist/src/adapters/runIdResolver.mjs.map +1 -1
  66. package/dist/src/adapters/staleRunReconciler.cjs +1 -1
  67. package/dist/src/adapters/staleRunReconciler.cjs.map +1 -1
  68. package/dist/src/adapters/staleRunReconciler.mjs +1 -1
  69. package/dist/src/adapters/staleRunReconciler.mjs.map +1 -1
  70. package/dist/src/adapters/subagentLaunchContract.mjs +1 -1
  71. package/dist/src/adapters/subagentLaunchContract.mjs.map +1 -1
  72. package/dist/src/adapters/suspendedRuns.mjs +2 -2
  73. package/dist/src/adapters/suspendedRuns.mjs.map +1 -1
  74. package/dist/src/commands/slash/slashCommands.mjs +3 -3
  75. package/dist/src/commands/slash/slashCommands.mjs.map +1 -1
  76. package/dist/src/commands/slash/subagentLaunch.cjs +1 -1
  77. package/dist/src/commands/slash/subagentLaunch.mjs +1 -1
  78. package/dist/src/extensions/config.mjs +1 -1
  79. package/dist/src/extensions/config.mjs.map +1 -1
  80. package/dist/src/extensions/delegationBridge.cjs +1 -1
  81. package/dist/src/extensions/delegationBridge.cjs.map +1 -1
  82. package/dist/src/extensions/delegationBridge.mjs +1 -1
  83. package/dist/src/extensions/delegationBridge.mjs.map +1 -1
  84. package/dist/src/extensions/fablePlanBridge.cjs +1 -1
  85. package/dist/src/extensions/fablePlanBridge.cjs.map +1 -1
  86. package/dist/src/extensions/fablePlanBridge.mjs +1 -1
  87. package/dist/src/extensions/fablePlanBridge.mjs.map +1 -1
  88. package/dist/src/extensions/managementActions.cjs +1 -1
  89. package/dist/src/extensions/managementActions.cjs.map +1 -1
  90. package/dist/src/extensions/managementActions.mjs +1 -1
  91. package/dist/src/extensions/managementActions.mjs.map +1 -1
  92. package/dist/src/extensions/operationJournal.cjs +1 -1
  93. package/dist/src/extensions/operationJournal.mjs +1 -1
  94. package/dist/src/extensions/operationJournal.mjs.map +1 -1
  95. package/dist/src/extensions/schemas.mjs +1 -2
  96. package/dist/src/extensions/spawnPlan.cjs +3 -3
  97. package/dist/src/extensions/spawnPlan.cjs.map +1 -1
  98. package/dist/src/extensions/spawnPlan.mjs +3 -3
  99. package/dist/src/extensions/spawnPlan.mjs.map +1 -1
  100. package/dist/src/extensions/statusViews.mjs +6 -6
  101. package/dist/src/extensions/statusViews.mjs.map +1 -1
  102. package/dist/src/extensions/subagentPromptRuntime.cjs +9 -9
  103. package/dist/src/extensions/subagentPromptRuntime.cjs.map +1 -1
  104. package/dist/src/extensions/subagentPromptRuntime.d.cts +2 -12
  105. package/dist/src/extensions/subagentPromptRuntime.d.cts.map +1 -1
  106. package/dist/src/extensions/subagentPromptRuntime.d.mts +2 -12
  107. package/dist/src/extensions/subagentPromptRuntime.d.mts.map +1 -1
  108. package/dist/src/extensions/subagentPromptRuntime.mjs +5 -5
  109. package/dist/src/extensions/subagentPromptRuntime.mjs.map +1 -1
  110. package/dist/src/extensions/subagentTool.cjs +5 -5
  111. package/dist/src/extensions/subagentTool.cjs.map +1 -1
  112. package/dist/src/extensions/subagentTool.mjs +5 -5
  113. package/dist/src/extensions/subagentTool.mjs.map +1 -1
  114. package/dist/src/extensions/toolDescription.mjs +1 -1
  115. package/dist/src/extensions/toolDescription.mjs.map +1 -1
  116. package/dist/src/schemas/team/capabilityCeiling.cjs +1 -1
  117. package/dist/src/schemas/team/capabilityCeiling.cjs.map +1 -1
  118. package/dist/src/schemas/team/capabilityCeiling.d.cts +1 -15
  119. package/dist/src/schemas/team/capabilityCeiling.d.cts.map +1 -1
  120. package/dist/src/schemas/team/capabilityCeiling.d.mts +1 -15
  121. package/dist/src/schemas/team/capabilityCeiling.d.mts.map +1 -1
  122. package/dist/src/schemas/team/capabilityCeiling.mjs +1 -1
  123. package/dist/src/schemas/team/capabilityCeiling.mjs.map +1 -1
  124. package/dist/src/schemas/team/packageConfig.mjs +1 -1
  125. package/dist/src/schemas/team/packageConfig.mjs.map +1 -1
  126. package/dist/src/services/agents/discovery.cjs +1 -1
  127. package/dist/src/services/agents/discovery.cjs.map +1 -1
  128. package/dist/src/services/agents/discovery.mjs +1 -1
  129. package/dist/src/services/agents/discovery.mjs.map +1 -1
  130. package/dist/src/services/agents/frontmatter.mjs +5 -5
  131. package/dist/src/services/agents/frontmatter.mjs.map +1 -1
  132. package/dist/src/services/agents/loader.mjs +1 -1
  133. package/dist/src/services/agents/loader.mjs.map +1 -1
  134. package/dist/src/services/agents/memory.mjs +2 -2
  135. package/dist/src/services/agents/memory.mjs.map +1 -1
  136. package/dist/src/services/agents/projectRoot.mjs +1 -1
  137. package/dist/src/services/agents/projectRoot.mjs.map +1 -1
  138. package/dist/src/services/agents/settings.mjs +1 -1
  139. package/dist/src/services/agents/settings.mjs.map +1 -1
  140. package/dist/src/services/agents/skills.cjs +0 -0
  141. package/dist/src/services/agents/skills.cjs.map +1 -1
  142. package/dist/src/services/agents/skills.mjs +0 -0
  143. package/dist/src/services/agents/skills.mjs.map +1 -1
  144. package/dist/src/services/api/capabilityCeiling.d.cts +1 -1
  145. package/dist/src/services/api/capabilityCeiling.d.mts +1 -1
  146. package/dist/src/services/api/capabilityCeiling.mjs.map +1 -1
  147. package/dist/src/services/backgroundWorkService.cjs +2 -0
  148. package/dist/src/services/backgroundWorkService.cjs.map +1 -0
  149. package/dist/src/services/backgroundWorkService.mjs +2 -0
  150. package/dist/src/services/backgroundWorkService.mjs.map +1 -0
  151. package/dist/src/services/intercom/supervisorControlChannel.cjs +1 -1
  152. package/dist/src/services/intercom/supervisorControlChannel.cjs.map +1 -1
  153. package/dist/src/services/intercom/supervisorControlChannel.mjs +1 -1
  154. package/dist/src/services/intercom/supervisorControlChannel.mjs.map +1 -1
  155. package/dist/src/services/runs/background/asyncExecution.cjs +1 -1
  156. package/dist/src/services/runs/background/asyncExecution.cjs.map +1 -1
  157. package/dist/src/services/runs/background/asyncExecution.mjs +1 -1
  158. package/dist/src/services/runs/background/asyncExecution.mjs.map +1 -1
  159. package/dist/src/services/runs/background/cliRunnerEntry.cjs +1 -1
  160. package/dist/src/services/runs/background/cliRunnerEntry.mjs +1 -1
  161. package/dist/src/services/runs/background/completionBatcher.mjs +1 -1
  162. package/dist/src/services/runs/background/completionBatcher.mjs.map +1 -1
  163. package/dist/src/services/runs/background/notify.cjs +3 -3
  164. package/dist/src/services/runs/background/notify.cjs.map +1 -1
  165. package/dist/src/services/runs/background/notify.mjs +3 -3
  166. package/dist/src/services/runs/background/notify.mjs.map +1 -1
  167. package/dist/src/services/runs/background/runnerBootstrap.cjs +1 -1
  168. package/dist/src/services/runs/background/runnerBootstrap.cjs.map +1 -1
  169. package/dist/src/services/runs/background/runnerBootstrap.d.cts +1 -0
  170. package/dist/src/services/runs/background/runnerBootstrap.d.mts +1 -0
  171. package/dist/src/services/runs/background/runnerBootstrap.mjs +1 -1
  172. package/dist/src/services/runs/background/runnerBootstrap.mjs.map +1 -1
  173. package/dist/src/services/runs/background/runnerExecution.cjs +1 -1
  174. package/dist/src/services/runs/background/runnerExecution.cjs.map +1 -1
  175. package/dist/src/services/runs/background/runnerExecution.d.cts +1 -0
  176. package/dist/src/services/runs/background/runnerExecution.d.mts +1 -0
  177. package/dist/src/services/runs/background/runnerExecution.mjs +1 -1
  178. package/dist/src/services/runs/background/runnerExecution.mjs.map +1 -1
  179. package/dist/src/services/runs/background/runnerReporting.cjs +2 -2
  180. package/dist/src/services/runs/background/runnerReporting.cjs.map +1 -1
  181. package/dist/src/services/runs/background/runnerReporting.d.cts +1 -0
  182. package/dist/src/services/runs/background/runnerReporting.d.mts +1 -0
  183. package/dist/src/services/runs/background/runnerReporting.mjs +2 -2
  184. package/dist/src/services/runs/background/runnerReporting.mjs.map +1 -1
  185. package/dist/src/services/runs/background/runnerTeamMembership.cjs +1 -1
  186. package/dist/src/services/runs/background/runnerTeamMembership.cjs.map +1 -1
  187. package/dist/src/services/runs/background/runnerTeamMembership.d.cts +1 -0
  188. package/dist/src/services/runs/background/runnerTeamMembership.d.mts +1 -0
  189. package/dist/src/services/runs/background/runnerTeamMembership.mjs +1 -1
  190. package/dist/src/services/runs/background/runnerTeamMembership.mjs.map +1 -1
  191. package/dist/src/services/runs/background/spawnHandshake.cjs +1 -1
  192. package/dist/src/services/runs/background/spawnHandshake.cjs.map +1 -1
  193. package/dist/src/services/runs/background/spawnHandshake.mjs +1 -1
  194. package/dist/src/services/runs/background/spawnHandshake.mjs.map +1 -1
  195. package/dist/src/services/runs/background/statusWriter.cjs +1 -1
  196. package/dist/src/services/runs/background/statusWriter.cjs.map +1 -1
  197. package/dist/src/services/runs/background/statusWriter.mjs +1 -1
  198. package/dist/src/services/runs/background/statusWriter.mjs.map +1 -1
  199. package/dist/src/services/runs/background/subagentWait.cjs +1 -1
  200. package/dist/src/services/runs/background/subagentWait.cjs.map +1 -1
  201. package/dist/src/services/runs/background/subagentWait.mjs +1 -1
  202. package/dist/src/services/runs/background/subagentWait.mjs.map +1 -1
  203. package/dist/src/services/runs/background/terminalPersistence.cjs +1 -1
  204. package/dist/src/services/runs/background/terminalPersistence.cjs.map +1 -1
  205. package/dist/src/services/runs/background/terminalPersistence.mjs +1 -1
  206. package/dist/src/services/runs/background/terminalPersistence.mjs.map +1 -1
  207. package/dist/src/services/runs/registry/sessionLifecycle.cjs +1 -1
  208. package/dist/src/services/runs/registry/sessionLifecycle.cjs.map +1 -1
  209. package/dist/src/services/runs/registry/sessionLifecycle.mjs +1 -1
  210. package/dist/src/services/runs/registry/sessionLifecycle.mjs.map +1 -1
  211. package/dist/src/services/runs/registry/suspendedRuns.mjs +1 -2
  212. package/dist/src/services/runs/shared/depthGuard.mjs +1 -1
  213. package/dist/src/services/runs/shared/depthGuard.mjs.map +1 -1
  214. package/dist/src/services/runs/shared/mcpDirectToolAllowlist.cjs +1 -1
  215. package/dist/src/services/runs/shared/mcpDirectToolAllowlist.cjs.map +1 -1
  216. package/dist/src/services/runs/shared/mcpDirectToolAllowlist.mjs +1 -1
  217. package/dist/src/services/runs/shared/mcpDirectToolAllowlist.mjs.map +1 -1
  218. package/dist/src/services/runs/shared/modelFallback.mjs +1 -1
  219. package/dist/src/services/runs/shared/modelFallback.mjs.map +1 -1
  220. package/dist/src/services/runs/shared/modelScope.mjs +1 -1
  221. package/dist/src/services/runs/shared/modelScope.mjs.map +1 -1
  222. package/dist/src/services/runs/shared/piArgs.cjs +1 -1
  223. package/dist/src/services/runs/shared/piArgs.d.cts +1 -0
  224. package/dist/src/services/runs/shared/piArgs.d.mts +1 -0
  225. package/dist/src/services/runs/shared/piArgs.mjs +1 -1
  226. package/dist/src/services/runs/shared/runWithConcurrency.mjs +1 -1
  227. package/dist/src/services/runs/shared/runWithConcurrency.mjs.map +1 -1
  228. package/dist/src/services/runs/shared/structuredOutput.cjs +1 -1
  229. package/dist/src/services/runs/shared/structuredOutput.cjs.map +1 -1
  230. package/dist/src/services/runs/shared/structuredOutput.mjs +1 -1
  231. package/dist/src/services/runs/shared/structuredOutput.mjs.map +1 -1
  232. package/dist/src/services/subagentPolicyService.cjs +2 -0
  233. package/dist/src/services/subagentPolicyService.cjs.map +1 -0
  234. package/dist/src/services/subagentPolicyService.mjs +2 -0
  235. package/dist/src/services/subagentPolicyService.mjs.map +1 -0
  236. package/dist/src/shared/formatters.mjs +1 -1
  237. package/dist/src/shared/formatters.mjs.map +1 -1
  238. package/dist/src/shared/modelResolution.mjs +1 -1
  239. package/dist/src/shared/modelResolution.mjs.map +1 -1
  240. package/dist/src/tui/agentResourceProjection.mjs +1 -1
  241. package/dist/src/tui/agentResourceProjection.mjs.map +1 -1
  242. package/dist/src/tui/completionNotice.cjs +3 -3
  243. package/dist/src/tui/completionNotice.mjs +3 -3
  244. package/dist/src/tui/completionNotice.mjs.map +1 -1
  245. package/dist/src/tui/fleet.cjs +2 -2
  246. package/dist/src/tui/fleet.mjs +2 -2
  247. package/dist/src/tui/fleet.mjs.map +1 -1
  248. package/dist/src/tui/fleetAgentView.mjs +1 -1
  249. package/dist/src/tui/fleetAgentView.mjs.map +1 -1
  250. package/dist/src/tui/fleetStatus.cjs.map +1 -1
  251. package/dist/src/tui/fleetStatus.mjs.map +1 -1
  252. package/dist/src/tui/fleetTranscript.mjs +4 -4
  253. package/dist/src/tui/fleetTranscript.mjs.map +1 -1
  254. package/dist/src/tui/register.cjs +1 -1
  255. package/dist/src/tui/register.cjs.map +1 -1
  256. package/dist/src/tui/register.mjs +1 -1
  257. package/dist/src/tui/register.mjs.map +1 -1
  258. package/dist/src/tui/subagentToolRender.cjs +1 -1
  259. package/dist/src/tui/subagentToolRender.mjs +2 -2
  260. package/dist/src/tui/subagentToolRender.mjs.map +1 -1
  261. package/dist/src/types/index.d.cts +1 -23
  262. package/dist/src/types/index.d.cts.map +1 -1
  263. package/dist/src/types/index.d.mts +1 -23
  264. package/dist/src/types/index.d.mts.map +1 -1
  265. package/package.json +7 -10
  266. package/dist/_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs +0 -1
  267. package/dist/_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs +0 -1
  268. package/dist/_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs +0 -1
  269. package/dist/_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.mjs +0 -1
  270. package/dist/_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs +0 -1
  271. package/dist/_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.mjs +0 -1
  272. package/dist/api/backgroundWork.cjs +0 -1
  273. package/dist/api/backgroundWork.d.cts +0 -2
  274. package/dist/api/backgroundWork.d.mts +0 -2
  275. package/dist/api/backgroundWork.mjs +0 -1
  276. package/dist/index.mjs.map +0 -1
  277. package/dist/src/container/bindOrRebind.cjs +0 -2
  278. package/dist/src/container/bindOrRebind.cjs.map +0 -1
  279. package/dist/src/container/bindOrRebind.mjs +0 -2
  280. package/dist/src/container/bindOrRebind.mjs.map +0 -1
  281. package/dist/src/container/globalBridge.cjs +0 -2
  282. package/dist/src/container/globalBridge.cjs.map +0 -1
  283. package/dist/src/container/globalBridge.mjs +0 -2
  284. package/dist/src/container/globalBridge.mjs.map +0 -1
  285. package/dist/src/container/index.cjs +0 -2
  286. package/dist/src/container/index.cjs.map +0 -1
  287. package/dist/src/container/index.d.cts +0 -39
  288. package/dist/src/container/index.d.cts.map +0 -1
  289. package/dist/src/container/index.d.mts +0 -39
  290. package/dist/src/container/index.d.mts.map +0 -1
  291. package/dist/src/container/index.mjs +0 -2
  292. package/dist/src/container/index.mjs.map +0 -1
  293. package/dist/src/container/modules/agents.cjs +0 -2
  294. package/dist/src/container/modules/agents.cjs.map +0 -1
  295. package/dist/src/container/modules/agents.d.mts +0 -1
  296. package/dist/src/container/modules/agents.mjs +0 -2
  297. package/dist/src/container/modules/agents.mjs.map +0 -1
  298. package/dist/src/container/modules/core.cjs +0 -2
  299. package/dist/src/container/modules/core.cjs.map +0 -1
  300. package/dist/src/container/modules/core.d.mts +0 -1
  301. package/dist/src/container/modules/core.mjs +0 -2
  302. package/dist/src/container/modules/core.mjs.map +0 -1
  303. package/dist/src/container/modules/extensions.cjs +0 -2
  304. package/dist/src/container/modules/extensions.cjs.map +0 -1
  305. package/dist/src/container/modules/extensions.mjs +0 -2
  306. package/dist/src/container/modules/extensions.mjs.map +0 -1
  307. package/dist/src/container/modules/intercom.cjs +0 -2
  308. package/dist/src/container/modules/intercom.cjs.map +0 -1
  309. package/dist/src/container/modules/intercom.mjs +0 -2
  310. package/dist/src/container/modules/intercom.mjs.map +0 -1
  311. package/dist/src/container/modules/runs.cjs +0 -2
  312. package/dist/src/container/modules/runs.cjs.map +0 -1
  313. package/dist/src/container/modules/runs.mjs +0 -2
  314. package/dist/src/container/modules/runs.mjs.map +0 -1
  315. package/dist/src/container/types.cjs +0 -2
  316. package/dist/src/container/types.cjs.map +0 -1
  317. package/dist/src/container/types.d.cts +0 -46
  318. package/dist/src/container/types.d.cts.map +0 -1
  319. package/dist/src/container/types.d.mts +0 -46
  320. package/dist/src/container/types.d.mts.map +0 -1
  321. package/dist/src/container/types.mjs +0 -2
  322. package/dist/src/container/types.mjs.map +0 -1
  323. package/dist/src/extensions/schemas.mjs.map +0 -1
  324. package/dist/src/extensions/standard.cjs +0 -2
  325. package/dist/src/extensions/standard.cjs.map +0 -1
  326. package/dist/src/extensions/standard.d.cts +0 -8
  327. package/dist/src/extensions/standard.d.cts.map +0 -1
  328. package/dist/src/extensions/standard.d.mts +0 -8
  329. package/dist/src/extensions/standard.d.mts.map +0 -1
  330. package/dist/src/extensions/standard.mjs +0 -2
  331. package/dist/src/extensions/standard.mjs.map +0 -1
  332. package/dist/src/schemas/team/backgroundWork.cjs +0 -2
  333. package/dist/src/schemas/team/backgroundWork.cjs.map +0 -1
  334. package/dist/src/schemas/team/backgroundWork.d.cts +0 -52
  335. package/dist/src/schemas/team/backgroundWork.d.cts.map +0 -1
  336. package/dist/src/schemas/team/backgroundWork.d.mts +0 -52
  337. package/dist/src/schemas/team/backgroundWork.d.mts.map +0 -1
  338. package/dist/src/schemas/team/backgroundWork.mjs +0 -2
  339. package/dist/src/schemas/team/backgroundWork.mjs.map +0 -1
  340. package/dist/src/services/api/backgroundWork.cjs +0 -1
  341. package/dist/src/services/api/backgroundWork.mjs +0 -1
  342. package/dist/src/services/runs/background/processTerminal.cjs +0 -1
  343. package/dist/src/services/runs/background/processTerminal.mjs +0 -2
  344. package/dist/src/services/runs/background/processTerminal.mjs.map +0 -1
  345. package/dist/src/services/runs/background/runIdResolver.cjs +0 -1
  346. package/dist/src/services/runs/background/runIdResolver.mjs +0 -2
  347. package/dist/src/services/runs/background/runIdResolver.mjs.map +0 -1
  348. package/dist/src/services/runs/background/staleRunReconciler.cjs +0 -1
  349. package/dist/src/services/runs/background/staleRunReconciler.mjs +0 -2
  350. package/dist/src/services/runs/background/staleRunReconciler.mjs.map +0 -1
  351. package/dist/src/services/runs/registry/suspendedRuns.mjs.map +0 -1
  352. package/dist/src/services/runs/shared/runWithConcurrency.d.cts +0 -25
  353. package/dist/src/services/runs/shared/runWithConcurrency.d.cts.map +0 -1
  354. package/dist/src/services/runs/shared/runWithConcurrency.d.mts +0 -25
  355. package/dist/src/services/runs/shared/runWithConcurrency.d.mts.map +0 -1
  356. package/dist/src/shared/pollScheduler.cjs +0 -1
  357. package/dist/src/shared/pollScheduler.mjs +0 -2
  358. package/dist/src/shared/pollScheduler.mjs.map +0 -1
  359. /package/dist/src/{container/modules/agents.d.cts → services/runs/background/asyncExecution.d.cts} +0 -0
  360. /package/dist/src/{container/modules/core.d.cts → services/runs/background/asyncExecution.d.mts} +0 -0
package/README.md CHANGED
@@ -81,15 +81,15 @@ With Task installed:
81
81
  3. Team owns the background run, messaging, steering, and suspension.
82
82
  4. Task records the terminal result on its own task.
83
83
 
84
- This is a protocol relationship, not shared persistence.
84
+ This is a named Cordis-service relationship, not shared persistence. Team provides `doom/delegation`, `doom/background-work`, `doom/subagent-policy`, and `doom/fable-plan` from the active session fiber; consumers unload and rebind automatically with that provider.
85
85
 
86
86
  ## Public API
87
87
 
88
88
  ```ts
89
- import { createExtensionContainer, resolveSubagentLaunchContract } from '@agimon-ai/doompi-team';
89
+ import { resolveSubagentLaunchContract } from '@agimon-ai/doompi-team';
90
90
  ```
91
91
 
92
- Focused subpaths expose background-work, capability-ceiling, delegation, and team-snapshot contracts. The standard Pi factory is available at `/extensions/pi`.
92
+ Focused subpaths expose the pure capability-ceiling codec, legacy delegation payload vocabulary, and team-snapshot contracts. Live cross-extension collaboration contracts come from `@agimon-ai/doompi-extension-contracts`; the standard Pi factory is available at `/extensions/pi`.
93
93
 
94
94
  ## Development
95
95
 
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../src/adapters/process/env.cjs`),t=require(`../src/schemas/team/capabilityCeiling.cjs`);require(`../src/services/api/capabilityCeiling.cjs`),exports.SUBAGENT_CAPABILITY_CEILING_ENV=e.SUBAGENT_CAPABILITY_CEILING_ENV,exports.SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY=t.SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY,exports.SUBAGENT_CAPABILITY_CEILING_VERSION=t.SUBAGENT_CAPABILITY_CEILING_VERSION,exports.decodeSubagentCapabilityCeiling=t.decodeSubagentCapabilityCeiling,exports.encodeSubagentCapabilityCeiling=t.encodeSubagentCapabilityCeiling,exports.intersectSubagentCapabilityCeilings=t.intersectSubagentCapabilityCeilings,exports.parseSubagentCapabilityCeiling=t.parseSubagentCapabilityCeiling,exports.registerSubagentCapabilityCeiling=t.registerSubagentCapabilityCeiling,exports.resolveCurrentSubagentCapabilityCeiling=t.resolveCurrentSubagentCapabilityCeiling,exports.resolveSubagentCapabilityCeiling=t.resolveSubagentCapabilityCeiling;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../src/adapters/process/env.cjs`),t=require(`../src/schemas/team/capabilityCeiling.cjs`);require(`../src/services/api/capabilityCeiling.cjs`),exports.SUBAGENT_CAPABILITY_CEILING_ENV=e.SUBAGENT_CAPABILITY_CEILING_ENV,exports.SUBAGENT_CAPABILITY_CEILING_VERSION=t.SUBAGENT_CAPABILITY_CEILING_VERSION,exports.decodeSubagentCapabilityCeiling=t.decodeSubagentCapabilityCeiling,exports.encodeSubagentCapabilityCeiling=t.encodeSubagentCapabilityCeiling,exports.intersectSubagentCapabilityCeilings=t.intersectSubagentCapabilityCeilings,exports.parseSubagentCapabilityCeiling=t.parseSubagentCapabilityCeiling;
@@ -1,3 +1,3 @@
1
1
  import { SUBAGENT_CAPABILITY_CEILING_ENV } from "../src/adapters/process/env.cjs";
2
- import { RegisterSubagentCapabilityCeilingOptions, ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, SubagentCapabilityCeilingHandle, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling, registerSubagentCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling, resolveSubagentCapabilityCeiling } from "../src/schemas/team/capabilityCeiling.cjs";
3
- export { RegisterSubagentCapabilityCeilingOptions, ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, SubagentCapabilityCeilingHandle, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling, registerSubagentCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling, resolveSubagentCapabilityCeiling };
2
+ import { ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling } from "../src/schemas/team/capabilityCeiling.cjs";
3
+ export { ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling };
@@ -1,3 +1,3 @@
1
1
  import { SUBAGENT_CAPABILITY_CEILING_ENV } from "../src/adapters/process/env.mjs";
2
- import { RegisterSubagentCapabilityCeilingOptions, ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, SubagentCapabilityCeilingHandle, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling, registerSubagentCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling, resolveSubagentCapabilityCeiling } from "../src/schemas/team/capabilityCeiling.mjs";
3
- export { RegisterSubagentCapabilityCeilingOptions, ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, SubagentCapabilityCeilingHandle, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling, registerSubagentCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling, resolveSubagentCapabilityCeiling };
2
+ import { ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling } from "../src/schemas/team/capabilityCeiling.mjs";
3
+ export { ResolvedSubagentCapabilityCeiling, SUBAGENT_CAPABILITY_CEILING_ENV, SUBAGENT_CAPABILITY_CEILING_VERSION, SubagentCapabilityAudit, SubagentCapabilityCeiling, decodeSubagentCapabilityCeiling, encodeSubagentCapabilityCeiling, intersectSubagentCapabilityCeilings, parseSubagentCapabilityCeiling };
@@ -1 +1 @@
1
- import{SUBAGENT_CAPABILITY_CEILING_ENV as e}from"../src/adapters/process/env.mjs";import{SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY as t,SUBAGENT_CAPABILITY_CEILING_VERSION as n,decodeSubagentCapabilityCeiling as r,encodeSubagentCapabilityCeiling as i,intersectSubagentCapabilityCeilings as a,parseSubagentCapabilityCeiling as o,registerSubagentCapabilityCeiling as s,resolveCurrentSubagentCapabilityCeiling as c,resolveSubagentCapabilityCeiling as l}from"../src/schemas/team/capabilityCeiling.mjs";import"../src/services/api/capabilityCeiling.mjs";export{e as SUBAGENT_CAPABILITY_CEILING_ENV,t as SUBAGENT_CAPABILITY_CEILING_REGISTRY_KEY,n as SUBAGENT_CAPABILITY_CEILING_VERSION,r as decodeSubagentCapabilityCeiling,i as encodeSubagentCapabilityCeiling,a as intersectSubagentCapabilityCeilings,o as parseSubagentCapabilityCeiling,s as registerSubagentCapabilityCeiling,c as resolveCurrentSubagentCapabilityCeiling,l as resolveSubagentCapabilityCeiling};
1
+ import{SUBAGENT_CAPABILITY_CEILING_ENV as e}from"../src/adapters/process/env.mjs";import{SUBAGENT_CAPABILITY_CEILING_VERSION as t,decodeSubagentCapabilityCeiling as n,encodeSubagentCapabilityCeiling as r,intersectSubagentCapabilityCeilings as i,parseSubagentCapabilityCeiling as a}from"../src/schemas/team/capabilityCeiling.mjs";import"../src/services/api/capabilityCeiling.mjs";export{e as SUBAGENT_CAPABILITY_CEILING_ENV,t as SUBAGENT_CAPABILITY_CEILING_VERSION,n as decodeSubagentCapabilityCeiling,r as encodeSubagentCapabilityCeiling,i as intersectSubagentCapabilityCeilings,a as parseSubagentCapabilityCeiling};
@@ -1 +1 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require(`../src/extensions/standard.cjs`);exports.activateTeamExtension=e.activateTeamExtension,exports.default=e.activateTeamExtension;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require(`../src/adapters/pi/standard.cjs`);exports.activateTeamExtension=e,exports.default=e;
@@ -1,2 +1,2 @@
1
- import { activateTeamExtension } from "../src/extensions/standard.cjs";
1
+ import { activateTeamExtension } from "../src/adapters/pi/standard.cjs";
2
2
  export { activateTeamExtension, activateTeamExtension as default };
@@ -1,2 +1,2 @@
1
- import { activateTeamExtension } from "../src/extensions/standard.mjs";
1
+ import { activateTeamExtension } from "../src/adapters/pi/standard.mjs";
2
2
  export { activateTeamExtension, activateTeamExtension as default };
@@ -1 +1 @@
1
- import{activateTeamExtension as e}from"../src/extensions/standard.mjs";export{e as activateTeamExtension,e as default};
1
+ import e from"../src/adapters/pi/standard.mjs";export{e as activateTeamExtension,e as default};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./src/container/types.cjs`),t=require(`./src/container/index.cjs`),n=require(`./src/adapters/subagentLaunchContract.cjs`);exports.DOOM_TEAM_TYPES=e.DOOM_TEAM_TYPES,exports.createExtensionContainer=t.createExtensionContainer,exports.createPromptRuntimeContainer=t.createPromptRuntimeContainer,exports.resolveSubagentLaunchContract=n.resolveSubagentLaunchContract;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./src/adapters/subagentLaunchContract.cjs`);exports.resolveSubagentLaunchContract=e.resolveSubagentLaunchContract;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,2 @@
1
- import { DOOM_TEAM_TYPES } from "./src/container/types.cjs";
2
- import { createExtensionContainer, createPromptRuntimeContainer } from "./src/container/index.cjs";
3
1
  import { SubagentLaunchContract, SubagentLaunchContractInput, SubagentLaunchContractResult, resolveSubagentLaunchContract } from "./src/adapters/subagentLaunchContract.cjs";
4
- export { DOOM_TEAM_TYPES, type SubagentLaunchContract, type SubagentLaunchContractInput, type SubagentLaunchContractResult, createExtensionContainer, createPromptRuntimeContainer, resolveSubagentLaunchContract };
2
+ export { type SubagentLaunchContract, type SubagentLaunchContractInput, type SubagentLaunchContractResult, resolveSubagentLaunchContract };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,2 @@
1
- import { DOOM_TEAM_TYPES } from "./src/container/types.mjs";
2
- import { createExtensionContainer, createPromptRuntimeContainer } from "./src/container/index.mjs";
3
1
  import { SubagentLaunchContract, SubagentLaunchContractInput, SubagentLaunchContractResult, resolveSubagentLaunchContract } from "./src/adapters/subagentLaunchContract.mjs";
4
- export { DOOM_TEAM_TYPES, type SubagentLaunchContract, type SubagentLaunchContractInput, type SubagentLaunchContractResult, createExtensionContainer, createPromptRuntimeContainer, resolveSubagentLaunchContract };
2
+ export { type SubagentLaunchContract, type SubagentLaunchContractInput, type SubagentLaunchContractResult, resolveSubagentLaunchContract };
package/dist/index.mjs CHANGED
@@ -1,2 +1 @@
1
- import{DOOM_TEAM_TYPES as e}from"./src/container/types.mjs";import{createExtensionContainer as t,createPromptRuntimeContainer as n,init_container as r}from"./src/container/index.mjs";import{resolveSubagentLaunchContract as i}from"./src/adapters/subagentLaunchContract.mjs";r();export{e as DOOM_TEAM_TYPES,t as createExtensionContainer,n as createPromptRuntimeContainer,i as resolveSubagentLaunchContract};
2
- //# sourceMappingURL=index.mjs.map
1
+ import{resolveSubagentLaunchContract as e}from"./src/adapters/subagentLaunchContract.mjs";export{e as resolveSubagentLaunchContract};
@@ -1,2 +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(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.cjs`),i=require(`../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.cjs`),a=require(`../shared/paths.cjs`),o=require(`../services/runs/background/statusWriter.cjs`),s=require(`./statusReader.cjs`);require(`../services/runs/background/statusReader.cjs`);let c=require(`inversify`),l=require(`node:fs`);l=e.__toESM(l,1);let u=require(`node:path`);u=e.__toESM(u,1);const d=new Set([`complete`,`completed`,`failed`,`paused`,`stopped`]);function f(e,t){let n=e.list().map(e=>e.runId).filter(e=>e===t||e.startsWith(t)),r=n.find(e=>e===t);if(r)return r;if(n.length===1)return n[0];throw n.length===0?Error(`No current-session run found for '${t}'.`):Error(`Multiple current-session runs match '${t}'. Use a longer id.`)}const p=`__unscoped__`;function m(e){return u.join(a.currentRunsDir(),e,o.STATUS_FILE_NAME)}function h(e){return typeof e==`object`&&e&&`code`in e?e.code:void 0}function g(e){return h(e)===`ENOENT`}const _=new Set([`starting`,`working`,`tool`,`waiting_for_reply`,`needs_attention`,`finalizing`,`active_long_running`]);function v(e){return typeof e==`string`&&_.has(e)?e:void 0}let y=class{constructor(e){this.scheduler=e}pollIntervalMs=250;retentionMs=1e4;now(){return Date.now()}readFile(e){try{return l.readFileSync(e,`utf-8`)}catch(e){if(g(e))return;throw e}}async readFileAsync(e){try{return await l.promises.readFile(e,`utf-8`)}catch(e){if(g(e))return;throw e}}sessions=new Map;unregisterPoll;session(e){let t=this.sessions.get(e);return t||(t={jobs:new Map,terminalAt:new Map},this.sessions.set(e,t)),t}forSession(e){if(!e.trim())throw Error(`Pi session identity is required to track subagent runs.`);return{track:t=>this.trackInSession(e,t),untrack:t=>this.untrackInSession(e,t),list:()=>this.listInSession(e),get:t=>this.getInSession(e,t),reset:()=>this.resetSession(e)}}parseStatus(e,t){if(t===void 0)return;let n=s.parseAsyncRunStatus(t,m(e));if(n.kind!==`ok`)return;let r=n.status;return{agent:r.agent,status:r.state,startedAt:r.startedAt,updatedAt:r.lastUpdate,error:r.error,activityState:v(r.activityState),attentionReason:r.attentionReason,runtime:r.runtime,tokens:r.tokens,currentTool:r.currentTool,toolCount:r.toolCount}}readStatus(e){return this.parseStatus(e,this.readFile(m(e)))}async readStatusAsync(e){return this.parseStatus(e,await this.readFileAsync(m(e)))}applyStatus(e,t,n){let r=this.session(e),i=r.jobs.get(t);if(n===void 0)return i||r.jobs.set(t,{runId:t,status:void 0}),!1;let a={runId:t,...n};r.jobs.set(t,a);let o=i?.status!==void 0&&d.has(i.status),s=a.status!==void 0&&d.has(a.status);return s&&!o&&r.terminalAt.set(t,this.now()),s||r.terminalAt.delete(t),!i||i.status!==a.status||i.updatedAt!==a.updatedAt||i.tokens!==a.tokens||i.currentTool!==a.currentTool||i.toolCount!==a.toolCount}refresh(e,t){return this.applyStatus(e,t,this.readStatus(t))}async refreshAsync(e,t){return this.applyStatus(e,t,await this.readStatusAsync(t))}async run(){let e=!1,t=this.now();for(let[n,r]of this.sessions){for(let t of r.jobs.keys())await this.refreshAsync(n,t)&&(e=!0);for(let[n,i]of r.terminalAt)t-i<=this.retentionMs||(r.jobs.delete(n),r.terminalAt.delete(n),e=!0);r.jobs.size===0&&this.sessions.delete(n)}return e}track(e){this.trackInSession(p,e)}untrack(e){this.untrackInSession(p,e)}list(){return this.listInSession(p)}get(e){return this.getInSession(p,e)}reset(){this.resetSession(p)}trackInSession(e,t){this.refresh(e,t)}untrackInSession(e,t){let n=this.sessions.get(e);n?.jobs.delete(t),n?.terminalAt.delete(t),n?.jobs.size===0&&this.sessions.delete(e)}listInSession(e){return[...this.sessions.get(e)?.jobs.values()??[]]}getInSession(e,t){return this.sessions.get(e)?.jobs.get(t)}resetSession(e){this.sessions.delete(e)}start(){this.stop(),this.unregisterPoll=this.scheduler.register({id:`async-job-tracker`,intervalMs:this.pollIntervalMs,run:()=>this.run()})}stop(){this.unregisterPoll?.(),this.unregisterPoll=void 0,this.sessions.clear()}};y=t.__decorate([(0,c.injectable)(),i.__decorateParam(0,(0,c.inject)(n.DOOM_TEAM_TYPES.PollScheduler)),r.__decorateMetadata(`design:paramtypes`,[Object])],y),Object.defineProperty(exports,`AsyncJobTracker`,{enumerable:!0,get:function(){return y}}),exports.TERMINAL_ASYNC_JOB_STATES=d,exports.resolveTrackedRunId=f;
1
+ const e=require(`../../_virtual/_rolldown/runtime.cjs`),t=require(`../shared/paths.cjs`),n=require(`../services/runs/background/statusWriter.cjs`),r=require(`./statusReader.cjs`);require(`../services/runs/background/statusReader.cjs`);let i=require(`node:fs`);i=e.__toESM(i,1);let a=require(`node:path`);a=e.__toESM(a,1);const o=new Set([`complete`,`completed`,`failed`,`paused`,`stopped`]);function s(e,t){let n=e.list().map(e=>e.runId).filter(e=>e===t||e.startsWith(t)),r=n.find(e=>e===t);if(r)return r;if(n.length===1)return n[0];throw n.length===0?Error(`No current-session run found for '${t}'.`):Error(`Multiple current-session runs match '${t}'. Use a longer id.`)}const c=`__unscoped__`;function l(e){return a.join(t.currentRunsDir(),e,n.STATUS_FILE_NAME)}function u(e){return typeof e==`object`&&e&&`code`in e?e.code:void 0}function d(e){return u(e)===`ENOENT`}const f=new Set([`starting`,`working`,`tool`,`waiting_for_reply`,`needs_attention`,`finalizing`,`active_long_running`]);function p(e){return typeof e==`string`&&f.has(e)?e:void 0}var m=class{constructor(e){this.scheduler=e}pollIntervalMs=250;retentionMs=1e4;now(){return Date.now()}readFile(e){try{return i.readFileSync(e,`utf-8`)}catch(e){if(d(e))return;throw e}}async readFileAsync(e){try{return await i.promises.readFile(e,`utf-8`)}catch(e){if(d(e))return;throw e}}sessions=new Map;unregisterPoll;session(e){let t=this.sessions.get(e);return t||(t={jobs:new Map,terminalAt:new Map},this.sessions.set(e,t)),t}forSession(e){if(!e.trim())throw Error(`Pi session identity is required to track subagent runs.`);return{track:t=>this.trackInSession(e,t),untrack:t=>this.untrackInSession(e,t),list:()=>this.listInSession(e),get:t=>this.getInSession(e,t),reset:()=>this.resetSession(e)}}parseStatus(e,t){if(t===void 0)return;let n=r.parseAsyncRunStatus(t,l(e));if(n.kind!==`ok`)return;let i=n.status;return{agent:i.agent,status:i.state,startedAt:i.startedAt,updatedAt:i.lastUpdate,error:i.error,activityState:p(i.activityState),attentionReason:i.attentionReason,runtime:i.runtime,tokens:i.tokens,currentTool:i.currentTool,toolCount:i.toolCount}}readStatus(e){return this.parseStatus(e,this.readFile(l(e)))}async readStatusAsync(e){return this.parseStatus(e,await this.readFileAsync(l(e)))}applyStatus(e,t,n){let r=this.session(e),i=r.jobs.get(t);if(n===void 0)return i||r.jobs.set(t,{runId:t,status:void 0}),!1;let a={runId:t,...n};r.jobs.set(t,a);let s=i?.status!==void 0&&o.has(i.status),c=a.status!==void 0&&o.has(a.status);return c&&!s&&r.terminalAt.set(t,this.now()),c||r.terminalAt.delete(t),!i||i.status!==a.status||i.updatedAt!==a.updatedAt||i.tokens!==a.tokens||i.currentTool!==a.currentTool||i.toolCount!==a.toolCount}refresh(e,t){return this.applyStatus(e,t,this.readStatus(t))}async refreshAsync(e,t){return this.applyStatus(e,t,await this.readStatusAsync(t))}async run(){let e=!1,t=this.now();for(let[n,r]of this.sessions){for(let t of r.jobs.keys())await this.refreshAsync(n,t)&&(e=!0);for(let[n,i]of r.terminalAt)t-i<=this.retentionMs||(r.jobs.delete(n),r.terminalAt.delete(n),e=!0);r.jobs.size===0&&this.sessions.delete(n)}return e}track(e){this.trackInSession(c,e)}untrack(e){this.untrackInSession(c,e)}list(){return this.listInSession(c)}get(e){return this.getInSession(c,e)}reset(){this.resetSession(c)}trackInSession(e,t){this.refresh(e,t)}untrackInSession(e,t){let n=this.sessions.get(e);n?.jobs.delete(t),n?.terminalAt.delete(t),n?.jobs.size===0&&this.sessions.delete(e)}listInSession(e){return[...this.sessions.get(e)?.jobs.values()??[]]}getInSession(e,t){return this.sessions.get(e)?.jobs.get(t)}resetSession(e){this.sessions.delete(e)}start(){this.stop(),this.unregisterPoll=this.scheduler.register({id:`async-job-tracker`,intervalMs:this.pollIntervalMs,run:()=>this.run()})}stop(){this.unregisterPoll?.(),this.unregisterPoll=void 0,this.sessions.clear()}};exports.AsyncJobTracker=m,exports.TERMINAL_ASYNC_JOB_STATES=o,exports.resolveTrackedRunId=s;
2
2
  //# sourceMappingURL=asyncJobTracker.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"asyncJobTracker.cjs","names":["path","currentRunsDir","STATUS_FILE_NAME","fs","parseAsyncRunStatus","DOOM_TEAM_TYPES"],"sources":["../../../src/adapters/asyncJobTracker.ts"],"sourcesContent":["/**\n * Live, in-memory registry of the async runs this session currently cares\n * about, refreshed from `status.json` on a `PollScheduler` tick.\n *\n * WHY THIS IS SMALLER THAN THE PREDECESSOR:\n * `doom-pi-subagents/src/runs/background/asyncJobTracker.ts` is 590 lines\n * doing four different jobs: this registry, TUI widget rendering\n * (`renderWidget`/`widgetRenderKey`/`ctx.ui.requestRender`), forwarding\n * control events and steering notices by byte-range-tailing each run's\n * `events.jsonl`, and projecting nested/parallel-group run trees. Only the\n * registry is ported. The other three have no consumer in this package yet:\n * TUI rendering is `G8` (slash commands + TUI), and nested/chain/parallel run\n * modes are `G7`+ (this package is currently single-run async-only - see\n * `spawnHandshake.ts`'s header). Porting rendering or event-tailing logic\n * with nothing to render to or forward to would be untested, unreachable\n * code; it is deferred to whichever later port actually needs it, not\n * dropped silently - this note is where to look for it.\n *\n * DESIGN PATTERNS:\n * - The in-memory map is a pure CACHE, never authoritative on its own:\n * `status.json` (owned by `CoalescedStatusWriter` elsewhere) is the only\n * source of truth. `track()` reads it synchronously immediately, so a\n * caller that already knows a run's id sees *something* right away rather\n * than waiting out the first poll\n * - Restart survivability follows from the point above rather than a second\n * persistence layer: this package has not built session-scoped run\n * ownership yet (which ids \"belong\" to a restarted session is not\n * something this module can determine on its own - see the AVOID entry),\n * so recovery is the caller re-`track()`-ing whatever ids it still cares\n * about from ITS OWN durable record. The very next poll tick repopulates\n * that job's status straight from disk. There is no separate store to keep\n * in sync, and therefore no window where memory could diverge from disk\n * that a restart would not immediately close\n * - Registered with `PollScheduler`, not a private timer: this polls\n * potentially many jobs' status files on an unbounded, periodic cadence\n * with no low-latency requirement - the exact shape `PollScheduler` exists\n * for. Contrast `completionBatcher.ts`/`spawnHandshake.ts`, which own\n * their own timers because they are short-lived, single-shot, and need\n * sub-200ms responsiveness `PollScheduler`'s floor cannot give them; this\n * registry needs neither\n * - Retention-then-eviction happens on the SAME poll tick as the status\n * refresh, rather than the predecessor's per-job `setTimeout`\n * (`scheduleCleanup`): a terminal job aged past `retentionMs` is simply\n * dropped the next time `run()` walks the map. One clock, not one timer per\n * job\n *\n * AVOID:\n * - Scanning `currentRunsDir()` to guess which run ids \"belong\" to this session on\n * startup. This package has no session-scoped run ownership concept yet;\n * inventing one here to answer \"what should I restore\" would be a guess,\n * not a fact this module has standing to assert. Restoration is the\n * caller's job (see the design note above)\n * - Growing `terminalStates` independently of `staleRunReconciler.ts`'s own\n * (unexported) copy; both must treat the same state strings as terminal,\n * or a job could be evicted here while the reconciler still thinks it is\n * in flight, or vice versa\n *\n * `activityState`/`attentionReason` (added for `subagentWait.ts`):\n * `DeliverableGuard.evaluate()` computes `activityState: 'needs_attention'`\n * and a `reason` (e.g. `'missing-deliverable'`), but returns it rather than\n * writing it anywhere - it has no standing to touch `status.json` itself (see\n * that module's header). Something upstream of this tracker - the run's own\n * runner main loop, not yet built - is responsible for folding that result\n * into `status.json` through `CoalescedStatusWriter`. This tracker's job is\n * only to read whatever ends up there, the same as every other field: it does\n * not compute attention, detect it, or decide when a run needs it.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { inject, injectable } from 'inversify';\nimport { DOOM_TEAM_TYPES } from '../container/types.ts';\nimport { parseAsyncRunStatus } from '../services/runs/background/statusReader.ts';\nimport { STATUS_FILE_NAME } from '../services/runs/background/statusWriter.ts';\nimport { currentRunsDir } from '../shared/paths.ts';\nimport type { IPollScheduler } from '../shared/pollScheduler.ts';\nimport type { ActivityState } from '../types/index.ts';\n\n/**\n * States that mean \"already finished\"; matches `staleRunReconciler.ts`'s\n * own (unexported) set. Exported so a caller outside this module (the slash\n * layer's poll-until-terminal helper) can recognize the same terminal set\n * `TrackedAsyncJob.status` uses, rather than declaring a third copy of this\n * literal.\n */\nexport const TERMINAL_ASYNC_JOB_STATES = new Set(['complete', 'completed', 'failed', 'paused', 'stopped']);\n\n/** How long a terminal job stays queryable before eviction. */\nconst DEFAULT_RETENTION_MS = 10_000;\n/** How often tracked jobs' status is refreshed from disk. */\nconst DEFAULT_POLL_INTERVAL_MS = 250;\n\nconst POLL_SUBSCRIBER_ID = 'async-job-tracker';\n\n/**\n * The minimum shape this module reads. A run's actual `status.json` carries\n * far more (this package has no shared status type yet - see\n * `staleRunReconciler.ts`'s `ReconcilableStatus` for the same caveat);\n * everything else is simply not read here.\n */\nexport interface TrackedAsyncJob {\n runId: string;\n /** Named agent executing this run. Absent until the first readable status. */\n agent?: string;\n /** `status.json`'s `state` field. `undefined` until the first successful read. */\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n /** `status.json`'s `activityState` field, e.g. `'needs_attention'`. See the module doc. */\n activityState?: ActivityState;\n /** `status.json`'s `reason` field, present alongside `activityState` (e.g. `'missing-deliverable'`). */\n attentionReason?: string;\n /** Which runtime is executing this run. Absent means the default `pi` path. */\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nexport interface ITrackedAsyncJobs {\n /**\n * Start tracking `runId`: reads its current status synchronously (so a\n * caller sees something immediately) and adds it to the poll rotation.\n * Calling this again for an id already tracked simply re-reads it now,\n * the same idempotent-refresh idiom as `CoalescedStatusWriter.open()`.\n */\n track(runId: string): void;\n /** Stop tracking `runId` immediately, without waiting out its retention window. */\n untrack(runId: string): void;\n /** Every currently tracked job (in-flight, or terminal within its retention window). */\n list(): TrackedAsyncJob[];\n get(runId: string): TrackedAsyncJob | undefined;\n /** Drop every tracked job. */\n reset(): void;\n}\n\nexport interface IAsyncJobTracker extends ITrackedAsyncJobs {\n /** Return the isolated run collection owned by one Pi session context. */\n forSession(sessionId: string): ITrackedAsyncJobs;\n /** Register with `PollScheduler`. Call once; a second call is a reset, same as `ResultWatcher.start()`. */\n start(): void;\n /** Unregister from `PollScheduler` and drop every tracked job. */\n stop(): void;\n}\n\n/** Resolve an exact id or unique prefix only inside one Pi session's run collection. */\nexport function resolveTrackedRunId(jobs: ITrackedAsyncJobs, id: string): string {\n const matches = jobs\n .list()\n .map((job) => job.runId)\n .filter((runId) => runId === id || runId.startsWith(id));\n const exact = matches.find((runId) => runId === id);\n if (exact) return exact;\n if (matches.length === 1) return matches[0]!;\n if (matches.length === 0) throw new Error(`No current-session run found for '${id}'.`);\n throw new Error(`Multiple current-session runs match '${id}'. Use a longer id.`);\n}\n\ninterface SessionJobs {\n jobs: Map<string, TrackedAsyncJob>;\n terminalAt: Map<string, number>;\n}\n\nconst UNSCOPED_SESSION = '__unscoped__';\n\nfunction statusPathFor(runId: string): string {\n return path.join(currentRunsDir(), runId, STATUS_FILE_NAME);\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return typeof error === 'object' && error !== null && 'code' in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return errorCode(error) === 'ENOENT';\n}\n\ninterface ReadStatusResult {\n agent: string;\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n activityState?: ActivityState;\n attentionReason?: string;\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nconst VALID_ACTIVITY_STATES: ReadonlySet<string> = new Set<ActivityState>([\n 'starting',\n 'working',\n 'tool',\n 'waiting_for_reply',\n 'needs_attention',\n 'finalizing',\n 'active_long_running',\n]);\n\nfunction asActivityState(value: unknown): ActivityState | undefined {\n return typeof value === 'string' && VALID_ACTIVITY_STATES.has(value) ? (value as ActivityState) : undefined;\n}\n\n@injectable()\nexport class AsyncJobTracker implements IAsyncJobTracker {\n constructor(@inject(DOOM_TEAM_TYPES.PollScheduler) private readonly scheduler: IPollScheduler) {}\n\n /**\n * Seams for tests, as protected members rather than constructor arguments:\n * inversify cannot resolve a primitive. See `pollScheduler.ts` and\n * `agents/discovery.ts` for the same pattern.\n */\n protected readonly pollIntervalMs: number = DEFAULT_POLL_INTERVAL_MS;\n protected readonly retentionMs: number = DEFAULT_RETENTION_MS;\n\n protected now(): number {\n return Date.now();\n }\n\n protected readFile(filePath: string): string | undefined {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n protected async readFileAsync(filePath: string): Promise<string | undefined> {\n try {\n return await fs.promises.readFile(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n private readonly sessions = new Map<string, SessionJobs>();\n private unregisterPoll: (() => void) | undefined;\n\n private session(sessionId: string): SessionJobs {\n let session = this.sessions.get(sessionId);\n if (!session) {\n session = { jobs: new Map(), terminalAt: new Map() };\n this.sessions.set(sessionId, session);\n }\n return session;\n }\n\n forSession(sessionId: string): ITrackedAsyncJobs {\n if (!sessionId.trim()) throw new Error('Pi session identity is required to track subagent runs.');\n return {\n track: (runId) => this.trackInSession(sessionId, runId),\n untrack: (runId) => this.untrackInSession(sessionId, runId),\n list: () => this.listInSession(sessionId),\n get: (runId) => this.getInSession(sessionId, runId),\n reset: () => this.resetSession(sessionId),\n };\n }\n\n private parseStatus(runId: string, raw: string | undefined): ReadStatusResult | undefined {\n if (raw === undefined) return undefined;\n const result = parseAsyncRunStatus(raw, statusPathFor(runId));\n if (result.kind !== 'ok') return undefined;\n const status = result.status;\n return {\n agent: status.agent,\n status: status.state,\n startedAt: status.startedAt,\n updatedAt: status.lastUpdate,\n error: status.error,\n activityState: asActivityState(status.activityState),\n attentionReason: status.attentionReason,\n runtime: status.runtime,\n tokens: status.tokens,\n currentTool: status.currentTool,\n toolCount: status.toolCount,\n };\n }\n\n private readStatus(runId: string): ReadStatusResult | undefined {\n return this.parseStatus(runId, this.readFile(statusPathFor(runId)));\n }\n\n private async readStatusAsync(runId: string): Promise<ReadStatusResult | undefined> {\n return this.parseStatus(runId, await this.readFileAsync(statusPathFor(runId)));\n }\n\n private applyStatus(sessionId: string, runId: string, read: ReadStatusResult | undefined): boolean {\n const session = this.session(sessionId);\n const existing = session.jobs.get(runId);\n if (read === undefined) {\n // A run may not have created its file yet, and a torn read must not blank\n // a previously known status for one polling pass.\n if (existing) return false;\n session.jobs.set(runId, { runId, status: undefined });\n return false;\n }\n\n const job: TrackedAsyncJob = { runId, ...read };\n session.jobs.set(runId, job);\n const wasTerminal = existing?.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(existing.status);\n const isTerminal = job.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(job.status);\n if (isTerminal && !wasTerminal) session.terminalAt.set(runId, this.now());\n if (!isTerminal) session.terminalAt.delete(runId);\n return (\n !existing ||\n existing.status !== job.status ||\n existing.updatedAt !== job.updatedAt ||\n existing.tokens !== job.tokens ||\n existing.currentTool !== job.currentTool ||\n existing.toolCount !== job.toolCount\n );\n }\n\n private refresh(sessionId: string, runId: string): boolean {\n return this.applyStatus(sessionId, runId, this.readStatus(runId));\n }\n\n private async refreshAsync(sessionId: string, runId: string): Promise<boolean> {\n return this.applyStatus(sessionId, runId, await this.readStatusAsync(runId));\n }\n\n /** One scheduler tick: asynchronously refresh every tracked status, then evict expired terminal jobs. */\n protected async run(): Promise<boolean> {\n let changed = false;\n const now = this.now();\n for (const [sessionId, session] of this.sessions) {\n for (const runId of session.jobs.keys()) {\n if (await this.refreshAsync(sessionId, runId)) changed = true;\n }\n for (const [runId, terminatedAt] of session.terminalAt) {\n if (now - terminatedAt <= this.retentionMs) continue;\n session.jobs.delete(runId);\n session.terminalAt.delete(runId);\n changed = true;\n }\n if (session.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n return changed;\n }\n\n track(runId: string): void {\n this.trackInSession(UNSCOPED_SESSION, runId);\n }\n\n untrack(runId: string): void {\n this.untrackInSession(UNSCOPED_SESSION, runId);\n }\n\n list(): TrackedAsyncJob[] {\n return this.listInSession(UNSCOPED_SESSION);\n }\n\n get(runId: string): TrackedAsyncJob | undefined {\n return this.getInSession(UNSCOPED_SESSION, runId);\n }\n\n reset(): void {\n this.resetSession(UNSCOPED_SESSION);\n }\n\n private trackInSession(sessionId: string, runId: string): void {\n this.refresh(sessionId, runId);\n }\n\n private untrackInSession(sessionId: string, runId: string): void {\n const session = this.sessions.get(sessionId);\n session?.jobs.delete(runId);\n session?.terminalAt.delete(runId);\n if (session?.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n private listInSession(sessionId: string): TrackedAsyncJob[] {\n return [...(this.sessions.get(sessionId)?.jobs.values() ?? [])];\n }\n\n private getInSession(sessionId: string, runId: string): TrackedAsyncJob | undefined {\n return this.sessions.get(sessionId)?.jobs.get(runId);\n }\n\n private resetSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n start(): void {\n this.stop();\n this.unregisterPoll = this.scheduler.register({\n id: POLL_SUBSCRIBER_ID,\n intervalMs: this.pollIntervalMs,\n run: () => this.run(),\n });\n }\n\n stop(): void {\n this.unregisterPoll?.();\n this.unregisterPoll = undefined;\n this.sessions.clear();\n }\n}\n"],"mappings":"snBAqFA,MAAa,EAA4B,IAAI,IAAI,CAAC,WAAY,YAAa,SAAU,SAAU,UAAU,CAAC,CA8D1G,SAAgB,EAAoB,EAAyB,EAAoB,CAC/E,IAAM,EAAU,EACb,MAAM,CACN,IAAK,GAAQ,EAAI,MAAM,CACvB,OAAQ,GAAU,IAAU,GAAM,EAAM,WAAW,EAAG,CAAC,CACpD,EAAQ,EAAQ,KAAM,GAAU,IAAU,EAAG,CACnD,GAAI,EAAO,OAAO,EAClB,GAAI,EAAQ,SAAW,EAAG,OAAO,EAAQ,GAEzC,MADI,EAAQ,SAAW,EAAa,MAAM,qCAAqC,EAAG,IAAI,CAC5E,MAAM,wCAAwC,EAAG,qBAAqB,CAQlF,MAAM,EAAmB,eAEzB,SAAS,EAAc,EAAuB,CAC5C,OAAOA,EAAK,KAAKC,EAAAA,gBAAgB,CAAE,EAAOC,EAAAA,iBAAiB,CAG7D,SAAS,EAAU,EAAoC,CACrD,OAAO,OAAO,GAAU,UAAY,GAAkB,SAAU,EAC3D,EAAgC,KACjC,IAAA,GAGN,SAAS,EAAW,EAAyB,CAC3C,OAAO,EAAU,EAAM,GAAK,SAiB9B,MAAM,EAA6C,IAAI,IAAmB,CACxE,WACA,UACA,OACA,oBACA,kBACA,aACA,sBACD,CAAC,CAEF,SAAS,EAAgB,EAA2C,CAClE,OAAO,OAAO,GAAU,UAAY,EAAsB,IAAI,EAAM,CAAI,EAA0B,IAAA,GAI7F,IAAA,EAAA,KAAkD,CACvD,YAAY,EAAmF,CAA3B,KAAA,UAAA,EAOpE,eAA4C,IAC5C,YAAyC,IAEzC,KAAwB,CACtB,OAAO,KAAK,KAAK,CAGnB,SAAmB,EAAsC,CACvD,GAAI,CACF,OAAOC,EAAG,aAAa,EAAU,QAAQ,OAClC,EAAO,CACd,GAAI,EAAW,EAAM,CAAE,OACvB,MAAM,GAIV,MAAgB,cAAc,EAA+C,CAC3E,GAAI,CACF,OAAO,MAAMA,EAAG,SAAS,SAAS,EAAU,QAAQ,OAC7C,EAAO,CACd,GAAI,EAAW,EAAM,CAAE,OACvB,MAAM,GAIV,SAA4B,IAAI,IAChC,eAEA,QAAgB,EAAgC,CAC9C,IAAI,EAAU,KAAK,SAAS,IAAI,EAAU,CAK1C,OAJK,IACH,EAAU,CAAE,KAAM,IAAI,IAAO,WAAY,IAAI,IAAO,CACpD,KAAK,SAAS,IAAI,EAAW,EAAQ,EAEhC,EAGT,WAAW,EAAsC,CAC/C,GAAI,CAAC,EAAU,MAAM,CAAE,MAAU,MAAM,0DAA0D,CACjG,MAAO,CACL,MAAQ,GAAU,KAAK,eAAe,EAAW,EAAM,CACvD,QAAU,GAAU,KAAK,iBAAiB,EAAW,EAAM,CAC3D,SAAY,KAAK,cAAc,EAAU,CACzC,IAAM,GAAU,KAAK,aAAa,EAAW,EAAM,CACnD,UAAa,KAAK,aAAa,EAAU,CAC1C,CAGH,YAAoB,EAAe,EAAuD,CACxF,GAAI,IAAQ,IAAA,GAAW,OACvB,IAAM,EAASC,EAAAA,oBAAoB,EAAK,EAAc,EAAM,CAAC,CAC7D,GAAI,EAAO,OAAS,KAAM,OAC1B,IAAM,EAAS,EAAO,OACtB,MAAO,CACL,MAAO,EAAO,MACd,OAAQ,EAAO,MACf,UAAW,EAAO,UAClB,UAAW,EAAO,WAClB,MAAO,EAAO,MACd,cAAe,EAAgB,EAAO,cAAc,CACpD,gBAAiB,EAAO,gBACxB,QAAS,EAAO,QAChB,OAAQ,EAAO,OACf,YAAa,EAAO,YACpB,UAAW,EAAO,UACnB,CAGH,WAAmB,EAA6C,CAC9D,OAAO,KAAK,YAAY,EAAO,KAAK,SAAS,EAAc,EAAM,CAAC,CAAC,CAGrE,MAAc,gBAAgB,EAAsD,CAClF,OAAO,KAAK,YAAY,EAAO,MAAM,KAAK,cAAc,EAAc,EAAM,CAAC,CAAC,CAGhF,YAAoB,EAAmB,EAAe,EAA6C,CACjG,IAAM,EAAU,KAAK,QAAQ,EAAU,CACjC,EAAW,EAAQ,KAAK,IAAI,EAAM,CACxC,GAAI,IAAS,IAAA,GAKX,OAFI,GACJ,EAAQ,KAAK,IAAI,EAAO,CAAE,QAAO,OAAQ,IAAA,GAAW,CAAC,CADhC,GAKvB,IAAM,EAAuB,CAAE,QAAO,GAAG,EAAM,CAC/C,EAAQ,KAAK,IAAI,EAAO,EAAI,CAC5B,IAAM,EAAc,GAAU,SAAW,IAAA,IAAa,EAA0B,IAAI,EAAS,OAAO,CAC9F,EAAa,EAAI,SAAW,IAAA,IAAa,EAA0B,IAAI,EAAI,OAAO,CAGxF,OAFI,GAAc,CAAC,GAAa,EAAQ,WAAW,IAAI,EAAO,KAAK,KAAK,CAAC,CACpE,GAAY,EAAQ,WAAW,OAAO,EAAM,CAE/C,CAAC,GACD,EAAS,SAAW,EAAI,QACxB,EAAS,YAAc,EAAI,WAC3B,EAAS,SAAW,EAAI,QACxB,EAAS,cAAgB,EAAI,aAC7B,EAAS,YAAc,EAAI,UAI/B,QAAgB,EAAmB,EAAwB,CACzD,OAAO,KAAK,YAAY,EAAW,EAAO,KAAK,WAAW,EAAM,CAAC,CAGnE,MAAc,aAAa,EAAmB,EAAiC,CAC7E,OAAO,KAAK,YAAY,EAAW,EAAO,MAAM,KAAK,gBAAgB,EAAM,CAAC,CAI9E,MAAgB,KAAwB,CACtC,IAAI,EAAU,GACR,EAAM,KAAK,KAAK,CACtB,IAAK,GAAM,CAAC,EAAW,KAAY,KAAK,SAAU,CAChD,IAAK,IAAM,KAAS,EAAQ,KAAK,MAAM,CACjC,MAAM,KAAK,aAAa,EAAW,EAAM,GAAE,EAAU,IAE3D,IAAK,GAAM,CAAC,EAAO,KAAiB,EAAQ,WACtC,EAAM,GAAgB,KAAK,cAC/B,EAAQ,KAAK,OAAO,EAAM,CAC1B,EAAQ,WAAW,OAAO,EAAM,CAChC,EAAU,IAER,EAAQ,KAAK,OAAS,GAAG,KAAK,SAAS,OAAO,EAAU,CAG9D,OAAO,EAGT,MAAM,EAAqB,CACzB,KAAK,eAAe,EAAkB,EAAM,CAG9C,QAAQ,EAAqB,CAC3B,KAAK,iBAAiB,EAAkB,EAAM,CAGhD,MAA0B,CACxB,OAAO,KAAK,cAAc,EAAiB,CAG7C,IAAI,EAA4C,CAC9C,OAAO,KAAK,aAAa,EAAkB,EAAM,CAGnD,OAAc,CACZ,KAAK,aAAa,EAAiB,CAGrC,eAAuB,EAAmB,EAAqB,CAC7D,KAAK,QAAQ,EAAW,EAAM,CAGhC,iBAAyB,EAAmB,EAAqB,CAC/D,IAAM,EAAU,KAAK,SAAS,IAAI,EAAU,CAC5C,GAAS,KAAK,OAAO,EAAM,CAC3B,GAAS,WAAW,OAAO,EAAM,CAC7B,GAAS,KAAK,OAAS,GAAG,KAAK,SAAS,OAAO,EAAU,CAG/D,cAAsB,EAAsC,CAC1D,MAAO,CAAC,GAAI,KAAK,SAAS,IAAI,EAAU,EAAE,KAAK,QAAQ,EAAI,EAAE,CAAE,CAGjE,aAAqB,EAAmB,EAA4C,CAClF,OAAO,KAAK,SAAS,IAAI,EAAU,EAAE,KAAK,IAAI,EAAM,CAGtD,aAAqB,EAAyB,CAC5C,KAAK,SAAS,OAAO,EAAU,CAGjC,OAAc,CACZ,KAAK,MAAM,CACX,KAAK,eAAiB,KAAK,UAAU,SAAS,CAC5C,GAAI,oBACJ,WAAY,KAAK,eACjB,QAAW,KAAK,KAAK,CACtB,CAAC,CAGJ,MAAa,CACX,KAAK,kBAAkB,CACvB,KAAK,eAAiB,IAAA,GACtB,KAAK,SAAS,OAAO,qCAnMZ,kCAESC,EAAAA,gBAAgB,cAAc,CAAA"}
1
+ {"version":3,"file":"asyncJobTracker.cjs","names":["path","currentRunsDir","STATUS_FILE_NAME","fs","parseAsyncRunStatus"],"sources":["../../../src/adapters/asyncJobTracker.ts"],"sourcesContent":["/**\n * Live, in-memory registry of the async runs this session currently cares\n * about, refreshed from `status.json` on a `PollScheduler` tick.\n *\n * WHY THIS IS SMALLER THAN THE PREDECESSOR:\n * `doom-pi-subagents/src/runs/background/asyncJobTracker.ts` is 590 lines\n * doing four different jobs: this registry, TUI widget rendering\n * (`renderWidget`/`widgetRenderKey`/`ctx.ui.requestRender`), forwarding\n * control events and steering notices by byte-range-tailing each run's\n * `events.jsonl`, and projecting nested/parallel-group run trees. Only the\n * registry is ported. The other three have no consumer in this package yet:\n * TUI rendering is `G8` (slash commands + TUI), and nested/chain/parallel run\n * modes are `G7`+ (this package is currently single-run async-only - see\n * `spawnHandshake.ts`'s header). Porting rendering or event-tailing logic\n * with nothing to render to or forward to would be untested, unreachable\n * code; it is deferred to whichever later port actually needs it, not\n * dropped silently - this note is where to look for it.\n *\n * DESIGN PATTERNS:\n * - The in-memory map is a pure CACHE, never authoritative on its own:\n * `status.json` (owned by `CoalescedStatusWriter` elsewhere) is the only\n * source of truth. `track()` reads it synchronously immediately, so a\n * caller that already knows a run's id sees *something* right away rather\n * than waiting out the first poll\n * - Restart survivability follows from the point above rather than a second\n * persistence layer: this package has not built session-scoped run\n * ownership yet (which ids \"belong\" to a restarted session is not\n * something this module can determine on its own - see the AVOID entry),\n * so recovery is the caller re-`track()`-ing whatever ids it still cares\n * about from ITS OWN durable record. The very next poll tick repopulates\n * that job's status straight from disk. There is no separate store to keep\n * in sync, and therefore no window where memory could diverge from disk\n * that a restart would not immediately close\n * - Registered with `PollScheduler`, not a private timer: this polls\n * potentially many jobs' status files on an unbounded, periodic cadence\n * with no low-latency requirement - the exact shape `PollScheduler` exists\n * for. Contrast `completionBatcher.ts`/`spawnHandshake.ts`, which own\n * their own timers because they are short-lived, single-shot, and need\n * sub-200ms responsiveness `PollScheduler`'s floor cannot give them; this\n * registry needs neither\n * - Retention-then-eviction happens on the SAME poll tick as the status\n * refresh, rather than the predecessor's per-job `setTimeout`\n * (`scheduleCleanup`): a terminal job aged past `retentionMs` is simply\n * dropped the next time `run()` walks the map. One clock, not one timer per\n * job\n *\n * AVOID:\n * - Scanning `currentRunsDir()` to guess which run ids \"belong\" to this session on\n * startup. This package has no session-scoped run ownership concept yet;\n * inventing one here to answer \"what should I restore\" would be a guess,\n * not a fact this module has standing to assert. Restoration is the\n * caller's job (see the design note above)\n * - Growing `terminalStates` independently of `staleRunReconciler.ts`'s own\n * (unexported) copy; both must treat the same state strings as terminal,\n * or a job could be evicted here while the reconciler still thinks it is\n * in flight, or vice versa\n *\n * `activityState`/`attentionReason` (added for `subagentWait.ts`):\n * `DeliverableGuard.evaluate()` computes `activityState: 'needs_attention'`\n * and a `reason` (e.g. `'missing-deliverable'`), but returns it rather than\n * writing it anywhere - it has no standing to touch `status.json` itself (see\n * that module's header). Something upstream of this tracker - the run's own\n * runner main loop, not yet built - is responsible for folding that result\n * into `status.json` through `CoalescedStatusWriter`. This tracker's job is\n * only to read whatever ends up there, the same as every other field: it does\n * not compute attention, detect it, or decide when a run needs it.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseAsyncRunStatus } from '../services/runs/background/statusReader.ts';\nimport { STATUS_FILE_NAME } from '../services/runs/background/statusWriter.ts';\nimport { currentRunsDir } from '../shared/paths.ts';\nimport type { IPollScheduler } from '../shared/pollScheduler.ts';\nimport type { ActivityState } from '../types/index.ts';\n\n/**\n * States that mean \"already finished\"; matches `staleRunReconciler.ts`'s\n * own (unexported) set. Exported so a caller outside this module (the slash\n * layer's poll-until-terminal helper) can recognize the same terminal set\n * `TrackedAsyncJob.status` uses, rather than declaring a third copy of this\n * literal.\n */\nexport const TERMINAL_ASYNC_JOB_STATES = new Set(['complete', 'completed', 'failed', 'paused', 'stopped']);\n\n/** How long a terminal job stays queryable before eviction. */\nconst DEFAULT_RETENTION_MS = 10_000;\n/** How often tracked jobs' status is refreshed from disk. */\nconst DEFAULT_POLL_INTERVAL_MS = 250;\n\nconst POLL_SUBSCRIBER_ID = 'async-job-tracker';\n\n/**\n * The minimum shape this module reads. A run's actual `status.json` carries\n * far more (this package has no shared status type yet - see\n * `staleRunReconciler.ts`'s `ReconcilableStatus` for the same caveat);\n * everything else is simply not read here.\n */\nexport interface TrackedAsyncJob {\n runId: string;\n /** Named agent executing this run. Absent until the first readable status. */\n agent?: string;\n /** `status.json`'s `state` field. `undefined` until the first successful read. */\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n /** `status.json`'s `activityState` field, e.g. `'needs_attention'`. See the module doc. */\n activityState?: ActivityState;\n /** `status.json`'s `reason` field, present alongside `activityState` (e.g. `'missing-deliverable'`). */\n attentionReason?: string;\n /** Which runtime is executing this run. Absent means the default `pi` path. */\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nexport interface ITrackedAsyncJobs {\n /**\n * Start tracking `runId`: reads its current status synchronously (so a\n * caller sees something immediately) and adds it to the poll rotation.\n * Calling this again for an id already tracked simply re-reads it now,\n * the same idempotent-refresh idiom as `CoalescedStatusWriter.open()`.\n */\n track(runId: string): void;\n /** Stop tracking `runId` immediately, without waiting out its retention window. */\n untrack(runId: string): void;\n /** Every currently tracked job (in-flight, or terminal within its retention window). */\n list(): TrackedAsyncJob[];\n get(runId: string): TrackedAsyncJob | undefined;\n /** Drop every tracked job. */\n reset(): void;\n}\n\nexport interface IAsyncJobTracker extends ITrackedAsyncJobs {\n /** Return the isolated run collection owned by one Pi session context. */\n forSession(sessionId: string): ITrackedAsyncJobs;\n /** Register with `PollScheduler`. Call once; a second call is a reset, same as `ResultWatcher.start()`. */\n start(): void;\n /** Unregister from `PollScheduler` and drop every tracked job. */\n stop(): void;\n}\n\n/** Resolve an exact id or unique prefix only inside one Pi session's run collection. */\nexport function resolveTrackedRunId(jobs: ITrackedAsyncJobs, id: string): string {\n const matches = jobs\n .list()\n .map((job) => job.runId)\n .filter((runId) => runId === id || runId.startsWith(id));\n const exact = matches.find((runId) => runId === id);\n if (exact) return exact;\n if (matches.length === 1) return matches[0]!;\n if (matches.length === 0) throw new Error(`No current-session run found for '${id}'.`);\n throw new Error(`Multiple current-session runs match '${id}'. Use a longer id.`);\n}\n\ninterface SessionJobs {\n jobs: Map<string, TrackedAsyncJob>;\n terminalAt: Map<string, number>;\n}\n\nconst UNSCOPED_SESSION = '__unscoped__';\n\nfunction statusPathFor(runId: string): string {\n return path.join(currentRunsDir(), runId, STATUS_FILE_NAME);\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return typeof error === 'object' && error !== null && 'code' in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return errorCode(error) === 'ENOENT';\n}\n\ninterface ReadStatusResult {\n agent: string;\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n activityState?: ActivityState;\n attentionReason?: string;\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nconst VALID_ACTIVITY_STATES: ReadonlySet<string> = new Set<ActivityState>([\n 'starting',\n 'working',\n 'tool',\n 'waiting_for_reply',\n 'needs_attention',\n 'finalizing',\n 'active_long_running',\n]);\n\nfunction asActivityState(value: unknown): ActivityState | undefined {\n return typeof value === 'string' && VALID_ACTIVITY_STATES.has(value) ? (value as ActivityState) : undefined;\n}\n\nexport class AsyncJobTracker implements IAsyncJobTracker {\n constructor(private readonly scheduler: IPollScheduler) {}\n\n /**\n * Runtime tuning seams for tests, kept out of the dependency constructor.\n */\n protected readonly pollIntervalMs: number = DEFAULT_POLL_INTERVAL_MS;\n protected readonly retentionMs: number = DEFAULT_RETENTION_MS;\n\n protected now(): number {\n return Date.now();\n }\n\n protected readFile(filePath: string): string | undefined {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n protected async readFileAsync(filePath: string): Promise<string | undefined> {\n try {\n return await fs.promises.readFile(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n private readonly sessions = new Map<string, SessionJobs>();\n private unregisterPoll: (() => void) | undefined;\n\n private session(sessionId: string): SessionJobs {\n let session = this.sessions.get(sessionId);\n if (!session) {\n session = { jobs: new Map(), terminalAt: new Map() };\n this.sessions.set(sessionId, session);\n }\n return session;\n }\n\n forSession(sessionId: string): ITrackedAsyncJobs {\n if (!sessionId.trim()) throw new Error('Pi session identity is required to track subagent runs.');\n return {\n track: (runId) => this.trackInSession(sessionId, runId),\n untrack: (runId) => this.untrackInSession(sessionId, runId),\n list: () => this.listInSession(sessionId),\n get: (runId) => this.getInSession(sessionId, runId),\n reset: () => this.resetSession(sessionId),\n };\n }\n\n private parseStatus(runId: string, raw: string | undefined): ReadStatusResult | undefined {\n if (raw === undefined) return undefined;\n const result = parseAsyncRunStatus(raw, statusPathFor(runId));\n if (result.kind !== 'ok') return undefined;\n const status = result.status;\n return {\n agent: status.agent,\n status: status.state,\n startedAt: status.startedAt,\n updatedAt: status.lastUpdate,\n error: status.error,\n activityState: asActivityState(status.activityState),\n attentionReason: status.attentionReason,\n runtime: status.runtime,\n tokens: status.tokens,\n currentTool: status.currentTool,\n toolCount: status.toolCount,\n };\n }\n\n private readStatus(runId: string): ReadStatusResult | undefined {\n return this.parseStatus(runId, this.readFile(statusPathFor(runId)));\n }\n\n private async readStatusAsync(runId: string): Promise<ReadStatusResult | undefined> {\n return this.parseStatus(runId, await this.readFileAsync(statusPathFor(runId)));\n }\n\n private applyStatus(sessionId: string, runId: string, read: ReadStatusResult | undefined): boolean {\n const session = this.session(sessionId);\n const existing = session.jobs.get(runId);\n if (read === undefined) {\n // A run may not have created its file yet, and a torn read must not blank\n // a previously known status for one polling pass.\n if (existing) return false;\n session.jobs.set(runId, { runId, status: undefined });\n return false;\n }\n\n const job: TrackedAsyncJob = { runId, ...read };\n session.jobs.set(runId, job);\n const wasTerminal = existing?.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(existing.status);\n const isTerminal = job.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(job.status);\n if (isTerminal && !wasTerminal) session.terminalAt.set(runId, this.now());\n if (!isTerminal) session.terminalAt.delete(runId);\n return (\n !existing ||\n existing.status !== job.status ||\n existing.updatedAt !== job.updatedAt ||\n existing.tokens !== job.tokens ||\n existing.currentTool !== job.currentTool ||\n existing.toolCount !== job.toolCount\n );\n }\n\n private refresh(sessionId: string, runId: string): boolean {\n return this.applyStatus(sessionId, runId, this.readStatus(runId));\n }\n\n private async refreshAsync(sessionId: string, runId: string): Promise<boolean> {\n return this.applyStatus(sessionId, runId, await this.readStatusAsync(runId));\n }\n\n /** One scheduler tick: asynchronously refresh every tracked status, then evict expired terminal jobs. */\n protected async run(): Promise<boolean> {\n let changed = false;\n const now = this.now();\n for (const [sessionId, session] of this.sessions) {\n for (const runId of session.jobs.keys()) {\n if (await this.refreshAsync(sessionId, runId)) changed = true;\n }\n for (const [runId, terminatedAt] of session.terminalAt) {\n if (now - terminatedAt <= this.retentionMs) continue;\n session.jobs.delete(runId);\n session.terminalAt.delete(runId);\n changed = true;\n }\n if (session.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n return changed;\n }\n\n track(runId: string): void {\n this.trackInSession(UNSCOPED_SESSION, runId);\n }\n\n untrack(runId: string): void {\n this.untrackInSession(UNSCOPED_SESSION, runId);\n }\n\n list(): TrackedAsyncJob[] {\n return this.listInSession(UNSCOPED_SESSION);\n }\n\n get(runId: string): TrackedAsyncJob | undefined {\n return this.getInSession(UNSCOPED_SESSION, runId);\n }\n\n reset(): void {\n this.resetSession(UNSCOPED_SESSION);\n }\n\n private trackInSession(sessionId: string, runId: string): void {\n this.refresh(sessionId, runId);\n }\n\n private untrackInSession(sessionId: string, runId: string): void {\n const session = this.sessions.get(sessionId);\n session?.jobs.delete(runId);\n session?.terminalAt.delete(runId);\n if (session?.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n private listInSession(sessionId: string): TrackedAsyncJob[] {\n return [...(this.sessions.get(sessionId)?.jobs.values() ?? [])];\n }\n\n private getInSession(sessionId: string, runId: string): TrackedAsyncJob | undefined {\n return this.sessions.get(sessionId)?.jobs.get(runId);\n }\n\n private resetSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n start(): void {\n this.stop();\n this.unregisterPoll = this.scheduler.register({\n id: POLL_SUBSCRIBER_ID,\n intervalMs: this.pollIntervalMs,\n run: () => this.run(),\n });\n }\n\n stop(): void {\n this.unregisterPoll?.();\n this.unregisterPoll = undefined;\n this.sessions.clear();\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{__esmMin as e}from"../../_virtual/_rolldown/runtime.mjs";import{__decorate as t,init_decorate as n}from"../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.mjs";import{DOOM_TEAM_TYPES as r,init_types as i}from"../container/types.mjs";import{__decorateMetadata as a,init_decorateMetadata as o}from"../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.mjs";import{__decorateParam as s,init_decorateParam as c}from"../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateParam.mjs";import{currentRunsDir as l,init_paths as u}from"../shared/paths.mjs";import{STATUS_FILE_NAME as d,init_statusWriter as f}from"../services/runs/background/statusWriter.mjs";import{parseAsyncRunStatus as p}from"./statusReader.mjs";import{init_statusReader as m}from"../services/runs/background/statusReader.mjs";import{inject as h,injectable as g}from"inversify";import*as _ from"node:fs";import*as v from"node:path";function y(e,t){let n=e.list().map(e=>e.runId).filter(e=>e===t||e.startsWith(t)),r=n.find(e=>e===t);if(r)return r;if(n.length===1)return n[0];throw n.length===0?Error(`No current-session run found for '${t}'.`):Error(`Multiple current-session runs match '${t}'. Use a longer id.`)}function b(e){return v.join(l(),e,d)}function x(e){return typeof e==`object`&&e&&`code`in e?e.code:void 0}function S(e){return x(e)===`ENOENT`}function C(e){return typeof e==`string`&&k.has(e)?e:void 0}var w,T,E,D,O,k,A,j=e((()=>{i(),m(),f(),u(),o(),c(),n(),w=new Set([`complete`,`completed`,`failed`,`paused`,`stopped`]),T=1e4,E=250,D=`async-job-tracker`,O=`__unscoped__`,k=new Set([`starting`,`working`,`tool`,`waiting_for_reply`,`needs_attention`,`finalizing`,`active_long_running`]),A=class{constructor(e){this.scheduler=e}pollIntervalMs=E;retentionMs=T;now(){return Date.now()}readFile(e){try{return _.readFileSync(e,`utf-8`)}catch(e){if(S(e))return;throw e}}async readFileAsync(e){try{return await _.promises.readFile(e,`utf-8`)}catch(e){if(S(e))return;throw e}}sessions=new Map;unregisterPoll;session(e){let t=this.sessions.get(e);return t||(t={jobs:new Map,terminalAt:new Map},this.sessions.set(e,t)),t}forSession(e){if(!e.trim())throw Error(`Pi session identity is required to track subagent runs.`);return{track:t=>this.trackInSession(e,t),untrack:t=>this.untrackInSession(e,t),list:()=>this.listInSession(e),get:t=>this.getInSession(e,t),reset:()=>this.resetSession(e)}}parseStatus(e,t){if(t===void 0)return;let n=p(t,b(e));if(n.kind!==`ok`)return;let r=n.status;return{agent:r.agent,status:r.state,startedAt:r.startedAt,updatedAt:r.lastUpdate,error:r.error,activityState:C(r.activityState),attentionReason:r.attentionReason,runtime:r.runtime,tokens:r.tokens,currentTool:r.currentTool,toolCount:r.toolCount}}readStatus(e){return this.parseStatus(e,this.readFile(b(e)))}async readStatusAsync(e){return this.parseStatus(e,await this.readFileAsync(b(e)))}applyStatus(e,t,n){let r=this.session(e),i=r.jobs.get(t);if(n===void 0)return i||r.jobs.set(t,{runId:t,status:void 0}),!1;let a={runId:t,...n};r.jobs.set(t,a);let o=i?.status!==void 0&&w.has(i.status),s=a.status!==void 0&&w.has(a.status);return s&&!o&&r.terminalAt.set(t,this.now()),s||r.terminalAt.delete(t),!i||i.status!==a.status||i.updatedAt!==a.updatedAt||i.tokens!==a.tokens||i.currentTool!==a.currentTool||i.toolCount!==a.toolCount}refresh(e,t){return this.applyStatus(e,t,this.readStatus(t))}async refreshAsync(e,t){return this.applyStatus(e,t,await this.readStatusAsync(t))}async run(){let e=!1,t=this.now();for(let[n,r]of this.sessions){for(let t of r.jobs.keys())await this.refreshAsync(n,t)&&(e=!0);for(let[n,i]of r.terminalAt)t-i<=this.retentionMs||(r.jobs.delete(n),r.terminalAt.delete(n),e=!0);r.jobs.size===0&&this.sessions.delete(n)}return e}track(e){this.trackInSession(O,e)}untrack(e){this.untrackInSession(O,e)}list(){return this.listInSession(O)}get(e){return this.getInSession(O,e)}reset(){this.resetSession(O)}trackInSession(e,t){this.refresh(e,t)}untrackInSession(e,t){let n=this.sessions.get(e);n?.jobs.delete(t),n?.terminalAt.delete(t),n?.jobs.size===0&&this.sessions.delete(e)}listInSession(e){return[...this.sessions.get(e)?.jobs.values()??[]]}getInSession(e,t){return this.sessions.get(e)?.jobs.get(t)}resetSession(e){this.sessions.delete(e)}start(){this.stop(),this.unregisterPoll=this.scheduler.register({id:D,intervalMs:this.pollIntervalMs,run:()=>this.run()})}stop(){this.unregisterPoll?.(),this.unregisterPoll=void 0,this.sessions.clear()}},A=t([g(),s(0,h(r.PollScheduler)),a(`design:paramtypes`,[Object])],A)}));j();export{A as AsyncJobTracker,w as TERMINAL_ASYNC_JOB_STATES,j as init_asyncJobTracker,y as resolveTrackedRunId};
1
+ import{__esmMin as e}from"../../_virtual/_rolldown/runtime.mjs";import{currentRunsDir as t,init_paths as n}from"../shared/paths.mjs";import{STATUS_FILE_NAME as r,init_statusWriter as i}from"../services/runs/background/statusWriter.mjs";import{parseAsyncRunStatus as a}from"./statusReader.mjs";import{init_statusReader as o}from"../services/runs/background/statusReader.mjs";import*as s from"node:fs";import*as c from"node:path";function l(e,t){let n=e.list().map(e=>e.runId).filter(e=>e===t||e.startsWith(t)),r=n.find(e=>e===t);if(r)return r;if(n.length===1)return n[0];throw n.length===0?Error(`No current-session run found for '${t}'.`):Error(`Multiple current-session runs match '${t}'. Use a longer id.`)}function u(e){return c.join(t(),e,r)}function d(e){return typeof e==`object`&&e&&`code`in e?e.code:void 0}function f(e){return d(e)===`ENOENT`}function p(e){return typeof e==`string`&&y.has(e)?e:void 0}var m,h,g,_,v,y,b,x=e((()=>{o(),i(),n(),m=new Set([`complete`,`completed`,`failed`,`paused`,`stopped`]),h=1e4,g=250,_=`async-job-tracker`,v=`__unscoped__`,y=new Set([`starting`,`working`,`tool`,`waiting_for_reply`,`needs_attention`,`finalizing`,`active_long_running`]),b=class{constructor(e){this.scheduler=e}pollIntervalMs=g;retentionMs=h;now(){return Date.now()}readFile(e){try{return s.readFileSync(e,`utf-8`)}catch(e){if(f(e))return;throw e}}async readFileAsync(e){try{return await s.promises.readFile(e,`utf-8`)}catch(e){if(f(e))return;throw e}}sessions=new Map;unregisterPoll;session(e){let t=this.sessions.get(e);return t||(t={jobs:new Map,terminalAt:new Map},this.sessions.set(e,t)),t}forSession(e){if(!e.trim())throw Error(`Pi session identity is required to track subagent runs.`);return{track:t=>this.trackInSession(e,t),untrack:t=>this.untrackInSession(e,t),list:()=>this.listInSession(e),get:t=>this.getInSession(e,t),reset:()=>this.resetSession(e)}}parseStatus(e,t){if(t===void 0)return;let n=a(t,u(e));if(n.kind!==`ok`)return;let r=n.status;return{agent:r.agent,status:r.state,startedAt:r.startedAt,updatedAt:r.lastUpdate,error:r.error,activityState:p(r.activityState),attentionReason:r.attentionReason,runtime:r.runtime,tokens:r.tokens,currentTool:r.currentTool,toolCount:r.toolCount}}readStatus(e){return this.parseStatus(e,this.readFile(u(e)))}async readStatusAsync(e){return this.parseStatus(e,await this.readFileAsync(u(e)))}applyStatus(e,t,n){let r=this.session(e),i=r.jobs.get(t);if(n===void 0)return i||r.jobs.set(t,{runId:t,status:void 0}),!1;let a={runId:t,...n};r.jobs.set(t,a);let o=i?.status!==void 0&&m.has(i.status),s=a.status!==void 0&&m.has(a.status);return s&&!o&&r.terminalAt.set(t,this.now()),s||r.terminalAt.delete(t),!i||i.status!==a.status||i.updatedAt!==a.updatedAt||i.tokens!==a.tokens||i.currentTool!==a.currentTool||i.toolCount!==a.toolCount}refresh(e,t){return this.applyStatus(e,t,this.readStatus(t))}async refreshAsync(e,t){return this.applyStatus(e,t,await this.readStatusAsync(t))}async run(){let e=!1,t=this.now();for(let[n,r]of this.sessions){for(let t of r.jobs.keys())await this.refreshAsync(n,t)&&(e=!0);for(let[n,i]of r.terminalAt)t-i<=this.retentionMs||(r.jobs.delete(n),r.terminalAt.delete(n),e=!0);r.jobs.size===0&&this.sessions.delete(n)}return e}track(e){this.trackInSession(v,e)}untrack(e){this.untrackInSession(v,e)}list(){return this.listInSession(v)}get(e){return this.getInSession(v,e)}reset(){this.resetSession(v)}trackInSession(e,t){this.refresh(e,t)}untrackInSession(e,t){let n=this.sessions.get(e);n?.jobs.delete(t),n?.terminalAt.delete(t),n?.jobs.size===0&&this.sessions.delete(e)}listInSession(e){return[...this.sessions.get(e)?.jobs.values()??[]]}getInSession(e,t){return this.sessions.get(e)?.jobs.get(t)}resetSession(e){this.sessions.delete(e)}start(){this.stop(),this.unregisterPoll=this.scheduler.register({id:_,intervalMs:this.pollIntervalMs,run:()=>this.run()})}stop(){this.unregisterPoll?.(),this.unregisterPoll=void 0,this.sessions.clear()}}}));x();export{b as AsyncJobTracker,m as TERMINAL_ASYNC_JOB_STATES,x as init_asyncJobTracker,l as resolveTrackedRunId};
2
2
  //# sourceMappingURL=asyncJobTracker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"asyncJobTracker.mjs","names":[],"sources":["../../../src/adapters/asyncJobTracker.ts"],"sourcesContent":["/**\n * Live, in-memory registry of the async runs this session currently cares\n * about, refreshed from `status.json` on a `PollScheduler` tick.\n *\n * WHY THIS IS SMALLER THAN THE PREDECESSOR:\n * `doom-pi-subagents/src/runs/background/asyncJobTracker.ts` is 590 lines\n * doing four different jobs: this registry, TUI widget rendering\n * (`renderWidget`/`widgetRenderKey`/`ctx.ui.requestRender`), forwarding\n * control events and steering notices by byte-range-tailing each run's\n * `events.jsonl`, and projecting nested/parallel-group run trees. Only the\n * registry is ported. The other three have no consumer in this package yet:\n * TUI rendering is `G8` (slash commands + TUI), and nested/chain/parallel run\n * modes are `G7`+ (this package is currently single-run async-only - see\n * `spawnHandshake.ts`'s header). Porting rendering or event-tailing logic\n * with nothing to render to or forward to would be untested, unreachable\n * code; it is deferred to whichever later port actually needs it, not\n * dropped silently - this note is where to look for it.\n *\n * DESIGN PATTERNS:\n * - The in-memory map is a pure CACHE, never authoritative on its own:\n * `status.json` (owned by `CoalescedStatusWriter` elsewhere) is the only\n * source of truth. `track()` reads it synchronously immediately, so a\n * caller that already knows a run's id sees *something* right away rather\n * than waiting out the first poll\n * - Restart survivability follows from the point above rather than a second\n * persistence layer: this package has not built session-scoped run\n * ownership yet (which ids \"belong\" to a restarted session is not\n * something this module can determine on its own - see the AVOID entry),\n * so recovery is the caller re-`track()`-ing whatever ids it still cares\n * about from ITS OWN durable record. The very next poll tick repopulates\n * that job's status straight from disk. There is no separate store to keep\n * in sync, and therefore no window where memory could diverge from disk\n * that a restart would not immediately close\n * - Registered with `PollScheduler`, not a private timer: this polls\n * potentially many jobs' status files on an unbounded, periodic cadence\n * with no low-latency requirement - the exact shape `PollScheduler` exists\n * for. Contrast `completionBatcher.ts`/`spawnHandshake.ts`, which own\n * their own timers because they are short-lived, single-shot, and need\n * sub-200ms responsiveness `PollScheduler`'s floor cannot give them; this\n * registry needs neither\n * - Retention-then-eviction happens on the SAME poll tick as the status\n * refresh, rather than the predecessor's per-job `setTimeout`\n * (`scheduleCleanup`): a terminal job aged past `retentionMs` is simply\n * dropped the next time `run()` walks the map. One clock, not one timer per\n * job\n *\n * AVOID:\n * - Scanning `currentRunsDir()` to guess which run ids \"belong\" to this session on\n * startup. This package has no session-scoped run ownership concept yet;\n * inventing one here to answer \"what should I restore\" would be a guess,\n * not a fact this module has standing to assert. Restoration is the\n * caller's job (see the design note above)\n * - Growing `terminalStates` independently of `staleRunReconciler.ts`'s own\n * (unexported) copy; both must treat the same state strings as terminal,\n * or a job could be evicted here while the reconciler still thinks it is\n * in flight, or vice versa\n *\n * `activityState`/`attentionReason` (added for `subagentWait.ts`):\n * `DeliverableGuard.evaluate()` computes `activityState: 'needs_attention'`\n * and a `reason` (e.g. `'missing-deliverable'`), but returns it rather than\n * writing it anywhere - it has no standing to touch `status.json` itself (see\n * that module's header). Something upstream of this tracker - the run's own\n * runner main loop, not yet built - is responsible for folding that result\n * into `status.json` through `CoalescedStatusWriter`. This tracker's job is\n * only to read whatever ends up there, the same as every other field: it does\n * not compute attention, detect it, or decide when a run needs it.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { inject, injectable } from 'inversify';\nimport { DOOM_TEAM_TYPES } from '../container/types.ts';\nimport { parseAsyncRunStatus } from '../services/runs/background/statusReader.ts';\nimport { STATUS_FILE_NAME } from '../services/runs/background/statusWriter.ts';\nimport { currentRunsDir } from '../shared/paths.ts';\nimport type { IPollScheduler } from '../shared/pollScheduler.ts';\nimport type { ActivityState } from '../types/index.ts';\n\n/**\n * States that mean \"already finished\"; matches `staleRunReconciler.ts`'s\n * own (unexported) set. Exported so a caller outside this module (the slash\n * layer's poll-until-terminal helper) can recognize the same terminal set\n * `TrackedAsyncJob.status` uses, rather than declaring a third copy of this\n * literal.\n */\nexport const TERMINAL_ASYNC_JOB_STATES = new Set(['complete', 'completed', 'failed', 'paused', 'stopped']);\n\n/** How long a terminal job stays queryable before eviction. */\nconst DEFAULT_RETENTION_MS = 10_000;\n/** How often tracked jobs' status is refreshed from disk. */\nconst DEFAULT_POLL_INTERVAL_MS = 250;\n\nconst POLL_SUBSCRIBER_ID = 'async-job-tracker';\n\n/**\n * The minimum shape this module reads. A run's actual `status.json` carries\n * far more (this package has no shared status type yet - see\n * `staleRunReconciler.ts`'s `ReconcilableStatus` for the same caveat);\n * everything else is simply not read here.\n */\nexport interface TrackedAsyncJob {\n runId: string;\n /** Named agent executing this run. Absent until the first readable status. */\n agent?: string;\n /** `status.json`'s `state` field. `undefined` until the first successful read. */\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n /** `status.json`'s `activityState` field, e.g. `'needs_attention'`. See the module doc. */\n activityState?: ActivityState;\n /** `status.json`'s `reason` field, present alongside `activityState` (e.g. `'missing-deliverable'`). */\n attentionReason?: string;\n /** Which runtime is executing this run. Absent means the default `pi` path. */\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nexport interface ITrackedAsyncJobs {\n /**\n * Start tracking `runId`: reads its current status synchronously (so a\n * caller sees something immediately) and adds it to the poll rotation.\n * Calling this again for an id already tracked simply re-reads it now,\n * the same idempotent-refresh idiom as `CoalescedStatusWriter.open()`.\n */\n track(runId: string): void;\n /** Stop tracking `runId` immediately, without waiting out its retention window. */\n untrack(runId: string): void;\n /** Every currently tracked job (in-flight, or terminal within its retention window). */\n list(): TrackedAsyncJob[];\n get(runId: string): TrackedAsyncJob | undefined;\n /** Drop every tracked job. */\n reset(): void;\n}\n\nexport interface IAsyncJobTracker extends ITrackedAsyncJobs {\n /** Return the isolated run collection owned by one Pi session context. */\n forSession(sessionId: string): ITrackedAsyncJobs;\n /** Register with `PollScheduler`. Call once; a second call is a reset, same as `ResultWatcher.start()`. */\n start(): void;\n /** Unregister from `PollScheduler` and drop every tracked job. */\n stop(): void;\n}\n\n/** Resolve an exact id or unique prefix only inside one Pi session's run collection. */\nexport function resolveTrackedRunId(jobs: ITrackedAsyncJobs, id: string): string {\n const matches = jobs\n .list()\n .map((job) => job.runId)\n .filter((runId) => runId === id || runId.startsWith(id));\n const exact = matches.find((runId) => runId === id);\n if (exact) return exact;\n if (matches.length === 1) return matches[0]!;\n if (matches.length === 0) throw new Error(`No current-session run found for '${id}'.`);\n throw new Error(`Multiple current-session runs match '${id}'. Use a longer id.`);\n}\n\ninterface SessionJobs {\n jobs: Map<string, TrackedAsyncJob>;\n terminalAt: Map<string, number>;\n}\n\nconst UNSCOPED_SESSION = '__unscoped__';\n\nfunction statusPathFor(runId: string): string {\n return path.join(currentRunsDir(), runId, STATUS_FILE_NAME);\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return typeof error === 'object' && error !== null && 'code' in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return errorCode(error) === 'ENOENT';\n}\n\ninterface ReadStatusResult {\n agent: string;\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n activityState?: ActivityState;\n attentionReason?: string;\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nconst VALID_ACTIVITY_STATES: ReadonlySet<string> = new Set<ActivityState>([\n 'starting',\n 'working',\n 'tool',\n 'waiting_for_reply',\n 'needs_attention',\n 'finalizing',\n 'active_long_running',\n]);\n\nfunction asActivityState(value: unknown): ActivityState | undefined {\n return typeof value === 'string' && VALID_ACTIVITY_STATES.has(value) ? (value as ActivityState) : undefined;\n}\n\n@injectable()\nexport class AsyncJobTracker implements IAsyncJobTracker {\n constructor(@inject(DOOM_TEAM_TYPES.PollScheduler) private readonly scheduler: IPollScheduler) {}\n\n /**\n * Seams for tests, as protected members rather than constructor arguments:\n * inversify cannot resolve a primitive. See `pollScheduler.ts` and\n * `agents/discovery.ts` for the same pattern.\n */\n protected readonly pollIntervalMs: number = DEFAULT_POLL_INTERVAL_MS;\n protected readonly retentionMs: number = DEFAULT_RETENTION_MS;\n\n protected now(): number {\n return Date.now();\n }\n\n protected readFile(filePath: string): string | undefined {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n protected async readFileAsync(filePath: string): Promise<string | undefined> {\n try {\n return await fs.promises.readFile(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n private readonly sessions = new Map<string, SessionJobs>();\n private unregisterPoll: (() => void) | undefined;\n\n private session(sessionId: string): SessionJobs {\n let session = this.sessions.get(sessionId);\n if (!session) {\n session = { jobs: new Map(), terminalAt: new Map() };\n this.sessions.set(sessionId, session);\n }\n return session;\n }\n\n forSession(sessionId: string): ITrackedAsyncJobs {\n if (!sessionId.trim()) throw new Error('Pi session identity is required to track subagent runs.');\n return {\n track: (runId) => this.trackInSession(sessionId, runId),\n untrack: (runId) => this.untrackInSession(sessionId, runId),\n list: () => this.listInSession(sessionId),\n get: (runId) => this.getInSession(sessionId, runId),\n reset: () => this.resetSession(sessionId),\n };\n }\n\n private parseStatus(runId: string, raw: string | undefined): ReadStatusResult | undefined {\n if (raw === undefined) return undefined;\n const result = parseAsyncRunStatus(raw, statusPathFor(runId));\n if (result.kind !== 'ok') return undefined;\n const status = result.status;\n return {\n agent: status.agent,\n status: status.state,\n startedAt: status.startedAt,\n updatedAt: status.lastUpdate,\n error: status.error,\n activityState: asActivityState(status.activityState),\n attentionReason: status.attentionReason,\n runtime: status.runtime,\n tokens: status.tokens,\n currentTool: status.currentTool,\n toolCount: status.toolCount,\n };\n }\n\n private readStatus(runId: string): ReadStatusResult | undefined {\n return this.parseStatus(runId, this.readFile(statusPathFor(runId)));\n }\n\n private async readStatusAsync(runId: string): Promise<ReadStatusResult | undefined> {\n return this.parseStatus(runId, await this.readFileAsync(statusPathFor(runId)));\n }\n\n private applyStatus(sessionId: string, runId: string, read: ReadStatusResult | undefined): boolean {\n const session = this.session(sessionId);\n const existing = session.jobs.get(runId);\n if (read === undefined) {\n // A run may not have created its file yet, and a torn read must not blank\n // a previously known status for one polling pass.\n if (existing) return false;\n session.jobs.set(runId, { runId, status: undefined });\n return false;\n }\n\n const job: TrackedAsyncJob = { runId, ...read };\n session.jobs.set(runId, job);\n const wasTerminal = existing?.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(existing.status);\n const isTerminal = job.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(job.status);\n if (isTerminal && !wasTerminal) session.terminalAt.set(runId, this.now());\n if (!isTerminal) session.terminalAt.delete(runId);\n return (\n !existing ||\n existing.status !== job.status ||\n existing.updatedAt !== job.updatedAt ||\n existing.tokens !== job.tokens ||\n existing.currentTool !== job.currentTool ||\n existing.toolCount !== job.toolCount\n );\n }\n\n private refresh(sessionId: string, runId: string): boolean {\n return this.applyStatus(sessionId, runId, this.readStatus(runId));\n }\n\n private async refreshAsync(sessionId: string, runId: string): Promise<boolean> {\n return this.applyStatus(sessionId, runId, await this.readStatusAsync(runId));\n }\n\n /** One scheduler tick: asynchronously refresh every tracked status, then evict expired terminal jobs. */\n protected async run(): Promise<boolean> {\n let changed = false;\n const now = this.now();\n for (const [sessionId, session] of this.sessions) {\n for (const runId of session.jobs.keys()) {\n if (await this.refreshAsync(sessionId, runId)) changed = true;\n }\n for (const [runId, terminatedAt] of session.terminalAt) {\n if (now - terminatedAt <= this.retentionMs) continue;\n session.jobs.delete(runId);\n session.terminalAt.delete(runId);\n changed = true;\n }\n if (session.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n return changed;\n }\n\n track(runId: string): void {\n this.trackInSession(UNSCOPED_SESSION, runId);\n }\n\n untrack(runId: string): void {\n this.untrackInSession(UNSCOPED_SESSION, runId);\n }\n\n list(): TrackedAsyncJob[] {\n return this.listInSession(UNSCOPED_SESSION);\n }\n\n get(runId: string): TrackedAsyncJob | undefined {\n return this.getInSession(UNSCOPED_SESSION, runId);\n }\n\n reset(): void {\n this.resetSession(UNSCOPED_SESSION);\n }\n\n private trackInSession(sessionId: string, runId: string): void {\n this.refresh(sessionId, runId);\n }\n\n private untrackInSession(sessionId: string, runId: string): void {\n const session = this.sessions.get(sessionId);\n session?.jobs.delete(runId);\n session?.terminalAt.delete(runId);\n if (session?.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n private listInSession(sessionId: string): TrackedAsyncJob[] {\n return [...(this.sessions.get(sessionId)?.jobs.values() ?? [])];\n }\n\n private getInSession(sessionId: string, runId: string): TrackedAsyncJob | undefined {\n return this.sessions.get(sessionId)?.jobs.get(runId);\n }\n\n private resetSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n start(): void {\n this.stop();\n this.unregisterPoll = this.scheduler.register({\n id: POLL_SUBSCRIBER_ID,\n intervalMs: this.pollIntervalMs,\n run: () => this.run(),\n });\n }\n\n stop(): void {\n this.unregisterPoll?.();\n this.unregisterPoll = undefined;\n this.sessions.clear();\n }\n}\n"],"mappings":"q6BAmJA,SAAgB,EAAoB,EAAyB,EAAoB,CAC/E,IAAM,EAAU,EACb,MAAM,CACN,IAAK,GAAQ,EAAI,MAAM,CACvB,OAAQ,GAAU,IAAU,GAAM,EAAM,WAAW,EAAG,CAAC,CACpD,EAAQ,EAAQ,KAAM,GAAU,IAAU,EAAG,CACnD,GAAI,EAAO,OAAO,EAClB,GAAI,EAAQ,SAAW,EAAG,OAAO,EAAQ,GAEzC,MADI,EAAQ,SAAW,EAAa,MAAM,qCAAqC,EAAG,IAAI,CAC5E,MAAM,wCAAwC,EAAG,qBAAqB,CAUlF,SAAS,EAAc,EAAuB,CAC5C,OAAO,EAAK,KAAK,GAAgB,CAAE,EAAO,EAAiB,CAG7D,SAAS,EAAU,EAAoC,CACrD,OAAO,OAAO,GAAU,UAAY,GAAkB,SAAU,EAC3D,EAAgC,KACjC,IAAA,GAGN,SAAS,EAAW,EAAyB,CAC3C,OAAO,EAAU,EAAM,GAAK,SA2B9B,SAAS,EAAgB,EAA2C,CAClE,OAAO,OAAO,GAAU,UAAY,EAAsB,IAAI,EAAM,CAAI,EAA0B,IAAA,kCAtI5C,IAC0B,IACH,IAC3B,aAWvC,EAA4B,IAAI,IAAI,CAAC,WAAY,YAAa,SAAU,SAAU,UAAU,CAAC,CAGpG,EAAuB,IAEvB,EAA2B,IAE3B,EAAqB,oBAwErB,EAAmB,eA8BnB,EAA6C,IAAI,IAAmB,CACxE,WACA,UACA,OACA,oBACA,kBACA,aACA,sBACD,CAAC,GAOK,KAAkD,CACvD,YAAY,EAAmF,CAA3B,KAAA,UAAA,EAOpE,eAA4C,EAC5C,YAAyC,EAEzC,KAAwB,CACtB,OAAO,KAAK,KAAK,CAGnB,SAAmB,EAAsC,CACvD,GAAI,CACF,OAAO,EAAG,aAAa,EAAU,QAAQ,OAClC,EAAO,CACd,GAAI,EAAW,EAAM,CAAE,OACvB,MAAM,GAIV,MAAgB,cAAc,EAA+C,CAC3E,GAAI,CACF,OAAO,MAAM,EAAG,SAAS,SAAS,EAAU,QAAQ,OAC7C,EAAO,CACd,GAAI,EAAW,EAAM,CAAE,OACvB,MAAM,GAIV,SAA4B,IAAI,IAChC,eAEA,QAAgB,EAAgC,CAC9C,IAAI,EAAU,KAAK,SAAS,IAAI,EAAU,CAK1C,OAJK,IACH,EAAU,CAAE,KAAM,IAAI,IAAO,WAAY,IAAI,IAAO,CACpD,KAAK,SAAS,IAAI,EAAW,EAAQ,EAEhC,EAGT,WAAW,EAAsC,CAC/C,GAAI,CAAC,EAAU,MAAM,CAAE,MAAU,MAAM,0DAA0D,CACjG,MAAO,CACL,MAAQ,GAAU,KAAK,eAAe,EAAW,EAAM,CACvD,QAAU,GAAU,KAAK,iBAAiB,EAAW,EAAM,CAC3D,SAAY,KAAK,cAAc,EAAU,CACzC,IAAM,GAAU,KAAK,aAAa,EAAW,EAAM,CACnD,UAAa,KAAK,aAAa,EAAU,CAC1C,CAGH,YAAoB,EAAe,EAAuD,CACxF,GAAI,IAAQ,IAAA,GAAW,OACvB,IAAM,EAAS,EAAoB,EAAK,EAAc,EAAM,CAAC,CAC7D,GAAI,EAAO,OAAS,KAAM,OAC1B,IAAM,EAAS,EAAO,OACtB,MAAO,CACL,MAAO,EAAO,MACd,OAAQ,EAAO,MACf,UAAW,EAAO,UAClB,UAAW,EAAO,WAClB,MAAO,EAAO,MACd,cAAe,EAAgB,EAAO,cAAc,CACpD,gBAAiB,EAAO,gBACxB,QAAS,EAAO,QAChB,OAAQ,EAAO,OACf,YAAa,EAAO,YACpB,UAAW,EAAO,UACnB,CAGH,WAAmB,EAA6C,CAC9D,OAAO,KAAK,YAAY,EAAO,KAAK,SAAS,EAAc,EAAM,CAAC,CAAC,CAGrE,MAAc,gBAAgB,EAAsD,CAClF,OAAO,KAAK,YAAY,EAAO,MAAM,KAAK,cAAc,EAAc,EAAM,CAAC,CAAC,CAGhF,YAAoB,EAAmB,EAAe,EAA6C,CACjG,IAAM,EAAU,KAAK,QAAQ,EAAU,CACjC,EAAW,EAAQ,KAAK,IAAI,EAAM,CACxC,GAAI,IAAS,IAAA,GAKX,OAFI,GACJ,EAAQ,KAAK,IAAI,EAAO,CAAE,QAAO,OAAQ,IAAA,GAAW,CAAC,CADhC,GAKvB,IAAM,EAAuB,CAAE,QAAO,GAAG,EAAM,CAC/C,EAAQ,KAAK,IAAI,EAAO,EAAI,CAC5B,IAAM,EAAc,GAAU,SAAW,IAAA,IAAa,EAA0B,IAAI,EAAS,OAAO,CAC9F,EAAa,EAAI,SAAW,IAAA,IAAa,EAA0B,IAAI,EAAI,OAAO,CAGxF,OAFI,GAAc,CAAC,GAAa,EAAQ,WAAW,IAAI,EAAO,KAAK,KAAK,CAAC,CACpE,GAAY,EAAQ,WAAW,OAAO,EAAM,CAE/C,CAAC,GACD,EAAS,SAAW,EAAI,QACxB,EAAS,YAAc,EAAI,WAC3B,EAAS,SAAW,EAAI,QACxB,EAAS,cAAgB,EAAI,aAC7B,EAAS,YAAc,EAAI,UAI/B,QAAgB,EAAmB,EAAwB,CACzD,OAAO,KAAK,YAAY,EAAW,EAAO,KAAK,WAAW,EAAM,CAAC,CAGnE,MAAc,aAAa,EAAmB,EAAiC,CAC7E,OAAO,KAAK,YAAY,EAAW,EAAO,MAAM,KAAK,gBAAgB,EAAM,CAAC,CAI9E,MAAgB,KAAwB,CACtC,IAAI,EAAU,GACR,EAAM,KAAK,KAAK,CACtB,IAAK,GAAM,CAAC,EAAW,KAAY,KAAK,SAAU,CAChD,IAAK,IAAM,KAAS,EAAQ,KAAK,MAAM,CACjC,MAAM,KAAK,aAAa,EAAW,EAAM,GAAE,EAAU,IAE3D,IAAK,GAAM,CAAC,EAAO,KAAiB,EAAQ,WACtC,EAAM,GAAgB,KAAK,cAC/B,EAAQ,KAAK,OAAO,EAAM,CAC1B,EAAQ,WAAW,OAAO,EAAM,CAChC,EAAU,IAER,EAAQ,KAAK,OAAS,GAAG,KAAK,SAAS,OAAO,EAAU,CAG9D,OAAO,EAGT,MAAM,EAAqB,CACzB,KAAK,eAAe,EAAkB,EAAM,CAG9C,QAAQ,EAAqB,CAC3B,KAAK,iBAAiB,EAAkB,EAAM,CAGhD,MAA0B,CACxB,OAAO,KAAK,cAAc,EAAiB,CAG7C,IAAI,EAA4C,CAC9C,OAAO,KAAK,aAAa,EAAkB,EAAM,CAGnD,OAAc,CACZ,KAAK,aAAa,EAAiB,CAGrC,eAAuB,EAAmB,EAAqB,CAC7D,KAAK,QAAQ,EAAW,EAAM,CAGhC,iBAAyB,EAAmB,EAAqB,CAC/D,IAAM,EAAU,KAAK,SAAS,IAAI,EAAU,CAC5C,GAAS,KAAK,OAAO,EAAM,CAC3B,GAAS,WAAW,OAAO,EAAM,CAC7B,GAAS,KAAK,OAAS,GAAG,KAAK,SAAS,OAAO,EAAU,CAG/D,cAAsB,EAAsC,CAC1D,MAAO,CAAC,GAAI,KAAK,SAAS,IAAI,EAAU,EAAE,KAAK,QAAQ,EAAI,EAAE,CAAE,CAGjE,aAAqB,EAAmB,EAA4C,CAClF,OAAO,KAAK,SAAS,IAAI,EAAU,EAAE,KAAK,IAAI,EAAM,CAGtD,aAAqB,EAAyB,CAC5C,KAAK,SAAS,OAAO,EAAU,CAGjC,OAAc,CACZ,KAAK,MAAM,CACX,KAAK,eAAiB,KAAK,UAAU,SAAS,CAC5C,GAAI,EACJ,WAAY,KAAK,eACjB,QAAW,KAAK,KAAK,CACtB,CAAC,CAGJ,MAAa,CACX,KAAK,kBAAkB,CACvB,KAAK,eAAiB,IAAA,GACtB,KAAK,SAAS,OAAO,QAnMxB,GAAY,KAEE,EAAO,EAAgB,cAAc,CAAA"}
1
+ {"version":3,"file":"asyncJobTracker.mjs","names":[],"sources":["../../../src/adapters/asyncJobTracker.ts"],"sourcesContent":["/**\n * Live, in-memory registry of the async runs this session currently cares\n * about, refreshed from `status.json` on a `PollScheduler` tick.\n *\n * WHY THIS IS SMALLER THAN THE PREDECESSOR:\n * `doom-pi-subagents/src/runs/background/asyncJobTracker.ts` is 590 lines\n * doing four different jobs: this registry, TUI widget rendering\n * (`renderWidget`/`widgetRenderKey`/`ctx.ui.requestRender`), forwarding\n * control events and steering notices by byte-range-tailing each run's\n * `events.jsonl`, and projecting nested/parallel-group run trees. Only the\n * registry is ported. The other three have no consumer in this package yet:\n * TUI rendering is `G8` (slash commands + TUI), and nested/chain/parallel run\n * modes are `G7`+ (this package is currently single-run async-only - see\n * `spawnHandshake.ts`'s header). Porting rendering or event-tailing logic\n * with nothing to render to or forward to would be untested, unreachable\n * code; it is deferred to whichever later port actually needs it, not\n * dropped silently - this note is where to look for it.\n *\n * DESIGN PATTERNS:\n * - The in-memory map is a pure CACHE, never authoritative on its own:\n * `status.json` (owned by `CoalescedStatusWriter` elsewhere) is the only\n * source of truth. `track()` reads it synchronously immediately, so a\n * caller that already knows a run's id sees *something* right away rather\n * than waiting out the first poll\n * - Restart survivability follows from the point above rather than a second\n * persistence layer: this package has not built session-scoped run\n * ownership yet (which ids \"belong\" to a restarted session is not\n * something this module can determine on its own - see the AVOID entry),\n * so recovery is the caller re-`track()`-ing whatever ids it still cares\n * about from ITS OWN durable record. The very next poll tick repopulates\n * that job's status straight from disk. There is no separate store to keep\n * in sync, and therefore no window where memory could diverge from disk\n * that a restart would not immediately close\n * - Registered with `PollScheduler`, not a private timer: this polls\n * potentially many jobs' status files on an unbounded, periodic cadence\n * with no low-latency requirement - the exact shape `PollScheduler` exists\n * for. Contrast `completionBatcher.ts`/`spawnHandshake.ts`, which own\n * their own timers because they are short-lived, single-shot, and need\n * sub-200ms responsiveness `PollScheduler`'s floor cannot give them; this\n * registry needs neither\n * - Retention-then-eviction happens on the SAME poll tick as the status\n * refresh, rather than the predecessor's per-job `setTimeout`\n * (`scheduleCleanup`): a terminal job aged past `retentionMs` is simply\n * dropped the next time `run()` walks the map. One clock, not one timer per\n * job\n *\n * AVOID:\n * - Scanning `currentRunsDir()` to guess which run ids \"belong\" to this session on\n * startup. This package has no session-scoped run ownership concept yet;\n * inventing one here to answer \"what should I restore\" would be a guess,\n * not a fact this module has standing to assert. Restoration is the\n * caller's job (see the design note above)\n * - Growing `terminalStates` independently of `staleRunReconciler.ts`'s own\n * (unexported) copy; both must treat the same state strings as terminal,\n * or a job could be evicted here while the reconciler still thinks it is\n * in flight, or vice versa\n *\n * `activityState`/`attentionReason` (added for `subagentWait.ts`):\n * `DeliverableGuard.evaluate()` computes `activityState: 'needs_attention'`\n * and a `reason` (e.g. `'missing-deliverable'`), but returns it rather than\n * writing it anywhere - it has no standing to touch `status.json` itself (see\n * that module's header). Something upstream of this tracker - the run's own\n * runner main loop, not yet built - is responsible for folding that result\n * into `status.json` through `CoalescedStatusWriter`. This tracker's job is\n * only to read whatever ends up there, the same as every other field: it does\n * not compute attention, detect it, or decide when a run needs it.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseAsyncRunStatus } from '../services/runs/background/statusReader.ts';\nimport { STATUS_FILE_NAME } from '../services/runs/background/statusWriter.ts';\nimport { currentRunsDir } from '../shared/paths.ts';\nimport type { IPollScheduler } from '../shared/pollScheduler.ts';\nimport type { ActivityState } from '../types/index.ts';\n\n/**\n * States that mean \"already finished\"; matches `staleRunReconciler.ts`'s\n * own (unexported) set. Exported so a caller outside this module (the slash\n * layer's poll-until-terminal helper) can recognize the same terminal set\n * `TrackedAsyncJob.status` uses, rather than declaring a third copy of this\n * literal.\n */\nexport const TERMINAL_ASYNC_JOB_STATES = new Set(['complete', 'completed', 'failed', 'paused', 'stopped']);\n\n/** How long a terminal job stays queryable before eviction. */\nconst DEFAULT_RETENTION_MS = 10_000;\n/** How often tracked jobs' status is refreshed from disk. */\nconst DEFAULT_POLL_INTERVAL_MS = 250;\n\nconst POLL_SUBSCRIBER_ID = 'async-job-tracker';\n\n/**\n * The minimum shape this module reads. A run's actual `status.json` carries\n * far more (this package has no shared status type yet - see\n * `staleRunReconciler.ts`'s `ReconcilableStatus` for the same caveat);\n * everything else is simply not read here.\n */\nexport interface TrackedAsyncJob {\n runId: string;\n /** Named agent executing this run. Absent until the first readable status. */\n agent?: string;\n /** `status.json`'s `state` field. `undefined` until the first successful read. */\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n /** `status.json`'s `activityState` field, e.g. `'needs_attention'`. See the module doc. */\n activityState?: ActivityState;\n /** `status.json`'s `reason` field, present alongside `activityState` (e.g. `'missing-deliverable'`). */\n attentionReason?: string;\n /** Which runtime is executing this run. Absent means the default `pi` path. */\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nexport interface ITrackedAsyncJobs {\n /**\n * Start tracking `runId`: reads its current status synchronously (so a\n * caller sees something immediately) and adds it to the poll rotation.\n * Calling this again for an id already tracked simply re-reads it now,\n * the same idempotent-refresh idiom as `CoalescedStatusWriter.open()`.\n */\n track(runId: string): void;\n /** Stop tracking `runId` immediately, without waiting out its retention window. */\n untrack(runId: string): void;\n /** Every currently tracked job (in-flight, or terminal within its retention window). */\n list(): TrackedAsyncJob[];\n get(runId: string): TrackedAsyncJob | undefined;\n /** Drop every tracked job. */\n reset(): void;\n}\n\nexport interface IAsyncJobTracker extends ITrackedAsyncJobs {\n /** Return the isolated run collection owned by one Pi session context. */\n forSession(sessionId: string): ITrackedAsyncJobs;\n /** Register with `PollScheduler`. Call once; a second call is a reset, same as `ResultWatcher.start()`. */\n start(): void;\n /** Unregister from `PollScheduler` and drop every tracked job. */\n stop(): void;\n}\n\n/** Resolve an exact id or unique prefix only inside one Pi session's run collection. */\nexport function resolveTrackedRunId(jobs: ITrackedAsyncJobs, id: string): string {\n const matches = jobs\n .list()\n .map((job) => job.runId)\n .filter((runId) => runId === id || runId.startsWith(id));\n const exact = matches.find((runId) => runId === id);\n if (exact) return exact;\n if (matches.length === 1) return matches[0]!;\n if (matches.length === 0) throw new Error(`No current-session run found for '${id}'.`);\n throw new Error(`Multiple current-session runs match '${id}'. Use a longer id.`);\n}\n\ninterface SessionJobs {\n jobs: Map<string, TrackedAsyncJob>;\n terminalAt: Map<string, number>;\n}\n\nconst UNSCOPED_SESSION = '__unscoped__';\n\nfunction statusPathFor(runId: string): string {\n return path.join(currentRunsDir(), runId, STATUS_FILE_NAME);\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return typeof error === 'object' && error !== null && 'code' in error\n ? (error as NodeJS.ErrnoException).code\n : undefined;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return errorCode(error) === 'ENOENT';\n}\n\ninterface ReadStatusResult {\n agent: string;\n status: string | undefined;\n startedAt?: number;\n updatedAt?: number;\n error?: string;\n activityState?: ActivityState;\n attentionReason?: string;\n runtime?: string;\n tokens?: number;\n currentTool?: string;\n toolCount?: number;\n}\n\nconst VALID_ACTIVITY_STATES: ReadonlySet<string> = new Set<ActivityState>([\n 'starting',\n 'working',\n 'tool',\n 'waiting_for_reply',\n 'needs_attention',\n 'finalizing',\n 'active_long_running',\n]);\n\nfunction asActivityState(value: unknown): ActivityState | undefined {\n return typeof value === 'string' && VALID_ACTIVITY_STATES.has(value) ? (value as ActivityState) : undefined;\n}\n\nexport class AsyncJobTracker implements IAsyncJobTracker {\n constructor(private readonly scheduler: IPollScheduler) {}\n\n /**\n * Runtime tuning seams for tests, kept out of the dependency constructor.\n */\n protected readonly pollIntervalMs: number = DEFAULT_POLL_INTERVAL_MS;\n protected readonly retentionMs: number = DEFAULT_RETENTION_MS;\n\n protected now(): number {\n return Date.now();\n }\n\n protected readFile(filePath: string): string | undefined {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n protected async readFileAsync(filePath: string): Promise<string | undefined> {\n try {\n return await fs.promises.readFile(filePath, 'utf-8');\n } catch (error) {\n if (isNotFound(error)) return undefined;\n throw error;\n }\n }\n\n private readonly sessions = new Map<string, SessionJobs>();\n private unregisterPoll: (() => void) | undefined;\n\n private session(sessionId: string): SessionJobs {\n let session = this.sessions.get(sessionId);\n if (!session) {\n session = { jobs: new Map(), terminalAt: new Map() };\n this.sessions.set(sessionId, session);\n }\n return session;\n }\n\n forSession(sessionId: string): ITrackedAsyncJobs {\n if (!sessionId.trim()) throw new Error('Pi session identity is required to track subagent runs.');\n return {\n track: (runId) => this.trackInSession(sessionId, runId),\n untrack: (runId) => this.untrackInSession(sessionId, runId),\n list: () => this.listInSession(sessionId),\n get: (runId) => this.getInSession(sessionId, runId),\n reset: () => this.resetSession(sessionId),\n };\n }\n\n private parseStatus(runId: string, raw: string | undefined): ReadStatusResult | undefined {\n if (raw === undefined) return undefined;\n const result = parseAsyncRunStatus(raw, statusPathFor(runId));\n if (result.kind !== 'ok') return undefined;\n const status = result.status;\n return {\n agent: status.agent,\n status: status.state,\n startedAt: status.startedAt,\n updatedAt: status.lastUpdate,\n error: status.error,\n activityState: asActivityState(status.activityState),\n attentionReason: status.attentionReason,\n runtime: status.runtime,\n tokens: status.tokens,\n currentTool: status.currentTool,\n toolCount: status.toolCount,\n };\n }\n\n private readStatus(runId: string): ReadStatusResult | undefined {\n return this.parseStatus(runId, this.readFile(statusPathFor(runId)));\n }\n\n private async readStatusAsync(runId: string): Promise<ReadStatusResult | undefined> {\n return this.parseStatus(runId, await this.readFileAsync(statusPathFor(runId)));\n }\n\n private applyStatus(sessionId: string, runId: string, read: ReadStatusResult | undefined): boolean {\n const session = this.session(sessionId);\n const existing = session.jobs.get(runId);\n if (read === undefined) {\n // A run may not have created its file yet, and a torn read must not blank\n // a previously known status for one polling pass.\n if (existing) return false;\n session.jobs.set(runId, { runId, status: undefined });\n return false;\n }\n\n const job: TrackedAsyncJob = { runId, ...read };\n session.jobs.set(runId, job);\n const wasTerminal = existing?.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(existing.status);\n const isTerminal = job.status !== undefined && TERMINAL_ASYNC_JOB_STATES.has(job.status);\n if (isTerminal && !wasTerminal) session.terminalAt.set(runId, this.now());\n if (!isTerminal) session.terminalAt.delete(runId);\n return (\n !existing ||\n existing.status !== job.status ||\n existing.updatedAt !== job.updatedAt ||\n existing.tokens !== job.tokens ||\n existing.currentTool !== job.currentTool ||\n existing.toolCount !== job.toolCount\n );\n }\n\n private refresh(sessionId: string, runId: string): boolean {\n return this.applyStatus(sessionId, runId, this.readStatus(runId));\n }\n\n private async refreshAsync(sessionId: string, runId: string): Promise<boolean> {\n return this.applyStatus(sessionId, runId, await this.readStatusAsync(runId));\n }\n\n /** One scheduler tick: asynchronously refresh every tracked status, then evict expired terminal jobs. */\n protected async run(): Promise<boolean> {\n let changed = false;\n const now = this.now();\n for (const [sessionId, session] of this.sessions) {\n for (const runId of session.jobs.keys()) {\n if (await this.refreshAsync(sessionId, runId)) changed = true;\n }\n for (const [runId, terminatedAt] of session.terminalAt) {\n if (now - terminatedAt <= this.retentionMs) continue;\n session.jobs.delete(runId);\n session.terminalAt.delete(runId);\n changed = true;\n }\n if (session.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n return changed;\n }\n\n track(runId: string): void {\n this.trackInSession(UNSCOPED_SESSION, runId);\n }\n\n untrack(runId: string): void {\n this.untrackInSession(UNSCOPED_SESSION, runId);\n }\n\n list(): TrackedAsyncJob[] {\n return this.listInSession(UNSCOPED_SESSION);\n }\n\n get(runId: string): TrackedAsyncJob | undefined {\n return this.getInSession(UNSCOPED_SESSION, runId);\n }\n\n reset(): void {\n this.resetSession(UNSCOPED_SESSION);\n }\n\n private trackInSession(sessionId: string, runId: string): void {\n this.refresh(sessionId, runId);\n }\n\n private untrackInSession(sessionId: string, runId: string): void {\n const session = this.sessions.get(sessionId);\n session?.jobs.delete(runId);\n session?.terminalAt.delete(runId);\n if (session?.jobs.size === 0) this.sessions.delete(sessionId);\n }\n\n private listInSession(sessionId: string): TrackedAsyncJob[] {\n return [...(this.sessions.get(sessionId)?.jobs.values() ?? [])];\n }\n\n private getInSession(sessionId: string, runId: string): TrackedAsyncJob | undefined {\n return this.sessions.get(sessionId)?.jobs.get(runId);\n }\n\n private resetSession(sessionId: string): void {\n this.sessions.delete(sessionId);\n }\n\n start(): void {\n this.stop();\n this.unregisterPoll = this.scheduler.register({\n id: POLL_SUBSCRIBER_ID,\n intervalMs: this.pollIntervalMs,\n run: () => this.run(),\n });\n }\n\n stop(): void {\n this.unregisterPoll?.();\n this.unregisterPoll = undefined;\n this.sessions.clear();\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../process/env.cjs`),n=require(`../../shared/lruCache.cjs`),r=require(`../atomicJson.cjs`);require(`../../shared/atomicJson.cjs`);const i=require(`../../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.cjs`),a=require(`../../shared/paths.cjs`),o=require(`../../shared/errors.cjs`),s=require(`../../shared/versioned.cjs`),c=require(`../../shared/boundedKeySet.cjs`);let l=require(`inversify`),u=require(`node:fs`);u=e.__toESM(u,1);let d=require(`node:path`);d=e.__toESM(d,1);let f=require(`node:crypto`);const p=`intercom`,m=`subagent.team.message`,h=`subagent.team.reply`,g=`members`,ee=`heartbeats`,_=`inboxes`,te=`replies`,ne=`receipts`,re=`team.json`,v=`.json`,y=`main`,b=`agent`,x=64*1024,S=4*1024,ie=[`members`,`send`,`ask`,`reply`,`pending`],ae=/^[A-Za-z0-9._-]{1,256}$/,oe=/[^a-z0-9._-]+/g,C=/^[-.]+|[-.]+$/g,se=`sha256`,w=`delivered`,ce=`failed`,le={oneOf:[...[`members`,`pending`].map(e=>({type:`object`,properties:{action:{const:e}},required:[`action`],additionalProperties:!1})),{type:`object`,properties:{action:{const:`send`},to:{type:`string`},message:{type:`string`}},required:[`action`,`to`,`message`],additionalProperties:!1},{type:`object`,properties:{action:{const:`ask`},to:{type:`string`},message:{type:`string`},timeoutMs:{type:`integer`,minimum:1}},required:[`action`,`to`,`message`],additionalProperties:!1},{type:`object`,properties:{action:{const:`reply`},requestId:{type:`string`},message:{type:`string`}},required:[`action`,`requestId`,`message`],additionalProperties:!1}]};function T(e){return typeof e==`string`&&ae.test(e)}function E(e){return typeof e==`number`&&Number.isInteger(e)}function D(e){return typeof e==`number`&&Number.isFinite(e)}function O(e){return typeof e==`string`&&e.trim().length>0}function k(e){return e===void 0||typeof e==`string`}function ue(e){return e===void 0||E(e)}function de(e){return e===`main`||e===`subagent`}function fe(e){return e===`send`||e===`ask`}function A(e,t){return Buffer.byteLength(e,`utf-8`)<=t}function pe(e){return e instanceof Error?e.message:String(e)}function j(e){return process.env[e]?.trim()||void 0}function M(e){return(0,f.createHash)(se).update(e).digest(`hex`)}function me(){return(0,f.randomBytes)(32).toString(`base64url`)}function he(e){return`session-${M(e).slice(0,32)}`}function N(e){return e.trim().toLowerCase().replace(oe,`-`).replace(C,``).slice(0,48).replace(C,``)||b}function ge(e,t){let n=`-${t+1}`,r=48-n.length;return`${e.slice(0,Math.max(r,0)).replace(C,``)||b}${n}`}function _e(e,t){if(e!==y)return e;if(t)throw Error(`Native team member name '${y}' is reserved for the root session.`);return`main-agent`}function P(e){if(!T(e))throw Error(`Invalid native team id.`);return d.join(a.scopeTeamDir(a.requireCurrentSessionScope()),e)}function F(e,t){if(!T(t))throw Error(`Invalid native team member id.`);return d.join(P(e.teamId),g,`${t}${v}`)}function I(e,t){if(!T(t))throw Error(`Invalid native team member id.`);return d.join(P(e.teamId),ee,`${t}${v}`)}function L(e,t){if(!T(t))throw Error(`Invalid native team member id.`);return d.join(P(e.teamId),_,t)}function R(e){return`${e}${v}`}function z(e,t,n){if(!T(n))throw Error(`Invalid native team message id.`);return d.join(L(e,t),R(n))}function ve(e,t){if(!T(t))throw Error(`Invalid native team request id.`);return d.join(P(e.teamId),te,`${t}${v}`)}function B(e,t,n){if(!T(t)||!T(n))throw Error(`Invalid intercom receipt identity.`);return d.join(P(e.teamId),ne,t,`${n}${v}`)}function ye(e,t){return(0,f.createHash)(se).update(`${e}:${t}`).digest(`hex`)}function be(e){let t=P(e.teamId);for(let e of[g,ee,_,te,ne])u.mkdirSync(d.join(t,e),{recursive:!0,mode:448})}function V(e){try{let t=JSON.parse(u.readFileSync(e,`utf-8`));return t&&typeof t==`object`&&!Array.isArray(t)?t:void 0}catch{return}}function H(e){try{return u.rmSync(e,{force:!0}),!0}catch(e){return e.code===`ENOENT`}}function xe(e){try{return u.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}function Se(e){if(!(!s.parseVersioned(e,[1]).ok||!e)&&!(!T(e.teamId)||!O(e.rootSessionId)||e.mainMemberId!==y||!D(e.createdAt)||!D(e.updatedAt)))return{version:1,teamId:e.teamId,rootSessionId:e.rootSessionId,mainMemberId:y,createdAt:e.createdAt,updatedAt:e.updatedAt}}function Ce(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(!(!O(t.id)||!O(t.subject))&&!(!A(t.id,256)||!A(t.subject,S)))return{id:t.id,subject:t.subject}}function we(e){if(!s.parseVersioned(e,[1]).ok||!e||!T(e.teamId)||!O(e.rootSessionId)||!O(e.mainMemberId)||!T(e.memberId)||!de(e.role)||!O(e.tokenHash)||!E(e.pid)||typeof e.active!=`boolean`||!D(e.joinedAt)||!k(e.agent)||!k(e.runId)||!ue(e.childIndex)||!k(e.parentMemberId))return;let t=e.task===void 0?void 0:Ce(e.task);if(!(e.task!==void 0&&!t))return{version:1,teamId:e.teamId,rootSessionId:e.rootSessionId,mainMemberId:e.mainMemberId,memberId:e.memberId,role:e.role,tokenHash:e.tokenHash,pid:e.pid,active:e.active,joinedAt:e.joinedAt,...D(e.leftAt)?{leftAt:e.leftAt}:{},...e.agent===void 0?{}:{agent:e.agent},...e.runId===void 0?{}:{runId:e.runId},...e.childIndex===void 0?{}:{childIndex:e.childIndex},...e.parentMemberId===void 0?{}:{parentMemberId:e.parentMemberId},...t?{task:t}:{}}}function Te(e){if(!(!s.parseVersioned(e,[1]).ok||!e)&&!(!T(e.memberId)||!O(e.tokenHash)||!E(e.pid)||!D(e.heartbeatAt)))return{version:1,memberId:e.memberId,tokenHash:e.tokenHash,pid:e.pid,heartbeatAt:e.heartbeatAt}}function Ee(e){if(!(!s.parseVersioned(e,[2]).ok||!e)&&!(e.type!==m||!T(e.id)||!T(e.teamId)||!fe(e.kind)||!T(e.fromMemberId)||!T(e.toMemberId)||!O(e.senderTokenHash)||!E(e.seq)||typeof e.message!=`string`||!A(e.message,x)||!D(e.createdAt)||!D(e.expiresAt)))return{type:m,version:2,id:e.id,teamId:e.teamId,kind:e.kind,fromMemberId:e.fromMemberId,toMemberId:e.toMemberId,senderTokenHash:e.senderTokenHash,seq:e.seq,message:e.message,createdAt:e.createdAt,expiresAt:e.expiresAt}}function De(e){if(!(!s.parseVersioned(e,[2]).ok||!e)&&!(e.type!==h||!T(e.requestId)||!T(e.teamId)||!T(e.fromMemberId)||!T(e.toMemberId)||!O(e.senderTokenHash)||typeof e.message!=`string`||!A(e.message,x)||!D(e.createdAt)))return{type:h,version:2,requestId:e.requestId,teamId:e.teamId,fromMemberId:e.fromMemberId,toMemberId:e.toMemberId,senderTokenHash:e.senderTokenHash,message:e.message,createdAt:e.createdAt}}function Oe(e){if(!e||typeof e!=`object`||Array.isArray(e))throw o.invalidRequest(`Intercom params must be an object.`,`Use one documented intercom action shape.`);let t=e,n=ie.find(e=>e===t.action);if(!n)throw new o.DoomTeamExpectedError(`unsupported_operation`,`Unsupported intercom action: ${String(t.action)}.`,!1,`Use members, send, ask, pending, or reply.`);if(!k(t.to)||!k(t.message)||!k(t.requestId))throw o.invalidRequest(`Intercom to, message and requestId values must be strings.`,`Correct the action fields and retry.`);if(t.timeoutMs!==void 0&&(!E(t.timeoutMs)||t.timeoutMs<1))throw o.invalidRequest(`Intercom timeoutMs must be a positive integer.`,`Correct timeoutMs and retry.`);let r=new Set(n===`members`||n===`pending`?[`action`]:n===`reply`?[`action`,`requestId`,`message`]:n===`ask`?[`action`,`to`,`message`,`timeoutMs`]:[`action`,`to`,`message`]),i=Object.keys(t).filter(e=>!r.has(e));if(i.length)throw o.invalidRequest(`Intercom action '${n}' does not accept: ${i.join(`, `)}.`,`Remove unknown fields and retry.`);return{action:n,...t.to===void 0?{}:{to:t.to},...t.message===void 0?{}:{message:t.message},...t.requestId===void 0?{}:{requestId:t.requestId},...t.timeoutMs===void 0?{}:{timeoutMs:t.timeoutMs}}}function U(e,t){return we(V(F(e,t)))}function ke(e,t){let n=Te(V(I(e,t.memberId)));if(!(!n||n.memberId!==t.memberId||n.tokenHash!==t.tokenHash))return n}function Ae(e){if(e===process.pid)return!0;try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}function je(e,t){return ke(e,t)?.heartbeatAt??t.leftAt??t.joinedAt}function W(e,t,n){return t.active&&Ae(t.pid)&&n-je(e,t)<=3e4}function Me(e){u.mkdirSync(L(e,e.memberId),{recursive:!0,mode:448}),r.writePrivateAtomicJson(F(e,e.memberId),e)}function G(e,t,n){let i={version:1,memberId:t.memberId,tokenHash:t.tokenHash,pid:t.pid,heartbeatAt:n};r.writePrivateAtomicJson(I(e,t.memberId),i)}function K(e){let t=d.join(P(e.teamId),g),n;try{n=u.readdirSync(t,{withFileTypes:!0})}catch{return[]}return n.filter(e=>e.isFile()&&e.name.endsWith(v)).map(e=>we(V(d.join(t,e.name)))).filter(e=>!!e).filter(t=>t.teamId===e.teamId&&t.rootSessionId===e.rootSessionId)}function q(e,t){return K(e).filter(n=>W(e,n,t)).sort((e,t)=>e.joinedAt-t.joinedAt||e.memberId.localeCompare(t.memberId))}function Ne(e=Date.now()){let t=Y();if(t)return{members:q(t,e).map(Je)}}function Pe(e,t,n){let r=0;for(let i of K(e))i.memberId!==t&&(W(e,i,n)||n-je(e,i)<=33e4||(xe(L(e,i.memberId)),H(I(e,i.memberId)),H(F(e,i.memberId)),r+=1));return r}function Fe(e){let t=e.trim();if(!t)throw Error(`A root session id is required for native team communication.`);let n={version:1,teamId:he(t),rootSessionId:t,mainMemberId:y};be(n);let i=d.join(P(n.teamId),re),a=Se(V(i));if(a&&a.rootSessionId!==t)throw Error(`Native team identity collision detected.`);let o=Date.now();return r.writePrivateAtomicJson(i,{...n,createdAt:a?.createdAt??o,updatedAt:o}),n}function J(e){return{[t.SUBAGENT_TEAM_ID_ENV]:e.teamId,[t.SUBAGENT_TEAM_ROOT_SESSION_ENV]:e.rootSessionId,[t.SUBAGENT_TEAM_MAIN_MEMBER_ENV]:e.mainMemberId}}function Ie(e){return{...J(e),[t.SUBAGENT_TEAM_MEMBER_ID_ENV]:e.memberId,[t.SUBAGENT_TEAM_MEMBER_TOKEN_ENV]:e.token}}function Le(){return{[t.SUBAGENT_TEAM_MEMBER_ID_ENV]:void 0,[t.SUBAGENT_TEAM_MEMBER_TOKEN_ENV]:void 0}}function Re(e){Object.assign(process.env,J(e))}function ze(e){e&&process.env.PI_SUBAGENT_TEAM_ID!==e.teamId||(delete process.env[t.SUBAGENT_TEAM_ID_ENV],delete process.env[t.SUBAGENT_TEAM_ROOT_SESSION_ENV],delete process.env[t.SUBAGENT_TEAM_MAIN_MEMBER_ENV])}function Y(){let e=j(t.SUBAGENT_TEAM_ID_ENV),n=j(t.SUBAGENT_TEAM_ROOT_SESSION_ENV),r=j(t.SUBAGENT_TEAM_MAIN_MEMBER_ENV);if(!e||!T(e)||!n||r!==y||e!==he(n))return;let i=Se(V(d.join(P(e),re)));if(!(!i||i.rootSessionId!==n||i.teamId!==e))return{version:1,teamId:e,rootSessionId:n,mainMemberId:r}}function Be(e){if(!e)return;let t=e.id.trim(),n=e.subject.trim();if(!t||!A(t,256))throw Error(`Native team task id must be between 1 and 256 bytes.`);if(!n||!A(n,S))throw Error(`Native team task subject must be between 1 and ${S} bytes.`);return{id:t,subject:n}}function Ve(e){if(e.role===`main`)return e.root.mainMemberId;let t=e.name!==void 0;if(!t&&!e.agent)throw Error(`An intercom member needs a name or an agent to derive one from.`);let n=_e(N(e.name??e.agent??b),t);if(e.runId){let t=N(e.runId).slice(0,8),r=48-t.length-1;return`${n.slice(0,r).replace(C,``)||b}-${t}`}return e.fanoutIndex===void 0?n:ge(n,e.fanoutIndex)}function He(e){let t=Ve(e);if(!T(t))throw Error(`A safe native team member id is required.`);let n=me(),r=M(n),i=Date.now(),a=Be(e.task),o={...e.root,memberId:t,token:n,role:e.role,...e.agent?{agent:e.agent}:{},...e.runId?{runId:e.runId}:{},...e.childIndex===void 0?{}:{childIndex:e.childIndex},...e.parentMemberId?{parentMemberId:e.parentMemberId}:{},...a?{task:a}:{}},s=U(e.root,t);s&&s.tokenHash!==r&&xe(L(e.root,t));let{token:c,version:l,...u}=o,d={...u,version:1,tokenHash:r,pid:e.pid??process.pid,active:!0,joinedAt:i};Me(d),G(e.root,d,i);let f=!1;return{context:o,dispose:()=>{if(f)return;f=!0;let n=U(e.root,t);if(!n||n.tokenHash!==r)return;let i=Date.now();Me({...n,active:!1,leftAt:i}),G(e.root,n,i)}}}function X(){let e=Y(),n=j(t.SUBAGENT_TEAM_MEMBER_ID_ENV),r=j(t.SUBAGENT_TEAM_MEMBER_TOKEN_ENV);if(!e||!n||!T(n)||!r)return;let i=U(e,n);if(!(!i||i.teamId!==e.teamId||i.rootSessionId!==e.rootSessionId)&&!(i.tokenHash!==M(r)||!i.active))return{...e,memberId:n,token:r,role:i.role,...i.agent?{agent:i.agent}:{},...i.runId?{runId:i.runId}:{},...i.childIndex===void 0?{}:{childIndex:i.childIndex},...i.parentMemberId?{parentMemberId:i.parentMemberId}:{},...i.task?{task:i.task}:{}}}function Z(e,t){let n=U(e,e.memberId);if(!n||n.tokenHash!==M(e.token)||!W(e,n,t))throw Error(`This native team member is no longer active.`);return n}function Ue(e,t,n){let r=t?.trim();if(!r)throw o.invalidRequest(`to is required for intercom send and ask.`,`Provide an explicit recipient.`);let i=q(e,n).filter(t=>t.memberId!==e.memberId),a=N(r),s=i.find(e=>e.memberId===r||e.memberId===a);if(s)return s;let c=r.toLowerCase(),l=i.filter(e=>e.agent?.toLowerCase()===c||e.runId?.toLowerCase()===c||c===y&&e.role===`main`);if(l.length===1)return l[0];throw l.length>1?new o.DoomTeamExpectedError(`recipient_ambiguous`,`Multiple active intercom members match '${r}': ${l.map(e=>e.memberId).join(`, `)}.`,!1,`Retry with one exact member id.`):new o.DoomTeamExpectedError(`recipient_not_found`,`Active intercom member '${r}' was not found.`,!0,`Call intercom({"action":"members"}) and retry with an active member id.`)}function We(e){let t=e?.trim();if(!t)throw o.invalidRequest(`message is required for intercom communication.`,`Provide a nonblank message.`);if(!A(t,x))throw o.invalidRequest(`Intercom message exceeds 64 KiB.`,`Shorten the message and retry.`);return t}function Q(e,t,n){let r=U(e,t);return!!(r&&r.tokenHash===n)}function Ge(e,t,n){let r=L(e,e.memberId),i;try{i=u.readdirSync(r,{withFileTypes:!0})}catch{return{messages:[],foreignFiles:[]}}let a=[],o=[];for(let s of i){if(!s.isFile()||!s.name.endsWith(v)||n?.(s.name))continue;let i=d.join(r,s.name),c=Ee(V(i));if(!c){H(i);continue}if(c.teamId!==e.teamId||c.toMemberId!==e.memberId){o.push(s.name);continue}if(c.expiresAt<t||!Q(e,c.fromMemberId,c.senderTokenHash)){H(i);continue}a.push(c)}return{messages:Ke(a),foreignFiles:o}}function Ke(e){let t=new Map;for(let n of e){let e=t.get(n.fromMemberId);e?e.push(n):t.set(n.fromMemberId,[n])}let n=[];for(let e of t.values())e.sort((e,t)=>e.seq-t.seq),n.push(e);let r=[];for(;;){let e,t;for(let r of n){let n=r[0];n&&(!t||n.createdAt<t.createdAt||n.createdAt===t.createdAt&&n.fromMemberId<t.fromMemberId)&&(e=r,t=n)}if(!e||!t)break;e.shift(),r.push(t)}return r}function qe(e){let t=e.role===`main`?y:e.agent??e.memberId,n=e.runId?` [${e.runId}]`:``,r=e.task?`, task ${e.task.id}: ${e.task.subject}`:``;return`- ${e.memberId}: ${t}${n}${r}`}function Je(e){return{name:e.memberId,role:e.role,...e.agent?{agent:e.agent}:{},...e.runId?{runId:e.runId}:{},...e.task?{task:e.task}:{}}}function Ye(e,t){return new Promise((n,r)=>{if(t?.aborted){r(Error(`Native team request cancelled.`));return}let i,a=()=>{i&&clearTimeout(i),t?.removeEventListener(`abort`,o)},o=()=>{a(),r(Error(`Native team request cancelled.`))};i=setTimeout(()=>{a(),n()},e),t?.addEventListener(`abort`,o,{once:!0})})}function Xe(e,t){let n=U(e,t.fromMemberId),r=`${t.fromMemberId}${n?.agent?` (${n.agent})`:``}`,i=n?.task?`, task ${n.task.id}`:``,a=[`${t.kind===`ask`?`Question`:`Message`} from ${r}${i}.`];return a.push(``,t.message),t.kind===`ask`&&a.push(``,`Reply with ${p}({ action: "reply", requestId: "${t.id}", message: "..." }).`),a.join(`
2
- `)}function Ze(e,t){try{return e.getAllTools().some(e=>e.name===t)}catch{return!1}}var Qe=class{context;ownedMembershipDispose;poller;lastHeartbeatAt=0;lastGcAt=0;seenFiles=new c.BoundedKeySet(1024);deliveryAttempts=new n.LruCache(256);undeliverableMessages=[];outboundSeq=0;constructor(e,t){if(this.pi=e,this.options=t,Ze(e,`intercom`))throw Error(`[tool_conflict] A foreign '${p}' tool is already registered. Recovery: disable the competing extension and reload Doom Team.`);e.registerTool(this.buildTool())}current(){return this.context}undeliverable(){return this.undeliverableMessages}bindMainSession(e){let t=Fe(e);Re(t);let n=He({root:t,role:`main`});return this.startBinding(n.context,n.dispose)}bindChildFromEnvironment(){let e=X();if(e)return this.context?.memberId===e.memberId&&this.context.token===e.token?this.context:this.startBinding(e)}dispose(){let e=this.context;this.stopBinding(),e?.role===`main`&&ze(e)}startBinding(e,t){return this.stopBinding(),this.context=e,this.ownedMembershipDispose=t,this.poll(),this.poller=setInterval(()=>{this.poll()},this.options.pollIntervalMs),this.poller.unref?.(),e}stopBinding(){this.poller&&clearInterval(this.poller),this.poller=void 0,this.ownedMembershipDispose?.(),this.ownedMembershipDispose=void 0,this.seenFiles.clear(),this.deliveryAttempts.clear(),this.lastHeartbeatAt=0,this.lastGcAt=0,this.outboundSeq=0,this.context=void 0}poll(){let e=this.context;if(!e)return;let t=this.options.now();this.heartbeat(e,t),this.collectGarbageIfDue(e,t);let n=Ge(e,t,e=>this.seenFiles.has(e));for(let e of n.foreignFiles)this.seenFiles.add(e);for(let t of n.messages)this.deliverOnce(e,t)}deliverOnce(e,t){let n=R(t.id);try{this.deliver(e,t)}catch(r){let i=(this.deliveryAttempts.get(n)??0)+1;if(i<this.options.maxDeliveryAttempts){this.deliveryAttempts.set(n,i);return}this.deliveryAttempts.delete(n),this.seenFiles.add(n),this.reportUndeliverable(e,t,i,r);return}this.seenFiles.add(n),this.deliveryAttempts.delete(n),r.writePrivateAtomicJson(B(e,t.fromMemberId,t.id),{version:1,messageId:t.id,state:w,deliveredAt:this.options.now()}),t.kind===`send`&&H(z(e,e.memberId,t.id))}deliver(e,t){let n=Xe(e,t);if(e.role===`subagent`){this.pi.sendUserMessage(n,{deliverAs:`steer`});return}this.pi.sendMessage({customType:`intercom_message`,content:n,display:!0,details:{id:t.id,kind:t.kind,from:t.fromMemberId,to:t.toMemberId,seq:t.seq}},{triggerTurn:!0,deliverAs:`steer`})}reportUndeliverable(e,t,n,i){let a={messageId:t.id,fromMemberId:t.fromMemberId,kind:t.kind,attempts:n,reason:pe(i),at:this.options.now()};for(this.undeliverableMessages.push(a),r.writePrivateAtomicJson(B(e,t.fromMemberId,t.id),{version:1,messageId:t.id,state:ce,reason:a.reason,failedAt:a.at});this.undeliverableMessages.length>32;)this.undeliverableMessages.shift();try{return this.pi.sendMessage({customType:`intercom_undeliverable`,content:`Native team message ${t.id} from ${t.fromMemberId} could not be delivered after ${n} attempts: ${a.reason}`,display:!0,details:{...a}},{triggerTurn:!0,deliverAs:`steer`}),!0}catch{return!1}}heartbeat(e,t){if(t-this.lastHeartbeatAt<this.options.heartbeatIntervalMs)return;let n=U(e,e.memberId);!n||n.tokenHash!==M(e.token)||!n.active||(this.lastHeartbeatAt=t,G(e,n,t))}collectGarbageIfDue(e,t){if(!(t-this.lastGcAt<this.options.gcIntervalMs)){this.lastGcAt=t;try{Pe(e,e.memberId,t)}catch(n){for(this.undeliverableMessages.push({messageId:``,fromMemberId:e.memberId,kind:`send`,attempts:0,reason:`Native team directory sweep failed: ${pe(n)}`,at:t});this.undeliverableMessages.length>32;)this.undeliverableMessages.shift()}}}nextSeq(){return this.outboundSeq+=1,this.outboundSeq}queueMessage(e,t,n,i,a,o){if(Z(e,a),!W(e,t,a))throw Error(`Native team member '${t.memberId}' is no longer active.`);let s={type:m,version:2,id:o,teamId:e.teamId,kind:n,fromMemberId:e.memberId,toMemberId:t.memberId,senderTokenHash:M(e.token),seq:this.nextSeq(),message:i,createdAt:a,expiresAt:a+864e5};return u.mkdirSync(L(e,t.memberId),{recursive:!0,mode:448}),r.writePrivateAtomicJson(z(e,t.memberId,s.id),s),s}replyToRequest(e,t,n,i){if(!t||!T(t))throw Error(`requestId must be a valid intercom request id.`);Z(e,i);let a=z(e,e.memberId,t),s=Ee(V(a));if(!s||s.kind!==`ask`||s.teamId!==e.teamId||s.toMemberId!==e.memberId||!Q(e,s.fromMemberId,s.senderTokenHash))throw new o.DoomTeamExpectedError(`recipient_not_found`,`No pending intercom ask matches requestId '${t}'.`,!1,`Call intercom({"action":"pending"}) and retry with an exact requestId.`);let c={type:h,version:2,requestId:t,teamId:e.teamId,fromMemberId:e.memberId,toMemberId:s.fromMemberId,senderTokenHash:M(e.token),message:n,createdAt:i};return r.writePrivateAtomicJson(ve(e,t),c),H(a),this.seenFiles.delete(R(t)),c}async waitForReply(e,t,n,r,i){let a=ve(e,n.id),s=this.options.now()+(i??this.options.askTimeoutMs);for(;this.options.now()<=s;){if(r?.aborted)throw Error(`Native team request cancelled.`);let i=De(V(a));if(i&&i.teamId===e.teamId&&i.requestId===n.id&&i.fromMemberId===t.memberId&&i.toMemberId===e.memberId&&Q(e,i.fromMemberId,i.senderTokenHash))return H(a),i;let s=U(e,t.memberId);if(!s||!W(e,s,this.options.now()))throw new o.DoomTeamExpectedError(`communication_unavailable`,`Intercom member '${t.memberId}' became unreachable before replying.`,!0,`Call intercom({"action":"members"}) and decide whether to retry with an active member.`);await Ye(this.options.replyPollIntervalMs,r)}throw new o.DoomTeamExpectedError(`reply_timeout`,`Timed out waiting for intercom member '${t.memberId}' to reply.`,!0,`Check member status before deciding whether to ask again.`)}buildTool(){return{name:p,label:`Intercom`,description:`Communicate with active agents in this root session. Use members, send, ask, pending, or reply. The stable root identity is main.`,promptGuidelines:[`Send only new progress, blockers, or decisions. Do not repeat the task brief, sender task, or delegation instructions because the recipient already has them.`],parameters:le,execute:async(e,t,n,r)=>{let i=this.context;if(!i)throw new o.DoomTeamExpectedError(`communication_unavailable`,`Intercom is not active for this session.`,!0,`Wait for session startup or reload Doom Team.`);let a=Oe(t),s=this.options.now();if(Z(i,s),a.action===`members`){let e=q(i,s);return{content:[{type:`text`,text:e.length?e.map(qe).join(`
3
- `):`No active members.`}],details:{members:e.map(Je)}}}if(a.action===`pending`){let e=Ge(i,s).messages.filter(e=>e.kind===`ask`),t=e.map(e=>`- ${e.id}: from ${e.fromMemberId}. Reply with ${p}({ action: "reply", requestId: "${e.id}", message: "..." }).`);return{content:[{type:`text`,text:t.length?t.join(`
4
- `):`No pending native team asks.`}],details:{pending:e.map(e=>({id:e.id,from:e.fromMemberId,message:e.message}))}}}let c=We(a.message);if(a.action===`reply`){let e=this.replyToRequest(i,a.requestId,c,s);return{content:[{type:`text`,text:`Replied to native team request ${e.requestId}.`}],details:{requestId:e.requestId,to:e.toMemberId}}}let l=Ue(i,a.to,s);a.action===`ask`&&r?.({content:[{type:`text`,text:`Waiting for ${l.memberId} to reply...`}],details:{action:`ask`,to:l.memberId,partial:!0}});let u=ye(i.memberId,e),d=V(B(i,i.memberId,u));if(d?.state===ce)throw new o.DoomTeamExpectedError(`delivery_unconfirmed`,`Intercom message ${u} failed: ${typeof d.reason==`string`?d.reason:`unknown error`}`,!1,`Call intercom({"action":"members"}) and do not resend automatically.`);if(a.action===`send`&&d?.state===w)return{content:[{type:`text`,text:`Message ${u} delivered to ${l.memberId}.`}],details:{state:w,delivered:!0,messageId:u,to:l.memberId}};let f=this.queueMessage(i,l,a.action,c,s,u);if(a.action===`send`)return{content:[{type:`text`,text:`Message ${f.id} queued for ${l.memberId}; delivery is not yet confirmed. Do not resend.`}],details:{state:`queued`,delivered:!1,messageId:f.id,to:l.memberId,seq:f.seq}};try{let e=await this.waitForReply(i,l,f,n,a.timeoutMs);return{content:[{type:`text`,text:`Reply from ${l.memberId}:\n${e.message}`}],details:{requestId:f.id,from:l.memberId,reply:e.message}}}finally{H(z(i,l.memberId,f.id))}}}}};let $=class{runtimes=new WeakMap;pollIntervalMs=250;replyPollIntervalMs=250;heartbeatIntervalMs=5e3;gcIntervalMs=6e4;askTimeoutMs=6e5;maxDeliveryAttempts=5;now(){return Date.now()}createRuntime(e){let t=this.runtimes.get(e);if(t)return t;let n=new Qe(e,{pollIntervalMs:this.pollIntervalMs,replyPollIntervalMs:this.replyPollIntervalMs,heartbeatIntervalMs:this.heartbeatIntervalMs,gcIntervalMs:this.gcIntervalMs,askTimeoutMs:this.askTimeoutMs,maxDeliveryAttempts:this.maxDeliveryAttempts,now:()=>this.now()});return this.runtimes.set(e,n),e.on(`session_shutdown`,()=>{this.runtimes.get(e)?.dispose()}),n}registerClient(e){a.tryCurrentSessionScope()&&X()&&this.createRuntime(e).bindChildFromEnvironment()}};$=i.__decorate([(0,l.injectable)()],$),exports.HEARTBEAT_STALE_MS=3e4,exports.NATIVE_TEAM_TOOL_NAME=p,Object.defineProperty(exports,`NativeTeamChannelService`,{enumerable:!0,get:function(){return $}}),exports.applyNativeTeamRootEnvironment=Re,exports.clearNativeTeamMemberEnvironment=Le,exports.clearNativeTeamRootEnvironment=ze,exports.ensureNativeTeamRoot=Fe,exports.listMemberRecords=K,exports.nativeTeamMemberEnvironment=Ie,exports.nativeTeamRootEnvironment=J,exports.normalizeTeamMemberName=N,exports.processAlive=Ae,exports.readActiveNativeTeamSnapshot=Ne,exports.readHeartbeat=ke,exports.readMember=U,exports.readNativeTeamMemberFromEnvironment=X,exports.readNativeTeamRootFromEnvironment=Y,exports.registerNativeTeamMember=He,exports.teamDir=P;
1
+ const e=require(`../../../_virtual/_rolldown/runtime.cjs`),t=require(`../process/env.cjs`),n=require(`../../shared/lruCache.cjs`),r=require(`../atomicJson.cjs`);require(`../../shared/atomicJson.cjs`);const i=require(`../../shared/boundedKeySet.cjs`),a=require(`../../shared/errors.cjs`),o=require(`../../shared/paths.cjs`),s=require(`../../shared/versioned.cjs`);let c=require(`node:fs`);c=e.__toESM(c,1);let l=require(`node:path`);l=e.__toESM(l,1);let u=require(`node:crypto`);const d=`intercom`,f=`subagent.team.message`,p=`subagent.team.reply`,m=`members`,ee=`heartbeats`,h=`inboxes`,g=`replies`,te=`receipts`,ne=`team.json`,_=`.json`,v=`main`,y=`agent`,b=64*1024,x=4*1024,re=[`members`,`send`,`ask`,`reply`,`pending`],ie=/^[A-Za-z0-9._-]{1,256}$/,ae=/[^a-z0-9._-]+/g,S=/^[-.]+|[-.]+$/g,oe=`sha256`,C=`delivered`,se=`failed`,ce={oneOf:[...[`members`,`pending`].map(e=>({type:`object`,properties:{action:{const:e}},required:[`action`],additionalProperties:!1})),{type:`object`,properties:{action:{const:`send`},to:{type:`string`},message:{type:`string`}},required:[`action`,`to`,`message`],additionalProperties:!1},{type:`object`,properties:{action:{const:`ask`},to:{type:`string`},message:{type:`string`},timeoutMs:{type:`integer`,minimum:1}},required:[`action`,`to`,`message`],additionalProperties:!1},{type:`object`,properties:{action:{const:`reply`},requestId:{type:`string`},message:{type:`string`}},required:[`action`,`requestId`,`message`],additionalProperties:!1}]};function w(e){return typeof e==`string`&&ie.test(e)}function T(e){return typeof e==`number`&&Number.isInteger(e)}function E(e){return typeof e==`number`&&Number.isFinite(e)}function D(e){return typeof e==`string`&&e.trim().length>0}function O(e){return e===void 0||typeof e==`string`}function le(e){return e===void 0||T(e)}function ue(e){return e===`main`||e===`subagent`}function de(e){return e===`send`||e===`ask`}function k(e,t){return Buffer.byteLength(e,`utf-8`)<=t}function fe(e){return e instanceof Error?e.message:String(e)}function A(e){return process.env[e]?.trim()||void 0}function j(e){return(0,u.createHash)(oe).update(e).digest(`hex`)}function pe(){return(0,u.randomBytes)(32).toString(`base64url`)}function me(e){return`session-${j(e).slice(0,32)}`}function M(e){return e.trim().toLowerCase().replace(ae,`-`).replace(S,``).slice(0,48).replace(S,``)||y}function he(e,t){let n=`-${t+1}`,r=48-n.length;return`${e.slice(0,Math.max(r,0)).replace(S,``)||y}${n}`}function ge(e,t){if(e!==v)return e;if(t)throw Error(`Native team member name '${v}' is reserved for the root session.`);return`main-agent`}function N(e){if(!w(e))throw Error(`Invalid native team id.`);return l.join(o.scopeTeamDir(o.requireCurrentSessionScope()),e)}function P(e,t){if(!w(t))throw Error(`Invalid native team member id.`);return l.join(N(e.teamId),m,`${t}${_}`)}function F(e,t){if(!w(t))throw Error(`Invalid native team member id.`);return l.join(N(e.teamId),ee,`${t}${_}`)}function I(e,t){if(!w(t))throw Error(`Invalid native team member id.`);return l.join(N(e.teamId),h,t)}function L(e){return`${e}${_}`}function R(e,t,n){if(!w(n))throw Error(`Invalid native team message id.`);return l.join(I(e,t),L(n))}function _e(e,t){if(!w(t))throw Error(`Invalid native team request id.`);return l.join(N(e.teamId),g,`${t}${_}`)}function z(e,t,n){if(!w(t)||!w(n))throw Error(`Invalid intercom receipt identity.`);return l.join(N(e.teamId),te,t,`${n}${_}`)}function ve(e,t){return(0,u.createHash)(oe).update(`${e}:${t}`).digest(`hex`)}function ye(e){let t=N(e.teamId);for(let e of[m,ee,h,g,te])c.mkdirSync(l.join(t,e),{recursive:!0,mode:448})}function B(e){try{let t=JSON.parse(c.readFileSync(e,`utf-8`));return t&&typeof t==`object`&&!Array.isArray(t)?t:void 0}catch{return}}function V(e){try{return c.rmSync(e,{force:!0}),!0}catch(e){return e.code===`ENOENT`}}function be(e){try{return c.rmSync(e,{recursive:!0,force:!0}),!0}catch{return!1}}function xe(e){if(!(!s.parseVersioned(e,[1]).ok||!e)&&!(!w(e.teamId)||!D(e.rootSessionId)||e.mainMemberId!==v||!E(e.createdAt)||!E(e.updatedAt)))return{version:1,teamId:e.teamId,rootSessionId:e.rootSessionId,mainMemberId:v,createdAt:e.createdAt,updatedAt:e.updatedAt}}function Se(e){if(!e||typeof e!=`object`||Array.isArray(e))return;let t=e;if(!(!D(t.id)||!D(t.subject))&&!(!k(t.id,256)||!k(t.subject,x)))return{id:t.id,subject:t.subject}}function Ce(e){if(!s.parseVersioned(e,[1]).ok||!e||!w(e.teamId)||!D(e.rootSessionId)||!D(e.mainMemberId)||!w(e.memberId)||!ue(e.role)||!D(e.tokenHash)||!T(e.pid)||typeof e.active!=`boolean`||!E(e.joinedAt)||!O(e.agent)||!O(e.runId)||!le(e.childIndex)||!O(e.parentMemberId))return;let t=e.task===void 0?void 0:Se(e.task);if(!(e.task!==void 0&&!t))return{version:1,teamId:e.teamId,rootSessionId:e.rootSessionId,mainMemberId:e.mainMemberId,memberId:e.memberId,role:e.role,tokenHash:e.tokenHash,pid:e.pid,active:e.active,joinedAt:e.joinedAt,...E(e.leftAt)?{leftAt:e.leftAt}:{},...e.agent===void 0?{}:{agent:e.agent},...e.runId===void 0?{}:{runId:e.runId},...e.childIndex===void 0?{}:{childIndex:e.childIndex},...e.parentMemberId===void 0?{}:{parentMemberId:e.parentMemberId},...t?{task:t}:{}}}function we(e){if(!(!s.parseVersioned(e,[1]).ok||!e)&&!(!w(e.memberId)||!D(e.tokenHash)||!T(e.pid)||!E(e.heartbeatAt)))return{version:1,memberId:e.memberId,tokenHash:e.tokenHash,pid:e.pid,heartbeatAt:e.heartbeatAt}}function Te(e){if(!(!s.parseVersioned(e,[2]).ok||!e)&&!(e.type!==f||!w(e.id)||!w(e.teamId)||!de(e.kind)||!w(e.fromMemberId)||!w(e.toMemberId)||!D(e.senderTokenHash)||!T(e.seq)||typeof e.message!=`string`||!k(e.message,b)||!E(e.createdAt)||!E(e.expiresAt)))return{type:f,version:2,id:e.id,teamId:e.teamId,kind:e.kind,fromMemberId:e.fromMemberId,toMemberId:e.toMemberId,senderTokenHash:e.senderTokenHash,seq:e.seq,message:e.message,createdAt:e.createdAt,expiresAt:e.expiresAt}}function Ee(e){if(!(!s.parseVersioned(e,[2]).ok||!e)&&!(e.type!==p||!w(e.requestId)||!w(e.teamId)||!w(e.fromMemberId)||!w(e.toMemberId)||!D(e.senderTokenHash)||typeof e.message!=`string`||!k(e.message,b)||!E(e.createdAt)))return{type:p,version:2,requestId:e.requestId,teamId:e.teamId,fromMemberId:e.fromMemberId,toMemberId:e.toMemberId,senderTokenHash:e.senderTokenHash,message:e.message,createdAt:e.createdAt}}function De(e){if(!e||typeof e!=`object`||Array.isArray(e))throw a.invalidRequest(`Intercom params must be an object.`,`Use one documented intercom action shape.`);let t=e,n=re.find(e=>e===t.action);if(!n)throw new a.DoomTeamExpectedError(`unsupported_operation`,`Unsupported intercom action: ${String(t.action)}.`,!1,`Use members, send, ask, pending, or reply.`);if(!O(t.to)||!O(t.message)||!O(t.requestId))throw a.invalidRequest(`Intercom to, message and requestId values must be strings.`,`Correct the action fields and retry.`);if(t.timeoutMs!==void 0&&(!T(t.timeoutMs)||t.timeoutMs<1))throw a.invalidRequest(`Intercom timeoutMs must be a positive integer.`,`Correct timeoutMs and retry.`);let r=new Set(n===`members`||n===`pending`?[`action`]:n===`reply`?[`action`,`requestId`,`message`]:n===`ask`?[`action`,`to`,`message`,`timeoutMs`]:[`action`,`to`,`message`]),i=Object.keys(t).filter(e=>!r.has(e));if(i.length)throw a.invalidRequest(`Intercom action '${n}' does not accept: ${i.join(`, `)}.`,`Remove unknown fields and retry.`);return{action:n,...t.to===void 0?{}:{to:t.to},...t.message===void 0?{}:{message:t.message},...t.requestId===void 0?{}:{requestId:t.requestId},...t.timeoutMs===void 0?{}:{timeoutMs:t.timeoutMs}}}function H(e,t){return Ce(B(P(e,t)))}function U(e,t){let n=we(B(F(e,t.memberId)));if(!(!n||n.memberId!==t.memberId||n.tokenHash!==t.tokenHash))return n}function Oe(e){if(e===process.pid)return!0;try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}function ke(e,t){return U(e,t)?.heartbeatAt??t.leftAt??t.joinedAt}function W(e,t,n){return t.active&&Oe(t.pid)&&n-ke(e,t)<=3e4}function Ae(e){c.mkdirSync(I(e,e.memberId),{recursive:!0,mode:448}),r.writePrivateAtomicJson(P(e,e.memberId),e)}function G(e,t,n){let i={version:1,memberId:t.memberId,tokenHash:t.tokenHash,pid:t.pid,heartbeatAt:n};r.writePrivateAtomicJson(F(e,t.memberId),i)}function K(e){let t=l.join(N(e.teamId),m),n;try{n=c.readdirSync(t,{withFileTypes:!0})}catch{return[]}return n.filter(e=>e.isFile()&&e.name.endsWith(_)).map(e=>Ce(B(l.join(t,e.name)))).filter(e=>!!e).filter(t=>t.teamId===e.teamId&&t.rootSessionId===e.rootSessionId)}function q(e,t){return K(e).filter(n=>W(e,n,t)).sort((e,t)=>e.joinedAt-t.joinedAt||e.memberId.localeCompare(t.memberId))}function je(e=Date.now()){let t=Y();if(t)return{members:q(t,e).map($)}}function Me(e,t,n){let r=0;for(let i of K(e))i.memberId!==t&&(W(e,i,n)||n-ke(e,i)<=33e4||(be(I(e,i.memberId)),V(F(e,i.memberId)),V(P(e,i.memberId)),r+=1));return r}function Ne(e){let t=e.trim();if(!t)throw Error(`A root session id is required for native team communication.`);let n={version:1,teamId:me(t),rootSessionId:t,mainMemberId:v};ye(n);let i=l.join(N(n.teamId),ne),a=xe(B(i));if(a&&a.rootSessionId!==t)throw Error(`Native team identity collision detected.`);let o=Date.now();return r.writePrivateAtomicJson(i,{...n,createdAt:a?.createdAt??o,updatedAt:o}),n}function J(e){return{[t.SUBAGENT_TEAM_ID_ENV]:e.teamId,[t.SUBAGENT_TEAM_ROOT_SESSION_ENV]:e.rootSessionId,[t.SUBAGENT_TEAM_MAIN_MEMBER_ENV]:e.mainMemberId}}function Pe(e){return{...J(e),[t.SUBAGENT_TEAM_MEMBER_ID_ENV]:e.memberId,[t.SUBAGENT_TEAM_MEMBER_TOKEN_ENV]:e.token}}function Fe(){return{[t.SUBAGENT_TEAM_MEMBER_ID_ENV]:void 0,[t.SUBAGENT_TEAM_MEMBER_TOKEN_ENV]:void 0}}function Ie(e){Object.assign(process.env,J(e))}function Le(e){e&&process.env.PI_SUBAGENT_TEAM_ID!==e.teamId||(delete process.env[t.SUBAGENT_TEAM_ID_ENV],delete process.env[t.SUBAGENT_TEAM_ROOT_SESSION_ENV],delete process.env[t.SUBAGENT_TEAM_MAIN_MEMBER_ENV])}function Y(){let e=A(t.SUBAGENT_TEAM_ID_ENV),n=A(t.SUBAGENT_TEAM_ROOT_SESSION_ENV),r=A(t.SUBAGENT_TEAM_MAIN_MEMBER_ENV);if(!e||!w(e)||!n||r!==v||e!==me(n))return;let i=xe(B(l.join(N(e),ne)));if(!(!i||i.rootSessionId!==n||i.teamId!==e))return{version:1,teamId:e,rootSessionId:n,mainMemberId:r}}function Re(e){if(!e)return;let t=e.id.trim(),n=e.subject.trim();if(!t||!k(t,256))throw Error(`Native team task id must be between 1 and 256 bytes.`);if(!n||!k(n,x))throw Error(`Native team task subject must be between 1 and ${x} bytes.`);return{id:t,subject:n}}function ze(e){if(e.role===`main`)return e.root.mainMemberId;let t=e.name!==void 0;if(!t&&!e.agent)throw Error(`An intercom member needs a name or an agent to derive one from.`);let n=ge(M(e.name??e.agent??y),t);if(e.runId){let t=M(e.runId).slice(0,8),r=48-t.length-1;return`${n.slice(0,r).replace(S,``)||y}-${t}`}return e.fanoutIndex===void 0?n:he(n,e.fanoutIndex)}function Be(e){let t=ze(e);if(!w(t))throw Error(`A safe native team member id is required.`);let n=pe(),r=j(n),i=Date.now(),a=Re(e.task),o={...e.root,memberId:t,token:n,role:e.role,...e.agent?{agent:e.agent}:{},...e.runId?{runId:e.runId}:{},...e.childIndex===void 0?{}:{childIndex:e.childIndex},...e.parentMemberId?{parentMemberId:e.parentMemberId}:{},...a?{task:a}:{}},s=H(e.root,t);s&&s.tokenHash!==r&&be(I(e.root,t));let{token:c,version:l,...u}=o,d={...u,version:1,tokenHash:r,pid:e.pid??process.pid,active:!0,joinedAt:i};Ae(d),G(e.root,d,i);let f=!1;return{context:o,dispose:()=>{if(f)return;f=!0;let n=H(e.root,t);if(!n||n.tokenHash!==r)return;let i=Date.now();Ae({...n,active:!1,leftAt:i}),G(e.root,n,i)}}}function X(){let e=Y(),n=A(t.SUBAGENT_TEAM_MEMBER_ID_ENV),r=A(t.SUBAGENT_TEAM_MEMBER_TOKEN_ENV);if(!e||!n||!w(n)||!r)return;let i=H(e,n);if(!(!i||i.teamId!==e.teamId||i.rootSessionId!==e.rootSessionId)&&!(i.tokenHash!==j(r)||!i.active))return{...e,memberId:n,token:r,role:i.role,...i.agent?{agent:i.agent}:{},...i.runId?{runId:i.runId}:{},...i.childIndex===void 0?{}:{childIndex:i.childIndex},...i.parentMemberId?{parentMemberId:i.parentMemberId}:{},...i.task?{task:i.task}:{}}}function Z(e,t){let n=H(e,e.memberId);if(!n||n.tokenHash!==j(e.token)||!W(e,n,t))throw Error(`This native team member is no longer active.`);return n}function Ve(e,t,n){let r=t?.trim();if(!r)throw a.invalidRequest(`to is required for intercom send and ask.`,`Provide an explicit recipient.`);let i=q(e,n).filter(t=>t.memberId!==e.memberId),o=M(r),s=i.find(e=>e.memberId===r||e.memberId===o);if(s)return s;let c=r.toLowerCase(),l=i.filter(e=>e.agent?.toLowerCase()===c||e.runId?.toLowerCase()===c||c===v&&e.role===`main`);if(l.length===1)return l[0];throw l.length>1?new a.DoomTeamExpectedError(`recipient_ambiguous`,`Multiple active intercom members match '${r}': ${l.map(e=>e.memberId).join(`, `)}.`,!1,`Retry with one exact member id.`):new a.DoomTeamExpectedError(`recipient_not_found`,`Active intercom member '${r}' was not found.`,!0,`Call intercom({"action":"members"}) and retry with an active member id.`)}function He(e){let t=e?.trim();if(!t)throw a.invalidRequest(`message is required for intercom communication.`,`Provide a nonblank message.`);if(!k(t,b))throw a.invalidRequest(`Intercom message exceeds 64 KiB.`,`Shorten the message and retry.`);return t}function Q(e,t,n){let r=H(e,t);return!!(r&&r.tokenHash===n)}function Ue(e,t,n){let r=I(e,e.memberId),i;try{i=c.readdirSync(r,{withFileTypes:!0})}catch{return{messages:[],foreignFiles:[]}}let a=[],o=[];for(let s of i){if(!s.isFile()||!s.name.endsWith(_)||n?.(s.name))continue;let i=l.join(r,s.name),c=Te(B(i));if(!c){V(i);continue}if(c.teamId!==e.teamId||c.toMemberId!==e.memberId){o.push(s.name);continue}if(c.expiresAt<t||!Q(e,c.fromMemberId,c.senderTokenHash)){V(i);continue}a.push(c)}return{messages:We(a),foreignFiles:o}}function We(e){let t=new Map;for(let n of e){let e=t.get(n.fromMemberId);e?e.push(n):t.set(n.fromMemberId,[n])}let n=[];for(let e of t.values())e.sort((e,t)=>e.seq-t.seq),n.push(e);let r=[];for(;;){let e,t;for(let r of n){let n=r[0];n&&(!t||n.createdAt<t.createdAt||n.createdAt===t.createdAt&&n.fromMemberId<t.fromMemberId)&&(e=r,t=n)}if(!e||!t)break;e.shift(),r.push(t)}return r}function Ge(e){let t=e.role===`main`?v:e.agent??e.memberId,n=e.runId?` [${e.runId}]`:``,r=e.task?`, task ${e.task.id}: ${e.task.subject}`:``;return`- ${e.memberId}: ${t}${n}${r}`}function $(e){return{name:e.memberId,role:e.role,...e.agent?{agent:e.agent}:{},...e.runId?{runId:e.runId}:{},...e.task?{task:e.task}:{}}}function Ke(e,t){return new Promise((n,r)=>{if(t?.aborted){r(Error(`Native team request cancelled.`));return}let i,a=()=>{i&&clearTimeout(i),t?.removeEventListener(`abort`,o)},o=()=>{a(),r(Error(`Native team request cancelled.`))};i=setTimeout(()=>{a(),n()},e),t?.addEventListener(`abort`,o,{once:!0})})}function qe(e,t){let n=H(e,t.fromMemberId),r=`${t.fromMemberId}${n?.agent?` (${n.agent})`:``}`,i=n?.task?`, task ${n.task.id}`:``,a=[`${t.kind===`ask`?`Question`:`Message`} from ${r}${i}.`];return a.push(``,t.message),t.kind===`ask`&&a.push(``,`Reply with ${d}({ action: "reply", requestId: "${t.id}", message: "..." }).`),a.join(`
2
+ `)}function Je(e,t){try{return e.getAllTools().some(e=>e.name===t)}catch{return!1}}var Ye=class{context;ownedMembershipDispose;poller;lastHeartbeatAt=0;lastGcAt=0;seenFiles=new i.BoundedKeySet(1024);deliveryAttempts=new n.LruCache(256);undeliverableMessages=[];outboundSeq=0;constructor(e,t){if(this.pi=e,this.options=t,Je(e,`intercom`))throw Error(`[tool_conflict] A foreign '${d}' tool is already registered. Recovery: disable the competing extension and reload Doom Team.`);e.registerTool(this.buildTool())}current(){return this.context}undeliverable(){return this.undeliverableMessages}bindMainSession(e){let t=Ne(e);Ie(t);let n=Be({root:t,role:`main`});return this.startBinding(n.context,n.dispose)}bindChildFromEnvironment(){let e=X();if(e)return this.context?.memberId===e.memberId&&this.context.token===e.token?this.context:this.startBinding(e)}dispose(){let e=this.context;this.stopBinding(),e?.role===`main`&&Le(e)}startBinding(e,t){return this.stopBinding(),this.context=e,this.ownedMembershipDispose=t,this.poll(),this.poller=setInterval(()=>{this.poll()},this.options.pollIntervalMs),this.poller.unref?.(),e}stopBinding(){this.poller&&clearInterval(this.poller),this.poller=void 0,this.ownedMembershipDispose?.(),this.ownedMembershipDispose=void 0,this.seenFiles.clear(),this.deliveryAttempts.clear(),this.lastHeartbeatAt=0,this.lastGcAt=0,this.outboundSeq=0,this.context=void 0}poll(){let e=this.context;if(!e)return;let t=this.options.now();this.heartbeat(e,t),this.collectGarbageIfDue(e,t);let n=Ue(e,t,e=>this.seenFiles.has(e));for(let e of n.foreignFiles)this.seenFiles.add(e);for(let t of n.messages)this.deliverOnce(e,t)}deliverOnce(e,t){let n=L(t.id);try{this.deliver(e,t)}catch(r){let i=(this.deliveryAttempts.get(n)??0)+1;if(i<this.options.maxDeliveryAttempts){this.deliveryAttempts.set(n,i);return}this.deliveryAttempts.delete(n),this.seenFiles.add(n),this.reportUndeliverable(e,t,i,r);return}this.seenFiles.add(n),this.deliveryAttempts.delete(n),r.writePrivateAtomicJson(z(e,t.fromMemberId,t.id),{version:1,messageId:t.id,state:C,deliveredAt:this.options.now()}),t.kind===`send`&&V(R(e,e.memberId,t.id))}deliver(e,t){let n=qe(e,t);if(e.role===`subagent`){this.pi.sendUserMessage(n,{deliverAs:`steer`});return}this.pi.sendMessage({customType:`intercom_message`,content:n,display:!0,details:{id:t.id,kind:t.kind,from:t.fromMemberId,to:t.toMemberId,seq:t.seq}},{triggerTurn:!0,deliverAs:`steer`})}reportUndeliverable(e,t,n,i){let a={messageId:t.id,fromMemberId:t.fromMemberId,kind:t.kind,attempts:n,reason:fe(i),at:this.options.now()};for(this.undeliverableMessages.push(a),r.writePrivateAtomicJson(z(e,t.fromMemberId,t.id),{version:1,messageId:t.id,state:se,reason:a.reason,failedAt:a.at});this.undeliverableMessages.length>32;)this.undeliverableMessages.shift();try{return this.pi.sendMessage({customType:`intercom_undeliverable`,content:`Native team message ${t.id} from ${t.fromMemberId} could not be delivered after ${n} attempts: ${a.reason}`,display:!0,details:{...a}},{triggerTurn:!0,deliverAs:`steer`}),!0}catch{return!1}}heartbeat(e,t){if(t-this.lastHeartbeatAt<this.options.heartbeatIntervalMs)return;let n=H(e,e.memberId);!n||n.tokenHash!==j(e.token)||!n.active||(this.lastHeartbeatAt=t,G(e,n,t))}collectGarbageIfDue(e,t){if(!(t-this.lastGcAt<this.options.gcIntervalMs)){this.lastGcAt=t;try{Me(e,e.memberId,t)}catch(n){for(this.undeliverableMessages.push({messageId:``,fromMemberId:e.memberId,kind:`send`,attempts:0,reason:`Native team directory sweep failed: ${fe(n)}`,at:t});this.undeliverableMessages.length>32;)this.undeliverableMessages.shift()}}}nextSeq(){return this.outboundSeq+=1,this.outboundSeq}queueMessage(e,t,n,i,a,o){if(Z(e,a),!W(e,t,a))throw Error(`Native team member '${t.memberId}' is no longer active.`);let s={type:f,version:2,id:o,teamId:e.teamId,kind:n,fromMemberId:e.memberId,toMemberId:t.memberId,senderTokenHash:j(e.token),seq:this.nextSeq(),message:i,createdAt:a,expiresAt:a+864e5};return c.mkdirSync(I(e,t.memberId),{recursive:!0,mode:448}),r.writePrivateAtomicJson(R(e,t.memberId,s.id),s),s}replyToRequest(e,t,n,i){if(!t||!w(t))throw Error(`requestId must be a valid intercom request id.`);Z(e,i);let o=R(e,e.memberId,t),s=Te(B(o));if(!s||s.kind!==`ask`||s.teamId!==e.teamId||s.toMemberId!==e.memberId||!Q(e,s.fromMemberId,s.senderTokenHash))throw new a.DoomTeamExpectedError(`recipient_not_found`,`No pending intercom ask matches requestId '${t}'.`,!1,`Call intercom({"action":"pending"}) and retry with an exact requestId.`);let c={type:p,version:2,requestId:t,teamId:e.teamId,fromMemberId:e.memberId,toMemberId:s.fromMemberId,senderTokenHash:j(e.token),message:n,createdAt:i};return r.writePrivateAtomicJson(_e(e,t),c),V(o),this.seenFiles.delete(L(t)),c}async waitForReply(e,t,n,r,i){let o=_e(e,n.id),s=this.options.now()+(i??this.options.askTimeoutMs);for(;this.options.now()<=s;){if(r?.aborted)throw Error(`Native team request cancelled.`);let i=Ee(B(o));if(i&&i.teamId===e.teamId&&i.requestId===n.id&&i.fromMemberId===t.memberId&&i.toMemberId===e.memberId&&Q(e,i.fromMemberId,i.senderTokenHash))return V(o),i;let s=H(e,t.memberId);if(!s||!W(e,s,this.options.now()))throw new a.DoomTeamExpectedError(`communication_unavailable`,`Intercom member '${t.memberId}' became unreachable before replying.`,!0,`Call intercom({"action":"members"}) and decide whether to retry with an active member.`);await Ke(this.options.replyPollIntervalMs,r)}throw new a.DoomTeamExpectedError(`reply_timeout`,`Timed out waiting for intercom member '${t.memberId}' to reply.`,!0,`Check member status before deciding whether to ask again.`)}buildTool(){return{name:d,label:`Intercom`,description:`Communicate with active agents in this root session. Use members, send, ask, pending, or reply. The stable root identity is main.`,promptGuidelines:[`Send only new progress, blockers, or decisions. Do not repeat the task brief, sender task, or delegation instructions because the recipient already has them.`],parameters:ce,execute:async(e,t,n,r)=>{let i=this.context;if(!i)throw new a.DoomTeamExpectedError(`communication_unavailable`,`Intercom is not active for this session.`,!0,`Wait for session startup or reload Doom Team.`);let o=De(t),s=this.options.now();if(Z(i,s),o.action===`members`){let e=q(i,s);return{content:[{type:`text`,text:e.length?e.map(Ge).join(`
3
+ `):`No active members.`}],details:{members:e.map($)}}}if(o.action===`pending`){let e=Ue(i,s).messages.filter(e=>e.kind===`ask`),t=e.map(e=>`- ${e.id}: from ${e.fromMemberId}. Reply with ${d}({ action: "reply", requestId: "${e.id}", message: "..." }).`);return{content:[{type:`text`,text:t.length?t.join(`
4
+ `):`No pending native team asks.`}],details:{pending:e.map(e=>({id:e.id,from:e.fromMemberId,message:e.message}))}}}let c=He(o.message);if(o.action===`reply`){let e=this.replyToRequest(i,o.requestId,c,s);return{content:[{type:`text`,text:`Replied to native team request ${e.requestId}.`}],details:{requestId:e.requestId,to:e.toMemberId}}}let l=Ve(i,o.to,s);o.action===`ask`&&r?.({content:[{type:`text`,text:`Waiting for ${l.memberId} to reply...`}],details:{action:`ask`,to:l.memberId,partial:!0}});let u=ve(i.memberId,e),f=B(z(i,i.memberId,u));if(f?.state===se)throw new a.DoomTeamExpectedError(`delivery_unconfirmed`,`Intercom message ${u} failed: ${typeof f.reason==`string`?f.reason:`unknown error`}`,!1,`Call intercom({"action":"members"}) and do not resend automatically.`);if(o.action===`send`&&f?.state===C)return{content:[{type:`text`,text:`Message ${u} delivered to ${l.memberId}.`}],details:{state:C,delivered:!0,messageId:u,to:l.memberId}};let p=this.queueMessage(i,l,o.action,c,s,u);if(o.action===`send`)return{content:[{type:`text`,text:`Message ${p.id} queued for ${l.memberId}; delivery is not yet confirmed. Do not resend.`}],details:{state:`queued`,delivered:!1,messageId:p.id,to:l.memberId,seq:p.seq}};try{let e=await this.waitForReply(i,l,p,n,o.timeoutMs);return{content:[{type:`text`,text:`Reply from ${l.memberId}:\n${e.message}`}],details:{requestId:p.id,from:l.memberId,reply:e.message}}}finally{V(R(i,l.memberId,p.id))}}}}},Xe=class{runtimes=new WeakMap;pollIntervalMs=250;replyPollIntervalMs=250;heartbeatIntervalMs=5e3;gcIntervalMs=6e4;askTimeoutMs=6e5;maxDeliveryAttempts=5;now(){return Date.now()}createRuntime(e){let t=this.runtimes.get(e);if(t)return t;let n=new Ye(e,{pollIntervalMs:this.pollIntervalMs,replyPollIntervalMs:this.replyPollIntervalMs,heartbeatIntervalMs:this.heartbeatIntervalMs,gcIntervalMs:this.gcIntervalMs,askTimeoutMs:this.askTimeoutMs,maxDeliveryAttempts:this.maxDeliveryAttempts,now:()=>this.now()});return this.runtimes.set(e,n),e.on(`session_shutdown`,()=>{this.runtimes.get(e)?.dispose()}),n}registerClient(e){o.tryCurrentSessionScope()&&X()&&this.createRuntime(e).bindChildFromEnvironment()}};exports.HEARTBEAT_STALE_MS=3e4,exports.NATIVE_TEAM_TOOL_NAME=d,exports.NativeTeamChannelService=Xe,exports.applyNativeTeamRootEnvironment=Ie,exports.clearNativeTeamMemberEnvironment=Fe,exports.clearNativeTeamRootEnvironment=Le,exports.ensureNativeTeamRoot=Ne,exports.listMemberRecords=K,exports.nativeTeamMemberEnvironment=Pe,exports.nativeTeamRootEnvironment=J,exports.normalizeTeamMemberName=M,exports.processAlive=Oe,exports.readActiveNativeTeamSnapshot=je,exports.readHeartbeat=U,exports.readMember=H,exports.readNativeTeamMemberFromEnvironment=X,exports.readNativeTeamRootFromEnvironment=Y,exports.registerNativeTeamMember=Be,exports.teamDir=N;
5
5
  //# sourceMappingURL=nativeTeamChannel.cjs.map