macro-agent 0.1.1 → 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/.sudocode/issues.jsonl +28 -0
- package/.sudocode/specs.jsonl +4 -0
- package/CLAUDE.md +9 -3
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +111 -48
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +7 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/server.d.ts +5 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +100 -3
- 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/cli/acp.d.ts.map +1 -1
- package/dist/cli/acp.js +71 -1
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +5 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.js +27 -8
- package/dist/cli/mcp.js.map +1 -1
- package/dist/config/project-config.d.ts +13 -2
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +12 -2
- 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/extensions/index.d.ts +4 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +27 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- 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/index.d.ts +1 -1
- package/dist/map/adapter/index.d.ts.map +1 -1
- package/dist/map/adapter/index.js +3 -1
- package/dist/map/adapter/index.js.map +1 -1
- package/dist/map/adapter/types.d.ts +1 -1
- package/dist/map/adapter/types.d.ts.map +1 -1
- package/dist/mcp/mcp-server.d.ts +2 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +12 -3
- 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/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 +6 -0
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +10 -0
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/config-loader.d.ts +1 -1
- package/dist/roles/config-loader.d.ts.map +1 -1
- package/dist/roles/config-loader.js +3 -2
- package/dist/roles/config-loader.js.map +1 -1
- package/dist/roles/types.d.ts +3 -1
- package/dist/roles/types.d.ts.map +1 -1
- package/dist/server/combined-server.d.ts +8 -1
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +6 -2
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +12 -5
- 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 +5 -0
- package/dist/store/types/agents.d.ts.map +1 -1
- package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -1
- package/dist/task/backend/opentasks/daemon-manager.js +1 -1
- package/dist/task/backend/opentasks/daemon-manager.js.map +1 -1
- 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 +6 -2
- package/dist/teams/team-loader.d.ts.map +1 -1
- package/dist/teams/team-loader.js +154 -162
- 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 +527 -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/teams.md +73 -0
- package/package.json +2 -1
- 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/agent/agent-manager.ts +143 -72
- package/src/agent/types.ts +9 -0
- package/src/api/__tests__/server.test.ts +203 -4
- package/src/api/server.ts +130 -5
- package/src/api/types.ts +3 -1
- package/src/cli/acp.ts +68 -1
- package/src/cli/index.ts +5 -1
- package/src/cli/mcp.ts +27 -13
- package/src/config/project-config.ts +27 -3
- package/src/index.ts +3 -0
- 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__/stream-extensions.test.ts +494 -0
- package/src/map/adapter/extensions/index.ts +36 -0
- package/src/map/adapter/extensions/streams.ts +839 -0
- package/src/map/adapter/index.ts +5 -0
- package/src/map/adapter/types.ts +8 -1
- package/src/mcp/mcp-server.ts +14 -3
- package/src/mcp/tools/done.ts +19 -0
- 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 +11 -0
- package/src/roles/config-loader.ts +3 -2
- package/src/roles/types.ts +7 -0
- package/src/server/combined-server.ts +15 -1
- package/src/store/__tests__/event-store-oob.test.ts +109 -0
- package/src/store/event-store.ts +13 -3
- package/src/store/instance.ts +2 -2
- package/src/store/types/agents.ts +5 -0
- package/src/task/backend/__tests__/memory-pull-mode.test.ts +153 -0
- package/src/task/backend/opentasks/daemon-manager.ts +4 -1
- package/src/teams/CLAUDE.md +180 -0
- 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 +200 -234
- package/src/teams/team-manager.ts +387 -0
- package/src/teams/team-runtime.ts +590 -121
- package/src/teams/types.ts +99 -200
package/src/map/adapter/index.ts
CHANGED
|
@@ -155,4 +155,9 @@ export {
|
|
|
155
155
|
registerResumeExtension,
|
|
156
156
|
unregisterResumeExtension,
|
|
157
157
|
type ResumeExtensionServices,
|
|
158
|
+
// Stream/checkpoint/diffStack/mergeQueue
|
|
159
|
+
registerStreamExtensions,
|
|
160
|
+
unregisterStreamExtensions,
|
|
161
|
+
STREAM_EXTENSION_METHODS,
|
|
162
|
+
type StreamExtensionServices,
|
|
158
163
|
} from "./extensions/index.js";
|
package/src/map/adapter/types.ts
CHANGED
|
@@ -168,7 +168,14 @@ export type MAPEventType =
|
|
|
168
168
|
| "task.created"
|
|
169
169
|
| "task.assigned"
|
|
170
170
|
| "task.completed"
|
|
171
|
-
| "task.failed"
|
|
171
|
+
| "task.failed"
|
|
172
|
+
// Stream/checkpoint/merge events (git-cascade)
|
|
173
|
+
| "stream.updated"
|
|
174
|
+
| "checkpoint.created"
|
|
175
|
+
| "diffstack.created"
|
|
176
|
+
| "diffstack.updated"
|
|
177
|
+
| "merge_request.created"
|
|
178
|
+
| "merge_request.updated";
|
|
172
179
|
|
|
173
180
|
/**
|
|
174
181
|
* Filter for event subscriptions.
|
package/src/mcp/mcp-server.ts
CHANGED
|
@@ -103,6 +103,8 @@ export interface MCPServices {
|
|
|
103
103
|
integrationStrategy?: import("../workspace/strategies/types.js").IntegrationStrategy;
|
|
104
104
|
/** Optional task backend for pull model tools (claim/unclaim) */
|
|
105
105
|
taskBackend?: import("../task/backend/types.js").TaskBackend;
|
|
106
|
+
/** Optional workspace manager for workspace isolation */
|
|
107
|
+
workspaceManager?: import("../workspace/types.js").WorkspaceManager;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -1046,6 +1048,7 @@ export function createMCPServer(
|
|
|
1046
1048
|
roleRegistry,
|
|
1047
1049
|
integrationStrategy: services.integrationStrategy,
|
|
1048
1050
|
taskMode: services.taskMode,
|
|
1051
|
+
workspaceManager: services.workspaceManager,
|
|
1049
1052
|
});
|
|
1050
1053
|
|
|
1051
1054
|
try {
|
|
@@ -1056,6 +1059,14 @@ export function createMCPServer(
|
|
|
1056
1059
|
task_id?: string;
|
|
1057
1060
|
});
|
|
1058
1061
|
|
|
1062
|
+
// Persist events emitted by the done handler (MERGE_REQUEST, WORKER_DONE, etc.)
|
|
1063
|
+
// so the main process polling can see them via EventStore reload.
|
|
1064
|
+
try {
|
|
1065
|
+
await eventStore.persist();
|
|
1066
|
+
} catch {
|
|
1067
|
+
// Best-effort — events may still be picked up on next reload
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1059
1070
|
// If shouldTerminate is true, schedule termination after this tool returns
|
|
1060
1071
|
// The agent will be terminated after the tool execution completes
|
|
1061
1072
|
if (result.shouldTerminate) {
|
|
@@ -1091,7 +1102,7 @@ export function createMCPServer(
|
|
|
1091
1102
|
// Tools: claim_task, unclaim_task, list_claimable_tasks (pull model)
|
|
1092
1103
|
// ─────────────────────────────────────────────────────────────────
|
|
1093
1104
|
|
|
1094
|
-
if (services.taskBackend && shouldRegisterTool("claim_task")) {
|
|
1105
|
+
if (services.taskBackend && services.taskMode === "pull" && shouldRegisterTool("claim_task")) {
|
|
1095
1106
|
server.registerTool(CLAIM_TASK_TOOL_INFO.name, {
|
|
1096
1107
|
description: CLAIM_TASK_TOOL_INFO.description,
|
|
1097
1108
|
inputSchema: ClaimTaskSchema,
|
|
@@ -1104,7 +1115,7 @@ export function createMCPServer(
|
|
|
1104
1115
|
});
|
|
1105
1116
|
}
|
|
1106
1117
|
|
|
1107
|
-
if (services.taskBackend && shouldRegisterTool("unclaim_task")) {
|
|
1118
|
+
if (services.taskBackend && services.taskMode === "pull" && shouldRegisterTool("unclaim_task")) {
|
|
1108
1119
|
server.registerTool(UNCLAIM_TASK_TOOL_INFO.name, {
|
|
1109
1120
|
description: UNCLAIM_TASK_TOOL_INFO.description,
|
|
1110
1121
|
inputSchema: UnclaimTaskSchema,
|
|
@@ -1117,7 +1128,7 @@ export function createMCPServer(
|
|
|
1117
1128
|
});
|
|
1118
1129
|
}
|
|
1119
1130
|
|
|
1120
|
-
if (services.taskBackend && shouldRegisterTool("list_claimable_tasks")) {
|
|
1131
|
+
if (services.taskBackend && services.taskMode === "pull" && shouldRegisterTool("list_claimable_tasks")) {
|
|
1121
1132
|
server.registerTool(LIST_CLAIMABLE_TASKS_TOOL_INFO.name, {
|
|
1122
1133
|
description: LIST_CLAIMABLE_TASKS_TOOL_INFO.description,
|
|
1123
1134
|
inputSchema: ListClaimableTasksSchema,
|
package/src/mcp/tools/done.ts
CHANGED
|
@@ -147,6 +147,13 @@ export function buildLifecycleContext(
|
|
|
147
147
|
streamId = workspace?.streamId;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// Fallback: read streamId from env var (set by buildMacroAgentMcp during spawn).
|
|
151
|
+
// WorkspaceManager is not available in MCP subprocesses, but the streamId is
|
|
152
|
+
// needed for MERGE_REQUEST signal details so the team runtime can submit to the merge queue.
|
|
153
|
+
if (!streamId && process.env.MACRO_STREAM_ID) {
|
|
154
|
+
streamId = process.env.MACRO_STREAM_ID;
|
|
155
|
+
}
|
|
156
|
+
|
|
150
157
|
return {
|
|
151
158
|
agentId: toolContext.agent_id,
|
|
152
159
|
role,
|
|
@@ -206,6 +213,18 @@ export function createDoneHandler(context: ToolContext, deps: DoneToolDeps) {
|
|
|
206
213
|
workspaceManager
|
|
207
214
|
);
|
|
208
215
|
|
|
216
|
+
// Resolve capabilities for capability-based handler dispatch (team roles)
|
|
217
|
+
if (roleRegistry) {
|
|
218
|
+
try {
|
|
219
|
+
const resolvedRole = roleRegistry.resolveRole(role);
|
|
220
|
+
if (resolvedRole?.capabilities) {
|
|
221
|
+
lifecycleContext.capabilities = [...resolvedRole.capabilities];
|
|
222
|
+
}
|
|
223
|
+
} catch {
|
|
224
|
+
// Role not in registry — capabilities stay undefined
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
209
228
|
const cleanupStatus = detectCleanupStatus(lifecycleContext, {
|
|
210
229
|
messageRouter,
|
|
211
230
|
});
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
TASK_CAPABILITIES,
|
|
12
12
|
AGENT_CAPABILITIES,
|
|
13
13
|
MSG_CAPABILITIES,
|
|
14
|
+
WORKSPACE_CAPABILITIES,
|
|
14
15
|
} from "../capabilities.js";
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -42,6 +43,7 @@ export const CoordinatorRole: RoleDefinition = {
|
|
|
42
43
|
MSG_CAPABILITIES.SEND,
|
|
43
44
|
MSG_CAPABILITIES.BROADCAST,
|
|
44
45
|
MSG_CAPABILITIES.SUBSCRIBE,
|
|
46
|
+
WORKSPACE_CAPABILITIES.STREAM,
|
|
45
47
|
// Note: lifecycle.done is optional, configured per-coordinator
|
|
46
48
|
],
|
|
47
49
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
AGENT_CAPABILITIES,
|
|
13
13
|
LIFECYCLE_CAPABILITIES,
|
|
14
14
|
MSG_CAPABILITIES,
|
|
15
|
+
WORKSPACE_CAPABILITIES,
|
|
15
16
|
} from "../capabilities.js";
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -39,6 +40,7 @@ export const IntegratorRole: RoleDefinition = {
|
|
|
39
40
|
LIFECYCLE_CAPABILITIES.DONE,
|
|
40
41
|
MSG_CAPABILITIES.SEND,
|
|
41
42
|
MSG_CAPABILITIES.SUBSCRIBE,
|
|
43
|
+
WORKSPACE_CAPABILITIES.INTEGRATE,
|
|
42
44
|
],
|
|
43
45
|
|
|
44
46
|
workspace: {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
LIFECYCLE_CAPABILITIES,
|
|
14
14
|
AGENT_CAPABILITIES,
|
|
15
15
|
MSG_CAPABILITIES,
|
|
16
|
+
WORKSPACE_CAPABILITIES,
|
|
16
17
|
} from "../capabilities.js";
|
|
17
18
|
|
|
18
19
|
/** 30 minutes in milliseconds (stale timeout) */
|
|
@@ -45,6 +46,7 @@ export const WorkerRole: RoleDefinition = {
|
|
|
45
46
|
LIFECYCLE_CAPABILITIES.DONE,
|
|
46
47
|
AGENT_CAPABILITIES.SPAWN_WORKER,
|
|
47
48
|
MSG_CAPABILITIES.SEND,
|
|
49
|
+
WORKSPACE_CAPABILITIES.WORKTREE,
|
|
48
50
|
],
|
|
49
51
|
|
|
50
52
|
workspace: {
|
|
@@ -100,6 +102,7 @@ export const ResolverWorkerRole: RoleDefinition = {
|
|
|
100
102
|
LIFECYCLE_CAPABILITIES.DONE,
|
|
101
103
|
AGENT_CAPABILITIES.SPAWN_WORKER,
|
|
102
104
|
MSG_CAPABILITIES.SEND,
|
|
105
|
+
WORKSPACE_CAPABILITIES.WORKTREE,
|
|
103
106
|
],
|
|
104
107
|
|
|
105
108
|
// Inherits workspace from worker
|
|
@@ -66,6 +66,13 @@ export const MSG_CAPABILITIES = {
|
|
|
66
66
|
SUBSCRIBE: "msg.subscribe" as const,
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
+
/** Workspace capabilities */
|
|
70
|
+
export const WORKSPACE_CAPABILITIES = {
|
|
71
|
+
WORKTREE: "workspace.worktree" as const, // Gets own git worktree; done() submits to merge queue
|
|
72
|
+
STREAM: "workspace.stream" as const, // Creates integration stream at spawn
|
|
73
|
+
INTEGRATE: "workspace.integrate" as const, // Joins stream; processes merge queue entries
|
|
74
|
+
};
|
|
75
|
+
|
|
69
76
|
/** Wildcard capability */
|
|
70
77
|
export const WILDCARD_CAPABILITY = "*" as const;
|
|
71
78
|
|
|
@@ -112,6 +119,10 @@ export const ALL_CAPABILITIES: Set<Capability> = new Set([
|
|
|
112
119
|
MSG_CAPABILITIES.SEND,
|
|
113
120
|
MSG_CAPABILITIES.BROADCAST,
|
|
114
121
|
MSG_CAPABILITIES.SUBSCRIBE,
|
|
122
|
+
// Workspace
|
|
123
|
+
WORKSPACE_CAPABILITIES.WORKTREE,
|
|
124
|
+
WORKSPACE_CAPABILITIES.STREAM,
|
|
125
|
+
WORKSPACE_CAPABILITIES.INTEGRATE,
|
|
115
126
|
// Wildcard
|
|
116
127
|
WILDCARD_CAPABILITY,
|
|
117
128
|
]);
|
|
@@ -126,10 +126,11 @@ export function getProjectConfigPath(projectPath?: string): string {
|
|
|
126
126
|
/**
|
|
127
127
|
* Get the user-level config file path
|
|
128
128
|
*
|
|
129
|
-
* @returns Path to ~/.multiagent/roles.json
|
|
129
|
+
* @returns Path to ~/.multiagent/roles.json (or MACRO_AGENT_HOME/roles.json)
|
|
130
130
|
*/
|
|
131
131
|
export function getUserConfigPath(): string {
|
|
132
|
-
|
|
132
|
+
const globalDir = process.env.MACRO_AGENT_HOME || path.join(os.homedir(), USER_CONFIG_DIR);
|
|
133
|
+
return path.join(globalDir, CONFIG_FILE_NAME);
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
// =============================================================================
|
package/src/roles/types.ts
CHANGED
|
@@ -54,6 +54,12 @@ export type ExecCapability =
|
|
|
54
54
|
/** Communication capabilities */
|
|
55
55
|
export type MsgCapability = "msg.send" | "msg.broadcast" | "msg.subscribe";
|
|
56
56
|
|
|
57
|
+
/** Workspace capabilities */
|
|
58
|
+
export type WorkspaceCapability =
|
|
59
|
+
| "workspace.worktree"
|
|
60
|
+
| "workspace.stream"
|
|
61
|
+
| "workspace.integrate";
|
|
62
|
+
|
|
57
63
|
/** All capability types combined, plus wildcard */
|
|
58
64
|
export type Capability =
|
|
59
65
|
| FileCapability
|
|
@@ -63,6 +69,7 @@ export type Capability =
|
|
|
63
69
|
| TaskCapability
|
|
64
70
|
| ExecCapability
|
|
65
71
|
| MsgCapability
|
|
72
|
+
| WorkspaceCapability
|
|
66
73
|
| "*"; // Wildcard for all capabilities
|
|
67
74
|
|
|
68
75
|
// =============================================================================
|
|
@@ -31,9 +31,11 @@ import {
|
|
|
31
31
|
registerTaskExtensions,
|
|
32
32
|
registerResumeExtension,
|
|
33
33
|
registerAgentLifecycleExtensions,
|
|
34
|
+
registerStreamExtensions,
|
|
34
35
|
type MAPAdapter,
|
|
35
36
|
type MAPAdapterServices,
|
|
36
37
|
type MAPWebSocketHandler,
|
|
38
|
+
type StreamExtensionServices,
|
|
37
39
|
} from "../map/adapter/index.js";
|
|
38
40
|
import type { Agent, AgentId } from "../store/types/index.js";
|
|
39
41
|
import type { Address, SendOptions } from "../map/types.js";
|
|
@@ -49,6 +51,7 @@ import {
|
|
|
49
51
|
secureCompare,
|
|
50
52
|
} from "../auth/token.js";
|
|
51
53
|
import { TaskBackend, TaskToolProvider } from "../task/backend/types.js";
|
|
54
|
+
import type { TeamManager } from "../teams/team-manager.js";
|
|
52
55
|
|
|
53
56
|
// ─────────────────────────────────────────────────────────────────
|
|
54
57
|
// Types
|
|
@@ -73,6 +76,12 @@ export interface CombinedServerServices {
|
|
|
73
76
|
agentTokenManager?: AgentTokenManager;
|
|
74
77
|
/** Get connected opentasks project paths (for health endpoint) */
|
|
75
78
|
getConnectedProjects?: () => string[];
|
|
79
|
+
/** Optional stream extension services for git-cascade stream/checkpoint/merge-queue features */
|
|
80
|
+
streamExtensions?: StreamExtensionServices;
|
|
81
|
+
/** Optional team manager for dynamic team management */
|
|
82
|
+
teamManager?: TeamManager;
|
|
83
|
+
/** Optional workspace manager for workspace isolation and merge queue */
|
|
84
|
+
workspaceManager?: import("../workspace/types.js").WorkspaceManager;
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
export interface CombinedServerConfig {
|
|
@@ -258,7 +267,7 @@ export function createCombinedServer(
|
|
|
258
267
|
// Create Express app with API routes (include mail services)
|
|
259
268
|
const app = createAPIApp(
|
|
260
269
|
{ ...services, mailService, conversationMap },
|
|
261
|
-
{ cors, serverToken: resolvedServerToken },
|
|
270
|
+
{ cors, serverToken: resolvedServerToken, defaultCwd },
|
|
262
271
|
);
|
|
263
272
|
|
|
264
273
|
// Create HTTP server with Express
|
|
@@ -369,6 +378,11 @@ export function createCombinedServer(
|
|
|
369
378
|
agentTokenManager: services.agentTokenManager,
|
|
370
379
|
});
|
|
371
380
|
|
|
381
|
+
// Register stream/checkpoint/diffStack/mergeQueue extensions
|
|
382
|
+
if (services.streamExtensions) {
|
|
383
|
+
registerStreamExtensions(mapAdapter, services.streamExtensions);
|
|
384
|
+
}
|
|
385
|
+
|
|
372
386
|
mapHandler = createMAPWebSocketHandler(mapAdapter);
|
|
373
387
|
}
|
|
374
388
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventStore Out-of-Band Field Preservation Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests that fields written via updateAgentMetadata() (out-of-band,
|
|
5
|
+
* not through events) survive the rebuildViews() cycle that occurs
|
|
6
|
+
* on every auto-load (every 1 second) and on reload().
|
|
7
|
+
*
|
|
8
|
+
* The preservation relies on OUT_OF_BAND_FIELDS in rebuildViews()
|
|
9
|
+
* which saves these values before clearing views, replays all events,
|
|
10
|
+
* then restores the saved values.
|
|
11
|
+
*
|
|
12
|
+
* @module store/__tests__/event-store-oob
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
16
|
+
import { createEventStore, type EventStore } from "../event-store.js";
|
|
17
|
+
import type { AgentId } from "../types/index.js";
|
|
18
|
+
|
|
19
|
+
describe("EventStore — Out-of-Band Field Preservation", () => {
|
|
20
|
+
let eventStore: EventStore;
|
|
21
|
+
|
|
22
|
+
const AGENT_ID = "oob-test-001" as AgentId;
|
|
23
|
+
|
|
24
|
+
beforeEach(async () => {
|
|
25
|
+
eventStore = await createEventStore({ instanceId: `oob-test-${Date.now()}` });
|
|
26
|
+
|
|
27
|
+
// Create an agent via spawn event
|
|
28
|
+
eventStore.emit({
|
|
29
|
+
type: "spawn",
|
|
30
|
+
source: { agent_id: AGENT_ID },
|
|
31
|
+
payload: {
|
|
32
|
+
agent_id: AGENT_ID,
|
|
33
|
+
task: "Test task",
|
|
34
|
+
role: "worker",
|
|
35
|
+
cwd: "/original/path",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
await eventStore.persist();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(async () => {
|
|
42
|
+
try { await eventStore.close(); } catch { /* ignore */ }
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("cwd survives rebuildViews after updateAgentMetadata", async () => {
|
|
46
|
+
// Verify initial cwd from spawn event
|
|
47
|
+
expect(eventStore.getAgent(AGENT_ID)?.cwd).toBe("/original/path");
|
|
48
|
+
|
|
49
|
+
// Update cwd out-of-band
|
|
50
|
+
eventStore.updateAgentMetadata(AGENT_ID, { cwd: "/workspace/worktree-001" });
|
|
51
|
+
expect(eventStore.getAgent(AGENT_ID)?.cwd).toBe("/workspace/worktree-001");
|
|
52
|
+
|
|
53
|
+
// Persist and reload (triggers rebuildViews)
|
|
54
|
+
await eventStore.persist();
|
|
55
|
+
await eventStore.reload();
|
|
56
|
+
|
|
57
|
+
// cwd should survive the rebuild
|
|
58
|
+
const agent = eventStore.getAgent(AGENT_ID);
|
|
59
|
+
expect(agent).not.toBeNull();
|
|
60
|
+
expect(agent!.cwd).toBe("/workspace/worktree-001");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("team_instance survives rebuildViews", async () => {
|
|
64
|
+
// Set team_instance out-of-band
|
|
65
|
+
eventStore.updateAgentMetadata(AGENT_ID, { team_instance: "team-alpha-001" });
|
|
66
|
+
expect(eventStore.getAgent(AGENT_ID)?.team_instance).toBe("team-alpha-001");
|
|
67
|
+
|
|
68
|
+
// Persist and reload
|
|
69
|
+
await eventStore.persist();
|
|
70
|
+
await eventStore.reload();
|
|
71
|
+
|
|
72
|
+
// team_instance should survive
|
|
73
|
+
expect(eventStore.getAgent(AGENT_ID)?.team_instance).toBe("team-alpha-001");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("all OUT_OF_BAND_FIELDS preserved together", async () => {
|
|
77
|
+
// Set all out-of-band fields simultaneously
|
|
78
|
+
eventStore.updateAgentMetadata(AGENT_ID, {
|
|
79
|
+
name: "Developer Alpha",
|
|
80
|
+
plan: [{ content: "Step 1: do the thing", priority: "high", status: "pending" }],
|
|
81
|
+
metadata: { custom_key: "custom_value" },
|
|
82
|
+
cwd: "/workspace/worktree-002",
|
|
83
|
+
team_instance: "team-beta-002",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Verify all set correctly
|
|
87
|
+
const before = eventStore.getAgent(AGENT_ID)!;
|
|
88
|
+
expect(before.name).toBe("Developer Alpha");
|
|
89
|
+
expect(before.cwd).toBe("/workspace/worktree-002");
|
|
90
|
+
expect(before.team_instance).toBe("team-beta-002");
|
|
91
|
+
|
|
92
|
+
// Persist and reload (triggers rebuildViews)
|
|
93
|
+
await eventStore.persist();
|
|
94
|
+
await eventStore.reload();
|
|
95
|
+
|
|
96
|
+
// All fields should survive
|
|
97
|
+
const after = eventStore.getAgent(AGENT_ID)!;
|
|
98
|
+
expect(after.name).toBe("Developer Alpha");
|
|
99
|
+
expect(after.cwd).toBe("/workspace/worktree-002");
|
|
100
|
+
expect(after.team_instance).toBe("team-beta-002");
|
|
101
|
+
|
|
102
|
+
// plan and metadata may be stored as JSON strings or objects depending on TinyBase internals
|
|
103
|
+
const plan = typeof after.plan === "string" ? JSON.parse(after.plan) : after.plan;
|
|
104
|
+
expect(plan).toEqual([{ content: "Step 1: do the thing", priority: "high", status: "pending" }]);
|
|
105
|
+
|
|
106
|
+
const metadata = typeof after.metadata === "string" ? JSON.parse(after.metadata) : after.metadata;
|
|
107
|
+
expect(metadata).toEqual({ custom_key: "custom_value" });
|
|
108
|
+
});
|
|
109
|
+
});
|
package/src/store/event-store.ts
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
readInstanceMeta,
|
|
59
59
|
touchInstance,
|
|
60
60
|
registerInstance,
|
|
61
|
+
DEFAULT_BASE_DIR,
|
|
61
62
|
DEFAULT_NAMESPACE,
|
|
62
63
|
DEFAULT_PEER_VISIBILITY,
|
|
63
64
|
filterEventsForPeer,
|
|
@@ -308,7 +309,7 @@ export async function createEventStore(config: StoreConfig = {}): Promise<EventS
|
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
// Track baseDir for MCP subprocess communication
|
|
311
|
-
const baseDir = config.baseDir ??
|
|
312
|
+
const baseDir = config.baseDir ?? DEFAULT_BASE_DIR;
|
|
312
313
|
|
|
313
314
|
// Get peer visibility config (default is restrictive)
|
|
314
315
|
const peerVisibility: PeerVisibilityConfig =
|
|
@@ -382,7 +383,7 @@ export async function createEventStore(config: StoreConfig = {}): Promise<EventS
|
|
|
382
383
|
|
|
383
384
|
// Register in namespace for discovery
|
|
384
385
|
registerInstance(
|
|
385
|
-
config.baseDir ??
|
|
386
|
+
config.baseDir ?? DEFAULT_BASE_DIR,
|
|
386
387
|
namespace,
|
|
387
388
|
instanceId,
|
|
388
389
|
{ label: config.label }
|
|
@@ -548,6 +549,12 @@ export async function createEventStore(config: StoreConfig = {}): Promise<EventS
|
|
|
548
549
|
const existing = row.metadata ? JSON.parse(row.metadata as string) : {};
|
|
549
550
|
partial.metadata = JSON.stringify({ ...existing, ...updates.metadata });
|
|
550
551
|
}
|
|
552
|
+
if (updates.team_instance !== undefined) {
|
|
553
|
+
partial.team_instance = updates.team_instance;
|
|
554
|
+
}
|
|
555
|
+
if (updates.cwd !== undefined) {
|
|
556
|
+
partial.cwd = updates.cwd;
|
|
557
|
+
}
|
|
551
558
|
|
|
552
559
|
store.setPartialRow('agents', agentId, partial);
|
|
553
560
|
|
|
@@ -1332,7 +1339,7 @@ function rebuildViews(store: Store): void {
|
|
|
1332
1339
|
// Preserve out-of-band agent fields that aren't derived from events.
|
|
1333
1340
|
// These fields are written directly (not through events),
|
|
1334
1341
|
// so they would be lost when we clear and replay.
|
|
1335
|
-
const OUT_OF_BAND_FIELDS = ['plan', 'name', 'metadata'] as const;
|
|
1342
|
+
const OUT_OF_BAND_FIELDS = ['plan', 'name', 'metadata', 'cwd', 'team_instance'] as const;
|
|
1336
1343
|
const savedOutOfBand = new Map<string, Record<string, string>>();
|
|
1337
1344
|
for (const rowId of store.getRowIds('agents')) {
|
|
1338
1345
|
const row = store.getRow('agents', rowId);
|
|
@@ -1478,6 +1485,7 @@ function applySpawnEvent(
|
|
|
1478
1485
|
task_id?: TaskId;
|
|
1479
1486
|
parent?: AgentId | null;
|
|
1480
1487
|
role?: string;
|
|
1488
|
+
team_instance?: string;
|
|
1481
1489
|
config?: Record<string, unknown>;
|
|
1482
1490
|
cwd?: string;
|
|
1483
1491
|
};
|
|
@@ -1508,6 +1516,7 @@ function applySpawnEvent(
|
|
|
1508
1516
|
task: payload.task,
|
|
1509
1517
|
task_id: payload.task_id ?? '',
|
|
1510
1518
|
role: payload.role ?? '',
|
|
1519
|
+
team_instance: payload.team_instance ?? '',
|
|
1511
1520
|
config: JSON.stringify(payload.config ?? {}),
|
|
1512
1521
|
cwd: payload.cwd ?? process.cwd(),
|
|
1513
1522
|
plan: '[]',
|
|
@@ -1866,6 +1875,7 @@ function rowToAgent(row: Record<string, unknown>): Agent {
|
|
|
1866
1875
|
task: row.task as string,
|
|
1867
1876
|
task_id: (row.task_id as string) || undefined,
|
|
1868
1877
|
role: (row.role as string) || undefined,
|
|
1878
|
+
team_instance: (row.team_instance as string) || undefined,
|
|
1869
1879
|
config: row.config ? JSON.parse(row.config as string) : {},
|
|
1870
1880
|
cwd: (row.cwd as string) || process.cwd(),
|
|
1871
1881
|
plan: row.plan ? JSON.parse(row.plan as string) : [],
|
package/src/store/instance.ts
CHANGED
|
@@ -221,8 +221,8 @@ export interface ResolvedInstance {
|
|
|
221
221
|
// Constants
|
|
222
222
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
223
223
|
|
|
224
|
-
/** Default base directory */
|
|
225
|
-
export const DEFAULT_BASE_DIR = path.join(os.homedir(), '.multiagent');
|
|
224
|
+
/** Default base directory (override with MACRO_AGENT_HOME env var) */
|
|
225
|
+
export const DEFAULT_BASE_DIR = process.env.MACRO_AGENT_HOME || path.join(os.homedir(), '.multiagent');
|
|
226
226
|
|
|
227
227
|
/** Default namespace */
|
|
228
228
|
export const DEFAULT_NAMESPACE = 'default';
|
|
@@ -40,6 +40,8 @@ export interface Agent {
|
|
|
40
40
|
task: string;
|
|
41
41
|
task_id?: TaskId;
|
|
42
42
|
role?: string;
|
|
43
|
+
/** Team instance ID this agent belongs to (set by TeamManager) */
|
|
44
|
+
team_instance?: string;
|
|
43
45
|
config: AgentConfig;
|
|
44
46
|
cwd: string;
|
|
45
47
|
plan: Array<{ content: string; priority: string; status: string }>;
|
|
@@ -61,4 +63,7 @@ export interface AgentMetadataUpdate {
|
|
|
61
63
|
name?: string;
|
|
62
64
|
plan?: Array<{ content: string; priority: string; status: string }>;
|
|
63
65
|
metadata?: Record<string, unknown>;
|
|
66
|
+
team_instance?: string;
|
|
67
|
+
/** Override the agent's working directory (e.g., to workspace worktree path) */
|
|
68
|
+
cwd?: string;
|
|
64
69
|
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pull-Mode Task Backend Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the claim/unclaim/listClaimable methods of InMemoryTaskBackend
|
|
5
|
+
* which enable the pull model where workers claim tasks from a pool.
|
|
6
|
+
*
|
|
7
|
+
* @module task/backend/__tests__/memory-pull-mode
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
11
|
+
import { createEventStore, type EventStore } from "../../../store/event-store.js";
|
|
12
|
+
import { InMemoryTaskBackend } from "../memory.js";
|
|
13
|
+
import type { AgentId, TaskId } from "../../../store/types/index.js";
|
|
14
|
+
|
|
15
|
+
describe("InMemoryTaskBackend — Pull Mode", () => {
|
|
16
|
+
let eventStore: EventStore;
|
|
17
|
+
let backend: InMemoryTaskBackend;
|
|
18
|
+
|
|
19
|
+
const AGENT_A = "agent-a" as AgentId;
|
|
20
|
+
const AGENT_B = "agent-b" as AgentId;
|
|
21
|
+
const CREATOR = "creator-001" as AgentId;
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
eventStore = await createEventStore({ instanceId: `pull-test-${Date.now()}` });
|
|
25
|
+
backend = new InMemoryTaskBackend(eventStore);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────
|
|
29
|
+
// claim()
|
|
30
|
+
// ─────────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
it("claim returns first pending unblocked task", async () => {
|
|
33
|
+
const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
|
|
34
|
+
const t2 = await backend.create({ description: "Task 2", created_by: CREATOR });
|
|
35
|
+
const t3 = await backend.create({ description: "Task 3", created_by: CREATOR });
|
|
36
|
+
|
|
37
|
+
const claimed = await backend.claim!(AGENT_A);
|
|
38
|
+
expect(claimed).not.toBeNull();
|
|
39
|
+
expect(claimed!.id).toBe(t1.id);
|
|
40
|
+
expect(claimed!.assigned_agent).toBe(AGENT_A);
|
|
41
|
+
|
|
42
|
+
// Second claim should return t2
|
|
43
|
+
const claimed2 = await backend.claim!(AGENT_B);
|
|
44
|
+
expect(claimed2).not.toBeNull();
|
|
45
|
+
expect(claimed2!.id).toBe(t2.id);
|
|
46
|
+
expect(claimed2!.assigned_agent).toBe(AGENT_B);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("claim skips assigned tasks", async () => {
|
|
50
|
+
const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
|
|
51
|
+
const t2 = await backend.create({ description: "Task 2", created_by: CREATOR });
|
|
52
|
+
|
|
53
|
+
// Assign t1 directly
|
|
54
|
+
await backend.assign(t1.id, { agent_id: AGENT_A });
|
|
55
|
+
|
|
56
|
+
// claim should skip t1 and return t2
|
|
57
|
+
const claimed = await backend.claim!(AGENT_B);
|
|
58
|
+
expect(claimed).not.toBeNull();
|
|
59
|
+
expect(claimed!.id).toBe(t2.id);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("claim skips blocked tasks", async () => {
|
|
63
|
+
const blocker = await backend.create({ description: "Blocker task", created_by: CREATOR });
|
|
64
|
+
const blocked = await backend.create({ description: "Blocked task", created_by: CREATOR });
|
|
65
|
+
const available = await backend.create({ description: "Available task", created_by: CREATOR });
|
|
66
|
+
|
|
67
|
+
// Add blocker dependency
|
|
68
|
+
await backend.addBlocker(blocked.id, blocker.id);
|
|
69
|
+
|
|
70
|
+
// claim should skip blocked and return available
|
|
71
|
+
const claimed = await backend.claim!(AGENT_A);
|
|
72
|
+
expect(claimed).not.toBeNull();
|
|
73
|
+
// Should return either blocker or available (blocker is pending+unblocked, so it comes first)
|
|
74
|
+
// blocker is pending + not assigned + not blocked → claimable
|
|
75
|
+
// blocked is pending + not assigned but IS blocked → not claimable
|
|
76
|
+
// available is pending + not assigned + not blocked → claimable
|
|
77
|
+
expect([blocker.id, available.id]).toContain(claimed!.id);
|
|
78
|
+
expect(claimed!.id).not.toBe(blocked.id);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("claim returns null when no claimable tasks", async () => {
|
|
82
|
+
// Create a task and assign it
|
|
83
|
+
const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
|
|
84
|
+
await backend.assign(t1.id, { agent_id: AGENT_A });
|
|
85
|
+
|
|
86
|
+
// No unassigned pending tasks left
|
|
87
|
+
const claimed = await backend.claim!(AGENT_B);
|
|
88
|
+
expect(claimed).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ─────────────────────────────────────────────────────────────────
|
|
92
|
+
// unclaim()
|
|
93
|
+
// ─────────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
it("unclaim returns task to pending pool", async () => {
|
|
96
|
+
const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
|
|
97
|
+
|
|
98
|
+
// Claim it
|
|
99
|
+
const claimed = await backend.claim!(AGENT_A);
|
|
100
|
+
expect(claimed!.id).toBe(t1.id);
|
|
101
|
+
expect(claimed!.assigned_agent).toBe(AGENT_A);
|
|
102
|
+
|
|
103
|
+
// Unclaim it
|
|
104
|
+
await backend.unclaim!(t1.id);
|
|
105
|
+
|
|
106
|
+
// Task should be claimable again
|
|
107
|
+
const reClaimed = await backend.claim!(AGENT_B);
|
|
108
|
+
expect(reClaimed).not.toBeNull();
|
|
109
|
+
expect(reClaimed!.id).toBe(t1.id);
|
|
110
|
+
expect(reClaimed!.assigned_agent).toBe(AGENT_B);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("unclaim throws on unassigned task", async () => {
|
|
114
|
+
const t1 = await backend.create({ description: "Task 1", created_by: CREATOR });
|
|
115
|
+
|
|
116
|
+
await expect(backend.unclaim!(t1.id)).rejects.toThrow("not assigned");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ─────────────────────────────────────────────────────────────────
|
|
120
|
+
// listClaimable()
|
|
121
|
+
// ─────────────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
it("listClaimable filters by tags", async () => {
|
|
124
|
+
await backend.create({
|
|
125
|
+
description: "Frontend task",
|
|
126
|
+
created_by: CREATOR,
|
|
127
|
+
tags: ["frontend", "ui"],
|
|
128
|
+
});
|
|
129
|
+
await backend.create({
|
|
130
|
+
description: "Backend task",
|
|
131
|
+
created_by: CREATOR,
|
|
132
|
+
tags: ["backend", "api"],
|
|
133
|
+
});
|
|
134
|
+
await backend.create({
|
|
135
|
+
description: "Untagged task",
|
|
136
|
+
created_by: CREATOR,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Filter by "backend" tag
|
|
140
|
+
const claimable = await backend.listClaimable!({ tags: ["backend"] });
|
|
141
|
+
expect(claimable.length).toBe(1);
|
|
142
|
+
expect(claimable[0].description).toBe("Backend task");
|
|
143
|
+
|
|
144
|
+
// Filter by "frontend" tag
|
|
145
|
+
const frontendTasks = await backend.listClaimable!({ tags: ["frontend"] });
|
|
146
|
+
expect(frontendTasks.length).toBe(1);
|
|
147
|
+
expect(frontendTasks[0].description).toBe("Frontend task");
|
|
148
|
+
|
|
149
|
+
// No filter returns all claimable
|
|
150
|
+
const allClaimable = await backend.listClaimable!();
|
|
151
|
+
expect(allClaimable.length).toBe(3);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -54,7 +54,10 @@ export interface DaemonManagerResult {
|
|
|
54
54
|
// Constants
|
|
55
55
|
// =============================================================================
|
|
56
56
|
|
|
57
|
-
const DEFAULT_CENTRAL_PATH = path.join(
|
|
57
|
+
const DEFAULT_CENTRAL_PATH = path.join(
|
|
58
|
+
process.env.MACRO_AGENT_HOME || path.join(os.homedir(), ".multiagent"),
|
|
59
|
+
"opentasks",
|
|
60
|
+
);
|
|
58
61
|
|
|
59
62
|
/** Grace period (ms) between client disconnect and daemon.stop() to let children finish disconnecting */
|
|
60
63
|
const DAEMON_DRAIN_MS = 500;
|