lorenz 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +13 -0
  3. package/README.md +774 -0
  4. package/RELEASE-MANIFEST.json +211 -0
  5. package/apps/cli/bin/lorenz.js +25 -0
  6. package/apps/cli/dist/bin/cli.d.ts +3 -0
  7. package/apps/cli/dist/bin/cli.d.ts.map +1 -0
  8. package/apps/cli/dist/bin/cli.js +4 -0
  9. package/apps/cli/dist/bin/cli.js.map +1 -0
  10. package/apps/cli/dist/daemon.d.ts +76 -0
  11. package/apps/cli/dist/daemon.d.ts.map +1 -0
  12. package/apps/cli/dist/daemon.js +189 -0
  13. package/apps/cli/dist/daemon.js.map +1 -0
  14. package/apps/cli/dist/doctor.d.ts +40 -0
  15. package/apps/cli/dist/doctor.d.ts.map +1 -0
  16. package/apps/cli/dist/doctor.js +590 -0
  17. package/apps/cli/dist/doctor.js.map +1 -0
  18. package/apps/cli/dist/index.d.ts +32 -0
  19. package/apps/cli/dist/index.d.ts.map +1 -0
  20. package/apps/cli/dist/index.js +26 -0
  21. package/apps/cli/dist/index.js.map +1 -0
  22. package/apps/cli/dist/main.d.ts +40 -0
  23. package/apps/cli/dist/main.d.ts.map +1 -0
  24. package/apps/cli/dist/main.js +259 -0
  25. package/apps/cli/dist/main.js.map +1 -0
  26. package/apps/cli/dist/runs.d.ts +31 -0
  27. package/apps/cli/dist/runs.d.ts.map +1 -0
  28. package/apps/cli/dist/runs.js +281 -0
  29. package/apps/cli/dist/runs.js.map +1 -0
  30. package/apps/cli/dist/workerDriverLoader.d.ts +64 -0
  31. package/apps/cli/dist/workerDriverLoader.d.ts.map +1 -0
  32. package/apps/cli/dist/workerDriverLoader.js +211 -0
  33. package/apps/cli/dist/workerDriverLoader.js.map +1 -0
  34. package/apps/cli/package.json +57 -0
  35. package/apps/symphony-dashboard/dist/assets/index-B3owF3jd.css +1 -0
  36. package/apps/symphony-dashboard/dist/assets/index-DQ6XlL0d.js +227 -0
  37. package/apps/symphony-dashboard/dist/index.html +18 -0
  38. package/bin/lorenz +16 -0
  39. package/extensions/docker-worker/dist/index.d.ts +92 -0
  40. package/extensions/docker-worker/dist/index.d.ts.map +1 -0
  41. package/extensions/docker-worker/dist/index.js +283 -0
  42. package/extensions/docker-worker/dist/index.js.map +1 -0
  43. package/extensions/docker-worker/package.json +14 -0
  44. package/extensions/jira-tracker/dist/client.d.ts +50 -0
  45. package/extensions/jira-tracker/dist/client.d.ts.map +1 -0
  46. package/extensions/jira-tracker/dist/client.js +619 -0
  47. package/extensions/jira-tracker/dist/client.js.map +1 -0
  48. package/extensions/jira-tracker/dist/index.d.ts +5 -0
  49. package/extensions/jira-tracker/dist/index.d.ts.map +1 -0
  50. package/extensions/jira-tracker/dist/index.js +5 -0
  51. package/extensions/jira-tracker/dist/index.js.map +1 -0
  52. package/extensions/jira-tracker/dist/options.d.ts +38 -0
  53. package/extensions/jira-tracker/dist/options.d.ts.map +1 -0
  54. package/extensions/jira-tracker/dist/options.js +61 -0
  55. package/extensions/jira-tracker/dist/options.js.map +1 -0
  56. package/extensions/jira-tracker/dist/provider.d.ts +6 -0
  57. package/extensions/jira-tracker/dist/provider.d.ts.map +1 -0
  58. package/extensions/jira-tracker/dist/provider.js +178 -0
  59. package/extensions/jira-tracker/dist/provider.js.map +1 -0
  60. package/extensions/jira-tracker/dist/register.d.ts +10 -0
  61. package/extensions/jira-tracker/dist/register.d.ts.map +1 -0
  62. package/extensions/jira-tracker/dist/register.js +15 -0
  63. package/extensions/jira-tracker/dist/register.js.map +1 -0
  64. package/extensions/jira-tracker/package.json +16 -0
  65. package/extensions/linear-tracker/dist/client.d.ts +82 -0
  66. package/extensions/linear-tracker/dist/client.d.ts.map +1 -0
  67. package/extensions/linear-tracker/dist/client.js +622 -0
  68. package/extensions/linear-tracker/dist/client.js.map +1 -0
  69. package/extensions/linear-tracker/dist/index.d.ts +8 -0
  70. package/extensions/linear-tracker/dist/index.d.ts.map +1 -0
  71. package/extensions/linear-tracker/dist/index.js +7 -0
  72. package/extensions/linear-tracker/dist/index.js.map +1 -0
  73. package/extensions/linear-tracker/dist/options.d.ts +32 -0
  74. package/extensions/linear-tracker/dist/options.d.ts.map +1 -0
  75. package/extensions/linear-tracker/dist/options.js +59 -0
  76. package/extensions/linear-tracker/dist/options.js.map +1 -0
  77. package/extensions/linear-tracker/dist/provider.d.ts +4 -0
  78. package/extensions/linear-tracker/dist/provider.d.ts.map +1 -0
  79. package/extensions/linear-tracker/dist/provider.js +58 -0
  80. package/extensions/linear-tracker/dist/provider.js.map +1 -0
  81. package/extensions/linear-tracker/dist/register.d.ts +11 -0
  82. package/extensions/linear-tracker/dist/register.d.ts.map +1 -0
  83. package/extensions/linear-tracker/dist/register.js +19 -0
  84. package/extensions/linear-tracker/dist/register.js.map +1 -0
  85. package/extensions/linear-tracker/dist/toolOps.d.ts +8 -0
  86. package/extensions/linear-tracker/dist/toolOps.d.ts.map +1 -0
  87. package/extensions/linear-tracker/dist/toolOps.js +160 -0
  88. package/extensions/linear-tracker/dist/toolOps.js.map +1 -0
  89. package/extensions/linear-tracker/dist/tools.d.ts +7 -0
  90. package/extensions/linear-tracker/dist/tools.d.ts.map +1 -0
  91. package/extensions/linear-tracker/dist/tools.js +210 -0
  92. package/extensions/linear-tracker/dist/tools.js.map +1 -0
  93. package/extensions/linear-tracker/package.json +18 -0
  94. package/extensions/local-tracker/dist/boardStore.d.ts +116 -0
  95. package/extensions/local-tracker/dist/boardStore.d.ts.map +1 -0
  96. package/extensions/local-tracker/dist/boardStore.js +475 -0
  97. package/extensions/local-tracker/dist/boardStore.js.map +1 -0
  98. package/extensions/local-tracker/dist/client.d.ts +14 -0
  99. package/extensions/local-tracker/dist/client.d.ts.map +1 -0
  100. package/extensions/local-tracker/dist/client.js +27 -0
  101. package/extensions/local-tracker/dist/client.js.map +1 -0
  102. package/extensions/local-tracker/dist/index.d.ts +7 -0
  103. package/extensions/local-tracker/dist/index.d.ts.map +1 -0
  104. package/extensions/local-tracker/dist/index.js +7 -0
  105. package/extensions/local-tracker/dist/index.js.map +1 -0
  106. package/extensions/local-tracker/dist/options.d.ts +31 -0
  107. package/extensions/local-tracker/dist/options.d.ts.map +1 -0
  108. package/extensions/local-tracker/dist/options.js +69 -0
  109. package/extensions/local-tracker/dist/options.js.map +1 -0
  110. package/extensions/local-tracker/dist/provider.d.ts +9 -0
  111. package/extensions/local-tracker/dist/provider.d.ts.map +1 -0
  112. package/extensions/local-tracker/dist/provider.js +35 -0
  113. package/extensions/local-tracker/dist/provider.js.map +1 -0
  114. package/extensions/local-tracker/dist/register.d.ts +11 -0
  115. package/extensions/local-tracker/dist/register.d.ts.map +1 -0
  116. package/extensions/local-tracker/dist/register.js +19 -0
  117. package/extensions/local-tracker/dist/register.js.map +1 -0
  118. package/extensions/local-tracker/dist/resolveBoardDir.d.ts +24 -0
  119. package/extensions/local-tracker/dist/resolveBoardDir.d.ts.map +1 -0
  120. package/extensions/local-tracker/dist/resolveBoardDir.js +39 -0
  121. package/extensions/local-tracker/dist/resolveBoardDir.js.map +1 -0
  122. package/extensions/local-tracker/dist/toolOps.d.ts +9 -0
  123. package/extensions/local-tracker/dist/toolOps.d.ts.map +1 -0
  124. package/extensions/local-tracker/dist/toolOps.js +86 -0
  125. package/extensions/local-tracker/dist/toolOps.js.map +1 -0
  126. package/extensions/local-tracker/dist/tools.d.ts +7 -0
  127. package/extensions/local-tracker/dist/tools.d.ts.map +1 -0
  128. package/extensions/local-tracker/dist/tools.js +170 -0
  129. package/extensions/local-tracker/dist/tools.js.map +1 -0
  130. package/extensions/local-tracker/package.json +18 -0
  131. package/extensions/memory-tracker/dist/index.d.ts +24 -0
  132. package/extensions/memory-tracker/dist/index.d.ts.map +1 -0
  133. package/extensions/memory-tracker/dist/index.js +110 -0
  134. package/extensions/memory-tracker/dist/index.js.map +1 -0
  135. package/extensions/memory-tracker/package.json +16 -0
  136. package/extensions/slack-tracker/dist/client.d.ts +88 -0
  137. package/extensions/slack-tracker/dist/client.d.ts.map +1 -0
  138. package/extensions/slack-tracker/dist/client.js +246 -0
  139. package/extensions/slack-tracker/dist/client.js.map +1 -0
  140. package/extensions/slack-tracker/dist/inMemoryTransport.d.ts +42 -0
  141. package/extensions/slack-tracker/dist/inMemoryTransport.d.ts.map +1 -0
  142. package/extensions/slack-tracker/dist/inMemoryTransport.js +104 -0
  143. package/extensions/slack-tracker/dist/inMemoryTransport.js.map +1 -0
  144. package/extensions/slack-tracker/dist/index.d.ts +15 -0
  145. package/extensions/slack-tracker/dist/index.d.ts.map +1 -0
  146. package/extensions/slack-tracker/dist/index.js +11 -0
  147. package/extensions/slack-tracker/dist/index.js.map +1 -0
  148. package/extensions/slack-tracker/dist/mapping.d.ts +27 -0
  149. package/extensions/slack-tracker/dist/mapping.d.ts.map +1 -0
  150. package/extensions/slack-tracker/dist/mapping.js +109 -0
  151. package/extensions/slack-tracker/dist/mapping.js.map +1 -0
  152. package/extensions/slack-tracker/dist/operations.d.ts +41 -0
  153. package/extensions/slack-tracker/dist/operations.d.ts.map +1 -0
  154. package/extensions/slack-tracker/dist/operations.js +97 -0
  155. package/extensions/slack-tracker/dist/operations.js.map +1 -0
  156. package/extensions/slack-tracker/dist/options.d.ts +30 -0
  157. package/extensions/slack-tracker/dist/options.d.ts.map +1 -0
  158. package/extensions/slack-tracker/dist/options.js +49 -0
  159. package/extensions/slack-tracker/dist/options.js.map +1 -0
  160. package/extensions/slack-tracker/dist/provider.d.ts +9 -0
  161. package/extensions/slack-tracker/dist/provider.d.ts.map +1 -0
  162. package/extensions/slack-tracker/dist/provider.js +74 -0
  163. package/extensions/slack-tracker/dist/provider.js.map +1 -0
  164. package/extensions/slack-tracker/dist/register.d.ts +11 -0
  165. package/extensions/slack-tracker/dist/register.d.ts.map +1 -0
  166. package/extensions/slack-tracker/dist/register.js +19 -0
  167. package/extensions/slack-tracker/dist/register.js.map +1 -0
  168. package/extensions/slack-tracker/dist/threadState.d.ts +52 -0
  169. package/extensions/slack-tracker/dist/threadState.d.ts.map +1 -0
  170. package/extensions/slack-tracker/dist/threadState.js +192 -0
  171. package/extensions/slack-tracker/dist/threadState.js.map +1 -0
  172. package/extensions/slack-tracker/dist/toolOps.d.ts +13 -0
  173. package/extensions/slack-tracker/dist/toolOps.d.ts.map +1 -0
  174. package/extensions/slack-tracker/dist/toolOps.js +76 -0
  175. package/extensions/slack-tracker/dist/toolOps.js.map +1 -0
  176. package/extensions/slack-tracker/dist/tools.d.ts +8 -0
  177. package/extensions/slack-tracker/dist/tools.d.ts.map +1 -0
  178. package/extensions/slack-tracker/dist/tools.js +266 -0
  179. package/extensions/slack-tracker/dist/tools.js.map +1 -0
  180. package/extensions/slack-tracker/dist/transport.d.ts +63 -0
  181. package/extensions/slack-tracker/dist/transport.d.ts.map +1 -0
  182. package/extensions/slack-tracker/dist/transport.js +2 -0
  183. package/extensions/slack-tracker/dist/transport.js.map +1 -0
  184. package/extensions/slack-tracker/dist/webTransport.d.ts +44 -0
  185. package/extensions/slack-tracker/dist/webTransport.d.ts.map +1 -0
  186. package/extensions/slack-tracker/dist/webTransport.js +402 -0
  187. package/extensions/slack-tracker/dist/webTransport.js.map +1 -0
  188. package/extensions/slack-tracker/package.json +17 -0
  189. package/package.json +89 -0
  190. package/packages/acp/dist/childProcess.d.ts +4 -0
  191. package/packages/acp/dist/childProcess.d.ts.map +1 -0
  192. package/packages/acp/dist/childProcess.js +33 -0
  193. package/packages/acp/dist/childProcess.js.map +1 -0
  194. package/packages/acp/dist/index.d.ts +70 -0
  195. package/packages/acp/dist/index.d.ts.map +1 -0
  196. package/packages/acp/dist/index.js +701 -0
  197. package/packages/acp/dist/index.js.map +1 -0
  198. package/packages/acp/dist/options.d.ts +24 -0
  199. package/packages/acp/dist/options.d.ts.map +1 -0
  200. package/packages/acp/dist/options.js +92 -0
  201. package/packages/acp/dist/options.js.map +1 -0
  202. package/packages/acp/dist/toml.d.ts +2 -0
  203. package/packages/acp/dist/toml.d.ts.map +1 -0
  204. package/packages/acp/dist/toml.js +51 -0
  205. package/packages/acp/dist/toml.js.map +1 -0
  206. package/packages/acp/package.json +24 -0
  207. package/packages/agent-runner/dist/index.d.ts +58 -0
  208. package/packages/agent-runner/dist/index.d.ts.map +1 -0
  209. package/packages/agent-runner/dist/index.js +288 -0
  210. package/packages/agent-runner/dist/index.js.map +1 -0
  211. package/packages/agent-runner/package.json +19 -0
  212. package/packages/agent-sdk/dist/index.d.ts +2 -0
  213. package/packages/agent-sdk/dist/index.d.ts.map +1 -0
  214. package/packages/agent-sdk/dist/index.js +2 -0
  215. package/packages/agent-sdk/dist/index.js.map +1 -0
  216. package/packages/agent-sdk/dist/provider.d.ts +66 -0
  217. package/packages/agent-sdk/dist/provider.d.ts.map +1 -0
  218. package/packages/agent-sdk/dist/provider.js +38 -0
  219. package/packages/agent-sdk/dist/provider.js.map +1 -0
  220. package/packages/agent-sdk/package.json +14 -0
  221. package/packages/cli-kit/dist/index.d.ts +20 -0
  222. package/packages/cli-kit/dist/index.d.ts.map +1 -0
  223. package/packages/cli-kit/dist/index.js +72 -0
  224. package/packages/cli-kit/dist/index.js.map +1 -0
  225. package/packages/cli-kit/package.json +14 -0
  226. package/packages/config/dist/aliases.d.ts +10 -0
  227. package/packages/config/dist/aliases.d.ts.map +1 -0
  228. package/packages/config/dist/aliases.js +153 -0
  229. package/packages/config/dist/aliases.js.map +1 -0
  230. package/packages/config/dist/defaults.d.ts +12 -0
  231. package/packages/config/dist/defaults.d.ts.map +1 -0
  232. package/packages/config/dist/defaults.js +78 -0
  233. package/packages/config/dist/defaults.js.map +1 -0
  234. package/packages/config/dist/errors.d.ts +3 -0
  235. package/packages/config/dist/errors.d.ts.map +1 -0
  236. package/packages/config/dist/errors.js +56 -0
  237. package/packages/config/dist/errors.js.map +1 -0
  238. package/packages/config/dist/index.d.ts +5 -0
  239. package/packages/config/dist/index.d.ts.map +1 -0
  240. package/packages/config/dist/index.js +4 -0
  241. package/packages/config/dist/index.js.map +1 -0
  242. package/packages/config/dist/leaf-utils.d.ts +3 -0
  243. package/packages/config/dist/leaf-utils.d.ts.map +1 -0
  244. package/packages/config/dist/leaf-utils.js +9 -0
  245. package/packages/config/dist/leaf-utils.js.map +1 -0
  246. package/packages/config/dist/parse.d.ts +11 -0
  247. package/packages/config/dist/parse.d.ts.map +1 -0
  248. package/packages/config/dist/parse.js +821 -0
  249. package/packages/config/dist/parse.js.map +1 -0
  250. package/packages/config/dist/schemas.d.ts +214 -0
  251. package/packages/config/dist/schemas.d.ts.map +1 -0
  252. package/packages/config/dist/schemas.js +248 -0
  253. package/packages/config/dist/schemas.js.map +1 -0
  254. package/packages/config/package.json +19 -0
  255. package/packages/dispatch/dist/index.d.ts +22 -0
  256. package/packages/dispatch/dist/index.d.ts.map +1 -0
  257. package/packages/dispatch/dist/index.js +117 -0
  258. package/packages/dispatch/dist/index.js.map +1 -0
  259. package/packages/dispatch/package.json +16 -0
  260. package/packages/dispatch-coordinator/dist/coordinator.d.ts +158 -0
  261. package/packages/dispatch-coordinator/dist/coordinator.d.ts.map +1 -0
  262. package/packages/dispatch-coordinator/dist/coordinator.js +529 -0
  263. package/packages/dispatch-coordinator/dist/coordinator.js.map +1 -0
  264. package/packages/dispatch-coordinator/dist/gate.d.ts +24 -0
  265. package/packages/dispatch-coordinator/dist/gate.d.ts.map +1 -0
  266. package/packages/dispatch-coordinator/dist/gate.js +47 -0
  267. package/packages/dispatch-coordinator/dist/gate.js.map +1 -0
  268. package/packages/dispatch-coordinator/dist/index.d.ts +6 -0
  269. package/packages/dispatch-coordinator/dist/index.d.ts.map +1 -0
  270. package/packages/dispatch-coordinator/dist/index.js +16 -0
  271. package/packages/dispatch-coordinator/dist/index.js.map +1 -0
  272. package/packages/dispatch-coordinator/dist/mcpEndpointManager.d.ts +28 -0
  273. package/packages/dispatch-coordinator/dist/mcpEndpointManager.d.ts.map +1 -0
  274. package/packages/dispatch-coordinator/dist/mcpEndpointManager.js +54 -0
  275. package/packages/dispatch-coordinator/dist/mcpEndpointManager.js.map +1 -0
  276. package/packages/dispatch-coordinator/dist/nullEndpointManager.d.ts +18 -0
  277. package/packages/dispatch-coordinator/dist/nullEndpointManager.d.ts.map +1 -0
  278. package/packages/dispatch-coordinator/dist/nullEndpointManager.js +40 -0
  279. package/packages/dispatch-coordinator/dist/nullEndpointManager.js.map +1 -0
  280. package/packages/dispatch-coordinator/dist/types.d.ts +119 -0
  281. package/packages/dispatch-coordinator/dist/types.d.ts.map +1 -0
  282. package/packages/dispatch-coordinator/dist/types.js +17 -0
  283. package/packages/dispatch-coordinator/dist/types.js.map +1 -0
  284. package/packages/dispatch-coordinator/package.json +16 -0
  285. package/packages/domain/dist/index.d.ts +775 -0
  286. package/packages/domain/dist/index.d.ts.map +1 -0
  287. package/packages/domain/dist/index.js +124 -0
  288. package/packages/domain/dist/index.js.map +1 -0
  289. package/packages/domain/package.json +14 -0
  290. package/packages/humanize/dist/index.d.ts +4 -0
  291. package/packages/humanize/dist/index.d.ts.map +1 -0
  292. package/packages/humanize/dist/index.js +347 -0
  293. package/packages/humanize/dist/index.js.map +1 -0
  294. package/packages/humanize/package.json +11 -0
  295. package/packages/issue/dist/index.d.ts +7 -0
  296. package/packages/issue/dist/index.d.ts.map +1 -0
  297. package/packages/issue/dist/index.js +147 -0
  298. package/packages/issue/dist/index.js.map +1 -0
  299. package/packages/issue/package.json +14 -0
  300. package/packages/log-file/dist/index.d.ts +10 -0
  301. package/packages/log-file/dist/index.d.ts.map +1 -0
  302. package/packages/log-file/dist/index.js +200 -0
  303. package/packages/log-file/dist/index.js.map +1 -0
  304. package/packages/log-file/package.json +15 -0
  305. package/packages/mcp/dist/agentEndpoint.d.ts +31 -0
  306. package/packages/mcp/dist/agentEndpoint.d.ts.map +1 -0
  307. package/packages/mcp/dist/agentEndpoint.js +270 -0
  308. package/packages/mcp/dist/agentEndpoint.js.map +1 -0
  309. package/packages/mcp/dist/auth.d.ts +7 -0
  310. package/packages/mcp/dist/auth.d.ts.map +1 -0
  311. package/packages/mcp/dist/auth.js +48 -0
  312. package/packages/mcp/dist/auth.js.map +1 -0
  313. package/packages/mcp/dist/filter.d.ts +70 -0
  314. package/packages/mcp/dist/filter.d.ts.map +1 -0
  315. package/packages/mcp/dist/filter.js +231 -0
  316. package/packages/mcp/dist/filter.js.map +1 -0
  317. package/packages/mcp/dist/index.d.ts +7 -0
  318. package/packages/mcp/dist/index.d.ts.map +1 -0
  319. package/packages/mcp/dist/index.js +5 -0
  320. package/packages/mcp/dist/index.js.map +1 -0
  321. package/packages/mcp/dist/server.d.ts +31 -0
  322. package/packages/mcp/dist/server.d.ts.map +1 -0
  323. package/packages/mcp/dist/server.js +176 -0
  324. package/packages/mcp/dist/server.js.map +1 -0
  325. package/packages/mcp/dist/tools/linear.d.ts +5 -0
  326. package/packages/mcp/dist/tools/linear.d.ts.map +1 -0
  327. package/packages/mcp/dist/tools/linear.js +192 -0
  328. package/packages/mcp/dist/tools/linear.js.map +1 -0
  329. package/packages/mcp/dist/tools/local.d.ts +5 -0
  330. package/packages/mcp/dist/tools/local.d.ts.map +1 -0
  331. package/packages/mcp/dist/tools/local.js +161 -0
  332. package/packages/mcp/dist/tools/local.js.map +1 -0
  333. package/packages/mcp/dist/tools/result.d.ts +5 -0
  334. package/packages/mcp/dist/tools/result.d.ts.map +1 -0
  335. package/packages/mcp/dist/tools/result.js +15 -0
  336. package/packages/mcp/dist/tools/result.js.map +1 -0
  337. package/packages/mcp/dist/tools.d.ts +14 -0
  338. package/packages/mcp/dist/tools.d.ts.map +1 -0
  339. package/packages/mcp/dist/tools.js +58 -0
  340. package/packages/mcp/dist/tools.js.map +1 -0
  341. package/packages/mcp/package.json +20 -0
  342. package/packages/orchestrator/dist/index.d.ts +171 -0
  343. package/packages/orchestrator/dist/index.d.ts.map +1 -0
  344. package/packages/orchestrator/dist/index.js +524 -0
  345. package/packages/orchestrator/dist/index.js.map +1 -0
  346. package/packages/orchestrator/package.json +18 -0
  347. package/packages/policies/dist/index.d.ts +11 -0
  348. package/packages/policies/dist/index.d.ts.map +1 -0
  349. package/packages/policies/dist/index.js +6 -0
  350. package/packages/policies/dist/index.js.map +1 -0
  351. package/packages/policies/dist/reconciliation.d.ts +5 -0
  352. package/packages/policies/dist/reconciliation.d.ts.map +1 -0
  353. package/packages/policies/dist/reconciliation.js +17 -0
  354. package/packages/policies/dist/reconciliation.js.map +1 -0
  355. package/packages/policies/dist/resume.d.ts +14 -0
  356. package/packages/policies/dist/resume.d.ts.map +1 -0
  357. package/packages/policies/dist/resume.js +7 -0
  358. package/packages/policies/dist/resume.js.map +1 -0
  359. package/packages/policies/dist/retry.d.ts +4 -0
  360. package/packages/policies/dist/retry.d.ts.map +1 -0
  361. package/packages/policies/dist/retry.js +7 -0
  362. package/packages/policies/dist/retry.js.map +1 -0
  363. package/packages/policies/dist/stopReason.d.ts +4 -0
  364. package/packages/policies/dist/stopReason.d.ts.map +1 -0
  365. package/packages/policies/dist/stopReason.js +11 -0
  366. package/packages/policies/dist/stopReason.js.map +1 -0
  367. package/packages/policies/dist/usage.d.ts +14 -0
  368. package/packages/policies/dist/usage.d.ts.map +1 -0
  369. package/packages/policies/dist/usage.js +38 -0
  370. package/packages/policies/dist/usage.js.map +1 -0
  371. package/packages/policies/dist/workerHost.d.ts +8 -0
  372. package/packages/policies/dist/workerHost.d.ts.map +1 -0
  373. package/packages/policies/dist/workerHost.js +20 -0
  374. package/packages/policies/dist/workerHost.js.map +1 -0
  375. package/packages/policies/package.json +21 -0
  376. package/packages/presenter/dist/index.d.ts +81 -0
  377. package/packages/presenter/dist/index.d.ts.map +1 -0
  378. package/packages/presenter/dist/index.js +421 -0
  379. package/packages/presenter/dist/index.js.map +1 -0
  380. package/packages/presenter/package.json +16 -0
  381. package/packages/projections/dist/index.d.ts +10 -0
  382. package/packages/projections/dist/index.d.ts.map +1 -0
  383. package/packages/projections/dist/index.js +30 -0
  384. package/packages/projections/dist/index.js.map +1 -0
  385. package/packages/projections/package.json +15 -0
  386. package/packages/prompt/dist/index.d.ts +9 -0
  387. package/packages/prompt/dist/index.d.ts.map +1 -0
  388. package/packages/prompt/dist/index.js +71 -0
  389. package/packages/prompt/dist/index.js.map +1 -0
  390. package/packages/prompt/package.json +16 -0
  391. package/packages/retry-scheduler/dist/index.d.ts +12 -0
  392. package/packages/retry-scheduler/dist/index.d.ts.map +1 -0
  393. package/packages/retry-scheduler/dist/index.js +39 -0
  394. package/packages/retry-scheduler/dist/index.js.map +1 -0
  395. package/packages/retry-scheduler/package.json +15 -0
  396. package/packages/runtime/dist/index.d.ts +157 -0
  397. package/packages/runtime/dist/index.d.ts.map +1 -0
  398. package/packages/runtime/dist/index.js +1074 -0
  399. package/packages/runtime/dist/index.js.map +1 -0
  400. package/packages/runtime/package.json +26 -0
  401. package/packages/runtime-events/dist/index.d.ts +110 -0
  402. package/packages/runtime-events/dist/index.d.ts.map +1 -0
  403. package/packages/runtime-events/dist/index.js +25 -0
  404. package/packages/runtime-events/dist/index.js.map +1 -0
  405. package/packages/runtime-events/package.json +14 -0
  406. package/packages/server/dist/index.d.ts +25 -0
  407. package/packages/server/dist/index.d.ts.map +1 -0
  408. package/packages/server/dist/index.js +213 -0
  409. package/packages/server/dist/index.js.map +1 -0
  410. package/packages/server/dist/issue-store.d.ts +26 -0
  411. package/packages/server/dist/issue-store.d.ts.map +1 -0
  412. package/packages/server/dist/issue-store.js +88 -0
  413. package/packages/server/dist/issue-store.js.map +1 -0
  414. package/packages/server/dist/path-params.d.ts +6 -0
  415. package/packages/server/dist/path-params.d.ts.map +1 -0
  416. package/packages/server/dist/path-params.js +15 -0
  417. package/packages/server/dist/path-params.js.map +1 -0
  418. package/packages/server/dist/source.d.ts +12 -0
  419. package/packages/server/dist/source.d.ts.map +1 -0
  420. package/packages/server/dist/source.js +2 -0
  421. package/packages/server/dist/source.js.map +1 -0
  422. package/packages/server/dist/trace-routes.d.ts +21 -0
  423. package/packages/server/dist/trace-routes.d.ts.map +1 -0
  424. package/packages/server/dist/trace-routes.js +66 -0
  425. package/packages/server/dist/trace-routes.js.map +1 -0
  426. package/packages/server/dist/ws.d.ts +18 -0
  427. package/packages/server/dist/ws.d.ts.map +1 -0
  428. package/packages/server/dist/ws.js +168 -0
  429. package/packages/server/dist/ws.js.map +1 -0
  430. package/packages/server/package.json +22 -0
  431. package/packages/ssh/dist/index.d.ts +33 -0
  432. package/packages/ssh/dist/index.d.ts.map +1 -0
  433. package/packages/ssh/dist/index.js +281 -0
  434. package/packages/ssh/dist/index.js.map +1 -0
  435. package/packages/ssh/package.json +15 -0
  436. package/packages/static-worker/dist/index.d.ts +73 -0
  437. package/packages/static-worker/dist/index.d.ts.map +1 -0
  438. package/packages/static-worker/dist/index.js +150 -0
  439. package/packages/static-worker/dist/index.js.map +1 -0
  440. package/packages/static-worker/package.json +14 -0
  441. package/packages/tool-sdk/dist/filter.d.ts +70 -0
  442. package/packages/tool-sdk/dist/filter.d.ts.map +1 -0
  443. package/packages/tool-sdk/dist/filter.js +231 -0
  444. package/packages/tool-sdk/dist/filter.js.map +1 -0
  445. package/packages/tool-sdk/dist/index.d.ts +6 -0
  446. package/packages/tool-sdk/dist/index.d.ts.map +1 -0
  447. package/packages/tool-sdk/dist/index.js +4 -0
  448. package/packages/tool-sdk/dist/index.js.map +1 -0
  449. package/packages/tool-sdk/dist/provider.d.ts +51 -0
  450. package/packages/tool-sdk/dist/provider.d.ts.map +1 -0
  451. package/packages/tool-sdk/dist/provider.js +2 -0
  452. package/packages/tool-sdk/dist/provider.js.map +1 -0
  453. package/packages/tool-sdk/dist/registry.d.ts +35 -0
  454. package/packages/tool-sdk/dist/registry.d.ts.map +1 -0
  455. package/packages/tool-sdk/dist/registry.js +85 -0
  456. package/packages/tool-sdk/dist/registry.js.map +1 -0
  457. package/packages/tool-sdk/dist/result.d.ts +5 -0
  458. package/packages/tool-sdk/dist/result.d.ts.map +1 -0
  459. package/packages/tool-sdk/dist/result.js +15 -0
  460. package/packages/tool-sdk/dist/result.js.map +1 -0
  461. package/packages/tool-sdk/package.json +14 -0
  462. package/packages/traceviz-emitter/dist/index.d.ts +19 -0
  463. package/packages/traceviz-emitter/dist/index.d.ts.map +1 -0
  464. package/packages/traceviz-emitter/dist/index.js +97 -0
  465. package/packages/traceviz-emitter/dist/index.js.map +1 -0
  466. package/packages/traceviz-emitter/package.json +17 -0
  467. package/packages/traceviz-server/dist/index.d.ts +14 -0
  468. package/packages/traceviz-server/dist/index.d.ts.map +1 -0
  469. package/packages/traceviz-server/dist/index.js +10 -0
  470. package/packages/traceviz-server/dist/index.js.map +1 -0
  471. package/packages/traceviz-server/dist/models/api.d.ts +51 -0
  472. package/packages/traceviz-server/dist/models/api.d.ts.map +1 -0
  473. package/packages/traceviz-server/dist/models/api.js +5 -0
  474. package/packages/traceviz-server/dist/models/api.js.map +1 -0
  475. package/packages/traceviz-server/dist/models/display-events.d.ts +58 -0
  476. package/packages/traceviz-server/dist/models/display-events.d.ts.map +1 -0
  477. package/packages/traceviz-server/dist/models/display-events.js +6 -0
  478. package/packages/traceviz-server/dist/models/display-events.js.map +1 -0
  479. package/packages/traceviz-server/dist/parser.d.ts +14 -0
  480. package/packages/traceviz-server/dist/parser.d.ts.map +1 -0
  481. package/packages/traceviz-server/dist/parser.js +363 -0
  482. package/packages/traceviz-server/dist/parser.js.map +1 -0
  483. package/packages/traceviz-server/dist/stats.d.ts +7 -0
  484. package/packages/traceviz-server/dist/stats.d.ts.map +1 -0
  485. package/packages/traceviz-server/dist/stats.js +81 -0
  486. package/packages/traceviz-server/dist/stats.js.map +1 -0
  487. package/packages/traceviz-server/dist/watcher.d.ts +54 -0
  488. package/packages/traceviz-server/dist/watcher.d.ts.map +1 -0
  489. package/packages/traceviz-server/dist/watcher.js +368 -0
  490. package/packages/traceviz-server/dist/watcher.js.map +1 -0
  491. package/packages/traceviz-server/package.json +16 -0
  492. package/packages/tracker-sdk/dist/index.d.ts +5 -0
  493. package/packages/tracker-sdk/dist/index.d.ts.map +1 -0
  494. package/packages/tracker-sdk/dist/index.js +4 -0
  495. package/packages/tracker-sdk/dist/index.js.map +1 -0
  496. package/packages/tracker-sdk/dist/options.d.ts +20 -0
  497. package/packages/tracker-sdk/dist/options.d.ts.map +1 -0
  498. package/packages/tracker-sdk/dist/options.js +46 -0
  499. package/packages/tracker-sdk/dist/options.js.map +1 -0
  500. package/packages/tracker-sdk/dist/provider.d.ts +104 -0
  501. package/packages/tracker-sdk/dist/provider.d.ts.map +1 -0
  502. package/packages/tracker-sdk/dist/provider.js +2 -0
  503. package/packages/tracker-sdk/dist/provider.js.map +1 -0
  504. package/packages/tracker-sdk/dist/registry.d.ts +26 -0
  505. package/packages/tracker-sdk/dist/registry.d.ts.map +1 -0
  506. package/packages/tracker-sdk/dist/registry.js +52 -0
  507. package/packages/tracker-sdk/dist/registry.js.map +1 -0
  508. package/packages/tracker-sdk/dist/toolPack.d.ts +10 -0
  509. package/packages/tracker-sdk/dist/toolPack.d.ts.map +1 -0
  510. package/packages/tracker-sdk/dist/toolPack.js +185 -0
  511. package/packages/tracker-sdk/dist/toolPack.js.map +1 -0
  512. package/packages/tracker-sdk/package.json +15 -0
  513. package/packages/tui/dist/index.d.ts +35 -0
  514. package/packages/tui/dist/index.d.ts.map +1 -0
  515. package/packages/tui/dist/index.js +354 -0
  516. package/packages/tui/dist/index.js.map +1 -0
  517. package/packages/tui/package.json +18 -0
  518. package/packages/worker-host-pool/dist/index.d.ts +33 -0
  519. package/packages/worker-host-pool/dist/index.d.ts.map +1 -0
  520. package/packages/worker-host-pool/dist/index.js +311 -0
  521. package/packages/worker-host-pool/dist/index.js.map +1 -0
  522. package/packages/worker-host-pool/package.json +14 -0
  523. package/packages/worker-pool/dist/index.d.ts +6 -0
  524. package/packages/worker-pool/dist/index.d.ts.map +1 -0
  525. package/packages/worker-pool/dist/index.js +15 -0
  526. package/packages/worker-pool/dist/index.js.map +1 -0
  527. package/packages/worker-pool/dist/lease.d.ts +36 -0
  528. package/packages/worker-pool/dist/lease.d.ts.map +1 -0
  529. package/packages/worker-pool/dist/lease.js +53 -0
  530. package/packages/worker-pool/dist/lease.js.map +1 -0
  531. package/packages/worker-pool/dist/ledger.d.ts +51 -0
  532. package/packages/worker-pool/dist/ledger.d.ts.map +1 -0
  533. package/packages/worker-pool/dist/ledger.js +165 -0
  534. package/packages/worker-pool/dist/ledger.js.map +1 -0
  535. package/packages/worker-pool/dist/mutex.d.ts +10 -0
  536. package/packages/worker-pool/dist/mutex.d.ts.map +1 -0
  537. package/packages/worker-pool/dist/mutex.js +22 -0
  538. package/packages/worker-pool/dist/mutex.js.map +1 -0
  539. package/packages/worker-pool/dist/pool.d.ts +33 -0
  540. package/packages/worker-pool/dist/pool.d.ts.map +1 -0
  541. package/packages/worker-pool/dist/pool.js +1727 -0
  542. package/packages/worker-pool/dist/pool.js.map +1 -0
  543. package/packages/worker-pool/dist/reaper.d.ts +94 -0
  544. package/packages/worker-pool/dist/reaper.d.ts.map +1 -0
  545. package/packages/worker-pool/dist/reaper.js +295 -0
  546. package/packages/worker-pool/dist/reaper.js.map +1 -0
  547. package/packages/worker-pool/dist/types.d.ts +249 -0
  548. package/packages/worker-pool/dist/types.d.ts.map +1 -0
  549. package/packages/worker-pool/dist/types.js +2 -0
  550. package/packages/worker-pool/dist/types.js.map +1 -0
  551. package/packages/worker-pool/package.json +16 -0
  552. package/packages/worker-sdk/dist/conformance.d.ts +64 -0
  553. package/packages/worker-sdk/dist/conformance.d.ts.map +1 -0
  554. package/packages/worker-sdk/dist/conformance.js +109 -0
  555. package/packages/worker-sdk/dist/conformance.js.map +1 -0
  556. package/packages/worker-sdk/dist/fake.d.ts +76 -0
  557. package/packages/worker-sdk/dist/fake.d.ts.map +1 -0
  558. package/packages/worker-sdk/dist/fake.js +142 -0
  559. package/packages/worker-sdk/dist/fake.js.map +1 -0
  560. package/packages/worker-sdk/dist/index.d.ts +5 -0
  561. package/packages/worker-sdk/dist/index.d.ts.map +1 -0
  562. package/packages/worker-sdk/dist/index.js +10 -0
  563. package/packages/worker-sdk/dist/index.js.map +1 -0
  564. package/packages/worker-sdk/dist/module.d.ts +46 -0
  565. package/packages/worker-sdk/dist/module.d.ts.map +1 -0
  566. package/packages/worker-sdk/dist/module.js +59 -0
  567. package/packages/worker-sdk/dist/module.js.map +1 -0
  568. package/packages/worker-sdk/dist/registry.d.ts +24 -0
  569. package/packages/worker-sdk/dist/registry.d.ts.map +1 -0
  570. package/packages/worker-sdk/dist/registry.js +49 -0
  571. package/packages/worker-sdk/dist/registry.js.map +1 -0
  572. package/packages/worker-sdk/dist/types.d.ts +138 -0
  573. package/packages/worker-sdk/dist/types.d.ts.map +1 -0
  574. package/packages/worker-sdk/dist/types.js +21 -0
  575. package/packages/worker-sdk/dist/types.js.map +1 -0
  576. package/packages/worker-sdk/package.json +15 -0
  577. package/packages/workflow/dist/index.d.ts +33 -0
  578. package/packages/workflow/dist/index.d.ts.map +1 -0
  579. package/packages/workflow/dist/index.js +125 -0
  580. package/packages/workflow/dist/index.js.map +1 -0
  581. package/packages/workflow/package.json +19 -0
  582. package/packages/workspace/dist/index.d.ts +70 -0
  583. package/packages/workspace/dist/index.d.ts.map +1 -0
  584. package/packages/workspace/dist/index.js +1016 -0
  585. package/packages/workspace/dist/index.js.map +1 -0
  586. package/packages/workspace/package.json +17 -0
  587. package/runtime-deps/anthropic-claude-agent-sdk/LICENSE.md +1 -0
  588. package/runtime-deps/anthropic-claude-agent-sdk/README.md +65 -0
  589. package/runtime-deps/anthropic-claude-agent-sdk/agentSdkTypes.d.ts +1 -0
  590. package/runtime-deps/anthropic-claude-agent-sdk/assistant.d.ts +135 -0
  591. package/runtime-deps/anthropic-claude-agent-sdk/assistant.mjs +190 -0
  592. package/runtime-deps/anthropic-claude-agent-sdk/bridge.d.ts +231 -0
  593. package/runtime-deps/anthropic-claude-agent-sdk/bridge.mjs +168 -0
  594. package/runtime-deps/anthropic-claude-agent-sdk/browser-sdk.d.ts +53 -0
  595. package/runtime-deps/anthropic-claude-agent-sdk/browser-sdk.js +93 -0
  596. package/runtime-deps/anthropic-claude-agent-sdk/extractFromBunfs.d.ts +1 -0
  597. package/runtime-deps/anthropic-claude-agent-sdk/extractFromBunfs.js +156 -0
  598. package/runtime-deps/anthropic-claude-agent-sdk/manifest.json +47 -0
  599. package/runtime-deps/anthropic-claude-agent-sdk/manifest.zst.json +55 -0
  600. package/runtime-deps/anthropic-claude-agent-sdk/node_modules/.bin/anthropic-ai-sdk +21 -0
  601. package/runtime-deps/anthropic-claude-agent-sdk/package.json +81 -0
  602. package/runtime-deps/anthropic-claude-agent-sdk/sdk-tools.d.ts +3170 -0
  603. package/runtime-deps/anthropic-claude-agent-sdk/sdk.d.ts +6000 -0
  604. package/runtime-deps/anthropic-claude-agent-sdk/sdk.mjs +119 -0
  605. package/runtime-deps/openai-codex/README.md +60 -0
  606. package/runtime-deps/openai-codex/bin/codex.js +229 -0
  607. package/runtime-deps/openai-codex/bin/rg +79 -0
  608. package/runtime-deps/openai-codex/package.json +22 -0
  609. package/vendor/claude-agent-acp/dist/acp-agent.d.ts +239 -0
  610. package/vendor/claude-agent-acp/dist/acp-agent.d.ts.map +1 -0
  611. package/vendor/claude-agent-acp/dist/acp-agent.js +2693 -0
  612. package/vendor/claude-agent-acp/dist/bundle.js +41230 -0
  613. package/vendor/claude-agent-acp/dist/index.d.ts +3 -0
  614. package/vendor/claude-agent-acp/dist/index.d.ts.map +1 -0
  615. package/vendor/claude-agent-acp/dist/index.js +67 -0
  616. package/vendor/claude-agent-acp/dist/lib.d.ts +6 -0
  617. package/vendor/claude-agent-acp/dist/lib.d.ts.map +1 -0
  618. package/vendor/claude-agent-acp/dist/lib.js +5 -0
  619. package/vendor/claude-agent-acp/dist/settings.d.ts +68 -0
  620. package/vendor/claude-agent-acp/dist/settings.d.ts.map +1 -0
  621. package/vendor/claude-agent-acp/dist/settings.js +182 -0
  622. package/vendor/claude-agent-acp/dist/tools.d.ts +103 -0
  623. package/vendor/claude-agent-acp/dist/tools.d.ts.map +1 -0
  624. package/vendor/claude-agent-acp/dist/tools.js +713 -0
  625. package/vendor/claude-agent-acp/dist/utils.d.ts +16 -0
  626. package/vendor/claude-agent-acp/dist/utils.d.ts.map +1 -0
  627. package/vendor/claude-agent-acp/dist/utils.js +83 -0
  628. package/vendor/claude-agent-acp/package.json +23 -0
  629. package/vendor/codex-acp/dist/index.js +21280 -0
  630. package/vendor/codex-acp/package.json +17 -0
@@ -0,0 +1,1074 @@
1
+ import { issueHasOpenBlockers, issueIsActive, routedToThisWorker, slotKey } from "@lorenz/dispatch";
2
+ import { reconciliationStopReason } from "@lorenz/policies/reconciliation";
3
+ import { isTerminalState } from "@lorenz/issue";
4
+ import { Orchestrator } from "@lorenz/orchestrator";
5
+ import { settingsForIssueState, validateDispatchConfig } from "@lorenz/config";
6
+ import { runAgentAttempt } from "@lorenz/agent-runner";
7
+ import { ProjectionActor } from "@lorenz/projections";
8
+ import { RetryScheduler } from "@lorenz/retry-scheduler";
9
+ import { workflowFileChanged, workflowStampsEqual } from "@lorenz/workflow";
10
+ import { durationMs, errorMessage, systemClock, withDerivedMaxInFlight, } from "@lorenz/domain";
11
+ import { checkSlotsPerMachineGate, createDispatchCoordinator, nullEndpointManager, } from "@lorenz/dispatch-coordinator";
12
+ export { RUNTIME_EVENT_TYPES, RUNTIME_RUN_OUTCOMES } from "@lorenz/runtime-events";
13
+ export { RUNTIME_RECONCILIATION_REASONS, } from "@lorenz/policies/reconciliation";
14
+ /**
15
+ * Classifies a run error into a worker outcome. Returns `poison` ONLY for typed worker-transport faults
16
+ * (the worker is bad and must be recycled); everything else is `healthy` (a local/config/agent fault
17
+ * that left the worker reusable). Matches typed PREFIXES, not arbitrary substrings, so that
18
+ * `invalid_ssh_timeout` (a local config fault) is never mistaken for the `ssh_timeout` transport
19
+ * fault even though one is a substring of the other.
20
+ */
21
+ const POISON_WORKER_ERROR_PREFIXES = [
22
+ "ssh_timeout:",
23
+ "remote_home_lookup_failed:",
24
+ "workspace_prepare_failed:",
25
+ // A REMOTE workspace hook (run over SSH against the worker's workerHost) that exits
26
+ // non-zero throws `workspace hook failed with status N: ...`. That is a worker-side
27
+ // fault, so it poisons the worker. The LOCAL hook failure string is
28
+ // `hook failed with status N` (no `workspace ` prefix) and stays healthy.
29
+ "workspace hook failed with status ",
30
+ ];
31
+ export function classifyWorkerOutcome(error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ return POISON_WORKER_ERROR_PREFIXES.some((prefix) => message.startsWith(prefix))
34
+ ? "poison"
35
+ : "healthy";
36
+ }
37
+ function pollIntent(options = {}) {
38
+ return {
39
+ dryRun: options.dryRun === true,
40
+ waitForRuns: options.waitForRuns === true,
41
+ };
42
+ }
43
+ function pollOptionsFromIntent(intent) {
44
+ const options = {};
45
+ if (intent.dryRun)
46
+ options.dryRun = true;
47
+ if (intent.waitForRuns)
48
+ options.waitForRuns = true;
49
+ return options;
50
+ }
51
+ function pollOptionsCover(active, requested) {
52
+ const activeIntent = pollIntent(active);
53
+ const requestedIntent = pollIntent(requested);
54
+ return ((!activeIntent.dryRun || requestedIntent.dryRun) &&
55
+ (activeIntent.waitForRuns || !requestedIntent.waitForRuns));
56
+ }
57
+ function mergePollOptions(existing, requested) {
58
+ if (!existing)
59
+ return pollOptionsFromIntent(pollIntent(requested));
60
+ const existingIntent = pollIntent(existing);
61
+ const requestedIntent = pollIntent(requested);
62
+ return pollOptionsFromIntent({
63
+ dryRun: existingIntent.dryRun && requestedIntent.dryRun,
64
+ waitForRuns: existingIntent.waitForRuns || requestedIntent.waitForRuns,
65
+ });
66
+ }
67
+ class ActiveRunHandle {
68
+ key;
69
+ runId;
70
+ activeRuns;
71
+ controller = new AbortController();
72
+ /**
73
+ * Set when the run is force-finished externally (e.g. a stall reconciliation aborts it). The
74
+ * worker pool reads this so a stall-finished run poisons its worker even though the runner surfaces a
75
+ * generic `agent_run_aborted` (which would otherwise classify as healthy).
76
+ */
77
+ reason = null;
78
+ constructor(key, runId, activeRuns) {
79
+ this.key = key;
80
+ this.runId = runId;
81
+ this.activeRuns = activeRuns;
82
+ }
83
+ get signal() {
84
+ return this.controller.signal;
85
+ }
86
+ get isActive() {
87
+ return this.activeRuns.get(this.key) === this;
88
+ }
89
+ abort() {
90
+ this.controller.abort();
91
+ }
92
+ finishExternally(reason = null) {
93
+ if (reason)
94
+ this.reason = reason;
95
+ this.abort();
96
+ this.release();
97
+ }
98
+ release() {
99
+ if (this.isActive)
100
+ this.activeRuns.delete(this.key);
101
+ }
102
+ }
103
+ export class SymphonyRuntime {
104
+ input;
105
+ client;
106
+ orchestrator;
107
+ runner;
108
+ clock;
109
+ validateDispatch;
110
+ listeners = new Set();
111
+ retryScheduler;
112
+ inFlight = new Set();
113
+ stopped = false;
114
+ appStatus = "starting";
115
+ pollStatus = "idle";
116
+ candidates = 0;
117
+ eligible = 0;
118
+ lastPollAt = null;
119
+ nextPollAt = null;
120
+ lastError = null;
121
+ projection = new ProjectionActor();
122
+ activeRuns = new Map();
123
+ startupCleanupDone = false;
124
+ nextRunNumber = 1;
125
+ pollInProgress = null;
126
+ activePollOptions = null;
127
+ pendingPollOptions = null;
128
+ workerPoolDrained = false;
129
+ /**
130
+ * The reload-surviving coordinator singleton. Built ONCE here: either the
131
+ * pre-built `input.coordinator` (preferred), or a null-endpoint passthrough
132
+ * wrapping a bare `input.workerPool` (the low-churn path that keeps every existing
133
+ * workerPool-injecting site byte-identical at the runtime boundary). `undefined`
134
+ * when neither is supplied (the static/local path, byte-identical to today).
135
+ */
136
+ coordinator;
137
+ constructor(input) {
138
+ this.input = input;
139
+ this.client =
140
+ input.client ?? input.clientFactory?.(input.workflow.settings) ?? missingRuntimeClient();
141
+ this.clock = input.clock ?? systemClock;
142
+ // Prefer the pre-built coordinator; otherwise wrap a bare workerPool in a
143
+ // null-endpoint passthrough so `acquireRunSlot`/`governs`/`canAcquire`/
144
+ // `reconcile`/`drain` drive a uniform surface (default slotsPerMachine=1 +
145
+ // mcpEndpoint=null make this a 1:1 passthrough over the pool). Built once: a
146
+ // reload reconciles it in place, never reconstructs it.
147
+ this.coordinator =
148
+ input.coordinator ?? wrapWorkerPoolInCoordinator(input.workerPool, input.workflow.settings);
149
+ const coordinator = this.coordinator;
150
+ this.orchestrator =
151
+ input.orchestrator ??
152
+ new Orchestrator(input.workflow.settings, this.clock, undefined,
153
+ // The coordinator IS the orchestrator's capacity authority (it satisfies
154
+ // the CapacityProbe shape directly). It is installed for the orchestrator's
155
+ // lifetime whenever it exists, but a reload can disable the underlying pool
156
+ // (draining it to zero) without tearing the authority down. `governs`
157
+ // tracks whether the live pool still governs capacity so a disabled pool
158
+ // falls through to static/local execution instead of permanently blocking
159
+ // dispatch as worker_host_capacity. The coordinator is a reload-surviving
160
+ // singleton (stable identity across reconcile) re-reading live pool state
161
+ // on each call.
162
+ coordinator);
163
+ // Poll nudge: when the pool frees capacity (a worker lands warm after the FIFO
164
+ // waiters had first claim), re-poll promptly so a capacity-skipped issue
165
+ // re-dispatches without waiting out polling.intervalMs.
166
+ coordinator?.onCapacityAvailable(() => this.nudgePollForFreedCapacity());
167
+ this.runner = input.runner ?? runAgentAttempt;
168
+ this.validateDispatch = input.validateDispatch ?? validateDispatchConfig;
169
+ this.retryScheduler = new RetryScheduler(this.clock);
170
+ this.appStatus = "idle";
171
+ }
172
+ get workflow() {
173
+ return this.input.workflow;
174
+ }
175
+ subscribe(listener) {
176
+ this.listeners.add(listener);
177
+ listener(this.snapshot());
178
+ return () => {
179
+ this.listeners.delete(listener);
180
+ };
181
+ }
182
+ snapshot() {
183
+ const orchestration = this.orchestrator.snapshot();
184
+ return this.projection.snapshot({
185
+ appStatus: this.appStatus,
186
+ workflowPath: this.workflow.path,
187
+ poll: {
188
+ status: this.pollStatus,
189
+ candidates: this.candidates,
190
+ eligible: this.eligible,
191
+ lastPollAt: this.lastPollAt,
192
+ nextPollAt: this.nextPollAt,
193
+ lastError: this.lastError,
194
+ },
195
+ running: orchestration.running.map((entry) => runtimeRunningEntry(entry, this.activeRuns.get(slotKey(entry.issue.id, entry.slotIndex))?.runId)),
196
+ // In-acquire slots, surfaced honestly (host-less) instead of appearing in
197
+ // `running` with a placeholder host.
198
+ reserving: orchestration.reserving.map((entry) => ({ ...entry })),
199
+ retrying: orchestration.retrying.map(runtimeRetryEntry),
200
+ blocked: orchestration.blocked.map((entry) => ({ ...entry })),
201
+ usageTotals: orchestration.usageTotals,
202
+ rateLimits: orchestration.rateLimits,
203
+ logFile: this.workflow.settings.logging.logFile,
204
+ });
205
+ }
206
+ async start(options = {}) {
207
+ this.stopped = false;
208
+ do {
209
+ if (options.once) {
210
+ await this.pollOnce({ dryRun: options.dryRun, waitForRuns: true });
211
+ break;
212
+ }
213
+ // A thrown poll (e.g. tracker fetchCandidateIssues rejecting) must not
214
+ // terminate the recurring daemon loop. pollOnceUnlocked already records a
215
+ // poll_error event and surfaces the error on the snapshot before rethrowing,
216
+ // so swallow the rejection here and continue to the next interval.
217
+ try {
218
+ await this.pollOnce({ dryRun: options.dryRun });
219
+ }
220
+ catch {
221
+ // Intentionally ignored: the error is already logged as poll_error.
222
+ }
223
+ await delay(this.clock, this.workflow.settings.polling.intervalMs, () => this.stopped);
224
+ } while (!this.stopped);
225
+ }
226
+ stop() {
227
+ this.stopped = true;
228
+ this.appStatus = "stopping";
229
+ this.pendingPollOptions = null;
230
+ // finishExternally (abort + release) mirrors the other abort sites and clears
231
+ // isActive, so the resulting agent_run_aborted rejection is treated as a clean
232
+ // shutdown in runClaim rather than recorded as a failed run.
233
+ for (const handle of [...this.activeRuns.values()])
234
+ handle.finishExternally();
235
+ this.retryScheduler.stop();
236
+ this.emit();
237
+ }
238
+ /**
239
+ * Drains the worker pool once (idempotent). `stop()` stays synchronous (it only flips `stopped` and
240
+ * aborts handles), so this is invoked by the daemon's `finally` AFTER `start()` resolves to
241
+ * destroy paid cloud workers before process exit. A no-op when no pool is configured.
242
+ */
243
+ async drainWorkerPool() {
244
+ if (this.workerPoolDrained)
245
+ return;
246
+ this.workerPoolDrained = true;
247
+ const deadlineMs = this.workflow.settings.worker.workerPool?.drainDeadlineMs ?? 30_000;
248
+ await this.coordinator?.drain({ deadlineMs });
249
+ }
250
+ async pollOnce(options = {}) {
251
+ if (this.pollInProgress) {
252
+ this.queuePendingPoll(options);
253
+ return this.pollInProgress;
254
+ }
255
+ const poll = this.pollUntilQueueDrained(options);
256
+ this.pollInProgress = poll;
257
+ try {
258
+ await poll;
259
+ }
260
+ finally {
261
+ if (this.pollInProgress === poll) {
262
+ this.pollInProgress = null;
263
+ this.activePollOptions = null;
264
+ this.pendingPollOptions = null;
265
+ }
266
+ }
267
+ }
268
+ async pollUntilQueueDrained(options) {
269
+ let nextOptions = options;
270
+ while (true) {
271
+ this.activePollOptions = nextOptions;
272
+ await this.pollOnceUnlocked(nextOptions);
273
+ this.activePollOptions = null;
274
+ const pending = this.pendingPollOptions;
275
+ this.pendingPollOptions = null;
276
+ if (!pending)
277
+ return;
278
+ nextOptions = pending;
279
+ }
280
+ }
281
+ /**
282
+ * Requests a prompt re-poll after the worker pool freed capacity. The pool fires the
283
+ * hook synchronously inside its settle/reconcile paths (under a per-worker mutex), so
284
+ * the nudge is deferred a microtask to never re-enter them on the same stack. A
285
+ * poll already in progress gets a FORCED follow-up poll queued (merged via the
286
+ * pendingPollOptions machinery) because the freed capacity may post-date that
287
+ * poll's eligibility pass.
288
+ */
289
+ nudgePollForFreedCapacity() {
290
+ queueMicrotask(() => {
291
+ if (this.stopped)
292
+ return;
293
+ if (this.pollInProgress) {
294
+ this.queuePendingPoll({}, true);
295
+ return;
296
+ }
297
+ this.pollOnce().catch(() => {
298
+ // Intentionally ignored: pollOnceUnlocked already recorded poll_error.
299
+ });
300
+ });
301
+ }
302
+ queuePendingPoll(options = {}, force = false) {
303
+ if (!force &&
304
+ ((this.activePollOptions && pollOptionsCover(this.activePollOptions, options)) ||
305
+ (this.pendingPollOptions && pollOptionsCover(this.pendingPollOptions, options)))) {
306
+ return;
307
+ }
308
+ this.pendingPollOptions = mergePollOptions(this.pendingPollOptions, options);
309
+ }
310
+ async pollOnceUnlocked(options = {}) {
311
+ this.pollStatus = "checking";
312
+ this.appStatus = this.inFlight.size > 0 ? "running" : "polling";
313
+ this.lastPollAt = this.clock.now().toISOString();
314
+ this.lastError = null;
315
+ this.emit();
316
+ const dispatched = [];
317
+ try {
318
+ await this.reloadWorkflowIfConfigured();
319
+ this.validateDispatch(this.workflow.settings);
320
+ await this.cleanupTerminalWorkspacesOnce();
321
+ this.reconcileStalledRuns();
322
+ await this.reconcileTrackedIssues();
323
+ const issues = await this.client.fetchCandidateIssues();
324
+ const eligibleIssues = this.orchestrator.eligibleIssues(issues);
325
+ if (!options.dryRun)
326
+ this.syncRetryTimersForIssues(issues);
327
+ this.candidates = issues.length;
328
+ this.eligible = eligibleIssues.length;
329
+ if (options.dryRun) {
330
+ this.addEvent("dry_run", `eligible=${eligibleIssues.length} candidates=${issues.length}`);
331
+ }
332
+ else {
333
+ for (const issue of eligibleIssues) {
334
+ dispatched.push(...(await this.maybeDispatch(issue)));
335
+ }
336
+ }
337
+ if (options.waitForRuns) {
338
+ await Promise.allSettled(dispatched);
339
+ }
340
+ this.pollStatus = "idle";
341
+ this.appStatus = this.inFlight.size > 0 ? "running" : "idle";
342
+ this.nextPollAt = new Date(this.clock.now().getTime() + this.workflow.settings.polling.intervalMs).toISOString();
343
+ }
344
+ catch (error) {
345
+ this.pollStatus = "error";
346
+ this.appStatus = "error";
347
+ this.lastError = errorMessage(error);
348
+ this.addEvent("poll_error", this.lastError);
349
+ throw error;
350
+ }
351
+ finally {
352
+ this.emit();
353
+ }
354
+ }
355
+ async maybeDispatch(issue) {
356
+ const refreshed = await this.fetchIssueForDispatch(issue);
357
+ if (!refreshed) {
358
+ this.addEvent("dispatch_skipped", `${issue.identifier} missing_before_dispatch`);
359
+ return [];
360
+ }
361
+ const claim = this.orchestrator.claim(refreshed);
362
+ if (!claim) {
363
+ this.addEvent("dispatch_skipped", `${refreshed.identifier} stale_before_dispatch`);
364
+ return [];
365
+ }
366
+ this.syncRetryTimer(refreshed.id);
367
+ const slotIndex = claim.kind === "running" ? claim.entry.slotIndex : claim.reservation.slotIndex;
368
+ const key = slotKey(refreshed.id, slotIndex);
369
+ const runId = `run-${this.nextRunNumber}`;
370
+ this.nextRunNumber += 1;
371
+ // The handle is registered for the WHOLE run lifecycle - including the reserved
372
+ // path's acquire window - so stop()/reconcile abort an in-acquire run (the
373
+ // signal reaches the pool's FIFO waiter) exactly as they abort a running one.
374
+ const handle = new ActiveRunHandle(key, runId, this.activeRuns);
375
+ this.activeRuns.set(key, handle);
376
+ // On the static/local path the run starts immediately. On the pool-governed
377
+ // path run_reserving marks dispatch intent and run_started moves AFTER
378
+ // bindReservation (inside runReservedClaim): a capacity-refused dispatch
379
+ // never emits a phantom run_started.
380
+ if (claim.kind === "running") {
381
+ this.addEvent("run_started", `${refreshed.identifier} slot=${slotIndex}`);
382
+ }
383
+ else {
384
+ this.addEvent("run_reserving", `${refreshed.identifier} slot=${slotIndex}`);
385
+ }
386
+ this.input.onIssueDispatched?.(refreshed);
387
+ const run = claim.kind === "running"
388
+ ? this.runClaim(refreshed, claim.entry.slotIndex, claim.entry.agentKind, runId, claim.entry.workerHost ?? null, handle)
389
+ : this.runReservedClaim(refreshed, claim.reservation, runId, handle);
390
+ this.inFlight.add(run);
391
+ void run.finally(() => {
392
+ this.inFlight.delete(run);
393
+ this.appStatus = this.inFlight.size > 0 ? "running" : "idle";
394
+ this.emit();
395
+ });
396
+ this.emit();
397
+ return [run];
398
+ }
399
+ async fetchIssueForDispatch(issue) {
400
+ try {
401
+ const refreshed = await this.client.fetchIssuesByIds([issue.id]);
402
+ return refreshed[0] ?? null;
403
+ }
404
+ catch (error) {
405
+ this.addEvent("dispatch_refresh_failed", `${issue.identifier} ${errorMessage(error)}`);
406
+ return null;
407
+ }
408
+ }
409
+ /**
410
+ * Phase 1 -> negotiation -> phase 2 for a pool-governed (reserved) claim: drive the
411
+ * coordinator's acquire inside this detached per-run promise (a cold provision never blocks
412
+ * the poll thread), then either bind the reservation to the CONCRETE `slot.workerHost` and run,
413
+ * or cancel the reservation (restoring the consumed retry entry) on a capacity refusal /
414
+ * acquire fault. `run_started` is only emitted after a successful bind.
415
+ */
416
+ async runReservedClaim(issue, reservation, runId, handle) {
417
+ const coordinator = this.coordinator;
418
+ if (!coordinator) {
419
+ // A reservation can only be minted while a capacity probe governs, which in
420
+ // production implies a coordinator. An injected probe without one (test
421
+ // wiring) is treated like an acquire fault: cancel and skip, never strand.
422
+ this.addEvent("dispatch_skipped", `${issue.identifier} worker_pool_acquire_error coordinator_missing`);
423
+ this.orchestrator.cancelReservation(reservation);
424
+ handle.release();
425
+ return;
426
+ }
427
+ let acquired;
428
+ try {
429
+ acquired = await coordinator.acquireRunSlot({
430
+ issueId: issue.id,
431
+ slotIndex: reservation.slotIndex,
432
+ labels: issue.labels,
433
+ // Sticky retry affinity travels on the reservation (the prior run's
434
+ // CONCRETE host from the consumed retry entry).
435
+ affinityKey: reservation.affinityHost,
436
+ timeoutMs: this.workflow.settings.worker.workerPool?.acquireTimeoutMs ?? 30_000,
437
+ signal: handle.signal,
438
+ // Thread the FULL workflow Settings (with server.port) so the per-run
439
+ // endpoint manager can build the remote endpoint; the WorkerPoolSettings the
440
+ // coordinator holds has no server.port and would fail every acquire.
441
+ settings: this.workflow.settings,
442
+ // The ACP executor - the only executor - consumes the per-run MCP
443
+ // endpoint over the reverse tunnel, so every run needs one. The flag
444
+ // stays on the request so a future executor that runs its tools
445
+ // in-process can skip minting the endpoint (and its tunnel-ceiling
446
+ // reservation) without an API change.
447
+ needsMcpEndpoint: true,
448
+ });
449
+ }
450
+ catch (error) {
451
+ // acquireRunSlot() REJECTED outside the no_capacity result path (ledger /
452
+ // filesystem / driver / endpoint-open fault). Handle it like a failed
453
+ // dispatch rather than letting the rejection strand the reservation: cancel
454
+ // it (restoring the consumed retry entry) so the slot is re-evaluated next
455
+ // poll, release the active handle, surface a clear error event (never
456
+ // swallowed), and return WITHOUT running or recording history. The
457
+ // coordinator already settled any just-bound lease healthy before throwing,
458
+ // so there is nothing to settle here.
459
+ this.addEvent("dispatch_skipped", `${issue.identifier} worker_pool_acquire_error ${errorMessage(error)}`);
460
+ this.orchestrator.cancelReservation(reservation);
461
+ this.syncRetryTimer(issue.id);
462
+ handle.release();
463
+ return;
464
+ }
465
+ if (acquired.status !== "bound") {
466
+ // No capacity within the acquire window (EVERY typed no_capacity reason maps
467
+ // to the SAME event - no per-reason differentiation, matching today): cancel
468
+ // the reservation with NO backoff. The consumed retry entry is RESTORED (its
469
+ // deadline already passed) so the issue is immediately re-eligible with its
470
+ // affinity and attempt counter intact; never record history for a run that
471
+ // did not start.
472
+ this.addEvent("dispatch_skipped", `${issue.identifier} worker_host_capacity`);
473
+ this.orchestrator.cancelReservation(reservation);
474
+ this.syncRetryTimer(issue.id);
475
+ handle.release();
476
+ return;
477
+ }
478
+ const slot = acquired.slot;
479
+ const entry = this.orchestrator.bindReservation(reservation, slot.workerHost);
480
+ if (!entry) {
481
+ // The reservation was cancelled/expired during the acquire (cleanup, stop,
482
+ // or the expiry sweep): release the bound worker back to warm inventory (the
483
+ // slot's settled-once guard makes this exactly-once) and skip the run.
484
+ await slot.release("healthy");
485
+ this.addEvent("dispatch_skipped", `${issue.identifier} reservation_lapsed`);
486
+ handle.release();
487
+ return;
488
+ }
489
+ this.addEvent("run_started", `${issue.identifier} slot=${reservation.slotIndex}`);
490
+ await this.runClaim(issue, reservation.slotIndex, reservation.agentKind, runId, slot.workerHost, handle, slot);
491
+ }
492
+ async runClaim(issue, slotIndex, agentKind, runId, workerHost, handle, slot = null) {
493
+ const startedAt = this.clock.now().toISOString();
494
+ const effectiveWorkerHost = workerHost;
495
+ let workerOutcome = "healthy";
496
+ const heartbeatSlot = slot;
497
+ try {
498
+ const result = await this.runner({
499
+ issue,
500
+ workflow: this.workflow,
501
+ workerHost: effectiveWorkerHost,
502
+ slotIndex,
503
+ // Thread the bound slot's per-run MCP endpoint (or null on the local /
504
+ // non-pool / null-manager path) into the runner so the ACP executor
505
+ // consumes it and SKIPS its own acquire+release. The coordinator owns the
506
+ // whole lease and closes it via slot.release in this run's finally.
507
+ mcpEndpoint: slot?.mcpEndpoint ?? null,
508
+ // With more than one run slot per machine, two solo runs of the SAME
509
+ // issue could land on one worker and would otherwise share a workspace
510
+ // path; force the per-slot suffix whenever co-residence is possible.
511
+ // Single-tenant (default) keeps the bare path.
512
+ forceSlotSuffix: (this.workflow.settings.worker.workerPool?.slotsPerMachine ?? 1) > 1,
513
+ onUpdate: (update) => {
514
+ heartbeatSlot?.heartbeat();
515
+ this.orchestrator.applyUpdate(issue.id, slotIndex, update);
516
+ this.addEvent(update.type, agentUpdateRuntimeMessage(issue.identifier, update));
517
+ this.input.onAgentUpdate?.(issue, update);
518
+ },
519
+ fetchIssue: async (current) => {
520
+ const refreshed = await this.client.fetchIssuesByIds([current.id]);
521
+ return refreshed[0] ?? current;
522
+ },
523
+ abortSignal: handle.signal,
524
+ });
525
+ if (!handle.isActive)
526
+ return;
527
+ const finalIssue = result.finalIssue ?? (await this.fetchIssueOrSelf(issue));
528
+ if (!handle.isActive)
529
+ return;
530
+ const entry = this.runningEntry(issue.id, slotIndex);
531
+ this.orchestrator.finish(issue.id, slotIndex, true, undefined, "continuation");
532
+ this.syncRetryTimer(issue.id);
533
+ this.recordHistory(buildRunHistoryEntry({
534
+ id: runId,
535
+ issue,
536
+ state: finalIssue.state,
537
+ slotIndex,
538
+ agentKind,
539
+ outcome: "success",
540
+ turnCount: result.turnCount,
541
+ runningEntry: entry,
542
+ workspacePath: result.workspace,
543
+ startedAt,
544
+ endedAt: this.clock.now().toISOString(),
545
+ durationMs: durationMs(startedAt, this.clock.now().toISOString()),
546
+ }));
547
+ this.addEvent("run_completed", `${issue.identifier} turns=${result.turnCount}`);
548
+ }
549
+ catch (error) {
550
+ // Classify the worker outcome BEFORE any early return so a run finished
551
+ // externally (e.g. a stall reconciliation aborted it -> the runner throws
552
+ // `agent_run_aborted`) still poisons the worker: a stall-finished run is
553
+ // treated as poison via `handle.reason`, otherwise typed transport faults.
554
+ workerOutcome = handle.reason === "stalled" ? "poison" : classifyWorkerOutcome(error);
555
+ // Skip runs that are no longer active: superseded, finished externally, or
556
+ // released by stop() during shutdown. In the shutdown case the runner
557
+ // rejects with agent_run_aborted; recording it as a failure would emit a
558
+ // run_failed event the TUI renders as a red error banner on Ctrl+C.
559
+ if (!handle.isActive)
560
+ return;
561
+ const entry = this.runningEntry(issue.id, slotIndex);
562
+ if (!handle.isActive)
563
+ return;
564
+ this.orchestrator.finish(issue.id, slotIndex, true, errorMessage(error), "failure");
565
+ this.syncRetryTimer(issue.id);
566
+ this.recordHistory(buildRunHistoryEntry({
567
+ id: runId,
568
+ issue,
569
+ slotIndex,
570
+ agentKind,
571
+ outcome: "failed",
572
+ turnCount: entry?.turnCount ?? 0,
573
+ runningEntry: entry,
574
+ startedAt,
575
+ endedAt: this.clock.now().toISOString(),
576
+ durationMs: durationMs(startedAt, this.clock.now().toISOString()),
577
+ error: errorMessage(error),
578
+ fallbackLastEvent: "turn_failed",
579
+ }));
580
+ this.addEvent("run_failed", `${issue.identifier} ${errorMessage(error)}`);
581
+ }
582
+ finally {
583
+ handle.release();
584
+ if (slot) {
585
+ // A stall reconciliation force-finished this run (handle.reason='stalled').
586
+ // The CATCH path already poisons on a rejected runner, but a runner that
587
+ // ignores the abort - or races to a SUCCESSFUL resolve after finishExternally -
588
+ // takes the success path's early return with workerOutcome still 'healthy'. Poison
589
+ // the worker here, BEFORE settling, whenever the run was stall-finished,
590
+ // independent of whether the runner resolved or rejected: a stalled worker must
591
+ // never be released healthy and reused.
592
+ if (handle.reason === "stalled")
593
+ workerOutcome = "poison";
594
+ // Settle the slot exactly once: close THIS slot's endpoint (a no-op in
595
+ // STEP 1's null-endpoint passthrough) THEN settle the wrapped lease. Lease
596
+ // ops are leaseId + settled + worker-state guarded inside the pool, so a stale
597
+ // generation's late resolve is a no-op that never touches inFlight.
598
+ if (workerOutcome === "poison") {
599
+ await slot.fail("worker_poisoned");
600
+ }
601
+ else {
602
+ await slot.release("healthy");
603
+ }
604
+ }
605
+ }
606
+ }
607
+ async fetchIssueOrSelf(issue) {
608
+ const refreshed = await this.client.fetchIssuesByIds([issue.id]);
609
+ return refreshed[0] ?? issue;
610
+ }
611
+ async reloadWorkflowIfConfigured() {
612
+ if (!this.input.reloadWorkflow)
613
+ return;
614
+ const prevWorkerPool = this.input.workflow.settings.worker.workerPool;
615
+ try {
616
+ if (!(await workflowFileChanged(this.input.workflow)))
617
+ return;
618
+ const previous = this.input.workflow;
619
+ const workflow = await this.input.reloadWorkflow();
620
+ if (workflow === previous || workflowStampsEqual(previous.stamp, workflow.stamp))
621
+ return;
622
+ // Enforce the SAME slots-per-machine co-residence gate the daemon runs at
623
+ // startup. The startup gate runs ONCE; without this a live daemon could
624
+ // reload max_in_flight 1 -> >1 WITHOUT the per-run-endpoint capability OR the
625
+ // co_residence opt-in, silently widening the shared-machine blast radius the
626
+ // startup gate rejects. Throwing here lands in the catch below: last-good
627
+ // settings are KEPT (not applied, the live pool is NOT reconciled onto the
628
+ // unsafe settings) and a workflow_reload_failed event carries the gate's
629
+ // message - mirroring the anti-double-capacity guard behavior.
630
+ const gateMessage = checkSlotsPerMachineGate(workflow.settings.worker.workerPool, this.coordinator?.capabilities);
631
+ if (gateMessage !== null)
632
+ throw new Error(gateMessage);
633
+ // TRANSACTIONAL reload: run EVERY throwing side effect FIRST (the gate above,
634
+ // then the coordinator/pool reconcile), and ONLY swap the runtime settings
635
+ // (this.input.workflow + this.orchestrator.settings + the client) AFTER they
636
+ // ALL succeed. If reconcile throws (e.g. driver unavailable / invalid
637
+ // driverOptions) the catch below leaves BOTH the runtime settings AND the
638
+ // pool/coordinator state on the PREVIOUS config - last-good is never partially
639
+ // applied, so dispatch can never use settings that do not match the live pool.
640
+ //
641
+ // The coordinator (and its pool) is a reload-surviving singleton: diff
642
+ // prev-vs-next worker-pool settings instead of being reconstructed. When the
643
+ // reload REMOVES the worker_pool block entirely (next === undefined), reconcile
644
+ // to a disabled-equivalent of the prior settings so the live pool drains to
645
+ // zero instead of leaking its (paid) workers unmanaged. A present block (even
646
+ // one with `enabled: false`) keeps the existing path: reconcile handles the
647
+ // disable-and-drain itself.
648
+ if (this.coordinator) {
649
+ const next = workflow.settings.worker.workerPool ?? disabledWorkerPoolSettings(prevWorkerPool);
650
+ // Awaited: reconcile is async so the coordinator's injected driverLoader
651
+ // can dynamic-import an out-of-tree driver module BEFORE the (still
652
+ // synchronous) pool reconcile. A rejection lands in the catch below,
653
+ // keeping last-good settings and emitting workflow_reload_failed.
654
+ if (next)
655
+ await this.coordinator.reconcile(next);
656
+ }
657
+ this.input.workflow = workflow;
658
+ this.orchestrator.settings = workflow.settings;
659
+ if (!this.input.client && this.input.clientFactory) {
660
+ this.client = this.input.clientFactory(workflow.settings);
661
+ }
662
+ this.addEvent("workflow_reloaded", workflow.path);
663
+ }
664
+ catch (error) {
665
+ // Keeps last-good settings. errorMessage(error) already surfaces the
666
+ // anti-double-capacity guard message so operators learn why a reload that
667
+ // tried to enable the pool alongside ssh_hosts did not take effect.
668
+ this.addEvent("workflow_reload_failed", errorMessage(error));
669
+ }
670
+ }
671
+ async reconcileTrackedIssues() {
672
+ const snapshot = this.orchestrator.snapshot();
673
+ const tracked = new Map();
674
+ // Reserving (in-acquire) slots are tracked host-less so an issue that goes
675
+ // terminal mid-acquire is still aborted and cleaned up; running/retrying
676
+ // entries below override with their richer metadata when present.
677
+ for (const entry of snapshot.reserving)
678
+ tracked.set(entry.issueId, {
679
+ identifier: entry.identifier,
680
+ workerHost: null,
681
+ workspacePath: null,
682
+ });
683
+ for (const entry of snapshot.running)
684
+ tracked.set(entry.issue.id, {
685
+ identifier: entry.issue.identifier,
686
+ workerHost: entry.workerHost,
687
+ workspacePath: entry.workspacePath,
688
+ });
689
+ for (const entry of snapshot.retrying)
690
+ tracked.set(entry.issueId, {
691
+ identifier: entry.identifier,
692
+ workerHost: entry.workerHost,
693
+ workspacePath: entry.workspacePath,
694
+ });
695
+ if (tracked.size === 0)
696
+ return;
697
+ let refreshed;
698
+ try {
699
+ refreshed = await this.client.fetchIssuesByIds([...tracked.keys()]);
700
+ }
701
+ catch (error) {
702
+ this.addEvent("reconcile_refresh_failed", errorMessage(error));
703
+ return;
704
+ }
705
+ const refreshedIds = new Set(refreshed.map((issue) => issue.id));
706
+ for (const issue of refreshed) {
707
+ if (issueIsActive(issue, this.workflow.settings) &&
708
+ routedToThisWorker(issue, this.workflow.settings) &&
709
+ !issueHasOpenBlockers(issue, this.workflow.settings)) {
710
+ this.orchestrator.refreshRunningIssue(issue);
711
+ continue;
712
+ }
713
+ this.abortIssueRuns(issue.id);
714
+ this.orchestrator.cleanupIssue(issue.id);
715
+ this.clearRetryTimer(issue.id);
716
+ const reason = reconciliationStopReason(issue, this.workflow.settings);
717
+ if (isTerminalState(issue.state, this.workflow.settings.tracker.terminalStates)) {
718
+ await this.removeIssueWorkspaces(this.workflow.settings, issue.identifier || tracked.get(issue.id)?.identifier, tracked.get(issue.id)?.workerHost, issue);
719
+ this.addEvent("workspace_cleanup", `${issue.identifier} ${reason}`);
720
+ }
721
+ else {
722
+ this.addEvent("run_reconciled", `${issue.identifier} ${reason}`);
723
+ }
724
+ }
725
+ for (const [issueId, meta] of tracked.entries()) {
726
+ if (refreshedIds.has(issueId))
727
+ continue;
728
+ this.abortIssueRuns(issueId);
729
+ this.orchestrator.cleanupIssue(issueId);
730
+ this.clearRetryTimer(issueId);
731
+ this.addEvent("run_reconciled", `${meta.identifier} missing`);
732
+ }
733
+ }
734
+ reconcileStalledRuns() {
735
+ for (const snapshotEntry of this.orchestrator.snapshot().running) {
736
+ const currentEntry = this.runningEntry(snapshotEntry.issue.id, snapshotEntry.slotIndex);
737
+ if (!currentEntry)
738
+ continue;
739
+ const effective = settingsForIssueState(this.workflow.settings, currentEntry.issue.state);
740
+ const agent = effective.agents[currentEntry.agentKind];
741
+ if (!agent)
742
+ throw new Error(`agents.${currentEntry.agentKind} is required`);
743
+ const timeoutMs = agent.stallTimeoutMs;
744
+ if (timeoutMs <= 0)
745
+ continue;
746
+ const lastActivity = currentEntry.lastAgentTimestamp ?? currentEntry.startedAt;
747
+ const elapsedMs = this.clock.now().getTime() - lastActivity.getTime();
748
+ if (elapsedMs <= timeoutMs)
749
+ continue;
750
+ const key = slotKey(currentEntry.issue.id, currentEntry.slotIndex);
751
+ const activeHandle = this.activeRuns.get(key);
752
+ const runId = activeHandle?.runId ?? `stalled-${currentEntry.issue.id}-${currentEntry.slotIndex}`;
753
+ const error = `agent_stalled after ${timeoutMs}ms`;
754
+ const entry = this.runningEntry(snapshotEntry.issue.id, snapshotEntry.slotIndex);
755
+ if (!entry)
756
+ continue;
757
+ this.orchestrator.finish(entry.issue.id, entry.slotIndex, true, error, "failure");
758
+ this.syncRetryTimer(entry.issue.id);
759
+ activeHandle?.finishExternally("stalled");
760
+ const endedAt = this.clock.now().toISOString();
761
+ this.recordHistory(buildRunHistoryEntry({
762
+ id: runId,
763
+ issue: entry.issue,
764
+ issueIdentifier: entry.identifier,
765
+ slotIndex: entry.slotIndex,
766
+ agentKind: entry.agentKind,
767
+ outcome: "stalled",
768
+ turnCount: entry.turnCount,
769
+ runningEntry: entry,
770
+ startedAt: entry.startedAt.toISOString(),
771
+ endedAt,
772
+ durationMs: durationMs(entry.startedAt.toISOString(), endedAt),
773
+ error,
774
+ fallbackLastEvent: "agent_stalled",
775
+ }));
776
+ this.addEvent("run_stalled", `${entry.identifier} ${error}`);
777
+ }
778
+ }
779
+ runningEntry(issueId, slotIndex) {
780
+ return this.orchestrator
781
+ .snapshot()
782
+ .running.find((entry) => entry.issue.id === issueId && entry.slotIndex === slotIndex);
783
+ }
784
+ // Cleanup is driven by what is actually on disk: list existing per-issue workspace
785
+ // directories and look up just those issues, instead of enumerating every terminal
786
+ // issue the tracker has ever seen (which scales with project history, not with
787
+ // leftover workspaces, and can blow the tracker request budget on large projects).
788
+ async cleanupTerminalWorkspacesOnce() {
789
+ if (this.startupCleanupDone)
790
+ return;
791
+ this.startupCleanupDone = true;
792
+ if (!this.input.listIssueWorkspaces)
793
+ return;
794
+ try {
795
+ const identifiers = await this.input.listIssueWorkspaces(this.workflow.settings);
796
+ if (identifiers.length === 0)
797
+ return;
798
+ const issues = await this.client.fetchIssuesByIds(identifiers);
799
+ let cleaned = 0;
800
+ for (const issue of issues) {
801
+ if (!isTerminalState(issue.state, this.workflow.settings.tracker.terminalStates))
802
+ continue;
803
+ await this.removeIssueWorkspaces(this.workflow.settings, issue.identifier, undefined, issue);
804
+ cleaned += 1;
805
+ }
806
+ if (cleaned > 0)
807
+ this.addEvent("startup_workspace_cleanup", `terminal=${cleaned}`);
808
+ }
809
+ catch (error) {
810
+ this.addEvent("startup_workspace_cleanup_failed", errorMessage(error));
811
+ }
812
+ }
813
+ abortIssueRuns(issueId) {
814
+ for (const [key, handle] of this.activeRuns.entries()) {
815
+ if (!key.startsWith(`${issueId}:`))
816
+ continue;
817
+ handle.finishExternally();
818
+ }
819
+ }
820
+ syncRetryTimer(issueId) {
821
+ const retry = this.orchestrator.snapshot().retrying.find((entry) => entry.issueId === issueId);
822
+ this.syncRetryTimerEntry(issueId, retry);
823
+ }
824
+ syncRetryTimerEntry(issueId, retry) {
825
+ if (!retry) {
826
+ this.clearRetryTimer(issueId);
827
+ return;
828
+ }
829
+ this.retryScheduler.sync(runtimeRetryEntry(retry), (scheduled) => {
830
+ const current = this.orchestrator
831
+ .snapshot()
832
+ .retrying.find((entry) => entry.issueId === scheduled.issueId);
833
+ if (!current ||
834
+ current.attempt !== scheduled.attempt ||
835
+ current.dueAtIso !== scheduled.dueAtIso) {
836
+ return;
837
+ }
838
+ this.addEvent("retry_timer_due", `${scheduled.issueIdentifier} attempt=${scheduled.attempt}`);
839
+ if (this.pollInProgress) {
840
+ this.queuePendingPoll({}, true);
841
+ return;
842
+ }
843
+ this.pollOnce().catch((error) => {
844
+ this.lastError = errorMessage(error);
845
+ this.addEvent("retry_timer_error", this.lastError);
846
+ });
847
+ });
848
+ }
849
+ clearRetryTimer(issueId) {
850
+ this.retryScheduler.clear(issueId);
851
+ }
852
+ syncRetryTimersForIssues(issues) {
853
+ const retryByIssueId = new Map();
854
+ for (const retry of this.orchestrator.snapshot().retrying) {
855
+ if (!retryByIssueId.has(retry.issueId))
856
+ retryByIssueId.set(retry.issueId, retry);
857
+ }
858
+ for (const issue of issues)
859
+ this.syncRetryTimerEntry(issue.id, retryByIssueId.get(issue.id));
860
+ }
861
+ recordHistory(entry) {
862
+ this.projection.recordRunHistory(entry);
863
+ }
864
+ addEvent(type, message) {
865
+ const event = { type, message, at: this.clock.now().toISOString() };
866
+ this.projection.recordEvent(event);
867
+ void this.appendLogEvent(this.workflow.settings.logging.logFile, {
868
+ at: event.at,
869
+ event: type,
870
+ message,
871
+ }).catch((err) => {
872
+ process.stderr.write(`appendLogEvent failed: ${err}\n`);
873
+ });
874
+ this.emit();
875
+ }
876
+ async removeIssueWorkspaces(settings, issueIdentifier, workerHost, issue) {
877
+ if (this.input.removeIssueWorkspaces) {
878
+ return this.input.removeIssueWorkspaces(settings, issueIdentifier, workerHost, issue, {
879
+ onHookEvent: (message) => this.addEvent("hook_execution", hookExecutionRuntimeMessage(issue?.identifier ?? issueIdentifier ?? "unknown", message)),
880
+ });
881
+ }
882
+ throw new Error("runtime_adapter_missing: removeIssueWorkspaces");
883
+ }
884
+ async appendLogEvent(logFile, event) {
885
+ if (!logFile)
886
+ return;
887
+ if (this.input.appendLogEvent)
888
+ return this.input.appendLogEvent(logFile, event);
889
+ }
890
+ emit() {
891
+ const snapshot = this.snapshot();
892
+ for (const listener of this.listeners)
893
+ listener(snapshot);
894
+ }
895
+ requestRefresh() {
896
+ const coalesced = this.pollStatus === "checking";
897
+ if (!coalesced) {
898
+ this.pollOnce().catch((error) => {
899
+ this.lastError = errorMessage(error);
900
+ this.addEvent("refresh_error", this.lastError);
901
+ });
902
+ }
903
+ return {
904
+ requested_at: this.clock.now().toISOString(),
905
+ queued: true,
906
+ coalesced,
907
+ operations: ["poll", "reconcile"],
908
+ };
909
+ }
910
+ }
911
+ function buildRunHistoryEntry(input) {
912
+ const entry = input.runningEntry;
913
+ const workspacePath = "workspacePath" in input ? input.workspacePath : entry?.workspacePath;
914
+ return {
915
+ id: input.id,
916
+ issueId: input.issue.id,
917
+ issueIdentifier: input.issueIdentifier ?? input.issue.identifier,
918
+ issueTitle: input.issue.title,
919
+ state: "state" in input ? input.state : input.issue.state,
920
+ slotIndex: input.slotIndex,
921
+ ensembleSize: entry?.ensembleSize,
922
+ agentKind: input.agentKind,
923
+ outcome: input.outcome,
924
+ turnCount: input.turnCount,
925
+ sessionId: entry?.sessionId,
926
+ executorPid: entry?.executorPid,
927
+ workspacePath,
928
+ workerHost: entry?.workerHost,
929
+ usageTotals: entry?.usageTotals,
930
+ startedAt: input.startedAt,
931
+ endedAt: input.endedAt,
932
+ durationMs: input.durationMs,
933
+ ...(input.error !== undefined ? { error: input.error } : {}),
934
+ lastEvent: entry?.lastAgentEvent ?? input.fallbackLastEvent,
935
+ lastMessage: entry?.lastAgentMessage,
936
+ lastEventAt: entry?.lastAgentTimestamp?.toISOString() ?? null,
937
+ retryAttempt: entry?.retryAttempt,
938
+ };
939
+ }
940
+ function runtimeRunningEntry(entry, runId) {
941
+ return {
942
+ runId,
943
+ issueId: entry.issue.id,
944
+ issueIdentifier: entry.identifier,
945
+ issueUrl: entry.issue.url ?? null,
946
+ issueTitle: entry.issue.title,
947
+ state: entry.issue.state,
948
+ slotIndex: entry.slotIndex,
949
+ ensembleSize: entry.ensembleSize,
950
+ agentKind: entry.agentKind,
951
+ sessionId: entry.sessionId,
952
+ executorPid: entry.executorPid,
953
+ workerHost: entry.workerHost,
954
+ turnCount: entry.turnCount,
955
+ startedAt: entry.startedAt.toISOString(),
956
+ lastEvent: entry.lastAgentEvent,
957
+ lastMessage: entry.lastAgentMessage,
958
+ lastEventAt: entry.lastAgentTimestamp?.toISOString() ?? null,
959
+ workspacePath: entry.workspacePath,
960
+ usageTotals: { ...entry.usageTotals },
961
+ retryAttempt: entry.retryAttempt,
962
+ };
963
+ }
964
+ function runtimeRetryEntry(entry) {
965
+ return {
966
+ issueId: entry.issueId,
967
+ issueIdentifier: entry.identifier,
968
+ issueUrl: entry.issueUrl ?? null,
969
+ attempt: entry.attempt,
970
+ dueAtIso: entry.dueAtIso,
971
+ monotonicDeadlineMs: entry.monotonicDeadlineMs,
972
+ ...(entry.error !== undefined ? { error: entry.error } : {}),
973
+ ...(entry.slotIndex !== undefined ? { slotIndex: entry.slotIndex } : {}),
974
+ ...(entry.workerHost !== undefined ? { workerHost: entry.workerHost } : {}),
975
+ ...(entry.workspacePath !== undefined ? { workspacePath: entry.workspacePath } : {}),
976
+ };
977
+ }
978
+ function agentUpdateRuntimeMessage(issueIdentifier, update) {
979
+ if (update.type !== "hook_execution")
980
+ return `${issueIdentifier} ${update.type}`;
981
+ return hookExecutionRuntimeMessage(issueIdentifier, update.message);
982
+ }
983
+ function hookExecutionRuntimeMessage(issueIdentifier, message) {
984
+ const hookName = message.hookName ?? "hook";
985
+ const parts = [
986
+ `${issueIdentifier} ${hookName} hook ${message.status}`,
987
+ `command=${inlineLogValue(message.command)}`,
988
+ ];
989
+ if (message.exitCode !== undefined)
990
+ parts.push(`exit_code=${message.exitCode ?? "unknown"}`);
991
+ if (message.error) {
992
+ const suffix = message.errorTruncated ? " (truncated)" : "";
993
+ parts.push(`error=${inlineLogValue(message.error)}${suffix}`);
994
+ }
995
+ if (message.output) {
996
+ const suffix = message.outputTruncated ? " (truncated)" : "";
997
+ parts.push(`output=${inlineLogValue(message.output)}${suffix}`);
998
+ }
999
+ return parts.join(" ");
1000
+ }
1001
+ function inlineLogValue(value) {
1002
+ return JSON.stringify(value.replace(/\s+/g, " ").trim());
1003
+ }
1004
+ async function delay(clock, ms, stopped) {
1005
+ const stepMs = Math.min(Math.max(ms, 25), 250);
1006
+ let remaining = ms;
1007
+ while (remaining > 0 && !stopped()) {
1008
+ await new Promise((resolve) => clock.setTimeout(resolve, Math.min(stepMs, remaining)));
1009
+ remaining -= stepMs;
1010
+ }
1011
+ }
1012
+ function missingRuntimeClient() {
1013
+ throw new Error("runtime tracker client or clientFactory is required");
1014
+ }
1015
+ /**
1016
+ * Builds a disabled-equivalent of the prior worker-pool settings so a reload that REMOVES the
1017
+ * `worker.worker_pool` block (next === undefined) can still reconcile the live pool to a drain
1018
+ * rather than leaking it. Preserves `drainDeadlineMs` from the prior settings so the drain
1019
+ * honors the operator's configured deadline. Returns `undefined` when there were no prior
1020
+ * settings (nothing to drain).
1021
+ */
1022
+ function disabledWorkerPoolSettings(prev) {
1023
+ if (!prev)
1024
+ return undefined;
1025
+ // A bare spread would copy the enumerable `maxInFlight` getter as a plain data property that
1026
+ // could drift from `slotsPerMachine`; strip it and re-install the derived accessor, matching
1027
+ // the config package's parse/clone paths.
1028
+ const { maxInFlight: _maxInFlight, ...rest } = prev;
1029
+ return withDerivedMaxInFlight({ ...rest, enabled: false });
1030
+ }
1031
+ /**
1032
+ * Wraps a bare {@link WorkerPool} in a null-endpoint passthrough {@link DispatchCoordinator} so the
1033
+ * runtime drives every run through the uniform coordinator surface while a bare-pool injection
1034
+ * stays byte-identical at the runtime boundary. STEP 1's null manager mints nothing
1035
+ * (`perRunEndpoint=false`, every `RunSlot.mcpEndpoint=null`), so this is a 1:1 passthrough over
1036
+ * the pool: `acquireRunSlot` delegates to `pool.acquire`, settle delegates straight to the
1037
+ * `WorkerLease`, and `reconcile`/`drain`/`governs`/`canAcquire` forward verbatim. Returns
1038
+ * `undefined` when no pool is supplied (the static/local path).
1039
+ *
1040
+ * `settings` only needs to satisfy the coordinator's constructor; in STEP 1 the coordinator does
1041
+ * not read it past construction (the pool owns live settings), so the live `worker.workerPool`
1042
+ * settings are passed when present and a disabled placeholder otherwise.
1043
+ */
1044
+ function wrapWorkerPoolInCoordinator(pool, settings) {
1045
+ if (!pool)
1046
+ return undefined;
1047
+ // A bare workerPool is only ever injected alongside a configured `worker.worker_pool`
1048
+ // block, so its settings are present in practice. The disabled placeholder is a
1049
+ // defensive fallback for the never-in-practice case; STEP 1's coordinator does
1050
+ // not read `settings` past construction (the pool owns live settings), so the
1051
+ // exact values are irrelevant to behavior - only the shape must satisfy the
1052
+ // constructor.
1053
+ const workerPoolSettings = settings.worker.workerPool ??
1054
+ withDerivedMaxInFlight({
1055
+ enabled: false,
1056
+ driver: "fake",
1057
+ min: 0,
1058
+ max: 0,
1059
+ warm: 0,
1060
+ slotsPerMachine: 1,
1061
+ ttlMs: 0,
1062
+ idleReapMs: 0,
1063
+ acquireTimeoutMs: 0,
1064
+ reapIntervalMs: 0,
1065
+ staleHeartbeatMs: 0,
1066
+ drainDeadlineMs: 0,
1067
+ });
1068
+ return createDispatchCoordinator({
1069
+ pool,
1070
+ mcpEndpointManager: nullEndpointManager,
1071
+ settings: workerPoolSettings,
1072
+ });
1073
+ }
1074
+ //# sourceMappingURL=index.js.map