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.
- package/.claude/settings.local.json +3 -1
- package/.sudocode/specs.jsonl +4 -0
- package/CLAUDE.md +16 -14
- package/README.md +11 -29
- package/dist/acp/macro-agent.d.ts +17 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +183 -55
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/types.d.ts +32 -1
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +65 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +464 -183
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/api/server.d.ts +3 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +37 -6
- package/dist/api/server.js.map +1 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/token.d.ts +41 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +73 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/cli/acp.d.ts +2 -23
- package/dist/cli/acp.d.ts.map +1 -1
- package/dist/cli/acp.js +127 -61
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +147 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +6 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +268 -181
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +43 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/stable-instance-id.d.ts +8 -0
- package/dist/cli/stable-instance-id.d.ts.map +1 -0
- package/dist/cli/stable-instance-id.js +14 -0
- package/dist/cli/stable-instance-id.js.map +1 -0
- package/dist/config/project-config.d.ts +74 -7
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +123 -20
- package/dist/config/project-config.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts +23 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +482 -55
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/connection-manager.d.ts.map +1 -1
- package/dist/map/adapter/connection-manager.js +3 -0
- package/dist/map/adapter/connection-manager.js.map +1 -1
- package/dist/map/adapter/event-log.d.ts +87 -0
- package/dist/map/adapter/event-log.d.ts.map +1 -0
- package/dist/map/adapter/event-log.js +122 -0
- package/dist/map/adapter/event-log.js.map +1 -0
- package/dist/map/adapter/event-translator.js +6 -6
- package/dist/map/adapter/event-translator.js.map +1 -1
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
- package/dist/map/adapter/extensions/index.d.ts +10 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +34 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
- package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
- package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
- package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
- package/dist/map/adapter/extensions/rename.d.ts +29 -0
- package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
- package/dist/map/adapter/extensions/rename.js +49 -0
- package/dist/map/adapter/extensions/rename.js.map +1 -0
- package/dist/map/adapter/extensions/task.d.ts.map +1 -1
- package/dist/map/adapter/extensions/task.js +10 -0
- package/dist/map/adapter/extensions/task.js.map +1 -1
- package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
- package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
- package/dist/map/adapter/extensions/update-metadata.js +67 -0
- package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
- package/dist/map/adapter/index.d.ts +2 -1
- package/dist/map/adapter/index.d.ts.map +1 -1
- package/dist/map/adapter/index.js +8 -2
- package/dist/map/adapter/index.js.map +1 -1
- package/dist/map/adapter/interface.d.ts +2 -0
- package/dist/map/adapter/interface.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.d.ts +4 -0
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +302 -30
- package/dist/map/adapter/map-adapter.js.map +1 -1
- package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
- package/dist/map/adapter/subscription-manager.js +5 -1
- package/dist/map/adapter/subscription-manager.js.map +1 -1
- package/dist/map/adapter/types.d.ts +2 -0
- package/dist/map/adapter/types.d.ts.map +1 -1
- package/dist/mcp/map-client.d.ts +39 -0
- package/dist/mcp/map-client.d.ts.map +1 -0
- package/dist/mcp/map-client.js +129 -0
- package/dist/mcp/map-client.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +14 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +113 -85
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/types.d.ts +9 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/metrics/metrics.js +1 -1
- package/dist/metrics/metrics.js.map +1 -1
- package/dist/roles/capabilities.d.ts +3 -1
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +17 -7
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/config-loader.d.ts +6 -6
- package/dist/roles/config-loader.d.ts.map +1 -1
- package/dist/roles/config-loader.js +6 -6
- package/dist/roles/config-loader.js.map +1 -1
- package/dist/roles/registry.d.ts +2 -2
- package/dist/roles/registry.js +2 -2
- package/dist/server/combined-server.d.ts +20 -0
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +107 -8
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts +7 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +91 -8
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +23 -0
- package/dist/store/types/agents.d.ts.map +1 -1
- package/dist/store/types/events.d.ts +1 -1
- package/dist/store/types/events.d.ts.map +1 -1
- package/dist/task/backend/index.d.ts +47 -29
- package/dist/task/backend/index.d.ts.map +1 -1
- package/dist/task/backend/index.js +109 -71
- package/dist/task/backend/index.js.map +1 -1
- package/dist/task/backend/memory.d.ts +1 -0
- package/dist/task/backend/memory.d.ts.map +1 -1
- package/dist/task/backend/memory.js +3 -0
- package/dist/task/backend/memory.js.map +1 -1
- package/dist/task/backend/opentasks/backend.d.ts +140 -0
- package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
- package/dist/task/backend/opentasks/backend.js +1023 -0
- package/dist/task/backend/opentasks/backend.js.map +1 -0
- package/dist/task/backend/opentasks/client.d.ts +337 -0
- package/dist/task/backend/opentasks/client.d.ts.map +1 -0
- package/dist/task/backend/opentasks/client.js +225 -0
- package/dist/task/backend/opentasks/client.js.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.js +195 -0
- package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
- package/dist/task/backend/opentasks/index.d.ts +21 -0
- package/dist/task/backend/opentasks/index.d.ts.map +1 -0
- package/dist/task/backend/opentasks/index.js +21 -0
- package/dist/task/backend/opentasks/index.js.map +1 -0
- package/dist/task/backend/opentasks/mapping.d.ts +48 -0
- package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
- package/dist/task/backend/opentasks/mapping.js +77 -0
- package/dist/task/backend/opentasks/mapping.js.map +1 -0
- package/dist/task/backend/types.d.ts +33 -53
- package/dist/task/backend/types.d.ts.map +1 -1
- package/dist/task/backend/types.js +7 -11
- package/dist/task/backend/types.js.map +1 -1
- package/dist/task/backend/unified-tool-provider.d.ts +57 -0
- package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
- package/dist/task/backend/unified-tool-provider.js +623 -0
- package/dist/task/backend/unified-tool-provider.js.map +1 -0
- package/dist/teams/team-loader.d.ts +2 -2
- package/dist/teams/team-loader.js +3 -3
- package/dist/teams/team-loader.js.map +1 -1
- package/dist/teams/team-runtime.d.ts.map +1 -1
- package/dist/teams/team-runtime.js +2 -0
- package/dist/teams/team-runtime.js.map +1 -1
- package/docs/architecture.md +7 -6
- package/docs/configuration.md +26 -62
- package/docs/implementation-details.md +5 -5
- package/docs/implementation-summary.md +17 -17
- package/docs/plan-self-driving-support.md +4 -4
- package/docs/spec-self-driving-support.md +10 -10
- package/docs/team-templates.md +2 -2
- package/docs/teams.md +3 -3
- package/docs/troubleshooting.md +10 -11
- package/package.json +6 -4
- package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
- package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
- package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
- package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
- package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
- package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
- package/src/acp/__tests__/history.test.ts +8 -4
- package/src/acp/__tests__/integration.test.ts +56 -31
- package/src/acp/__tests__/macro-agent.test.ts +16 -7
- package/src/acp/macro-agent.ts +230 -62
- package/src/acp/types.ts +46 -1
- package/src/agent/__tests__/agent-manager.test.ts +228 -2
- package/src/agent/agent-manager.ts +714 -261
- package/src/agent/types.ts +3 -1
- package/src/api/server.ts +41 -7
- package/src/auth/__tests__/token.test.ts +100 -0
- package/src/auth/index.ts +1 -0
- package/src/auth/token.ts +82 -0
- package/src/cli/__tests__/acp.test.ts +1 -1
- package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
- package/src/cli/acp.ts +130 -72
- package/src/cli/index.ts +120 -14
- package/src/cli/mcp.ts +311 -207
- package/src/cli/parse-args.ts +54 -0
- package/src/cli/stable-instance-id.ts +14 -0
- package/src/config/project-config.ts +190 -27
- package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
- package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +820 -0
- package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
- package/src/map/adapter/__tests__/acp-over-map-history.test.ts +724 -2
- package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
- package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
- package/src/map/adapter/__tests__/event-log.test.ts +527 -0
- package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
- package/src/map/adapter/__tests__/extensions.test.ts +408 -0
- package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
- package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
- package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
- package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
- package/src/map/adapter/acp-over-map.ts +777 -92
- package/src/map/adapter/connection-manager.ts +3 -0
- package/src/map/adapter/event-log.ts +208 -0
- package/src/map/adapter/event-translator.ts +6 -6
- package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
- package/src/map/adapter/extensions/index.ts +60 -0
- package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
- package/src/map/adapter/extensions/task.ts +11 -0
- package/src/map/adapter/extensions/update-metadata.ts +126 -0
- package/src/map/adapter/index.ts +28 -0
- package/src/map/adapter/interface.ts +2 -0
- package/src/map/adapter/map-adapter.ts +373 -38
- package/src/map/adapter/subscription-manager.ts +5 -1
- package/src/map/adapter/types.ts +2 -0
- package/src/mcp/__tests__/map-client.test.ts +386 -0
- package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
- package/src/mcp/__tests__/mcp-server.test.ts +100 -1
- package/src/mcp/map-client.ts +177 -0
- package/src/mcp/mcp-server.ts +191 -100
- package/src/mcp/types.ts +6 -1
- package/src/metrics/metrics.ts +1 -1
- package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
- package/src/roles/__tests__/config-loader.test.ts +7 -7
- package/src/roles/capabilities.ts +17 -7
- package/src/roles/config-loader.ts +6 -6
- package/src/roles/registry.ts +2 -2
- package/src/server/__tests__/combined-server.test.ts +94 -21
- package/src/server/combined-server.ts +189 -33
- package/src/steering/__tests__/steering-integration.test.ts +1 -1
- package/src/store/__tests__/event-store.test.ts +236 -1
- package/src/store/__tests__/instance.test.ts +3 -3
- package/src/store/event-store.ts +109 -8
- package/src/store/types/agents.ts +16 -0
- package/src/store/types/events.ts +1 -1
- package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
- package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
- package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
- package/src/task/backend/index.ts +156 -106
- package/src/task/backend/memory.ts +4 -0
- package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
- package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
- package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
- package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
- package/src/task/backend/opentasks/backend.ts +1323 -0
- package/src/task/backend/opentasks/client.ts +652 -0
- package/src/task/backend/opentasks/daemon-manager.ts +253 -0
- package/src/task/backend/opentasks/index.ts +69 -0
- package/src/task/backend/opentasks/mapping.ts +94 -0
- package/src/task/backend/types.ts +42 -66
- package/src/task/backend/unified-tool-provider.ts +779 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
- package/src/teams/team-loader.ts +3 -3
- package/src/teams/team-runtime.ts +2 -0
- package/test_fixtures/README.md +2 -3
- package/test_fixtures/fixtures/index.ts +0 -3
- package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
- package/test_fixtures/fixtures/repos/index.ts +1 -3
- package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
- package/test_fixtures/fixtures/repos/types.ts +0 -11
- package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
- package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
- package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
- package/vitest.config.ts +1 -1
- package/vitest.e2e.config.ts +1 -1
- package/vitest.setup.ts +1 -30
- package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
- package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
- package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
- package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
- package/.macro-agent/teams/self-driving/team.yaml +0 -103
- package/.macro-agent/teams/structured/prompts/developer.md +0 -26
- package/.macro-agent/teams/structured/prompts/lead.md +0 -25
- package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
- package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
- package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
- package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
- package/.macro-agent/teams/structured/team.yaml +0 -89
- package/docs/sudocode-integration.md +0 -383
- package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
- package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
- package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
- package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
- package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
- package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
- package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
- package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
- package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
- package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
- package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
- package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
- package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
- package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
- package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
- package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
- package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
- package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
- package/src/task/backend/sudocode/backend.ts +0 -1237
- package/src/task/backend/sudocode/client.ts +0 -515
- package/src/task/backend/sudocode/index.ts +0 -120
- package/src/task/backend/sudocode/mapping.ts +0 -93
- package/src/task/backend/sudocode/server-client.ts +0 -522
- package/src/task/backend/sudocode/standalone-client.ts +0 -623
- package/src/task/backend/sudocode/sync-policy.ts +0 -387
- package/src/task/backend/sudocode/tools.ts +0 -896
- package/src/task/backend/tool-provider.ts +0 -506
- package/test_fixtures/fixtures/sudocode/index.ts +0 -29
- package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
- 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
|
-
}
|