@stoneforge/smithy 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 (497) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +114 -0
  3. package/dist/api/index.d.ts +7 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/api/index.js +7 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/orchestrator-api.d.ts +153 -0
  8. package/dist/api/orchestrator-api.d.ts.map +1 -0
  9. package/dist/api/orchestrator-api.js +374 -0
  10. package/dist/api/orchestrator-api.js.map +1 -0
  11. package/dist/bin/sf.d.ts +3 -0
  12. package/dist/bin/sf.d.ts.map +1 -0
  13. package/dist/bin/sf.js +10 -0
  14. package/dist/bin/sf.js.map +1 -0
  15. package/dist/cli/commands/agent.d.ts +20 -0
  16. package/dist/cli/commands/agent.d.ts.map +1 -0
  17. package/dist/cli/commands/agent.js +861 -0
  18. package/dist/cli/commands/agent.js.map +1 -0
  19. package/dist/cli/commands/daemon.d.ts +14 -0
  20. package/dist/cli/commands/daemon.d.ts.map +1 -0
  21. package/dist/cli/commands/daemon.js +272 -0
  22. package/dist/cli/commands/daemon.js.map +1 -0
  23. package/dist/cli/commands/dispatch.d.ts +9 -0
  24. package/dist/cli/commands/dispatch.d.ts.map +1 -0
  25. package/dist/cli/commands/dispatch.js +128 -0
  26. package/dist/cli/commands/dispatch.js.map +1 -0
  27. package/dist/cli/commands/merge.d.ts +11 -0
  28. package/dist/cli/commands/merge.d.ts.map +1 -0
  29. package/dist/cli/commands/merge.js +246 -0
  30. package/dist/cli/commands/merge.js.map +1 -0
  31. package/dist/cli/commands/pool.d.ts +21 -0
  32. package/dist/cli/commands/pool.d.ts.map +1 -0
  33. package/dist/cli/commands/pool.js +762 -0
  34. package/dist/cli/commands/pool.js.map +1 -0
  35. package/dist/cli/commands/serve.d.ts +54 -0
  36. package/dist/cli/commands/serve.d.ts.map +1 -0
  37. package/dist/cli/commands/serve.js +57 -0
  38. package/dist/cli/commands/serve.js.map +1 -0
  39. package/dist/cli/commands/task.d.ts +36 -0
  40. package/dist/cli/commands/task.d.ts.map +1 -0
  41. package/dist/cli/commands/task.js +889 -0
  42. package/dist/cli/commands/task.js.map +1 -0
  43. package/dist/cli/commands/test-orchestration.d.ts +32 -0
  44. package/dist/cli/commands/test-orchestration.d.ts.map +1 -0
  45. package/dist/cli/commands/test-orchestration.js +392 -0
  46. package/dist/cli/commands/test-orchestration.js.map +1 -0
  47. package/dist/cli/index.d.ts +13 -0
  48. package/dist/cli/index.d.ts.map +1 -0
  49. package/dist/cli/index.js +15 -0
  50. package/dist/cli/index.js.map +1 -0
  51. package/dist/cli/plugin.d.ts +23 -0
  52. package/dist/cli/plugin.d.ts.map +1 -0
  53. package/dist/cli/plugin.js +36 -0
  54. package/dist/cli/plugin.js.map +1 -0
  55. package/dist/git/index.d.ts +10 -0
  56. package/dist/git/index.d.ts.map +1 -0
  57. package/dist/git/index.js +12 -0
  58. package/dist/git/index.js.map +1 -0
  59. package/dist/git/merge.d.ts +79 -0
  60. package/dist/git/merge.d.ts.map +1 -0
  61. package/dist/git/merge.js +254 -0
  62. package/dist/git/merge.js.map +1 -0
  63. package/dist/git/worktree-manager.d.ts +299 -0
  64. package/dist/git/worktree-manager.d.ts.map +1 -0
  65. package/dist/git/worktree-manager.js +744 -0
  66. package/dist/git/worktree-manager.js.map +1 -0
  67. package/dist/index.d.ts +24 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +31 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/prompts/director.md +272 -0
  72. package/dist/prompts/index.d.ts +100 -0
  73. package/dist/prompts/index.d.ts.map +1 -0
  74. package/dist/prompts/index.js +294 -0
  75. package/dist/prompts/index.js.map +1 -0
  76. package/dist/prompts/message-triage.md +50 -0
  77. package/dist/prompts/persistent-worker.md +240 -0
  78. package/dist/prompts/steward-base.md +64 -0
  79. package/dist/prompts/steward-docs.md +118 -0
  80. package/dist/prompts/steward-health.md +39 -0
  81. package/dist/prompts/steward-merge.md +168 -0
  82. package/dist/prompts/steward-ops.md +28 -0
  83. package/dist/prompts/steward-reminder.md +26 -0
  84. package/dist/prompts/worker.md +282 -0
  85. package/dist/providers/claude/headless.d.ts +18 -0
  86. package/dist/providers/claude/headless.d.ts.map +1 -0
  87. package/dist/providers/claude/headless.js +307 -0
  88. package/dist/providers/claude/headless.js.map +1 -0
  89. package/dist/providers/claude/index.d.ts +24 -0
  90. package/dist/providers/claude/index.d.ts.map +1 -0
  91. package/dist/providers/claude/index.js +80 -0
  92. package/dist/providers/claude/index.js.map +1 -0
  93. package/dist/providers/claude/interactive.d.ts +21 -0
  94. package/dist/providers/claude/interactive.d.ts.map +1 -0
  95. package/dist/providers/claude/interactive.js +142 -0
  96. package/dist/providers/claude/interactive.js.map +1 -0
  97. package/dist/providers/codex/event-mapper.d.ts +91 -0
  98. package/dist/providers/codex/event-mapper.d.ts.map +1 -0
  99. package/dist/providers/codex/event-mapper.js +299 -0
  100. package/dist/providers/codex/event-mapper.js.map +1 -0
  101. package/dist/providers/codex/headless.d.ts +20 -0
  102. package/dist/providers/codex/headless.d.ts.map +1 -0
  103. package/dist/providers/codex/headless.js +174 -0
  104. package/dist/providers/codex/headless.js.map +1 -0
  105. package/dist/providers/codex/index.d.ts +30 -0
  106. package/dist/providers/codex/index.d.ts.map +1 -0
  107. package/dist/providers/codex/index.js +55 -0
  108. package/dist/providers/codex/index.js.map +1 -0
  109. package/dist/providers/codex/interactive.d.ts +21 -0
  110. package/dist/providers/codex/interactive.d.ts.map +1 -0
  111. package/dist/providers/codex/interactive.js +141 -0
  112. package/dist/providers/codex/interactive.js.map +1 -0
  113. package/dist/providers/codex/jsonrpc-client.d.ts +52 -0
  114. package/dist/providers/codex/jsonrpc-client.d.ts.map +1 -0
  115. package/dist/providers/codex/jsonrpc-client.js +141 -0
  116. package/dist/providers/codex/jsonrpc-client.js.map +1 -0
  117. package/dist/providers/codex/server-manager.d.ts +100 -0
  118. package/dist/providers/codex/server-manager.d.ts.map +1 -0
  119. package/dist/providers/codex/server-manager.js +153 -0
  120. package/dist/providers/codex/server-manager.js.map +1 -0
  121. package/dist/providers/index.d.ts +15 -0
  122. package/dist/providers/index.d.ts.map +1 -0
  123. package/dist/providers/index.js +19 -0
  124. package/dist/providers/index.js.map +1 -0
  125. package/dist/providers/opencode/async-queue.d.ts +21 -0
  126. package/dist/providers/opencode/async-queue.d.ts.map +1 -0
  127. package/dist/providers/opencode/async-queue.js +51 -0
  128. package/dist/providers/opencode/async-queue.js.map +1 -0
  129. package/dist/providers/opencode/event-mapper.d.ts +132 -0
  130. package/dist/providers/opencode/event-mapper.d.ts.map +1 -0
  131. package/dist/providers/opencode/event-mapper.js +204 -0
  132. package/dist/providers/opencode/event-mapper.js.map +1 -0
  133. package/dist/providers/opencode/headless.d.ts +25 -0
  134. package/dist/providers/opencode/headless.d.ts.map +1 -0
  135. package/dist/providers/opencode/headless.js +190 -0
  136. package/dist/providers/opencode/headless.js.map +1 -0
  137. package/dist/providers/opencode/index.d.ts +33 -0
  138. package/dist/providers/opencode/index.d.ts.map +1 -0
  139. package/dist/providers/opencode/index.js +42 -0
  140. package/dist/providers/opencode/index.js.map +1 -0
  141. package/dist/providers/opencode/interactive.d.ts +21 -0
  142. package/dist/providers/opencode/interactive.d.ts.map +1 -0
  143. package/dist/providers/opencode/interactive.js +135 -0
  144. package/dist/providers/opencode/interactive.js.map +1 -0
  145. package/dist/providers/opencode/server-manager.d.ts +145 -0
  146. package/dist/providers/opencode/server-manager.d.ts.map +1 -0
  147. package/dist/providers/opencode/server-manager.js +163 -0
  148. package/dist/providers/opencode/server-manager.js.map +1 -0
  149. package/dist/providers/registry.d.ts +38 -0
  150. package/dist/providers/registry.d.ts.map +1 -0
  151. package/dist/providers/registry.js +82 -0
  152. package/dist/providers/registry.js.map +1 -0
  153. package/dist/providers/types.d.ts +144 -0
  154. package/dist/providers/types.d.ts.map +1 -0
  155. package/dist/providers/types.js +25 -0
  156. package/dist/providers/types.js.map +1 -0
  157. package/dist/runtime/event-utils.d.ts +8 -0
  158. package/dist/runtime/event-utils.d.ts.map +1 -0
  159. package/dist/runtime/event-utils.js +23 -0
  160. package/dist/runtime/event-utils.js.map +1 -0
  161. package/dist/runtime/handoff.d.ts +195 -0
  162. package/dist/runtime/handoff.d.ts.map +1 -0
  163. package/dist/runtime/handoff.js +332 -0
  164. package/dist/runtime/handoff.js.map +1 -0
  165. package/dist/runtime/index.d.ts +17 -0
  166. package/dist/runtime/index.d.ts.map +1 -0
  167. package/dist/runtime/index.js +60 -0
  168. package/dist/runtime/index.js.map +1 -0
  169. package/dist/runtime/message-mapper.d.ts +99 -0
  170. package/dist/runtime/message-mapper.d.ts.map +1 -0
  171. package/dist/runtime/message-mapper.js +202 -0
  172. package/dist/runtime/message-mapper.js.map +1 -0
  173. package/dist/runtime/predecessor-query.d.ts +212 -0
  174. package/dist/runtime/predecessor-query.d.ts.map +1 -0
  175. package/dist/runtime/predecessor-query.js +283 -0
  176. package/dist/runtime/predecessor-query.js.map +1 -0
  177. package/dist/runtime/session-manager.d.ts +466 -0
  178. package/dist/runtime/session-manager.d.ts.map +1 -0
  179. package/dist/runtime/session-manager.js +986 -0
  180. package/dist/runtime/session-manager.js.map +1 -0
  181. package/dist/runtime/spawner.d.ts +407 -0
  182. package/dist/runtime/spawner.d.ts.map +1 -0
  183. package/dist/runtime/spawner.js +781 -0
  184. package/dist/runtime/spawner.js.map +1 -0
  185. package/dist/server/config.d.ts +22 -0
  186. package/dist/server/config.d.ts.map +1 -0
  187. package/dist/server/config.js +59 -0
  188. package/dist/server/config.js.map +1 -0
  189. package/dist/server/daemon-state.d.ts +50 -0
  190. package/dist/server/daemon-state.d.ts.map +1 -0
  191. package/dist/server/daemon-state.js +100 -0
  192. package/dist/server/daemon-state.js.map +1 -0
  193. package/dist/server/events-websocket.d.ts +32 -0
  194. package/dist/server/events-websocket.d.ts.map +1 -0
  195. package/dist/server/events-websocket.js +96 -0
  196. package/dist/server/events-websocket.js.map +1 -0
  197. package/dist/server/formatters.d.ts +94 -0
  198. package/dist/server/formatters.d.ts.map +1 -0
  199. package/dist/server/formatters.js +142 -0
  200. package/dist/server/formatters.js.map +1 -0
  201. package/dist/server/index.d.ts +17 -0
  202. package/dist/server/index.d.ts.map +1 -0
  203. package/dist/server/index.js +153 -0
  204. package/dist/server/index.js.map +1 -0
  205. package/dist/server/lsp-websocket.d.ts +33 -0
  206. package/dist/server/lsp-websocket.d.ts.map +1 -0
  207. package/dist/server/lsp-websocket.js +161 -0
  208. package/dist/server/lsp-websocket.js.map +1 -0
  209. package/dist/server/routes/agents.d.ts +9 -0
  210. package/dist/server/routes/agents.d.ts.map +1 -0
  211. package/dist/server/routes/agents.js +369 -0
  212. package/dist/server/routes/agents.js.map +1 -0
  213. package/dist/server/routes/daemon.d.ts +13 -0
  214. package/dist/server/routes/daemon.d.ts.map +1 -0
  215. package/dist/server/routes/daemon.js +187 -0
  216. package/dist/server/routes/daemon.js.map +1 -0
  217. package/dist/server/routes/events.d.ts +23 -0
  218. package/dist/server/routes/events.d.ts.map +1 -0
  219. package/dist/server/routes/events.js +282 -0
  220. package/dist/server/routes/events.js.map +1 -0
  221. package/dist/server/routes/extensions.d.ts +9 -0
  222. package/dist/server/routes/extensions.d.ts.map +1 -0
  223. package/dist/server/routes/extensions.js +202 -0
  224. package/dist/server/routes/extensions.js.map +1 -0
  225. package/dist/server/routes/health.d.ts +7 -0
  226. package/dist/server/routes/health.d.ts.map +1 -0
  227. package/dist/server/routes/health.js +33 -0
  228. package/dist/server/routes/health.js.map +1 -0
  229. package/dist/server/routes/index.d.ts +21 -0
  230. package/dist/server/routes/index.d.ts.map +1 -0
  231. package/dist/server/routes/index.js +21 -0
  232. package/dist/server/routes/index.js.map +1 -0
  233. package/dist/server/routes/lsp.d.ts +9 -0
  234. package/dist/server/routes/lsp.d.ts.map +1 -0
  235. package/dist/server/routes/lsp.js +50 -0
  236. package/dist/server/routes/lsp.js.map +1 -0
  237. package/dist/server/routes/plugins.d.ts +9 -0
  238. package/dist/server/routes/plugins.d.ts.map +1 -0
  239. package/dist/server/routes/plugins.js +109 -0
  240. package/dist/server/routes/plugins.js.map +1 -0
  241. package/dist/server/routes/pools.d.ts +9 -0
  242. package/dist/server/routes/pools.d.ts.map +1 -0
  243. package/dist/server/routes/pools.js +189 -0
  244. package/dist/server/routes/pools.js.map +1 -0
  245. package/dist/server/routes/scheduler.d.ts +9 -0
  246. package/dist/server/routes/scheduler.d.ts.map +1 -0
  247. package/dist/server/routes/scheduler.js +162 -0
  248. package/dist/server/routes/scheduler.js.map +1 -0
  249. package/dist/server/routes/sessions.d.ts +27 -0
  250. package/dist/server/routes/sessions.d.ts.map +1 -0
  251. package/dist/server/routes/sessions.js +773 -0
  252. package/dist/server/routes/sessions.js.map +1 -0
  253. package/dist/server/routes/tasks.d.ts +9 -0
  254. package/dist/server/routes/tasks.d.ts.map +1 -0
  255. package/dist/server/routes/tasks.js +954 -0
  256. package/dist/server/routes/tasks.js.map +1 -0
  257. package/dist/server/routes/upload.d.ts +8 -0
  258. package/dist/server/routes/upload.d.ts.map +1 -0
  259. package/dist/server/routes/upload.js +40 -0
  260. package/dist/server/routes/upload.js.map +1 -0
  261. package/dist/server/routes/workflows.d.ts +9 -0
  262. package/dist/server/routes/workflows.d.ts.map +1 -0
  263. package/dist/server/routes/workflows.js +532 -0
  264. package/dist/server/routes/workflows.js.map +1 -0
  265. package/dist/server/routes/workspace-files.d.ts +12 -0
  266. package/dist/server/routes/workspace-files.d.ts.map +1 -0
  267. package/dist/server/routes/workspace-files.js +520 -0
  268. package/dist/server/routes/workspace-files.js.map +1 -0
  269. package/dist/server/routes/worktrees.d.ts +9 -0
  270. package/dist/server/routes/worktrees.d.ts.map +1 -0
  271. package/dist/server/routes/worktrees.js +94 -0
  272. package/dist/server/routes/worktrees.js.map +1 -0
  273. package/dist/server/server.d.ts +14 -0
  274. package/dist/server/server.d.ts.map +1 -0
  275. package/dist/server/server.js +258 -0
  276. package/dist/server/server.js.map +1 -0
  277. package/dist/server/services/lsp-manager.d.ts +93 -0
  278. package/dist/server/services/lsp-manager.d.ts.map +1 -0
  279. package/dist/server/services/lsp-manager.js +291 -0
  280. package/dist/server/services/lsp-manager.js.map +1 -0
  281. package/dist/server/services/session-messages.d.ts +61 -0
  282. package/dist/server/services/session-messages.d.ts.map +1 -0
  283. package/dist/server/services/session-messages.js +101 -0
  284. package/dist/server/services/session-messages.js.map +1 -0
  285. package/dist/server/services.d.ts +35 -0
  286. package/dist/server/services.d.ts.map +1 -0
  287. package/dist/server/services.js +159 -0
  288. package/dist/server/services.js.map +1 -0
  289. package/dist/server/static.d.ts +18 -0
  290. package/dist/server/static.d.ts.map +1 -0
  291. package/dist/server/static.js +71 -0
  292. package/dist/server/static.js.map +1 -0
  293. package/dist/server/types.d.ts +20 -0
  294. package/dist/server/types.d.ts.map +1 -0
  295. package/dist/server/types.js +7 -0
  296. package/dist/server/types.js.map +1 -0
  297. package/dist/server/websocket.d.ts +16 -0
  298. package/dist/server/websocket.d.ts.map +1 -0
  299. package/dist/server/websocket.js +143 -0
  300. package/dist/server/websocket.js.map +1 -0
  301. package/dist/services/agent-pool-service.d.ts +181 -0
  302. package/dist/services/agent-pool-service.d.ts.map +1 -0
  303. package/dist/services/agent-pool-service.js +590 -0
  304. package/dist/services/agent-pool-service.js.map +1 -0
  305. package/dist/services/agent-registry.d.ts +185 -0
  306. package/dist/services/agent-registry.d.ts.map +1 -0
  307. package/dist/services/agent-registry.js +432 -0
  308. package/dist/services/agent-registry.js.map +1 -0
  309. package/dist/services/dispatch-daemon.d.ts +429 -0
  310. package/dist/services/dispatch-daemon.d.ts.map +1 -0
  311. package/dist/services/dispatch-daemon.js +1833 -0
  312. package/dist/services/dispatch-daemon.js.map +1 -0
  313. package/dist/services/dispatch-service.d.ts +148 -0
  314. package/dist/services/dispatch-service.d.ts.map +1 -0
  315. package/dist/services/dispatch-service.js +170 -0
  316. package/dist/services/dispatch-service.js.map +1 -0
  317. package/dist/services/docs-steward-service.d.ts +199 -0
  318. package/dist/services/docs-steward-service.d.ts.map +1 -0
  319. package/dist/services/docs-steward-service.js +599 -0
  320. package/dist/services/docs-steward-service.js.map +1 -0
  321. package/dist/services/health-steward-service.d.ts +446 -0
  322. package/dist/services/health-steward-service.d.ts.map +1 -0
  323. package/dist/services/health-steward-service.js +866 -0
  324. package/dist/services/health-steward-service.js.map +1 -0
  325. package/dist/services/index.d.ts +26 -0
  326. package/dist/services/index.d.ts.map +1 -0
  327. package/dist/services/index.js +111 -0
  328. package/dist/services/index.js.map +1 -0
  329. package/dist/services/merge-request-provider.d.ts +59 -0
  330. package/dist/services/merge-request-provider.d.ts.map +1 -0
  331. package/dist/services/merge-request-provider.js +89 -0
  332. package/dist/services/merge-request-provider.js.map +1 -0
  333. package/dist/services/merge-steward-service.d.ts +268 -0
  334. package/dist/services/merge-steward-service.d.ts.map +1 -0
  335. package/dist/services/merge-steward-service.js +568 -0
  336. package/dist/services/merge-steward-service.js.map +1 -0
  337. package/dist/services/plugin-executor.d.ts +247 -0
  338. package/dist/services/plugin-executor.d.ts.map +1 -0
  339. package/dist/services/plugin-executor.js +451 -0
  340. package/dist/services/plugin-executor.js.map +1 -0
  341. package/dist/services/role-definition-service.d.ts +117 -0
  342. package/dist/services/role-definition-service.d.ts.map +1 -0
  343. package/dist/services/role-definition-service.js +289 -0
  344. package/dist/services/role-definition-service.js.map +1 -0
  345. package/dist/services/steward-scheduler.d.ts +336 -0
  346. package/dist/services/steward-scheduler.d.ts.map +1 -0
  347. package/dist/services/steward-scheduler.js +732 -0
  348. package/dist/services/steward-scheduler.js.map +1 -0
  349. package/dist/services/task-assignment-service.d.ts +291 -0
  350. package/dist/services/task-assignment-service.d.ts.map +1 -0
  351. package/dist/services/task-assignment-service.js +454 -0
  352. package/dist/services/task-assignment-service.js.map +1 -0
  353. package/dist/services/worker-task-service.d.ts +202 -0
  354. package/dist/services/worker-task-service.d.ts.map +1 -0
  355. package/dist/services/worker-task-service.js +228 -0
  356. package/dist/services/worker-task-service.js.map +1 -0
  357. package/dist/testing/index.d.ts +13 -0
  358. package/dist/testing/index.d.ts.map +1 -0
  359. package/dist/testing/index.js +17 -0
  360. package/dist/testing/index.js.map +1 -0
  361. package/dist/testing/orchestration-tests.d.ts +62 -0
  362. package/dist/testing/orchestration-tests.d.ts.map +1 -0
  363. package/dist/testing/orchestration-tests.js +1115 -0
  364. package/dist/testing/orchestration-tests.js.map +1 -0
  365. package/dist/testing/test-context.d.ts +171 -0
  366. package/dist/testing/test-context.d.ts.map +1 -0
  367. package/dist/testing/test-context.js +665 -0
  368. package/dist/testing/test-context.js.map +1 -0
  369. package/dist/testing/test-prompts.d.ts +46 -0
  370. package/dist/testing/test-prompts.d.ts.map +1 -0
  371. package/dist/testing/test-prompts.js +140 -0
  372. package/dist/testing/test-prompts.js.map +1 -0
  373. package/dist/testing/test-utils.d.ts +200 -0
  374. package/dist/testing/test-utils.d.ts.map +1 -0
  375. package/dist/testing/test-utils.js +378 -0
  376. package/dist/testing/test-utils.js.map +1 -0
  377. package/dist/types/agent-pool.d.ts +215 -0
  378. package/dist/types/agent-pool.d.ts.map +1 -0
  379. package/dist/types/agent-pool.js +143 -0
  380. package/dist/types/agent-pool.js.map +1 -0
  381. package/dist/types/agent.d.ts +265 -0
  382. package/dist/types/agent.d.ts.map +1 -0
  383. package/dist/types/agent.js +127 -0
  384. package/dist/types/agent.js.map +1 -0
  385. package/dist/types/index.d.ts +11 -0
  386. package/dist/types/index.d.ts.map +1 -0
  387. package/dist/types/index.js +40 -0
  388. package/dist/types/index.js.map +1 -0
  389. package/dist/types/message-types.d.ts +294 -0
  390. package/dist/types/message-types.d.ts.map +1 -0
  391. package/dist/types/message-types.js +354 -0
  392. package/dist/types/message-types.js.map +1 -0
  393. package/dist/types/role-definition.d.ts +272 -0
  394. package/dist/types/role-definition.d.ts.map +1 -0
  395. package/dist/types/role-definition.js +144 -0
  396. package/dist/types/role-definition.js.map +1 -0
  397. package/dist/types/task-meta.d.ts +248 -0
  398. package/dist/types/task-meta.d.ts.map +1 -0
  399. package/dist/types/task-meta.js +213 -0
  400. package/dist/types/task-meta.js.map +1 -0
  401. package/package.json +120 -0
  402. package/web/assets/abap-BrgZPUOV.js +6 -0
  403. package/web/assets/apex-DyP6w7ZV.js +6 -0
  404. package/web/assets/azcli-BaLxmfj-.js +6 -0
  405. package/web/assets/bat-CFOPXBzS.js +6 -0
  406. package/web/assets/bicep-BfEKNvv3.js +7 -0
  407. package/web/assets/cameligo-BFG1Mk7z.js +6 -0
  408. package/web/assets/clojure-DTECt2xU.js +6 -0
  409. package/web/assets/codicon-DCmgc-ay.ttf +0 -0
  410. package/web/assets/coffee-CDGzqUPQ.js +6 -0
  411. package/web/assets/cpp-CLLBncYj.js +6 -0
  412. package/web/assets/csharp-dUCx_-0o.js +6 -0
  413. package/web/assets/csp-5Rap-vPy.js +6 -0
  414. package/web/assets/css-D3h14YRZ.js +8 -0
  415. package/web/assets/cssMode-DMo-5YLA.js +9 -0
  416. package/web/assets/cypher-DrQuvNYM.js +6 -0
  417. package/web/assets/dart-CFKIUWau.js +6 -0
  418. package/web/assets/dockerfile-Zznr-cwX.js +6 -0
  419. package/web/assets/ecl-Ce3n6wWz.js +6 -0
  420. package/web/assets/elixir-deUWdS0T.js +6 -0
  421. package/web/assets/flow9-i9-g7ZhI.js +6 -0
  422. package/web/assets/freemarker2-D4qgkQzN.js +8 -0
  423. package/web/assets/fsharp-CzKuDChf.js +6 -0
  424. package/web/assets/go-Cphgjts3.js +6 -0
  425. package/web/assets/graphql-Cg7bfA9N.js +6 -0
  426. package/web/assets/handlebars-CXFvNjQC.js +6 -0
  427. package/web/assets/hcl-0cvrggvQ.js +6 -0
  428. package/web/assets/html-oyuB_D-B.js +6 -0
  429. package/web/assets/htmlMode-iWuZ24-r.js +9 -0
  430. package/web/assets/index-DqP-_E4F.css +32 -0
  431. package/web/assets/index-R1cylSgw.js +1665 -0
  432. package/web/assets/ini-Drc7WvVn.js +6 -0
  433. package/web/assets/java-B_fMsGYe.js +6 -0
  434. package/web/assets/javascript-CRIkN2Pg.js +6 -0
  435. package/web/assets/jsonMode-DVDkDgex.js +15 -0
  436. package/web/assets/julia-Bqgm2twL.js +6 -0
  437. package/web/assets/kotlin-BSkB5QuD.js +6 -0
  438. package/web/assets/less-BsTHnhdd.js +7 -0
  439. package/web/assets/lexon-YWi4-JPR.js +6 -0
  440. package/web/assets/liquid-CSfldbB5.js +6 -0
  441. package/web/assets/lua-nf6ki56Z.js +6 -0
  442. package/web/assets/m3-Cpb6xl2v.js +6 -0
  443. package/web/assets/markdown-DSZPf7rp.js +6 -0
  444. package/web/assets/mdx-Dd58iymR.js +6 -0
  445. package/web/assets/mips-B_c3zf-v.js +6 -0
  446. package/web/assets/monaco-editor-B4lwqA13.js +751 -0
  447. package/web/assets/monaco-editor-CQpyCxOA.css +1 -0
  448. package/web/assets/msdax-rUNN04Wq.js +6 -0
  449. package/web/assets/mysql-DDwshQtU.js +6 -0
  450. package/web/assets/objective-c-B5zXfXm9.js +6 -0
  451. package/web/assets/pascal-CXOwvkN_.js +6 -0
  452. package/web/assets/pascaligo-Bc-ZgV77.js +6 -0
  453. package/web/assets/perl-CwNk8-XU.js +6 -0
  454. package/web/assets/pgsql-tGk8EFnU.js +6 -0
  455. package/web/assets/php-CpIb_Oan.js +6 -0
  456. package/web/assets/pla-B03wrqEc.js +6 -0
  457. package/web/assets/postiats-BKlk5iyT.js +6 -0
  458. package/web/assets/powerquery-Bhzvs7bI.js +6 -0
  459. package/web/assets/powershell-Dd3NCNK9.js +6 -0
  460. package/web/assets/protobuf-COyEY5Pt.js +7 -0
  461. package/web/assets/pug-BaJupSGV.js +6 -0
  462. package/web/assets/python-XWrMqdhO.js +6 -0
  463. package/web/assets/qsharp-DXyYeYxl.js +6 -0
  464. package/web/assets/r-CdQndTaG.js +6 -0
  465. package/web/assets/razor-DPlhCpIs.js +6 -0
  466. package/web/assets/redis-CVwtpugi.js +6 -0
  467. package/web/assets/redshift-25W9uPmb.js +6 -0
  468. package/web/assets/restructuredtext-DfzH4Xui.js +6 -0
  469. package/web/assets/router-vendor-DHlGizSU.js +41 -0
  470. package/web/assets/ruby-Cp1zYvxS.js +6 -0
  471. package/web/assets/rust-D5C2fndG.js +6 -0
  472. package/web/assets/sb-CDntyWJ8.js +6 -0
  473. package/web/assets/scala-BoFRg7Ot.js +6 -0
  474. package/web/assets/scheme-Bio4gycK.js +6 -0
  475. package/web/assets/scss-4Ik7cdeQ.js +8 -0
  476. package/web/assets/shell-CX-rkNHf.js +6 -0
  477. package/web/assets/solidity-Tw7wswEv.js +6 -0
  478. package/web/assets/sophia-C5WLch3f.js +6 -0
  479. package/web/assets/sparql-DHaeiCBh.js +6 -0
  480. package/web/assets/sql-CCSDG5nI.js +6 -0
  481. package/web/assets/st-pnP8ivHi.js +6 -0
  482. package/web/assets/swift-DwJ7jVG9.js +8 -0
  483. package/web/assets/systemverilog-B9Xyijhd.js +6 -0
  484. package/web/assets/tcl-DnHyzjbg.js +6 -0
  485. package/web/assets/tsMode-BbA1Jbf3.js +16 -0
  486. package/web/assets/twig-CPajHgWi.js +6 -0
  487. package/web/assets/typescript-DcLHYzvH.js +6 -0
  488. package/web/assets/typespec-D-MeaMDU.js +6 -0
  489. package/web/assets/ui-vendor-BSco96uv.js +51 -0
  490. package/web/assets/utils-vendor-DaJ2Dubl.js +911 -0
  491. package/web/assets/vb-DgyLZaXg.js +6 -0
  492. package/web/assets/wgsl-DYQUnd45.js +303 -0
  493. package/web/assets/xml-xKYS3dO6.js +6 -0
  494. package/web/assets/yaml-CNmlXqzH.js +6 -0
  495. package/web/favicon.ico +0 -0
  496. package/web/index.html +22 -0
  497. package/web/logo.png +0 -0
@@ -0,0 +1,744 @@
1
+ /**
2
+ * Worktree Manager
3
+ *
4
+ * This module provides git worktree management for the orchestration system.
5
+ * Each worker agent gets a dedicated git worktree for true parallel development.
6
+ *
7
+ * Key features:
8
+ * - Verify git repo exists before operations
9
+ * - Create isolated worktrees for workers
10
+ * - Branch naming: agent/{worker-name}/{task-id}-{slug}
11
+ * - Worktree path: .stoneforge/.worktrees/{worker-name}-{task-slug}/
12
+ * - Clean up worktrees after merge
13
+ *
14
+ * @module
15
+ */
16
+ import { execFile } from 'node:child_process';
17
+ import { promisify } from 'node:util';
18
+ import * as path from 'node:path';
19
+ import * as fs from 'node:fs';
20
+ import { createTimestamp } from '@stoneforge/core';
21
+ import { generateBranchName, generateWorktreePath, createSlugFromTitle, } from '../types/task-meta.js';
22
+ const execFileAsync = promisify(execFile);
23
+ /** Default timeout for git operations (30 seconds) */
24
+ const GIT_OPERATION_TIMEOUT_MS = 30_000;
25
+ /**
26
+ * All valid worktree states
27
+ */
28
+ export const WorktreeStates = [
29
+ 'creating',
30
+ 'active',
31
+ 'suspended',
32
+ 'merging',
33
+ 'cleaning',
34
+ 'archived',
35
+ ];
36
+ /**
37
+ * Valid state transitions for worktrees
38
+ */
39
+ export const WorktreeStateTransitions = {
40
+ creating: ['active', 'cleaning'],
41
+ active: ['suspended', 'merging', 'cleaning'],
42
+ suspended: ['active', 'cleaning'],
43
+ merging: ['archived', 'cleaning', 'active'],
44
+ cleaning: ['archived'],
45
+ archived: [],
46
+ };
47
+ /**
48
+ * Error thrown when git repository is not found
49
+ */
50
+ export class GitRepositoryNotFoundError extends Error {
51
+ constructor(path) {
52
+ super(`Git repository not found at ${path}.\n\n` +
53
+ `The orchestrator requires an existing git repository.\n` +
54
+ `Please initialize a git repository first:\n\n` +
55
+ ` cd ${path}\n` +
56
+ ` git init\n` +
57
+ ` git add .\n` +
58
+ ` git commit -m "Initial commit"\n`);
59
+ this.name = 'GitRepositoryNotFoundError';
60
+ }
61
+ }
62
+ /**
63
+ * Error thrown when a worktree operation fails
64
+ */
65
+ export class WorktreeError extends Error {
66
+ code;
67
+ details;
68
+ constructor(message, code, details) {
69
+ super(message);
70
+ this.name = 'WorktreeError';
71
+ this.code = code;
72
+ this.details = details;
73
+ }
74
+ }
75
+ // ============================================================================
76
+ // WorktreeManager Implementation
77
+ // ============================================================================
78
+ /**
79
+ * Implementation of the WorktreeManager.
80
+ */
81
+ export class WorktreeManagerImpl {
82
+ config;
83
+ initialized = false;
84
+ defaultBranch;
85
+ worktreeStates = new Map();
86
+ realWorkspaceRoot;
87
+ constructor(config) {
88
+ this.config = {
89
+ workspaceRoot: path.resolve(config.workspaceRoot),
90
+ worktreeDir: config.worktreeDir ?? '.stoneforge/.worktrees',
91
+ defaultBaseBranch: config.defaultBaseBranch ?? '',
92
+ };
93
+ }
94
+ // ----------------------------------------
95
+ // Initialization
96
+ // ----------------------------------------
97
+ async initWorkspace() {
98
+ const gitDir = path.join(this.config.workspaceRoot, '.git');
99
+ // Check if .git exists (could be a file for worktrees or a directory)
100
+ if (!fs.existsSync(gitDir)) {
101
+ throw new GitRepositoryNotFoundError(this.config.workspaceRoot);
102
+ }
103
+ // Verify it's actually a git repository by running a git command
104
+ try {
105
+ await this.execGit(['rev-parse', '--git-dir']);
106
+ }
107
+ catch {
108
+ throw new GitRepositoryNotFoundError(this.config.workspaceRoot);
109
+ }
110
+ // Create worktree directory if it doesn't exist
111
+ const worktreeDir = path.join(this.config.workspaceRoot, this.config.worktreeDir);
112
+ if (!fs.existsSync(worktreeDir)) {
113
+ fs.mkdirSync(worktreeDir, { recursive: true });
114
+ }
115
+ // Add worktree directory to .gitignore if not already there
116
+ await this.ensureGitignore();
117
+ // Cache the default branch
118
+ this.defaultBranch = await this.detectDefaultBranch();
119
+ // Prune stale worktree entries (directories removed but git still tracks them)
120
+ await this.execGit(['worktree', 'prune']);
121
+ // Resolve real path (handles symlinks like /tmp -> /private/tmp on macOS)
122
+ try {
123
+ this.realWorkspaceRoot = fs.realpathSync(this.config.workspaceRoot);
124
+ }
125
+ catch {
126
+ this.realWorkspaceRoot = this.config.workspaceRoot;
127
+ }
128
+ this.initialized = true;
129
+ }
130
+ isInitialized() {
131
+ return this.initialized;
132
+ }
133
+ getWorkspaceRoot() {
134
+ return this.config.workspaceRoot;
135
+ }
136
+ // ----------------------------------------
137
+ // Worktree Operations
138
+ // ----------------------------------------
139
+ async createWorktree(options) {
140
+ this.ensureInitialized();
141
+ // Generate paths and branch name
142
+ const slug = options.taskTitle ? createSlugFromTitle(options.taskTitle) : undefined;
143
+ const branch = options.customBranch ?? generateBranchName(options.agentName, options.taskId, slug);
144
+ const relativePath = options.customPath ?? generateWorktreePath(options.agentName, slug);
145
+ const fullPath = path.join(this.config.workspaceRoot, relativePath);
146
+ // Check if worktree already exists
147
+ if (fs.existsSync(fullPath)) {
148
+ throw new WorktreeError(`Worktree already exists at ${relativePath}`, 'WORKTREE_EXISTS');
149
+ }
150
+ // Track state
151
+ this.worktreeStates.set(relativePath, 'creating');
152
+ let branchCreated = false;
153
+ const baseBranch = options.baseBranch ?? await this.getDefaultBranch();
154
+ // Fetch latest remote state so origin/<baseBranch> is up to date.
155
+ // Without this, worktrees branch from the (possibly stale) local ref
156
+ // and may be missing recently merged dependencies/code.
157
+ try {
158
+ await this.execGit(['fetch', 'origin', baseBranch]);
159
+ }
160
+ catch {
161
+ // Non-fatal: remote may not exist or be unreachable
162
+ }
163
+ // Use origin/<baseBranch> as the start point for new worktrees so they
164
+ // always include the latest merged code, even when the local branch ref
165
+ // has fallen behind. Falls back to the local branch if the remote ref
166
+ // doesn't exist (e.g. no remote configured).
167
+ let startPoint = baseBranch;
168
+ try {
169
+ await this.execGit(['rev-parse', '--verify', `origin/${baseBranch}`]);
170
+ startPoint = `origin/${baseBranch}`;
171
+ }
172
+ catch {
173
+ // origin/<baseBranch> doesn't exist — use local branch
174
+ }
175
+ try {
176
+ // Check if branch exists
177
+ const branchExists = await this.branchExists(branch);
178
+ if (branchExists) {
179
+ // Branch exists, create worktree checking out existing branch
180
+ await this.execGit(['worktree', 'add', fullPath, branch]);
181
+ }
182
+ else {
183
+ // Create new branch from the latest remote base
184
+ await this.execGit(['worktree', 'add', '-b', branch, fullPath, startPoint]);
185
+ branchCreated = true;
186
+ // Set up tracking if requested
187
+ if (options.trackRemote !== false) {
188
+ try {
189
+ // Try to set upstream (may fail if remote doesn't exist)
190
+ await this.execGit(['branch', '--set-upstream-to', `origin/${baseBranch}`, branch]);
191
+ }
192
+ catch {
193
+ // Ignore - remote may not exist
194
+ }
195
+ }
196
+ }
197
+ // Install dependencies if requested
198
+ if (options.installDependencies) {
199
+ await this.installDependencies(fullPath);
200
+ }
201
+ // Update state to active
202
+ this.worktreeStates.set(relativePath, 'active');
203
+ // Get worktree info
204
+ const worktree = await this.getWorktree(relativePath);
205
+ if (!worktree) {
206
+ throw new WorktreeError('Failed to get worktree info after creation', 'WORKTREE_INFO_FAILED');
207
+ }
208
+ // Attach additional metadata
209
+ const enrichedWorktree = {
210
+ ...worktree,
211
+ agentName: options.agentName,
212
+ taskId: options.taskId,
213
+ createdAt: createTimestamp(),
214
+ state: 'active',
215
+ };
216
+ return {
217
+ worktree: enrichedWorktree,
218
+ branch,
219
+ path: fullPath,
220
+ branchCreated,
221
+ };
222
+ }
223
+ catch (error) {
224
+ // Clean up on failure
225
+ this.worktreeStates.delete(relativePath);
226
+ if (fs.existsSync(fullPath)) {
227
+ try {
228
+ await this.execGit(['worktree', 'remove', '--force', fullPath]);
229
+ }
230
+ catch {
231
+ // Ignore cleanup errors
232
+ }
233
+ }
234
+ throw error;
235
+ }
236
+ }
237
+ /**
238
+ * Create a read-only (detached HEAD) worktree for triage sessions.
239
+ * Uses `git worktree add --detach` so no new branch is created.
240
+ */
241
+ async createReadOnlyWorktree(options) {
242
+ this.ensureInitialized();
243
+ const relativePath = `.stoneforge/.worktrees/${options.agentName}-${options.purpose}`;
244
+ const fullPath = path.join(this.config.workspaceRoot, relativePath);
245
+ if (fs.existsSync(fullPath)) {
246
+ throw new WorktreeError(`Worktree already exists at ${relativePath}`, 'WORKTREE_EXISTS');
247
+ }
248
+ this.worktreeStates.set(relativePath, 'creating');
249
+ try {
250
+ const baseBranch = await this.getDefaultBranch();
251
+ // Fetch latest remote state so read-only worktrees see the latest code
252
+ try {
253
+ await this.execGit(['fetch', 'origin', baseBranch]);
254
+ }
255
+ catch {
256
+ // Non-fatal: remote may not exist
257
+ }
258
+ // Use origin/<baseBranch> if available for latest code
259
+ let startPoint = baseBranch;
260
+ try {
261
+ await this.execGit(['rev-parse', '--verify', `origin/${baseBranch}`]);
262
+ startPoint = `origin/${baseBranch}`;
263
+ }
264
+ catch {
265
+ // origin/<baseBranch> doesn't exist — use local branch
266
+ }
267
+ // Prune stale worktree entries before adding, in case git's list is stale
268
+ await this.execGit(['worktree', 'prune']);
269
+ await this.execGit(['worktree', 'add', '--detach', fullPath, startPoint]);
270
+ this.worktreeStates.set(relativePath, 'active');
271
+ const worktree = await this.getWorktree(relativePath);
272
+ if (!worktree) {
273
+ throw new WorktreeError('Failed to get worktree info after creation', 'WORKTREE_INFO_FAILED');
274
+ }
275
+ const enrichedWorktree = {
276
+ ...worktree,
277
+ agentName: options.agentName,
278
+ createdAt: createTimestamp(),
279
+ state: 'active',
280
+ };
281
+ return {
282
+ worktree: enrichedWorktree,
283
+ branch: `(detached-${options.purpose})`,
284
+ path: fullPath,
285
+ branchCreated: false,
286
+ };
287
+ }
288
+ catch (error) {
289
+ this.worktreeStates.delete(relativePath);
290
+ if (fs.existsSync(fullPath)) {
291
+ try {
292
+ await this.execGit(['worktree', 'remove', '--force', fullPath]);
293
+ }
294
+ catch {
295
+ // Ignore cleanup errors
296
+ }
297
+ }
298
+ throw error;
299
+ }
300
+ }
301
+ async removeWorktree(worktreePath, options) {
302
+ this.ensureInitialized();
303
+ const fullPath = this.resolvePath(worktreePath);
304
+ const relativePath = this.getRelativePath(fullPath);
305
+ // Get worktree info to find the branch
306
+ const worktree = await this.getWorktree(worktreePath);
307
+ if (!worktree) {
308
+ throw new WorktreeError(`Worktree not found: ${worktreePath}`, 'WORKTREE_NOT_FOUND');
309
+ }
310
+ if (worktree.isMain) {
311
+ throw new WorktreeError('Cannot remove the main worktree', 'CANNOT_REMOVE_MAIN');
312
+ }
313
+ // Update state
314
+ this.worktreeStates.set(relativePath, 'cleaning');
315
+ try {
316
+ // Remove the worktree
317
+ const removeArgs = ['worktree', 'remove'];
318
+ if (options?.force) {
319
+ removeArgs.push('--force');
320
+ }
321
+ removeArgs.push(fullPath);
322
+ await this.execGit(removeArgs);
323
+ // Delete branch if requested
324
+ if (options?.deleteBranch && worktree.branch) {
325
+ // Delete remote branch first if requested
326
+ if (options.deleteRemoteBranch) {
327
+ try {
328
+ await this.execGit(['push', 'origin', '--delete', worktree.branch]);
329
+ }
330
+ catch {
331
+ // Remote branch might not exist or push access denied
332
+ // Log warning but continue with local branch deletion
333
+ console.warn(`[worktree-manager] Failed to delete remote branch origin/${worktree.branch}`);
334
+ }
335
+ }
336
+ // Delete local branch
337
+ const deleteArgs = ['branch'];
338
+ if (options.forceBranchDelete) {
339
+ deleteArgs.push('-D');
340
+ }
341
+ else {
342
+ deleteArgs.push('-d');
343
+ }
344
+ deleteArgs.push(worktree.branch);
345
+ try {
346
+ await this.execGit(deleteArgs);
347
+ }
348
+ catch (error) {
349
+ // Branch might not exist or might not be fully merged
350
+ // Only throw if not forcing
351
+ if (!options.forceBranchDelete) {
352
+ throw new WorktreeError(`Failed to delete branch ${worktree.branch}. Use forceBranchDelete to force deletion.`, 'BRANCH_DELETE_FAILED', error.message);
353
+ }
354
+ }
355
+ }
356
+ // Update state to archived
357
+ this.worktreeStates.set(relativePath, 'archived');
358
+ }
359
+ catch (error) {
360
+ if (error instanceof WorktreeError) {
361
+ throw error;
362
+ }
363
+ throw new WorktreeError(`Failed to remove worktree: ${worktreePath}`, 'REMOVE_FAILED', error.message);
364
+ }
365
+ }
366
+ async suspendWorktree(worktreePath) {
367
+ this.ensureInitialized();
368
+ const worktree = await this.getWorktree(worktreePath);
369
+ if (!worktree) {
370
+ throw new WorktreeError(`Worktree not found: ${worktreePath}`, 'WORKTREE_NOT_FOUND');
371
+ }
372
+ const relativePath = this.getRelativePath(this.resolvePath(worktreePath));
373
+ const currentState = this.worktreeStates.get(relativePath) ?? 'active';
374
+ if (!WorktreeStateTransitions[currentState].includes('suspended')) {
375
+ throw new WorktreeError(`Cannot suspend worktree in state: ${currentState}`, 'INVALID_STATE_TRANSITION');
376
+ }
377
+ this.worktreeStates.set(relativePath, 'suspended');
378
+ }
379
+ async resumeWorktree(worktreePath) {
380
+ this.ensureInitialized();
381
+ const worktree = await this.getWorktree(worktreePath);
382
+ if (!worktree) {
383
+ throw new WorktreeError(`Worktree not found: ${worktreePath}`, 'WORKTREE_NOT_FOUND');
384
+ }
385
+ const relativePath = this.getRelativePath(this.resolvePath(worktreePath));
386
+ const currentState = this.worktreeStates.get(relativePath) ?? 'active';
387
+ if (currentState !== 'suspended') {
388
+ throw new WorktreeError(`Cannot resume worktree in state: ${currentState}`, 'INVALID_STATE_TRANSITION');
389
+ }
390
+ this.worktreeStates.set(relativePath, 'active');
391
+ }
392
+ // ----------------------------------------
393
+ // Worktree Queries
394
+ // ----------------------------------------
395
+ async listWorktrees(includeMain = false) {
396
+ this.ensureInitialized();
397
+ try {
398
+ const { stdout } = await this.execGit(['worktree', 'list', '--porcelain']);
399
+ const worktrees = this.parseWorktreeList(stdout);
400
+ if (includeMain) {
401
+ return worktrees;
402
+ }
403
+ return worktrees.filter((w) => !w.isMain);
404
+ }
405
+ catch (error) {
406
+ throw new WorktreeError('Failed to list worktrees', 'LIST_FAILED', error.message);
407
+ }
408
+ }
409
+ async getWorktree(worktreePath) {
410
+ this.ensureInitialized();
411
+ const fullPath = this.resolvePath(worktreePath);
412
+ // Resolve real path for comparison (handles symlinks like /tmp -> /private/tmp)
413
+ let realFullPath;
414
+ try {
415
+ realFullPath = fs.realpathSync(fullPath);
416
+ }
417
+ catch {
418
+ realFullPath = fullPath;
419
+ }
420
+ const worktrees = await this.listWorktrees(true);
421
+ return worktrees.find((w) => {
422
+ // Compare real paths to handle symlinks
423
+ try {
424
+ const realWPath = fs.realpathSync(w.path);
425
+ return realWPath === realFullPath;
426
+ }
427
+ catch {
428
+ return w.path === fullPath;
429
+ }
430
+ });
431
+ }
432
+ getWorktreePath(agentName, taskTitle) {
433
+ const slug = taskTitle ? createSlugFromTitle(taskTitle) : undefined;
434
+ const relativePath = generateWorktreePath(agentName, slug);
435
+ return path.join(this.config.workspaceRoot, relativePath);
436
+ }
437
+ async getWorktreesForAgent(agentName) {
438
+ this.ensureInitialized();
439
+ const worktrees = await this.listWorktrees();
440
+ const safeName = agentName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
441
+ return worktrees.filter((w) => {
442
+ // Check if the relative path starts with the agent's prefix
443
+ // Match either exact name (.stoneforge/.worktrees/bob) or name with slug (.stoneforge/.worktrees/bob-feature)
444
+ // Escape special regex characters in the worktreeDir path (like .)
445
+ const escapedDir = this.config.worktreeDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
446
+ const pathPattern = new RegExp(`^${escapedDir}/${safeName}($|-)`);
447
+ return pathPattern.test(w.relativePath);
448
+ });
449
+ }
450
+ async worktreeExists(worktreePath) {
451
+ const worktree = await this.getWorktree(worktreePath);
452
+ return worktree !== undefined;
453
+ }
454
+ // ----------------------------------------
455
+ // Branch Operations
456
+ // ----------------------------------------
457
+ async getCurrentBranch() {
458
+ this.ensureInitialized();
459
+ try {
460
+ const { stdout } = await this.execGit(['rev-parse', '--abbrev-ref', 'HEAD']);
461
+ return stdout.trim();
462
+ }
463
+ catch (error) {
464
+ throw new WorktreeError('Failed to get current branch', 'BRANCH_QUERY_FAILED', error.message);
465
+ }
466
+ }
467
+ async getDefaultBranch() {
468
+ if (this.defaultBranch) {
469
+ return this.defaultBranch;
470
+ }
471
+ this.defaultBranch = await this.detectDefaultBranch();
472
+ return this.defaultBranch;
473
+ }
474
+ async branchExists(branchName) {
475
+ try {
476
+ await this.execGit(['rev-parse', '--verify', `refs/heads/${branchName}`]);
477
+ return true;
478
+ }
479
+ catch {
480
+ return false;
481
+ }
482
+ }
483
+ // ----------------------------------------
484
+ // Private Helpers
485
+ // ----------------------------------------
486
+ ensureInitialized() {
487
+ if (!this.initialized) {
488
+ throw new WorktreeError('WorktreeManager not initialized. Call initWorkspace() first.', 'NOT_INITIALIZED');
489
+ }
490
+ }
491
+ async execGit(args) {
492
+ return execFileAsync('git', args, {
493
+ cwd: this.config.workspaceRoot,
494
+ encoding: 'utf8',
495
+ timeout: GIT_OPERATION_TIMEOUT_MS,
496
+ });
497
+ }
498
+ /**
499
+ * Installs dependencies in a worktree directory.
500
+ * Detects the package manager (pnpm, npm, yarn, bun) and runs install.
501
+ * Uses a longer timeout since dependency installation can take a while.
502
+ *
503
+ * Tries a strict install first (--frozen-lockfile / ci) and falls back to
504
+ * a plain install when the lockfile is out of sync with package.json
505
+ * (common when the base branch has uncommitted lockfile changes).
506
+ */
507
+ async installDependencies(worktreePath) {
508
+ // Check if package.json exists
509
+ const packageJsonPath = path.join(worktreePath, 'package.json');
510
+ if (!fs.existsSync(packageJsonPath)) {
511
+ // No package.json, nothing to install
512
+ return;
513
+ }
514
+ // Detect package manager by lockfile presence
515
+ const hasLockfile = (name) => fs.existsSync(path.join(worktreePath, name));
516
+ let command;
517
+ let strictArgs;
518
+ if (hasLockfile('pnpm-lock.yaml')) {
519
+ command = 'pnpm';
520
+ strictArgs = ['install', '--frozen-lockfile'];
521
+ }
522
+ else if (hasLockfile('bun.lockb') || hasLockfile('bun.lock')) {
523
+ command = 'bun';
524
+ strictArgs = ['install', '--frozen-lockfile'];
525
+ }
526
+ else if (hasLockfile('yarn.lock')) {
527
+ command = 'yarn';
528
+ strictArgs = ['install', '--frozen-lockfile'];
529
+ }
530
+ else if (hasLockfile('package-lock.json')) {
531
+ command = 'npm';
532
+ strictArgs = ['ci'];
533
+ }
534
+ else {
535
+ // Default to pnpm if no lockfile detected (monorepo case)
536
+ command = 'pnpm';
537
+ strictArgs = ['install'];
538
+ }
539
+ // Use a longer timeout for dependency installation (5 minutes)
540
+ const INSTALL_TIMEOUT_MS = 5 * 60 * 1000;
541
+ const execOptions = {
542
+ cwd: worktreePath,
543
+ encoding: 'utf8',
544
+ timeout: INSTALL_TIMEOUT_MS,
545
+ };
546
+ try {
547
+ await execFileAsync(command, strictArgs, execOptions);
548
+ }
549
+ catch {
550
+ // Strict install failed — the lockfile may be out of sync with
551
+ // package.json (e.g. uncommitted lockfile changes on the base branch).
552
+ // Fall back to a plain install so the worktree is still usable.
553
+ try {
554
+ await execFileAsync(command, ['install'], execOptions);
555
+ }
556
+ catch (error) {
557
+ const execError = error;
558
+ const details = [
559
+ execError.message,
560
+ execError.stderr ? `stderr: ${execError.stderr}` : '',
561
+ execError.stdout ? `stdout: ${execError.stdout}` : '',
562
+ ].filter(Boolean).join('\n');
563
+ throw new WorktreeError(`Failed to install dependencies in worktree: ${worktreePath}`, 'DEPENDENCY_INSTALL_FAILED', details);
564
+ }
565
+ }
566
+ }
567
+ resolvePath(worktreePath) {
568
+ if (path.isAbsolute(worktreePath)) {
569
+ return worktreePath;
570
+ }
571
+ return path.join(this.config.workspaceRoot, worktreePath);
572
+ }
573
+ getRelativePath(fullPath) {
574
+ // Use the real workspace root for relative path calculation to handle symlinks
575
+ const baseRoot = this.realWorkspaceRoot ?? this.config.workspaceRoot;
576
+ // Also resolve the full path to handle symlinks in both paths
577
+ let realFullPath = fullPath;
578
+ try {
579
+ realFullPath = fs.realpathSync(fullPath);
580
+ }
581
+ catch {
582
+ // Path might not exist yet during creation, use as-is
583
+ }
584
+ return path.relative(baseRoot, realFullPath);
585
+ }
586
+ parseWorktreeList(output) {
587
+ const worktrees = [];
588
+ const lines = output.trim().split('\n');
589
+ let current = {};
590
+ for (const line of lines) {
591
+ if (line.startsWith('worktree ')) {
592
+ // Start of new worktree entry
593
+ if (current.path) {
594
+ worktrees.push(this.finalizeWorktreeInfo(current));
595
+ }
596
+ current = {
597
+ path: line.substring(9),
598
+ isMain: false,
599
+ };
600
+ }
601
+ else if (line.startsWith('HEAD ')) {
602
+ current.head = line.substring(5);
603
+ }
604
+ else if (line.startsWith('branch ')) {
605
+ // Remove refs/heads/ prefix
606
+ const branch = line.substring(7);
607
+ current.branch = branch.replace(/^refs\/heads\//, '');
608
+ }
609
+ else if (line === 'bare') {
610
+ current.isMain = true;
611
+ }
612
+ else if (line === '') {
613
+ // End of entry
614
+ if (current.path) {
615
+ worktrees.push(this.finalizeWorktreeInfo(current));
616
+ current = {};
617
+ }
618
+ }
619
+ }
620
+ // Handle last entry
621
+ if (current.path) {
622
+ worktrees.push(this.finalizeWorktreeInfo(current));
623
+ }
624
+ // The first worktree is always the main one
625
+ if (worktrees.length > 0) {
626
+ worktrees[0].isMain = true;
627
+ }
628
+ return worktrees;
629
+ }
630
+ finalizeWorktreeInfo(partial) {
631
+ const fullPath = partial.path;
632
+ const relativePath = this.getRelativePath(fullPath);
633
+ const state = this.worktreeStates.get(relativePath) ?? 'active';
634
+ // Parse agent name and task ID from path if it matches our pattern
635
+ let agentName;
636
+ let taskId;
637
+ // Escape special regex characters in the worktreeDir path and match agent name
638
+ const escapedDir = this.config.worktreeDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
639
+ const match = relativePath.match(new RegExp(`^${escapedDir}/([^-]+)-`));
640
+ if (match) {
641
+ agentName = match[1];
642
+ // Task ID might be in the branch name
643
+ const branchMatch = partial.branch?.match(/^agent\/[^/]+\/([^-]+)/);
644
+ if (branchMatch) {
645
+ taskId = branchMatch[1];
646
+ }
647
+ }
648
+ return {
649
+ path: fullPath,
650
+ relativePath,
651
+ branch: partial.branch ?? 'HEAD',
652
+ head: partial.head ?? '',
653
+ isMain: partial.isMain ?? false,
654
+ state,
655
+ agentName,
656
+ taskId,
657
+ };
658
+ }
659
+ async detectDefaultBranch() {
660
+ // Check config first
661
+ if (this.config.defaultBaseBranch) {
662
+ return this.config.defaultBaseBranch;
663
+ }
664
+ // Try to detect from remote
665
+ try {
666
+ const { stdout } = await this.execGit(['remote', 'show', 'origin']);
667
+ const match = stdout.match(/HEAD branch: (.+)/);
668
+ if (match) {
669
+ return match[1].trim();
670
+ }
671
+ }
672
+ catch {
673
+ // No remote or error, continue
674
+ }
675
+ // Try common default branch names
676
+ for (const branch of ['main', 'master', 'develop']) {
677
+ if (await this.branchExists(branch)) {
678
+ return branch;
679
+ }
680
+ }
681
+ // Fall back to current branch
682
+ return this.getCurrentBranch();
683
+ }
684
+ async ensureGitignore() {
685
+ const gitignorePath = path.join(this.config.workspaceRoot, '.gitignore');
686
+ const worktreeDirPattern = `/${this.config.worktreeDir}/`;
687
+ let content = '';
688
+ if (fs.existsSync(gitignorePath)) {
689
+ content = fs.readFileSync(gitignorePath, 'utf8');
690
+ }
691
+ if (!content.includes(worktreeDirPattern)) {
692
+ const newContent = content.endsWith('\n')
693
+ ? content + worktreeDirPattern + '\n'
694
+ : content + '\n' + worktreeDirPattern + '\n';
695
+ fs.writeFileSync(gitignorePath, newContent, 'utf8');
696
+ }
697
+ }
698
+ }
699
+ // ============================================================================
700
+ // Factory Function
701
+ // ============================================================================
702
+ /**
703
+ * Creates a WorktreeManager instance
704
+ */
705
+ export function createWorktreeManager(config) {
706
+ return new WorktreeManagerImpl(config);
707
+ }
708
+ // ============================================================================
709
+ // Utility Functions
710
+ // ============================================================================
711
+ /**
712
+ * Type guard to check if a value is a valid WorktreeState
713
+ */
714
+ export function isWorktreeState(value) {
715
+ return typeof value === 'string' && WorktreeStates.includes(value);
716
+ }
717
+ /**
718
+ * Checks if a state transition is valid
719
+ */
720
+ export function isValidStateTransition(from, to) {
721
+ return WorktreeStateTransitions[from].includes(to);
722
+ }
723
+ /**
724
+ * Gets human-readable description of a worktree state
725
+ */
726
+ export function getWorktreeStateDescription(state) {
727
+ switch (state) {
728
+ case 'creating':
729
+ return 'Being created';
730
+ case 'active':
731
+ return 'Active and in use';
732
+ case 'suspended':
733
+ return 'Suspended (can be resumed)';
734
+ case 'merging':
735
+ return 'Branch being merged';
736
+ case 'cleaning':
737
+ return 'Being cleaned up';
738
+ case 'archived':
739
+ return 'Archived (removed)';
740
+ default:
741
+ return 'Unknown';
742
+ }
743
+ }
744
+ //# sourceMappingURL=worktree-manager.js.map