macro-agent 0.0.10 → 0.0.12
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/.macro-agent/teams/self-driving/prompts/grinder.md +27 -0
- package/.macro-agent/teams/self-driving/prompts/judge.md +27 -0
- package/.macro-agent/teams/self-driving/prompts/planner.md +33 -0
- package/.macro-agent/teams/self-driving/roles/grinder.yaml +17 -0
- package/.macro-agent/teams/self-driving/roles/judge.yaml +24 -0
- package/.macro-agent/teams/self-driving/roles/planner.yaml +18 -0
- package/.macro-agent/teams/self-driving/team.yaml +103 -0
- package/.macro-agent/teams/structured/prompts/developer.md +26 -0
- package/.macro-agent/teams/structured/prompts/lead.md +25 -0
- package/.macro-agent/teams/structured/prompts/reviewer.md +24 -0
- package/.macro-agent/teams/structured/roles/developer.yaml +12 -0
- package/.macro-agent/teams/structured/roles/lead.yaml +11 -0
- package/.macro-agent/teams/structured/roles/reviewer.yaml +19 -0
- package/.macro-agent/teams/structured/team.yaml +89 -0
- package/.sudocode/issues.jsonl +56 -51
- package/.sudocode/specs.jsonl +8 -1
- package/CLAUDE.md +121 -30
- package/README.md +60 -3
- package/dist/acp/macro-agent.d.ts +4 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +50 -4
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/session-mapper.d.ts +20 -1
- package/dist/acp/session-mapper.d.ts.map +1 -1
- package/dist/acp/session-mapper.js +90 -1
- package/dist/acp/session-mapper.js.map +1 -1
- package/dist/acp/types.d.ts +24 -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 +40 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +172 -8
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +22 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/agent/wake.d.ts +15 -0
- package/dist/agent/wake.d.ts.map +1 -1
- package/dist/agent/wake.js +15 -0
- package/dist/agent/wake.js.map +1 -1
- package/dist/agent-detection/command-builder.d.ts +30 -0
- package/dist/agent-detection/command-builder.d.ts.map +1 -0
- package/dist/agent-detection/command-builder.js +71 -0
- package/dist/agent-detection/command-builder.js.map +1 -0
- package/dist/agent-detection/detector.d.ts +84 -0
- package/dist/agent-detection/detector.d.ts.map +1 -0
- package/dist/agent-detection/detector.js +240 -0
- package/dist/agent-detection/detector.js.map +1 -0
- package/dist/agent-detection/index.d.ts +12 -0
- package/dist/agent-detection/index.d.ts.map +1 -0
- package/dist/agent-detection/index.js +14 -0
- package/dist/agent-detection/index.js.map +1 -0
- package/dist/agent-detection/registry.d.ts +53 -0
- package/dist/agent-detection/registry.d.ts.map +1 -0
- package/dist/agent-detection/registry.js +177 -0
- package/dist/agent-detection/registry.js.map +1 -0
- package/dist/agent-detection/types.d.ts +121 -0
- package/dist/agent-detection/types.d.ts.map +1 -0
- package/dist/agent-detection/types.js +20 -0
- package/dist/agent-detection/types.js.map +1 -0
- package/dist/api/server.d.ts +5 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +362 -0
- package/dist/api/server.js.map +1 -1
- package/dist/api/types.d.ts +50 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/cli/acp.d.ts +2 -0
- package/dist/cli/acp.d.ts.map +1 -1
- package/dist/cli/acp.js +8 -1
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.js +38 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/project-config.d.ts +46 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/config/project-config.js +68 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/lifecycle/cascade.d.ts +1 -1
- package/dist/lifecycle/cascade.d.ts.map +1 -1
- package/dist/lifecycle/handlers/index.d.ts +4 -0
- package/dist/lifecycle/handlers/index.d.ts.map +1 -1
- package/dist/lifecycle/handlers/index.js +2 -0
- package/dist/lifecycle/handlers/index.js.map +1 -1
- package/dist/lifecycle/handlers/worker.d.ts +4 -0
- package/dist/lifecycle/handlers/worker.d.ts.map +1 -1
- package/dist/lifecycle/handlers/worker.js +35 -3
- package/dist/lifecycle/handlers/worker.js.map +1 -1
- package/dist/mail/conversation-map.d.ts +33 -0
- package/dist/mail/conversation-map.d.ts.map +1 -0
- package/dist/mail/conversation-map.js +61 -0
- package/dist/mail/conversation-map.js.map +1 -0
- package/dist/mail/index.d.ts +11 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +11 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/mail-service.d.ts +85 -0
- package/dist/mail/mail-service.d.ts.map +1 -0
- package/dist/mail/mail-service.js +121 -0
- package/dist/mail/mail-service.js.map +1 -0
- package/dist/mail/stores/eventstore-conversation-store.d.ts +40 -0
- package/dist/mail/stores/eventstore-conversation-store.d.ts.map +1 -0
- package/dist/mail/stores/eventstore-conversation-store.js +131 -0
- package/dist/mail/stores/eventstore-conversation-store.js.map +1 -0
- package/dist/mail/stores/eventstore-participant-store.d.ts +43 -0
- package/dist/mail/stores/eventstore-participant-store.d.ts.map +1 -0
- package/dist/mail/stores/eventstore-participant-store.js +145 -0
- package/dist/mail/stores/eventstore-participant-store.js.map +1 -0
- package/dist/mail/stores/eventstore-thread-store.d.ts +46 -0
- package/dist/mail/stores/eventstore-thread-store.d.ts.map +1 -0
- package/dist/mail/stores/eventstore-thread-store.js +118 -0
- package/dist/mail/stores/eventstore-thread-store.js.map +1 -0
- package/dist/mail/stores/eventstore-turn-store.d.ts +47 -0
- package/dist/mail/stores/eventstore-turn-store.d.ts.map +1 -0
- package/dist/mail/stores/eventstore-turn-store.js +153 -0
- package/dist/mail/stores/eventstore-turn-store.js.map +1 -0
- package/dist/mail/stores/index.d.ts +12 -0
- package/dist/mail/stores/index.d.ts.map +1 -0
- package/dist/mail/stores/index.js +12 -0
- package/dist/mail/stores/index.js.map +1 -0
- package/dist/mail/stores/types.d.ts +146 -0
- package/dist/mail/stores/types.d.ts.map +1 -0
- package/dist/mail/stores/types.js +13 -0
- package/dist/mail/stores/types.js.map +1 -0
- package/dist/mail/turn-recorder.d.ts +30 -0
- package/dist/mail/turn-recorder.d.ts.map +1 -0
- package/dist/mail/turn-recorder.js +98 -0
- package/dist/mail/turn-recorder.js.map +1 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +32 -2
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/event-translator.d.ts.map +1 -1
- package/dist/map/adapter/event-translator.js +4 -0
- package/dist/map/adapter/event-translator.js.map +1 -1
- package/dist/map/adapter/extensions/agent-detection.d.ts +49 -0
- package/dist/map/adapter/extensions/agent-detection.d.ts.map +1 -0
- package/dist/map/adapter/extensions/agent-detection.js +91 -0
- package/dist/map/adapter/extensions/agent-detection.js.map +1 -0
- package/dist/map/adapter/extensions/index.d.ts +10 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +39 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- package/dist/map/adapter/extensions/resume.d.ts +47 -0
- package/dist/map/adapter/extensions/resume.d.ts.map +1 -0
- package/dist/map/adapter/extensions/resume.js +59 -0
- package/dist/map/adapter/extensions/resume.js.map +1 -0
- package/dist/map/adapter/extensions/workspace-files.d.ts +42 -0
- package/dist/map/adapter/extensions/workspace-files.d.ts.map +1 -0
- package/dist/map/adapter/extensions/workspace-files.js +338 -0
- package/dist/map/adapter/extensions/workspace-files.js.map +1 -0
- package/dist/map/adapter/mail-handler-adapter.d.ts +27 -0
- package/dist/map/adapter/mail-handler-adapter.d.ts.map +1 -0
- package/dist/map/adapter/mail-handler-adapter.js +292 -0
- package/dist/map/adapter/mail-handler-adapter.js.map +1 -0
- package/dist/map/adapter/map-adapter.d.ts +34 -10
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +110 -14
- package/dist/map/adapter/map-adapter.js.map +1 -1
- package/dist/map/adapter/rpc-handler.d.ts +4 -1
- package/dist/map/adapter/rpc-handler.d.ts.map +1 -1
- package/dist/map/adapter/rpc-handler.js +6 -0
- package/dist/map/adapter/rpc-handler.js.map +1 -1
- package/dist/map/index.d.ts +1 -0
- package/dist/map/index.d.ts.map +1 -1
- package/dist/map/index.js +2 -0
- package/dist/map/index.js.map +1 -1
- package/dist/map/types.d.ts +3 -1
- package/dist/map/types.d.ts.map +1 -1
- package/dist/map/types.js.map +1 -1
- package/dist/mcp/mcp-server.d.ts +6 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +45 -0
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/tools/claim_task.d.ts +35 -0
- package/dist/mcp/tools/claim_task.d.ts.map +1 -0
- package/dist/mcp/tools/claim_task.js +58 -0
- package/dist/mcp/tools/claim_task.js.map +1 -0
- package/dist/mcp/tools/done.d.ts +15 -2
- package/dist/mcp/tools/done.d.ts.map +1 -1
- package/dist/mcp/tools/done.js +45 -10
- package/dist/mcp/tools/done.js.map +1 -1
- package/dist/mcp/tools/list_claimable_tasks.d.ts +38 -0
- package/dist/mcp/tools/list_claimable_tasks.d.ts.map +1 -0
- package/dist/mcp/tools/list_claimable_tasks.js +63 -0
- package/dist/mcp/tools/list_claimable_tasks.js.map +1 -0
- package/dist/mcp/tools/unclaim_task.d.ts +31 -0
- package/dist/mcp/tools/unclaim_task.d.ts.map +1 -0
- package/dist/mcp/tools/unclaim_task.js +47 -0
- package/dist/mcp/tools/unclaim_task.js.map +1 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +2 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/metrics.d.ts +79 -0
- package/dist/metrics/metrics.d.ts.map +1 -0
- package/dist/metrics/metrics.js +166 -0
- package/dist/metrics/metrics.js.map +1 -0
- package/dist/roles/capabilities.d.ts +1 -0
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +3 -0
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/types.d.ts +1 -1
- package/dist/roles/types.d.ts.map +1 -1
- package/dist/router/channels.d.ts +2 -4
- package/dist/router/channels.d.ts.map +1 -1
- package/dist/router/channels.js.map +1 -1
- package/dist/router/message-router.d.ts +85 -9
- package/dist/router/message-router.d.ts.map +1 -1
- package/dist/router/message-router.js +203 -14
- package/dist/router/message-router.js.map +1 -1
- package/dist/router/role-resolver.d.ts +10 -1
- package/dist/router/role-resolver.d.ts.map +1 -1
- package/dist/router/role-resolver.js +15 -1
- package/dist/router/role-resolver.js.map +1 -1
- package/dist/router/types.d.ts +30 -1
- package/dist/router/types.d.ts.map +1 -1
- package/dist/router/types.js.map +1 -1
- package/dist/server/combined-server.d.ts +6 -0
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +24 -2
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts +14 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +456 -4
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +1 -1
- package/dist/store/types/agents.d.ts.map +1 -1
- package/dist/store/types/conversations.d.ts +91 -0
- package/dist/store/types/conversations.d.ts.map +1 -0
- package/dist/store/types/conversations.js +8 -0
- package/dist/store/types/conversations.js.map +1 -0
- package/dist/store/types/events.d.ts +1 -1
- package/dist/store/types/events.d.ts.map +1 -1
- package/dist/store/types/events.js.map +1 -1
- package/dist/store/types/index.d.ts +2 -0
- package/dist/store/types/index.d.ts.map +1 -1
- package/dist/store/types/index.js +2 -0
- package/dist/store/types/index.js.map +1 -1
- package/dist/store/types/sessions.d.ts +44 -0
- package/dist/store/types/sessions.d.ts.map +1 -0
- package/dist/store/types/sessions.js +9 -0
- package/dist/store/types/sessions.js.map +1 -0
- package/dist/store/types/tasks.d.ts +2 -0
- package/dist/store/types/tasks.d.ts.map +1 -1
- package/dist/task/backend/memory.d.ts +4 -1
- package/dist/task/backend/memory.d.ts.map +1 -1
- package/dist/task/backend/memory.js +81 -0
- package/dist/task/backend/memory.js.map +1 -1
- package/dist/task/backend/types.d.ts +30 -0
- package/dist/task/backend/types.d.ts.map +1 -1
- package/dist/task/backend/types.js.map +1 -1
- package/dist/teams/index.d.ts +4 -0
- package/dist/teams/index.d.ts.map +1 -0
- package/dist/teams/index.js +4 -0
- package/dist/teams/index.js.map +1 -0
- package/dist/teams/team-loader.d.ts +20 -0
- package/dist/teams/team-loader.d.ts.map +1 -0
- package/dist/teams/team-loader.js +293 -0
- package/dist/teams/team-loader.js.map +1 -0
- package/dist/teams/team-runtime.d.ts +139 -0
- package/dist/teams/team-runtime.d.ts.map +1 -0
- package/dist/teams/team-runtime.js +613 -0
- package/dist/teams/team-runtime.js.map +1 -0
- package/dist/teams/types.d.ts +266 -0
- package/dist/teams/types.d.ts.map +1 -0
- package/dist/teams/types.js +20 -0
- package/dist/teams/types.js.map +1 -0
- package/dist/trigger/router/trigger-router.d.ts +30 -3
- package/dist/trigger/router/trigger-router.d.ts.map +1 -1
- package/dist/trigger/router/trigger-router.js +30 -3
- package/dist/trigger/router/trigger-router.js.map +1 -1
- package/dist/trigger/wake/types.d.ts +31 -5
- package/dist/trigger/wake/types.d.ts.map +1 -1
- package/dist/trigger/wake/types.js +19 -0
- package/dist/trigger/wake/types.js.map +1 -1
- package/dist/workspace/dataplane-adapter.d.ts +1 -1
- package/dist/workspace/dataplane-adapter.d.ts.map +1 -1
- package/dist/workspace/dataplane-adapter.js +1 -1
- package/dist/workspace/dataplane-adapter.js.map +1 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/strategies/index.d.ts +6 -0
- package/dist/workspace/strategies/index.d.ts.map +1 -0
- package/dist/workspace/strategies/index.js +5 -0
- package/dist/workspace/strategies/index.js.map +1 -0
- package/dist/workspace/strategies/optimistic.d.ts +26 -0
- package/dist/workspace/strategies/optimistic.d.ts.map +1 -0
- package/dist/workspace/strategies/optimistic.js +121 -0
- package/dist/workspace/strategies/optimistic.js.map +1 -0
- package/dist/workspace/strategies/queue.d.ts +26 -0
- package/dist/workspace/strategies/queue.d.ts.map +1 -0
- package/dist/workspace/strategies/queue.js +67 -0
- package/dist/workspace/strategies/queue.js.map +1 -0
- package/dist/workspace/strategies/registry.d.ts +37 -0
- package/dist/workspace/strategies/registry.d.ts.map +1 -0
- package/dist/workspace/strategies/registry.js +63 -0
- package/dist/workspace/strategies/registry.js.map +1 -0
- package/dist/workspace/strategies/trunk.d.ts +20 -0
- package/dist/workspace/strategies/trunk.d.ts.map +1 -0
- package/dist/workspace/strategies/trunk.js +108 -0
- package/dist/workspace/strategies/trunk.js.map +1 -0
- package/dist/workspace/strategies/types.d.ts +104 -0
- package/dist/workspace/strategies/types.d.ts.map +1 -0
- package/dist/workspace/strategies/types.js +11 -0
- package/dist/workspace/strategies/types.js.map +1 -0
- package/dist/workspace/types.d.ts +1 -1
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.d.ts +1 -1
- package/dist/workspace/workspace-manager.d.ts.map +1 -1
- package/docs/implementation-details.md +1127 -0
- package/docs/implementation-summary.md +448 -0
- package/docs/mail-integration.md +608 -0
- package/docs/plan-self-driving-support.md +433 -0
- package/docs/spec-self-driving-support.md +462 -0
- package/docs/team-templates.md +860 -0
- package/docs/teams.md +233 -0
- package/package.json +5 -3
- package/src/acp/__tests__/integration.test.ts +161 -1
- package/src/acp/__tests__/macro-agent.test.ts +95 -0
- package/src/acp/__tests__/session-persistence.test.ts +276 -0
- package/src/acp/macro-agent.ts +79 -7
- package/src/acp/session-mapper.ts +108 -1
- package/src/acp/types.ts +33 -1
- package/src/agent/agent-manager.ts +278 -6
- package/src/agent/types.ts +27 -0
- package/src/agent/wake.ts +15 -0
- package/src/agent-detection/__tests__/command-builder.test.ts +336 -0
- package/src/agent-detection/__tests__/detector.test.ts +768 -0
- package/src/agent-detection/__tests__/registry.test.ts +254 -0
- package/src/agent-detection/command-builder.ts +90 -0
- package/src/agent-detection/detector.ts +307 -0
- package/src/agent-detection/index.ts +36 -0
- package/src/agent-detection/registry.ts +200 -0
- package/src/agent-detection/types.ts +184 -0
- package/src/api/__tests__/conversation-api.test.ts +468 -0
- package/src/api/server.ts +425 -1
- package/src/api/types.ts +64 -1
- package/src/cli/acp.ts +9 -1
- package/src/cli/index.ts +44 -0
- package/src/cli/mcp.ts +47 -0
- package/src/config/index.ts +9 -0
- package/src/config/project-config.ts +107 -0
- package/src/lifecycle/cascade.ts +1 -1
- package/src/lifecycle/handlers/index.ts +8 -0
- package/src/lifecycle/handlers/worker.ts +48 -3
- package/src/mail/__tests__/conversation-lifecycle.test.ts +409 -0
- package/src/mail/__tests__/eventstore-stores.test.ts +1073 -0
- package/src/mail/__tests__/mail-full-agent.e2e.test.ts +575 -0
- package/src/mail/__tests__/mail-integration.test.ts +759 -0
- package/src/mail/__tests__/mail-map-protocol.e2e.test.ts +1068 -0
- package/src/mail/__tests__/mail-service.test.ts +506 -0
- package/src/mail/__tests__/turn-recorder.test.ts +328 -0
- package/src/mail/conversation-map.ts +107 -0
- package/src/mail/index.ts +25 -0
- package/src/mail/mail-service.ts +257 -0
- package/src/mail/stores/eventstore-conversation-store.ts +146 -0
- package/src/mail/stores/eventstore-participant-store.ts +172 -0
- package/src/mail/stores/eventstore-thread-store.ts +129 -0
- package/src/mail/stores/eventstore-turn-store.ts +173 -0
- package/src/mail/stores/index.ts +12 -0
- package/src/mail/stores/types.ts +160 -0
- package/src/mail/turn-recorder.ts +124 -0
- package/src/map/README.md +79 -0
- package/src/map/adapter/__tests__/extensions.test.ts +359 -0
- package/src/map/adapter/__tests__/map-adapter.test.ts +90 -0
- package/src/map/adapter/__tests__/workspace-files.test.ts +673 -0
- package/src/map/adapter/acp-over-map.ts +45 -2
- package/src/map/adapter/event-translator.ts +4 -0
- package/src/map/adapter/extensions/agent-detection.ts +201 -0
- package/src/map/adapter/extensions/index.ts +63 -0
- package/src/map/adapter/extensions/resume.ts +114 -0
- package/src/map/adapter/extensions/workspace-files.ts +449 -0
- package/src/map/adapter/mail-handler-adapter.ts +429 -0
- package/src/map/adapter/map-adapter.ts +173 -27
- package/src/map/adapter/rpc-handler.ts +8 -1
- package/src/map/index.ts +3 -0
- package/src/map/types.ts +3 -1
- package/src/mcp/mcp-server.ts +67 -0
- package/src/mcp/tools/claim_task.ts +86 -0
- package/src/mcp/tools/done.ts +59 -10
- package/src/mcp/tools/list_claimable_tasks.ts +93 -0
- package/src/mcp/tools/unclaim_task.ts +71 -0
- package/src/metrics/index.ts +9 -0
- package/src/metrics/metrics.ts +280 -0
- package/src/roles/capabilities.ts +3 -0
- package/src/roles/types.ts +2 -1
- package/src/router/README.md +120 -0
- package/src/router/__tests__/message-router.test.ts +561 -0
- package/src/router/channels.ts +3 -4
- package/src/router/message-router.ts +308 -22
- package/src/router/role-resolver.ts +22 -1
- package/src/router/types.ts +36 -1
- package/src/server/combined-server.ts +36 -2
- package/src/store/README.md +134 -0
- package/src/store/event-store.ts +546 -3
- package/src/store/types/agents.ts +1 -1
- package/src/store/types/conversations.ts +129 -0
- package/src/store/types/events.ts +5 -1
- package/src/store/types/index.ts +2 -0
- package/src/store/types/sessions.ts +53 -0
- package/src/store/types/tasks.ts +3 -0
- package/src/task/backend/memory.ts +116 -0
- package/src/task/backend/types.ts +43 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +983 -0
- package/src/teams/__tests__/e2e/team-runtime.e2e.test.ts +553 -0
- package/src/teams/__tests__/team-system.test.ts +1280 -0
- package/src/teams/index.ts +13 -0
- package/src/teams/team-loader.ts +434 -0
- package/src/teams/team-runtime.ts +727 -0
- package/src/teams/types.ts +377 -0
- package/src/trigger/router/trigger-router.ts +30 -3
- package/src/trigger/wake/types.ts +32 -5
- package/src/trigger/wake/wake-manager.ts +2 -2
- package/src/workspace/dataplane-adapter.ts +1 -1
- package/src/workspace/index.ts +1 -1
- package/src/workspace/strategies/index.ts +18 -0
- package/src/workspace/strategies/optimistic.ts +136 -0
- package/src/workspace/strategies/queue.ts +81 -0
- package/src/workspace/strategies/registry.ts +89 -0
- package/src/workspace/strategies/trunk.ts +123 -0
- package/src/workspace/strategies/types.ts +145 -0
- package/src/workspace/types.ts +1 -1
- package/src/workspace/workspace-manager.ts +1 -1
- package/.claude/settings.local.json +0 -59
- package/dist/map/utils/address-translation.d.ts +0 -99
- package/dist/map/utils/address-translation.d.ts.map +0 -1
- package/dist/map/utils/address-translation.js +0 -285
- package/dist/map/utils/address-translation.js.map +0 -1
- package/dist/map/utils/index.d.ts +0 -7
- package/dist/map/utils/index.d.ts.map +0 -1
- package/dist/map/utils/index.js +0 -7
- package/dist/map/utils/index.js.map +0 -1
- package/openspec/AGENTS.md +0 -456
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/design.md +0 -128
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/proposal.md +0 -49
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/agent-manager/spec.md +0 -150
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/cli-api/spec.md +0 -258
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/event-store/spec.md +0 -160
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/mcp-tools/spec.md +0 -224
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/message-router/spec.md +0 -153
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/specs/task-manager/spec.md +0 -136
- package/openspec/changes/archive/2025-12-21-add-mvp-foundation/tasks.md +0 -147
- package/openspec/project.md +0 -31
- package/openspec/specs/agent-manager/spec.md +0 -154
- package/openspec/specs/cli-api/spec.md +0 -262
- package/openspec/specs/event-store/spec.md +0 -164
- package/openspec/specs/mcp-tools/spec.md +0 -228
- package/openspec/specs/message-router/spec.md +0 -157
- package/openspec/specs/task-manager/spec.md +0 -140
- package/references/acp-factory-ref/CHANGELOG.md +0 -33
- package/references/acp-factory-ref/LICENSE +0 -21
- package/references/acp-factory-ref/README.md +0 -341
- package/references/acp-factory-ref/package-lock.json +0 -3102
- package/references/acp-factory-ref/package.json +0 -96
- package/references/acp-factory-ref/python/CHANGELOG.md +0 -33
- package/references/acp-factory-ref/python/LICENSE +0 -21
- package/references/acp-factory-ref/python/Makefile +0 -57
- package/references/acp-factory-ref/python/README.md +0 -253
- package/references/acp-factory-ref/python/pyproject.toml +0 -73
- package/references/acp-factory-ref/python/tests/__init__.py +0 -0
- package/references/acp-factory-ref/python/tests/e2e/__init__.py +0 -1
- package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +0 -349
- package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +0 -165
- package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +0 -296
- package/references/acp-factory-ref/python/tests/test_client_handler.py +0 -543
- package/references/acp-factory-ref/python/tests/test_pushable.py +0 -199
- package/references/claude-code-acp/.github/workflows/ci.yml +0 -45
- package/references/claude-code-acp/.github/workflows/publish.yml +0 -34
- package/references/claude-code-acp/.prettierrc.json +0 -4
- package/references/claude-code-acp/CHANGELOG.md +0 -249
- package/references/claude-code-acp/LICENSE +0 -222
- package/references/claude-code-acp/README.md +0 -53
- package/references/claude-code-acp/docs/RELEASES.md +0 -24
- package/references/claude-code-acp/eslint.config.js +0 -48
- package/references/claude-code-acp/package-lock.json +0 -4570
- package/references/claude-code-acp/package.json +0 -88
- package/references/claude-code-acp/scripts/release.sh +0 -119
- package/references/claude-code-acp/src/acp-agent.ts +0 -2065
- package/references/claude-code-acp/src/index.ts +0 -26
- package/references/claude-code-acp/src/lib.ts +0 -38
- package/references/claude-code-acp/src/mcp-server.ts +0 -911
- package/references/claude-code-acp/src/settings.ts +0 -522
- package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +0 -5
- package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +0 -6
- package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +0 -479
- package/references/claude-code-acp/src/tests/acp-agent.test.ts +0 -1502
- package/references/claude-code-acp/src/tests/extract-lines.test.ts +0 -103
- package/references/claude-code-acp/src/tests/fork-session.test.ts +0 -335
- package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +0 -334
- package/references/claude-code-acp/src/tests/settings.test.ts +0 -617
- package/references/claude-code-acp/src/tests/skills-options.test.ts +0 -187
- package/references/claude-code-acp/src/tests/tools.test.ts +0 -318
- package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +0 -558
- package/references/claude-code-acp/src/tools.ts +0 -819
- package/references/claude-code-acp/src/utils.ts +0 -171
- package/references/claude-code-acp/tsconfig.json +0 -18
- package/references/claude-code-acp/vitest.config.ts +0 -19
- package/references/multi-agent-protocol/.sudocode/issues.jsonl +0 -82
- package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -9
- package/references/multi-agent-protocol/LICENSE +0 -21
- package/references/multi-agent-protocol/README.md +0 -113
- package/references/multi-agent-protocol/docs/00-design-specification.md +0 -460
- package/references/multi-agent-protocol/docs/01-open-questions.md +0 -1050
- package/references/multi-agent-protocol/docs/02-wire-protocol.md +0 -296
- package/references/multi-agent-protocol/docs/03-streaming-semantics.md +0 -252
- package/references/multi-agent-protocol/docs/04-error-handling.md +0 -231
- package/references/multi-agent-protocol/docs/05-connection-model.md +0 -244
- package/references/multi-agent-protocol/docs/06-visibility-permissions.md +0 -243
- package/references/multi-agent-protocol/docs/07-federation.md +0 -259
- package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +0 -253
- package/references/multi-agent-protocol/package-lock.json +0 -3239
- package/references/multi-agent-protocol/package.json +0 -56
- package/references/multi-agent-protocol/schema/meta.json +0 -337
- package/references/multi-agent-protocol/schema/schema.json +0 -1828
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team Runtime
|
|
3
|
+
*
|
|
4
|
+
* Wires a loaded TeamManifest into the running system: registers roles,
|
|
5
|
+
* sets up integration strategy, configures communication topology,
|
|
6
|
+
* and manages the team lifecycle.
|
|
7
|
+
*
|
|
8
|
+
* @module teams/team-runtime
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { EventStore } from "../store/event-store.js";
|
|
12
|
+
import type { MessageRouter } from "../router/message-router.js";
|
|
13
|
+
import type { AgentManager, SpawnInterceptor } from "../agent/agent-manager.js";
|
|
14
|
+
import type { RoleRegistry } from "../roles/types.js";
|
|
15
|
+
import type { SpawnAgentOptions } from "../agent/types.js";
|
|
16
|
+
import type { AgentId } from "../store/types/index.js";
|
|
17
|
+
import type {
|
|
18
|
+
TeamManifest,
|
|
19
|
+
McpServerEntry,
|
|
20
|
+
PeerConnection,
|
|
21
|
+
} from "./types.js";
|
|
22
|
+
import type { IntegrationStrategy } from "../workspace/strategies/types.js";
|
|
23
|
+
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Types
|
|
26
|
+
// =============================================================================
|
|
27
|
+
|
|
28
|
+
export interface TeamServices {
|
|
29
|
+
agentManager: AgentManager;
|
|
30
|
+
messageRouter: MessageRouter;
|
|
31
|
+
eventStore: EventStore;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface TeamBootstrapResult {
|
|
35
|
+
rootId: string;
|
|
36
|
+
companionIds: string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// =============================================================================
|
|
40
|
+
// TeamRuntime
|
|
41
|
+
// =============================================================================
|
|
42
|
+
|
|
43
|
+
export class TeamRuntime {
|
|
44
|
+
private rootAgentId?: string;
|
|
45
|
+
private companionAgentIds: string[] = [];
|
|
46
|
+
private roleRegistry: RoleRegistry;
|
|
47
|
+
private lifecycleUnsubscribe?: () => void;
|
|
48
|
+
private integrationStrategy?: IntegrationStrategy;
|
|
49
|
+
|
|
50
|
+
/** Role name → spawned agent ID mapping (populated during bootstrap) */
|
|
51
|
+
private roleAgentMap = new Map<string, AgentId>();
|
|
52
|
+
|
|
53
|
+
/** Peer connections that couldn't be wired at bootstrap (target role not yet spawned) */
|
|
54
|
+
private pendingPeerRoutes: PeerConnection[] = [];
|
|
55
|
+
|
|
56
|
+
/** Per-agent signal filters from peer connections. Key: "fromAgentId→toAgentId" */
|
|
57
|
+
private peerSignalFilters = new Map<string, string[]>();
|
|
58
|
+
|
|
59
|
+
/** Reverse mapping: agent ID → role name (for signal filter lookups) */
|
|
60
|
+
private agentRoleMap = new Map<AgentId, string>();
|
|
61
|
+
|
|
62
|
+
/** Lifecycle unsubscribe for deferred peer wiring */
|
|
63
|
+
private peerWiringUnsubscribe?: () => void;
|
|
64
|
+
|
|
65
|
+
constructor(
|
|
66
|
+
private readonly manifest: TeamManifest,
|
|
67
|
+
private readonly services: TeamServices
|
|
68
|
+
) {
|
|
69
|
+
this.roleRegistry = services.agentManager.getRoleRegistry();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ─────────────────────────────────────────────────────────────
|
|
73
|
+
// Initialization
|
|
74
|
+
// ─────────────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Wire team configuration into running services.
|
|
78
|
+
*
|
|
79
|
+
* 1. Register team roles into RoleRegistry
|
|
80
|
+
* 2. Store team_config event in EventStore (for MCP subprocess discovery)
|
|
81
|
+
* 3. Register spawn interceptor on AgentManager
|
|
82
|
+
*/
|
|
83
|
+
async initialize(): Promise<void> {
|
|
84
|
+
const { agentManager, eventStore } = this.services;
|
|
85
|
+
|
|
86
|
+
// 1. Register team roles into RoleRegistry (custom layer, highest priority)
|
|
87
|
+
for (const [, resolved] of this.manifest._resolvedRoles) {
|
|
88
|
+
this.roleRegistry.registerRole(resolved.roleDefinition);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 2. Store team config in EventStore for cross-process access (RD2)
|
|
92
|
+
const taskMode = this.manifest.macro_agent.task_assignment?.mode ?? "push";
|
|
93
|
+
const strategyName = this.manifest.macro_agent.integration?.strategy ?? "queue";
|
|
94
|
+
const strategyConfig = this.manifest.macro_agent.integration?.config ?? {};
|
|
95
|
+
const enforcement = this.manifest.communication.enforcement ?? "permissive";
|
|
96
|
+
|
|
97
|
+
// Serialize resolved roles for MCP subprocess capability checks
|
|
98
|
+
const serializedRoles: Record<string, { name: string; capabilities: string[]; tools?: object; lifecycle?: object; description?: string }> = {};
|
|
99
|
+
for (const [name, resolved] of this.manifest._resolvedRoles) {
|
|
100
|
+
const rd = resolved.roleDefinition;
|
|
101
|
+
serializedRoles[name] = {
|
|
102
|
+
name: rd.name,
|
|
103
|
+
capabilities: [...rd.capabilities],
|
|
104
|
+
...(rd.tools && { tools: rd.tools }),
|
|
105
|
+
...(rd.lifecycle && { lifecycle: rd.lifecycle }),
|
|
106
|
+
...(rd.description && { description: rd.description }),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
eventStore.emit({
|
|
111
|
+
type: "status",
|
|
112
|
+
source: { agent_id: "system" },
|
|
113
|
+
payload: {
|
|
114
|
+
status_type: "discovery",
|
|
115
|
+
summary: `Team '${this.manifest.name}' initialized`,
|
|
116
|
+
team_config: {
|
|
117
|
+
teamName: this.manifest.name,
|
|
118
|
+
strategy: strategyName,
|
|
119
|
+
strategyConfig,
|
|
120
|
+
taskMode,
|
|
121
|
+
enforcement,
|
|
122
|
+
roles: serializedRoles,
|
|
123
|
+
peerRoutes: this.manifest.communication.routing?.peers ?? [],
|
|
124
|
+
emissions: this.manifest.communication.emissions ?? {},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await eventStore.persist();
|
|
130
|
+
|
|
131
|
+
// 2b. Instantiate integration strategy and call lifecycle hook
|
|
132
|
+
try {
|
|
133
|
+
const { defaultStrategyRegistry } = await import("../workspace/strategies/registry.js");
|
|
134
|
+
this.integrationStrategy = defaultStrategyRegistry.get(strategyName, strategyConfig as Record<string, unknown>);
|
|
135
|
+
if (this.integrationStrategy.initialize) {
|
|
136
|
+
await this.integrationStrategy.initialize();
|
|
137
|
+
}
|
|
138
|
+
} catch {
|
|
139
|
+
// Strategy instantiation is best-effort — queue strategy needs merge queue set later
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 3. Register spawn interceptor
|
|
143
|
+
agentManager.setSpawnInterceptor(this.createSpawnInterceptor());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ─────────────────────────────────────────────────────────────
|
|
147
|
+
// Bootstrap
|
|
148
|
+
// ─────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Spawn root and companion agents per the team topology.
|
|
152
|
+
*/
|
|
153
|
+
async bootstrap(): Promise<TeamBootstrapResult> {
|
|
154
|
+
const { agentManager, messageRouter } = this.services;
|
|
155
|
+
const { topology } = this.manifest;
|
|
156
|
+
|
|
157
|
+
// 1. Spawn root agent
|
|
158
|
+
const rootPrompt = this.getPromptForTopologyNode(topology.root);
|
|
159
|
+
const root = await agentManager.spawn({
|
|
160
|
+
task: rootPrompt
|
|
161
|
+
? `[${this.manifest.name}] ${topology.root.role}`
|
|
162
|
+
: `Team ${this.manifest.name} root: ${topology.root.role}`,
|
|
163
|
+
parent: null,
|
|
164
|
+
role: topology.root.role,
|
|
165
|
+
config: {
|
|
166
|
+
model: topology.root.config?.model,
|
|
167
|
+
},
|
|
168
|
+
customPrompt: rootPrompt,
|
|
169
|
+
interactionPatterns: this.getInteractionPatterns(),
|
|
170
|
+
});
|
|
171
|
+
this.rootAgentId = root.id;
|
|
172
|
+
|
|
173
|
+
// 2. Spawn companions (peers, not children)
|
|
174
|
+
const companionIds: string[] = [];
|
|
175
|
+
for (const companion of topology.companions ?? []) {
|
|
176
|
+
const companionPrompt = this.getPromptForTopologyNode(companion);
|
|
177
|
+
const agent = await agentManager.spawn({
|
|
178
|
+
task: `[${this.manifest.name}] ${companion.role}`,
|
|
179
|
+
parent: null,
|
|
180
|
+
role: companion.role,
|
|
181
|
+
config: {
|
|
182
|
+
model: companion.config?.model,
|
|
183
|
+
},
|
|
184
|
+
customPrompt: companionPrompt,
|
|
185
|
+
interactionPatterns: this.getInteractionPatterns(),
|
|
186
|
+
});
|
|
187
|
+
companionIds.push(agent.id);
|
|
188
|
+
}
|
|
189
|
+
this.companionAgentIds = companionIds;
|
|
190
|
+
|
|
191
|
+
// 3. Build role↔agent mappings and wire peer subscriptions
|
|
192
|
+
this.roleAgentMap.set(topology.root.role, root.id as AgentId);
|
|
193
|
+
this.agentRoleMap.set(root.id as AgentId, topology.root.role);
|
|
194
|
+
for (let i = 0; i < (topology.companions ?? []).length; i++) {
|
|
195
|
+
this.roleAgentMap.set(topology.companions![i].role, companionIds[i] as AgentId);
|
|
196
|
+
this.agentRoleMap.set(companionIds[i] as AgentId, topology.companions![i].role);
|
|
197
|
+
}
|
|
198
|
+
this.wirePeerRoutes();
|
|
199
|
+
|
|
200
|
+
// 4. Install signal filter on message router
|
|
201
|
+
this.installSignalFilter();
|
|
202
|
+
|
|
203
|
+
// 5. Install emission validator on message router
|
|
204
|
+
this.installEmissionValidator();
|
|
205
|
+
|
|
206
|
+
// 6. Set up continuation monitoring for daemon agents (P4.2)
|
|
207
|
+
this.monitorContinuations();
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
rootId: root.id,
|
|
211
|
+
companionIds,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ─────────────────────────────────────────────────────────────
|
|
216
|
+
// Teardown
|
|
217
|
+
// ─────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Tear down team: remove spawn interceptor, stop continuation monitoring.
|
|
221
|
+
*/
|
|
222
|
+
async teardown(): Promise<void> {
|
|
223
|
+
this.services.agentManager.setSpawnInterceptor(null);
|
|
224
|
+
if (this.lifecycleUnsubscribe) {
|
|
225
|
+
this.lifecycleUnsubscribe();
|
|
226
|
+
this.lifecycleUnsubscribe = undefined;
|
|
227
|
+
}
|
|
228
|
+
if (this.peerWiringUnsubscribe) {
|
|
229
|
+
this.peerWiringUnsubscribe();
|
|
230
|
+
this.peerWiringUnsubscribe = undefined;
|
|
231
|
+
}
|
|
232
|
+
// Call strategy lifecycle close hook
|
|
233
|
+
if (this.integrationStrategy?.close) {
|
|
234
|
+
try {
|
|
235
|
+
await this.integrationStrategy.close();
|
|
236
|
+
} catch {
|
|
237
|
+
// Best-effort cleanup
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ─────────────────────────────────────────────────────────────
|
|
243
|
+
// Getters
|
|
244
|
+
// ─────────────────────────────────────────────────────────────
|
|
245
|
+
|
|
246
|
+
/** Get task assignment mode */
|
|
247
|
+
getTaskMode(): "push" | "pull" {
|
|
248
|
+
return this.manifest.macro_agent.task_assignment?.mode ?? "push";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Get integration strategy name */
|
|
252
|
+
getStrategyName(): string {
|
|
253
|
+
return this.manifest.macro_agent.integration?.strategy ?? "queue";
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Get the active manifest (for API) */
|
|
257
|
+
getManifest(): TeamManifest {
|
|
258
|
+
return this.manifest;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Get root agent ID (after bootstrap) */
|
|
262
|
+
getRootAgentId(): string | undefined {
|
|
263
|
+
return this.rootAgentId;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Get companion agent IDs (after bootstrap) */
|
|
267
|
+
getCompanionAgentIds(): string[] {
|
|
268
|
+
return [...this.companionAgentIds];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Get the instantiated integration strategy (after initialize) */
|
|
272
|
+
getIntegrationStrategy(): IntegrationStrategy | undefined {
|
|
273
|
+
return this.integrationStrategy;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Get signal filters for peer connections (for use by signal filtering - i-3o8g) */
|
|
277
|
+
getPeerSignalFilters(): ReadonlyMap<string, string[]> {
|
|
278
|
+
return this.peerSignalFilters;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ─────────────────────────────────────────────────────────────
|
|
282
|
+
// Continuation Monitoring (P4.2)
|
|
283
|
+
// ─────────────────────────────────────────────────────────────
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Monitor agent lifecycle events for auto-continuation of daemon agents.
|
|
287
|
+
*
|
|
288
|
+
* When a root or companion agent terminates unexpectedly and the team's
|
|
289
|
+
* lifecycle config enables continuations, automatically spawn a continuation.
|
|
290
|
+
*/
|
|
291
|
+
private monitorContinuations(): void {
|
|
292
|
+
const lifecycleConfig = this.manifest.macro_agent.lifecycle;
|
|
293
|
+
if (!lifecycleConfig?.continuations?.enabled) return;
|
|
294
|
+
|
|
295
|
+
const { agentManager } = this.services;
|
|
296
|
+
const monitoredAgents = new Set([
|
|
297
|
+
this.rootAgentId,
|
|
298
|
+
...this.companionAgentIds,
|
|
299
|
+
]);
|
|
300
|
+
|
|
301
|
+
this.lifecycleUnsubscribe = agentManager.onLifecycleEvent((event) => {
|
|
302
|
+
if (event.type !== "stopped") return;
|
|
303
|
+
if (!monitoredAgents.has(event.agent.id)) return;
|
|
304
|
+
|
|
305
|
+
// Only auto-continue on unexpected stops (not explicit completion)
|
|
306
|
+
const reason = (event as { reason?: string }).reason;
|
|
307
|
+
if (reason === "completed" || reason === "cancelled") return;
|
|
308
|
+
|
|
309
|
+
// Schedule auto-continuation (async, fire-and-forget)
|
|
310
|
+
setTimeout(async () => {
|
|
311
|
+
try {
|
|
312
|
+
const newAgent = await agentManager.continueAgent(event.agent.id);
|
|
313
|
+
// Update monitoring set
|
|
314
|
+
monitoredAgents.delete(event.agent.id);
|
|
315
|
+
monitoredAgents.add(newAgent.id);
|
|
316
|
+
|
|
317
|
+
if (event.agent.id === this.rootAgentId) {
|
|
318
|
+
this.rootAgentId = newAgent.id;
|
|
319
|
+
} else {
|
|
320
|
+
const idx = this.companionAgentIds.indexOf(event.agent.id);
|
|
321
|
+
if (idx >= 0) {
|
|
322
|
+
this.companionAgentIds[idx] = newAgent.id;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
} catch {
|
|
326
|
+
// Failed to continue — agent is gone
|
|
327
|
+
}
|
|
328
|
+
}, 1000);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ─────────────────────────────────────────────────────────────
|
|
333
|
+
// Spawn Interceptor
|
|
334
|
+
// ─────────────────────────────────────────────────────────────
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create the spawn interceptor that injects team context into spawn options.
|
|
338
|
+
*/
|
|
339
|
+
private createSpawnInterceptor(): SpawnInterceptor {
|
|
340
|
+
return (options: SpawnAgentOptions): SpawnAgentOptions => {
|
|
341
|
+
const roleName = options.role;
|
|
342
|
+
if (!roleName) return options;
|
|
343
|
+
|
|
344
|
+
const resolved = this.manifest._resolvedRoles.get(roleName);
|
|
345
|
+
if (!resolved) return options; // Unknown role — pass through
|
|
346
|
+
|
|
347
|
+
// Compute topics from communication topology
|
|
348
|
+
const teamTopics = this.getTopicsForRole(roleName);
|
|
349
|
+
|
|
350
|
+
// Get MCP servers for this role
|
|
351
|
+
const teamMcpServers = this.getMcpServersForRole(roleName);
|
|
352
|
+
|
|
353
|
+
// Get prompt from role definition or topology
|
|
354
|
+
const teamPrompt = this.getPromptForRole(roleName);
|
|
355
|
+
|
|
356
|
+
// Build team env vars
|
|
357
|
+
const teamEnv: Record<string, string> = {
|
|
358
|
+
MACRO_TEAM_NAME: this.manifest.name,
|
|
359
|
+
MACRO_TASK_MODE: this.getTaskMode(),
|
|
360
|
+
};
|
|
361
|
+
const strategyName = this.getStrategyName();
|
|
362
|
+
if (strategyName) {
|
|
363
|
+
teamEnv.MACRO_INTEGRATION_STRATEGY = strategyName;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
...options,
|
|
368
|
+
// Merge topics
|
|
369
|
+
topics: [
|
|
370
|
+
...(options.topics ?? []),
|
|
371
|
+
...teamTopics,
|
|
372
|
+
],
|
|
373
|
+
// Merge config
|
|
374
|
+
config: {
|
|
375
|
+
...options.config,
|
|
376
|
+
mcpServers: [
|
|
377
|
+
...(options.config?.mcpServers ?? []),
|
|
378
|
+
...teamMcpServers.map((s) => ({
|
|
379
|
+
name: s.name,
|
|
380
|
+
command: s.command,
|
|
381
|
+
args: s.args,
|
|
382
|
+
env: s.env,
|
|
383
|
+
})),
|
|
384
|
+
],
|
|
385
|
+
env: {
|
|
386
|
+
...options.config?.env,
|
|
387
|
+
...teamEnv,
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
// Set team prompt (only if not already provided by caller)
|
|
391
|
+
customPrompt: options.customPrompt ?? teamPrompt,
|
|
392
|
+
// Set interaction patterns (only if not already provided)
|
|
393
|
+
interactionPatterns: options.interactionPatterns ?? this.getInteractionPatterns(),
|
|
394
|
+
};
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// ─────────────────────────────────────────────────────────────
|
|
399
|
+
// Communication Topology Helpers
|
|
400
|
+
// ─────────────────────────────────────────────────────────────
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Get topic names a role should subscribe to based on communication config.
|
|
404
|
+
*/
|
|
405
|
+
private getTopicsForRole(roleName: string): string[] {
|
|
406
|
+
const topics: string[] = [];
|
|
407
|
+
const subs = this.manifest.communication.subscriptions?.[roleName] ?? [];
|
|
408
|
+
|
|
409
|
+
for (const sub of subs) {
|
|
410
|
+
// Channel name becomes the topic name
|
|
411
|
+
if (!topics.includes(sub.channel)) {
|
|
412
|
+
topics.push(sub.channel);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return topics;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Get MCP servers configured for a role.
|
|
421
|
+
*/
|
|
422
|
+
private getMcpServersForRole(roleName: string): McpServerEntry[] {
|
|
423
|
+
return this.manifest._mcpServers.get(roleName) ?? [];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Get the loaded prompt content for a role.
|
|
428
|
+
*/
|
|
429
|
+
private getPromptForRole(roleName: string): string | undefined {
|
|
430
|
+
const resolved = this.manifest._resolvedRoles.get(roleName);
|
|
431
|
+
if (!resolved?.prompt) return undefined;
|
|
432
|
+
return this.manifest._loadedPrompts.get(resolved.prompt);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Get the prompt for a topology node (root or companion).
|
|
437
|
+
*/
|
|
438
|
+
private getPromptForTopologyNode(
|
|
439
|
+
node: { role: string; prompt?: string }
|
|
440
|
+
): string | undefined {
|
|
441
|
+
// Prefer topology-level prompt reference
|
|
442
|
+
if (node.prompt) {
|
|
443
|
+
return this.manifest._loadedPrompts.get(node.prompt);
|
|
444
|
+
}
|
|
445
|
+
// Fall back to role-level prompt
|
|
446
|
+
return this.getPromptForRole(node.role);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Generate interaction pattern injection sections based on team config.
|
|
451
|
+
*/
|
|
452
|
+
private getInteractionPatterns(): string[] {
|
|
453
|
+
const patterns: string[] = [];
|
|
454
|
+
const taskMode = this.getTaskMode();
|
|
455
|
+
|
|
456
|
+
if (taskMode === "pull") {
|
|
457
|
+
const pullConfig = this.manifest.macro_agent.task_assignment?.pull;
|
|
458
|
+
const idleTimeout = pullConfig?.idle_timeout_s ?? 300;
|
|
459
|
+
|
|
460
|
+
patterns.push(`## Task Claiming
|
|
461
|
+
|
|
462
|
+
You operate in PULL mode. After completing a task:
|
|
463
|
+
1. Call done() with your results
|
|
464
|
+
2. Call claim_task() to get your next task
|
|
465
|
+
3. If no tasks available, wait briefly and retry
|
|
466
|
+
4. After ${idleTimeout} seconds idle, call done() to exit gracefully
|
|
467
|
+
|
|
468
|
+
Claim and execute independently — do not wait for instructions.`);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const strategy = this.getStrategyName();
|
|
472
|
+
if (strategy === "trunk") {
|
|
473
|
+
patterns.push(`## Integration
|
|
474
|
+
|
|
475
|
+
Your changes are integrated via trunk-based development. When you call done(),
|
|
476
|
+
your work is pushed directly to the integration branch. If there's a conflict,
|
|
477
|
+
the system will rebase and retry automatically. Write small, focused changes
|
|
478
|
+
to minimize conflict probability.`);
|
|
479
|
+
} else if (strategy === "optimistic") {
|
|
480
|
+
patterns.push(`## Integration
|
|
481
|
+
|
|
482
|
+
Your changes are integrated optimistically. They are pushed immediately and
|
|
483
|
+
validated asynchronously. If validation fails, a fixup task will be created.
|
|
484
|
+
Focus on correctness — your changes go live immediately.`);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return patterns;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// ─────────────────────────────────────────────────────────────
|
|
491
|
+
// Signal Filtering
|
|
492
|
+
// ─────────────────────────────────────────────────────────────
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Install a signal filter on the message router.
|
|
496
|
+
*
|
|
497
|
+
* Combines two filter sources:
|
|
498
|
+
* 1. Channel subscription filters (per-role, per-topic): from communication.subscriptions
|
|
499
|
+
* 2. Peer connection filters (per-agent-pair): from communication.routing.peers
|
|
500
|
+
*
|
|
501
|
+
* Status events with no details.signal always pass through (backwards compat).
|
|
502
|
+
*/
|
|
503
|
+
private installSignalFilter(): void {
|
|
504
|
+
const { messageRouter } = this.services;
|
|
505
|
+
|
|
506
|
+
// Pre-compute per-role allowed signals from channel subscriptions.
|
|
507
|
+
// Key: role name, Value: Set of allowed signal names.
|
|
508
|
+
// If a role has any subscription without a signals filter, it receives all signals.
|
|
509
|
+
const roleAllowedSignals = new Map<string, Set<string> | "all">();
|
|
510
|
+
|
|
511
|
+
for (const [roleName, subs] of Object.entries(this.manifest.communication.subscriptions ?? {})) {
|
|
512
|
+
let allowed: Set<string> | "all" = new Set<string>();
|
|
513
|
+
|
|
514
|
+
for (const sub of subs) {
|
|
515
|
+
if (!sub.signals || sub.signals.length === 0) {
|
|
516
|
+
// No filter on this subscription — role receives all signals
|
|
517
|
+
allowed = "all";
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
for (const sig of sub.signals) {
|
|
521
|
+
(allowed as Set<string>).add(sig);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
roleAllowedSignals.set(roleName, allowed);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (messageRouter.setSignalFilter) {
|
|
529
|
+
messageRouter.setSignalFilter((from, to, signal) => {
|
|
530
|
+
// Untagged status events always pass through
|
|
531
|
+
if (!signal) return true;
|
|
532
|
+
|
|
533
|
+
// Check peer connection filter (directional: from→to)
|
|
534
|
+
const peerFilter = this.peerSignalFilters.get(`${from}→${to}`);
|
|
535
|
+
if (peerFilter) {
|
|
536
|
+
return peerFilter.includes(signal);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Check channel subscription filter for recipient's role
|
|
540
|
+
const recipientRole = this.agentRoleMap.get(to);
|
|
541
|
+
if (recipientRole) {
|
|
542
|
+
const allowed = roleAllowedSignals.get(recipientRole);
|
|
543
|
+
if (allowed && allowed !== "all") {
|
|
544
|
+
return allowed.has(signal);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// No filter configured — allow delivery
|
|
549
|
+
return true;
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// ─────────────────────────────────────────────────────────────
|
|
555
|
+
// Emission Validation
|
|
556
|
+
// ─────────────────────────────────────────────────────────────
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Install emission validator on the message router.
|
|
560
|
+
* Checks whether an agent's emitted signal is in its role's allowed emissions list.
|
|
561
|
+
* Behavior depends on enforcement mode: strict (reject), permissive (warn), audit (record).
|
|
562
|
+
*/
|
|
563
|
+
private installEmissionValidator(): void {
|
|
564
|
+
const { messageRouter } = this.services;
|
|
565
|
+
const emissions = this.manifest.communication.emissions;
|
|
566
|
+
const enforcement = this.manifest.communication.enforcement ?? "permissive";
|
|
567
|
+
|
|
568
|
+
// No emissions config — nothing to enforce
|
|
569
|
+
if (!emissions || Object.keys(emissions).length === 0) return;
|
|
570
|
+
|
|
571
|
+
if (messageRouter.setEmissionValidator) {
|
|
572
|
+
messageRouter.setEmissionValidator((agentId, signal) => {
|
|
573
|
+
// Untagged status events are always allowed
|
|
574
|
+
if (!signal) return { action: "allow" };
|
|
575
|
+
|
|
576
|
+
const role = this.agentRoleMap.get(agentId);
|
|
577
|
+
if (!role) return { action: "allow" };
|
|
578
|
+
|
|
579
|
+
const allowedSignals = emissions[role];
|
|
580
|
+
if (!allowedSignals) return { action: "allow" };
|
|
581
|
+
|
|
582
|
+
if (allowedSignals.includes(signal)) {
|
|
583
|
+
return { action: "allow" };
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Signal not in allowed list — enforce
|
|
587
|
+
const message = `Agent '${agentId}' (role: ${role}) emitted disallowed signal '${signal}'. Allowed: [${allowedSignals.join(", ")}]`;
|
|
588
|
+
|
|
589
|
+
switch (enforcement) {
|
|
590
|
+
case "strict":
|
|
591
|
+
return { action: "reject", message };
|
|
592
|
+
case "audit":
|
|
593
|
+
return { action: "audit", message };
|
|
594
|
+
case "permissive":
|
|
595
|
+
default:
|
|
596
|
+
return { action: "warn", message };
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// ─────────────────────────────────────────────────────────────
|
|
603
|
+
// Peer Routing
|
|
604
|
+
// ─────────────────────────────────────────────────────────────
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Wire peer subscriptions from communication config.
|
|
608
|
+
* Falls back to legacy bidirectional subtree subs when no peers config exists.
|
|
609
|
+
*/
|
|
610
|
+
private wirePeerRoutes(): void {
|
|
611
|
+
const peers = this.manifest.communication.routing?.peers;
|
|
612
|
+
|
|
613
|
+
if (!peers || peers.length === 0) {
|
|
614
|
+
// Fallback: hardcoded mutual subtree subscriptions (backwards compat)
|
|
615
|
+
this.setupLegacyPeerSubscriptions();
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
this.pendingPeerRoutes = [];
|
|
620
|
+
|
|
621
|
+
for (const peer of peers) {
|
|
622
|
+
const fromAgent = this.roleAgentMap.get(peer.from);
|
|
623
|
+
const toAgent = this.roleAgentMap.get(peer.to);
|
|
624
|
+
|
|
625
|
+
if (!fromAgent || !toAgent) {
|
|
626
|
+
// One or both roles not yet spawned — defer
|
|
627
|
+
this.pendingPeerRoutes.push(peer);
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
this.wireSinglePeerRoute(peer, fromAgent, toAgent);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// If there are pending routes, set up lifecycle listener for deferred wiring
|
|
635
|
+
if (this.pendingPeerRoutes.length > 0) {
|
|
636
|
+
this.setupDeferredPeerWiring();
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Wire a single peer connection based on its `via` type.
|
|
642
|
+
*/
|
|
643
|
+
private wireSinglePeerRoute(
|
|
644
|
+
peer: PeerConnection,
|
|
645
|
+
fromAgent: AgentId,
|
|
646
|
+
toAgent: AgentId
|
|
647
|
+
): void {
|
|
648
|
+
const { messageRouter } = this.services;
|
|
649
|
+
|
|
650
|
+
switch (peer.via) {
|
|
651
|
+
case "direct":
|
|
652
|
+
// Directional: from receives status events from to's subtree
|
|
653
|
+
messageRouter.subscribe(fromAgent, { type: "subtree", target: toAgent });
|
|
654
|
+
break;
|
|
655
|
+
|
|
656
|
+
case "topic": {
|
|
657
|
+
// Both agents share a named topic
|
|
658
|
+
const topicName = `peer:${peer.from}:${peer.to}`;
|
|
659
|
+
messageRouter.subscribe(fromAgent, { type: "topic", target: topicName });
|
|
660
|
+
messageRouter.subscribe(toAgent, { type: "topic", target: topicName });
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
case "scope":
|
|
665
|
+
// from subscribes to to's role channel
|
|
666
|
+
messageRouter.subscribe(fromAgent, { type: "role", target: peer.to });
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// Store signal filter if specified
|
|
671
|
+
if (peer.signals && peer.signals.length > 0) {
|
|
672
|
+
const key = `${fromAgent}→${toAgent}`;
|
|
673
|
+
this.peerSignalFilters.set(key, peer.signals);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Legacy bidirectional subtree subscriptions between root and companions.
|
|
679
|
+
* Used when no `routing.peers` config is defined (backwards compat).
|
|
680
|
+
*/
|
|
681
|
+
private setupLegacyPeerSubscriptions(): void {
|
|
682
|
+
const { messageRouter } = this.services;
|
|
683
|
+
|
|
684
|
+
if (!this.rootAgentId) return;
|
|
685
|
+
for (const companionId of this.companionAgentIds) {
|
|
686
|
+
messageRouter.subscribe(this.rootAgentId as AgentId, { type: "subtree", target: companionId as AgentId });
|
|
687
|
+
messageRouter.subscribe(companionId as AgentId, { type: "subtree", target: this.rootAgentId as AgentId });
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Listen for agent spawns and wire pending peer routes when roles become available.
|
|
693
|
+
*/
|
|
694
|
+
private setupDeferredPeerWiring(): void {
|
|
695
|
+
const { agentManager } = this.services;
|
|
696
|
+
|
|
697
|
+
this.peerWiringUnsubscribe = agentManager.onLifecycleEvent((event) => {
|
|
698
|
+
if (event.type !== "spawned") return;
|
|
699
|
+
const role = event.agent.role;
|
|
700
|
+
if (!role) return;
|
|
701
|
+
|
|
702
|
+
// Update role↔agent mappings
|
|
703
|
+
this.roleAgentMap.set(role, event.agent.id as AgentId);
|
|
704
|
+
this.agentRoleMap.set(event.agent.id as AgentId, role);
|
|
705
|
+
|
|
706
|
+
// Try to wire any pending routes involving this role
|
|
707
|
+
const stillPending: PeerConnection[] = [];
|
|
708
|
+
for (const peer of this.pendingPeerRoutes) {
|
|
709
|
+
const fromAgent = this.roleAgentMap.get(peer.from);
|
|
710
|
+
const toAgent = this.roleAgentMap.get(peer.to);
|
|
711
|
+
|
|
712
|
+
if (fromAgent && toAgent) {
|
|
713
|
+
this.wireSinglePeerRoute(peer, fromAgent, toAgent);
|
|
714
|
+
} else {
|
|
715
|
+
stillPending.push(peer);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
this.pendingPeerRoutes = stillPending;
|
|
719
|
+
|
|
720
|
+
// All wired — unsubscribe
|
|
721
|
+
if (stillPending.length === 0 && this.peerWiringUnsubscribe) {
|
|
722
|
+
this.peerWiringUnsubscribe();
|
|
723
|
+
this.peerWiringUnsubscribe = undefined;
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
}
|