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,575 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail Full Agent E2E Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests that real agent spawning via agentManager.spawn() correctly
|
|
5
|
+
* creates mail conversations, wires the ConversationMap, and cleans
|
|
6
|
+
* up on terminate.
|
|
7
|
+
*
|
|
8
|
+
* REQUIRES: RUN_FULL_AGENT_TESTS=true environment variable (and authenticated Claude Code)
|
|
9
|
+
*
|
|
10
|
+
* Run with:
|
|
11
|
+
* RUN_FULL_AGENT_TESTS=true npx vitest run --config vitest.e2e.config.ts src/mail/__tests__/mail-full-agent.e2e.test.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
15
|
+
import { WebSocket } from "ws";
|
|
16
|
+
import * as fs from "fs";
|
|
17
|
+
import * as path from "path";
|
|
18
|
+
import * as os from "os";
|
|
19
|
+
import { execSync } from "child_process";
|
|
20
|
+
import { createEventStore, type EventStore } from "../../store/event-store.js";
|
|
21
|
+
import {
|
|
22
|
+
createAgentManager,
|
|
23
|
+
type AgentManager,
|
|
24
|
+
} from "../../agent/agent-manager.js";
|
|
25
|
+
import {
|
|
26
|
+
createTaskManager,
|
|
27
|
+
type TaskManager,
|
|
28
|
+
} from "../../task/task-manager.js";
|
|
29
|
+
import {
|
|
30
|
+
createMessageRouter,
|
|
31
|
+
type MessageRouter,
|
|
32
|
+
} from "../../router/message-router.js";
|
|
33
|
+
import {
|
|
34
|
+
createCombinedServer,
|
|
35
|
+
type CombinedServer,
|
|
36
|
+
type CombinedServerServices,
|
|
37
|
+
} from "../../server/combined-server.js";
|
|
38
|
+
import type { MailService } from "../mail-service.js";
|
|
39
|
+
import type { ConversationMap } from "../conversation-map.js";
|
|
40
|
+
import type { AgentId } from "../../store/types/index.js";
|
|
41
|
+
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────
|
|
43
|
+
// Test Configuration
|
|
44
|
+
// ─────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
const RUN_FULL_AGENT = !!process.env.RUN_FULL_AGENT_TESTS;
|
|
47
|
+
const testFn = RUN_FULL_AGENT ? it : it.skip;
|
|
48
|
+
|
|
49
|
+
const TIMEOUT = {
|
|
50
|
+
SPAWN: 60000,
|
|
51
|
+
MULTI_SPAWN: 180000,
|
|
52
|
+
HIERARCHY: 120000,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function log(message: string): void {
|
|
56
|
+
console.log(`[Mail E2E] ${message}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getRandomPort(): number {
|
|
60
|
+
return 10000 + Math.floor(Math.random() * 50000);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create an isolated test git repo.
|
|
65
|
+
*/
|
|
66
|
+
function createTestRepo(): { path: string; cleanup: () => void } {
|
|
67
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mail-agent-e2e-"));
|
|
68
|
+
const repoPath = path.join(tmpDir, "test-repo");
|
|
69
|
+
fs.mkdirSync(repoPath);
|
|
70
|
+
execSync("git init", { cwd: repoPath, stdio: "pipe" });
|
|
71
|
+
execSync('git config user.email "test@test.com"', { cwd: repoPath, stdio: "pipe" });
|
|
72
|
+
execSync('git config user.name "Test User"', { cwd: repoPath, stdio: "pipe" });
|
|
73
|
+
fs.writeFileSync(path.join(repoPath, "README.md"), "# Test Repo\n");
|
|
74
|
+
execSync("git add -A", { cwd: repoPath, stdio: "pipe" });
|
|
75
|
+
execSync('git commit -m "Initial commit"', { cwd: repoPath, stdio: "pipe" });
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
path: repoPath,
|
|
79
|
+
cleanup: () => fs.rmSync(tmpDir, { recursive: true, force: true }),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ─────────────────────────────────────────────────────────────────
|
|
84
|
+
// ACP WebSocket Client
|
|
85
|
+
// ─────────────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
interface JsonRpcMessage {
|
|
88
|
+
jsonrpc: "2.0";
|
|
89
|
+
id?: number;
|
|
90
|
+
method?: string;
|
|
91
|
+
params?: unknown;
|
|
92
|
+
result?: unknown;
|
|
93
|
+
error?: { code: number; message: string; data?: unknown };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
class ACPTestClient {
|
|
97
|
+
private ws!: WebSocket;
|
|
98
|
+
private waiters: Map<number, (msg: JsonRpcMessage) => void> = new Map();
|
|
99
|
+
private nextId = 1;
|
|
100
|
+
private url: string;
|
|
101
|
+
|
|
102
|
+
constructor(url: string) {
|
|
103
|
+
this.url = url;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async connect(): Promise<void> {
|
|
107
|
+
this.ws = new WebSocket(this.url);
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
const timeout = setTimeout(() => reject(new Error("Connection timeout")), 10000);
|
|
110
|
+
this.ws.on("open", () => { clearTimeout(timeout); resolve(); });
|
|
111
|
+
this.ws.on("error", (err) => { clearTimeout(timeout); reject(err); });
|
|
112
|
+
this.ws.on("message", (data: Buffer) => {
|
|
113
|
+
try {
|
|
114
|
+
const msg = JSON.parse(data.toString()) as JsonRpcMessage;
|
|
115
|
+
if (msg.id !== undefined) {
|
|
116
|
+
const waiter = this.waiters.get(msg.id);
|
|
117
|
+
if (waiter) {
|
|
118
|
+
this.waiters.delete(msg.id);
|
|
119
|
+
waiter(msg);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch { /* ignore */ }
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async request(method: string, params?: unknown, timeoutMs = 30000): Promise<JsonRpcMessage> {
|
|
128
|
+
const id = this.nextId++;
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const timeout = setTimeout(() => {
|
|
131
|
+
this.waiters.delete(id);
|
|
132
|
+
reject(new Error(`Timeout waiting for ${method}`));
|
|
133
|
+
}, timeoutMs);
|
|
134
|
+
this.waiters.set(id, (response) => {
|
|
135
|
+
clearTimeout(timeout);
|
|
136
|
+
resolve(response);
|
|
137
|
+
});
|
|
138
|
+
this.ws.send(JSON.stringify({ jsonrpc: "2.0", method, params, id }));
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async initialize(): Promise<JsonRpcMessage> {
|
|
143
|
+
return this.request("initialize", {
|
|
144
|
+
protocolVersion: 1,
|
|
145
|
+
capabilities: {},
|
|
146
|
+
clientInfo: { name: "mail-e2e-test", version: "1.0.0" },
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async newSession(params: { cwd?: string } = {}): Promise<JsonRpcMessage> {
|
|
151
|
+
return this.request("session/new", { mcpServers: [], ...params }, 60000);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async spawnAgent(parentId: string, task: string): Promise<JsonRpcMessage> {
|
|
155
|
+
return this.request("_macro/spawnAgent", {
|
|
156
|
+
task_description: task,
|
|
157
|
+
parentId,
|
|
158
|
+
}, 60000);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
close(): void {
|
|
162
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
163
|
+
this.ws.close();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ─────────────────────────────────────────────────────────────────
|
|
169
|
+
// Tests
|
|
170
|
+
// ─────────────────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
describe("Mail Full Agent E2E", () => {
|
|
173
|
+
let eventStore: EventStore;
|
|
174
|
+
let agentManager: AgentManager;
|
|
175
|
+
let taskManager: TaskManager;
|
|
176
|
+
let messageRouter: MessageRouter;
|
|
177
|
+
let server: CombinedServer;
|
|
178
|
+
let mailService: MailService;
|
|
179
|
+
let conversationMap: ConversationMap;
|
|
180
|
+
let testRepo: { path: string; cleanup: () => void };
|
|
181
|
+
let testPort: number;
|
|
182
|
+
const clients: ACPTestClient[] = [];
|
|
183
|
+
|
|
184
|
+
beforeEach(async () => {
|
|
185
|
+
if (!RUN_FULL_AGENT) {
|
|
186
|
+
log("Skipping: RUN_FULL_AGENT_TESTS not set");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
testRepo = createTestRepo();
|
|
191
|
+
testPort = getRandomPort();
|
|
192
|
+
|
|
193
|
+
// File-based EventStore (required for MCP subprocess access)
|
|
194
|
+
const instanceId = `mail-e2e-${Date.now()}`;
|
|
195
|
+
eventStore = await createEventStore({
|
|
196
|
+
instanceId,
|
|
197
|
+
baseDir: testRepo.path,
|
|
198
|
+
});
|
|
199
|
+
messageRouter = createMessageRouter(eventStore);
|
|
200
|
+
taskManager = createTaskManager(eventStore);
|
|
201
|
+
agentManager = createAgentManager(eventStore, messageRouter, {
|
|
202
|
+
defaultPermissionMode: "auto-approve",
|
|
203
|
+
defaultCwd: testRepo.path,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// CombinedServer auto-wires: mailService, conversationMap, turnRecorder
|
|
207
|
+
const services: CombinedServerServices = {
|
|
208
|
+
eventStore,
|
|
209
|
+
agentManager,
|
|
210
|
+
taskManager,
|
|
211
|
+
messageRouter,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
server = createCombinedServer(services, {
|
|
215
|
+
port: testPort,
|
|
216
|
+
host: "localhost",
|
|
217
|
+
defaultCwd: testRepo.path,
|
|
218
|
+
});
|
|
219
|
+
await server.start();
|
|
220
|
+
|
|
221
|
+
// Get the auto-wired mail services
|
|
222
|
+
mailService = server.mailService!;
|
|
223
|
+
conversationMap = server.conversationMap!;
|
|
224
|
+
|
|
225
|
+
expect(mailService).toBeDefined();
|
|
226
|
+
expect(conversationMap).toBeDefined();
|
|
227
|
+
|
|
228
|
+
log(`Server started on port ${testPort}`);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
afterEach(async () => {
|
|
232
|
+
if (!RUN_FULL_AGENT) return;
|
|
233
|
+
|
|
234
|
+
for (const client of clients) {
|
|
235
|
+
client.close();
|
|
236
|
+
}
|
|
237
|
+
clients.length = 0;
|
|
238
|
+
|
|
239
|
+
// Terminate all agents
|
|
240
|
+
try {
|
|
241
|
+
const heads = agentManager.listHeadManagers();
|
|
242
|
+
for (const head of heads) {
|
|
243
|
+
try {
|
|
244
|
+
await agentManager.terminate(head.id, "test_cleanup");
|
|
245
|
+
} catch { /* ignore */ }
|
|
246
|
+
}
|
|
247
|
+
} catch { /* ignore */ }
|
|
248
|
+
|
|
249
|
+
await server?.stop().catch(() => {});
|
|
250
|
+
await agentManager?.close();
|
|
251
|
+
await eventStore?.close();
|
|
252
|
+
testRepo?.cleanup();
|
|
253
|
+
log("Cleanup complete");
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe("Spawn creates mail conversations", () => {
|
|
257
|
+
testFn(
|
|
258
|
+
"creates task conversation when spawning child agent",
|
|
259
|
+
async () => {
|
|
260
|
+
const client = new ACPTestClient(`ws://localhost:${testPort}/acp`);
|
|
261
|
+
clients.push(client);
|
|
262
|
+
|
|
263
|
+
await client.connect();
|
|
264
|
+
await client.initialize();
|
|
265
|
+
|
|
266
|
+
// Create head manager session
|
|
267
|
+
const sessionResult = await client.newSession({ cwd: testRepo.path });
|
|
268
|
+
expect(sessionResult.error).toBeUndefined();
|
|
269
|
+
log("Head manager session created");
|
|
270
|
+
|
|
271
|
+
const headManagers = agentManager.listHeadManagers();
|
|
272
|
+
expect(headManagers.length).toBeGreaterThanOrEqual(1);
|
|
273
|
+
const headId = headManagers[0].id;
|
|
274
|
+
log(`Head manager: ${headId}`);
|
|
275
|
+
|
|
276
|
+
// Verify head manager has a session conversation in conversationMap
|
|
277
|
+
const sessionConvId = conversationMap.getSessionConversation(headId);
|
|
278
|
+
// Note: session conversation is created by POST /api/init, not by ACP session/new
|
|
279
|
+
// The ACP path doesn't create session conversations — that's fine for this test
|
|
280
|
+
|
|
281
|
+
// Spawn child agent
|
|
282
|
+
const spawnResult = await client.spawnAgent(headId, "Worker: process test data");
|
|
283
|
+
expect(spawnResult.error).toBeUndefined();
|
|
284
|
+
const childId = (spawnResult.result as any).agentId;
|
|
285
|
+
expect(childId).toBeDefined();
|
|
286
|
+
log(`Child spawned: ${childId}`);
|
|
287
|
+
|
|
288
|
+
// Verify task conversation was created for child
|
|
289
|
+
const childConvId = conversationMap.getAgentConversation(childId);
|
|
290
|
+
expect(childConvId).toBeDefined();
|
|
291
|
+
log(`Child task conversation: ${childConvId}`);
|
|
292
|
+
|
|
293
|
+
// Verify conversation properties
|
|
294
|
+
const childConv = mailService.getConversation(childConvId!);
|
|
295
|
+
expect(childConv).not.toBeNull();
|
|
296
|
+
expect(childConv!.type).toBe("task");
|
|
297
|
+
expect(childConv!.status).toBe("active");
|
|
298
|
+
expect(childConv!.subject).toBe("Worker: process test data");
|
|
299
|
+
log(`Conversation type=${childConv!.type}, status=${childConv!.status}`);
|
|
300
|
+
|
|
301
|
+
// Verify participants: parent + child
|
|
302
|
+
const participants = mailService.listParticipants(childConvId!);
|
|
303
|
+
expect(participants).toHaveLength(2);
|
|
304
|
+
const participantIds = participants.map((p) => p.id);
|
|
305
|
+
expect(participantIds).toContain(headId);
|
|
306
|
+
expect(participantIds).toContain(childId);
|
|
307
|
+
|
|
308
|
+
// Verify roles
|
|
309
|
+
const parentParticipant = participants.find((p) => p.id === headId);
|
|
310
|
+
const childParticipant = participants.find((p) => p.id === childId);
|
|
311
|
+
expect(parentParticipant!.role).toBe("initiator");
|
|
312
|
+
expect(childParticipant!.role).toBe("worker");
|
|
313
|
+
log("Participants verified: initiator + worker");
|
|
314
|
+
},
|
|
315
|
+
{ timeout: TIMEOUT.SPAWN },
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
testFn(
|
|
319
|
+
"creates conversation tree with correct parentConversationId for 3-level hierarchy",
|
|
320
|
+
async () => {
|
|
321
|
+
const client = new ACPTestClient(`ws://localhost:${testPort}/acp`);
|
|
322
|
+
clients.push(client);
|
|
323
|
+
|
|
324
|
+
await client.connect();
|
|
325
|
+
await client.initialize();
|
|
326
|
+
|
|
327
|
+
// Level 0: head manager
|
|
328
|
+
const sessionResult = await client.newSession({ cwd: testRepo.path });
|
|
329
|
+
expect(sessionResult.error).toBeUndefined();
|
|
330
|
+
const headId = agentManager.listHeadManagers()[0].id;
|
|
331
|
+
log(`Level 0 (Head): ${headId}`);
|
|
332
|
+
|
|
333
|
+
// Level 1: team lead
|
|
334
|
+
const level1Result = await client.spawnAgent(headId, "Team Lead: coordinate workers");
|
|
335
|
+
expect(level1Result.error).toBeUndefined();
|
|
336
|
+
const level1Id = (level1Result.result as any).agentId;
|
|
337
|
+
log(`Level 1 (Lead): ${level1Id}`);
|
|
338
|
+
|
|
339
|
+
// Level 2: worker (child of Level 1)
|
|
340
|
+
const level2Result = await client.spawnAgent(level1Id, "Worker: execute task");
|
|
341
|
+
expect(level2Result.error).toBeUndefined();
|
|
342
|
+
const level2Id = (level2Result.result as any).agentId;
|
|
343
|
+
log(`Level 2 (Worker): ${level2Id}`);
|
|
344
|
+
|
|
345
|
+
// Verify conversation chain
|
|
346
|
+
const level1ConvId = conversationMap.getAgentConversation(level1Id)!;
|
|
347
|
+
const level2ConvId = conversationMap.getAgentConversation(level2Id)!;
|
|
348
|
+
expect(level1ConvId).toBeDefined();
|
|
349
|
+
expect(level2ConvId).toBeDefined();
|
|
350
|
+
|
|
351
|
+
const level1Conv = mailService.getConversation(level1ConvId);
|
|
352
|
+
const level2Conv = mailService.getConversation(level2ConvId);
|
|
353
|
+
|
|
354
|
+
// Level 2's parent conversation should be Level 1's task conversation
|
|
355
|
+
expect(level2Conv!.parentConversationId).toBe(level1ConvId);
|
|
356
|
+
log(`Level 2 parentConversationId → Level 1 task conv: correct`);
|
|
357
|
+
|
|
358
|
+
// Level 1's parent conversation should be head manager's conversation (if it exists)
|
|
359
|
+
const headConvId =
|
|
360
|
+
conversationMap.getAgentConversation(headId) ??
|
|
361
|
+
conversationMap.getSessionConversation(headId);
|
|
362
|
+
if (headConvId) {
|
|
363
|
+
expect(level1Conv!.parentConversationId).toBe(headConvId);
|
|
364
|
+
log(`Level 1 parentConversationId → Head conv: correct`);
|
|
365
|
+
} else {
|
|
366
|
+
// Head manager has no conversation (ACP path doesn't create one)
|
|
367
|
+
expect(level1Conv!.parentConversationId).toBeUndefined();
|
|
368
|
+
log(`Level 1 parentConversationId → undefined (no head conv): correct`);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Verify total conversations
|
|
372
|
+
const allConvs = mailService.listConversations({ type: "task" });
|
|
373
|
+
expect(allConvs.length).toBeGreaterThanOrEqual(2);
|
|
374
|
+
log(`Total task conversations: ${allConvs.length}`);
|
|
375
|
+
},
|
|
376
|
+
{ timeout: TIMEOUT.HIERARCHY },
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
testFn(
|
|
380
|
+
"creates separate task conversations for multiple children",
|
|
381
|
+
async () => {
|
|
382
|
+
const client = new ACPTestClient(`ws://localhost:${testPort}/acp`);
|
|
383
|
+
clients.push(client);
|
|
384
|
+
|
|
385
|
+
await client.connect();
|
|
386
|
+
await client.initialize();
|
|
387
|
+
|
|
388
|
+
await client.newSession({ cwd: testRepo.path });
|
|
389
|
+
const headId = agentManager.listHeadManagers()[0].id;
|
|
390
|
+
|
|
391
|
+
// Spawn two children
|
|
392
|
+
const child1Result = await client.spawnAgent(headId, "Worker A: first task");
|
|
393
|
+
const child2Result = await client.spawnAgent(headId, "Worker B: second task");
|
|
394
|
+
expect(child1Result.error).toBeUndefined();
|
|
395
|
+
expect(child2Result.error).toBeUndefined();
|
|
396
|
+
|
|
397
|
+
const child1Id = (child1Result.result as any).agentId;
|
|
398
|
+
const child2Id = (child2Result.result as any).agentId;
|
|
399
|
+
log(`Child 1: ${child1Id}, Child 2: ${child2Id}`);
|
|
400
|
+
|
|
401
|
+
// Verify separate conversations
|
|
402
|
+
const conv1Id = conversationMap.getAgentConversation(child1Id)!;
|
|
403
|
+
const conv2Id = conversationMap.getAgentConversation(child2Id)!;
|
|
404
|
+
expect(conv1Id).toBeDefined();
|
|
405
|
+
expect(conv2Id).toBeDefined();
|
|
406
|
+
expect(conv1Id).not.toBe(conv2Id);
|
|
407
|
+
|
|
408
|
+
const conv1 = mailService.getConversation(conv1Id);
|
|
409
|
+
const conv2 = mailService.getConversation(conv2Id);
|
|
410
|
+
expect(conv1!.subject).toBe("Worker A: first task");
|
|
411
|
+
expect(conv2!.subject).toBe("Worker B: second task");
|
|
412
|
+
|
|
413
|
+
// Both should have same parent conversation
|
|
414
|
+
expect(conv1!.parentConversationId).toBe(conv2!.parentConversationId);
|
|
415
|
+
log("Both children share same parentConversationId");
|
|
416
|
+
|
|
417
|
+
// Each conversation should have 2 participants (parent + child)
|
|
418
|
+
expect(mailService.listParticipants(conv1Id)).toHaveLength(2);
|
|
419
|
+
expect(mailService.listParticipants(conv2Id)).toHaveLength(2);
|
|
420
|
+
log("Each conversation has 2 participants");
|
|
421
|
+
},
|
|
422
|
+
{ timeout: TIMEOUT.MULTI_SPAWN },
|
|
423
|
+
);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
describe("Terminate cleans up mail conversations", () => {
|
|
427
|
+
testFn(
|
|
428
|
+
"closes task conversation on agent terminate",
|
|
429
|
+
async () => {
|
|
430
|
+
const client = new ACPTestClient(`ws://localhost:${testPort}/acp`);
|
|
431
|
+
clients.push(client);
|
|
432
|
+
|
|
433
|
+
await client.connect();
|
|
434
|
+
await client.initialize();
|
|
435
|
+
await client.newSession({ cwd: testRepo.path });
|
|
436
|
+
const headId = agentManager.listHeadManagers()[0].id;
|
|
437
|
+
|
|
438
|
+
// Spawn child
|
|
439
|
+
const childResult = await client.spawnAgent(headId, "Ephemeral worker");
|
|
440
|
+
const childId = (childResult.result as any).agentId;
|
|
441
|
+
const childConvId = conversationMap.getAgentConversation(childId)!;
|
|
442
|
+
|
|
443
|
+
// Verify conversation is active
|
|
444
|
+
expect(mailService.getConversation(childConvId)!.status).toBe("active");
|
|
445
|
+
log(`Child conv ${childConvId} is active`);
|
|
446
|
+
|
|
447
|
+
// Terminate the child
|
|
448
|
+
await agentManager.terminate(childId, "completed");
|
|
449
|
+
log(`Child ${childId} terminated`);
|
|
450
|
+
|
|
451
|
+
// Verify conversation is closed
|
|
452
|
+
const closedConv = mailService.getConversation(childConvId);
|
|
453
|
+
expect(closedConv!.status).toBe("completed");
|
|
454
|
+
log(`Child conv status: ${closedConv!.status}`);
|
|
455
|
+
|
|
456
|
+
// Verify agent removed from conversationMap
|
|
457
|
+
expect(conversationMap.getAgentConversation(childId)).toBeUndefined();
|
|
458
|
+
log("Agent removed from conversationMap");
|
|
459
|
+
},
|
|
460
|
+
{ timeout: TIMEOUT.SPAWN },
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
testFn(
|
|
464
|
+
"cascade terminate closes all descendant conversations",
|
|
465
|
+
async () => {
|
|
466
|
+
const client = new ACPTestClient(`ws://localhost:${testPort}/acp`);
|
|
467
|
+
clients.push(client);
|
|
468
|
+
|
|
469
|
+
await client.connect();
|
|
470
|
+
await client.initialize();
|
|
471
|
+
await client.newSession({ cwd: testRepo.path });
|
|
472
|
+
const headId = agentManager.listHeadManagers()[0].id;
|
|
473
|
+
|
|
474
|
+
// Build 3-level hierarchy
|
|
475
|
+
const level1Result = await client.spawnAgent(headId, "Middle manager");
|
|
476
|
+
const level1Id = (level1Result.result as any).agentId;
|
|
477
|
+
const level1ConvId = conversationMap.getAgentConversation(level1Id)!;
|
|
478
|
+
|
|
479
|
+
const level2Result = await client.spawnAgent(level1Id, "Leaf worker");
|
|
480
|
+
const level2Id = (level2Result.result as any).agentId;
|
|
481
|
+
const level2ConvId = conversationMap.getAgentConversation(level2Id)!;
|
|
482
|
+
|
|
483
|
+
// All active
|
|
484
|
+
expect(mailService.getConversation(level1ConvId)!.status).toBe("active");
|
|
485
|
+
expect(mailService.getConversation(level2ConvId)!.status).toBe("active");
|
|
486
|
+
log("All conversations active");
|
|
487
|
+
|
|
488
|
+
// Terminate head manager (cascade terminates level1 and level2)
|
|
489
|
+
await agentManager.terminate(headId, "completed");
|
|
490
|
+
log("Head manager terminated (cascade)");
|
|
491
|
+
|
|
492
|
+
// Wait a moment for cascade to complete
|
|
493
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
494
|
+
|
|
495
|
+
// Both descendant conversations should be closed
|
|
496
|
+
expect(mailService.getConversation(level1ConvId)!.status).not.toBe("active");
|
|
497
|
+
expect(mailService.getConversation(level2ConvId)!.status).not.toBe("active");
|
|
498
|
+
log(`Level 1 conv: ${mailService.getConversation(level1ConvId)!.status}`);
|
|
499
|
+
log(`Level 2 conv: ${mailService.getConversation(level2ConvId)!.status}`);
|
|
500
|
+
|
|
501
|
+
// Agents removed from conversationMap
|
|
502
|
+
expect(conversationMap.getAgentConversation(level1Id)).toBeUndefined();
|
|
503
|
+
expect(conversationMap.getAgentConversation(level2Id)).toBeUndefined();
|
|
504
|
+
log("All agents removed from conversationMap");
|
|
505
|
+
},
|
|
506
|
+
{ timeout: TIMEOUT.HIERARCHY },
|
|
507
|
+
);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
describe("Mail conversations visible via MAP protocol", () => {
|
|
511
|
+
testFn(
|
|
512
|
+
"task conversations created by spawn appear in mail/list",
|
|
513
|
+
async () => {
|
|
514
|
+
// ACP client for spawning
|
|
515
|
+
const acpClient = new ACPTestClient(`ws://localhost:${testPort}/acp`);
|
|
516
|
+
clients.push(acpClient);
|
|
517
|
+
|
|
518
|
+
await acpClient.connect();
|
|
519
|
+
await acpClient.initialize();
|
|
520
|
+
await acpClient.newSession({ cwd: testRepo.path });
|
|
521
|
+
const headId = agentManager.listHeadManagers()[0].id;
|
|
522
|
+
|
|
523
|
+
// Spawn a child
|
|
524
|
+
const childResult = await acpClient.spawnAgent(headId, "Visible worker");
|
|
525
|
+
expect(childResult.error).toBeUndefined();
|
|
526
|
+
const childId = (childResult.result as any).agentId;
|
|
527
|
+
log(`Child spawned: ${childId}`);
|
|
528
|
+
|
|
529
|
+
// MAP client to query conversations
|
|
530
|
+
const mapWs = new WebSocket(`ws://localhost:${testPort}/map`);
|
|
531
|
+
await new Promise<void>((resolve, reject) => {
|
|
532
|
+
const timeout = setTimeout(() => reject(new Error("MAP timeout")), 5000);
|
|
533
|
+
mapWs.on("open", () => { clearTimeout(timeout); resolve(); });
|
|
534
|
+
mapWs.on("error", (e) => { clearTimeout(timeout); reject(e); });
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
// Send mail/list via MAP
|
|
538
|
+
const listId = 1;
|
|
539
|
+
mapWs.send(JSON.stringify({
|
|
540
|
+
jsonrpc: "2.0",
|
|
541
|
+
method: "mail/list",
|
|
542
|
+
params: { type: "task" },
|
|
543
|
+
id: listId,
|
|
544
|
+
}));
|
|
545
|
+
|
|
546
|
+
const response = await new Promise<any>((resolve, reject) => {
|
|
547
|
+
const timeout = setTimeout(() => reject(new Error("mail/list timeout")), 10000);
|
|
548
|
+
mapWs.on("message", (data: Buffer) => {
|
|
549
|
+
const msg = JSON.parse(data.toString());
|
|
550
|
+
if (msg.id === listId) {
|
|
551
|
+
clearTimeout(timeout);
|
|
552
|
+
resolve(msg);
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
expect(response.error).toBeUndefined();
|
|
558
|
+
expect(response.result.conversations.length).toBeGreaterThanOrEqual(1);
|
|
559
|
+
|
|
560
|
+
// Find our child's conversation
|
|
561
|
+
const childConvId = conversationMap.getAgentConversation(childId);
|
|
562
|
+
const found = response.result.conversations.find(
|
|
563
|
+
(c: any) => c.id === childConvId,
|
|
564
|
+
);
|
|
565
|
+
expect(found).toBeDefined();
|
|
566
|
+
expect(found.type).toBe("task");
|
|
567
|
+
expect(found.status).toBe("active");
|
|
568
|
+
log(`Task conversation found via MAP mail/list`);
|
|
569
|
+
|
|
570
|
+
mapWs.close();
|
|
571
|
+
},
|
|
572
|
+
{ timeout: TIMEOUT.SPAWN },
|
|
573
|
+
);
|
|
574
|
+
});
|
|
575
|
+
});
|