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
|
@@ -0,0 +1,1023 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTasksTaskBackend Implementation
|
|
3
|
+
*
|
|
4
|
+
* Implements TaskBackend using OpenTasks as the source of truth for task storage,
|
|
5
|
+
* with EventStore for local event tracking and subscriptions.
|
|
6
|
+
*
|
|
7
|
+
* Tasks are stored as OpenTasks issues. Blocking dependencies use OpenTasks
|
|
8
|
+
* 'blocks' edges. The pull model uses OpenTasks' ready query and claimed_by field.
|
|
9
|
+
*
|
|
10
|
+
* @module task/backend/opentasks/backend
|
|
11
|
+
*/
|
|
12
|
+
import { nanoid } from "nanoid";
|
|
13
|
+
import { mapOpenTasksStatus, mapTaskStatus, isIssueComplete } from "./mapping.js";
|
|
14
|
+
// Valid status transitions
|
|
15
|
+
const VALID_STATUS_TRANSITIONS = {
|
|
16
|
+
pending: ["assigned", "in_progress", "failed"],
|
|
17
|
+
assigned: ["in_progress", "pending", "failed"],
|
|
18
|
+
in_progress: ["completed", "failed", "pending"],
|
|
19
|
+
completed: [],
|
|
20
|
+
failed: ["pending"],
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Error thrown by OpenTasksTaskBackend operations
|
|
24
|
+
*/
|
|
25
|
+
export class OpenTasksBackendError extends Error {
|
|
26
|
+
code;
|
|
27
|
+
taskId;
|
|
28
|
+
constructor(message, code, taskId) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.taskId = taskId;
|
|
32
|
+
this.name = "OpenTasksBackendError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const DEFAULT_CONFIG = {
|
|
36
|
+
socketPath: "",
|
|
37
|
+
syncStatus: true,
|
|
38
|
+
sourceLabel: "macro-agent",
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* OpenTasksTaskBackend implements TaskBackend using:
|
|
42
|
+
* - OpenTasks daemon for issue storage and graph relationships
|
|
43
|
+
* - EventStore for local event tracking and subscriptions
|
|
44
|
+
*
|
|
45
|
+
* Key features:
|
|
46
|
+
* - Tasks are stored as OpenTasks issues with macro-agent metadata
|
|
47
|
+
* - Blocking dependencies use OpenTasks 'blocks' edges
|
|
48
|
+
* - Pull model uses OpenTasks ready query and claimed_by
|
|
49
|
+
* - Bidirectional ID mapping (task_id <-> issue_id) via metadata
|
|
50
|
+
*/
|
|
51
|
+
export class OpenTasksTaskBackend {
|
|
52
|
+
eventStore;
|
|
53
|
+
client;
|
|
54
|
+
config;
|
|
55
|
+
closed = false;
|
|
56
|
+
/** Map from macro-agent task ID to OpenTasks issue ID */
|
|
57
|
+
taskToIssue = new Map();
|
|
58
|
+
/** Map from OpenTasks issue ID to macro-agent task ID */
|
|
59
|
+
issueToTask = new Map();
|
|
60
|
+
constructor(eventStore, client, config) {
|
|
61
|
+
this.eventStore = eventStore;
|
|
62
|
+
this.client = client;
|
|
63
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Throw if the backend has been closed.
|
|
67
|
+
*/
|
|
68
|
+
ensureOpen() {
|
|
69
|
+
if (this.closed) {
|
|
70
|
+
throw new OpenTasksBackendError("Backend is closed", "BACKEND_CLOSED");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
74
|
+
// Lifecycle
|
|
75
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
76
|
+
async close() {
|
|
77
|
+
this.closed = true;
|
|
78
|
+
}
|
|
79
|
+
async create(options) {
|
|
80
|
+
this.ensureOpen();
|
|
81
|
+
const taskId = `task_${nanoid(12)}`;
|
|
82
|
+
// Resolve parent issue ID if parent task specified
|
|
83
|
+
let parentIssueId;
|
|
84
|
+
if (options.parent_task) {
|
|
85
|
+
parentIssueId = this.taskToIssue.get(options.parent_task);
|
|
86
|
+
if (!parentIssueId) {
|
|
87
|
+
// Check EventStore as fallback
|
|
88
|
+
const parent = this.eventStore.getTask(options.parent_task);
|
|
89
|
+
if (!parent) {
|
|
90
|
+
throw new OpenTasksBackendError(`Parent task not found: ${options.parent_task}`, "PARENT_TASK_NOT_FOUND", options.parent_task);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Create issue in OpenTasks
|
|
95
|
+
const issue = await this.client.createIssue({
|
|
96
|
+
title: options.description,
|
|
97
|
+
status: "open",
|
|
98
|
+
tags: options.tags,
|
|
99
|
+
parent_id: parentIssueId,
|
|
100
|
+
metadata: {
|
|
101
|
+
macro_agent_task_id: taskId,
|
|
102
|
+
created_by: options.created_by,
|
|
103
|
+
source: this.config.sourceLabel,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
// Store bidirectional mapping
|
|
107
|
+
this.taskToIssue.set(taskId, issue.id);
|
|
108
|
+
this.issueToTask.set(issue.id, taskId);
|
|
109
|
+
// Emit to EventStore for local tracking
|
|
110
|
+
this.eventStore.emit({
|
|
111
|
+
type: "task",
|
|
112
|
+
source: { agent_id: options.created_by },
|
|
113
|
+
payload: {
|
|
114
|
+
task_id: taskId,
|
|
115
|
+
action: "created",
|
|
116
|
+
details: {
|
|
117
|
+
description: options.description,
|
|
118
|
+
parent_task: options.parent_task,
|
|
119
|
+
tags: options.tags,
|
|
120
|
+
external_id: issue.id,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
// Update parent subtasks in EventStore
|
|
125
|
+
if (options.parent_task) {
|
|
126
|
+
this.eventStore.emit({
|
|
127
|
+
type: "task",
|
|
128
|
+
source: { agent_id: options.created_by },
|
|
129
|
+
payload: {
|
|
130
|
+
task_id: options.parent_task,
|
|
131
|
+
action: "status_change",
|
|
132
|
+
details: { subtask_added: taskId },
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Return from EventStore (which has the canonical local state)
|
|
137
|
+
const task = this.eventStore.getTask(taskId);
|
|
138
|
+
return this.toExtendedTask(task);
|
|
139
|
+
}
|
|
140
|
+
async get(id) {
|
|
141
|
+
// EventStore is the local mirror with richer state
|
|
142
|
+
// (assigned status, outputs, agent_history, etc.)
|
|
143
|
+
const task = this.eventStore.getTask(id);
|
|
144
|
+
if (!task)
|
|
145
|
+
return null;
|
|
146
|
+
return this.toExtendedTask(task);
|
|
147
|
+
}
|
|
148
|
+
async update(id, updates) {
|
|
149
|
+
this.ensureOpen();
|
|
150
|
+
const task = this.eventStore.getTask(id);
|
|
151
|
+
if (!task) {
|
|
152
|
+
throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
|
|
153
|
+
}
|
|
154
|
+
const source = task.assigned_agent ?? task.created_by;
|
|
155
|
+
// Handle status update with validation
|
|
156
|
+
if (updates.status !== undefined) {
|
|
157
|
+
const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
|
|
158
|
+
if (!validTransitions.includes(updates.status)) {
|
|
159
|
+
throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> ${updates.status}`, "INVALID_STATUS_TRANSITION", id);
|
|
160
|
+
}
|
|
161
|
+
this.eventStore.emit({
|
|
162
|
+
type: "task",
|
|
163
|
+
source: { agent_id: source },
|
|
164
|
+
payload: {
|
|
165
|
+
task_id: id,
|
|
166
|
+
action: "status_change",
|
|
167
|
+
details: { status: updates.status },
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
// Sync to OpenTasks
|
|
171
|
+
await this.syncStatusToOpenTasks(id, updates.status);
|
|
172
|
+
}
|
|
173
|
+
// Handle other updates
|
|
174
|
+
if (updates.outputs !== undefined) {
|
|
175
|
+
this.eventStore.emit({
|
|
176
|
+
type: "task",
|
|
177
|
+
source: { agent_id: source },
|
|
178
|
+
payload: {
|
|
179
|
+
task_id: id,
|
|
180
|
+
action: "status_change",
|
|
181
|
+
details: { outputs: updates.outputs },
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (updates.artifacts !== undefined) {
|
|
186
|
+
this.eventStore.emit({
|
|
187
|
+
type: "task",
|
|
188
|
+
source: { agent_id: source },
|
|
189
|
+
payload: {
|
|
190
|
+
task_id: id,
|
|
191
|
+
action: "status_change",
|
|
192
|
+
details: { artifacts: updates.artifacts },
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
if (updates.description !== undefined) {
|
|
197
|
+
this.eventStore.emit({
|
|
198
|
+
type: "task",
|
|
199
|
+
source: { agent_id: source },
|
|
200
|
+
payload: {
|
|
201
|
+
task_id: id,
|
|
202
|
+
action: "status_change",
|
|
203
|
+
details: { description: updates.description },
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
// Sync description to OpenTasks
|
|
207
|
+
const issueId = this.taskToIssue.get(id);
|
|
208
|
+
if (issueId) {
|
|
209
|
+
await this.client.updateIssue(issueId, {
|
|
210
|
+
title: updates.description,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const updated = this.eventStore.getTask(id);
|
|
215
|
+
return this.toExtendedTask(updated);
|
|
216
|
+
}
|
|
217
|
+
async delete(id) {
|
|
218
|
+
this.ensureOpen();
|
|
219
|
+
const issueId = this.taskToIssue.get(id);
|
|
220
|
+
if (issueId) {
|
|
221
|
+
await this.client.deleteIssue(issueId);
|
|
222
|
+
this.taskToIssue.delete(id);
|
|
223
|
+
this.issueToTask.delete(issueId);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
227
|
+
// Status Transitions
|
|
228
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
229
|
+
async assign(id, agentId, options) {
|
|
230
|
+
this.ensureOpen();
|
|
231
|
+
const task = this.eventStore.getTask(id);
|
|
232
|
+
if (!task) {
|
|
233
|
+
throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
|
|
234
|
+
}
|
|
235
|
+
this.eventStore.emit({
|
|
236
|
+
type: "task",
|
|
237
|
+
source: { agent_id: agentId },
|
|
238
|
+
payload: {
|
|
239
|
+
task_id: id,
|
|
240
|
+
action: "assigned",
|
|
241
|
+
details: {
|
|
242
|
+
agent_id: agentId,
|
|
243
|
+
role: options?.role,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
// Sync assignee to OpenTasks
|
|
248
|
+
const issueId = this.taskToIssue.get(id);
|
|
249
|
+
if (issueId) {
|
|
250
|
+
await this.client.updateIssue(issueId, {
|
|
251
|
+
assignee: agentId,
|
|
252
|
+
metadata: { claimed_by: agentId },
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async unassign(id) {
|
|
257
|
+
this.ensureOpen();
|
|
258
|
+
const task = this.eventStore.getTask(id);
|
|
259
|
+
if (!task) {
|
|
260
|
+
throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
|
|
261
|
+
}
|
|
262
|
+
if (!task.assigned_agent) {
|
|
263
|
+
throw new OpenTasksBackendError(`Task is not assigned: ${id}`, "TASK_NOT_ASSIGNED", id);
|
|
264
|
+
}
|
|
265
|
+
this.eventStore.emit({
|
|
266
|
+
type: "task",
|
|
267
|
+
source: { agent_id: task.assigned_agent },
|
|
268
|
+
payload: {
|
|
269
|
+
task_id: id,
|
|
270
|
+
action: "unassigned",
|
|
271
|
+
details: { agent_id: task.assigned_agent },
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
// Clear assignee in OpenTasks
|
|
275
|
+
const issueId = this.taskToIssue.get(id);
|
|
276
|
+
if (issueId) {
|
|
277
|
+
await this.client.updateIssue(issueId, {
|
|
278
|
+
assignee: null,
|
|
279
|
+
metadata: { claimed_by: null },
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
async start(id) {
|
|
284
|
+
this.ensureOpen();
|
|
285
|
+
const task = this.eventStore.getTask(id);
|
|
286
|
+
if (!task) {
|
|
287
|
+
throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
|
|
288
|
+
}
|
|
289
|
+
const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
|
|
290
|
+
if (!validTransitions.includes("in_progress")) {
|
|
291
|
+
throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> in_progress`, "INVALID_STATUS_TRANSITION", id);
|
|
292
|
+
}
|
|
293
|
+
this.eventStore.emit({
|
|
294
|
+
type: "task",
|
|
295
|
+
source: { agent_id: task.assigned_agent ?? task.created_by },
|
|
296
|
+
payload: {
|
|
297
|
+
task_id: id,
|
|
298
|
+
action: "status_change",
|
|
299
|
+
details: { status: "in_progress" },
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
await this.syncStatusToOpenTasks(id, "in_progress");
|
|
303
|
+
}
|
|
304
|
+
async complete(id, outputs) {
|
|
305
|
+
this.ensureOpen();
|
|
306
|
+
const task = this.eventStore.getTask(id);
|
|
307
|
+
if (!task) {
|
|
308
|
+
throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
|
|
309
|
+
}
|
|
310
|
+
const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
|
|
311
|
+
if (!validTransitions.includes("completed")) {
|
|
312
|
+
throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> completed`, "INVALID_STATUS_TRANSITION", id);
|
|
313
|
+
}
|
|
314
|
+
const agent = task.assigned_agent ?? task.created_by;
|
|
315
|
+
// Store outputs
|
|
316
|
+
if (outputs) {
|
|
317
|
+
const outputsToStore = {
|
|
318
|
+
...(outputs.data ?? {}),
|
|
319
|
+
};
|
|
320
|
+
if (outputs.summary !== undefined) {
|
|
321
|
+
outputsToStore.summary = outputs.summary;
|
|
322
|
+
}
|
|
323
|
+
if (Object.keys(outputsToStore).length > 0) {
|
|
324
|
+
this.eventStore.emit({
|
|
325
|
+
type: "task",
|
|
326
|
+
source: { agent_id: agent },
|
|
327
|
+
payload: {
|
|
328
|
+
task_id: id,
|
|
329
|
+
action: "status_change",
|
|
330
|
+
details: { outputs: outputsToStore },
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
if (outputs.artifacts) {
|
|
335
|
+
this.eventStore.emit({
|
|
336
|
+
type: "task",
|
|
337
|
+
source: { agent_id: agent },
|
|
338
|
+
payload: {
|
|
339
|
+
task_id: id,
|
|
340
|
+
action: "status_change",
|
|
341
|
+
details: { artifacts: outputs.artifacts },
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
this.eventStore.emit({
|
|
347
|
+
type: "task",
|
|
348
|
+
source: { agent_id: agent },
|
|
349
|
+
payload: {
|
|
350
|
+
task_id: id,
|
|
351
|
+
action: "completed",
|
|
352
|
+
details: {},
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
// Close the issue in OpenTasks
|
|
356
|
+
await this.syncStatusToOpenTasks(id, "completed");
|
|
357
|
+
}
|
|
358
|
+
async fail(id, error) {
|
|
359
|
+
this.ensureOpen();
|
|
360
|
+
const task = this.eventStore.getTask(id);
|
|
361
|
+
if (!task) {
|
|
362
|
+
throw new OpenTasksBackendError(`Task not found: ${id}`, "TASK_NOT_FOUND", id);
|
|
363
|
+
}
|
|
364
|
+
const validTransitions = VALID_STATUS_TRANSITIONS[task.status];
|
|
365
|
+
if (!validTransitions.includes("failed")) {
|
|
366
|
+
throw new OpenTasksBackendError(`Invalid status transition: ${task.status} -> failed`, "INVALID_STATUS_TRANSITION", id);
|
|
367
|
+
}
|
|
368
|
+
const agent = task.assigned_agent ?? task.created_by;
|
|
369
|
+
// Store error in outputs
|
|
370
|
+
this.eventStore.emit({
|
|
371
|
+
type: "task",
|
|
372
|
+
source: { agent_id: agent },
|
|
373
|
+
payload: {
|
|
374
|
+
task_id: id,
|
|
375
|
+
action: "status_change",
|
|
376
|
+
details: {
|
|
377
|
+
outputs: {
|
|
378
|
+
error: {
|
|
379
|
+
message: error.message,
|
|
380
|
+
code: error.code,
|
|
381
|
+
details: error.details,
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
this.eventStore.emit({
|
|
388
|
+
type: "task",
|
|
389
|
+
source: { agent_id: agent },
|
|
390
|
+
payload: {
|
|
391
|
+
task_id: id,
|
|
392
|
+
action: "failed",
|
|
393
|
+
details: {},
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
// Close in OpenTasks with error metadata
|
|
397
|
+
const issueId = this.taskToIssue.get(id);
|
|
398
|
+
if (issueId) {
|
|
399
|
+
await this.client.updateIssue(issueId, {
|
|
400
|
+
status: "closed",
|
|
401
|
+
metadata: {
|
|
402
|
+
macro_agent_failed: true,
|
|
403
|
+
macro_agent_error: error.message,
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
409
|
+
// Queries
|
|
410
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
411
|
+
async list(filter) {
|
|
412
|
+
let tasks = this.eventStore.listTasks();
|
|
413
|
+
if (filter) {
|
|
414
|
+
if (filter.status) {
|
|
415
|
+
const statuses = Array.isArray(filter.status)
|
|
416
|
+
? filter.status
|
|
417
|
+
: [filter.status];
|
|
418
|
+
tasks = tasks.filter((t) => statuses.includes(t.status));
|
|
419
|
+
}
|
|
420
|
+
if (filter.assigned_agent) {
|
|
421
|
+
tasks = tasks.filter((t) => t.assigned_agent === filter.assigned_agent);
|
|
422
|
+
}
|
|
423
|
+
if (filter.parent_task) {
|
|
424
|
+
tasks = tasks.filter((t) => t.parent_task === filter.parent_task);
|
|
425
|
+
}
|
|
426
|
+
if (filter.created_by) {
|
|
427
|
+
tasks = tasks.filter((t) => t.created_by === filter.created_by);
|
|
428
|
+
}
|
|
429
|
+
if (filter.rootTasksOnly) {
|
|
430
|
+
tasks = tasks.filter((t) => !t.parent_task);
|
|
431
|
+
}
|
|
432
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
433
|
+
const filterTags = new Set(filter.tags);
|
|
434
|
+
tasks = tasks.filter((t) => t.tags?.some((tag) => filterTags.has(tag)));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
// Compute isBlocked using OpenTasks graph for mapped tasks,
|
|
438
|
+
// EventStore blockers for unmapped tasks
|
|
439
|
+
const extended = await Promise.all(tasks.map((t) => this.toExtendedTaskAsync(t)));
|
|
440
|
+
if (!filter?.includeBlocked) {
|
|
441
|
+
return extended.filter((t) => !t.isBlocked);
|
|
442
|
+
}
|
|
443
|
+
return extended;
|
|
444
|
+
}
|
|
445
|
+
async listReady(filter) {
|
|
446
|
+
return this.list({
|
|
447
|
+
...filter,
|
|
448
|
+
status: filter?.status ?? ["pending", "assigned"],
|
|
449
|
+
includeBlocked: false,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
async getChildren(parentId) {
|
|
453
|
+
const tasks = this.eventStore.listTasks();
|
|
454
|
+
const children = tasks.filter((t) => t.parent_task === parentId);
|
|
455
|
+
return Promise.all(children.map((t) => this.toExtendedTaskAsync(t)));
|
|
456
|
+
}
|
|
457
|
+
async getSubtaskStatus(parentId) {
|
|
458
|
+
const children = await this.getChildren(parentId);
|
|
459
|
+
const status = {
|
|
460
|
+
total: children.length,
|
|
461
|
+
pending: 0,
|
|
462
|
+
assigned: 0,
|
|
463
|
+
in_progress: 0,
|
|
464
|
+
completed: 0,
|
|
465
|
+
failed: 0,
|
|
466
|
+
allCompleted: false,
|
|
467
|
+
anyFailed: false,
|
|
468
|
+
};
|
|
469
|
+
for (const task of children) {
|
|
470
|
+
switch (task.status) {
|
|
471
|
+
case "pending":
|
|
472
|
+
status.pending++;
|
|
473
|
+
break;
|
|
474
|
+
case "assigned":
|
|
475
|
+
status.assigned++;
|
|
476
|
+
break;
|
|
477
|
+
case "in_progress":
|
|
478
|
+
status.in_progress++;
|
|
479
|
+
break;
|
|
480
|
+
case "completed":
|
|
481
|
+
status.completed++;
|
|
482
|
+
break;
|
|
483
|
+
case "failed":
|
|
484
|
+
status.failed++;
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
status.allCompleted =
|
|
489
|
+
status.total > 0 && status.completed === status.total;
|
|
490
|
+
status.anyFailed = status.failed > 0;
|
|
491
|
+
return status;
|
|
492
|
+
}
|
|
493
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
494
|
+
// Hierarchy
|
|
495
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
496
|
+
async createSubtask(parentId, options) {
|
|
497
|
+
return this.create({
|
|
498
|
+
...options,
|
|
499
|
+
parent_task: parentId,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
503
|
+
// Dependencies (via OpenTasks edges)
|
|
504
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
505
|
+
async addBlocker(taskId, blockerId) {
|
|
506
|
+
this.ensureOpen();
|
|
507
|
+
const task = this.eventStore.getTask(taskId);
|
|
508
|
+
if (!task) {
|
|
509
|
+
throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
|
|
510
|
+
}
|
|
511
|
+
const blocker = this.eventStore.getTask(blockerId);
|
|
512
|
+
if (!blocker) {
|
|
513
|
+
throw new OpenTasksBackendError(`Blocker task not found: ${blockerId}`, "TASK_NOT_FOUND", blockerId);
|
|
514
|
+
}
|
|
515
|
+
// Record in EventStore
|
|
516
|
+
this.eventStore.emit({
|
|
517
|
+
type: "task",
|
|
518
|
+
source: { agent_id: task.assigned_agent ?? task.created_by },
|
|
519
|
+
payload: {
|
|
520
|
+
task_id: taskId,
|
|
521
|
+
action: "blocker_added",
|
|
522
|
+
details: { blocker_id: blockerId },
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
// Create 'blocks' edge in OpenTasks if both tasks are mapped
|
|
526
|
+
const blockerIssueId = this.taskToIssue.get(blockerId);
|
|
527
|
+
const taskIssueId = this.taskToIssue.get(taskId);
|
|
528
|
+
if (blockerIssueId && taskIssueId) {
|
|
529
|
+
await this.client.createEdge(blockerIssueId, taskIssueId, "blocks");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
async removeBlocker(taskId, blockerId) {
|
|
533
|
+
this.ensureOpen();
|
|
534
|
+
const task = this.eventStore.getTask(taskId);
|
|
535
|
+
if (!task) {
|
|
536
|
+
throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
|
|
537
|
+
}
|
|
538
|
+
// Record in EventStore
|
|
539
|
+
this.eventStore.emit({
|
|
540
|
+
type: "task",
|
|
541
|
+
source: { agent_id: task.assigned_agent ?? task.created_by },
|
|
542
|
+
payload: {
|
|
543
|
+
task_id: taskId,
|
|
544
|
+
action: "blocker_removed",
|
|
545
|
+
details: { blocker_id: blockerId },
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
// Remove 'blocks' edge in OpenTasks if both are mapped
|
|
549
|
+
const blockerIssueId = this.taskToIssue.get(blockerId);
|
|
550
|
+
const taskIssueId = this.taskToIssue.get(taskId);
|
|
551
|
+
if (blockerIssueId && taskIssueId) {
|
|
552
|
+
await this.client.removeEdge(blockerIssueId, taskIssueId, "blocks");
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
async getBlockers(taskId) {
|
|
556
|
+
const task = this.eventStore.getTask(taskId);
|
|
557
|
+
if (!task) {
|
|
558
|
+
throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
|
|
559
|
+
}
|
|
560
|
+
// Try OpenTasks first for mapped tasks
|
|
561
|
+
const issueId = this.taskToIssue.get(taskId);
|
|
562
|
+
if (issueId) {
|
|
563
|
+
try {
|
|
564
|
+
const blockerSummaries = await this.client.getBlockers(issueId);
|
|
565
|
+
const blockers = [];
|
|
566
|
+
for (const summary of blockerSummaries) {
|
|
567
|
+
const blockerTaskId = this.issueToTask.get(summary.id);
|
|
568
|
+
if (blockerTaskId) {
|
|
569
|
+
const blockerTask = this.eventStore.getTask(blockerTaskId);
|
|
570
|
+
if (blockerTask) {
|
|
571
|
+
blockers.push(this.toExtendedTask(blockerTask));
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return blockers;
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
// Fall through to EventStore
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
// Fallback: use EventStore blockers
|
|
582
|
+
const blockerIds = task.blockers ?? [];
|
|
583
|
+
const blockers = [];
|
|
584
|
+
for (const blockerId of blockerIds) {
|
|
585
|
+
const blocker = this.eventStore.getTask(blockerId);
|
|
586
|
+
if (blocker) {
|
|
587
|
+
blockers.push(this.toExtendedTask(blocker));
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return blockers;
|
|
591
|
+
}
|
|
592
|
+
async getBlocking(taskId) {
|
|
593
|
+
const task = this.eventStore.getTask(taskId);
|
|
594
|
+
if (!task) {
|
|
595
|
+
throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
|
|
596
|
+
}
|
|
597
|
+
// Try OpenTasks first for mapped tasks
|
|
598
|
+
const issueId = this.taskToIssue.get(taskId);
|
|
599
|
+
if (issueId) {
|
|
600
|
+
try {
|
|
601
|
+
const blockingSummaries = await this.client.getBlocking(issueId);
|
|
602
|
+
const blocking = [];
|
|
603
|
+
for (const summary of blockingSummaries) {
|
|
604
|
+
const blockedTaskId = this.issueToTask.get(summary.id);
|
|
605
|
+
if (blockedTaskId) {
|
|
606
|
+
const blockedTask = this.eventStore.getTask(blockedTaskId);
|
|
607
|
+
if (blockedTask) {
|
|
608
|
+
blocking.push(this.toExtendedTask(blockedTask));
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return blocking;
|
|
613
|
+
}
|
|
614
|
+
catch {
|
|
615
|
+
// Fall through to EventStore
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
// Fallback: scan EventStore
|
|
619
|
+
const allTasks = this.eventStore.listTasks();
|
|
620
|
+
const blocking = allTasks.filter((t) => t.blockers?.includes(taskId));
|
|
621
|
+
return blocking.map((t) => this.toExtendedTask(t));
|
|
622
|
+
}
|
|
623
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
624
|
+
// Pull Model (Claim/Unclaim)
|
|
625
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
626
|
+
async claim(agentId, filter) {
|
|
627
|
+
this.ensureOpen();
|
|
628
|
+
const candidates = await this.listClaimable(filter);
|
|
629
|
+
if (candidates.length === 0) {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
const task = candidates[0];
|
|
633
|
+
// Re-check for contention
|
|
634
|
+
const current = this.eventStore.getTask(task.id);
|
|
635
|
+
if (!current || current.status !== "pending" || current.assigned_agent) {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
// Assign locally
|
|
639
|
+
this.eventStore.emit({
|
|
640
|
+
type: "task",
|
|
641
|
+
source: { agent_id: agentId },
|
|
642
|
+
payload: {
|
|
643
|
+
task_id: task.id,
|
|
644
|
+
action: "assigned",
|
|
645
|
+
details: { agent_id: agentId },
|
|
646
|
+
},
|
|
647
|
+
});
|
|
648
|
+
// Claim in OpenTasks
|
|
649
|
+
const issueId = this.taskToIssue.get(task.id);
|
|
650
|
+
if (issueId) {
|
|
651
|
+
await this.client.updateIssue(issueId, {
|
|
652
|
+
assignee: agentId,
|
|
653
|
+
metadata: { claimed_by: agentId },
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
const assigned = this.eventStore.getTask(task.id);
|
|
657
|
+
return this.toExtendedTask(assigned);
|
|
658
|
+
}
|
|
659
|
+
async unclaim(taskId) {
|
|
660
|
+
this.ensureOpen();
|
|
661
|
+
const task = this.eventStore.getTask(taskId);
|
|
662
|
+
if (!task) {
|
|
663
|
+
throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
|
|
664
|
+
}
|
|
665
|
+
if (!task.assigned_agent) {
|
|
666
|
+
throw new OpenTasksBackendError(`Task is not assigned: ${taskId}`, "TASK_NOT_ASSIGNED", taskId);
|
|
667
|
+
}
|
|
668
|
+
this.eventStore.emit({
|
|
669
|
+
type: "task",
|
|
670
|
+
source: { agent_id: task.assigned_agent },
|
|
671
|
+
payload: {
|
|
672
|
+
task_id: taskId,
|
|
673
|
+
action: "unassigned",
|
|
674
|
+
details: { agent_id: task.assigned_agent },
|
|
675
|
+
},
|
|
676
|
+
});
|
|
677
|
+
// Unclaim in OpenTasks
|
|
678
|
+
const issueId = this.taskToIssue.get(taskId);
|
|
679
|
+
if (issueId) {
|
|
680
|
+
await this.client.updateIssue(issueId, {
|
|
681
|
+
assignee: null,
|
|
682
|
+
metadata: { claimed_by: null },
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
async listClaimable(filter) {
|
|
687
|
+
let tasks = this.eventStore.listTasks();
|
|
688
|
+
// Only pending, unassigned tasks
|
|
689
|
+
tasks = tasks.filter((t) => t.status === "pending" && !t.assigned_agent);
|
|
690
|
+
if (filter) {
|
|
691
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
692
|
+
const filterTags = new Set(filter.tags);
|
|
693
|
+
tasks = tasks.filter((t) => t.tags?.some((tag) => filterTags.has(tag)));
|
|
694
|
+
}
|
|
695
|
+
if (filter.rootTasksOnly) {
|
|
696
|
+
tasks = tasks.filter((t) => !t.parent_task);
|
|
697
|
+
}
|
|
698
|
+
if (filter.created_by) {
|
|
699
|
+
tasks = tasks.filter((t) => t.created_by === filter.created_by);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
// Filter out blocked tasks
|
|
703
|
+
const extended = await Promise.all(tasks.map((t) => this.toExtendedTaskAsync(t)));
|
|
704
|
+
return extended.filter((t) => !t.isBlocked);
|
|
705
|
+
}
|
|
706
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
707
|
+
// History
|
|
708
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
709
|
+
async getAgentHistory(taskId) {
|
|
710
|
+
const task = this.eventStore.getTask(taskId);
|
|
711
|
+
if (!task) {
|
|
712
|
+
throw new OpenTasksBackendError(`Task not found: ${taskId}`, "TASK_NOT_FOUND", taskId);
|
|
713
|
+
}
|
|
714
|
+
return task.agent_history ?? [];
|
|
715
|
+
}
|
|
716
|
+
onTaskChange(callbackOrTaskId, maybeCallback) {
|
|
717
|
+
const filterTaskId = typeof callbackOrTaskId === "string" ? callbackOrTaskId : undefined;
|
|
718
|
+
const callback = typeof callbackOrTaskId === "function"
|
|
719
|
+
? callbackOrTaskId
|
|
720
|
+
: maybeCallback;
|
|
721
|
+
const seenTaskIds = new Set();
|
|
722
|
+
return this.eventStore.onTaskChange((taskId, task) => {
|
|
723
|
+
if (filterTaskId && taskId !== filterTaskId)
|
|
724
|
+
return;
|
|
725
|
+
let eventType;
|
|
726
|
+
if (!task) {
|
|
727
|
+
eventType = "deleted";
|
|
728
|
+
}
|
|
729
|
+
else if (seenTaskIds.has(taskId)) {
|
|
730
|
+
eventType = "updated";
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
eventType = "created";
|
|
734
|
+
seenTaskIds.add(taskId);
|
|
735
|
+
}
|
|
736
|
+
const event = {
|
|
737
|
+
type: eventType,
|
|
738
|
+
taskId,
|
|
739
|
+
task: task ? this.toExtendedTask(task) : {},
|
|
740
|
+
};
|
|
741
|
+
callback(event);
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
745
|
+
// Public Utility Methods
|
|
746
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
747
|
+
/**
|
|
748
|
+
* Get the OpenTasks issue ID for a macro-agent task.
|
|
749
|
+
* Returns undefined if the task is not mapped to an issue.
|
|
750
|
+
*/
|
|
751
|
+
getIssueForTask(taskId) {
|
|
752
|
+
return this.taskToIssue.get(taskId);
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Get the macro-agent task ID for an OpenTasks issue.
|
|
756
|
+
* Returns undefined if the issue is not mapped to a task.
|
|
757
|
+
*/
|
|
758
|
+
getTaskForIssue(issueId) {
|
|
759
|
+
return this.issueToTask.get(issueId);
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Import an existing OpenTasks issue as a macro-agent task.
|
|
763
|
+
* This is useful for pulling tasks from OpenTasks into macro-agent.
|
|
764
|
+
*/
|
|
765
|
+
async importIssue(issueId, createdBy) {
|
|
766
|
+
this.ensureOpen();
|
|
767
|
+
// Check if already imported
|
|
768
|
+
const existingTaskId = this.issueToTask.get(issueId);
|
|
769
|
+
if (existingTaskId) {
|
|
770
|
+
const existing = await this.get(existingTaskId);
|
|
771
|
+
if (existing)
|
|
772
|
+
return existing;
|
|
773
|
+
}
|
|
774
|
+
const issue = await this.client.getIssue(issueId);
|
|
775
|
+
if (!issue) {
|
|
776
|
+
throw new OpenTasksBackendError(`OpenTasks issue not found: ${issueId}`, "NOT_FOUND");
|
|
777
|
+
}
|
|
778
|
+
const taskId = `task_${nanoid(12)}`;
|
|
779
|
+
// Store mapping
|
|
780
|
+
this.taskToIssue.set(taskId, issueId);
|
|
781
|
+
this.issueToTask.set(issueId, taskId);
|
|
782
|
+
// Determine task status from issue
|
|
783
|
+
const taskStatus = mapOpenTasksStatus(issue.status);
|
|
784
|
+
// Create in EventStore
|
|
785
|
+
this.eventStore.emit({
|
|
786
|
+
type: "task",
|
|
787
|
+
source: { agent_id: createdBy },
|
|
788
|
+
payload: {
|
|
789
|
+
task_id: taskId,
|
|
790
|
+
action: "created",
|
|
791
|
+
details: {
|
|
792
|
+
description: issue.title,
|
|
793
|
+
tags: issue.tags,
|
|
794
|
+
external_id: issueId,
|
|
795
|
+
},
|
|
796
|
+
},
|
|
797
|
+
});
|
|
798
|
+
// If issue is not open/pending, transition to the right status
|
|
799
|
+
if (taskStatus === "in_progress") {
|
|
800
|
+
this.eventStore.emit({
|
|
801
|
+
type: "task",
|
|
802
|
+
source: { agent_id: createdBy },
|
|
803
|
+
payload: {
|
|
804
|
+
task_id: taskId,
|
|
805
|
+
action: "status_change",
|
|
806
|
+
details: { status: "in_progress" },
|
|
807
|
+
},
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
else if (taskStatus === "completed") {
|
|
811
|
+
this.eventStore.emit({
|
|
812
|
+
type: "task",
|
|
813
|
+
source: { agent_id: createdBy },
|
|
814
|
+
payload: {
|
|
815
|
+
task_id: taskId,
|
|
816
|
+
action: "completed",
|
|
817
|
+
details: {},
|
|
818
|
+
},
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
// If issue has an assignee, assign
|
|
822
|
+
if (issue.assignee) {
|
|
823
|
+
this.eventStore.emit({
|
|
824
|
+
type: "task",
|
|
825
|
+
source: { agent_id: issue.assignee },
|
|
826
|
+
payload: {
|
|
827
|
+
task_id: taskId,
|
|
828
|
+
action: "assigned",
|
|
829
|
+
details: { agent_id: issue.assignee },
|
|
830
|
+
},
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
return this.issueToExtendedTask(issue, taskId);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Bulk import all open issues from OpenTasks as tasks.
|
|
837
|
+
*/
|
|
838
|
+
async importOpenIssues(createdBy) {
|
|
839
|
+
this.ensureOpen();
|
|
840
|
+
const issues = await this.client.listIssues({
|
|
841
|
+
status: ["open", "in_progress"],
|
|
842
|
+
archived: false,
|
|
843
|
+
});
|
|
844
|
+
const tasks = [];
|
|
845
|
+
for (const issue of issues) {
|
|
846
|
+
// Skip already-imported issues
|
|
847
|
+
if (this.issueToTask.has(issue.id))
|
|
848
|
+
continue;
|
|
849
|
+
// Skip issues not created by macro-agent (unless they have no source)
|
|
850
|
+
// This allows importing issues from other sources too
|
|
851
|
+
const task = await this.importIssue(issue.id, createdBy);
|
|
852
|
+
tasks.push(task);
|
|
853
|
+
}
|
|
854
|
+
return tasks;
|
|
855
|
+
}
|
|
856
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
857
|
+
// Private Helpers
|
|
858
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
859
|
+
/**
|
|
860
|
+
* Sync a task status change to OpenTasks.
|
|
861
|
+
*/
|
|
862
|
+
async syncStatusToOpenTasks(taskId, status) {
|
|
863
|
+
if (!this.config.syncStatus)
|
|
864
|
+
return;
|
|
865
|
+
const issueId = this.taskToIssue.get(taskId);
|
|
866
|
+
if (!issueId)
|
|
867
|
+
return;
|
|
868
|
+
const openTasksStatus = mapTaskStatus(status);
|
|
869
|
+
try {
|
|
870
|
+
await this.client.updateIssue(issueId, {
|
|
871
|
+
status: openTasksStatus,
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
catch (error) {
|
|
875
|
+
// Log but don't fail - sync is best-effort
|
|
876
|
+
console.warn(`Failed to sync status to OpenTasks for ${taskId} (${issueId}): ${error}`);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Sync a transition that happened via the opentasks daemon's `task` tool.
|
|
881
|
+
* Updates the EventStore without re-syncing back to opentasks (since the
|
|
882
|
+
* daemon already processed the transition).
|
|
883
|
+
*
|
|
884
|
+
* Accepts either an opentasks issue ID (e.g., "i-xxxx") or an EventStore
|
|
885
|
+
* task ID (e.g., "task-xxx") — resolves to the EventStore ID either way.
|
|
886
|
+
*
|
|
887
|
+
* @param externalId - The opentasks issue ID or EventStore task ID
|
|
888
|
+
* @param action - The transition action ("complete", "start", "close", "block", "reopen", "assign")
|
|
889
|
+
* @param agentId - The agent that performed the transition or the assignee for "assign"
|
|
890
|
+
*/
|
|
891
|
+
async syncExternalTransition(externalId, action, agentId) {
|
|
892
|
+
// Resolve to EventStore task ID: try opentasks ID lookup first, then direct
|
|
893
|
+
const taskId = this.issueToTask.get(externalId)
|
|
894
|
+
?? (this.eventStore.getTask(externalId) ? externalId : undefined);
|
|
895
|
+
if (!taskId)
|
|
896
|
+
return;
|
|
897
|
+
const task = this.eventStore.getTask(taskId);
|
|
898
|
+
if (!task)
|
|
899
|
+
return;
|
|
900
|
+
const agent = agentId ?? task.assigned_agent ?? task.created_by;
|
|
901
|
+
// Handle assignment separately — it updates assignee, not status
|
|
902
|
+
if (action === "assign") {
|
|
903
|
+
if (task.assigned_agent !== agent) {
|
|
904
|
+
this.eventStore.emit({
|
|
905
|
+
type: "task",
|
|
906
|
+
source: { agent_id: agent },
|
|
907
|
+
payload: {
|
|
908
|
+
task_id: taskId,
|
|
909
|
+
action: "assigned",
|
|
910
|
+
details: { agent_id: agent },
|
|
911
|
+
},
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
// Map action to target status
|
|
917
|
+
const ACTION_TO_STATUS = {
|
|
918
|
+
complete: "completed",
|
|
919
|
+
close: "completed",
|
|
920
|
+
start: "in_progress",
|
|
921
|
+
block: "pending",
|
|
922
|
+
reopen: "pending",
|
|
923
|
+
};
|
|
924
|
+
const targetStatus = ACTION_TO_STATUS[action];
|
|
925
|
+
if (!targetStatus || task.status === targetStatus)
|
|
926
|
+
return;
|
|
927
|
+
// Emit the appropriate EventStore event
|
|
928
|
+
if (targetStatus === "completed") {
|
|
929
|
+
this.eventStore.emit({
|
|
930
|
+
type: "task",
|
|
931
|
+
source: { agent_id: agent },
|
|
932
|
+
payload: { task_id: taskId, action: "completed", details: {} },
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
else {
|
|
936
|
+
this.eventStore.emit({
|
|
937
|
+
type: "task",
|
|
938
|
+
source: { agent_id: agent },
|
|
939
|
+
payload: {
|
|
940
|
+
task_id: taskId,
|
|
941
|
+
action: "status_change",
|
|
942
|
+
details: { status: targetStatus },
|
|
943
|
+
},
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Convert an EventStore Task to ExtendedTask with isBlocked computed
|
|
949
|
+
* from local blockers.
|
|
950
|
+
*/
|
|
951
|
+
toExtendedTask(task) {
|
|
952
|
+
const blockerIds = task.blockers ?? [];
|
|
953
|
+
let isBlocked = false;
|
|
954
|
+
for (const blockerId of blockerIds) {
|
|
955
|
+
const blocker = this.eventStore.getTask(blockerId);
|
|
956
|
+
if (blocker && blocker.status !== "completed") {
|
|
957
|
+
isBlocked = true;
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return {
|
|
962
|
+
...task,
|
|
963
|
+
isBlocked,
|
|
964
|
+
external_id: this.taskToIssue.get(task.id),
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Convert an EventStore Task to ExtendedTask with isBlocked computed
|
|
969
|
+
* from OpenTasks graph (async, checks remote blockers).
|
|
970
|
+
*/
|
|
971
|
+
async toExtendedTaskAsync(task) {
|
|
972
|
+
const issueId = this.taskToIssue.get(task.id);
|
|
973
|
+
// If mapped to OpenTasks, use graph-based blocking
|
|
974
|
+
if (issueId) {
|
|
975
|
+
try {
|
|
976
|
+
const blockers = await this.client.getBlockers(issueId);
|
|
977
|
+
const hasActiveBlockers = blockers.some((b) => b.status && !isIssueComplete(b.status));
|
|
978
|
+
return {
|
|
979
|
+
...task,
|
|
980
|
+
isBlocked: hasActiveBlockers,
|
|
981
|
+
external_id: issueId,
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
catch {
|
|
985
|
+
// Fall through to local check
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return this.toExtendedTask(task);
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Convert an OpenTasks issue to an ExtendedTask.
|
|
992
|
+
*/
|
|
993
|
+
issueToExtendedTask(issue, taskId) {
|
|
994
|
+
const taskStatus = mapOpenTasksStatus(issue.status);
|
|
995
|
+
return {
|
|
996
|
+
id: taskId,
|
|
997
|
+
description: issue.title,
|
|
998
|
+
status: taskStatus,
|
|
999
|
+
assigned_agent: issue.assignee,
|
|
1000
|
+
parent_task: undefined, // Resolved separately if needed
|
|
1001
|
+
subtasks: undefined,
|
|
1002
|
+
blockers: undefined,
|
|
1003
|
+
created_at: new Date(issue.created_at).getTime(),
|
|
1004
|
+
started_at: taskStatus === "in_progress"
|
|
1005
|
+
? new Date(issue.updated_at).getTime()
|
|
1006
|
+
: undefined,
|
|
1007
|
+
completed_at: issue.closed_at
|
|
1008
|
+
? new Date(issue.closed_at).getTime()
|
|
1009
|
+
: undefined,
|
|
1010
|
+
created_by: issue.metadata?.created_by ?? "unknown",
|
|
1011
|
+
tags: issue.tags,
|
|
1012
|
+
isBlocked: issue.status === "blocked",
|
|
1013
|
+
external_id: issue.id,
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Create an OpenTasksTaskBackend instance.
|
|
1019
|
+
*/
|
|
1020
|
+
export function createOpenTasksTaskBackend(eventStore, client, config) {
|
|
1021
|
+
return new OpenTasksTaskBackend(eventStore, client, config);
|
|
1022
|
+
}
|
|
1023
|
+
//# sourceMappingURL=backend.js.map
|