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,451 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backend Parity Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests that verify InMemoryTaskBackend and SudocodeTaskBackend produce
|
|
5
|
-
* identical results for the same operations. This ensures the pluggable
|
|
6
|
-
* backend contract is maintained.
|
|
7
|
-
*
|
|
8
|
-
* @module task/backend/__tests__/backend-parity.test
|
|
9
|
-
* @see s-8472 Pluggable Task Backend Integration
|
|
10
|
-
* @see s-1zcx Multi-Agent Orchestration Testing Strategy
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
14
|
-
import { createEventStore, type EventStore } from "../../../store/event-store.js";
|
|
15
|
-
import { InMemoryTaskBackend, createInMemoryTaskBackend } from "../memory.js";
|
|
16
|
-
import {
|
|
17
|
-
SudocodeTaskBackend,
|
|
18
|
-
createSudocodeTaskBackend,
|
|
19
|
-
} from "../sudocode/backend.js";
|
|
20
|
-
import type { SudocodeClient, Issue, IssueChangeCallback } from "../sudocode/client.js";
|
|
21
|
-
import type { TaskBackend, ExtendedTask } from "../types.js";
|
|
22
|
-
|
|
23
|
-
// Mock SudocodeClient that mimics InMemory behavior
|
|
24
|
-
function createMinimalMockClient(): SudocodeClient {
|
|
25
|
-
const issues = new Map<string, Issue>();
|
|
26
|
-
const issueBlockers = new Map<string, Issue[]>();
|
|
27
|
-
const issueBlocking = new Map<string, Issue[]>();
|
|
28
|
-
const issueChangeCallbacks: IssueChangeCallback[] = [];
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
getIssue: vi.fn(async (id: string) => issues.get(id) ?? null),
|
|
32
|
-
createIssue: vi.fn(async (data: Partial<Issue>) => {
|
|
33
|
-
const id = `i-${Date.now()}`;
|
|
34
|
-
const issue: Issue = {
|
|
35
|
-
id,
|
|
36
|
-
uuid: `uuid-${id}`,
|
|
37
|
-
title: data.title ?? "Test Issue",
|
|
38
|
-
status: data.status ?? "open",
|
|
39
|
-
priority: data.priority ?? 2,
|
|
40
|
-
created_at: new Date().toISOString(),
|
|
41
|
-
updated_at: new Date().toISOString(),
|
|
42
|
-
};
|
|
43
|
-
issues.set(id, issue);
|
|
44
|
-
return issue;
|
|
45
|
-
}),
|
|
46
|
-
updateIssue: vi.fn(async (id: string, updates: Partial<Issue>) => {
|
|
47
|
-
const issue = issues.get(id);
|
|
48
|
-
if (!issue) throw new Error(`Issue not found: ${id}`);
|
|
49
|
-
Object.assign(issue, updates);
|
|
50
|
-
issue.updated_at = new Date().toISOString();
|
|
51
|
-
return issue;
|
|
52
|
-
}),
|
|
53
|
-
getReadyIssues: vi.fn(async () => {
|
|
54
|
-
return Array.from(issues.values()).filter((i) => {
|
|
55
|
-
const blockers = issueBlockers.get(i.id) ?? [];
|
|
56
|
-
return blockers.every((b) => b.status === "closed");
|
|
57
|
-
});
|
|
58
|
-
}),
|
|
59
|
-
getBlockers: vi.fn(async (id: string) => issueBlockers.get(id) ?? []),
|
|
60
|
-
getBlocking: vi.fn(async (id: string) => issueBlocking.get(id) ?? []),
|
|
61
|
-
createLink: vi.fn(async (from: string, to: string, type: string) => {
|
|
62
|
-
if (type === "blocks") {
|
|
63
|
-
const fromIssue = issues.get(from);
|
|
64
|
-
if (!fromIssue) throw new Error(`Issue not found: ${from}`);
|
|
65
|
-
const existing = issueBlockers.get(to) ?? [];
|
|
66
|
-
issueBlockers.set(to, [...existing, fromIssue]);
|
|
67
|
-
const blocking = issueBlocking.get(from) ?? [];
|
|
68
|
-
issueBlocking.set(from, [...blocking, issues.get(to)!]);
|
|
69
|
-
}
|
|
70
|
-
}),
|
|
71
|
-
removeLink: vi.fn(async (from: string, to: string, type: string) => {
|
|
72
|
-
if (type === "blocks") {
|
|
73
|
-
const blockers = issueBlockers.get(to) ?? [];
|
|
74
|
-
issueBlockers.set(to, blockers.filter((b) => b.id !== from));
|
|
75
|
-
const blocking = issueBlocking.get(from) ?? [];
|
|
76
|
-
issueBlocking.set(from, blocking.filter((b) => b.id !== to));
|
|
77
|
-
}
|
|
78
|
-
}),
|
|
79
|
-
onIssueChange: vi.fn((callback: IssueChangeCallback) => {
|
|
80
|
-
issueChangeCallbacks.push(callback);
|
|
81
|
-
return () => {
|
|
82
|
-
const idx = issueChangeCallbacks.indexOf(callback);
|
|
83
|
-
if (idx >= 0) issueChangeCallbacks.splice(idx, 1);
|
|
84
|
-
};
|
|
85
|
-
}),
|
|
86
|
-
close: vi.fn(),
|
|
87
|
-
isReady: vi.fn(() => true),
|
|
88
|
-
} as unknown as SudocodeClient;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
describe("Backend Parity", () => {
|
|
92
|
-
let memoryEventStore: EventStore;
|
|
93
|
-
let sudocodeEventStore: EventStore;
|
|
94
|
-
let memoryBackend: InMemoryTaskBackend;
|
|
95
|
-
let sudocodeBackend: SudocodeTaskBackend;
|
|
96
|
-
let mockClient: SudocodeClient;
|
|
97
|
-
const testAgentId = "agent_test";
|
|
98
|
-
|
|
99
|
-
beforeEach(async () => {
|
|
100
|
-
memoryEventStore = await createEventStore({ inMemory: true });
|
|
101
|
-
sudocodeEventStore = await createEventStore({ inMemory: true });
|
|
102
|
-
mockClient = createMinimalMockClient();
|
|
103
|
-
|
|
104
|
-
memoryBackend = createInMemoryTaskBackend(memoryEventStore);
|
|
105
|
-
sudocodeBackend = createSudocodeTaskBackend(
|
|
106
|
-
sudocodeEventStore,
|
|
107
|
-
mockClient,
|
|
108
|
-
{ syncStatus: false }
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
afterEach(async () => {
|
|
113
|
-
sudocodeBackend.close();
|
|
114
|
-
await memoryEventStore.close();
|
|
115
|
-
await sudocodeEventStore.close();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Run the same operation on both backends and compare results
|
|
120
|
-
*/
|
|
121
|
-
async function runOnBoth<T>(
|
|
122
|
-
operation: (backend: TaskBackend) => Promise<T>
|
|
123
|
-
): Promise<{ memory: T; sudocode: T }> {
|
|
124
|
-
const [memory, sudocode] = await Promise.all([
|
|
125
|
-
operation(memoryBackend),
|
|
126
|
-
operation(sudocodeBackend),
|
|
127
|
-
]);
|
|
128
|
-
return { memory, sudocode };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Compare task objects, ignoring timestamps and IDs
|
|
133
|
-
*/
|
|
134
|
-
function compareTasks(a: ExtendedTask | null, b: ExtendedTask | null): void {
|
|
135
|
-
if (!a && !b) return;
|
|
136
|
-
expect(a).not.toBeNull();
|
|
137
|
-
expect(b).not.toBeNull();
|
|
138
|
-
if (!a || !b) return;
|
|
139
|
-
|
|
140
|
-
expect(a.description).toBe(b.description);
|
|
141
|
-
expect(a.status).toBe(b.status);
|
|
142
|
-
expect(a.isBlocked).toBe(b.isBlocked);
|
|
143
|
-
expect(a.assigned_agent).toBe(b.assigned_agent);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
describe("create operations", () => {
|
|
147
|
-
it("should produce tasks with same fields", async () => {
|
|
148
|
-
const memoryTask = await memoryBackend.create({
|
|
149
|
-
description: "Test task",
|
|
150
|
-
created_by: testAgentId,
|
|
151
|
-
});
|
|
152
|
-
const sudocodeTask = await sudocodeBackend.create({
|
|
153
|
-
description: "Test task",
|
|
154
|
-
created_by: testAgentId,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
compareTasks(memoryTask, sudocodeTask);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it("should handle subtasks the same way", async () => {
|
|
161
|
-
const memParent = await memoryBackend.create({
|
|
162
|
-
description: "Parent",
|
|
163
|
-
created_by: testAgentId,
|
|
164
|
-
});
|
|
165
|
-
const sudParent = await sudocodeBackend.create({
|
|
166
|
-
description: "Parent",
|
|
167
|
-
created_by: testAgentId,
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
const memChild = await memoryBackend.createSubtask(memParent.id, {
|
|
171
|
-
description: "Child",
|
|
172
|
-
created_by: testAgentId,
|
|
173
|
-
});
|
|
174
|
-
const sudChild = await sudocodeBackend.createSubtask(sudParent.id, {
|
|
175
|
-
description: "Child",
|
|
176
|
-
created_by: testAgentId,
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
expect(memChild.parent_task).toBe(memParent.id);
|
|
180
|
-
expect(sudChild.parent_task).toBe(sudParent.id);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
describe("status transitions", () => {
|
|
185
|
-
it("should follow same transition rules", async () => {
|
|
186
|
-
// Create tasks
|
|
187
|
-
const memTask = await memoryBackend.create({
|
|
188
|
-
description: "Test",
|
|
189
|
-
created_by: testAgentId,
|
|
190
|
-
});
|
|
191
|
-
const sudTask = await sudocodeBackend.create({
|
|
192
|
-
description: "Test",
|
|
193
|
-
created_by: testAgentId,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// Assign
|
|
197
|
-
await memoryBackend.assign(memTask.id, "agent_a");
|
|
198
|
-
await sudocodeBackend.assign(sudTask.id, "agent_a");
|
|
199
|
-
|
|
200
|
-
const memAfterAssign = await memoryBackend.get(memTask.id);
|
|
201
|
-
const sudAfterAssign = await sudocodeBackend.get(sudTask.id);
|
|
202
|
-
compareTasks(memAfterAssign, sudAfterAssign);
|
|
203
|
-
|
|
204
|
-
// Start
|
|
205
|
-
await memoryBackend.start(memTask.id);
|
|
206
|
-
await sudocodeBackend.start(sudTask.id);
|
|
207
|
-
|
|
208
|
-
const memAfterStart = await memoryBackend.get(memTask.id);
|
|
209
|
-
const sudAfterStart = await sudocodeBackend.get(sudTask.id);
|
|
210
|
-
compareTasks(memAfterStart, sudAfterStart);
|
|
211
|
-
|
|
212
|
-
// Complete
|
|
213
|
-
await memoryBackend.complete(memTask.id);
|
|
214
|
-
await sudocodeBackend.complete(sudTask.id);
|
|
215
|
-
|
|
216
|
-
const memAfterComplete = await memoryBackend.get(memTask.id);
|
|
217
|
-
const sudAfterComplete = await sudocodeBackend.get(sudTask.id);
|
|
218
|
-
compareTasks(memAfterComplete, sudAfterComplete);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it("should reject same invalid transitions", async () => {
|
|
222
|
-
// Create and complete a task
|
|
223
|
-
const memTask = await memoryBackend.create({
|
|
224
|
-
description: "Test",
|
|
225
|
-
created_by: testAgentId,
|
|
226
|
-
});
|
|
227
|
-
const sudTask = await sudocodeBackend.create({
|
|
228
|
-
description: "Test",
|
|
229
|
-
created_by: testAgentId,
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
await memoryBackend.start(memTask.id);
|
|
233
|
-
await sudocodeBackend.start(sudTask.id);
|
|
234
|
-
await memoryBackend.complete(memTask.id);
|
|
235
|
-
await sudocodeBackend.complete(sudTask.id);
|
|
236
|
-
|
|
237
|
-
// Try to start completed task - both should reject
|
|
238
|
-
await expect(memoryBackend.start(memTask.id)).rejects.toThrow(
|
|
239
|
-
"Invalid status transition"
|
|
240
|
-
);
|
|
241
|
-
await expect(sudocodeBackend.start(sudTask.id)).rejects.toThrow(
|
|
242
|
-
"Invalid status transition"
|
|
243
|
-
);
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
describe("delete behavior", () => {
|
|
248
|
-
it("both backends throw 'not supported' on delete", async () => {
|
|
249
|
-
const memTask = await memoryBackend.create({
|
|
250
|
-
description: "Test",
|
|
251
|
-
created_by: testAgentId,
|
|
252
|
-
});
|
|
253
|
-
const sudTask = await sudocodeBackend.create({
|
|
254
|
-
description: "Test",
|
|
255
|
-
created_by: testAgentId,
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
// Both backends should throw "not supported"
|
|
259
|
-
await expect(memoryBackend.delete(memTask.id)).rejects.toThrow(
|
|
260
|
-
"not supported"
|
|
261
|
-
);
|
|
262
|
-
await expect(sudocodeBackend.delete(sudTask.id)).rejects.toThrow(
|
|
263
|
-
"not supported"
|
|
264
|
-
);
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it("delete throws for all task states", async () => {
|
|
268
|
-
// Test that delete throws regardless of task state
|
|
269
|
-
const pendingTask = await sudocodeBackend.create({
|
|
270
|
-
description: "Pending",
|
|
271
|
-
created_by: testAgentId,
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
const completedTask = await sudocodeBackend.create({
|
|
275
|
-
description: "Completed",
|
|
276
|
-
created_by: testAgentId,
|
|
277
|
-
});
|
|
278
|
-
await sudocodeBackend.start(completedTask.id);
|
|
279
|
-
await sudocodeBackend.complete(completedTask.id);
|
|
280
|
-
|
|
281
|
-
// Both should throw
|
|
282
|
-
await expect(sudocodeBackend.delete(pendingTask.id)).rejects.toThrow(
|
|
283
|
-
"not supported"
|
|
284
|
-
);
|
|
285
|
-
await expect(sudocodeBackend.delete(completedTask.id)).rejects.toThrow(
|
|
286
|
-
"not supported"
|
|
287
|
-
);
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
describe("blocker operations", () => {
|
|
292
|
-
it("should handle blockers identically", async () => {
|
|
293
|
-
const memBlocker = await memoryBackend.create({
|
|
294
|
-
description: "Blocker",
|
|
295
|
-
created_by: testAgentId,
|
|
296
|
-
});
|
|
297
|
-
const memBlocked = await memoryBackend.create({
|
|
298
|
-
description: "Blocked",
|
|
299
|
-
created_by: testAgentId,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const sudBlocker = await sudocodeBackend.create({
|
|
303
|
-
description: "Blocker",
|
|
304
|
-
created_by: testAgentId,
|
|
305
|
-
});
|
|
306
|
-
const sudBlocked = await sudocodeBackend.create({
|
|
307
|
-
description: "Blocked",
|
|
308
|
-
created_by: testAgentId,
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
await memoryBackend.addBlocker(memBlocked.id, memBlocker.id);
|
|
312
|
-
await sudocodeBackend.addBlocker(sudBlocked.id, sudBlocker.id);
|
|
313
|
-
|
|
314
|
-
const memBlockedTask = await memoryBackend.get(memBlocked.id);
|
|
315
|
-
const sudBlockedTask = await sudocodeBackend.get(sudBlocked.id);
|
|
316
|
-
|
|
317
|
-
expect(memBlockedTask?.isBlocked).toBe(true);
|
|
318
|
-
expect(sudBlockedTask?.isBlocked).toBe(true);
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("should unblock when blocker completes", async () => {
|
|
322
|
-
const memBlocker = await memoryBackend.create({
|
|
323
|
-
description: "Blocker",
|
|
324
|
-
created_by: testAgentId,
|
|
325
|
-
});
|
|
326
|
-
const memBlocked = await memoryBackend.create({
|
|
327
|
-
description: "Blocked",
|
|
328
|
-
created_by: testAgentId,
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
const sudBlocker = await sudocodeBackend.create({
|
|
332
|
-
description: "Blocker",
|
|
333
|
-
created_by: testAgentId,
|
|
334
|
-
});
|
|
335
|
-
const sudBlocked = await sudocodeBackend.create({
|
|
336
|
-
description: "Blocked",
|
|
337
|
-
created_by: testAgentId,
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
await memoryBackend.addBlocker(memBlocked.id, memBlocker.id);
|
|
341
|
-
await sudocodeBackend.addBlocker(sudBlocked.id, sudBlocker.id);
|
|
342
|
-
|
|
343
|
-
// Complete blockers
|
|
344
|
-
await memoryBackend.start(memBlocker.id);
|
|
345
|
-
await memoryBackend.complete(memBlocker.id);
|
|
346
|
-
await sudocodeBackend.start(sudBlocker.id);
|
|
347
|
-
await sudocodeBackend.complete(sudBlocker.id);
|
|
348
|
-
|
|
349
|
-
const memBlockedTask = await memoryBackend.get(memBlocked.id);
|
|
350
|
-
const sudBlockedTask = await sudocodeBackend.get(sudBlocked.id);
|
|
351
|
-
|
|
352
|
-
expect(memBlockedTask?.isBlocked).toBe(false);
|
|
353
|
-
expect(sudBlockedTask?.isBlocked).toBe(false);
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
describe("listReady operations", () => {
|
|
358
|
-
it("should return same tasks for identical blocker configurations", async () => {
|
|
359
|
-
// Create tasks in both backends
|
|
360
|
-
const memReady = await memoryBackend.create({
|
|
361
|
-
description: "Ready",
|
|
362
|
-
created_by: testAgentId,
|
|
363
|
-
});
|
|
364
|
-
const memBlocker = await memoryBackend.create({
|
|
365
|
-
description: "Blocker",
|
|
366
|
-
created_by: testAgentId,
|
|
367
|
-
});
|
|
368
|
-
const memBlocked = await memoryBackend.create({
|
|
369
|
-
description: "Blocked",
|
|
370
|
-
created_by: testAgentId,
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
const sudReady = await sudocodeBackend.create({
|
|
374
|
-
description: "Ready",
|
|
375
|
-
created_by: testAgentId,
|
|
376
|
-
});
|
|
377
|
-
const sudBlocker = await sudocodeBackend.create({
|
|
378
|
-
description: "Blocker",
|
|
379
|
-
created_by: testAgentId,
|
|
380
|
-
});
|
|
381
|
-
const sudBlocked = await sudocodeBackend.create({
|
|
382
|
-
description: "Blocked",
|
|
383
|
-
created_by: testAgentId,
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
await memoryBackend.addBlocker(memBlocked.id, memBlocker.id);
|
|
387
|
-
await sudocodeBackend.addBlocker(sudBlocked.id, sudBlocker.id);
|
|
388
|
-
|
|
389
|
-
const memReadyTasks = await memoryBackend.listReady();
|
|
390
|
-
const sudReadyTasks = await sudocodeBackend.listReady();
|
|
391
|
-
|
|
392
|
-
// Should have same number of ready tasks
|
|
393
|
-
expect(memReadyTasks.length).toBe(sudReadyTasks.length);
|
|
394
|
-
|
|
395
|
-
// Ready and Blocker should be in ready lists
|
|
396
|
-
expect(memReadyTasks.map((t) => t.description)).toContain("Ready");
|
|
397
|
-
expect(memReadyTasks.map((t) => t.description)).toContain("Blocker");
|
|
398
|
-
expect(memReadyTasks.map((t) => t.description)).not.toContain("Blocked");
|
|
399
|
-
|
|
400
|
-
expect(sudReadyTasks.map((t) => t.description)).toContain("Ready");
|
|
401
|
-
expect(sudReadyTasks.map((t) => t.description)).toContain("Blocker");
|
|
402
|
-
expect(sudReadyTasks.map((t) => t.description)).not.toContain("Blocked");
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
describe("subtask status operations", () => {
|
|
407
|
-
it("should aggregate subtask status identically", async () => {
|
|
408
|
-
const memParent = await memoryBackend.create({
|
|
409
|
-
description: "Parent",
|
|
410
|
-
created_by: testAgentId,
|
|
411
|
-
});
|
|
412
|
-
const sudParent = await sudocodeBackend.create({
|
|
413
|
-
description: "Parent",
|
|
414
|
-
created_by: testAgentId,
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
// Create subtasks
|
|
418
|
-
const memChild1 = await memoryBackend.createSubtask(memParent.id, {
|
|
419
|
-
description: "Child 1",
|
|
420
|
-
created_by: testAgentId,
|
|
421
|
-
});
|
|
422
|
-
const memChild2 = await memoryBackend.createSubtask(memParent.id, {
|
|
423
|
-
description: "Child 2",
|
|
424
|
-
created_by: testAgentId,
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
const sudChild1 = await sudocodeBackend.createSubtask(sudParent.id, {
|
|
428
|
-
description: "Child 1",
|
|
429
|
-
created_by: testAgentId,
|
|
430
|
-
});
|
|
431
|
-
const sudChild2 = await sudocodeBackend.createSubtask(sudParent.id, {
|
|
432
|
-
description: "Child 2",
|
|
433
|
-
created_by: testAgentId,
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
// Complete one child
|
|
437
|
-
await memoryBackend.start(memChild1.id);
|
|
438
|
-
await memoryBackend.complete(memChild1.id);
|
|
439
|
-
await sudocodeBackend.start(sudChild1.id);
|
|
440
|
-
await sudocodeBackend.complete(sudChild1.id);
|
|
441
|
-
|
|
442
|
-
const memStatus = await memoryBackend.getSubtaskStatus(memParent.id);
|
|
443
|
-
const sudStatus = await sudocodeBackend.getSubtaskStatus(sudParent.id);
|
|
444
|
-
|
|
445
|
-
expect(memStatus.total).toBe(sudStatus.total);
|
|
446
|
-
expect(memStatus.completed).toBe(sudStatus.completed);
|
|
447
|
-
expect(memStatus.pending).toBe(sudStatus.pending);
|
|
448
|
-
expect(memStatus.allCompleted).toBe(sudStatus.allCompleted);
|
|
449
|
-
});
|
|
450
|
-
});
|
|
451
|
-
});
|