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,387 +0,0 @@
1
- /**
2
- * Sync Policy Engine for Sudocode Integration
3
- *
4
- * Handles bidirectional sync between tasks and issues based on configurable policies.
5
- *
6
- * @module task/backend/sudocode/sync-policy
7
- * @see s-8472 Pluggable Task Backend Integration with Sudocode
8
- * @see i-1udw 7B.3: Implement sync policy engine
9
- */
10
-
11
- import type { TaskId } from "../../../store/types/index.js";
12
- import type { IssueChangeEvent } from "./client.js";
13
-
14
- // =============================================================================
15
- // Sync Policy Types
16
- // =============================================================================
17
-
18
- /**
19
- * Policy for handling external issue closure
20
- */
21
- export type IssueClosed = "complete_task" | "fail_task" | "notify_only";
22
-
23
- /**
24
- * Policy for handling description changes
25
- */
26
- export type DescriptionChanged = "snapshot" | "propagate";
27
-
28
- /**
29
- * Policy for handling blocker changes
30
- */
31
- export type BlockerChanged = "update_blocked" | "notify_only";
32
-
33
- /**
34
- * Policy for updating issue on task completion
35
- */
36
- export type UpdateIssueOnComplete = "never" | "if_all_complete" | "always";
37
-
38
- /**
39
- * Sync policy configuration
40
- */
41
- export interface SyncPolicy {
42
- /** How to handle external issue closure */
43
- onIssueClosed: IssueClosed;
44
-
45
- /** How to handle description changes (default: 'snapshot') */
46
- onDescriptionChanged: DescriptionChanged;
47
-
48
- /** How to handle blocker changes */
49
- onBlockerChanged: BlockerChanged;
50
-
51
- /** Whether to update issue status on task start */
52
- updateIssueOnStart: boolean;
53
-
54
- /** Whether to update issue status on task complete */
55
- updateIssueOnComplete: UpdateIssueOnComplete;
56
- }
57
-
58
- /**
59
- * Default sync policy
60
- */
61
- export const defaultSyncPolicy: SyncPolicy = {
62
- onIssueClosed: "notify_only",
63
- onDescriptionChanged: "snapshot",
64
- onBlockerChanged: "update_blocked",
65
- updateIssueOnStart: true,
66
- updateIssueOnComplete: "never",
67
- };
68
-
69
- // =============================================================================
70
- // Sync Event Types
71
- // =============================================================================
72
-
73
- /**
74
- * Base sync event
75
- */
76
- export interface BaseSyncEvent {
77
- type: string;
78
- taskId: TaskId;
79
- issueId: string;
80
- }
81
-
82
- /**
83
- * Issue closed event
84
- */
85
- export interface IssueClosedSyncEvent extends BaseSyncEvent {
86
- type: "issue_closed";
87
- }
88
-
89
- /**
90
- * Issue deleted event
91
- */
92
- export interface IssueDeletedSyncEvent extends BaseSyncEvent {
93
- type: "issue_deleted";
94
- }
95
-
96
- /**
97
- * Blocker added event
98
- */
99
- export interface BlockerAddedSyncEvent extends BaseSyncEvent {
100
- type: "blocker_added";
101
- blockerIssueId?: string;
102
- }
103
-
104
- /**
105
- * Blocker removed event
106
- */
107
- export interface BlockerRemovedSyncEvent extends BaseSyncEvent {
108
- type: "blocker_removed";
109
- blockerIssueId?: string;
110
- }
111
-
112
- /**
113
- * Description changed event
114
- */
115
- export interface DescriptionChangedSyncEvent extends BaseSyncEvent {
116
- type: "description_changed";
117
- oldDescription?: string;
118
- newDescription?: string;
119
- }
120
-
121
- /**
122
- * Union of all sync events
123
- */
124
- export type SyncEvent =
125
- | IssueClosedSyncEvent
126
- | IssueDeletedSyncEvent
127
- | BlockerAddedSyncEvent
128
- | BlockerRemovedSyncEvent
129
- | DescriptionChangedSyncEvent;
130
-
131
- /**
132
- * Callback for sync events
133
- */
134
- export type SyncEventCallback = (event: SyncEvent) => void;
135
-
136
- // =============================================================================
137
- // Task Backend Interface (for engine to use)
138
- // =============================================================================
139
-
140
- /**
141
- * Interface for the task operations the sync engine needs
142
- */
143
- export interface SyncableTaskBackend {
144
- getTasksByIssue(issueId: string): TaskId[];
145
- get(taskId: TaskId): Promise<{ status: string } | null>;
146
- complete(taskId: TaskId, outputs?: { summary?: string }): Promise<void>;
147
- fail(taskId: TaskId, error: { code: string; message: string }): Promise<void>;
148
- update(taskId: TaskId, updates: { description?: string }): Promise<unknown>;
149
- }
150
-
151
- // =============================================================================
152
- // Sync Policy Engine
153
- // =============================================================================
154
-
155
- /**
156
- * SyncPolicyEngine handles bidirectional sync between tasks and issues
157
- * based on configurable policies.
158
- */
159
- export class SyncPolicyEngine {
160
- private readonly callbacks: SyncEventCallback[] = [];
161
-
162
- constructor(
163
- private readonly policy: SyncPolicy,
164
- private readonly backend: SyncableTaskBackend
165
- ) {}
166
-
167
- /**
168
- * Subscribe to sync events
169
- */
170
- onSyncEvent(callback: SyncEventCallback): () => void {
171
- this.callbacks.push(callback);
172
- return () => {
173
- const idx = this.callbacks.indexOf(callback);
174
- if (idx >= 0) this.callbacks.splice(idx, 1);
175
- };
176
- }
177
-
178
- /**
179
- * Emit a sync event to all subscribers
180
- */
181
- private emit(event: SyncEvent): void {
182
- for (const callback of this.callbacks) {
183
- try {
184
- callback(event);
185
- } catch {
186
- // Ignore callback errors
187
- }
188
- }
189
- }
190
-
191
- /**
192
- * Handle an issue change event
193
- */
194
- async handleIssueChange(event: IssueChangeEvent): Promise<void> {
195
- const boundTasks = this.backend.getTasksByIssue(event.issueId);
196
- if (boundTasks.length === 0) return;
197
-
198
- switch (event.type) {
199
- case "deleted":
200
- await this.handleIssueDeleted(boundTasks, event);
201
- break;
202
-
203
- case "status_changed":
204
- if (event.issue?.status === "closed") {
205
- await this.handleIssueClosed(boundTasks, event);
206
- }
207
- break;
208
-
209
- case "blocked":
210
- await this.handleBlockerAdded(boundTasks, event);
211
- break;
212
-
213
- case "unblocked":
214
- await this.handleBlockerRemoved(boundTasks, event);
215
- break;
216
-
217
- case "updated":
218
- await this.handleIssueUpdated(boundTasks, event);
219
- break;
220
- }
221
- }
222
-
223
- /**
224
- * Handle issue closed
225
- */
226
- private async handleIssueClosed(
227
- taskIds: TaskId[],
228
- event: IssueChangeEvent
229
- ): Promise<void> {
230
- for (const taskId of taskIds) {
231
- const task = await this.backend.get(taskId);
232
- if (!task || task.status === "completed" || task.status === "failed") {
233
- continue;
234
- }
235
-
236
- switch (this.policy.onIssueClosed) {
237
- case "complete_task":
238
- await this.backend.complete(taskId, {
239
- summary: "Issue closed externally",
240
- });
241
- break;
242
-
243
- case "fail_task":
244
- await this.backend.fail(taskId, {
245
- code: "ISSUE_CLOSED",
246
- message: "Bound issue was closed externally",
247
- });
248
- break;
249
-
250
- case "notify_only":
251
- this.emit({
252
- type: "issue_closed",
253
- taskId,
254
- issueId: event.issueId,
255
- });
256
- break;
257
- }
258
- }
259
- }
260
-
261
- /**
262
- * Handle issue deleted - always fails orphaned tasks
263
- */
264
- private async handleIssueDeleted(
265
- taskIds: TaskId[],
266
- event: IssueChangeEvent
267
- ): Promise<void> {
268
- for (const taskId of taskIds) {
269
- const task = await this.backend.get(taskId);
270
- if (!task || task.status === "completed" || task.status === "failed") {
271
- continue;
272
- }
273
-
274
- await this.backend.fail(taskId, {
275
- code: "ISSUE_DELETED",
276
- message: `Bound issue ${event.issueId} was deleted`,
277
- });
278
-
279
- this.emit({
280
- type: "issue_deleted",
281
- taskId,
282
- issueId: event.issueId,
283
- });
284
- }
285
- }
286
-
287
- /**
288
- * Handle blocker added to issue
289
- */
290
- private async handleBlockerAdded(
291
- taskIds: TaskId[],
292
- event: IssueChangeEvent
293
- ): Promise<void> {
294
- if (this.policy.onBlockerChanged === "update_blocked") {
295
- // isBlocked will be recomputed on next get()
296
- // Emit notification for bound tasks
297
- for (const taskId of taskIds) {
298
- this.emit({
299
- type: "blocker_added",
300
- taskId,
301
- issueId: event.issueId,
302
- });
303
- }
304
- } else {
305
- // notify_only - just emit events
306
- for (const taskId of taskIds) {
307
- this.emit({
308
- type: "blocker_added",
309
- taskId,
310
- issueId: event.issueId,
311
- });
312
- }
313
- }
314
- }
315
-
316
- /**
317
- * Handle blocker removed from issue
318
- */
319
- private async handleBlockerRemoved(
320
- taskIds: TaskId[],
321
- event: IssueChangeEvent
322
- ): Promise<void> {
323
- // Emit notification for bound tasks
324
- for (const taskId of taskIds) {
325
- this.emit({
326
- type: "blocker_removed",
327
- taskId,
328
- issueId: event.issueId,
329
- });
330
- }
331
- }
332
-
333
- /**
334
- * Handle issue updated (e.g., description changed)
335
- */
336
- private async handleIssueUpdated(
337
- taskIds: TaskId[],
338
- event: IssueChangeEvent
339
- ): Promise<void> {
340
- // Check if description changed
341
- const oldDescription = event.previousIssue?.content;
342
- const newDescription = event.issue?.content;
343
-
344
- if (oldDescription !== newDescription && newDescription !== undefined) {
345
- if (this.policy.onDescriptionChanged === "propagate") {
346
- // Update task descriptions
347
- for (const taskId of taskIds) {
348
- await this.backend.update(taskId, {
349
- description: newDescription,
350
- });
351
- }
352
- }
353
-
354
- // Always emit event for tracking
355
- for (const taskId of taskIds) {
356
- this.emit({
357
- type: "description_changed",
358
- taskId,
359
- issueId: event.issueId,
360
- oldDescription,
361
- newDescription,
362
- });
363
- }
364
- }
365
- }
366
-
367
- /**
368
- * Get the current sync policy
369
- */
370
- getPolicy(): SyncPolicy {
371
- return { ...this.policy };
372
- }
373
- }
374
-
375
- /**
376
- * Create a sync policy engine
377
- */
378
- export function createSyncPolicyEngine(
379
- policy: Partial<SyncPolicy>,
380
- backend: SyncableTaskBackend
381
- ): SyncPolicyEngine {
382
- const fullPolicy: SyncPolicy = {
383
- ...defaultSyncPolicy,
384
- ...policy,
385
- };
386
- return new SyncPolicyEngine(fullPolicy, backend);
387
- }