@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,889 @@
1
+ /**
2
+ * Task Commands - CLI operations for orchestrator task management
3
+ *
4
+ * Provides commands for task management:
5
+ * - task handoff <task-id>: Hand off a task to another agent
6
+ * - task complete <task-id>: Complete a task and optionally create a PR
7
+ * - task merge <task-id>: Mark a task as merged and close it
8
+ * - task reject <task-id>: Mark a task merge as failed and reopen it
9
+ * - task sync <task-id>: Sync a task branch with the main branch
10
+ */
11
+ import { success, failure, ExitCode, getOutputMode } from '@stoneforge/quarry/cli';
12
+ import { TaskStatus, createTimestamp } from '@stoneforge/core';
13
+ // ============================================================================
14
+ // Shared Helpers
15
+ // ============================================================================
16
+ /**
17
+ * Creates task assignment service
18
+ */
19
+ async function createTaskAssignmentService(options) {
20
+ try {
21
+ const { createStorage, initializeSchema, findStoneforgeDir } = await import('@stoneforge/quarry');
22
+ const { createTaskAssignmentService: createService } = await import('../../services/task-assignment-service.js');
23
+ const { createLocalMergeProvider } = await import('../../services/merge-request-provider.js');
24
+ const { QuarryAPIImpl } = await import('@stoneforge/quarry');
25
+ const stoneforgeDir = findStoneforgeDir(process.cwd());
26
+ if (!stoneforgeDir) {
27
+ return {
28
+ service: null,
29
+ error: 'No .stoneforge directory found. Run "sf init" first.',
30
+ };
31
+ }
32
+ const dbPath = options.db ?? `${stoneforgeDir}/stoneforge.db`;
33
+ const backend = createStorage({ path: dbPath, create: true });
34
+ initializeSchema(backend);
35
+ const api = new QuarryAPIImpl(backend);
36
+ const mergeProvider = createLocalMergeProvider();
37
+ const service = createService(api, mergeProvider);
38
+ return { service };
39
+ }
40
+ catch (err) {
41
+ const message = err instanceof Error ? err.message : String(err);
42
+ return { service: null, error: `Failed to initialize service: ${message}` };
43
+ }
44
+ }
45
+ /**
46
+ * Creates an OrchestratorAPI instance for merge/reject operations
47
+ */
48
+ async function createOrchestratorApi(options) {
49
+ try {
50
+ const { createStorage, initializeSchema, findStoneforgeDir } = await import('@stoneforge/quarry');
51
+ const { createOrchestratorAPI } = await import('../../api/orchestrator-api.js');
52
+ const stoneforgeDir = findStoneforgeDir(process.cwd());
53
+ if (!stoneforgeDir) {
54
+ return {
55
+ api: null,
56
+ error: 'No .stoneforge directory found. Run "sf init" first.',
57
+ };
58
+ }
59
+ const dbPath = options.db ?? `${stoneforgeDir}/stoneforge.db`;
60
+ const backend = createStorage({ path: dbPath, create: true });
61
+ initializeSchema(backend);
62
+ const api = createOrchestratorAPI(backend);
63
+ return { api };
64
+ }
65
+ catch (err) {
66
+ const message = err instanceof Error ? err.message : String(err);
67
+ return { api: null, error: `Failed to initialize API: ${message}` };
68
+ }
69
+ }
70
+ /**
71
+ * Gets the current session ID from environment or generates a placeholder
72
+ */
73
+ function getCurrentSessionId() {
74
+ // Check for session ID in environment (set by spawner or agent)
75
+ return process.env.STONEFORGE_SESSION_ID || `cli-${Date.now()}`;
76
+ }
77
+ const taskHandoffOptions = [
78
+ {
79
+ name: 'message',
80
+ short: 'm',
81
+ description: 'Handoff message explaining context and reason',
82
+ hasValue: true,
83
+ },
84
+ {
85
+ name: 'branch',
86
+ short: 'b',
87
+ description: 'Override the branch to preserve (defaults to task branch)',
88
+ hasValue: true,
89
+ },
90
+ {
91
+ name: 'worktree',
92
+ short: 'w',
93
+ description: 'Override the worktree path to preserve (defaults to task worktree)',
94
+ hasValue: true,
95
+ },
96
+ {
97
+ name: 'sessionId',
98
+ short: 's',
99
+ description: 'Session ID of the agent handing off (defaults to current session)',
100
+ hasValue: true,
101
+ },
102
+ ];
103
+ async function taskHandoffHandler(args, options) {
104
+ const [taskId] = args;
105
+ if (!taskId) {
106
+ return failure('Usage: sf task handoff <task-id> [options]\nExample: sf task handoff el-abc123 --message "Need help with frontend"', ExitCode.INVALID_ARGUMENTS);
107
+ }
108
+ const { service, error } = await createTaskAssignmentService(options);
109
+ if (error || !service) {
110
+ return failure(error ?? 'Failed to create service', ExitCode.GENERAL_ERROR);
111
+ }
112
+ try {
113
+ const sessionId = options.sessionId || getCurrentSessionId();
114
+ const task = await service.handoffTask(taskId, {
115
+ sessionId,
116
+ message: options.message,
117
+ branch: options.branch,
118
+ worktree: options.worktree,
119
+ });
120
+ const mode = getOutputMode(options);
121
+ if (mode === 'json') {
122
+ return success({
123
+ taskId: task.id,
124
+ sessionId,
125
+ message: options.message,
126
+ branch: options.branch,
127
+ worktree: options.worktree,
128
+ handedOff: true,
129
+ });
130
+ }
131
+ if (mode === 'quiet') {
132
+ return success(task.id);
133
+ }
134
+ const lines = [
135
+ `Handed off task ${taskId}`,
136
+ ` Session: ${sessionId}`,
137
+ ];
138
+ if (options.message) {
139
+ lines.push(` Message: ${options.message.slice(0, 50)}${options.message.length > 50 ? '...' : ''}`);
140
+ }
141
+ if (options.branch) {
142
+ lines.push(` Branch: ${options.branch}`);
143
+ }
144
+ if (options.worktree) {
145
+ lines.push(` Worktree: ${options.worktree}`);
146
+ }
147
+ lines.push('');
148
+ lines.push('Task has been unassigned and is available for pickup by another agent.');
149
+ return success(task, lines.join('\n'));
150
+ }
151
+ catch (err) {
152
+ const message = err instanceof Error ? err.message : String(err);
153
+ return failure(`Failed to hand off task: ${message}`, ExitCode.GENERAL_ERROR);
154
+ }
155
+ }
156
+ export const taskHandoffCommand = {
157
+ name: 'handoff',
158
+ description: 'Hand off a task to another agent',
159
+ usage: 'sf task handoff <task-id> [options]',
160
+ help: `Hand off a task to be picked up by another agent.
161
+
162
+ This command:
163
+ 1. Preserves the branch and worktree references in task metadata
164
+ 2. Appends a handoff note with context to the task description
165
+ 3. Unassigns the task so it returns to the available pool
166
+
167
+ The next agent that picks up this task can continue from the
168
+ existing code state in the preserved branch/worktree.
169
+
170
+ Arguments:
171
+ task-id Task identifier to hand off
172
+
173
+ Options:
174
+ -m, --message <text> Handoff message with context and reason
175
+ -b, --branch <name> Override branch to preserve
176
+ -w, --worktree <path> Override worktree path to preserve
177
+ -s, --sessionId <id> Session ID (defaults to current session)
178
+
179
+ Examples:
180
+ sf task handoff el-abc123
181
+ sf task handoff el-abc123 --message "Completed API, need help with frontend"
182
+ sf task handoff el-abc123 -m "Blocked on database access" -b feature/my-branch`,
183
+ options: taskHandoffOptions,
184
+ handler: taskHandoffHandler,
185
+ };
186
+ const taskCompleteOptions = [
187
+ {
188
+ name: 'summary',
189
+ short: 's',
190
+ description: 'Summary of what was accomplished',
191
+ hasValue: true,
192
+ },
193
+ {
194
+ name: 'commitHash',
195
+ short: 'c',
196
+ description: 'Commit hash for the final commit',
197
+ hasValue: true,
198
+ },
199
+ {
200
+ name: 'no-mr',
201
+ description: 'Skip merge request creation',
202
+ },
203
+ {
204
+ name: 'mr-title',
205
+ description: 'Custom title for the merge request',
206
+ hasValue: true,
207
+ },
208
+ {
209
+ name: 'mr-body',
210
+ description: 'Custom body for the merge request',
211
+ hasValue: true,
212
+ },
213
+ {
214
+ name: 'baseBranch',
215
+ short: 'b',
216
+ description: 'Base branch for the merge request (default: main)',
217
+ hasValue: true,
218
+ },
219
+ ];
220
+ async function taskCompleteHandler(args, options) {
221
+ const [taskId] = args;
222
+ if (!taskId) {
223
+ return failure('Usage: sf task complete <task-id> [options]\nExample: sf task complete el-abc123 --summary "Implemented feature"', ExitCode.INVALID_ARGUMENTS);
224
+ }
225
+ const { service, error } = await createTaskAssignmentService(options);
226
+ if (error || !service) {
227
+ return failure(error ?? 'Failed to create service', ExitCode.GENERAL_ERROR);
228
+ }
229
+ try {
230
+ const result = await service.completeTask(taskId, {
231
+ summary: options.summary,
232
+ commitHash: options.commitHash,
233
+ createMergeRequest: options['no-mr'] !== true,
234
+ mergeRequestTitle: options['mr-title'],
235
+ mergeRequestBody: options['mr-body'],
236
+ baseBranch: options.baseBranch,
237
+ });
238
+ const mode = getOutputMode(options);
239
+ if (mode === 'json') {
240
+ return success({
241
+ taskId: result.task.id,
242
+ status: result.task.status,
243
+ mergeRequestUrl: result.mergeRequestUrl,
244
+ mergeRequestId: result.mergeRequestId,
245
+ });
246
+ }
247
+ if (mode === 'quiet') {
248
+ return success(result.task.id);
249
+ }
250
+ const lines = [
251
+ `Completed task ${taskId}`,
252
+ ` Status: ${result.task.status}`,
253
+ ];
254
+ if (options.summary) {
255
+ lines.push(` Summary: ${options.summary.slice(0, 50)}${options.summary.length > 50 ? '...' : ''}`);
256
+ }
257
+ if (result.mergeRequestUrl) {
258
+ lines.push(` MR: ${result.mergeRequestUrl}`);
259
+ }
260
+ return success(result, lines.join('\n'));
261
+ }
262
+ catch (err) {
263
+ const message = err instanceof Error ? err.message : String(err);
264
+ return failure(`Failed to complete task: ${message}`, ExitCode.GENERAL_ERROR);
265
+ }
266
+ }
267
+ export const taskCompleteCommand = {
268
+ name: 'complete',
269
+ description: 'Complete a task and optionally create a merge request',
270
+ usage: 'sf task complete <task-id> [options]',
271
+ help: `Complete a task and optionally create a merge request.
272
+
273
+ This command:
274
+ 1. Sets the task status to 'review' (awaiting merge)
275
+ 2. Clears the task assignee
276
+ 3. Records completion time and optional summary
277
+ 4. Creates a merge request for the task branch (if a provider is configured)
278
+
279
+ Arguments:
280
+ task-id Task identifier to complete
281
+
282
+ Options:
283
+ -s, --summary <text> Summary of what was accomplished
284
+ -c, --commitHash <hash> Commit hash for the final commit
285
+ --no-mr Skip merge request creation
286
+ --mr-title <title> Custom MR title (defaults to task title)
287
+ --mr-body <body> Custom MR body
288
+ -b, --baseBranch <name> Base branch for MR (default: main)
289
+
290
+ Examples:
291
+ sf task complete el-abc123
292
+ sf task complete el-abc123 --summary "Implemented login feature"
293
+ sf task complete el-abc123 --no-mr
294
+ sf task complete el-abc123 --baseBranch develop`,
295
+ options: taskCompleteOptions,
296
+ handler: taskCompleteHandler,
297
+ };
298
+ const taskMergeOptions = [
299
+ {
300
+ name: 'summary',
301
+ short: 's',
302
+ description: 'Summary of the merge',
303
+ hasValue: true,
304
+ },
305
+ ];
306
+ async function taskMergeHandler(args, options) {
307
+ const [taskId] = args;
308
+ if (!taskId) {
309
+ return failure('Usage: sf task merge <task-id> [options]\nExample: sf task merge el-abc123', ExitCode.INVALID_ARGUMENTS);
310
+ }
311
+ const { api, error } = await createOrchestratorApi(options);
312
+ if (error || !api) {
313
+ return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
314
+ }
315
+ try {
316
+ // 1. Get task and validate
317
+ const task = await api.get(taskId);
318
+ if (!task) {
319
+ return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
320
+ }
321
+ if (task.status !== TaskStatus.REVIEW) {
322
+ return failure(`Task ${taskId} is in '${task.status}' status. Only REVIEW tasks can be merged.`, ExitCode.GENERAL_ERROR);
323
+ }
324
+ const { getOrchestratorTaskMeta, updateOrchestratorTaskMeta } = await import('../../types/task-meta.js');
325
+ const orchestratorMeta = getOrchestratorTaskMeta(task.metadata);
326
+ const sourceBranch = orchestratorMeta?.branch;
327
+ if (!sourceBranch) {
328
+ return failure(`Task ${taskId} has no branch in orchestrator metadata.`, ExitCode.GENERAL_ERROR);
329
+ }
330
+ // 2. Derive workspace root from .stoneforge dir
331
+ const { findStoneforgeDir } = await import('@stoneforge/quarry');
332
+ const stoneforgeDir = findStoneforgeDir(process.cwd());
333
+ if (!stoneforgeDir) {
334
+ return failure('No .stoneforge directory found. Run "sf init" first.', ExitCode.GENERAL_ERROR);
335
+ }
336
+ const { default: path } = await import('node:path');
337
+ const workspaceRoot = path.dirname(stoneforgeDir);
338
+ // 3. Call mergeBranch() with syncLocal disabled (we'll do it after bookkeeping)
339
+ const { mergeBranch, syncLocalBranch } = await import('../../git/merge.js');
340
+ const { detectTargetBranch } = await import('../../git/merge.js');
341
+ const commitMessage = `${task.title} (${taskId})`;
342
+ const mergeResult = await mergeBranch({
343
+ workspaceRoot,
344
+ sourceBranch,
345
+ commitMessage,
346
+ syncLocal: false,
347
+ });
348
+ if (!mergeResult.success) {
349
+ const lines = [`Failed to merge task ${taskId}: ${mergeResult.error}`];
350
+ if (mergeResult.conflictFiles?.length) {
351
+ lines.push('Conflict files:');
352
+ for (const f of mergeResult.conflictFiles) {
353
+ lines.push(` - ${f}`);
354
+ }
355
+ }
356
+ return failure(lines.join('\n'), ExitCode.GENERAL_ERROR);
357
+ }
358
+ // 4. Atomic status update: set mergeStatus + close in one call
359
+ const now = createTimestamp();
360
+ const newMeta = updateOrchestratorTaskMeta(task.metadata, {
361
+ mergeStatus: 'merged',
362
+ completedAt: now,
363
+ ...(options.summary ? { completionSummary: options.summary } : {}),
364
+ });
365
+ await api.update(taskId, {
366
+ status: TaskStatus.CLOSED,
367
+ assignee: undefined,
368
+ closedAt: now,
369
+ metadata: newMeta,
370
+ });
371
+ // 5. Clean up: delete source branch and remove task worktree (best-effort)
372
+ const { exec } = await import('node:child_process');
373
+ const { promisify } = await import('node:util');
374
+ const execAsync = promisify(exec);
375
+ try {
376
+ await execAsync(`git branch -D ${sourceBranch}`, { cwd: workspaceRoot });
377
+ }
378
+ catch { /* branch may not exist locally */ }
379
+ try {
380
+ await execAsync(`git push origin --delete ${sourceBranch}`, { cwd: workspaceRoot });
381
+ }
382
+ catch { /* branch may not exist on remote */ }
383
+ const worktreePath = orchestratorMeta?.worktree;
384
+ if (worktreePath) {
385
+ try {
386
+ await execAsync(`git worktree remove --force "${worktreePath}"`, { cwd: workspaceRoot });
387
+ }
388
+ catch { /* worktree may already be gone */ }
389
+ }
390
+ // 6. Sync local target branch (best-effort, after all bookkeeping is done)
391
+ const targetBranch = await detectTargetBranch(workspaceRoot);
392
+ try {
393
+ await execAsync('git fetch origin', { cwd: workspaceRoot, encoding: 'utf8' });
394
+ }
395
+ catch { /* best-effort */ }
396
+ await syncLocalBranch(workspaceRoot, targetBranch);
397
+ // 7. Output result
398
+ const mode = getOutputMode(options);
399
+ if (mode === 'json') {
400
+ return success({
401
+ taskId,
402
+ mergeStatus: 'merged',
403
+ commitHash: mergeResult.commitHash,
404
+ });
405
+ }
406
+ if (mode === 'quiet') {
407
+ return success(taskId);
408
+ }
409
+ const lines = [
410
+ `Merged task ${taskId}`,
411
+ ` Commit: ${mergeResult.commitHash}`,
412
+ ' Merge Status: merged',
413
+ ' Task Status: CLOSED',
414
+ ];
415
+ if (options.summary) {
416
+ lines.push(` Summary: ${options.summary.slice(0, 50)}${options.summary.length > 50 ? '...' : ''}`);
417
+ }
418
+ return success({ taskId, mergeStatus: 'merged', commitHash: mergeResult.commitHash }, lines.join('\n'));
419
+ }
420
+ catch (err) {
421
+ const message = err instanceof Error ? err.message : String(err);
422
+ return failure(`Failed to merge task: ${message}`, ExitCode.GENERAL_ERROR);
423
+ }
424
+ }
425
+ export const taskMergeCommand = {
426
+ name: 'merge',
427
+ description: 'Squash-merge a task branch and close the task',
428
+ usage: 'sf task merge <task-id> [options]',
429
+ help: `Squash-merge a task's branch into the target branch and close it.
430
+
431
+ This command:
432
+ 1. Validates the task is in REVIEW status with an associated branch
433
+ 2. Squash-merges the branch into the target branch (auto-detected)
434
+ 3. Pushes to remote
435
+ 4. Atomically sets merge status to "merged" and closes the task
436
+ 5. Cleans up the source branch (local + remote) and worktree
437
+
438
+ Arguments:
439
+ task-id Task identifier to merge
440
+
441
+ Options:
442
+ -s, --summary <text> Summary of the merge
443
+
444
+ Examples:
445
+ sf task merge el-abc123
446
+ sf task merge el-abc123 --summary "All tests passing, merged to main"`,
447
+ options: taskMergeOptions,
448
+ handler: taskMergeHandler,
449
+ };
450
+ const taskRejectOptions = [
451
+ {
452
+ name: 'reason',
453
+ short: 'r',
454
+ description: 'Reason for rejection (required)',
455
+ hasValue: true,
456
+ },
457
+ {
458
+ name: 'message',
459
+ short: 'm',
460
+ description: 'Handoff message for the next worker',
461
+ hasValue: true,
462
+ },
463
+ ];
464
+ async function taskRejectHandler(args, options) {
465
+ const [taskId] = args;
466
+ if (!taskId) {
467
+ return failure('Usage: sf task reject <task-id> --reason "..." [options]\nExample: sf task reject el-abc123 --reason "Tests failed"', ExitCode.INVALID_ARGUMENTS);
468
+ }
469
+ if (!options.reason) {
470
+ return failure('--reason is required. Usage: sf task reject <task-id> --reason "..."\nExample: sf task reject el-abc123 --reason "Tests failed"', ExitCode.INVALID_ARGUMENTS);
471
+ }
472
+ const { api, error } = await createOrchestratorApi(options);
473
+ if (error || !api) {
474
+ return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
475
+ }
476
+ try {
477
+ await api.updateTaskOrchestratorMeta(taskId, {
478
+ mergeStatus: 'test_failed',
479
+ mergeFailureReason: options.reason,
480
+ ...(options.message ? { handoffHistory: [{ sessionId: 'cli', message: options.message, handoffAt: new Date().toISOString() }] } : {}),
481
+ });
482
+ await api.update(taskId, {
483
+ status: TaskStatus.OPEN,
484
+ assignee: undefined,
485
+ });
486
+ const mode = getOutputMode(options);
487
+ if (mode === 'json') {
488
+ return success({
489
+ taskId,
490
+ mergeStatus: 'test_failed',
491
+ reason: options.reason,
492
+ message: options.message,
493
+ });
494
+ }
495
+ if (mode === 'quiet') {
496
+ return success(taskId);
497
+ }
498
+ const lines = [
499
+ `Rejected task ${taskId}`,
500
+ ' Merge Status: test_failed',
501
+ ` Reason: ${options.reason.slice(0, 50)}${options.reason.length > 50 ? '...' : ''}`,
502
+ ];
503
+ if (options.message) {
504
+ lines.push(` Handoff: ${options.message.slice(0, 50)}${options.message.length > 50 ? '...' : ''}`);
505
+ }
506
+ lines.push('');
507
+ lines.push('Task has been reopened and unassigned for pickup by another agent.');
508
+ return success({ taskId, mergeStatus: 'test_failed' }, lines.join('\n'));
509
+ }
510
+ catch (err) {
511
+ const message = err instanceof Error ? err.message : String(err);
512
+ return failure(`Failed to reject task: ${message}`, ExitCode.GENERAL_ERROR);
513
+ }
514
+ }
515
+ export const taskRejectCommand = {
516
+ name: 'reject',
517
+ description: 'Mark a task merge as failed and reopen it',
518
+ usage: 'sf task reject <task-id> --reason "..." [options]',
519
+ help: `Mark a task merge as failed and reopen it.
520
+
521
+ This command:
522
+ 1. Sets the task's merge status to "test_failed"
523
+ 2. Records the failure reason
524
+ 3. Reopens the task and unassigns it
525
+
526
+ Arguments:
527
+ task-id Task identifier to reject
528
+
529
+ Options:
530
+ -r, --reason <text> Reason for rejection (required)
531
+ -m, --message <text> Handoff message for the next worker
532
+
533
+ Examples:
534
+ sf task reject el-abc123 --reason "Tests failed"
535
+ sf task reject el-abc123 --reason "Tests failed" --message "Fix flaky test in auth.test.ts"`,
536
+ options: taskRejectOptions,
537
+ handler: taskRejectHandler,
538
+ };
539
+ async function taskSyncHandler(args, options) {
540
+ const [taskId] = args;
541
+ if (!taskId) {
542
+ return failure('Usage: sf task sync <task-id>\nExample: sf task sync el-abc123', ExitCode.INVALID_ARGUMENTS);
543
+ }
544
+ const { api, error } = await createOrchestratorApi(options);
545
+ if (error || !api) {
546
+ return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
547
+ }
548
+ try {
549
+ // 1. Get task and its metadata
550
+ const task = await api.get(taskId);
551
+ if (!task) {
552
+ return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
553
+ }
554
+ // 2. Extract worktree and branch from task metadata
555
+ const taskMeta = task.metadata;
556
+ const orchestratorMeta = taskMeta?.orchestrator;
557
+ const worktreePath = orchestratorMeta?.worktree;
558
+ const branch = orchestratorMeta?.branch;
559
+ if (!worktreePath) {
560
+ const syncResult = {
561
+ success: false,
562
+ error: 'No worktree path found in task metadata',
563
+ message: 'Task has no worktree path - cannot sync',
564
+ };
565
+ const mode = getOutputMode(options);
566
+ if (mode === 'json') {
567
+ return success(syncResult);
568
+ }
569
+ return failure(syncResult.message, ExitCode.GENERAL_ERROR);
570
+ }
571
+ // 3. Check if worktree exists
572
+ const { findStoneforgeDir } = await import('@stoneforge/quarry');
573
+ const { createWorktreeManager } = await import('../../git/worktree-manager.js');
574
+ const stoneforgeDir = findStoneforgeDir(process.cwd());
575
+ if (!stoneforgeDir) {
576
+ return failure('No .stoneforge directory found. Run "sf init" first.', ExitCode.GENERAL_ERROR);
577
+ }
578
+ // Get workspace root (parent of .stoneforge)
579
+ const path = await import('node:path');
580
+ const workspaceRoot = path.dirname(stoneforgeDir);
581
+ const worktreeManager = createWorktreeManager({ workspaceRoot });
582
+ await worktreeManager.initWorkspace();
583
+ const worktreeExists = await worktreeManager.worktreeExists(worktreePath);
584
+ if (!worktreeExists) {
585
+ const syncResult = {
586
+ success: false,
587
+ error: `Worktree does not exist: ${worktreePath}`,
588
+ message: `Worktree not found at ${worktreePath}`,
589
+ worktreePath,
590
+ branch,
591
+ };
592
+ const mode = getOutputMode(options);
593
+ if (mode === 'json') {
594
+ return success(syncResult);
595
+ }
596
+ return failure(syncResult.message, ExitCode.GENERAL_ERROR);
597
+ }
598
+ // 4. Run git fetch and merge in the worktree
599
+ const { execFile } = await import('node:child_process');
600
+ const { promisify } = await import('node:util');
601
+ const execFileAsync = promisify(execFile);
602
+ // Resolve full worktree path
603
+ const fullWorktreePath = path.isAbsolute(worktreePath)
604
+ ? worktreePath
605
+ : path.join(workspaceRoot, worktreePath);
606
+ // Fetch from origin
607
+ try {
608
+ await execFileAsync('git', ['fetch', 'origin'], {
609
+ cwd: fullWorktreePath,
610
+ encoding: 'utf8',
611
+ timeout: 60_000,
612
+ });
613
+ }
614
+ catch (fetchError) {
615
+ const syncResult = {
616
+ success: false,
617
+ error: `Failed to fetch from origin: ${fetchError.message}`,
618
+ message: 'Git fetch failed',
619
+ worktreePath,
620
+ branch,
621
+ };
622
+ const mode = getOutputMode(options);
623
+ if (mode === 'json') {
624
+ return success(syncResult);
625
+ }
626
+ return failure(syncResult.message, ExitCode.GENERAL_ERROR);
627
+ }
628
+ // Detect the default branch (main or master)
629
+ const defaultBranch = await worktreeManager.getDefaultBranch();
630
+ const remoteBranch = `origin/${defaultBranch}`;
631
+ // Attempt to merge
632
+ try {
633
+ await execFileAsync('git', ['merge', remoteBranch, '--no-edit'], {
634
+ cwd: fullWorktreePath,
635
+ encoding: 'utf8',
636
+ timeout: 120_000,
637
+ });
638
+ // Merge succeeded
639
+ const syncResult = {
640
+ success: true,
641
+ message: `Branch synced with ${remoteBranch}`,
642
+ worktreePath,
643
+ branch,
644
+ };
645
+ const mode = getOutputMode(options);
646
+ if (mode === 'json') {
647
+ return success(syncResult);
648
+ }
649
+ if (mode === 'quiet') {
650
+ return success('synced');
651
+ }
652
+ return success(syncResult, `✓ Branch synced with ${remoteBranch}`);
653
+ }
654
+ catch (mergeError) {
655
+ // Check for merge conflicts
656
+ try {
657
+ const { stdout: statusOutput } = await execFileAsync('git', ['status', '--porcelain'], {
658
+ cwd: fullWorktreePath,
659
+ encoding: 'utf8',
660
+ });
661
+ // Parse conflicted files (lines starting with UU, AA, DD, AU, UA, DU, UD)
662
+ const conflictPatterns = /^(UU|AA|DD|AU|UA|DU|UD)\s+(.+)$/gm;
663
+ const conflicts = [];
664
+ let match;
665
+ while ((match = conflictPatterns.exec(statusOutput)) !== null) {
666
+ conflicts.push(match[2]);
667
+ }
668
+ if (conflicts.length > 0) {
669
+ const syncResult = {
670
+ success: false,
671
+ conflicts,
672
+ message: `Merge conflicts detected in ${conflicts.length} file(s)`,
673
+ worktreePath,
674
+ branch,
675
+ };
676
+ const mode = getOutputMode(options);
677
+ if (mode === 'json') {
678
+ return success(syncResult);
679
+ }
680
+ if (mode === 'quiet') {
681
+ return success(conflicts.join('\n'));
682
+ }
683
+ const lines = [
684
+ `⚠ Merge conflicts detected in ${conflicts.length} file(s):`,
685
+ ...conflicts.map(f => ` - ${f}`),
686
+ '',
687
+ 'Resolve conflicts, then commit the resolution.',
688
+ ];
689
+ return success(syncResult, lines.join('\n'));
690
+ }
691
+ // Some other merge error (not conflicts)
692
+ const syncResult = {
693
+ success: false,
694
+ error: mergeError.message,
695
+ message: 'Merge failed (not due to conflicts)',
696
+ worktreePath,
697
+ branch,
698
+ };
699
+ const mode = getOutputMode(options);
700
+ if (mode === 'json') {
701
+ return success(syncResult);
702
+ }
703
+ return failure(syncResult.message, ExitCode.GENERAL_ERROR);
704
+ }
705
+ catch {
706
+ // Failed to check status
707
+ const syncResult = {
708
+ success: false,
709
+ error: mergeError.message,
710
+ message: 'Merge failed',
711
+ worktreePath,
712
+ branch,
713
+ };
714
+ const mode = getOutputMode(options);
715
+ if (mode === 'json') {
716
+ return success(syncResult);
717
+ }
718
+ return failure(syncResult.message, ExitCode.GENERAL_ERROR);
719
+ }
720
+ }
721
+ }
722
+ catch (err) {
723
+ const message = err instanceof Error ? err.message : String(err);
724
+ return failure(`Failed to sync task branch: ${message}`, ExitCode.GENERAL_ERROR);
725
+ }
726
+ }
727
+ export const taskSyncCommand = {
728
+ name: 'sync',
729
+ description: 'Sync a task branch with the main branch',
730
+ usage: 'sf task sync <task-id>',
731
+ help: `Sync a task's branch with the main branch (master/main).
732
+
733
+ This command:
734
+ 1. Looks up the task's worktree path and branch from metadata
735
+ 2. Runs \`git fetch origin\` in the worktree
736
+ 3. Attempts \`git merge origin/main\` (or origin/master)
737
+ 4. Reports success, conflicts, or errors
738
+
739
+ This is typically run by the dispatch daemon before spawning a merge steward,
740
+ or by the steward during review if master advances.
741
+
742
+ Arguments:
743
+ task-id Task identifier to sync
744
+
745
+ Output (JSON mode):
746
+ {
747
+ "success": true/false,
748
+ "conflicts": ["file1.ts", "file2.ts"], // if conflicts
749
+ "error": "message", // if error
750
+ "message": "human-readable status",
751
+ "worktreePath": "/path/to/worktree",
752
+ "branch": "agent/bob/el-123-feature"
753
+ }
754
+
755
+ Examples:
756
+ sf task sync el-abc123
757
+ sf task sync el-abc123 --json`,
758
+ options: [],
759
+ handler: taskSyncHandler,
760
+ };
761
+ // ============================================================================
762
+ // Task Merge-Status Command
763
+ // ============================================================================
764
+ import { MergeStatusValues, isMergeStatus } from '../../types/task-meta.js';
765
+ async function taskMergeStatusHandler(args, options) {
766
+ const [taskId, statusArg] = args;
767
+ if (!taskId || !statusArg) {
768
+ return failure(`Usage: sf task merge-status <task-id> <status>\nExample: sf task merge-status el-abc123 merged\n\nValid statuses: ${MergeStatusValues.join(', ')}`, ExitCode.INVALID_ARGUMENTS);
769
+ }
770
+ // Validate that the provided status is a valid MergeStatus
771
+ if (!isMergeStatus(statusArg)) {
772
+ return failure(`Invalid merge status: "${statusArg}"\nValid statuses: ${MergeStatusValues.join(', ')}`, ExitCode.INVALID_ARGUMENTS);
773
+ }
774
+ const status = statusArg;
775
+ const { api, error } = await createOrchestratorApi(options);
776
+ if (error || !api) {
777
+ return failure(error ?? 'Failed to create API', ExitCode.GENERAL_ERROR);
778
+ }
779
+ try {
780
+ // Terminal statuses (merged, not_applicable) also close the task atomically
781
+ if (status === 'merged' || status === 'not_applicable') {
782
+ const task = await api.get(taskId);
783
+ if (!task) {
784
+ return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
785
+ }
786
+ const { updateOrchestratorTaskMeta } = await import('../../types/task-meta.js');
787
+ const now = createTimestamp();
788
+ const newMeta = updateOrchestratorTaskMeta(task.metadata, { mergeStatus: status });
789
+ await api.update(taskId, {
790
+ status: TaskStatus.CLOSED,
791
+ closedAt: now,
792
+ metadata: newMeta,
793
+ });
794
+ }
795
+ else {
796
+ await api.updateTaskOrchestratorMeta(taskId, {
797
+ mergeStatus: status,
798
+ });
799
+ }
800
+ const mode = getOutputMode(options);
801
+ if (mode === 'json') {
802
+ return success({
803
+ taskId,
804
+ mergeStatus: status,
805
+ });
806
+ }
807
+ if (mode === 'quiet') {
808
+ return success(taskId);
809
+ }
810
+ const statusLine = (status === 'merged' || status === 'not_applicable')
811
+ ? `Updated task ${taskId}\n Merge Status: ${status}\n Task Status: CLOSED`
812
+ : `Updated task ${taskId}\n Merge Status: ${status}`;
813
+ return success({ taskId, mergeStatus: status }, statusLine);
814
+ }
815
+ catch (err) {
816
+ const message = err instanceof Error ? err.message : String(err);
817
+ if (message.includes('not found') || message.includes('Task not found')) {
818
+ return failure(`Task not found: ${taskId}`, ExitCode.GENERAL_ERROR);
819
+ }
820
+ return failure(`Failed to update merge status: ${message}`, ExitCode.GENERAL_ERROR);
821
+ }
822
+ }
823
+ export const taskMergeStatusCommand = {
824
+ name: 'merge-status',
825
+ description: 'Update the merge status of a task',
826
+ usage: 'sf task merge-status <task-id> <status>',
827
+ help: `Update the merge status of a task.
828
+
829
+ This command allows you to manually update the merge status of a task,
830
+ which is useful when the merge steward gets stuck or when a branch is
831
+ manually merged outside of the normal workflow.
832
+
833
+ Arguments:
834
+ task-id Task identifier to update
835
+ status New merge status value
836
+
837
+ Valid status values:
838
+ pending Task completed, awaiting merge
839
+ testing Steward is running tests on the branch
840
+ merging Tests passed, merge in progress
841
+ merged Successfully merged
842
+ conflict Merge conflict detected
843
+ test_failed Tests failed, needs attention
844
+ failed Merge failed for other reason
845
+ not_applicable No merge needed (issue already fixed on master)
846
+
847
+ Examples:
848
+ sf task merge-status el-abc123 merged
849
+ sf task merge-status el-abc123 pending
850
+ sf task merge-status el-abc123 test_failed`,
851
+ options: [],
852
+ handler: taskMergeStatusHandler,
853
+ };
854
+ // ============================================================================
855
+ // Main Task Command
856
+ // ============================================================================
857
+ export const taskCommand = {
858
+ name: 'task',
859
+ description: 'Orchestrator task management',
860
+ usage: 'sf task <subcommand> [options]',
861
+ help: `Orchestrator task management commands.
862
+
863
+ Subcommands:
864
+ handoff Hand off a task to another agent
865
+ complete Complete a task and optionally create a merge request
866
+ merge Mark a task as merged and close it
867
+ reject Mark a task merge as failed and reopen it
868
+ sync Sync a task branch with the main branch
869
+ merge-status Update the merge status of a task
870
+
871
+ Examples:
872
+ sf task handoff el-abc123 --message "Need help with frontend"
873
+ sf task complete el-abc123 --summary "Implemented feature"
874
+ sf task merge el-abc123
875
+ sf task reject el-abc123 --reason "Tests failed"
876
+ sf task sync el-abc123
877
+ sf task merge-status el-abc123 merged`,
878
+ subcommands: {
879
+ handoff: taskHandoffCommand,
880
+ complete: taskCompleteCommand,
881
+ merge: taskMergeCommand,
882
+ reject: taskRejectCommand,
883
+ sync: taskSyncCommand,
884
+ 'merge-status': taskMergeStatusCommand,
885
+ },
886
+ handler: taskHandoffCommand.handler, // Default to handoff
887
+ options: [],
888
+ };
889
+ //# sourceMappingURL=task.js.map