macro-agent 0.1.0 → 0.1.1

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 (337) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/.sudocode/specs.jsonl +4 -0
  3. package/CLAUDE.md +16 -14
  4. package/README.md +11 -29
  5. package/dist/acp/macro-agent.d.ts +15 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +131 -35
  8. package/dist/acp/macro-agent.js.map +1 -1
  9. package/dist/acp/types.d.ts +32 -1
  10. package/dist/acp/types.d.ts.map +1 -1
  11. package/dist/acp/types.js.map +1 -1
  12. package/dist/agent/agent-manager.d.ts +65 -1
  13. package/dist/agent/agent-manager.d.ts.map +1 -1
  14. package/dist/agent/agent-manager.js +464 -183
  15. package/dist/agent/agent-manager.js.map +1 -1
  16. package/dist/agent/types.d.ts +1 -1
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/api/server.d.ts +3 -0
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +37 -6
  21. package/dist/api/server.js.map +1 -1
  22. package/dist/auth/index.d.ts +2 -0
  23. package/dist/auth/index.d.ts.map +1 -0
  24. package/dist/auth/index.js +2 -0
  25. package/dist/auth/index.js.map +1 -0
  26. package/dist/auth/token.d.ts +41 -0
  27. package/dist/auth/token.d.ts.map +1 -0
  28. package/dist/auth/token.js +73 -0
  29. package/dist/auth/token.js.map +1 -0
  30. package/dist/cli/acp.d.ts +2 -23
  31. package/dist/cli/acp.d.ts.map +1 -1
  32. package/dist/cli/acp.js +127 -61
  33. package/dist/cli/acp.js.map +1 -1
  34. package/dist/cli/index.js +147 -15
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/cli/mcp.d.ts +6 -0
  37. package/dist/cli/mcp.d.ts.map +1 -1
  38. package/dist/cli/mcp.js +268 -181
  39. package/dist/cli/mcp.js.map +1 -1
  40. package/dist/cli/parse-args.d.ts +20 -0
  41. package/dist/cli/parse-args.d.ts.map +1 -0
  42. package/dist/cli/parse-args.js +43 -0
  43. package/dist/cli/parse-args.js.map +1 -0
  44. package/dist/cli/stable-instance-id.d.ts +8 -0
  45. package/dist/cli/stable-instance-id.d.ts.map +1 -0
  46. package/dist/cli/stable-instance-id.js +14 -0
  47. package/dist/cli/stable-instance-id.js.map +1 -0
  48. package/dist/config/project-config.d.ts +74 -7
  49. package/dist/config/project-config.d.ts.map +1 -1
  50. package/dist/config/project-config.js +123 -20
  51. package/dist/config/project-config.js.map +1 -1
  52. package/dist/map/adapter/acp-over-map.d.ts +17 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +384 -23
  55. package/dist/map/adapter/acp-over-map.js.map +1 -1
  56. package/dist/map/adapter/connection-manager.d.ts.map +1 -1
  57. package/dist/map/adapter/connection-manager.js +3 -0
  58. package/dist/map/adapter/connection-manager.js.map +1 -1
  59. package/dist/map/adapter/event-log.d.ts +87 -0
  60. package/dist/map/adapter/event-log.d.ts.map +1 -0
  61. package/dist/map/adapter/event-log.js +122 -0
  62. package/dist/map/adapter/event-log.js.map +1 -0
  63. package/dist/map/adapter/event-translator.js +6 -6
  64. package/dist/map/adapter/event-translator.js.map +1 -1
  65. package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
  66. package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
  67. package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
  68. package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
  69. package/dist/map/adapter/extensions/index.d.ts +10 -1
  70. package/dist/map/adapter/extensions/index.d.ts.map +1 -1
  71. package/dist/map/adapter/extensions/index.js +34 -0
  72. package/dist/map/adapter/extensions/index.js.map +1 -1
  73. package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
  74. package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
  75. package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
  76. package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
  77. package/dist/map/adapter/extensions/rename.d.ts +29 -0
  78. package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
  79. package/dist/map/adapter/extensions/rename.js +49 -0
  80. package/dist/map/adapter/extensions/rename.js.map +1 -0
  81. package/dist/map/adapter/extensions/task.d.ts.map +1 -1
  82. package/dist/map/adapter/extensions/task.js +10 -0
  83. package/dist/map/adapter/extensions/task.js.map +1 -1
  84. package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
  85. package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
  86. package/dist/map/adapter/extensions/update-metadata.js +67 -0
  87. package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
  88. package/dist/map/adapter/index.d.ts +2 -1
  89. package/dist/map/adapter/index.d.ts.map +1 -1
  90. package/dist/map/adapter/index.js +8 -2
  91. package/dist/map/adapter/index.js.map +1 -1
  92. package/dist/map/adapter/interface.d.ts +2 -0
  93. package/dist/map/adapter/interface.d.ts.map +1 -1
  94. package/dist/map/adapter/map-adapter.d.ts +3 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +258 -35
  97. package/dist/map/adapter/map-adapter.js.map +1 -1
  98. package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
  99. package/dist/map/adapter/subscription-manager.js +5 -1
  100. package/dist/map/adapter/subscription-manager.js.map +1 -1
  101. package/dist/map/adapter/types.d.ts +2 -0
  102. package/dist/map/adapter/types.d.ts.map +1 -1
  103. package/dist/mcp/map-client.d.ts +39 -0
  104. package/dist/mcp/map-client.d.ts.map +1 -0
  105. package/dist/mcp/map-client.js +129 -0
  106. package/dist/mcp/map-client.js.map +1 -0
  107. package/dist/mcp/mcp-server.d.ts +14 -0
  108. package/dist/mcp/mcp-server.d.ts.map +1 -1
  109. package/dist/mcp/mcp-server.js +113 -85
  110. package/dist/mcp/mcp-server.js.map +1 -1
  111. package/dist/mcp/types.d.ts +9 -1
  112. package/dist/mcp/types.d.ts.map +1 -1
  113. package/dist/mcp/types.js.map +1 -1
  114. package/dist/metrics/metrics.js +1 -1
  115. package/dist/metrics/metrics.js.map +1 -1
  116. package/dist/roles/capabilities.d.ts +3 -1
  117. package/dist/roles/capabilities.d.ts.map +1 -1
  118. package/dist/roles/capabilities.js +17 -7
  119. package/dist/roles/capabilities.js.map +1 -1
  120. package/dist/roles/config-loader.d.ts +6 -6
  121. package/dist/roles/config-loader.d.ts.map +1 -1
  122. package/dist/roles/config-loader.js +6 -6
  123. package/dist/roles/config-loader.js.map +1 -1
  124. package/dist/roles/registry.d.ts +2 -2
  125. package/dist/roles/registry.js +2 -2
  126. package/dist/server/combined-server.d.ts +20 -0
  127. package/dist/server/combined-server.d.ts.map +1 -1
  128. package/dist/server/combined-server.js +107 -8
  129. package/dist/server/combined-server.js.map +1 -1
  130. package/dist/store/event-store.d.ts +2 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +69 -20
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +18 -0
  135. package/dist/store/types/agents.d.ts.map +1 -1
  136. package/dist/store/types/events.d.ts +1 -1
  137. package/dist/store/types/events.d.ts.map +1 -1
  138. package/dist/task/backend/index.d.ts +47 -29
  139. package/dist/task/backend/index.d.ts.map +1 -1
  140. package/dist/task/backend/index.js +109 -71
  141. package/dist/task/backend/index.js.map +1 -1
  142. package/dist/task/backend/memory.d.ts +1 -0
  143. package/dist/task/backend/memory.d.ts.map +1 -1
  144. package/dist/task/backend/memory.js +3 -0
  145. package/dist/task/backend/memory.js.map +1 -1
  146. package/dist/task/backend/opentasks/backend.d.ts +140 -0
  147. package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
  148. package/dist/task/backend/opentasks/backend.js +1023 -0
  149. package/dist/task/backend/opentasks/backend.js.map +1 -0
  150. package/dist/task/backend/opentasks/client.d.ts +337 -0
  151. package/dist/task/backend/opentasks/client.d.ts.map +1 -0
  152. package/dist/task/backend/opentasks/client.js +225 -0
  153. package/dist/task/backend/opentasks/client.js.map +1 -0
  154. package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
  155. package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
  156. package/dist/task/backend/opentasks/daemon-manager.js +195 -0
  157. package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
  158. package/dist/task/backend/opentasks/index.d.ts +21 -0
  159. package/dist/task/backend/opentasks/index.d.ts.map +1 -0
  160. package/dist/task/backend/opentasks/index.js +21 -0
  161. package/dist/task/backend/opentasks/index.js.map +1 -0
  162. package/dist/task/backend/opentasks/mapping.d.ts +48 -0
  163. package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
  164. package/dist/task/backend/opentasks/mapping.js +77 -0
  165. package/dist/task/backend/opentasks/mapping.js.map +1 -0
  166. package/dist/task/backend/types.d.ts +33 -53
  167. package/dist/task/backend/types.d.ts.map +1 -1
  168. package/dist/task/backend/types.js +7 -11
  169. package/dist/task/backend/types.js.map +1 -1
  170. package/dist/task/backend/unified-tool-provider.d.ts +57 -0
  171. package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
  172. package/dist/task/backend/unified-tool-provider.js +623 -0
  173. package/dist/task/backend/unified-tool-provider.js.map +1 -0
  174. package/dist/teams/team-loader.d.ts +2 -2
  175. package/dist/teams/team-loader.js +3 -3
  176. package/dist/teams/team-loader.js.map +1 -1
  177. package/dist/teams/team-runtime.d.ts.map +1 -1
  178. package/dist/teams/team-runtime.js +2 -0
  179. package/dist/teams/team-runtime.js.map +1 -1
  180. package/docs/architecture.md +7 -6
  181. package/docs/configuration.md +26 -62
  182. package/docs/implementation-details.md +5 -5
  183. package/docs/implementation-summary.md +17 -17
  184. package/docs/plan-self-driving-support.md +4 -4
  185. package/docs/spec-self-driving-support.md +10 -10
  186. package/docs/team-templates.md +2 -2
  187. package/docs/teams.md +3 -3
  188. package/docs/troubleshooting.md +10 -11
  189. package/package.json +6 -4
  190. package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
  191. package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
  192. package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
  193. package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
  194. package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
  195. package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
  196. package/src/acp/__tests__/integration.test.ts +56 -31
  197. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  198. package/src/acp/macro-agent.ts +170 -36
  199. package/src/acp/types.ts +46 -1
  200. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  201. package/src/agent/agent-manager.ts +714 -261
  202. package/src/agent/types.ts +3 -1
  203. package/src/api/server.ts +41 -7
  204. package/src/auth/__tests__/token.test.ts +100 -0
  205. package/src/auth/index.ts +1 -0
  206. package/src/auth/token.ts +82 -0
  207. package/src/cli/__tests__/acp.test.ts +1 -1
  208. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  209. package/src/cli/acp.ts +130 -72
  210. package/src/cli/index.ts +120 -14
  211. package/src/cli/mcp.ts +311 -207
  212. package/src/cli/parse-args.ts +54 -0
  213. package/src/cli/stable-instance-id.ts +14 -0
  214. package/src/config/project-config.ts +190 -27
  215. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  216. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
  217. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  218. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
  219. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  220. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  221. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  222. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  223. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  224. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  225. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  226. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  227. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  228. package/src/map/adapter/acp-over-map.ts +678 -66
  229. package/src/map/adapter/connection-manager.ts +3 -0
  230. package/src/map/adapter/event-log.ts +208 -0
  231. package/src/map/adapter/event-translator.ts +6 -6
  232. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  233. package/src/map/adapter/extensions/index.ts +60 -0
  234. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  235. package/src/map/adapter/extensions/task.ts +11 -0
  236. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  237. package/src/map/adapter/index.ts +28 -0
  238. package/src/map/adapter/interface.ts +2 -0
  239. package/src/map/adapter/map-adapter.ts +312 -47
  240. package/src/map/adapter/subscription-manager.ts +5 -1
  241. package/src/map/adapter/types.ts +2 -0
  242. package/src/mcp/__tests__/map-client.test.ts +386 -0
  243. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  244. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  245. package/src/mcp/map-client.ts +177 -0
  246. package/src/mcp/mcp-server.ts +191 -100
  247. package/src/mcp/types.ts +6 -1
  248. package/src/metrics/metrics.ts +1 -1
  249. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  250. package/src/roles/__tests__/config-loader.test.ts +7 -7
  251. package/src/roles/capabilities.ts +17 -7
  252. package/src/roles/config-loader.ts +6 -6
  253. package/src/roles/registry.ts +2 -2
  254. package/src/server/__tests__/combined-server.test.ts +94 -21
  255. package/src/server/combined-server.ts +189 -33
  256. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  257. package/src/store/__tests__/event-store.test.ts +196 -1
  258. package/src/store/__tests__/instance.test.ts +3 -3
  259. package/src/store/event-store.ts +80 -21
  260. package/src/store/types/agents.ts +15 -0
  261. package/src/store/types/events.ts +1 -1
  262. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  263. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  264. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  265. package/src/task/backend/index.ts +156 -106
  266. package/src/task/backend/memory.ts +4 -0
  267. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  268. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  269. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  270. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  271. package/src/task/backend/opentasks/backend.ts +1323 -0
  272. package/src/task/backend/opentasks/client.ts +652 -0
  273. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  274. package/src/task/backend/opentasks/index.ts +69 -0
  275. package/src/task/backend/opentasks/mapping.ts +94 -0
  276. package/src/task/backend/types.ts +42 -66
  277. package/src/task/backend/unified-tool-provider.ts +779 -0
  278. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  279. package/src/teams/team-loader.ts +3 -3
  280. package/src/teams/team-runtime.ts +2 -0
  281. package/test_fixtures/README.md +2 -3
  282. package/test_fixtures/fixtures/index.ts +0 -3
  283. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  284. package/test_fixtures/fixtures/repos/index.ts +1 -3
  285. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  286. package/test_fixtures/fixtures/repos/types.ts +0 -11
  287. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  288. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  289. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  290. package/vitest.config.ts +1 -1
  291. package/vitest.e2e.config.ts +1 -1
  292. package/vitest.setup.ts +1 -30
  293. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  294. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  296. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  297. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  298. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  299. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  300. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  301. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  302. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  303. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  304. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  305. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  306. package/.macro-agent/teams/structured/team.yaml +0 -89
  307. package/docs/sudocode-integration.md +0 -383
  308. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  309. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  310. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  311. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  312. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  313. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  314. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  315. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  316. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  317. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  318. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  319. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  320. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  321. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  322. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  323. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  324. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  325. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  326. package/src/task/backend/sudocode/backend.ts +0 -1237
  327. package/src/task/backend/sudocode/client.ts +0 -515
  328. package/src/task/backend/sudocode/index.ts +0 -120
  329. package/src/task/backend/sudocode/mapping.ts +0 -93
  330. package/src/task/backend/sudocode/server-client.ts +0 -522
  331. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  332. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  333. package/src/task/backend/sudocode/tools.ts +0 -896
  334. package/src/task/backend/tool-provider.ts +0 -506
  335. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  336. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  337. package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
@@ -1,93 +0,0 @@
1
- /**
2
- * Status Mapping Utilities for Sudocode Integration
3
- *
4
- * Maps between sudocode issue statuses and macro-agent task statuses.
5
- *
6
- * @module task/backend/sudocode/mapping
7
- * @see s-8472 Pluggable Task Backend Integration with Sudocode
8
- */
9
-
10
- import type { TaskStatus } from "../../../store/types/index.js";
11
- import type { IssueStatus } from "./client.js";
12
-
13
- /**
14
- * Map sudocode issue status to macro-agent task status.
15
- *
16
- * Sudocode statuses:
17
- * - open: Not started
18
- * - in_progress: Currently being worked on
19
- * - blocked: Blocked by dependencies (handled via isBlocked flag)
20
- * - closed: Completed
21
- *
22
- * Macro-agent statuses:
23
- * - pending: Not started
24
- * - assigned: Assigned to an agent but not started
25
- * - in_progress: Currently executing
26
- * - completed: Finished successfully
27
- * - failed: Finished with error
28
- */
29
- export function mapSudocodeStatus(sudocodeStatus: IssueStatus): TaskStatus {
30
- switch (sudocodeStatus) {
31
- case "open":
32
- return "pending";
33
- case "in_progress":
34
- return "in_progress";
35
- case "blocked":
36
- // Blocked issues map to pending - the isBlocked flag handles blocking
37
- return "pending";
38
- case "closed":
39
- return "completed";
40
- default:
41
- return "pending";
42
- }
43
- }
44
-
45
- /**
46
- * Map macro-agent task status to sudocode issue status.
47
- *
48
- * Note: Some task statuses don't have direct sudocode equivalents:
49
- * - assigned: No equivalent in sudocode (maps to in_progress)
50
- * - failed: No equivalent in sudocode (maps to closed with error flag)
51
- */
52
- export function mapTaskStatus(taskStatus: TaskStatus): IssueStatus {
53
- switch (taskStatus) {
54
- case "pending":
55
- return "open";
56
- case "assigned":
57
- // Assigned tasks are considered in_progress in sudocode
58
- return "in_progress";
59
- case "in_progress":
60
- return "in_progress";
61
- case "completed":
62
- return "closed";
63
- case "failed":
64
- // Failed tasks are closed in sudocode (failure tracked in outputs)
65
- return "closed";
66
- default:
67
- return "open";
68
- }
69
- }
70
-
71
- /**
72
- * Map issue priority to numeric priority.
73
- * Sudocode uses 0 (highest) to 4 (lowest).
74
- * This matches the TaskBackend convention.
75
- */
76
- export function mapIssuePriority(priority: number): number {
77
- return Math.max(0, Math.min(4, priority));
78
- }
79
-
80
- /**
81
- * Check if a sudocode issue status indicates completion.
82
- */
83
- export function isIssueComplete(status: IssueStatus): boolean {
84
- return status === "closed";
85
- }
86
-
87
- /**
88
- * Check if a sudocode issue is blocked.
89
- * Note: This is explicit 'blocked' status, not dependency-based blocking.
90
- */
91
- export function isIssueBlocked(status: IssueStatus): boolean {
92
- return status === "blocked";
93
- }
@@ -1,522 +0,0 @@
1
- /**
2
- * ServerClient - SudocodeClient implementation for managed mode
3
- *
4
- * Connects to sudocode server via REST API and WebSocket for real-time events.
5
- * This is used when macro-agent is launched as a subprocess by the sudocode server.
6
- *
7
- * @module task/backend/sudocode/server-client
8
- * @see s-8472 Pluggable Task Backend Integration with Sudocode
9
- * @see i-5rrj 7A.2: Implement ServerClient (managed mode)
10
- */
11
-
12
- import type {
13
- SudocodeClient,
14
- ServerClientConfig,
15
- ListIssuesOptions,
16
- ListSpecsOptions,
17
- UpdateIssueInput,
18
- FeedbackInput,
19
- IssueChangeCallback,
20
- IssueChangeEvent,
21
- Unsubscribe,
22
- } from "./client.js";
23
-
24
- import type {
25
- Issue,
26
- Spec,
27
- RelationshipType,
28
- } from "@sudocode-ai/types";
29
-
30
- // =============================================================================
31
- // Types
32
- // =============================================================================
33
-
34
- /**
35
- * Standard API response format from sudocode server
36
- */
37
- interface ApiResponse<T> {
38
- success: boolean;
39
- data: T | null;
40
- message?: string;
41
- error_data?: string;
42
- }
43
-
44
- /**
45
- * WebSocket message format from sudocode server
46
- */
47
- interface WsMessage {
48
- type: string;
49
- projectId?: string;
50
- entityId?: string;
51
- action?: string;
52
- data?: unknown;
53
- }
54
-
55
- // =============================================================================
56
- // ServerClient Implementation
57
- // =============================================================================
58
-
59
- /**
60
- * ServerClient - REST + WebSocket client for managed mode
61
- *
62
- * Connects to a running sudocode server for all operations.
63
- * Uses WebSocket for real-time event subscriptions with polling fallback.
64
- */
65
- export class ServerClient implements SudocodeClient {
66
- private config: ServerClientConfig;
67
- private _ready: boolean = false;
68
- private ws: WebSocket | null = null;
69
- private wsReconnectTimer: ReturnType<typeof setTimeout> | null = null;
70
- private wsReconnectAttempts: number = 0;
71
- private readonly maxReconnectAttempts: number = 10;
72
- private readonly reconnectDelay: number = 1000;
73
- private subscribers: Map<string, Set<IssueChangeCallback>> = new Map();
74
- private globalSubscribers: Set<IssueChangeCallback> = new Set();
75
-
76
- constructor(config: ServerClientConfig) {
77
- this.config = config;
78
- this.initWebSocket();
79
- }
80
-
81
- // ─── HTTP Helpers ────────────────────────────────────────────────────────────
82
-
83
- private get headers(): Record<string, string> {
84
- const headers: Record<string, string> = {
85
- "Content-Type": "application/json",
86
- };
87
- if (this.config.projectId) {
88
- headers["X-Project-ID"] = this.config.projectId;
89
- }
90
- return headers;
91
- }
92
-
93
- private async request<T>(
94
- method: string,
95
- path: string,
96
- body?: unknown
97
- ): Promise<T> {
98
- const url = `${this.config.serverUrl}${path}`;
99
- const options: RequestInit = {
100
- method,
101
- headers: this.headers,
102
- };
103
-
104
- if (body !== undefined) {
105
- options.body = JSON.stringify(body);
106
- }
107
-
108
- const response = await fetch(url, options);
109
- const json = (await response.json()) as ApiResponse<T>;
110
-
111
- if (!json.success) {
112
- throw new Error(json.message || json.error_data || "Request failed");
113
- }
114
-
115
- return json.data as T;
116
- }
117
-
118
- private async get<T>(path: string): Promise<T> {
119
- return this.request<T>("GET", path);
120
- }
121
-
122
- private async post<T>(path: string, body?: unknown): Promise<T> {
123
- return this.request<T>("POST", path, body);
124
- }
125
-
126
- private async put<T>(path: string, body?: unknown): Promise<T> {
127
- return this.request<T>("PUT", path, body);
128
- }
129
-
130
- private async delete<T>(path: string, body?: unknown): Promise<T> {
131
- const url = `${this.config.serverUrl}${path}`;
132
- const options: RequestInit = {
133
- method: "DELETE",
134
- headers: this.headers,
135
- };
136
-
137
- if (body !== undefined) {
138
- options.body = JSON.stringify(body);
139
- }
140
-
141
- const response = await fetch(url, options);
142
- const json = (await response.json()) as ApiResponse<T>;
143
-
144
- if (!json.success) {
145
- throw new Error(json.message || json.error_data || "Request failed");
146
- }
147
-
148
- return json.data as T;
149
- }
150
-
151
- // ─── WebSocket Management ────────────────────────────────────────────────────
152
-
153
- private initWebSocket(): void {
154
- const wsUrl =
155
- this.config.wsUrl ??
156
- this.config.serverUrl.replace(/^http/, "ws") + "/ws";
157
-
158
- try {
159
- this.ws = new WebSocket(wsUrl);
160
-
161
- this.ws.onopen = () => {
162
- this._ready = true;
163
- this.wsReconnectAttempts = 0;
164
- console.log("[ServerClient] WebSocket connected");
165
- };
166
-
167
- this.ws.onclose = () => {
168
- this._ready = false;
169
- console.log("[ServerClient] WebSocket disconnected");
170
- this.scheduleReconnect();
171
- };
172
-
173
- this.ws.onerror = (error) => {
174
- console.error("[ServerClient] WebSocket error:", error);
175
- };
176
-
177
- this.ws.onmessage = (event) => {
178
- this.handleWsMessage(event.data);
179
- };
180
- } catch (error) {
181
- console.error("[ServerClient] Failed to initialize WebSocket:", error);
182
- this._ready = false;
183
- }
184
- }
185
-
186
- private scheduleReconnect(): void {
187
- if (this.wsReconnectTimer) {
188
- clearTimeout(this.wsReconnectTimer);
189
- }
190
-
191
- if (this.wsReconnectAttempts >= this.maxReconnectAttempts) {
192
- console.error(
193
- "[ServerClient] Max reconnect attempts reached, giving up"
194
- );
195
- return;
196
- }
197
-
198
- const delay = this.reconnectDelay * Math.pow(2, this.wsReconnectAttempts);
199
- this.wsReconnectAttempts++;
200
-
201
- console.log(
202
- `[ServerClient] Scheduling reconnect in ${delay}ms (attempt ${this.wsReconnectAttempts})`
203
- );
204
-
205
- this.wsReconnectTimer = setTimeout(() => {
206
- this.initWebSocket();
207
- }, delay);
208
- }
209
-
210
- private handleWsMessage(data: string): void {
211
- try {
212
- const message = JSON.parse(data) as WsMessage;
213
-
214
- // Handle issue-related messages
215
- if (message.type === "issue" && message.entityId && message.action) {
216
- const event: IssueChangeEvent = {
217
- type: this.mapWsAction(message.action),
218
- issueId: message.entityId,
219
- issue: message.data as Issue | undefined,
220
- };
221
-
222
- // Notify global subscribers
223
- for (const callback of this.globalSubscribers) {
224
- try {
225
- callback(event);
226
- } catch (error) {
227
- console.error(
228
- "[ServerClient] Error in global subscriber callback:",
229
- error
230
- );
231
- }
232
- }
233
-
234
- // Notify issue-specific subscribers
235
- const issueSubscribers = this.subscribers.get(message.entityId);
236
- if (issueSubscribers) {
237
- for (const callback of issueSubscribers) {
238
- try {
239
- callback(event);
240
- } catch (error) {
241
- console.error(
242
- "[ServerClient] Error in issue subscriber callback:",
243
- error
244
- );
245
- }
246
- }
247
- }
248
- }
249
- } catch (error) {
250
- console.error("[ServerClient] Failed to parse WebSocket message:", error);
251
- }
252
- }
253
-
254
- private mapWsAction(
255
- action: string
256
- ): IssueChangeEvent["type"] {
257
- switch (action) {
258
- case "created":
259
- return "created";
260
- case "updated":
261
- return "updated";
262
- case "deleted":
263
- return "deleted";
264
- case "status_changed":
265
- return "status_changed";
266
- default:
267
- return "updated";
268
- }
269
- }
270
-
271
- // ─── Issue Operations ────────────────────────────────────────────────────────
272
-
273
- async getIssue(id: string): Promise<Issue | null> {
274
- try {
275
- return await this.get<Issue>(`/api/issues/${id}`);
276
- } catch (error) {
277
- if (error instanceof Error && error.message.includes("not found")) {
278
- return null;
279
- }
280
- throw error;
281
- }
282
- }
283
-
284
- async listIssues(filter?: ListIssuesOptions): Promise<Issue[]> {
285
- const params = new URLSearchParams();
286
-
287
- if (filter?.status) {
288
- params.set("status", filter.status);
289
- }
290
- if (filter?.priority !== undefined) {
291
- params.set("priority", filter.priority.toString());
292
- }
293
- if (filter?.search) {
294
- params.set("search", filter.search);
295
- }
296
- if (filter?.archived !== undefined) {
297
- params.set("archived", filter.archived.toString());
298
- }
299
- if (filter?.limit !== undefined) {
300
- params.set("limit", filter.limit.toString());
301
- }
302
-
303
- const queryString = params.toString();
304
- const path = queryString ? `/api/issues?${queryString}` : "/api/issues";
305
-
306
- return this.get<Issue[]>(path);
307
- }
308
-
309
- async getReadyIssues(): Promise<Issue[]> {
310
- // Use the project status endpoint which returns ready issues
311
- const status = await this.get<{
312
- ready_issues: Array<{ id: string; title: string; priority: number }>;
313
- }>("/api/project/status");
314
-
315
- // Fetch full issue details for each ready issue
316
- const issues: Issue[] = [];
317
- for (const item of status.ready_issues) {
318
- const issue = await this.getIssue(item.id);
319
- if (issue) {
320
- issues.push(issue);
321
- }
322
- }
323
-
324
- return issues;
325
- }
326
-
327
- async updateIssue(id: string, updates: UpdateIssueInput): Promise<Issue> {
328
- return this.put<Issue>(`/api/issues/${id}`, updates);
329
- }
330
-
331
- // ─── Relationship Operations ─────────────────────────────────────────────────
332
-
333
- async createLink(
334
- from: string,
335
- to: string,
336
- type: RelationshipType
337
- ): Promise<void> {
338
- const fromType = from.startsWith("s-") ? "spec" : "issue";
339
- const toType = to.startsWith("s-") ? "spec" : "issue";
340
-
341
- await this.post("/api/relationships", {
342
- from_id: from,
343
- from_type: fromType,
344
- to_id: to,
345
- to_type: toType,
346
- relationship_type: type,
347
- });
348
- }
349
-
350
- async removeLink(
351
- from: string,
352
- to: string,
353
- type: RelationshipType
354
- ): Promise<void> {
355
- const fromType = from.startsWith("s-") ? "spec" : "issue";
356
- const toType = to.startsWith("s-") ? "spec" : "issue";
357
-
358
- await this.delete("/api/relationships", {
359
- from_id: from,
360
- from_type: fromType,
361
- to_id: to,
362
- to_type: toType,
363
- relationship_type: type,
364
- });
365
- }
366
-
367
- async getBlockers(issueId: string): Promise<Issue[]> {
368
- // Get incoming "blocks" relationships (issues that block this one)
369
- const relationships = await this.get<
370
- Array<{ from_id: string; from_type: string }>
371
- >(
372
- `/api/relationships/issue/${issueId}/incoming?relationship_type=blocks`
373
- );
374
-
375
- // Fetch full issue details for each blocker
376
- const blockers: Issue[] = [];
377
- for (const rel of relationships) {
378
- if (rel.from_type === "issue") {
379
- const issue = await this.getIssue(rel.from_id);
380
- if (issue) {
381
- blockers.push(issue);
382
- }
383
- }
384
- }
385
-
386
- return blockers;
387
- }
388
-
389
- async getBlocking(issueId: string): Promise<Issue[]> {
390
- // Get outgoing "blocks" relationships (issues this one blocks)
391
- const relationships = await this.get<
392
- Array<{ to_id: string; to_type: string }>
393
- >(
394
- `/api/relationships/issue/${issueId}/outgoing?relationship_type=blocks`
395
- );
396
-
397
- // Fetch full issue details for each blocked issue
398
- const blocked: Issue[] = [];
399
- for (const rel of relationships) {
400
- if (rel.to_type === "issue") {
401
- const issue = await this.getIssue(rel.to_id);
402
- if (issue) {
403
- blocked.push(issue);
404
- }
405
- }
406
- }
407
-
408
- return blocked;
409
- }
410
-
411
- // ─── Spec Operations ─────────────────────────────────────────────────────────
412
-
413
- async getSpec(id: string): Promise<Spec | null> {
414
- try {
415
- return await this.get<Spec>(`/api/specs/${id}`);
416
- } catch (error) {
417
- if (error instanceof Error && error.message.includes("not found")) {
418
- return null;
419
- }
420
- throw error;
421
- }
422
- }
423
-
424
- async listSpecs(filter?: ListSpecsOptions): Promise<Spec[]> {
425
- const params = new URLSearchParams();
426
-
427
- if (filter?.search) {
428
- params.set("search", filter.search);
429
- }
430
- if (filter?.limit !== undefined) {
431
- params.set("limit", filter.limit.toString());
432
- }
433
-
434
- const queryString = params.toString();
435
- const path = queryString ? `/api/specs?${queryString}` : "/api/specs";
436
-
437
- return this.get<Spec[]>(path);
438
- }
439
-
440
- // ─── Feedback Operations ─────────────────────────────────────────────────────
441
-
442
- async addFeedback(
443
- fromIssueId: string | undefined,
444
- toId: string,
445
- feedback: FeedbackInput
446
- ): Promise<void> {
447
- await this.post("/api/feedback", {
448
- from_id: fromIssueId,
449
- to_id: toId,
450
- feedback_type: feedback.type,
451
- content: feedback.content,
452
- agent: feedback.agent,
453
- line: feedback.anchor?.line,
454
- text: feedback.anchor?.text,
455
- });
456
- }
457
-
458
- // ─── Event Subscription ──────────────────────────────────────────────────────
459
-
460
- onIssueChange(callback: IssueChangeCallback): Unsubscribe;
461
- onIssueChange(issueId: string, callback: IssueChangeCallback): Unsubscribe;
462
- onIssueChange(
463
- callbackOrId: IssueChangeCallback | string,
464
- maybeCallback?: IssueChangeCallback
465
- ): Unsubscribe {
466
- if (typeof callbackOrId === "function") {
467
- // Global subscription
468
- const callback = callbackOrId;
469
- this.globalSubscribers.add(callback);
470
-
471
- return () => {
472
- this.globalSubscribers.delete(callback);
473
- };
474
- } else {
475
- // Issue-specific subscription
476
- const issueId = callbackOrId;
477
- const callback = maybeCallback!;
478
-
479
- if (!this.subscribers.has(issueId)) {
480
- this.subscribers.set(issueId, new Set());
481
- }
482
- this.subscribers.get(issueId)!.add(callback);
483
-
484
- return () => {
485
- const subs = this.subscribers.get(issueId);
486
- if (subs) {
487
- subs.delete(callback);
488
- if (subs.size === 0) {
489
- this.subscribers.delete(issueId);
490
- }
491
- }
492
- };
493
- }
494
- }
495
-
496
- // ─── Lifecycle ───────────────────────────────────────────────────────────────
497
-
498
- isReady(): boolean {
499
- return this._ready;
500
- }
501
-
502
- close(): void {
503
- this._ready = false;
504
-
505
- // Clear reconnect timer
506
- if (this.wsReconnectTimer) {
507
- clearTimeout(this.wsReconnectTimer);
508
- this.wsReconnectTimer = null;
509
- }
510
-
511
- // Close WebSocket
512
- if (this.ws) {
513
- this.ws.onclose = null; // Prevent reconnect attempt
514
- this.ws.close();
515
- this.ws = null;
516
- }
517
-
518
- // Clear subscribers
519
- this.globalSubscribers.clear();
520
- this.subscribers.clear();
521
- }
522
- }