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,1016 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createReadStream } from "node:fs";
4
+ import os from "node:os";
5
+ import { pipeline } from "node:stream/promises";
6
+ import { Liquid } from "liquidjs";
7
+ import { runSsh, shellEscape, startSshProcess } from "@lorenz/ssh";
8
+ import { errorMessage, } from "@lorenz/domain";
9
+ import { execa } from "execa";
10
+ const remoteWorkspaceMarker = "__SYMPHONY_WORKSPACE__";
11
+ const hookForceKillDelayMs = 5_000;
12
+ const hookLogMaxChars = 4_096;
13
+ const hookTemplateReferencePattern = /(?:\{\{|\{%)[\s\S]*\bissue(?:\.|\[)/;
14
+ const liquidEngine = new Liquid({
15
+ strictVariables: true,
16
+ strictFilters: true,
17
+ outputEscape: shellEscapeOutput,
18
+ });
19
+ liquidEngine.registerFilter("shell_escape", {
20
+ raw: true,
21
+ handler: shellEscapeOutput,
22
+ });
23
+ function shellEscapeOutput(v) {
24
+ if (v == null)
25
+ return "''";
26
+ if (Array.isArray(v))
27
+ return shellEscape(v.join(","));
28
+ if (typeof v === "string")
29
+ return shellEscape(v);
30
+ return shellEscape(JSON.stringify(v));
31
+ }
32
+ async function renderHookCommand(command, context) {
33
+ if (!context.issue)
34
+ return command;
35
+ if (!hookTemplateReferencePattern.test(command))
36
+ return command;
37
+ const issue = context.issue;
38
+ return liquidEngine.parseAndRender(command, {
39
+ issue: {
40
+ id: issue.id,
41
+ identifier: issue.identifier,
42
+ title: issue.title,
43
+ description: issue.description ?? null,
44
+ priority: issue.priority ?? null,
45
+ state: issue.state,
46
+ state_type: issue.stateType ?? null,
47
+ branch_name: issue.branchName ?? null,
48
+ url: issue.url ?? null,
49
+ assignee_id: issue.assigneeId ?? null,
50
+ blocked_by: issue.blockers.map(issueRefHookContext),
51
+ labels: issue.labels,
52
+ assigned_to_worker: issue.assignedToWorker ?? true,
53
+ created_at: issue.createdAt ?? null,
54
+ updated_at: issue.updatedAt ?? null,
55
+ },
56
+ });
57
+ }
58
+ function issueRefHookContext(issue) {
59
+ return {
60
+ id: issue.id ?? null,
61
+ identifier: issue.identifier ?? null,
62
+ state: issue.state ?? null,
63
+ state_type: issue.stateType ?? null,
64
+ };
65
+ }
66
+ export function safeIdentifier(identifier) {
67
+ if (typeof identifier !== "string")
68
+ return "";
69
+ return identifier.replace(/[^A-Za-z0-9_.-]/g, "_");
70
+ }
71
+ function sharedWorkspaceRoot(settings) {
72
+ return settings.workspace.isolation === "none";
73
+ }
74
+ /**
75
+ * The local workspace directory for an issue's run.
76
+ *
77
+ * By default (`forceSlotSuffix = false`) the slot index is appended ONLY for an
78
+ * ensemble (`ensembleSize > 1`); a solo run returns the bare `<root>/<identifier>`.
79
+ *
80
+ * `forceSlotSuffix` is the gated co-residence override: when two run slots of the
81
+ * SAME issue may co-reside on one machine (`slotsPerMachine > 1` with the
82
+ * co-residence opt-in), each is its own solo (`ensembleSize = 1`) run yet must NOT
83
+ * share the bare path, so the slot suffix is applied UNCONDITIONALLY. It is set
84
+ * only on the gated co-residence path and NEVER alters the default single-slot
85
+ * layout (which depends on the bare path).
86
+ */
87
+ export function workspacePath(root, issueIdentifier, slotIndex = 0, ensembleSize = 1, forceSlotSuffix = false) {
88
+ const safe = safeIdentifier(issueIdentifier);
89
+ if (!safe)
90
+ throw new Error("empty identifier produces invalid workspace path");
91
+ const issueRoot = path.join(root, safe);
92
+ return ensembleSize > 1 || forceSlotSuffix ? path.join(issueRoot, String(slotIndex)) : issueRoot;
93
+ }
94
+ export async function createWorkspaceForIssue(settings, issue, options = {}) {
95
+ if (options.workerHost)
96
+ return createRemoteWorkspaceForIssue(settings, issue, options.workerHost, options);
97
+ const identifier = typeof issue === "string" ? issue : issue.identifier;
98
+ const slotIndex = options.slotIndex ?? 0;
99
+ const ensembleSize = options.ensembleSize ?? 1;
100
+ const forceSlotSuffix = options.forceSlotSuffix ?? false;
101
+ const rootPath = path.resolve(settings.workspace.root);
102
+ await fs.mkdir(rootPath, { recursive: true });
103
+ await rejectFinalSymlink(rootPath);
104
+ const canonicalRoot = await fs.realpath(rootPath);
105
+ // Shared workspaces run no lifecycle hooks (config rejects them); canonicalRoot is already
106
+ // realpath'd and symlink-checked above, so creation is done.
107
+ if (sharedWorkspaceRoot(settings)) {
108
+ await applyWorkspaceSkillOverlay(settings, canonicalRoot, null, options);
109
+ return canonicalRoot;
110
+ }
111
+ const target = workspacePath(canonicalRoot, identifier, slotIndex, ensembleSize, forceSlotSuffix);
112
+ const created = await ensureDirectoryWithinRoot(canonicalRoot, target);
113
+ const canonicalTarget = await validateWorkspaceCwd(settings, target);
114
+ if (created && settings.hooks.afterCreate) {
115
+ await runHook(settings.hooks.afterCreate, canonicalTarget, settings.hooks, null, {
116
+ abortSignal: options.abortSignal,
117
+ hookName: "after_create",
118
+ onHookEvent: options.onHookEvent,
119
+ validateCwd: async () => validateWorkspaceCwd(settings, canonicalTarget),
120
+ }, typeof issue === "string" ? undefined : issue);
121
+ }
122
+ await applyWorkspaceSkillOverlay(settings, canonicalTarget, null, options);
123
+ return canonicalTarget;
124
+ }
125
+ /** Run the configured skill overlay for a prepared workspace, sourcing the SSH timeout from settings. */
126
+ async function applyWorkspaceSkillOverlay(settings, workspace, workerHost, options) {
127
+ if (!options.skillOverlay)
128
+ return;
129
+ await syncWorkspaceSkills(workspace, options.skillOverlay, workerHost, {
130
+ abortSignal: options.abortSignal,
131
+ timeoutMs: settings.worker.sshTimeoutMs,
132
+ });
133
+ }
134
+ export async function syncWorkspaceSkills(workspace, overlay, workerHost, options = {}) {
135
+ if (overlay.sources.length === 0)
136
+ return;
137
+ if (options.abortSignal?.aborted)
138
+ throw new Error("workspace_skill_sync_canceled");
139
+ const plans = await workspaceSkillSourcePlans(overlay.sources);
140
+ const destSegments = skillDestinationSegments(overlay.destDir);
141
+ if (workerHost) {
142
+ await syncRemoteWorkspaceSkills(workerHost, workspace, plans, destSegments, {
143
+ abortSignal: options.abortSignal,
144
+ timeoutMs: options.timeoutMs,
145
+ });
146
+ return;
147
+ }
148
+ await syncLocalWorkspaceSkills(workspace, plans, destSegments);
149
+ }
150
+ /** Split an executor-provided destination (e.g. `.codex/skills`) into safe path segments. */
151
+ function skillDestinationSegments(destDir) {
152
+ const segments = destDir.split(/[\\/]+/).filter((segment) => segment !== "");
153
+ if (segments.length === 0 || segments.some((segment) => segment === "." || segment === ".."))
154
+ throw new Error(`workspace_skill_destination_invalid: ${destDir}`);
155
+ return segments;
156
+ }
157
+ export async function removeWorkspace(settings, workspace, issue, options = {}) {
158
+ if (!(await exists(settings.workspace.root)))
159
+ return [];
160
+ const candidate = path.resolve(workspace);
161
+ const canonicalRoot = await fs.realpath(settings.workspace.root);
162
+ if (candidate === canonicalRoot) {
163
+ throw new Error(`refusing to remove workspace root: ${canonicalRoot}`);
164
+ }
165
+ if (!(await exists(candidate)))
166
+ return [];
167
+ if ((await fs.realpath(candidate)) === canonicalRoot) {
168
+ throw new Error(`refusing to remove workspace root: ${canonicalRoot}`);
169
+ }
170
+ const canonicalTarget = await validateWorkspaceCwd(settings, candidate);
171
+ if (settings.hooks.beforeRemove) {
172
+ try {
173
+ await runHook(settings.hooks.beforeRemove, canonicalTarget, settings.hooks, null, {
174
+ hookName: "before_remove",
175
+ onHookEvent: options.onHookEvent,
176
+ validateCwd: async () => validateWorkspaceCwd(settings, canonicalTarget),
177
+ }, issue);
178
+ }
179
+ catch {
180
+ // before_remove is best effort; cleanup should continue.
181
+ }
182
+ }
183
+ await fs.rm(candidate, { recursive: true, force: true });
184
+ return [canonicalTarget];
185
+ }
186
+ export async function removeRemoteWorkspace(settings, workspace, workerHost, issue, options = {}) {
187
+ const canonicalWorkspace = await validateWorkspaceCwd(settings, workspace, workerHost);
188
+ if (settings.hooks.beforeRemove) {
189
+ try {
190
+ await runRemoteHook(workerHost, canonicalWorkspace, settings.hooks.beforeRemove, settings.hooks, { hookName: "before_remove", onHookEvent: options.onHookEvent }, { issue });
191
+ }
192
+ catch {
193
+ // before_remove is best-effort; cleanup should continue.
194
+ }
195
+ }
196
+ const result = await runSsh(workerHost, `rm -rf ${shellEscape(canonicalWorkspace)}`, {
197
+ timeoutMs: settings.hooks.timeoutMs,
198
+ stderrToStdout: true,
199
+ });
200
+ if (result.status !== 0)
201
+ throw new Error(`workspace_remove_failed: ${workerHost} ${result.status} ${result.stdout}`);
202
+ return [];
203
+ }
204
+ export async function removeIssueWorkspaces(settings, identifier, workerHost, issue, options = {}) {
205
+ const resolvedIdentifier = typeof identifier === "string" ? identifier : issue?.identifier;
206
+ if (typeof resolvedIdentifier !== "string")
207
+ return;
208
+ // The shared workspace is the root itself and is never owned by a single issue, so it must
209
+ // outlive any individual run; auto-cleanup would wipe other agents' work.
210
+ if (sharedWorkspaceRoot(settings))
211
+ return;
212
+ if (workerHost) {
213
+ try {
214
+ await removeRemoteIssueWorkspaces(settings, resolvedIdentifier, workerHost, issue, options);
215
+ }
216
+ catch {
217
+ // Issue-level cleanup is best effort.
218
+ }
219
+ return;
220
+ }
221
+ if (await exists(settings.workspace.root)) {
222
+ try {
223
+ const canonicalRoot = await fs.realpath(settings.workspace.root);
224
+ await removeWorkspace(settings, path.join(canonicalRoot, safeIdentifier(resolvedIdentifier)), issue, options);
225
+ }
226
+ catch {
227
+ // Issue-level cleanup is best effort.
228
+ }
229
+ }
230
+ for (const host of settings.worker.sshHosts) {
231
+ try {
232
+ await removeRemoteIssueWorkspaces(settings, resolvedIdentifier, host, issue, options);
233
+ }
234
+ catch {
235
+ // Continue cleaning other worker hosts.
236
+ }
237
+ }
238
+ }
239
+ export async function removeRemoteIssueWorkspaces(settings, identifier, workerHost, issue, options = {}) {
240
+ if (typeof identifier !== "string")
241
+ return;
242
+ const root = await remoteWorkspaceRoot(settings, workerHost);
243
+ await removeRemoteWorkspace(settings, path.posix.join(root, safeIdentifier(identifier)), workerHost, issue, options);
244
+ }
245
+ /**
246
+ * Names of per-issue workspace directories that currently exist under the workspace root,
247
+ * locally and on every configured SSH worker. Directories are created as
248
+ * `safeIdentifier(issue.identifier)`, so the returned names are the (sanitized) issue
249
+ * identifiers that may still own a workspace. Hosts that cannot be listed are skipped:
250
+ * the result feeds best-effort cleanup, never correctness.
251
+ */
252
+ export async function listIssueWorkspaceIdentifiers(settings) {
253
+ if (sharedWorkspaceRoot(settings))
254
+ return [];
255
+ const names = new Set();
256
+ if (await exists(settings.workspace.root)) {
257
+ try {
258
+ const canonicalRoot = await fs.realpath(settings.workspace.root);
259
+ for (const entry of await fs.readdir(canonicalRoot, { withFileTypes: true })) {
260
+ if (entry.isDirectory())
261
+ names.add(entry.name);
262
+ }
263
+ }
264
+ catch {
265
+ // Local listing is best effort.
266
+ }
267
+ }
268
+ for (const host of settings.worker.sshHosts) {
269
+ try {
270
+ const root = await remoteWorkspaceRoot(settings, host);
271
+ const result = await runSsh(host, `[ -d ${shellEscape(root)} ] && find ${shellEscape(root)} -mindepth 1 -maxdepth 1 -type d -exec basename {} \\; || true`, { timeoutMs: settings.worker.sshTimeoutMs, stderrToStdout: false });
272
+ if (result.status !== 0)
273
+ continue;
274
+ for (const line of result.stdout.split("\n")) {
275
+ const name = line.trim();
276
+ if (name)
277
+ names.add(name);
278
+ }
279
+ }
280
+ catch {
281
+ // Continue listing other worker hosts.
282
+ }
283
+ }
284
+ return [...names];
285
+ }
286
+ export async function runHook(command, cwd, hooks, workerHost, options = {}, issue) {
287
+ const templateContext = { issue };
288
+ if (workerHost)
289
+ return runRemoteHook(workerHost, cwd, command, hooks, options, templateContext);
290
+ if (options.abortSignal?.aborted)
291
+ throw new Error("hook canceled");
292
+ const hookCwd = options.validateCwd ? await options.validateCwd() : cwd;
293
+ if (options.abortSignal?.aborted)
294
+ throw new Error("hook canceled");
295
+ let rendered;
296
+ try {
297
+ rendered = await renderHookCommand(command, templateContext);
298
+ }
299
+ catch (error) {
300
+ const logError = truncateHookLogText(errorMessage(error));
301
+ emitHookEvent(options, {
302
+ status: "failed",
303
+ command,
304
+ cwd: hookCwd,
305
+ hookName: options.hookName,
306
+ exitCode: null,
307
+ error: logError.text,
308
+ errorTruncated: logError.truncated,
309
+ });
310
+ throw error;
311
+ }
312
+ emitHookEvent(options, {
313
+ status: "started",
314
+ command: rendered,
315
+ cwd: hookCwd,
316
+ hookName: options.hookName,
317
+ });
318
+ const subprocess = execa("bash", ["-lc", rendered], {
319
+ cwd: hookCwd,
320
+ all: true,
321
+ reject: false,
322
+ stdin: "ignore",
323
+ detached: true,
324
+ });
325
+ let timeoutTimer;
326
+ let forceKillTimer;
327
+ let terminationRequested = false;
328
+ let abortHandler;
329
+ const killProcessGroup = (signal) => {
330
+ if (subprocess.pid === undefined)
331
+ return;
332
+ try {
333
+ process.kill(-subprocess.pid, signal);
334
+ }
335
+ catch {
336
+ /* process already exited */
337
+ }
338
+ };
339
+ const forceKillProcessGroup = () => {
340
+ forceKillTimer ??= setTimeout(() => {
341
+ killProcessGroup("SIGKILL");
342
+ }, hookForceKillDelayMs);
343
+ };
344
+ const clearForceKillTimer = () => {
345
+ if (forceKillTimer !== undefined)
346
+ clearTimeout(forceKillTimer);
347
+ };
348
+ const clearTimers = () => {
349
+ if (timeoutTimer !== undefined)
350
+ clearTimeout(timeoutTimer);
351
+ if (!terminationRequested)
352
+ clearForceKillTimer();
353
+ if (abortHandler)
354
+ options.abortSignal?.removeEventListener("abort", abortHandler);
355
+ };
356
+ const terminate = (error, reject) => {
357
+ terminationRequested = true;
358
+ killProcessGroup("SIGTERM");
359
+ forceKillProcessGroup();
360
+ reject(error);
361
+ };
362
+ const races = [subprocess];
363
+ if (Number.isFinite(hooks.timeoutMs) && hooks.timeoutMs > 0) {
364
+ races.push(new Promise((_resolve, reject) => {
365
+ timeoutTimer = setTimeout(() => {
366
+ terminate(new Error(`hook timed out after ${hooks.timeoutMs}ms`), reject);
367
+ }, hooks.timeoutMs);
368
+ }));
369
+ }
370
+ if (options.abortSignal) {
371
+ races.push(new Promise((_resolve, reject) => {
372
+ abortHandler = () => terminate(new Error("hook canceled"), reject);
373
+ options.abortSignal?.addEventListener("abort", abortHandler, { once: true });
374
+ }));
375
+ }
376
+ void subprocess.then(clearForceKillTimer, clearForceKillTimer);
377
+ let result;
378
+ try {
379
+ result = (await Promise.race(races).finally(clearTimers));
380
+ }
381
+ catch (error) {
382
+ const logError = truncateHookLogText(errorMessage(error));
383
+ emitHookEvent(options, {
384
+ status: "failed",
385
+ command: rendered,
386
+ cwd: hookCwd,
387
+ hookName: options.hookName,
388
+ exitCode: null,
389
+ error: logError.text,
390
+ errorTruncated: logError.truncated,
391
+ });
392
+ throw error;
393
+ }
394
+ const exitCode = typeof result.exitCode === "number" ? result.exitCode : null;
395
+ const output = truncateHookLogText(result.all ?? "");
396
+ if (result.exitCode !== 0) {
397
+ const errorOutput = truncateHookLogText((result.all ?? "").trim());
398
+ const error = new Error(`hook failed with status ${exitCode}: ${errorOutput.text}`);
399
+ emitHookEvent(options, {
400
+ status: "failed",
401
+ command: rendered,
402
+ cwd: hookCwd,
403
+ hookName: options.hookName,
404
+ exitCode,
405
+ output: output.text,
406
+ outputTruncated: output.truncated,
407
+ error: error.message,
408
+ errorTruncated: errorOutput.truncated,
409
+ });
410
+ throw error;
411
+ }
412
+ emitHookEvent(options, {
413
+ status: "completed",
414
+ command: rendered,
415
+ cwd: hookCwd,
416
+ hookName: options.hookName,
417
+ exitCode,
418
+ output: output.text,
419
+ outputTruncated: output.truncated,
420
+ });
421
+ }
422
+ export function ensureInsideRoot(target, root) {
423
+ const relative = path.relative(root, target);
424
+ if (relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)))
425
+ return;
426
+ throw new Error(`workspace outside root: ${target}`);
427
+ }
428
+ export async function validateWorkspaceCwd(settings, workspace, workerHost) {
429
+ if (workerHost)
430
+ return validateRemoteWorkspaceCwd(settings, workspace, workerHost);
431
+ if (invalidWorkspaceInput(workspace))
432
+ throw new Error("invalid_workspace_cwd: blank");
433
+ const rootPath = path.resolve(settings.workspace.root);
434
+ await rejectFinalSymlink(rootPath);
435
+ const canonicalRoot = await fs.realpath(rootPath);
436
+ const candidate = path.resolve(workspace);
437
+ let canonicalTarget;
438
+ try {
439
+ canonicalTarget = await fs.realpath(candidate);
440
+ }
441
+ catch (error) {
442
+ if (error.code === "ENOENT")
443
+ throw new Error(`invalid_workspace_cwd: missing ${candidate}`, { cause: error });
444
+ throw error;
445
+ }
446
+ if (canonicalTarget === canonicalRoot && !sharedWorkspaceRoot(settings))
447
+ throw new Error(`refusing to use workspace root as cwd: ${canonicalRoot}`);
448
+ const candidateInsideRoot = insideRoot(candidate, rootPath) || insideRoot(candidate, canonicalRoot);
449
+ if (!insideRoot(canonicalTarget, canonicalRoot) && candidateInsideRoot) {
450
+ throw new Error(`unsafe symlink in workspace path: ${candidate}`);
451
+ }
452
+ ensureInsideRoot(canonicalTarget, canonicalRoot);
453
+ return canonicalTarget;
454
+ }
455
+ async function exists(filePath) {
456
+ try {
457
+ await fs.lstat(filePath);
458
+ return true;
459
+ }
460
+ catch (error) {
461
+ if (error.code === "ENOENT")
462
+ return false;
463
+ throw error;
464
+ }
465
+ }
466
+ async function rejectFinalSymlink(filePath) {
467
+ const stat = await fs.lstat(filePath);
468
+ if (stat.isSymbolicLink())
469
+ throw new Error(`unsafe symlink in workspace path: ${filePath}`);
470
+ }
471
+ async function ensureDirectoryWithinRoot(canonicalRoot, target) {
472
+ ensureInsideRoot(target, canonicalRoot);
473
+ const relative = path.relative(canonicalRoot, target);
474
+ if (relative === "")
475
+ return false;
476
+ let current = canonicalRoot;
477
+ let created = false;
478
+ const segments = relative.split(path.sep).filter((segment) => segment !== "");
479
+ for (const [index, segment] of segments.entries()) {
480
+ current = path.join(current, segment);
481
+ while (true) {
482
+ try {
483
+ await fs.mkdir(current);
484
+ created = true;
485
+ }
486
+ catch (error) {
487
+ if (error.code !== "EEXIST")
488
+ throw error;
489
+ }
490
+ let stat;
491
+ try {
492
+ stat = await fs.lstat(current);
493
+ }
494
+ catch (error) {
495
+ if (error.code === "ENOENT")
496
+ continue;
497
+ throw error;
498
+ }
499
+ if (stat.isSymbolicLink())
500
+ throw new Error(`unsafe symlink in workspace path: ${current}`);
501
+ if (stat.isDirectory())
502
+ break;
503
+ if (index !== segments.length - 1)
504
+ throw new Error(`workspace path segment is not a directory: ${current}`);
505
+ await fs.rm(current, { recursive: true, force: true });
506
+ created = true;
507
+ }
508
+ }
509
+ return created;
510
+ }
511
+ async function workspaceSkillSourcePlans(sources) {
512
+ const plans = [];
513
+ for (const source of sources) {
514
+ let stat;
515
+ try {
516
+ stat = await fs.lstat(source);
517
+ }
518
+ catch (error) {
519
+ if (error.code === "ENOENT") {
520
+ throw new Error(`workspace_skill_source_missing: ${source}`, { cause: error });
521
+ }
522
+ throw error;
523
+ }
524
+ if (stat.isSymbolicLink()) {
525
+ throw new Error(`workspace_skill_source_symlink: ${source}`);
526
+ }
527
+ // A skill is a directory; its whole tree ships into `<destDir>/<basename>`.
528
+ if (!stat.isDirectory()) {
529
+ throw new Error(`workspace_skill_source_unsupported: ${source}`);
530
+ }
531
+ const normalized = path.resolve(source);
532
+ await rejectSourceTreeSymlinks(normalized);
533
+ const target = path.basename(normalized);
534
+ if (target === "" || target === "." || target === "..")
535
+ throw new Error(`workspace_skill_source_invalid: ${source}`);
536
+ plans.push({
537
+ source: normalized,
538
+ target,
539
+ archiveCwd: path.dirname(normalized),
540
+ archiveEntry: target,
541
+ });
542
+ }
543
+ return plans;
544
+ }
545
+ async function rejectSourceTreeSymlinks(directory) {
546
+ for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
547
+ const entryPath = path.join(directory, entry.name);
548
+ if (entry.isSymbolicLink())
549
+ throw new Error(`workspace_skill_source_symlink: ${entryPath}`);
550
+ if (entry.isDirectory())
551
+ await rejectSourceTreeSymlinks(entryPath);
552
+ }
553
+ }
554
+ async function syncLocalWorkspaceSkills(workspace, plans, destSegments) {
555
+ const skillsRoot = path.join(workspace, ...destSegments);
556
+ await ensureDirectoryPathWithoutSymlinks(workspace, skillsRoot);
557
+ for (const plan of plans) {
558
+ const target = path.join(skillsRoot, plan.target);
559
+ await rejectExistingSymlink(target);
560
+ if (await sameRealPath(plan.source, target))
561
+ continue;
562
+ await fs.rm(target, { recursive: true, force: true });
563
+ await fs.cp(plan.source, target, {
564
+ dereference: true,
565
+ force: true,
566
+ recursive: true,
567
+ });
568
+ }
569
+ }
570
+ async function syncRemoteWorkspaceSkills(workerHost, workspace, plans, destSegments, options) {
571
+ const skillsRoot = path.posix.join(workspace, ...destSegments);
572
+ for (const plan of plans) {
573
+ await syncRemoteWorkspaceSkill(workerHost, skillsRoot, plan, options);
574
+ }
575
+ }
576
+ async function syncRemoteWorkspaceSkill(workerHost, skillsRoot, plan, options) {
577
+ if (options.abortSignal?.aborted)
578
+ throw new Error("workspace_skill_sync_canceled");
579
+ if (options.timeoutMs === undefined ||
580
+ !Number.isInteger(options.timeoutMs) ||
581
+ options.timeoutMs <= 0)
582
+ throw new Error(`invalid_ssh_timeout: ${options.timeoutMs}`);
583
+ const timeoutMs = options.timeoutMs;
584
+ const skillsParent = path.posix.dirname(skillsRoot);
585
+ const targetGuard = `
586
+ target=${shellEscape(path.posix.join(skillsRoot, plan.target))}
587
+ if [ -L "$target" ]; then
588
+ printf '%s\\n' "unsafe symlink in workspace path: $target" >&2
589
+ exit 1
590
+ fi
591
+ rm -rf "$target"`;
592
+ const command = [
593
+ "set -eu",
594
+ `skills_parent=${shellEscape(skillsParent)}`,
595
+ `skills_root=${shellEscape(skillsRoot)}`,
596
+ 'if [ -L "$skills_parent" ] || [ -L "$skills_root" ]; then',
597
+ " printf '%s\\n' \"unsafe symlink in workspace path: $skills_root\" >&2",
598
+ " exit 1",
599
+ "fi",
600
+ 'mkdir -p "$skills_parent"',
601
+ 'if [ -L "$skills_parent" ] || [ ! -d "$skills_parent" ]; then',
602
+ " printf '%s\\n' \"unsafe workspace skill path: $skills_parent\" >&2",
603
+ " exit 1",
604
+ "fi",
605
+ 'mkdir -p "$skills_root"',
606
+ 'if [ -L "$skills_root" ] || [ ! -d "$skills_root" ]; then',
607
+ " printf '%s\\n' \"unsafe workspace skill path: $skills_root\" >&2",
608
+ " exit 1",
609
+ "fi",
610
+ targetGuard,
611
+ `tar -C ${shellEscape(skillsRoot)} -xf -`,
612
+ ]
613
+ .filter(Boolean)
614
+ .join("\n");
615
+ const archiveDir = await fs.mkdtemp(path.join(os.tmpdir(), "symphony-skill-archive-"));
616
+ const archivePath = path.join(archiveDir, "skill.tar");
617
+ let timeoutTimer;
618
+ let forceKillTimer;
619
+ let terminationRequested = false;
620
+ let abortHandler;
621
+ const clearTimers = () => {
622
+ if (timeoutTimer !== undefined)
623
+ clearTimeout(timeoutTimer);
624
+ if (!terminationRequested && forceKillTimer !== undefined)
625
+ clearTimeout(forceKillTimer);
626
+ if (abortHandler)
627
+ options.abortSignal?.removeEventListener("abort", abortHandler);
628
+ };
629
+ try {
630
+ const archiveResult = await execa("tar", ["-C", plan.archiveCwd, "-cf", archivePath, "--", plan.archiveEntry], {
631
+ ...(options.abortSignal ? { cancelSignal: options.abortSignal } : {}),
632
+ reject: false,
633
+ stdin: "ignore",
634
+ });
635
+ if (options.abortSignal?.aborted)
636
+ throw new Error("workspace_skill_sync_canceled");
637
+ if (archiveResult.exitCode !== 0) {
638
+ throw new Error(`workspace_skill_archive_failed: ${plan.source} ${archiveResult.exitCode} ${archiveResult.stderr}`.trim());
639
+ }
640
+ const remote = startSshProcess(workerHost, command);
641
+ const remoteStdout = collectStreamText(remote.stdout);
642
+ const remoteStderr = collectStreamText(remote.stderr);
643
+ const remoteExit = waitForProcessExit(remote);
644
+ const forceKill = () => {
645
+ forceKillTimer ??= setTimeout(() => {
646
+ remote.kill("SIGKILL");
647
+ }, hookForceKillDelayMs);
648
+ };
649
+ const terminate = (error, reject) => {
650
+ terminationRequested = true;
651
+ remote.kill("SIGTERM");
652
+ forceKill();
653
+ reject(error);
654
+ };
655
+ const pipeResult = pipeline(createReadStream(archivePath), remote.stdin).then(() => null, (error) => error);
656
+ const syncResult = Promise.all([remoteExit, remoteStdout, remoteStderr, pipeResult]);
657
+ void syncResult.then(() => {
658
+ if (forceKillTimer !== undefined)
659
+ clearTimeout(forceKillTimer);
660
+ }, () => {
661
+ if (forceKillTimer !== undefined)
662
+ clearTimeout(forceKillTimer);
663
+ });
664
+ const races = [syncResult];
665
+ races.push(new Promise((_resolve, reject) => {
666
+ timeoutTimer = setTimeout(() => {
667
+ terminate(new Error(`workspace_skill_remote_sync_timeout: ${workerHost} ${timeoutMs}`), reject);
668
+ }, timeoutMs);
669
+ }));
670
+ if (options.abortSignal) {
671
+ races.push(new Promise((_resolve, reject) => {
672
+ abortHandler = () => terminate(new Error("workspace_skill_sync_canceled"), reject);
673
+ options.abortSignal?.addEventListener("abort", abortHandler, { once: true });
674
+ }));
675
+ }
676
+ const [remoteResult, remoteOutput, remoteError, pipeError] = (await Promise.race(races).finally(clearTimers));
677
+ if (options.abortSignal?.aborted)
678
+ throw new Error("workspace_skill_sync_canceled");
679
+ if (remoteResult.exitCode !== 0) {
680
+ const output = `${remoteOutput}${remoteOutput && remoteError ? "\n" : ""}${remoteError}`;
681
+ throw new Error(`workspace_skill_remote_sync_failed: ${workerHost} ${remoteResult.exitCode} ${output}`.trim());
682
+ }
683
+ if (pipeError) {
684
+ throw new Error(`workspace_skill_remote_sync_failed: ${workerHost} ${errorMessage(pipeError)}`);
685
+ }
686
+ }
687
+ finally {
688
+ clearTimers();
689
+ await fs.rm(archiveDir, { recursive: true, force: true });
690
+ }
691
+ }
692
+ async function ensureDirectoryPathWithoutSymlinks(root, target) {
693
+ ensureInsideRoot(target, root);
694
+ const relative = path.relative(root, target);
695
+ let current = root;
696
+ const segments = relative.split(path.sep).filter((segment) => segment !== "");
697
+ for (const segment of segments) {
698
+ current = path.join(current, segment);
699
+ while (true) {
700
+ try {
701
+ await fs.mkdir(current);
702
+ }
703
+ catch (error) {
704
+ if (error.code !== "EEXIST")
705
+ throw error;
706
+ }
707
+ let stat;
708
+ try {
709
+ stat = await fs.lstat(current);
710
+ }
711
+ catch (error) {
712
+ if (error.code === "ENOENT")
713
+ continue;
714
+ throw error;
715
+ }
716
+ if (stat.isSymbolicLink())
717
+ throw new Error(`unsafe symlink in workspace path: ${current}`);
718
+ if (!stat.isDirectory())
719
+ throw new Error(`workspace path segment is not a directory: ${current}`);
720
+ break;
721
+ }
722
+ }
723
+ }
724
+ async function rejectExistingSymlink(filePath) {
725
+ let stat;
726
+ try {
727
+ stat = await fs.lstat(filePath);
728
+ }
729
+ catch (error) {
730
+ if (error.code === "ENOENT")
731
+ return;
732
+ throw error;
733
+ }
734
+ if (stat.isSymbolicLink())
735
+ throw new Error(`unsafe symlink in workspace path: ${filePath}`);
736
+ }
737
+ async function sameRealPath(left, right) {
738
+ try {
739
+ const [leftReal, rightReal] = await Promise.all([fs.realpath(left), fs.realpath(right)]);
740
+ return leftReal === rightReal;
741
+ }
742
+ catch (error) {
743
+ if (error.code === "ENOENT")
744
+ return false;
745
+ throw error;
746
+ }
747
+ }
748
+ async function collectStreamText(stream) {
749
+ if (!stream)
750
+ return "";
751
+ let output = "";
752
+ stream.setEncoding("utf8");
753
+ stream.on("data", (chunk) => {
754
+ output += chunk;
755
+ });
756
+ await new Promise((resolve, reject) => {
757
+ stream.on("end", resolve);
758
+ stream.on("error", reject);
759
+ });
760
+ return output.trim();
761
+ }
762
+ async function waitForProcessExit(subprocess) {
763
+ return new Promise((resolve) => {
764
+ subprocess.on("close", (exitCode) => resolve({ exitCode }));
765
+ });
766
+ }
767
+ async function createRemoteWorkspaceForIssue(settings, issue, workerHost, options) {
768
+ const identifier = typeof issue === "string" ? issue : issue.identifier;
769
+ const root = await remoteWorkspaceRoot(settings, workerHost, options);
770
+ const workspace = sharedWorkspaceRoot(settings)
771
+ ? root
772
+ : remoteWorkspacePath(root, identifier, options.slotIndex ?? 0, options.ensembleSize ?? 1, options.forceSlotSuffix ?? false);
773
+ const script = [
774
+ "set -eu",
775
+ `workspace=${shellEscape(workspace)}`,
776
+ 'if [ -d "$workspace" ]; then',
777
+ " created=0",
778
+ 'elif [ -e "$workspace" ]; then',
779
+ ' rm -rf "$workspace"',
780
+ ' mkdir -p "$workspace"',
781
+ " created=1",
782
+ "else",
783
+ ' mkdir -p "$workspace"',
784
+ " created=1",
785
+ "fi",
786
+ 'cd "$workspace"',
787
+ `printf '%s\\t%s\\t%s\\n' ${shellEscape(remoteWorkspaceMarker)} "$created" "$(pwd -P)"`,
788
+ ].join("\n");
789
+ const result = await runSsh(workerHost, script, {
790
+ timeoutMs: settings.hooks.timeoutMs,
791
+ stderrToStdout: true,
792
+ abortSignal: options.abortSignal,
793
+ });
794
+ if (result.status !== 0)
795
+ throw new Error(`workspace_prepare_failed: ${workerHost} ${result.status} ${result.stdout}`);
796
+ const parsed = parseRemoteWorkspaceOutput(result.stdout);
797
+ const canonicalWorkspace = await validateRemoteWorkspaceCwd(settings, parsed.workspace, workerHost, options);
798
+ if (parsed.created && settings.hooks.afterCreate) {
799
+ await runRemoteHook(workerHost, canonicalWorkspace, settings.hooks.afterCreate, settings.hooks, { ...options, hookName: "after_create" }, { issue: typeof issue === "string" ? undefined : issue });
800
+ }
801
+ await applyWorkspaceSkillOverlay(settings, canonicalWorkspace, workerHost, options);
802
+ return canonicalWorkspace;
803
+ }
804
+ async function validateRemoteWorkspaceCwd(settings, workspace, workerHost, options = {}) {
805
+ if (invalidWorkspaceInput(workspace))
806
+ throw new Error("invalid_workspace_cwd: blank");
807
+ const shared = sharedWorkspaceRoot(settings);
808
+ const root = await remoteWorkspaceRoot(settings, workerHost, options);
809
+ ensureRemoteInsideRoot(workspace, root);
810
+ if (!shared && normalizeRemotePath(workspace) === normalizeRemotePath(root)) {
811
+ throw new Error(`refusing to use workspace root as cwd: ${root}`);
812
+ }
813
+ const script = [
814
+ "set -eu",
815
+ `root=${shellEscape(root)}`,
816
+ `workspace=${shellEscape(workspace)}`,
817
+ "canonicalize_path() {",
818
+ ' current="$1"',
819
+ " suffix=''",
820
+ ' while [ ! -e "$current" ] && [ "$current" != "/" ]; do',
821
+ " segment=${current##*/}",
822
+ ' suffix="/$segment$suffix"',
823
+ " current=${current%/*}",
824
+ ' if [ -z "$current" ]; then current="/"; fi',
825
+ " done",
826
+ ' if [ -d "$current" ]; then',
827
+ ' resolved=$(cd "$current" && pwd -P)',
828
+ " else",
829
+ " parent=${current%/*}",
830
+ ' if [ -z "$parent" ]; then parent="/"; fi',
831
+ " segment=${current##*/}",
832
+ ' resolved_parent=$(cd "$parent" && pwd -P)',
833
+ ' if [ "$resolved_parent" = "/" ]; then',
834
+ ' resolved="/$segment"',
835
+ " else",
836
+ ' resolved="$resolved_parent/$segment"',
837
+ " fi",
838
+ " fi",
839
+ ' if [ "$resolved" = "/" ]; then',
840
+ ' printf "/%s\\n" "${suffix#/}"',
841
+ " else",
842
+ ' printf "%s\\n" "$resolved$suffix"',
843
+ " fi",
844
+ "}",
845
+ 'root_real=$(canonicalize_path "$root")',
846
+ 'workspace_real=$(canonicalize_path "$workspace")',
847
+ `printf '%s\\t%s\\t%s\\n' ${shellEscape(remoteWorkspaceMarker)} "$root_real" "$workspace_real"`,
848
+ ].join("\n");
849
+ const result = await runSsh(workerHost, script, {
850
+ timeoutMs: settings.worker.sshTimeoutMs,
851
+ stderrToStdout: true,
852
+ abortSignal: options.abortSignal,
853
+ });
854
+ if (result.status !== 0)
855
+ throw new Error(`invalid_workspace_cwd: ${workerHost} ${result.status} ${result.stdout}`);
856
+ const parsed = parseRemoteWorkspaceValidationOutput(result.stdout);
857
+ if (!remotePathInsideRoot(parsed.workspace, parsed.root)) {
858
+ throw new Error(`invalid_workspace_cwd: symlink_escape ${workspace} -> ${parsed.workspace} outside ${parsed.root}`);
859
+ }
860
+ if (!shared && normalizeRemotePath(parsed.workspace) === normalizeRemotePath(parsed.root)) {
861
+ throw new Error(`refusing to use workspace root as cwd: ${parsed.root}`);
862
+ }
863
+ return parsed.workspace;
864
+ }
865
+ async function runRemoteHook(workerHost, workspace, command, hooks, options = {}, templateContext = {}) {
866
+ let rendered;
867
+ try {
868
+ rendered = await renderHookCommand(command, templateContext);
869
+ }
870
+ catch (error) {
871
+ const logError = truncateHookLogText(errorMessage(error));
872
+ emitHookEvent(options, {
873
+ status: "failed",
874
+ command,
875
+ cwd: workspace,
876
+ hookName: options.hookName,
877
+ workerHost,
878
+ exitCode: null,
879
+ error: logError.text,
880
+ errorTruncated: logError.truncated,
881
+ });
882
+ throw error;
883
+ }
884
+ emitHookEvent(options, {
885
+ status: "started",
886
+ command: rendered,
887
+ cwd: workspace,
888
+ hookName: options.hookName,
889
+ workerHost,
890
+ });
891
+ let result;
892
+ try {
893
+ result = await runSsh(workerHost, `cd ${shellEscape(workspace)} && ${rendered}`, {
894
+ timeoutMs: hooks.timeoutMs,
895
+ stderrToStdout: true,
896
+ abortSignal: options.abortSignal,
897
+ });
898
+ }
899
+ catch (error) {
900
+ const logError = truncateHookLogText(errorMessage(error));
901
+ emitHookEvent(options, {
902
+ status: "failed",
903
+ command: rendered,
904
+ cwd: workspace,
905
+ hookName: options.hookName,
906
+ workerHost,
907
+ exitCode: null,
908
+ error: logError.text,
909
+ errorTruncated: logError.truncated,
910
+ });
911
+ throw error;
912
+ }
913
+ const output = truncateHookLogText(result.stdout);
914
+ if (result.status !== 0) {
915
+ const errorOutput = truncateHookLogText(result.stdout.trim());
916
+ const error = new Error(`workspace hook failed with status ${result.status}: ${errorOutput.text}`);
917
+ emitHookEvent(options, {
918
+ status: "failed",
919
+ command: rendered,
920
+ cwd: workspace,
921
+ hookName: options.hookName,
922
+ workerHost,
923
+ exitCode: result.status,
924
+ output: output.text,
925
+ outputTruncated: output.truncated,
926
+ error: error.message,
927
+ errorTruncated: errorOutput.truncated,
928
+ });
929
+ throw error;
930
+ }
931
+ emitHookEvent(options, {
932
+ status: "completed",
933
+ command: rendered,
934
+ cwd: workspace,
935
+ hookName: options.hookName,
936
+ workerHost,
937
+ exitCode: result.status,
938
+ output: output.text,
939
+ outputTruncated: output.truncated,
940
+ });
941
+ }
942
+ function emitHookEvent(options, event) {
943
+ options.onHookEvent?.(event);
944
+ }
945
+ function truncateHookLogText(text) {
946
+ if (text.length <= hookLogMaxChars)
947
+ return { text, truncated: false };
948
+ return {
949
+ text: `${text.slice(0, hookLogMaxChars)}\n[truncated ${text.length - hookLogMaxChars} chars]`,
950
+ truncated: true,
951
+ };
952
+ }
953
+ async function remoteWorkspaceRoot(settings, workerHost, options = {}) {
954
+ const root = settings.workspace.rootExpression ?? settings.workspace.root;
955
+ if (root === "~" || root.startsWith("~/")) {
956
+ const result = await runSsh(workerHost, 'printf "%s\\n" "$HOME"', {
957
+ timeoutMs: settings.worker.sshTimeoutMs,
958
+ stderrToStdout: true,
959
+ abortSignal: options.abortSignal,
960
+ });
961
+ if (result.status !== 0)
962
+ throw new Error(`remote_home_lookup_failed: ${workerHost} ${result.status} ${result.stdout}`);
963
+ const home = result.stdout.trim();
964
+ if (!home)
965
+ throw new Error(`remote_home_lookup_failed: ${workerHost} empty_home`);
966
+ return root === "~" ? home : path.posix.join(home, root.slice(2));
967
+ }
968
+ return root;
969
+ }
970
+ function remoteWorkspacePath(root, identifier, slotIndex, ensembleSize, forceSlotSuffix = false) {
971
+ const issueRoot = path.posix.join(root, safeIdentifier(identifier));
972
+ return ensembleSize > 1 || forceSlotSuffix
973
+ ? path.posix.join(issueRoot, String(slotIndex))
974
+ : issueRoot;
975
+ }
976
+ function parseRemoteWorkspaceOutput(output) {
977
+ for (const line of output.split(/\r?\n/)) {
978
+ const [marker, created, workspace] = line.split("\t");
979
+ if (marker === remoteWorkspaceMarker && workspace) {
980
+ return { created: created === "1", workspace };
981
+ }
982
+ }
983
+ throw new Error(`workspace_prepare_failed: missing remote workspace marker`);
984
+ }
985
+ function parseRemoteWorkspaceValidationOutput(output) {
986
+ for (const line of output.split(/\r?\n/)) {
987
+ const [marker, root, workspace] = line.split("\t");
988
+ if (marker === remoteWorkspaceMarker && root && workspace)
989
+ return { root, workspace };
990
+ }
991
+ throw new Error("invalid_workspace_cwd: missing remote workspace marker");
992
+ }
993
+ function ensureRemoteInsideRoot(target, root) {
994
+ if (remotePathInsideRoot(target, root))
995
+ return;
996
+ throw new Error(`workspace outside root: ${target}`);
997
+ }
998
+ function remotePathInsideRoot(target, root) {
999
+ const normalizedRoot = normalizeRemotePath(root);
1000
+ const normalizedTarget = normalizeRemotePath(target);
1001
+ if (normalizedRoot === "/")
1002
+ return normalizedTarget.startsWith("/");
1003
+ return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(`${normalizedRoot}/`);
1004
+ }
1005
+ function normalizeRemotePath(value) {
1006
+ const normalized = path.posix.normalize(value);
1007
+ return normalized.endsWith("/") && normalized !== "/" ? normalized.slice(0, -1) : normalized;
1008
+ }
1009
+ function insideRoot(target, root) {
1010
+ const relative = path.relative(root, target);
1011
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
1012
+ }
1013
+ function invalidWorkspaceInput(value) {
1014
+ return !value.trim() || /[\n\r\0]/.test(value);
1015
+ }
1016
+ //# sourceMappingURL=index.js.map