macro-agent 0.1.0 → 0.1.2
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/issues.jsonl +28 -0
- package/.sudocode/specs.jsonl +8 -0
- package/CLAUDE.md +25 -17
- package/README.md +11 -29
- package/dist/acp/macro-agent.d.ts +15 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +131 -35
- 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 +544 -200
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +8 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/server.d.ts +8 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +136 -8
- package/dist/api/server.js.map +1 -1
- package/dist/api/types.d.ts +1 -1
- package/dist/api/types.d.ts.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 +197 -61
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +152 -16
- 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 +279 -173
- 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 +85 -7
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +133 -20
- package/dist/config/project-config.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/handlers/index.d.ts +7 -3
- package/dist/lifecycle/handlers/index.d.ts.map +1 -1
- package/dist/lifecycle/handlers/index.js +25 -8
- package/dist/lifecycle/handlers/index.js.map +1 -1
- package/dist/lifecycle/types.d.ts +2 -0
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts +17 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +384 -23
- 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 +13 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +61 -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/streams.d.ts +95 -0
- package/dist/map/adapter/extensions/streams.d.ts.map +1 -0
- package/dist/map/adapter/extensions/streams.js +515 -0
- package/dist/map/adapter/extensions/streams.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 +10 -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 +3 -0
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +258 -35
- 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 +3 -1
- 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 +16 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +125 -88
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/tools/done.d.ts.map +1 -1
- package/dist/mcp/tools/done.js +18 -0
- package/dist/mcp/tools/done.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/builtin/coordinator.d.ts.map +1 -1
- package/dist/roles/builtin/coordinator.js +2 -1
- package/dist/roles/builtin/coordinator.js.map +1 -1
- package/dist/roles/builtin/integrator.d.ts.map +1 -1
- package/dist/roles/builtin/integrator.js +2 -1
- package/dist/roles/builtin/integrator.js.map +1 -1
- package/dist/roles/builtin/worker.d.ts.map +1 -1
- package/dist/roles/builtin/worker.js +3 -1
- package/dist/roles/builtin/worker.js.map +1 -1
- package/dist/roles/capabilities.d.ts +9 -1
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +27 -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 +8 -7
- 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/roles/types.d.ts +3 -1
- package/dist/roles/types.d.ts.map +1 -1
- package/dist/server/combined-server.d.ts +28 -1
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +111 -8
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts +2 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +80 -24
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/instance.d.ts +1 -1
- package/dist/store/instance.d.ts.map +1 -1
- package/dist/store/instance.js +2 -2
- package/dist/store/instance.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/index.d.ts +3 -1
- package/dist/teams/index.d.ts.map +1 -1
- package/dist/teams/index.js +2 -0
- package/dist/teams/index.js.map +1 -1
- package/dist/teams/seed-defaults.d.ts +20 -0
- package/dist/teams/seed-defaults.d.ts.map +1 -0
- package/dist/teams/seed-defaults.js +71 -0
- package/dist/teams/seed-defaults.js.map +1 -0
- package/dist/teams/team-loader.d.ts +7 -3
- package/dist/teams/team-loader.d.ts.map +1 -1
- package/dist/teams/team-loader.js +156 -164
- package/dist/teams/team-loader.js.map +1 -1
- package/dist/teams/team-manager.d.ts +112 -0
- package/dist/teams/team-manager.d.ts.map +1 -0
- package/dist/teams/team-manager.js +305 -0
- package/dist/teams/team-manager.js.map +1 -0
- package/dist/teams/team-runtime.d.ts +125 -19
- package/dist/teams/team-runtime.d.ts.map +1 -1
- package/dist/teams/team-runtime.js +529 -119
- package/dist/teams/team-runtime.js.map +1 -1
- package/dist/teams/types.d.ts +41 -151
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/teams/types.js +2 -3
- package/dist/teams/types.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 +76 -3
- package/docs/troubleshooting.md +10 -11
- package/package.json +7 -4
- package/references/minimem/.claude/settings.json +7 -0
- package/references/minimem/.sudocode/issues.jsonl +18 -0
- package/references/minimem/.sudocode/specs.jsonl +1 -0
- package/references/minimem/CLAUDE.md +310 -0
- package/references/minimem/README.md +562 -0
- package/references/minimem/claude-plugin/.claude-plugin/plugin.json +10 -0
- package/references/minimem/claude-plugin/.mcp.json +7 -0
- package/references/minimem/claude-plugin/README.md +158 -0
- package/references/minimem/claude-plugin/commands/recall.md +47 -0
- package/references/minimem/claude-plugin/commands/remember.md +41 -0
- package/references/minimem/claude-plugin/hooks/__tests__/hooks.test.ts +272 -0
- package/references/minimem/claude-plugin/hooks/hooks.json +27 -0
- package/references/minimem/claude-plugin/hooks/session-end.sh +86 -0
- package/references/minimem/claude-plugin/hooks/session-start.sh +85 -0
- package/references/minimem/claude-plugin/skills/memory/SKILL.md +108 -0
- package/references/minimem/media/banner.png +0 -0
- package/references/minimem/package-lock.json +5373 -0
- package/references/minimem/package.json +72 -0
- package/references/minimem/scripts/postbuild.js +35 -0
- package/references/minimem/src/__tests__/edge-cases.test.ts +371 -0
- package/references/minimem/src/__tests__/errors.test.ts +265 -0
- package/references/minimem/src/__tests__/helpers.ts +199 -0
- package/references/minimem/src/__tests__/internal.test.ts +407 -0
- package/references/minimem/src/__tests__/knowledge.test.ts +287 -0
- package/references/minimem/src/__tests__/minimem.integration.test.ts +1127 -0
- package/references/minimem/src/__tests__/session.test.ts +190 -0
- package/references/minimem/src/cli/__tests__/commands.test.ts +759 -0
- package/references/minimem/src/cli/commands/__tests__/conflicts.test.ts +141 -0
- package/references/minimem/src/cli/commands/append.ts +76 -0
- package/references/minimem/src/cli/commands/config.ts +262 -0
- package/references/minimem/src/cli/commands/conflicts.ts +413 -0
- package/references/minimem/src/cli/commands/daemon.ts +169 -0
- package/references/minimem/src/cli/commands/index.ts +12 -0
- package/references/minimem/src/cli/commands/init.ts +88 -0
- package/references/minimem/src/cli/commands/mcp.ts +177 -0
- package/references/minimem/src/cli/commands/push-pull.ts +213 -0
- package/references/minimem/src/cli/commands/search.ts +158 -0
- package/references/minimem/src/cli/commands/status.ts +84 -0
- package/references/minimem/src/cli/commands/sync-init.ts +290 -0
- package/references/minimem/src/cli/commands/sync.ts +70 -0
- package/references/minimem/src/cli/commands/upsert.ts +197 -0
- package/references/minimem/src/cli/config.ts +584 -0
- package/references/minimem/src/cli/index.ts +264 -0
- package/references/minimem/src/cli/shared.ts +161 -0
- package/references/minimem/src/cli/sync/__tests__/central.test.ts +152 -0
- package/references/minimem/src/cli/sync/__tests__/conflicts.test.ts +209 -0
- package/references/minimem/src/cli/sync/__tests__/daemon.test.ts +118 -0
- package/references/minimem/src/cli/sync/__tests__/detection.test.ts +207 -0
- package/references/minimem/src/cli/sync/__tests__/integration.test.ts +476 -0
- package/references/minimem/src/cli/sync/__tests__/registry.test.ts +363 -0
- package/references/minimem/src/cli/sync/__tests__/state.test.ts +255 -0
- package/references/minimem/src/cli/sync/__tests__/validation.test.ts +193 -0
- package/references/minimem/src/cli/sync/__tests__/watcher.test.ts +178 -0
- package/references/minimem/src/cli/sync/central.ts +292 -0
- package/references/minimem/src/cli/sync/conflicts.ts +204 -0
- package/references/minimem/src/cli/sync/daemon.ts +407 -0
- package/references/minimem/src/cli/sync/detection.ts +138 -0
- package/references/minimem/src/cli/sync/index.ts +107 -0
- package/references/minimem/src/cli/sync/operations.ts +373 -0
- package/references/minimem/src/cli/sync/registry.ts +279 -0
- package/references/minimem/src/cli/sync/state.ts +355 -0
- package/references/minimem/src/cli/sync/validation.ts +206 -0
- package/references/minimem/src/cli/sync/watcher.ts +234 -0
- package/references/minimem/src/cli/version.ts +34 -0
- package/references/minimem/src/core/index.ts +9 -0
- package/references/minimem/src/core/indexer.ts +628 -0
- package/references/minimem/src/core/searcher.ts +221 -0
- package/references/minimem/src/db/schema.ts +183 -0
- package/references/minimem/src/db/sqlite-vec.ts +24 -0
- package/references/minimem/src/embeddings/__tests__/embeddings.test.ts +431 -0
- package/references/minimem/src/embeddings/batch-gemini.ts +392 -0
- package/references/minimem/src/embeddings/batch-openai.ts +409 -0
- package/references/minimem/src/embeddings/embeddings.ts +434 -0
- package/references/minimem/src/index.ts +109 -0
- package/references/minimem/src/internal.ts +299 -0
- package/references/minimem/src/minimem.ts +1276 -0
- package/references/minimem/src/search/__tests__/hybrid.test.ts +247 -0
- package/references/minimem/src/search/graph.ts +234 -0
- package/references/minimem/src/search/hybrid.ts +151 -0
- package/references/minimem/src/search/search.ts +256 -0
- package/references/minimem/src/server/__tests__/mcp.test.ts +341 -0
- package/references/minimem/src/server/__tests__/tools.test.ts +364 -0
- package/references/minimem/src/server/mcp.ts +326 -0
- package/references/minimem/src/server/tools.ts +720 -0
- package/references/minimem/src/session.ts +460 -0
- package/references/minimem/tsconfig.json +19 -0
- package/references/minimem/tsup.config.ts +26 -0
- package/references/minimem/vitest.config.ts +24 -0
- package/references/openteams/.claude/settings.json +6 -0
- package/references/openteams/README.md +1 -0
- package/references/openteams/SKILL.md +341 -0
- package/references/openteams/design.md +411 -0
- package/references/openteams/examples/bmad-method/prompts/analyst/ROLE.md +16 -0
- package/references/openteams/examples/bmad-method/prompts/analyst/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/architect/ROLE.md +24 -0
- package/references/openteams/examples/bmad-method/prompts/architect/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/developer/ROLE.md +25 -0
- package/references/openteams/examples/bmad-method/prompts/developer/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/master/ROLE.md +21 -0
- package/references/openteams/examples/bmad-method/prompts/master/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/pm/ROLE.md +20 -0
- package/references/openteams/examples/bmad-method/prompts/pm/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/qa/ROLE.md +17 -0
- package/references/openteams/examples/bmad-method/prompts/qa/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/ROLE.md +23 -0
- package/references/openteams/examples/bmad-method/prompts/quick-flow-dev/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/scrum-master/ROLE.md +27 -0
- package/references/openteams/examples/bmad-method/prompts/scrum-master/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/tech-writer/ROLE.md +21 -0
- package/references/openteams/examples/bmad-method/prompts/tech-writer/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/prompts/ux-designer/ROLE.md +16 -0
- package/references/openteams/examples/bmad-method/prompts/ux-designer/SOUL.md +5 -0
- package/references/openteams/examples/bmad-method/roles/analyst.yaml +9 -0
- package/references/openteams/examples/bmad-method/roles/architect.yaml +9 -0
- package/references/openteams/examples/bmad-method/roles/developer.yaml +8 -0
- package/references/openteams/examples/bmad-method/roles/master.yaml +8 -0
- package/references/openteams/examples/bmad-method/roles/pm.yaml +9 -0
- package/references/openteams/examples/bmad-method/roles/qa.yaml +8 -0
- package/references/openteams/examples/bmad-method/roles/quick-flow-dev.yaml +8 -0
- package/references/openteams/examples/bmad-method/roles/scrum-master.yaml +9 -0
- package/references/openteams/examples/bmad-method/roles/tech-writer.yaml +8 -0
- package/references/openteams/examples/bmad-method/roles/ux-designer.yaml +8 -0
- package/references/openteams/examples/bmad-method/team.yaml +161 -0
- package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/ROLE.md +17 -0
- package/references/openteams/examples/get-shit-done/prompts/codebase-mapper/SOUL.md +5 -0
- package/references/openteams/examples/get-shit-done/prompts/debugger/ROLE.md +25 -0
- package/references/openteams/examples/get-shit-done/prompts/debugger/SOUL.md +5 -0
- package/references/openteams/examples/get-shit-done/prompts/executor/ROLE.md +34 -0
- package/references/openteams/examples/get-shit-done/prompts/executor/SOUL.md +5 -0
- package/references/openteams/examples/get-shit-done/prompts/integration-checker/ROLE.md +18 -0
- package/references/openteams/examples/get-shit-done/prompts/integration-checker/SOUL.md +3 -0
- package/references/openteams/examples/get-shit-done/prompts/orchestrator/ROLE.md +42 -0
- package/references/openteams/examples/get-shit-done/prompts/orchestrator/SOUL.md +5 -0
- package/references/openteams/examples/get-shit-done/prompts/phase-researcher/ROLE.md +15 -0
- package/references/openteams/examples/get-shit-done/prompts/phase-researcher/SOUL.md +3 -0
- package/references/openteams/examples/get-shit-done/prompts/plan-checker/ROLE.md +17 -0
- package/references/openteams/examples/get-shit-done/prompts/plan-checker/SOUL.md +3 -0
- package/references/openteams/examples/get-shit-done/prompts/planner/ROLE.md +28 -0
- package/references/openteams/examples/get-shit-done/prompts/planner/SOUL.md +5 -0
- package/references/openteams/examples/get-shit-done/prompts/project-researcher/ROLE.md +16 -0
- package/references/openteams/examples/get-shit-done/prompts/project-researcher/SOUL.md +3 -0
- package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/ROLE.md +13 -0
- package/references/openteams/examples/get-shit-done/prompts/research-synthesizer/SOUL.md +3 -0
- package/references/openteams/examples/get-shit-done/prompts/roadmapper/ROLE.md +14 -0
- package/references/openteams/examples/get-shit-done/prompts/roadmapper/SOUL.md +3 -0
- package/references/openteams/examples/get-shit-done/prompts/verifier/ROLE.md +19 -0
- package/references/openteams/examples/get-shit-done/prompts/verifier/SOUL.md +5 -0
- package/references/openteams/examples/get-shit-done/roles/codebase-mapper.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/debugger.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/executor.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/integration-checker.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/orchestrator.yaml +9 -0
- package/references/openteams/examples/get-shit-done/roles/phase-researcher.yaml +7 -0
- package/references/openteams/examples/get-shit-done/roles/plan-checker.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/planner.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/project-researcher.yaml +8 -0
- package/references/openteams/examples/get-shit-done/roles/research-synthesizer.yaml +7 -0
- package/references/openteams/examples/get-shit-done/roles/roadmapper.yaml +7 -0
- package/references/openteams/examples/get-shit-done/roles/verifier.yaml +8 -0
- package/references/openteams/examples/get-shit-done/team.yaml +154 -0
- package/references/openteams/package-lock.json +2181 -0
- package/references/openteams/package.json +48 -0
- package/references/openteams/schema/role.schema.json +125 -0
- package/references/openteams/schema/team.schema.json +284 -0
- package/references/openteams/src/cli/agent.ts +104 -0
- package/references/openteams/src/cli/cli.test.ts +381 -0
- package/references/openteams/src/cli/generate.ts +220 -0
- package/references/openteams/src/cli/message.ts +241 -0
- package/references/openteams/src/cli/task.ts +154 -0
- package/references/openteams/src/cli/team.ts +104 -0
- package/references/openteams/src/cli/template.ts +207 -0
- package/references/openteams/src/cli.ts +45 -0
- package/references/openteams/src/db/database.test.ts +185 -0
- package/references/openteams/src/db/database.ts +240 -0
- package/references/openteams/src/generators/agent-prompt-generator.test.ts +332 -0
- package/references/openteams/src/generators/agent-prompt-generator.ts +521 -0
- package/references/openteams/src/generators/package-generator.test.ts +129 -0
- package/references/openteams/src/generators/package-generator.ts +102 -0
- package/references/openteams/src/generators/skill-generator.test.ts +246 -0
- package/references/openteams/src/generators/skill-generator.ts +374 -0
- package/references/openteams/src/index.ts +104 -0
- package/references/openteams/src/services/agent-service.test.ts +158 -0
- package/references/openteams/src/services/agent-service.ts +84 -0
- package/references/openteams/src/services/communication-service.test.ts +455 -0
- package/references/openteams/src/services/communication-service.ts +371 -0
- package/references/openteams/src/services/message-service.test.ts +342 -0
- package/references/openteams/src/services/message-service.ts +203 -0
- package/references/openteams/src/services/task-service.test.ts +434 -0
- package/references/openteams/src/services/task-service.ts +239 -0
- package/references/openteams/src/services/team-service.test.ts +181 -0
- package/references/openteams/src/services/team-service.ts +139 -0
- package/references/openteams/src/services/template-service.test.ts +306 -0
- package/references/openteams/src/services/template-service.ts +182 -0
- package/references/openteams/src/spawner/acp-factory.ts +96 -0
- package/references/openteams/src/spawner/interface.ts +31 -0
- package/references/openteams/src/spawner/mock.test.ts +93 -0
- package/references/openteams/src/spawner/mock.ts +59 -0
- package/references/openteams/src/template/loader.test.ts +1319 -0
- package/references/openteams/src/template/loader.ts +698 -0
- package/references/openteams/src/template/types.ts +200 -0
- package/references/openteams/src/types.ts +205 -0
- package/references/openteams/tsconfig.json +18 -0
- package/references/openteams/vitest.config.ts +9 -0
- package/references/skill-tree/.claude/settings.json +6 -0
- package/references/skill-tree/.sudocode/issues.jsonl +11 -0
- package/references/skill-tree/.sudocode/specs.jsonl +1 -0
- package/references/skill-tree/CLAUDE.md +150 -0
- package/references/skill-tree/README.md +324 -0
- package/references/skill-tree/docs/GAPS_v1.md +221 -0
- package/references/skill-tree/docs/INTEGRATION_PLAN.md +467 -0
- package/references/skill-tree/docs/TODOS.md +91 -0
- package/references/skill-tree/docs/anthropic_skill_guide.md +1364 -0
- package/references/skill-tree/docs/design/federated-skill-trees.md +524 -0
- package/references/skill-tree/docs/design/multi-agent-sync.md +759 -0
- package/references/skill-tree/docs/scraper/BRAINSTORM.md +583 -0
- package/references/skill-tree/docs/scraper/POC_PLAN.md +420 -0
- package/references/skill-tree/docs/scraper/README.md +170 -0
- package/references/skill-tree/examples/basic-usage.ts +190 -0
- package/references/skill-tree/package-lock.json +1509 -0
- package/references/skill-tree/package.json +66 -0
- package/references/skill-tree/scraper/README.md +123 -0
- package/references/skill-tree/scraper/docs/DESIGN.md +683 -0
- package/references/skill-tree/scraper/docs/PLAN.md +336 -0
- package/references/skill-tree/scraper/drizzle.config.ts +10 -0
- package/references/skill-tree/scraper/package-lock.json +6329 -0
- package/references/skill-tree/scraper/package.json +68 -0
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-description.md +7 -0
- package/references/skill-tree/scraper/test/fixtures/invalid-skill/missing-name.md +7 -0
- package/references/skill-tree/scraper/test/fixtures/minimal-skill/SKILL.md +27 -0
- package/references/skill-tree/scraper/test/fixtures/skill-json/SKILL.json +21 -0
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/SKILL.md +54 -0
- package/references/skill-tree/scraper/test/fixtures/skill-with-meta/_meta.json +24 -0
- package/references/skill-tree/scraper/test/fixtures/valid-skill/SKILL.md +93 -0
- package/references/skill-tree/scraper/test/fixtures/valid-skill/_meta.json +22 -0
- package/references/skill-tree/scraper/tsup.config.ts +14 -0
- package/references/skill-tree/scraper/vitest.config.ts +17 -0
- package/references/skill-tree/scripts/convert-to-vitest.ts +166 -0
- package/references/skill-tree/skills/skill-writer/SKILL.md +339 -0
- package/references/skill-tree/skills/skill-writer/references/examples.md +326 -0
- package/references/skill-tree/skills/skill-writer/references/patterns.md +210 -0
- package/references/skill-tree/skills/skill-writer/references/quality-checklist.md +123 -0
- package/references/skill-tree/test/run-all.ts +106 -0
- package/references/skill-tree/test/utils.ts +128 -0
- package/references/skill-tree/vitest.config.ts +16 -0
- 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__/integration.test.ts +56 -31
- package/src/acp/__tests__/macro-agent.test.ts +16 -7
- package/src/acp/macro-agent.ts +170 -36
- package/src/acp/types.ts +46 -1
- package/src/agent/__tests__/agent-manager.test.ts +228 -2
- package/src/agent/agent-manager.ts +809 -285
- package/src/agent/types.ts +12 -1
- package/src/api/__tests__/server.test.ts +203 -4
- package/src/api/server.ts +169 -10
- package/src/api/types.ts +3 -1
- 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 +197 -72
- package/src/cli/index.ts +125 -15
- package/src/cli/mcp.ts +315 -197
- package/src/cli/parse-args.ts +54 -0
- package/src/cli/stable-instance-id.ts +14 -0
- package/src/config/project-config.ts +214 -27
- package/src/index.ts +3 -0
- package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
- package/src/lifecycle/__tests__/handlers.test.ts +53 -0
- package/src/lifecycle/handlers/index.ts +25 -8
- package/src/lifecycle/types.ts +3 -0
- package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
- package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
- package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
- 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__/stream-extensions.test.ts +494 -0
- package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
- package/src/map/adapter/acp-over-map.ts +678 -66
- 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 +96 -0
- package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
- package/src/map/adapter/extensions/streams.ts +839 -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 +33 -0
- package/src/map/adapter/interface.ts +2 -0
- package/src/map/adapter/map-adapter.ts +312 -47
- package/src/map/adapter/subscription-manager.ts +5 -1
- package/src/map/adapter/types.ts +10 -1
- 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 +205 -103
- package/src/mcp/tools/done.ts +19 -0
- 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/builtin/coordinator.ts +2 -0
- package/src/roles/builtin/integrator.ts +2 -0
- package/src/roles/builtin/worker.ts +3 -0
- package/src/roles/capabilities.ts +28 -7
- package/src/roles/config-loader.ts +8 -7
- package/src/roles/registry.ts +2 -2
- package/src/roles/types.ts +7 -0
- package/src/server/__tests__/combined-server.test.ts +94 -21
- package/src/server/combined-server.ts +203 -33
- package/src/steering/__tests__/steering-integration.test.ts +1 -1
- package/src/store/__tests__/event-store-oob.test.ts +109 -0
- package/src/store/__tests__/event-store.test.ts +196 -1
- package/src/store/__tests__/instance.test.ts +3 -3
- package/src/store/event-store.ts +92 -23
- package/src/store/instance.ts +2 -2
- package/src/store/types/agents.ts +20 -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__/memory-pull-mode.test.ts +153 -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 +256 -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/CLAUDE.md +180 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
- package/src/teams/__tests__/e2e/workspace-isolation.e2e.test.ts +1263 -0
- package/src/teams/__tests__/team-manager.test.ts +814 -0
- package/src/teams/__tests__/team-system.test.ts +1291 -8
- package/src/teams/index.ts +21 -3
- package/src/teams/seed-defaults.ts +79 -0
- package/src/teams/team-loader.ts +202 -236
- package/src/teams/team-manager.ts +387 -0
- package/src/teams/team-runtime.ts +592 -121
- package/src/teams/types.ts +99 -200
- 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,1194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SudocodeTaskBackend Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for the SudocodeTaskBackend implementation.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
8
|
-
import {
|
|
9
|
-
SudocodeTaskBackend,
|
|
10
|
-
SudocodeTaskBackendError,
|
|
11
|
-
createSudocodeTaskBackend,
|
|
12
|
-
} from "../backend.js";
|
|
13
|
-
import type { EventStore } from "../../../../store/event-store.js";
|
|
14
|
-
import type { Task, TaskStatus } from "../../../../store/types/index.js";
|
|
15
|
-
import type { SudocodeClient, IssueChangeCallback } from "../client.js";
|
|
16
|
-
import type { Issue } from "../client.js";
|
|
17
|
-
|
|
18
|
-
// Mock EventStore
|
|
19
|
-
function createMockEventStore(): EventStore {
|
|
20
|
-
const tasks = new Map<string, Task>();
|
|
21
|
-
const taskChangeCallbacks: Array<(taskId: string, task: Task | null) => void> = [];
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
instanceId: "test-instance",
|
|
25
|
-
namespace: "test",
|
|
26
|
-
instancePath: ":memory:",
|
|
27
|
-
backendType: "memory",
|
|
28
|
-
peerVisibility: { level: "none" },
|
|
29
|
-
|
|
30
|
-
emit: vi.fn((event) => {
|
|
31
|
-
if (event.type === "task") {
|
|
32
|
-
const payload = event.payload as {
|
|
33
|
-
task_id: string;
|
|
34
|
-
action: string;
|
|
35
|
-
details: Record<string, unknown>;
|
|
36
|
-
};
|
|
37
|
-
const taskId = payload.task_id;
|
|
38
|
-
|
|
39
|
-
if (payload.action === "created") {
|
|
40
|
-
const task: Task = {
|
|
41
|
-
id: taskId,
|
|
42
|
-
description: payload.details.description as string,
|
|
43
|
-
status: "pending",
|
|
44
|
-
created_at: new Date().toISOString(),
|
|
45
|
-
created_by: event.source.agent_id,
|
|
46
|
-
parent_task: payload.details.parent_task as string | undefined,
|
|
47
|
-
blockers: [],
|
|
48
|
-
subtasks: [],
|
|
49
|
-
agent_history: [],
|
|
50
|
-
outputs: payload.details.external_id
|
|
51
|
-
? { external_id: payload.details.external_id }
|
|
52
|
-
: undefined,
|
|
53
|
-
};
|
|
54
|
-
tasks.set(taskId, task);
|
|
55
|
-
} else if (payload.action === "assigned") {
|
|
56
|
-
const task = tasks.get(taskId);
|
|
57
|
-
if (task) {
|
|
58
|
-
task.status = "assigned";
|
|
59
|
-
task.assigned_agent = payload.details.agent_id as string;
|
|
60
|
-
tasks.set(taskId, task);
|
|
61
|
-
}
|
|
62
|
-
} else if (payload.action === "unassigned") {
|
|
63
|
-
const task = tasks.get(taskId);
|
|
64
|
-
if (task) {
|
|
65
|
-
task.status = "pending";
|
|
66
|
-
task.assigned_agent = undefined;
|
|
67
|
-
tasks.set(taskId, task);
|
|
68
|
-
}
|
|
69
|
-
} else if (payload.action === "status_change") {
|
|
70
|
-
const task = tasks.get(taskId);
|
|
71
|
-
if (task) {
|
|
72
|
-
if (payload.details.status) {
|
|
73
|
-
task.status = payload.details.status as TaskStatus;
|
|
74
|
-
}
|
|
75
|
-
if (payload.details.description) {
|
|
76
|
-
task.description = payload.details.description as string;
|
|
77
|
-
}
|
|
78
|
-
if (payload.details.outputs) {
|
|
79
|
-
task.outputs = {
|
|
80
|
-
...(task.outputs ?? {}),
|
|
81
|
-
...(payload.details.outputs as Record<string, unknown>),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
if (payload.details.artifacts) {
|
|
85
|
-
task.artifacts = payload.details.artifacts as any[];
|
|
86
|
-
}
|
|
87
|
-
if (payload.details.subtask_added) {
|
|
88
|
-
task.subtasks = [
|
|
89
|
-
...(task.subtasks ?? []),
|
|
90
|
-
payload.details.subtask_added as string,
|
|
91
|
-
];
|
|
92
|
-
}
|
|
93
|
-
tasks.set(taskId, task);
|
|
94
|
-
}
|
|
95
|
-
} else if (payload.action === "completed") {
|
|
96
|
-
const task = tasks.get(taskId);
|
|
97
|
-
if (task) {
|
|
98
|
-
task.status = "completed";
|
|
99
|
-
task.completed_at = new Date().toISOString();
|
|
100
|
-
tasks.set(taskId, task);
|
|
101
|
-
}
|
|
102
|
-
} else if (payload.action === "failed") {
|
|
103
|
-
const task = tasks.get(taskId);
|
|
104
|
-
if (task) {
|
|
105
|
-
task.status = "failed";
|
|
106
|
-
tasks.set(taskId, task);
|
|
107
|
-
}
|
|
108
|
-
} else if (payload.action === "blocker_added") {
|
|
109
|
-
const task = tasks.get(taskId);
|
|
110
|
-
if (task) {
|
|
111
|
-
task.blockers = [
|
|
112
|
-
...(task.blockers ?? []),
|
|
113
|
-
payload.details.blocker_id as string,
|
|
114
|
-
];
|
|
115
|
-
tasks.set(taskId, task);
|
|
116
|
-
}
|
|
117
|
-
} else if (payload.action === "blocker_removed") {
|
|
118
|
-
const task = tasks.get(taskId);
|
|
119
|
-
if (task) {
|
|
120
|
-
task.blockers = (task.blockers ?? []).filter(
|
|
121
|
-
(b) => b !== payload.details.blocker_id
|
|
122
|
-
);
|
|
123
|
-
tasks.set(taskId, task);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Notify listeners
|
|
128
|
-
const updatedTask = tasks.get(taskId) ?? null;
|
|
129
|
-
for (const cb of taskChangeCallbacks) {
|
|
130
|
-
cb(taskId, updatedTask);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
id: `event_${Date.now()}`,
|
|
136
|
-
type: event.type,
|
|
137
|
-
source: event.source,
|
|
138
|
-
payload: event.payload,
|
|
139
|
-
timestamp: new Date().toISOString(),
|
|
140
|
-
version: 1,
|
|
141
|
-
};
|
|
142
|
-
}),
|
|
143
|
-
|
|
144
|
-
query: vi.fn(() => []),
|
|
145
|
-
|
|
146
|
-
getAgent: vi.fn(() => null),
|
|
147
|
-
listAgents: vi.fn(() => []),
|
|
148
|
-
|
|
149
|
-
getTask: vi.fn((taskId: string) => tasks.get(taskId) ?? null),
|
|
150
|
-
listTasks: vi.fn(() => Array.from(tasks.values())),
|
|
151
|
-
|
|
152
|
-
getMessages: vi.fn(() => []),
|
|
153
|
-
getFullMessage: vi.fn(() => null),
|
|
154
|
-
|
|
155
|
-
addSubscription: vi.fn(),
|
|
156
|
-
removeSubscription: vi.fn(),
|
|
157
|
-
getSubscriptions: vi.fn(() => []),
|
|
158
|
-
getSubscribers: vi.fn(() => []),
|
|
159
|
-
|
|
160
|
-
onAgentChange: vi.fn(() => () => {}),
|
|
161
|
-
onTaskChange: vi.fn((callback: (taskId: string, task: Task | null) => void) => {
|
|
162
|
-
taskChangeCallbacks.push(callback);
|
|
163
|
-
return () => {
|
|
164
|
-
const idx = taskChangeCallbacks.indexOf(callback);
|
|
165
|
-
if (idx >= 0) taskChangeCallbacks.splice(idx, 1);
|
|
166
|
-
};
|
|
167
|
-
}),
|
|
168
|
-
onMessageChange: vi.fn(() => () => {}),
|
|
169
|
-
|
|
170
|
-
persist: vi.fn(async () => {}),
|
|
171
|
-
reload: vi.fn(async () => {}),
|
|
172
|
-
close: vi.fn(async () => {}),
|
|
173
|
-
|
|
174
|
-
archive: vi.fn(async () => ({
|
|
175
|
-
archivedCount: 0,
|
|
176
|
-
archivePath: "",
|
|
177
|
-
oldestRetained: "",
|
|
178
|
-
})),
|
|
179
|
-
loadArchive: vi.fn(async () => []),
|
|
180
|
-
getArchiveInfo: vi.fn(async () => ({ archives: [], totalArchivedEvents: 0 })),
|
|
181
|
-
|
|
182
|
-
exportEvents: vi.fn(() => []),
|
|
183
|
-
importEvents: vi.fn(),
|
|
184
|
-
|
|
185
|
-
getBackend: vi.fn(() => ({} as any)),
|
|
186
|
-
} as unknown as EventStore;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Mock SudocodeClient
|
|
190
|
-
function createMockSudocodeClient(): SudocodeClient {
|
|
191
|
-
const issues = new Map<string, Issue>();
|
|
192
|
-
const issueBlockers = new Map<string, Issue[]>();
|
|
193
|
-
const issueBlocking = new Map<string, Issue[]>();
|
|
194
|
-
const issueChangeCallbacks: IssueChangeCallback[] = [];
|
|
195
|
-
|
|
196
|
-
// Add some test issues
|
|
197
|
-
issues.set("i-test1", {
|
|
198
|
-
id: "i-test1",
|
|
199
|
-
uuid: "uuid-1",
|
|
200
|
-
title: "Test Issue 1",
|
|
201
|
-
content: "Test content",
|
|
202
|
-
status: "open",
|
|
203
|
-
priority: 1,
|
|
204
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
205
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
206
|
-
});
|
|
207
|
-
issues.set("i-test2", {
|
|
208
|
-
id: "i-test2",
|
|
209
|
-
uuid: "uuid-2",
|
|
210
|
-
title: "Test Issue 2",
|
|
211
|
-
content: "Test content",
|
|
212
|
-
status: "open",
|
|
213
|
-
priority: 2,
|
|
214
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
215
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
getIssue: vi.fn(async (id: string) => issues.get(id) ?? null),
|
|
220
|
-
listIssues: vi.fn(async () => Array.from(issues.values())),
|
|
221
|
-
getReadyIssues: vi.fn(async () => Array.from(issues.values())),
|
|
222
|
-
updateIssue: vi.fn(async (id: string, updates: any) => {
|
|
223
|
-
const issue = issues.get(id);
|
|
224
|
-
if (!issue) throw new Error("Issue not found");
|
|
225
|
-
const updated = { ...issue, ...updates };
|
|
226
|
-
issues.set(id, updated);
|
|
227
|
-
return updated;
|
|
228
|
-
}),
|
|
229
|
-
|
|
230
|
-
createLink: vi.fn(async () => {}),
|
|
231
|
-
removeLink: vi.fn(async () => {}),
|
|
232
|
-
getBlockers: vi.fn(async (id: string) => issueBlockers.get(id) ?? []),
|
|
233
|
-
getBlocking: vi.fn(async (id: string) => issueBlocking.get(id) ?? []),
|
|
234
|
-
|
|
235
|
-
getSpec: vi.fn(async () => null),
|
|
236
|
-
listSpecs: vi.fn(async () => []),
|
|
237
|
-
|
|
238
|
-
addFeedback: vi.fn(async () => {}),
|
|
239
|
-
|
|
240
|
-
onIssueChange: vi.fn((callbackOrId: IssueChangeCallback | string, maybeCallback?: IssueChangeCallback) => {
|
|
241
|
-
const callback = typeof callbackOrId === "function" ? callbackOrId : maybeCallback!;
|
|
242
|
-
issueChangeCallbacks.push(callback);
|
|
243
|
-
return () => {
|
|
244
|
-
const idx = issueChangeCallbacks.indexOf(callback);
|
|
245
|
-
if (idx >= 0) issueChangeCallbacks.splice(idx, 1);
|
|
246
|
-
};
|
|
247
|
-
}),
|
|
248
|
-
|
|
249
|
-
isReady: vi.fn(() => true),
|
|
250
|
-
close: vi.fn(),
|
|
251
|
-
|
|
252
|
-
// Test helpers
|
|
253
|
-
_setIssue: (id: string, issue: Issue) => issues.set(id, issue),
|
|
254
|
-
_setBlockers: (id: string, blockers: Issue[]) => issueBlockers.set(id, blockers),
|
|
255
|
-
_setBlocking: (id: string, blocking: Issue[]) => issueBlocking.set(id, blocking),
|
|
256
|
-
_notifyChange: (event: any) => {
|
|
257
|
-
for (const cb of issueChangeCallbacks) {
|
|
258
|
-
cb(event);
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
} as unknown as SudocodeClient & {
|
|
262
|
-
_setIssue: (id: string, issue: Issue) => void;
|
|
263
|
-
_setBlockers: (id: string, blockers: Issue[]) => void;
|
|
264
|
-
_setBlocking: (id: string, blocking: Issue[]) => void;
|
|
265
|
-
_notifyChange: (event: any) => void;
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
describe("SudocodeTaskBackend", () => {
|
|
270
|
-
let eventStore: EventStore;
|
|
271
|
-
let client: SudocodeClient & {
|
|
272
|
-
_setIssue: (id: string, issue: Issue) => void;
|
|
273
|
-
_setBlockers: (id: string, blockers: Issue[]) => void;
|
|
274
|
-
_setBlocking: (id: string, blocking: Issue[]) => void;
|
|
275
|
-
_notifyChange: (event: any) => void;
|
|
276
|
-
};
|
|
277
|
-
let backend: SudocodeTaskBackend;
|
|
278
|
-
|
|
279
|
-
beforeEach(() => {
|
|
280
|
-
eventStore = createMockEventStore();
|
|
281
|
-
client = createMockSudocodeClient() as any;
|
|
282
|
-
backend = new SudocodeTaskBackend(eventStore, client, {
|
|
283
|
-
syncStatus: false, // Disable auto-sync for most tests
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
afterEach(() => {
|
|
288
|
-
backend.close();
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
describe("create", () => {
|
|
292
|
-
it("should create a task", async () => {
|
|
293
|
-
const task = await backend.create({
|
|
294
|
-
description: "Test task",
|
|
295
|
-
created_by: "agent-1",
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
expect(task.id).toMatch(/^task_/);
|
|
299
|
-
expect(task.description).toBe("Test task");
|
|
300
|
-
expect(task.status).toBe("pending");
|
|
301
|
-
expect(task.created_by).toBe("agent-1");
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
it("should create a task bound to an issue", async () => {
|
|
305
|
-
const task = await backend.create({
|
|
306
|
-
description: "Test task",
|
|
307
|
-
created_by: "agent-1",
|
|
308
|
-
external_id: "i-test1",
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
expect(task.external_id).toBe("i-test1");
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it("should throw when issue not found", async () => {
|
|
315
|
-
await expect(
|
|
316
|
-
backend.create({
|
|
317
|
-
description: "Test task",
|
|
318
|
-
created_by: "agent-1",
|
|
319
|
-
external_id: "i-nonexistent",
|
|
320
|
-
})
|
|
321
|
-
).rejects.toThrow("Issue not found");
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
it("should create a subtask", async () => {
|
|
325
|
-
const parent = await backend.create({
|
|
326
|
-
description: "Parent task",
|
|
327
|
-
created_by: "agent-1",
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const child = await backend.create({
|
|
331
|
-
description: "Child task",
|
|
332
|
-
created_by: "agent-1",
|
|
333
|
-
parent_task: parent.id,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
expect(child.parent_task).toBe(parent.id);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it("should throw when parent not found", async () => {
|
|
340
|
-
await expect(
|
|
341
|
-
backend.create({
|
|
342
|
-
description: "Child task",
|
|
343
|
-
created_by: "agent-1",
|
|
344
|
-
parent_task: "nonexistent",
|
|
345
|
-
})
|
|
346
|
-
).rejects.toThrow("Parent task not found");
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
describe("get", () => {
|
|
351
|
-
it("should get a task by ID", async () => {
|
|
352
|
-
const created = await backend.create({
|
|
353
|
-
description: "Test task",
|
|
354
|
-
created_by: "agent-1",
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
const fetched = await backend.get(created.id);
|
|
358
|
-
|
|
359
|
-
expect(fetched).not.toBeNull();
|
|
360
|
-
expect(fetched!.id).toBe(created.id);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it("should return null for non-existent task", async () => {
|
|
364
|
-
const fetched = await backend.get("nonexistent");
|
|
365
|
-
expect(fetched).toBeNull();
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
describe("update", () => {
|
|
370
|
-
it("should update task description", async () => {
|
|
371
|
-
const task = await backend.create({
|
|
372
|
-
description: "Original",
|
|
373
|
-
created_by: "agent-1",
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
const updated = await backend.update(task.id, {
|
|
377
|
-
description: "Updated",
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
expect(updated.description).toBe("Updated");
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
it("should update task status", async () => {
|
|
384
|
-
const task = await backend.create({
|
|
385
|
-
description: "Test task",
|
|
386
|
-
created_by: "agent-1",
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// Assign first
|
|
390
|
-
await backend.assign(task.id, "agent-1");
|
|
391
|
-
|
|
392
|
-
const updated = await backend.update(task.id, {
|
|
393
|
-
status: "in_progress",
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
expect(updated.status).toBe("in_progress");
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
it("should throw for invalid status transition", async () => {
|
|
400
|
-
const task = await backend.create({
|
|
401
|
-
description: "Test task",
|
|
402
|
-
created_by: "agent-1",
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
await expect(
|
|
406
|
-
backend.update(task.id, { status: "completed" })
|
|
407
|
-
).rejects.toThrow("Invalid status transition");
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it("should throw for non-existent task", async () => {
|
|
411
|
-
await expect(
|
|
412
|
-
backend.update("nonexistent", { description: "Test" })
|
|
413
|
-
).rejects.toThrow("Task not found");
|
|
414
|
-
});
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
describe("delete", () => {
|
|
418
|
-
it("should throw not supported error", async () => {
|
|
419
|
-
const task = await backend.create({
|
|
420
|
-
description: "Test task",
|
|
421
|
-
created_by: "agent-1",
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
// Delete is not supported - tasks are immutable in event-sourced system
|
|
425
|
-
await expect(backend.delete(task.id)).rejects.toThrow("not supported");
|
|
426
|
-
|
|
427
|
-
// Task should remain unchanged
|
|
428
|
-
const unchanged = await backend.get(task.id);
|
|
429
|
-
expect(unchanged!.status).toBe("pending");
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it("should throw not supported even for tasks bound to issues", async () => {
|
|
433
|
-
const task = await backend.create({
|
|
434
|
-
description: "Test task",
|
|
435
|
-
created_by: "agent-1",
|
|
436
|
-
external_id: "i-test1",
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// Delete is not supported regardless of issue binding
|
|
440
|
-
await expect(backend.delete(task.id)).rejects.toThrow("not supported");
|
|
441
|
-
|
|
442
|
-
// Task should still be in the issue index
|
|
443
|
-
const taskIds = backend.getTasksByIssue("i-test1");
|
|
444
|
-
expect(taskIds).toContain(task.id);
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
it("should throw not supported even for non-existent task", async () => {
|
|
448
|
-
// Note: We throw "not supported" before checking if task exists
|
|
449
|
-
// This matches InMemoryTaskBackend behavior for consistency
|
|
450
|
-
await expect(backend.delete("nonexistent")).rejects.toThrow(
|
|
451
|
-
"not supported"
|
|
452
|
-
);
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
describe("assign", () => {
|
|
457
|
-
it("should assign a task to an agent", async () => {
|
|
458
|
-
const task = await backend.create({
|
|
459
|
-
description: "Test task",
|
|
460
|
-
created_by: "agent-1",
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
await backend.assign(task.id, "agent-2");
|
|
464
|
-
|
|
465
|
-
const updated = await backend.get(task.id);
|
|
466
|
-
expect(updated!.status).toBe("assigned");
|
|
467
|
-
expect(updated!.assigned_agent).toBe("agent-2");
|
|
468
|
-
});
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
describe("unassign", () => {
|
|
472
|
-
it("should unassign a task", async () => {
|
|
473
|
-
const task = await backend.create({
|
|
474
|
-
description: "Test task",
|
|
475
|
-
created_by: "agent-1",
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
await backend.assign(task.id, "agent-2");
|
|
479
|
-
await backend.unassign(task.id);
|
|
480
|
-
|
|
481
|
-
const updated = await backend.get(task.id);
|
|
482
|
-
expect(updated!.status).toBe("pending");
|
|
483
|
-
expect(updated!.assigned_agent).toBeUndefined();
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
it("should throw when task is not assigned", async () => {
|
|
487
|
-
const task = await backend.create({
|
|
488
|
-
description: "Test task",
|
|
489
|
-
created_by: "agent-1",
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
await expect(backend.unassign(task.id)).rejects.toThrow("not assigned");
|
|
493
|
-
});
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
describe("start", () => {
|
|
497
|
-
it("should start a task", async () => {
|
|
498
|
-
const task = await backend.create({
|
|
499
|
-
description: "Test task",
|
|
500
|
-
created_by: "agent-1",
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
await backend.assign(task.id, "agent-1");
|
|
504
|
-
await backend.start(task.id);
|
|
505
|
-
|
|
506
|
-
const updated = await backend.get(task.id);
|
|
507
|
-
expect(updated!.status).toBe("in_progress");
|
|
508
|
-
});
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
describe("complete", () => {
|
|
512
|
-
it("should complete a task", async () => {
|
|
513
|
-
const task = await backend.create({
|
|
514
|
-
description: "Test task",
|
|
515
|
-
created_by: "agent-1",
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
await backend.assign(task.id, "agent-1");
|
|
519
|
-
await backend.start(task.id);
|
|
520
|
-
await backend.complete(task.id, { summary: "Done" });
|
|
521
|
-
|
|
522
|
-
const updated = await backend.get(task.id);
|
|
523
|
-
expect(updated!.status).toBe("completed");
|
|
524
|
-
});
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
describe("fail", () => {
|
|
528
|
-
it("should fail a task", async () => {
|
|
529
|
-
const task = await backend.create({
|
|
530
|
-
description: "Test task",
|
|
531
|
-
created_by: "agent-1",
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
await backend.assign(task.id, "agent-1");
|
|
535
|
-
await backend.start(task.id);
|
|
536
|
-
await backend.fail(task.id, { message: "Something went wrong" });
|
|
537
|
-
|
|
538
|
-
const updated = await backend.get(task.id);
|
|
539
|
-
expect(updated!.status).toBe("failed");
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
describe("list", () => {
|
|
544
|
-
it("should list all tasks", async () => {
|
|
545
|
-
await backend.create({ description: "Task 1", created_by: "agent-1" });
|
|
546
|
-
await backend.create({ description: "Task 2", created_by: "agent-1" });
|
|
547
|
-
|
|
548
|
-
const tasks = await backend.list();
|
|
549
|
-
expect(tasks).toHaveLength(2);
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
it("should filter by status", async () => {
|
|
553
|
-
const task1 = await backend.create({
|
|
554
|
-
description: "Task 1",
|
|
555
|
-
created_by: "agent-1",
|
|
556
|
-
});
|
|
557
|
-
await backend.create({ description: "Task 2", created_by: "agent-1" });
|
|
558
|
-
|
|
559
|
-
await backend.assign(task1.id, "agent-1");
|
|
560
|
-
|
|
561
|
-
const assigned = await backend.list({ status: "assigned" });
|
|
562
|
-
expect(assigned).toHaveLength(1);
|
|
563
|
-
expect(assigned[0].id).toBe(task1.id);
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
it("should filter by assigned_agent", async () => {
|
|
567
|
-
const task1 = await backend.create({
|
|
568
|
-
description: "Task 1",
|
|
569
|
-
created_by: "agent-1",
|
|
570
|
-
});
|
|
571
|
-
await backend.create({ description: "Task 2", created_by: "agent-1" });
|
|
572
|
-
|
|
573
|
-
await backend.assign(task1.id, "agent-2");
|
|
574
|
-
|
|
575
|
-
const tasks = await backend.list({ assigned_agent: "agent-2" });
|
|
576
|
-
expect(tasks).toHaveLength(1);
|
|
577
|
-
expect(tasks[0].id).toBe(task1.id);
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
it("should exclude blocked tasks by default", async () => {
|
|
581
|
-
const blocker = await backend.create({
|
|
582
|
-
description: "Blocker",
|
|
583
|
-
created_by: "agent-1",
|
|
584
|
-
});
|
|
585
|
-
const blocked = await backend.create({
|
|
586
|
-
description: "Blocked",
|
|
587
|
-
created_by: "agent-1",
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
591
|
-
|
|
592
|
-
const tasks = await backend.list();
|
|
593
|
-
expect(tasks.map((t) => t.id)).not.toContain(blocked.id);
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
it("should include blocked tasks when requested", async () => {
|
|
597
|
-
const blocker = await backend.create({
|
|
598
|
-
description: "Blocker",
|
|
599
|
-
created_by: "agent-1",
|
|
600
|
-
});
|
|
601
|
-
const blocked = await backend.create({
|
|
602
|
-
description: "Blocked",
|
|
603
|
-
created_by: "agent-1",
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
607
|
-
|
|
608
|
-
const tasks = await backend.list({ includeBlocked: true });
|
|
609
|
-
expect(tasks.map((t) => t.id)).toContain(blocked.id);
|
|
610
|
-
});
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
describe("listReady", () => {
|
|
614
|
-
it("should return unblocked pending tasks", async () => {
|
|
615
|
-
await backend.create({ description: "Task 1", created_by: "agent-1" });
|
|
616
|
-
await backend.create({ description: "Task 2", created_by: "agent-1" });
|
|
617
|
-
|
|
618
|
-
const ready = await backend.listReady();
|
|
619
|
-
expect(ready).toHaveLength(2);
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
it("should exclude blocked tasks", async () => {
|
|
623
|
-
const blocker = await backend.create({
|
|
624
|
-
description: "Blocker",
|
|
625
|
-
created_by: "agent-1",
|
|
626
|
-
});
|
|
627
|
-
const blocked = await backend.create({
|
|
628
|
-
description: "Blocked",
|
|
629
|
-
created_by: "agent-1",
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
633
|
-
|
|
634
|
-
const ready = await backend.listReady();
|
|
635
|
-
expect(ready.map((t) => t.id)).not.toContain(blocked.id);
|
|
636
|
-
});
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
describe("blockers", () => {
|
|
640
|
-
it("should add and get blockers", async () => {
|
|
641
|
-
const task1 = await backend.create({
|
|
642
|
-
description: "Task 1",
|
|
643
|
-
created_by: "agent-1",
|
|
644
|
-
});
|
|
645
|
-
const task2 = await backend.create({
|
|
646
|
-
description: "Task 2",
|
|
647
|
-
created_by: "agent-1",
|
|
648
|
-
});
|
|
649
|
-
|
|
650
|
-
await backend.addBlocker(task2.id, task1.id);
|
|
651
|
-
|
|
652
|
-
const blockers = await backend.getBlockers(task2.id);
|
|
653
|
-
expect(blockers).toHaveLength(1);
|
|
654
|
-
expect(blockers[0].id).toBe(task1.id);
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
it("should remove blockers", async () => {
|
|
658
|
-
const task1 = await backend.create({
|
|
659
|
-
description: "Task 1",
|
|
660
|
-
created_by: "agent-1",
|
|
661
|
-
});
|
|
662
|
-
const task2 = await backend.create({
|
|
663
|
-
description: "Task 2",
|
|
664
|
-
created_by: "agent-1",
|
|
665
|
-
});
|
|
666
|
-
|
|
667
|
-
await backend.addBlocker(task2.id, task1.id);
|
|
668
|
-
await backend.removeBlocker(task2.id, task1.id);
|
|
669
|
-
|
|
670
|
-
const blockers = await backend.getBlockers(task2.id);
|
|
671
|
-
expect(blockers).toHaveLength(0);
|
|
672
|
-
});
|
|
673
|
-
|
|
674
|
-
it("should get tasks that this task blocks", async () => {
|
|
675
|
-
const task1 = await backend.create({
|
|
676
|
-
description: "Task 1",
|
|
677
|
-
created_by: "agent-1",
|
|
678
|
-
});
|
|
679
|
-
const task2 = await backend.create({
|
|
680
|
-
description: "Task 2",
|
|
681
|
-
created_by: "agent-1",
|
|
682
|
-
});
|
|
683
|
-
|
|
684
|
-
await backend.addBlocker(task2.id, task1.id);
|
|
685
|
-
|
|
686
|
-
const blocking = await backend.getBlocking(task1.id);
|
|
687
|
-
expect(blocking).toHaveLength(1);
|
|
688
|
-
expect(blocking[0].id).toBe(task2.id);
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
it("should compute isBlocked from local blockers", async () => {
|
|
692
|
-
const blocker = await backend.create({
|
|
693
|
-
description: "Blocker",
|
|
694
|
-
created_by: "agent-1",
|
|
695
|
-
});
|
|
696
|
-
const blocked = await backend.create({
|
|
697
|
-
description: "Blocked",
|
|
698
|
-
created_by: "agent-1",
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
702
|
-
|
|
703
|
-
const task = await backend.get(blocked.id);
|
|
704
|
-
expect(task!.isBlocked).toBe(true);
|
|
705
|
-
});
|
|
706
|
-
|
|
707
|
-
it("should not be blocked when blocker is completed", async () => {
|
|
708
|
-
const blocker = await backend.create({
|
|
709
|
-
description: "Blocker",
|
|
710
|
-
created_by: "agent-1",
|
|
711
|
-
});
|
|
712
|
-
const blocked = await backend.create({
|
|
713
|
-
description: "Blocked",
|
|
714
|
-
created_by: "agent-1",
|
|
715
|
-
});
|
|
716
|
-
|
|
717
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
718
|
-
|
|
719
|
-
// Complete the blocker
|
|
720
|
-
await backend.assign(blocker.id, "agent-1");
|
|
721
|
-
await backend.start(blocker.id);
|
|
722
|
-
await backend.complete(blocker.id);
|
|
723
|
-
|
|
724
|
-
const task = await backend.get(blocked.id);
|
|
725
|
-
expect(task!.isBlocked).toBe(false);
|
|
726
|
-
});
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
describe("getChildren", () => {
|
|
730
|
-
it("should get child tasks", async () => {
|
|
731
|
-
const parent = await backend.create({
|
|
732
|
-
description: "Parent",
|
|
733
|
-
created_by: "agent-1",
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
await backend.create({
|
|
737
|
-
description: "Child 1",
|
|
738
|
-
created_by: "agent-1",
|
|
739
|
-
parent_task: parent.id,
|
|
740
|
-
});
|
|
741
|
-
await backend.create({
|
|
742
|
-
description: "Child 2",
|
|
743
|
-
created_by: "agent-1",
|
|
744
|
-
parent_task: parent.id,
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
const children = await backend.getChildren(parent.id);
|
|
748
|
-
expect(children).toHaveLength(2);
|
|
749
|
-
});
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
describe("getSubtaskStatus", () => {
|
|
753
|
-
it("should aggregate subtask statuses", async () => {
|
|
754
|
-
const parent = await backend.create({
|
|
755
|
-
description: "Parent",
|
|
756
|
-
created_by: "agent-1",
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
const child1 = await backend.create({
|
|
760
|
-
description: "Child 1",
|
|
761
|
-
created_by: "agent-1",
|
|
762
|
-
parent_task: parent.id,
|
|
763
|
-
});
|
|
764
|
-
await backend.create({
|
|
765
|
-
description: "Child 2",
|
|
766
|
-
created_by: "agent-1",
|
|
767
|
-
parent_task: parent.id,
|
|
768
|
-
});
|
|
769
|
-
|
|
770
|
-
await backend.assign(child1.id, "agent-1");
|
|
771
|
-
await backend.start(child1.id);
|
|
772
|
-
await backend.complete(child1.id);
|
|
773
|
-
|
|
774
|
-
const status = await backend.getSubtaskStatus(parent.id);
|
|
775
|
-
expect(status.total).toBe(2);
|
|
776
|
-
expect(status.completed).toBe(1);
|
|
777
|
-
expect(status.pending).toBe(1);
|
|
778
|
-
expect(status.allCompleted).toBe(false);
|
|
779
|
-
});
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
describe("getAgentHistory", () => {
|
|
783
|
-
it("should return agent history", async () => {
|
|
784
|
-
const task = await backend.create({
|
|
785
|
-
description: "Test",
|
|
786
|
-
created_by: "agent-1",
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
const history = await backend.getAgentHistory(task.id);
|
|
790
|
-
expect(Array.isArray(history)).toBe(true);
|
|
791
|
-
});
|
|
792
|
-
});
|
|
793
|
-
|
|
794
|
-
describe("onTaskChange", () => {
|
|
795
|
-
it("should notify on task changes", async () => {
|
|
796
|
-
const callback = vi.fn();
|
|
797
|
-
const unsubscribe = backend.onTaskChange(callback);
|
|
798
|
-
|
|
799
|
-
await backend.create({
|
|
800
|
-
description: "Test",
|
|
801
|
-
created_by: "agent-1",
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
expect(callback).toHaveBeenCalled();
|
|
805
|
-
|
|
806
|
-
unsubscribe();
|
|
807
|
-
});
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
describe("issue-bound tasks", () => {
|
|
811
|
-
it("should check issue blockers for bound tasks", async () => {
|
|
812
|
-
// Set up a blocker in sudocode
|
|
813
|
-
const blockerIssue: Issue = {
|
|
814
|
-
id: "i-blocker",
|
|
815
|
-
uuid: "uuid-blocker",
|
|
816
|
-
title: "Blocker Issue",
|
|
817
|
-
content: "Blocks test1",
|
|
818
|
-
status: "open",
|
|
819
|
-
priority: 1,
|
|
820
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
821
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
822
|
-
};
|
|
823
|
-
client._setIssue("i-blocker", blockerIssue);
|
|
824
|
-
client._setBlockers("i-test1", [blockerIssue]);
|
|
825
|
-
|
|
826
|
-
const task = await backend.create({
|
|
827
|
-
description: "Test task",
|
|
828
|
-
created_by: "agent-1",
|
|
829
|
-
external_id: "i-test1",
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
const fetched = await backend.get(task.id);
|
|
833
|
-
expect(fetched!.isBlocked).toBe(true);
|
|
834
|
-
});
|
|
835
|
-
|
|
836
|
-
it("should not be blocked when issue blocker is closed", async () => {
|
|
837
|
-
const blockerIssue: Issue = {
|
|
838
|
-
id: "i-blocker",
|
|
839
|
-
uuid: "uuid-blocker",
|
|
840
|
-
title: "Blocker Issue",
|
|
841
|
-
content: "Blocks test1",
|
|
842
|
-
status: "closed", // Closed - no longer blocks
|
|
843
|
-
priority: 1,
|
|
844
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
845
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
846
|
-
};
|
|
847
|
-
client._setIssue("i-blocker", blockerIssue);
|
|
848
|
-
client._setBlockers("i-test1", [blockerIssue]);
|
|
849
|
-
|
|
850
|
-
const task = await backend.create({
|
|
851
|
-
description: "Test task",
|
|
852
|
-
created_by: "agent-1",
|
|
853
|
-
external_id: "i-test1",
|
|
854
|
-
});
|
|
855
|
-
|
|
856
|
-
const fetched = await backend.get(task.id);
|
|
857
|
-
expect(fetched!.isBlocked).toBe(false);
|
|
858
|
-
});
|
|
859
|
-
});
|
|
860
|
-
|
|
861
|
-
describe("task-issue index", () => {
|
|
862
|
-
it("should track tasks by issue", async () => {
|
|
863
|
-
const task1 = await backend.create({
|
|
864
|
-
description: "Task 1",
|
|
865
|
-
created_by: "agent-1",
|
|
866
|
-
external_id: "i-test1",
|
|
867
|
-
});
|
|
868
|
-
const task2 = await backend.create({
|
|
869
|
-
description: "Task 2",
|
|
870
|
-
created_by: "agent-1",
|
|
871
|
-
external_id: "i-test1",
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
const taskIds = backend.getTasksByIssue("i-test1");
|
|
875
|
-
expect(taskIds).toHaveLength(2);
|
|
876
|
-
expect(taskIds).toContain(task1.id);
|
|
877
|
-
expect(taskIds).toContain(task2.id);
|
|
878
|
-
});
|
|
879
|
-
|
|
880
|
-
it("should track issue for each task", async () => {
|
|
881
|
-
const task = await backend.create({
|
|
882
|
-
description: "Test task",
|
|
883
|
-
created_by: "agent-1",
|
|
884
|
-
external_id: "i-test1",
|
|
885
|
-
});
|
|
886
|
-
|
|
887
|
-
const issueId = backend.getIssueForTask(task.id);
|
|
888
|
-
expect(issueId).toBe("i-test1");
|
|
889
|
-
});
|
|
890
|
-
|
|
891
|
-
it("should return undefined for unbound task", async () => {
|
|
892
|
-
const task = await backend.create({
|
|
893
|
-
description: "Test task",
|
|
894
|
-
created_by: "agent-1",
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
const issueId = backend.getIssueForTask(task.id);
|
|
898
|
-
expect(issueId).toBeUndefined();
|
|
899
|
-
});
|
|
900
|
-
});
|
|
901
|
-
|
|
902
|
-
describe("bindToIssue", () => {
|
|
903
|
-
it("should bind a task to an issue", async () => {
|
|
904
|
-
const task = await backend.create({
|
|
905
|
-
description: "Test task",
|
|
906
|
-
created_by: "agent-1",
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
await backend.bindToIssue(task.id, "i-test1");
|
|
910
|
-
|
|
911
|
-
const issueId = backend.getIssueForTask(task.id);
|
|
912
|
-
expect(issueId).toBe("i-test1");
|
|
913
|
-
|
|
914
|
-
const taskIds = backend.getTasksByIssue("i-test1");
|
|
915
|
-
expect(taskIds).toContain(task.id);
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
it("should throw when issue not found", async () => {
|
|
919
|
-
const task = await backend.create({
|
|
920
|
-
description: "Test task",
|
|
921
|
-
created_by: "agent-1",
|
|
922
|
-
});
|
|
923
|
-
|
|
924
|
-
await expect(
|
|
925
|
-
backend.bindToIssue(task.id, "i-nonexistent")
|
|
926
|
-
).rejects.toThrow("Issue not found");
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
it("should throw when task not found", async () => {
|
|
930
|
-
await expect(
|
|
931
|
-
backend.bindToIssue("nonexistent", "i-test1")
|
|
932
|
-
).rejects.toThrow("Task not found");
|
|
933
|
-
});
|
|
934
|
-
|
|
935
|
-
it("should rebind task to different issue", async () => {
|
|
936
|
-
const task = await backend.create({
|
|
937
|
-
description: "Test task",
|
|
938
|
-
created_by: "agent-1",
|
|
939
|
-
external_id: "i-test1",
|
|
940
|
-
});
|
|
941
|
-
|
|
942
|
-
await backend.bindToIssue(task.id, "i-test2");
|
|
943
|
-
|
|
944
|
-
const issueId = backend.getIssueForTask(task.id);
|
|
945
|
-
expect(issueId).toBe("i-test2");
|
|
946
|
-
|
|
947
|
-
// Should no longer be in old issue's list
|
|
948
|
-
const oldTaskIds = backend.getTasksByIssue("i-test1");
|
|
949
|
-
expect(oldTaskIds).not.toContain(task.id);
|
|
950
|
-
|
|
951
|
-
// Should be in new issue's list
|
|
952
|
-
const newTaskIds = backend.getTasksByIssue("i-test2");
|
|
953
|
-
expect(newTaskIds).toContain(task.id);
|
|
954
|
-
});
|
|
955
|
-
});
|
|
956
|
-
|
|
957
|
-
describe("unbindFromIssue", () => {
|
|
958
|
-
it("should unbind a task from its issue", async () => {
|
|
959
|
-
const task = await backend.create({
|
|
960
|
-
description: "Test task",
|
|
961
|
-
created_by: "agent-1",
|
|
962
|
-
external_id: "i-test1",
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
await backend.unbindFromIssue(task.id);
|
|
966
|
-
|
|
967
|
-
const issueId = backend.getIssueForTask(task.id);
|
|
968
|
-
expect(issueId).toBeUndefined();
|
|
969
|
-
|
|
970
|
-
const taskIds = backend.getTasksByIssue("i-test1");
|
|
971
|
-
expect(taskIds).not.toContain(task.id);
|
|
972
|
-
});
|
|
973
|
-
|
|
974
|
-
it("should do nothing for unbound task", async () => {
|
|
975
|
-
const task = await backend.create({
|
|
976
|
-
description: "Test task",
|
|
977
|
-
created_by: "agent-1",
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
// Should not throw
|
|
981
|
-
await backend.unbindFromIssue(task.id);
|
|
982
|
-
|
|
983
|
-
const issueId = backend.getIssueForTask(task.id);
|
|
984
|
-
expect(issueId).toBeUndefined();
|
|
985
|
-
});
|
|
986
|
-
|
|
987
|
-
it("should throw when task not found", async () => {
|
|
988
|
-
await expect(backend.unbindFromIssue("nonexistent")).rejects.toThrow(
|
|
989
|
-
"Task not found"
|
|
990
|
-
);
|
|
991
|
-
});
|
|
992
|
-
});
|
|
993
|
-
|
|
994
|
-
describe("sudocode relationship integration", () => {
|
|
995
|
-
it("should create sudocode link when both tasks are bound to issues", async () => {
|
|
996
|
-
// Create two tasks bound to different issues
|
|
997
|
-
const blocker = await backend.create({
|
|
998
|
-
description: "Blocker task",
|
|
999
|
-
created_by: "agent-1",
|
|
1000
|
-
external_id: "i-test1",
|
|
1001
|
-
});
|
|
1002
|
-
const blocked = await backend.create({
|
|
1003
|
-
description: "Blocked task",
|
|
1004
|
-
created_by: "agent-1",
|
|
1005
|
-
external_id: "i-test2",
|
|
1006
|
-
});
|
|
1007
|
-
|
|
1008
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
1009
|
-
|
|
1010
|
-
// Verify sudocode createLink was called with correct args
|
|
1011
|
-
expect(client.createLink).toHaveBeenCalledWith(
|
|
1012
|
-
"i-test1", // blocker issue
|
|
1013
|
-
"i-test2", // blocked issue
|
|
1014
|
-
"blocks"
|
|
1015
|
-
);
|
|
1016
|
-
});
|
|
1017
|
-
|
|
1018
|
-
it("should not create sudocode link when tasks are not bound", async () => {
|
|
1019
|
-
// Create two tasks without external_id
|
|
1020
|
-
const blocker = await backend.create({
|
|
1021
|
-
description: "Blocker task",
|
|
1022
|
-
created_by: "agent-1",
|
|
1023
|
-
});
|
|
1024
|
-
const blocked = await backend.create({
|
|
1025
|
-
description: "Blocked task",
|
|
1026
|
-
created_by: "agent-1",
|
|
1027
|
-
});
|
|
1028
|
-
|
|
1029
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
1030
|
-
|
|
1031
|
-
// createLink should not be called
|
|
1032
|
-
expect(client.createLink).not.toHaveBeenCalled();
|
|
1033
|
-
});
|
|
1034
|
-
|
|
1035
|
-
it("should remove sudocode link when both tasks are bound to issues", async () => {
|
|
1036
|
-
// Create two tasks bound to different issues
|
|
1037
|
-
const blocker = await backend.create({
|
|
1038
|
-
description: "Blocker task",
|
|
1039
|
-
created_by: "agent-1",
|
|
1040
|
-
external_id: "i-test1",
|
|
1041
|
-
});
|
|
1042
|
-
const blocked = await backend.create({
|
|
1043
|
-
description: "Blocked task",
|
|
1044
|
-
created_by: "agent-1",
|
|
1045
|
-
external_id: "i-test2",
|
|
1046
|
-
});
|
|
1047
|
-
|
|
1048
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
1049
|
-
await backend.removeBlocker(blocked.id, blocker.id);
|
|
1050
|
-
|
|
1051
|
-
// Verify sudocode removeLink was called with correct args
|
|
1052
|
-
expect(client.removeLink).toHaveBeenCalledWith(
|
|
1053
|
-
"i-test1", // blocker issue
|
|
1054
|
-
"i-test2", // blocked issue
|
|
1055
|
-
"blocks"
|
|
1056
|
-
);
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
it("should merge local and sudocode blockers in getBlockers", async () => {
|
|
1060
|
-
// Create a task bound to i-test2
|
|
1061
|
-
const task = await backend.create({
|
|
1062
|
-
description: "Test task",
|
|
1063
|
-
created_by: "agent-1",
|
|
1064
|
-
external_id: "i-test2",
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
|
-
// Create a local blocker (unbound task)
|
|
1068
|
-
const localBlocker = await backend.create({
|
|
1069
|
-
description: "Local blocker",
|
|
1070
|
-
created_by: "agent-1",
|
|
1071
|
-
});
|
|
1072
|
-
await backend.addBlocker(task.id, localBlocker.id);
|
|
1073
|
-
|
|
1074
|
-
// Create a task bound to i-test1 (sudocode blocker)
|
|
1075
|
-
const sudocodeBlocker = await backend.create({
|
|
1076
|
-
description: "Sudocode blocker",
|
|
1077
|
-
created_by: "agent-1",
|
|
1078
|
-
external_id: "i-test1",
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
// Set up sudocode to report i-test1 as blocking i-test2
|
|
1082
|
-
client._setBlockers("i-test2", [
|
|
1083
|
-
{
|
|
1084
|
-
id: "i-test1",
|
|
1085
|
-
uuid: "uuid-1",
|
|
1086
|
-
title: "Test Issue 1",
|
|
1087
|
-
content: "Test content",
|
|
1088
|
-
status: "open",
|
|
1089
|
-
priority: 1,
|
|
1090
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
1091
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
1092
|
-
},
|
|
1093
|
-
]);
|
|
1094
|
-
|
|
1095
|
-
const blockers = await backend.getBlockers(task.id);
|
|
1096
|
-
|
|
1097
|
-
// Should have both local and sudocode blockers
|
|
1098
|
-
expect(blockers).toHaveLength(2);
|
|
1099
|
-
expect(blockers.map((b) => b.id)).toContain(localBlocker.id);
|
|
1100
|
-
expect(blockers.map((b) => b.id)).toContain(sudocodeBlocker.id);
|
|
1101
|
-
});
|
|
1102
|
-
|
|
1103
|
-
it("should merge local and sudocode blocking in getBlocking", async () => {
|
|
1104
|
-
// Create a task bound to i-test1
|
|
1105
|
-
const task = await backend.create({
|
|
1106
|
-
description: "Test task",
|
|
1107
|
-
created_by: "agent-1",
|
|
1108
|
-
external_id: "i-test1",
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
// Create a local blocked task (unbound)
|
|
1112
|
-
const localBlocked = await backend.create({
|
|
1113
|
-
description: "Local blocked",
|
|
1114
|
-
created_by: "agent-1",
|
|
1115
|
-
});
|
|
1116
|
-
await backend.addBlocker(localBlocked.id, task.id);
|
|
1117
|
-
|
|
1118
|
-
// Create a task bound to i-test2 (sudocode blocked)
|
|
1119
|
-
const sudocodeBlocked = await backend.create({
|
|
1120
|
-
description: "Sudocode blocked",
|
|
1121
|
-
created_by: "agent-1",
|
|
1122
|
-
external_id: "i-test2",
|
|
1123
|
-
});
|
|
1124
|
-
|
|
1125
|
-
// Set up sudocode to report i-test1 blocks i-test2
|
|
1126
|
-
client._setBlocking("i-test1", [
|
|
1127
|
-
{
|
|
1128
|
-
id: "i-test2",
|
|
1129
|
-
uuid: "uuid-2",
|
|
1130
|
-
title: "Test Issue 2",
|
|
1131
|
-
content: "Test content",
|
|
1132
|
-
status: "open",
|
|
1133
|
-
priority: 2,
|
|
1134
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
1135
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
1136
|
-
},
|
|
1137
|
-
]);
|
|
1138
|
-
|
|
1139
|
-
const blocking = await backend.getBlocking(task.id);
|
|
1140
|
-
|
|
1141
|
-
// Should have both local and sudocode blocked tasks
|
|
1142
|
-
expect(blocking).toHaveLength(2);
|
|
1143
|
-
expect(blocking.map((b) => b.id)).toContain(localBlocked.id);
|
|
1144
|
-
expect(blocking.map((b) => b.id)).toContain(sudocodeBlocked.id);
|
|
1145
|
-
});
|
|
1146
|
-
|
|
1147
|
-
it("should deduplicate when same task is both local and sudocode blocker", async () => {
|
|
1148
|
-
// Create blocker bound to i-test1
|
|
1149
|
-
const blocker = await backend.create({
|
|
1150
|
-
description: "Blocker task",
|
|
1151
|
-
created_by: "agent-1",
|
|
1152
|
-
external_id: "i-test1",
|
|
1153
|
-
});
|
|
1154
|
-
|
|
1155
|
-
// Create blocked task bound to i-test2
|
|
1156
|
-
const blocked = await backend.create({
|
|
1157
|
-
description: "Blocked task",
|
|
1158
|
-
created_by: "agent-1",
|
|
1159
|
-
external_id: "i-test2",
|
|
1160
|
-
});
|
|
1161
|
-
|
|
1162
|
-
// Add as local blocker
|
|
1163
|
-
await backend.addBlocker(blocked.id, blocker.id);
|
|
1164
|
-
|
|
1165
|
-
// Also set up sudocode to report the same relationship
|
|
1166
|
-
client._setBlockers("i-test2", [
|
|
1167
|
-
{
|
|
1168
|
-
id: "i-test1",
|
|
1169
|
-
uuid: "uuid-1",
|
|
1170
|
-
title: "Test Issue 1",
|
|
1171
|
-
content: "Test content",
|
|
1172
|
-
status: "open",
|
|
1173
|
-
priority: 1,
|
|
1174
|
-
created_at: "2024-01-01T00:00:00Z",
|
|
1175
|
-
updated_at: "2024-01-01T00:00:00Z",
|
|
1176
|
-
},
|
|
1177
|
-
]);
|
|
1178
|
-
|
|
1179
|
-
const blockers = await backend.getBlockers(blocked.id);
|
|
1180
|
-
|
|
1181
|
-
// Should only have one blocker (deduplicated)
|
|
1182
|
-
expect(blockers).toHaveLength(1);
|
|
1183
|
-
expect(blockers[0].id).toBe(blocker.id);
|
|
1184
|
-
});
|
|
1185
|
-
});
|
|
1186
|
-
|
|
1187
|
-
describe("createSudocodeTaskBackend", () => {
|
|
1188
|
-
it("should create a backend instance", () => {
|
|
1189
|
-
const backend = createSudocodeTaskBackend(eventStore, client);
|
|
1190
|
-
expect(backend).toBeInstanceOf(SudocodeTaskBackend);
|
|
1191
|
-
backend.close();
|
|
1192
|
-
});
|
|
1193
|
-
});
|
|
1194
|
-
});
|