macro-agent 0.0.17 → 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 (338) 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 +17 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +183 -55
  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 +23 -0
  53. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  54. package/dist/map/adapter/acp-over-map.js +482 -55
  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 +4 -0
  95. package/dist/map/adapter/map-adapter.d.ts.map +1 -1
  96. package/dist/map/adapter/map-adapter.js +302 -30
  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 +7 -1
  131. package/dist/store/event-store.d.ts.map +1 -1
  132. package/dist/store/event-store.js +91 -8
  133. package/dist/store/event-store.js.map +1 -1
  134. package/dist/store/types/agents.d.ts +23 -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__/history.test.ts +8 -4
  197. package/src/acp/__tests__/integration.test.ts +56 -31
  198. package/src/acp/__tests__/macro-agent.test.ts +16 -7
  199. package/src/acp/macro-agent.ts +230 -62
  200. package/src/acp/types.ts +46 -1
  201. package/src/agent/__tests__/agent-manager.test.ts +228 -2
  202. package/src/agent/agent-manager.ts +714 -261
  203. package/src/agent/types.ts +3 -1
  204. package/src/api/server.ts +41 -7
  205. package/src/auth/__tests__/token.test.ts +100 -0
  206. package/src/auth/index.ts +1 -0
  207. package/src/auth/token.ts +82 -0
  208. package/src/cli/__tests__/acp.test.ts +1 -1
  209. package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
  210. package/src/cli/acp.ts +130 -72
  211. package/src/cli/index.ts +120 -14
  212. package/src/cli/mcp.ts +311 -207
  213. package/src/cli/parse-args.ts +54 -0
  214. package/src/cli/stable-instance-id.ts +14 -0
  215. package/src/config/project-config.ts +190 -27
  216. package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
  217. package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +820 -0
  218. package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
  219. package/src/map/adapter/__tests__/acp-over-map-history.test.ts +724 -2
  220. package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
  221. package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
  222. package/src/map/adapter/__tests__/event-log.test.ts +527 -0
  223. package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
  224. package/src/map/adapter/__tests__/extensions.test.ts +408 -0
  225. package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
  226. package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
  227. package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
  228. package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
  229. package/src/map/adapter/acp-over-map.ts +777 -92
  230. package/src/map/adapter/connection-manager.ts +3 -0
  231. package/src/map/adapter/event-log.ts +208 -0
  232. package/src/map/adapter/event-translator.ts +6 -6
  233. package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
  234. package/src/map/adapter/extensions/index.ts +60 -0
  235. package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
  236. package/src/map/adapter/extensions/task.ts +11 -0
  237. package/src/map/adapter/extensions/update-metadata.ts +126 -0
  238. package/src/map/adapter/index.ts +28 -0
  239. package/src/map/adapter/interface.ts +2 -0
  240. package/src/map/adapter/map-adapter.ts +373 -38
  241. package/src/map/adapter/subscription-manager.ts +5 -1
  242. package/src/map/adapter/types.ts +2 -0
  243. package/src/mcp/__tests__/map-client.test.ts +386 -0
  244. package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
  245. package/src/mcp/__tests__/mcp-server.test.ts +100 -1
  246. package/src/mcp/map-client.ts +177 -0
  247. package/src/mcp/mcp-server.ts +191 -100
  248. package/src/mcp/types.ts +6 -1
  249. package/src/metrics/metrics.ts +1 -1
  250. package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
  251. package/src/roles/__tests__/config-loader.test.ts +7 -7
  252. package/src/roles/capabilities.ts +17 -7
  253. package/src/roles/config-loader.ts +6 -6
  254. package/src/roles/registry.ts +2 -2
  255. package/src/server/__tests__/combined-server.test.ts +94 -21
  256. package/src/server/combined-server.ts +189 -33
  257. package/src/steering/__tests__/steering-integration.test.ts +1 -1
  258. package/src/store/__tests__/event-store.test.ts +236 -1
  259. package/src/store/__tests__/instance.test.ts +3 -3
  260. package/src/store/event-store.ts +109 -8
  261. package/src/store/types/agents.ts +16 -0
  262. package/src/store/types/events.ts +1 -1
  263. package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
  264. package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
  265. package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
  266. package/src/task/backend/index.ts +156 -106
  267. package/src/task/backend/memory.ts +4 -0
  268. package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
  269. package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
  270. package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
  271. package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
  272. package/src/task/backend/opentasks/backend.ts +1323 -0
  273. package/src/task/backend/opentasks/client.ts +652 -0
  274. package/src/task/backend/opentasks/daemon-manager.ts +253 -0
  275. package/src/task/backend/opentasks/index.ts +69 -0
  276. package/src/task/backend/opentasks/mapping.ts +94 -0
  277. package/src/task/backend/types.ts +42 -66
  278. package/src/task/backend/unified-tool-provider.ts +779 -0
  279. package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
  280. package/src/teams/team-loader.ts +3 -3
  281. package/src/teams/team-runtime.ts +2 -0
  282. package/test_fixtures/README.md +2 -3
  283. package/test_fixtures/fixtures/index.ts +0 -3
  284. package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
  285. package/test_fixtures/fixtures/repos/index.ts +1 -3
  286. package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
  287. package/test_fixtures/fixtures/repos/types.ts +0 -11
  288. package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
  289. package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
  290. package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
  291. package/vitest.config.ts +1 -1
  292. package/vitest.e2e.config.ts +1 -1
  293. package/vitest.setup.ts +1 -30
  294. package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
  295. package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
  296. package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
  297. package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
  298. package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
  299. package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
  300. package/.macro-agent/teams/self-driving/team.yaml +0 -103
  301. package/.macro-agent/teams/structured/prompts/developer.md +0 -26
  302. package/.macro-agent/teams/structured/prompts/lead.md +0 -25
  303. package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
  304. package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
  305. package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
  306. package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
  307. package/.macro-agent/teams/structured/team.yaml +0 -89
  308. package/docs/sudocode-integration.md +0 -383
  309. package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
  310. package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
  311. package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
  312. package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
  313. package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
  314. package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
  315. package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
  316. package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
  317. package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
  318. package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
  319. package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
  320. package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
  321. package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
  322. package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
  323. package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
  324. package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
  325. package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
  326. package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
  327. package/src/task/backend/sudocode/backend.ts +0 -1237
  328. package/src/task/backend/sudocode/client.ts +0 -515
  329. package/src/task/backend/sudocode/index.ts +0 -120
  330. package/src/task/backend/sudocode/mapping.ts +0 -93
  331. package/src/task/backend/sudocode/server-client.ts +0 -522
  332. package/src/task/backend/sudocode/standalone-client.ts +0 -623
  333. package/src/task/backend/sudocode/sync-policy.ts +0 -387
  334. package/src/task/backend/sudocode/tools.ts +0 -896
  335. package/src/task/backend/tool-provider.ts +0 -506
  336. package/test_fixtures/fixtures/sudocode/index.ts +0 -29
  337. package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
  338. 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
- }