macro-agent 0.0.11 → 0.0.13
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 +6 -0
- package/.sudocode/specs.jsonl +7 -0
- package/CLAUDE.md +110 -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 +25 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +93 -7
- 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-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.map +1 -1
- package/dist/api/server.js +95 -0
- package/dist/api/server.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/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 +1 -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/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 +11 -2
- package/dist/mcp/tools/done.d.ts.map +1 -1
- package/dist/mcp/tools/done.js +15 -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/message-router.d.ts +41 -0
- package/dist/router/message-router.d.ts.map +1 -1
- package/dist/router/message-router.js +136 -5
- package/dist/router/message-router.js.map +1 -1
- package/dist/store/event-store.d.ts +8 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +120 -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/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 +1 -0
- package/dist/store/types/index.d.ts.map +1 -1
- package/dist/store/types/index.js +1 -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/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/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 +158 -6
- package/src/agent/types.ts +27 -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/server.ts +110 -0
- 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/map/adapter/__tests__/extensions.test.ts +359 -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 +1 -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/mcp/mcp-server.ts +67 -0
- package/src/mcp/tools/claim_task.ts +86 -0
- package/src/mcp/tools/done.ts +24 -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/__tests__/message-router.test.ts +561 -0
- package/src/router/message-router.ts +223 -6
- package/src/store/event-store.ts +151 -3
- package/src/store/types/agents.ts +1 -1
- package/src/store/types/events.ts +2 -1
- package/src/store/types/index.ts +1 -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/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/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 -111
- package/references/multi-agent-protocol/.sudocode/specs.jsonl +0 -13
- 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 -496
- 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/docs/09-authentication.md +0 -680
- package/references/multi-agent-protocol/docs/10-mail-protocol.md +0 -553
- package/references/multi-agent-protocol/docs/agent-iam-integration.md +0 -877
- package/references/multi-agent-protocol/docs/agentic-mesh-integration-draft.md +0 -459
- package/references/multi-agent-protocol/docs/git-transport-draft.md +0 -251
- package/references/multi-agent-protocol/docs-site/Gemfile +0 -22
- package/references/multi-agent-protocol/docs-site/README.md +0 -82
- package/references/multi-agent-protocol/docs-site/_config.yml +0 -91
- package/references/multi-agent-protocol/docs-site/_includes/head_custom.html +0 -20
- package/references/multi-agent-protocol/docs-site/_sass/color_schemes/map.scss +0 -42
- package/references/multi-agent-protocol/docs-site/_sass/custom/custom.scss +0 -34
- package/references/multi-agent-protocol/docs-site/examples/full-integration.md +0 -510
- package/references/multi-agent-protocol/docs-site/examples/index.md +0 -138
- package/references/multi-agent-protocol/docs-site/examples/simple-chat.md +0 -282
- package/references/multi-agent-protocol/docs-site/examples/task-queue.md +0 -399
- package/references/multi-agent-protocol/docs-site/getting-started/index.md +0 -98
- package/references/multi-agent-protocol/docs-site/getting-started/installation.md +0 -219
- package/references/multi-agent-protocol/docs-site/getting-started/overview.md +0 -172
- package/references/multi-agent-protocol/docs-site/getting-started/quickstart.md +0 -237
- package/references/multi-agent-protocol/docs-site/index.md +0 -136
- package/references/multi-agent-protocol/docs-site/protocol/authentication.md +0 -391
- package/references/multi-agent-protocol/docs-site/protocol/connection-model.md +0 -376
- package/references/multi-agent-protocol/docs-site/protocol/design.md +0 -284
- package/references/multi-agent-protocol/docs-site/protocol/error-handling.md +0 -312
- package/references/multi-agent-protocol/docs-site/protocol/federation.md +0 -449
- package/references/multi-agent-protocol/docs-site/protocol/index.md +0 -129
- package/references/multi-agent-protocol/docs-site/protocol/permissions.md +0 -398
- package/references/multi-agent-protocol/docs-site/protocol/streaming.md +0 -353
- package/references/multi-agent-protocol/docs-site/protocol/wire-protocol.md +0 -369
- package/references/multi-agent-protocol/docs-site/sdk/api/agent.md +0 -357
- package/references/multi-agent-protocol/docs-site/sdk/api/client.md +0 -380
- package/references/multi-agent-protocol/docs-site/sdk/api/index.md +0 -62
- package/references/multi-agent-protocol/docs-site/sdk/api/server.md +0 -453
- package/references/multi-agent-protocol/docs-site/sdk/api/types.md +0 -468
- package/references/multi-agent-protocol/docs-site/sdk/guides/agent.md +0 -375
- package/references/multi-agent-protocol/docs-site/sdk/guides/authentication.md +0 -405
- package/references/multi-agent-protocol/docs-site/sdk/guides/client.md +0 -352
- package/references/multi-agent-protocol/docs-site/sdk/guides/index.md +0 -89
- package/references/multi-agent-protocol/docs-site/sdk/guides/server.md +0 -360
- package/references/multi-agent-protocol/docs-site/sdk/guides/testing.md +0 -446
- package/references/multi-agent-protocol/docs-site/sdk/guides/transports.md +0 -363
- package/references/multi-agent-protocol/docs-site/sdk/index.md +0 -206
- package/references/multi-agent-protocol/package-lock.json +0 -3886
- package/references/multi-agent-protocol/package.json +0 -56
- package/references/multi-agent-protocol/schema/meta.json +0 -467
- package/references/multi-agent-protocol/schema/schema.json +0 -2558
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session persistence and recovery tests
|
|
3
|
+
*
|
|
4
|
+
* Tests that session lifecycle events are persisted to the EventStore
|
|
5
|
+
* and that SessionMapper can recover its state from persisted sessions.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
9
|
+
import { SessionMapper } from "../session-mapper.js";
|
|
10
|
+
import { createEventStore, type EventStore } from "../../store/event-store.js";
|
|
11
|
+
|
|
12
|
+
describe("Session Persistence", () => {
|
|
13
|
+
let eventStore: EventStore;
|
|
14
|
+
let mapper: SessionMapper;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
eventStore = await createEventStore({ inMemory: true });
|
|
18
|
+
mapper = new SessionMapper(eventStore);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(async () => {
|
|
22
|
+
await eventStore.close();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("session lifecycle events", () => {
|
|
26
|
+
it("should emit session created event on createMapping", () => {
|
|
27
|
+
mapper.createMapping("session-1", "agent-head");
|
|
28
|
+
|
|
29
|
+
const session = eventStore.getSession("session-1");
|
|
30
|
+
expect(session).not.toBeNull();
|
|
31
|
+
expect(session!.id).toBe("session-1");
|
|
32
|
+
expect(session!.head_manager_id).toBe("agent-head");
|
|
33
|
+
expect(session!.current_agent_id).toBe("agent-head");
|
|
34
|
+
expect(session!.state).toBe("active");
|
|
35
|
+
expect(session!.created_at).toBeGreaterThan(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("should emit session mounted event on mount", () => {
|
|
39
|
+
mapper.createMapping("session-1", "agent-head");
|
|
40
|
+
mapper.mount("session-1", "agent-child");
|
|
41
|
+
|
|
42
|
+
const session = eventStore.getSession("session-1");
|
|
43
|
+
expect(session!.state).toBe("mounted");
|
|
44
|
+
expect(session!.current_agent_id).toBe("agent-child");
|
|
45
|
+
expect(session!.head_manager_id).toBe("agent-head");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should emit session unmounted event on unmount", () => {
|
|
49
|
+
mapper.createMapping("session-1", "agent-head");
|
|
50
|
+
mapper.mount("session-1", "agent-child");
|
|
51
|
+
mapper.unmount("session-1");
|
|
52
|
+
|
|
53
|
+
const session = eventStore.getSession("session-1");
|
|
54
|
+
expect(session!.state).toBe("active");
|
|
55
|
+
expect(session!.current_agent_id).toBe("agent-head");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("should emit unmounted when mounting back to head manager", () => {
|
|
59
|
+
mapper.createMapping("session-1", "agent-head");
|
|
60
|
+
mapper.mount("session-1", "agent-child");
|
|
61
|
+
mapper.mount("session-1", "agent-head");
|
|
62
|
+
|
|
63
|
+
const session = eventStore.getSession("session-1");
|
|
64
|
+
expect(session!.state).toBe("active");
|
|
65
|
+
expect(session!.current_agent_id).toBe("agent-head");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should emit session closed event on removeMapping", () => {
|
|
69
|
+
mapper.createMapping("session-1", "agent-head");
|
|
70
|
+
mapper.removeMapping("session-1");
|
|
71
|
+
|
|
72
|
+
const session = eventStore.getSession("session-1");
|
|
73
|
+
expect(session!.state).toBe("closed");
|
|
74
|
+
expect(session!.closed_at).toBeGreaterThan(0);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should not emit close for non-existent session", () => {
|
|
78
|
+
mapper.removeMapping("non-existent");
|
|
79
|
+
|
|
80
|
+
const session = eventStore.getSession("non-existent");
|
|
81
|
+
expect(session).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should track multiple sessions independently", () => {
|
|
85
|
+
mapper.createMapping("session-1", "agent-1");
|
|
86
|
+
mapper.createMapping("session-2", "agent-2");
|
|
87
|
+
mapper.mount("session-1", "agent-child");
|
|
88
|
+
|
|
89
|
+
const s1 = eventStore.getSession("session-1");
|
|
90
|
+
const s2 = eventStore.getSession("session-2");
|
|
91
|
+
|
|
92
|
+
expect(s1!.state).toBe("mounted");
|
|
93
|
+
expect(s2!.state).toBe("active");
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe("listSessions", () => {
|
|
98
|
+
it("should list sessions by state", () => {
|
|
99
|
+
mapper.createMapping("session-1", "agent-1");
|
|
100
|
+
mapper.createMapping("session-2", "agent-2");
|
|
101
|
+
mapper.mount("session-1", "agent-child");
|
|
102
|
+
|
|
103
|
+
const active = eventStore.listSessions({ state: "active" });
|
|
104
|
+
const mounted = eventStore.listSessions({ state: "mounted" });
|
|
105
|
+
|
|
106
|
+
expect(active).toHaveLength(1);
|
|
107
|
+
expect(active[0].id).toBe("session-2");
|
|
108
|
+
expect(mounted).toHaveLength(1);
|
|
109
|
+
expect(mounted[0].id).toBe("session-1");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should list sessions by agent", () => {
|
|
113
|
+
mapper.createMapping("session-1", "agent-1");
|
|
114
|
+
mapper.createMapping("session-2", "agent-2");
|
|
115
|
+
|
|
116
|
+
const sessions = eventStore.listSessions({ agent_id: "agent-1" });
|
|
117
|
+
expect(sessions).toHaveLength(1);
|
|
118
|
+
expect(sessions[0].id).toBe("session-1");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should filter closed sessions", () => {
|
|
122
|
+
mapper.createMapping("session-1", "agent-1");
|
|
123
|
+
mapper.createMapping("session-2", "agent-2");
|
|
124
|
+
mapper.removeMapping("session-1");
|
|
125
|
+
|
|
126
|
+
const active = eventStore.listSessions({ state: "active" });
|
|
127
|
+
const closed = eventStore.listSessions({ state: "closed" });
|
|
128
|
+
|
|
129
|
+
expect(active).toHaveLength(1);
|
|
130
|
+
expect(active[0].id).toBe("session-2");
|
|
131
|
+
expect(closed).toHaveLength(1);
|
|
132
|
+
expect(closed[0].id).toBe("session-1");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("session events in event log", () => {
|
|
137
|
+
it("should persist session events that can be queried", () => {
|
|
138
|
+
mapper.createMapping("session-1", "agent-head");
|
|
139
|
+
mapper.mount("session-1", "agent-child");
|
|
140
|
+
mapper.unmount("session-1");
|
|
141
|
+
mapper.removeMapping("session-1");
|
|
142
|
+
|
|
143
|
+
const events = eventStore.query({ type: "session" });
|
|
144
|
+
expect(events).toHaveLength(4);
|
|
145
|
+
expect(events[0].payload.action).toBe("created");
|
|
146
|
+
expect(events[1].payload.action).toBe("mounted");
|
|
147
|
+
expect(events[2].payload.action).toBe("unmounted");
|
|
148
|
+
expect(events[3].payload.action).toBe("closed");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("Session Recovery", () => {
|
|
154
|
+
let eventStore: EventStore;
|
|
155
|
+
|
|
156
|
+
beforeEach(async () => {
|
|
157
|
+
eventStore = await createEventStore({ inMemory: true });
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
afterEach(async () => {
|
|
161
|
+
await eventStore.close();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should recover active sessions from EventStore", () => {
|
|
165
|
+
// Create sessions with original mapper
|
|
166
|
+
const original = new SessionMapper(eventStore);
|
|
167
|
+
original.createMapping("session-1", "agent-1");
|
|
168
|
+
original.createMapping("session-2", "agent-2");
|
|
169
|
+
|
|
170
|
+
// Create new mapper and recover
|
|
171
|
+
const recovered = new SessionMapper(eventStore);
|
|
172
|
+
const count = recovered.recoverFromStore();
|
|
173
|
+
|
|
174
|
+
expect(count).toBe(2);
|
|
175
|
+
expect(recovered.size).toBe(2);
|
|
176
|
+
expect(recovered.getAgentId("session-1")).toBe("agent-1");
|
|
177
|
+
expect(recovered.getAgentId("session-2")).toBe("agent-2");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should recover mounted sessions with correct state", () => {
|
|
181
|
+
const original = new SessionMapper(eventStore);
|
|
182
|
+
original.createMapping("session-1", "agent-head");
|
|
183
|
+
original.mount("session-1", "agent-child");
|
|
184
|
+
|
|
185
|
+
const recovered = new SessionMapper(eventStore);
|
|
186
|
+
const count = recovered.recoverFromStore();
|
|
187
|
+
|
|
188
|
+
expect(count).toBe(1);
|
|
189
|
+
expect(recovered.getAgentId("session-1")).toBe("agent-child");
|
|
190
|
+
expect(recovered.getHeadManagerId("session-1")).toBe("agent-head");
|
|
191
|
+
expect(recovered.isMounted("session-1")).toBe(true);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("should not recover closed sessions", () => {
|
|
195
|
+
const original = new SessionMapper(eventStore);
|
|
196
|
+
original.createMapping("session-1", "agent-1");
|
|
197
|
+
original.createMapping("session-2", "agent-2");
|
|
198
|
+
original.removeMapping("session-1");
|
|
199
|
+
|
|
200
|
+
const recovered = new SessionMapper(eventStore);
|
|
201
|
+
const count = recovered.recoverFromStore();
|
|
202
|
+
|
|
203
|
+
expect(count).toBe(1);
|
|
204
|
+
expect(recovered.getAgentId("session-1")).toBeUndefined();
|
|
205
|
+
expect(recovered.getAgentId("session-2")).toBe("agent-2");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("should recover after unmount returns to active state", () => {
|
|
209
|
+
const original = new SessionMapper(eventStore);
|
|
210
|
+
original.createMapping("session-1", "agent-head");
|
|
211
|
+
original.mount("session-1", "agent-child");
|
|
212
|
+
original.unmount("session-1");
|
|
213
|
+
|
|
214
|
+
const recovered = new SessionMapper(eventStore);
|
|
215
|
+
const count = recovered.recoverFromStore();
|
|
216
|
+
|
|
217
|
+
expect(count).toBe(1);
|
|
218
|
+
expect(recovered.getAgentId("session-1")).toBe("agent-head");
|
|
219
|
+
expect(recovered.isMounted("session-1")).toBe(false);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("should reset isProcessing to false on recovery", () => {
|
|
223
|
+
const original = new SessionMapper(eventStore);
|
|
224
|
+
original.createMapping("session-1", "agent-1");
|
|
225
|
+
original.setProcessing("session-1", true);
|
|
226
|
+
|
|
227
|
+
const recovered = new SessionMapper(eventStore);
|
|
228
|
+
recovered.recoverFromStore();
|
|
229
|
+
|
|
230
|
+
const status = recovered.getSessionStatus("agent-1");
|
|
231
|
+
expect(status).toBeDefined();
|
|
232
|
+
expect(status!.isProcessing).toBe(false);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("should return 0 when no EventStore is configured", () => {
|
|
236
|
+
const mapper = new SessionMapper();
|
|
237
|
+
const count = mapper.recoverFromStore();
|
|
238
|
+
expect(count).toBe(0);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should survive view rebuild", () => {
|
|
242
|
+
const original = new SessionMapper(eventStore);
|
|
243
|
+
original.createMapping("session-1", "agent-1");
|
|
244
|
+
original.createMapping("session-2", "agent-2");
|
|
245
|
+
original.mount("session-1", "agent-child");
|
|
246
|
+
original.removeMapping("session-2");
|
|
247
|
+
|
|
248
|
+
// Simulate reload (which rebuilds views from events)
|
|
249
|
+
// We don't need to call reload() since in-memory; just verify
|
|
250
|
+
// the view state matches after rebuilding
|
|
251
|
+
const session1 = eventStore.getSession("session-1");
|
|
252
|
+
const session2 = eventStore.getSession("session-2");
|
|
253
|
+
|
|
254
|
+
expect(session1!.state).toBe("mounted");
|
|
255
|
+
expect(session1!.current_agent_id).toBe("agent-child");
|
|
256
|
+
expect(session2!.state).toBe("closed");
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
describe("SessionMapper backward compatibility", () => {
|
|
261
|
+
it("should work without EventStore (original behavior)", () => {
|
|
262
|
+
const mapper = new SessionMapper();
|
|
263
|
+
|
|
264
|
+
const mapping = mapper.createMapping("session-1", "agent-head");
|
|
265
|
+
expect(mapping.agentId).toBe("agent-head");
|
|
266
|
+
|
|
267
|
+
mapper.mount("session-1", "agent-child");
|
|
268
|
+
expect(mapper.getAgentId("session-1")).toBe("agent-child");
|
|
269
|
+
|
|
270
|
+
mapper.unmount("session-1");
|
|
271
|
+
expect(mapper.getAgentId("session-1")).toBe("agent-head");
|
|
272
|
+
|
|
273
|
+
mapper.removeMapping("session-1");
|
|
274
|
+
expect(mapper.getMapping("session-1")).toBeUndefined();
|
|
275
|
+
});
|
|
276
|
+
});
|
package/src/acp/macro-agent.ts
CHANGED
|
@@ -61,6 +61,8 @@ import type {
|
|
|
61
61
|
RespondToPermissionResponse,
|
|
62
62
|
CancelPermissionRequest,
|
|
63
63
|
CancelPermissionResponse,
|
|
64
|
+
ResumeAgentRequest,
|
|
65
|
+
ResumeAgentResponse,
|
|
64
66
|
} from "./types.js";
|
|
65
67
|
import { ACPError } from "./types.js";
|
|
66
68
|
import type { PeerManager } from "../peer/peer-manager.js";
|
|
@@ -92,6 +94,7 @@ const SUPPORTED_EXTENSIONS: ACPExtensionMethod[] = [
|
|
|
92
94
|
"_macro/checkCapability",
|
|
93
95
|
"_macro/respondToPermission",
|
|
94
96
|
"_macro/cancelPermission",
|
|
97
|
+
"_macro/resume",
|
|
95
98
|
];
|
|
96
99
|
|
|
97
100
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -155,8 +158,16 @@ export class MacroAgent implements Agent {
|
|
|
155
158
|
this.peerManager = config.peerManager;
|
|
156
159
|
this.capabilityManager = config.capabilityManager;
|
|
157
160
|
this.roleRegistry = config.roleRegistry ?? new DefaultRoleRegistry();
|
|
158
|
-
this.sessionMapper = new SessionMapper();
|
|
161
|
+
this.sessionMapper = new SessionMapper(config.eventStore);
|
|
159
162
|
this.defaultCwd = config.defaultCwd ?? process.cwd();
|
|
163
|
+
|
|
164
|
+
// Recover persisted sessions from the EventStore
|
|
165
|
+
const recovered = this.sessionMapper.recoverFromStore();
|
|
166
|
+
if (recovered > 0) {
|
|
167
|
+
console.log(
|
|
168
|
+
`[MacroAgent] Recovered ${recovered} session(s) from EventStore`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -229,9 +240,25 @@ export class MacroAgent implements Agent {
|
|
|
229
240
|
* Load an existing session from EventStore
|
|
230
241
|
*/
|
|
231
242
|
async loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {
|
|
232
|
-
|
|
243
|
+
let acpSessionId = params.sessionId;
|
|
233
244
|
const cwd = params.cwd ?? this.defaultCwd;
|
|
234
245
|
|
|
246
|
+
// Extension: If _meta.agentId provided, look up session from agent record
|
|
247
|
+
// This allows resuming a stopped head manager by MAP agent ID
|
|
248
|
+
// when the TUI doesn't know the ACP session ID
|
|
249
|
+
const metaAgentId = (params as { _meta?: Record<string, unknown> })._meta
|
|
250
|
+
?.agentId as string | undefined;
|
|
251
|
+
if (metaAgentId) {
|
|
252
|
+
const agent = this.eventStore.getAgent(metaAgentId as AgentId);
|
|
253
|
+
if (!agent) {
|
|
254
|
+
throw new Error(`Agent not found: ${metaAgentId}`);
|
|
255
|
+
}
|
|
256
|
+
acpSessionId = agent.session_id;
|
|
257
|
+
console.log(
|
|
258
|
+
`[MacroAgent] loadSession: Resolved agentId ${metaAgentId} to session ${acpSessionId}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
235
262
|
// Try to find an existing head manager with this session ID
|
|
236
263
|
const headManagers = this.agentManager.listHeadManagers();
|
|
237
264
|
const existing = headManagers.find((hm) => hm.session_id === acpSessionId);
|
|
@@ -340,8 +367,8 @@ export class MacroAgent implements Agent {
|
|
|
340
367
|
await this.connection.sessionUpdate({
|
|
341
368
|
sessionId: acpSessionId,
|
|
342
369
|
update: {
|
|
343
|
-
|
|
344
|
-
|
|
370
|
+
sessionUpdate: "agent_message_chunk",
|
|
371
|
+
content: { type: "text", text: `Error: ${errorMessage}` },
|
|
345
372
|
},
|
|
346
373
|
});
|
|
347
374
|
|
|
@@ -481,6 +508,11 @@ export class MacroAgent implements Agent {
|
|
|
481
508
|
params as unknown as CancelPermissionRequest
|
|
482
509
|
) as unknown as Record<string, unknown>;
|
|
483
510
|
|
|
511
|
+
case "_macro/resume":
|
|
512
|
+
return this.handleResumeAgent(
|
|
513
|
+
params as unknown as ResumeAgentRequest
|
|
514
|
+
) as unknown as Record<string, unknown>;
|
|
515
|
+
|
|
484
516
|
default:
|
|
485
517
|
throw new ACPError(
|
|
486
518
|
`Unknown extension method: ${method}`,
|
|
@@ -1089,6 +1121,42 @@ export class MacroAgent implements Agent {
|
|
|
1089
1121
|
}
|
|
1090
1122
|
}
|
|
1091
1123
|
|
|
1124
|
+
/**
|
|
1125
|
+
* Resume a stopped/failed agent
|
|
1126
|
+
*/
|
|
1127
|
+
private async handleResumeAgent(
|
|
1128
|
+
params: ResumeAgentRequest
|
|
1129
|
+
): Promise<ResumeAgentResponse> {
|
|
1130
|
+
const { agentId } = params;
|
|
1131
|
+
|
|
1132
|
+
if (!agentId) {
|
|
1133
|
+
throw new ACPError("agentId is required", "INVALID_EXTENSION");
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Verify agent exists
|
|
1137
|
+
const agent = this.eventStore.getAgent(agentId);
|
|
1138
|
+
if (!agent) {
|
|
1139
|
+
throw new ACPError(`Agent not found: ${agentId}`, "AGENT_NOT_FOUND");
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Only resume stopped/failed agents
|
|
1143
|
+
if (agent.state !== "stopped" && agent.state !== "failed") {
|
|
1144
|
+
throw new ACPError(
|
|
1145
|
+
`Agent ${agentId} is ${agent.state} — only stopped or failed agents can be resumed`,
|
|
1146
|
+
"INVALID_EXTENSION"
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
console.log(`[MacroAgent] Resuming agent ${agentId}`);
|
|
1151
|
+
const spawned = await this.agentManager.resume(agentId);
|
|
1152
|
+
|
|
1153
|
+
return {
|
|
1154
|
+
success: true,
|
|
1155
|
+
agentId: spawned.id,
|
|
1156
|
+
sessionId: spawned.session_id,
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1092
1160
|
// ─────────────────────────────────────────────────────────────────
|
|
1093
1161
|
// Helper Methods
|
|
1094
1162
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -1221,10 +1289,14 @@ export class MacroAgent implements Agent {
|
|
|
1221
1289
|
toolCall: {
|
|
1222
1290
|
toolCallId: permReq.toolCall.toolCallId,
|
|
1223
1291
|
title: permReq.toolCall.title,
|
|
1224
|
-
status: permReq.toolCall.status,
|
|
1292
|
+
status: permReq.toolCall.status as "pending" | "in_progress" | "completed" | "failed" | undefined,
|
|
1225
1293
|
rawInput: permReq.toolCall.rawInput,
|
|
1226
1294
|
},
|
|
1227
|
-
options: permReq.options
|
|
1295
|
+
options: permReq.options as Array<{
|
|
1296
|
+
kind: "allow_once" | "allow_always" | "reject_once" | "reject_always";
|
|
1297
|
+
name: string;
|
|
1298
|
+
optionId: string;
|
|
1299
|
+
}>,
|
|
1228
1300
|
});
|
|
1229
1301
|
|
|
1230
1302
|
// Forward the response back to the sub-agent via agentManager
|
|
@@ -1280,7 +1352,7 @@ export class MacroAgent implements Agent {
|
|
|
1280
1352
|
try {
|
|
1281
1353
|
await this.connection.sessionUpdate({
|
|
1282
1354
|
sessionId: acpSessionId,
|
|
1283
|
-
update: sessionUpdate,
|
|
1355
|
+
update: sessionUpdate as Parameters<AgentSideConnection["sessionUpdate"]>[0]["update"],
|
|
1284
1356
|
});
|
|
1285
1357
|
} catch (err) {
|
|
1286
1358
|
console.error(
|
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
* - Default mapping to head manager on session creation
|
|
7
7
|
* - Remapping via mount to control different agents
|
|
8
8
|
* - Multiple concurrent sessions with independent mappings
|
|
9
|
+
* - Persistent session lifecycle events via EventStore
|
|
10
|
+
* - Recovery of session state from EventStore after restart
|
|
9
11
|
*/
|
|
10
12
|
|
|
11
13
|
import type { AgentId } from "../store/types/index.js";
|
|
14
|
+
import type { EventStore } from "../store/event-store.js";
|
|
12
15
|
import type { ACPSessionId, SessionMapping } from "./types.js";
|
|
13
16
|
import { ACPError } from "./types.js";
|
|
14
17
|
|
|
@@ -16,6 +19,13 @@ export class SessionMapper {
|
|
|
16
19
|
/** Map of ACP session ID to mapping info */
|
|
17
20
|
private mappings: Map<ACPSessionId, SessionMapping> = new Map();
|
|
18
21
|
|
|
22
|
+
/** Optional EventStore for persisting session lifecycle events */
|
|
23
|
+
private eventStore: EventStore | null;
|
|
24
|
+
|
|
25
|
+
constructor(eventStore?: EventStore) {
|
|
26
|
+
this.eventStore = eventStore ?? null;
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
/**
|
|
20
30
|
* Register a new ACP session with its head manager
|
|
21
31
|
*
|
|
@@ -40,6 +50,12 @@ export class SessionMapper {
|
|
|
40
50
|
};
|
|
41
51
|
|
|
42
52
|
this.mappings.set(acpSessionId, mapping);
|
|
53
|
+
|
|
54
|
+
// Persist session creation event
|
|
55
|
+
this.emitSessionEvent("created", acpSessionId, {
|
|
56
|
+
head_manager_id: headManagerId,
|
|
57
|
+
});
|
|
58
|
+
|
|
43
59
|
return mapping;
|
|
44
60
|
}
|
|
45
61
|
|
|
@@ -123,6 +139,19 @@ export class SessionMapper {
|
|
|
123
139
|
mapping.isMounted = agentId !== mapping.headManagerId;
|
|
124
140
|
mapping.updatedAt = Date.now();
|
|
125
141
|
|
|
142
|
+
// Persist mount event
|
|
143
|
+
if (mapping.isMounted) {
|
|
144
|
+
this.emitSessionEvent("mounted", acpSessionId, {
|
|
145
|
+
target_agent_id: agentId,
|
|
146
|
+
previous_agent_id: previousAgentId,
|
|
147
|
+
});
|
|
148
|
+
} else {
|
|
149
|
+
// Mounting back to head manager is effectively an unmount
|
|
150
|
+
this.emitSessionEvent("unmounted", acpSessionId, {
|
|
151
|
+
previous_agent_id: previousAgentId,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
126
155
|
return previousAgentId;
|
|
127
156
|
}
|
|
128
157
|
|
|
@@ -141,6 +170,11 @@ export class SessionMapper {
|
|
|
141
170
|
mapping.isMounted = false;
|
|
142
171
|
mapping.updatedAt = Date.now();
|
|
143
172
|
|
|
173
|
+
// Persist unmount event
|
|
174
|
+
this.emitSessionEvent("unmounted", acpSessionId, {
|
|
175
|
+
previous_agent_id: previousAgentId,
|
|
176
|
+
});
|
|
177
|
+
|
|
144
178
|
return previousAgentId;
|
|
145
179
|
}
|
|
146
180
|
|
|
@@ -155,12 +189,17 @@ export class SessionMapper {
|
|
|
155
189
|
}
|
|
156
190
|
|
|
157
191
|
/**
|
|
158
|
-
* Remove a session mapping
|
|
192
|
+
* Remove a session mapping and emit a close event
|
|
159
193
|
*
|
|
160
194
|
* @param acpSessionId - The ACP session ID
|
|
161
195
|
* @returns True if removed, false if not found
|
|
162
196
|
*/
|
|
163
197
|
removeMapping(acpSessionId: ACPSessionId): boolean {
|
|
198
|
+
const existed = this.mappings.has(acpSessionId);
|
|
199
|
+
if (existed) {
|
|
200
|
+
// Persist close event before removing
|
|
201
|
+
this.emitSessionEvent("closed", acpSessionId, {});
|
|
202
|
+
}
|
|
164
203
|
return this.mappings.delete(acpSessionId);
|
|
165
204
|
}
|
|
166
205
|
|
|
@@ -226,6 +265,43 @@ export class SessionMapper {
|
|
|
226
265
|
return undefined;
|
|
227
266
|
}
|
|
228
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Recover session mappings from the EventStore.
|
|
270
|
+
*
|
|
271
|
+
* Loads all non-closed sessions and rebuilds the in-memory mapping state.
|
|
272
|
+
* Called during initialization to restore sessions after a restart.
|
|
273
|
+
*
|
|
274
|
+
* @returns Number of sessions recovered
|
|
275
|
+
*/
|
|
276
|
+
recoverFromStore(): number {
|
|
277
|
+
if (!this.eventStore || typeof this.eventStore.listSessions !== "function") {
|
|
278
|
+
return 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const activeSessions = this.eventStore.listSessions({ state: "active" });
|
|
282
|
+
const mountedSessions = this.eventStore.listSessions({ state: "mounted" });
|
|
283
|
+
const allSessions = [...activeSessions, ...mountedSessions];
|
|
284
|
+
|
|
285
|
+
let recovered = 0;
|
|
286
|
+
for (const session of allSessions) {
|
|
287
|
+
const now = Date.now();
|
|
288
|
+
const mapping: SessionMapping = {
|
|
289
|
+
acpSessionId: session.id,
|
|
290
|
+
agentId: session.current_agent_id,
|
|
291
|
+
headManagerId: session.head_manager_id,
|
|
292
|
+
isMounted: session.state === "mounted",
|
|
293
|
+
createdAt: session.created_at,
|
|
294
|
+
updatedAt: now,
|
|
295
|
+
isProcessing: false,
|
|
296
|
+
lastProcessingChangeAt: now,
|
|
297
|
+
};
|
|
298
|
+
this.mappings.set(session.id, mapping);
|
|
299
|
+
recovered++;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return recovered;
|
|
303
|
+
}
|
|
304
|
+
|
|
229
305
|
/**
|
|
230
306
|
* Get the number of active session mappings
|
|
231
307
|
*/
|
|
@@ -239,4 +315,35 @@ export class SessionMapper {
|
|
|
239
315
|
clear(): void {
|
|
240
316
|
this.mappings.clear();
|
|
241
317
|
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Emit a session lifecycle event to the EventStore
|
|
321
|
+
*/
|
|
322
|
+
private emitSessionEvent(
|
|
323
|
+
action: string,
|
|
324
|
+
sessionId: ACPSessionId,
|
|
325
|
+
details: Record<string, unknown>
|
|
326
|
+
): void {
|
|
327
|
+
if (!this.eventStore || typeof this.eventStore.emit !== "function") {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
try {
|
|
332
|
+
this.eventStore.emit({
|
|
333
|
+
type: "session",
|
|
334
|
+
source: {},
|
|
335
|
+
payload: {
|
|
336
|
+
action,
|
|
337
|
+
session_id: sessionId,
|
|
338
|
+
...details,
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
} catch (error) {
|
|
342
|
+
// Log but don't fail — session events are supplementary
|
|
343
|
+
console.warn(
|
|
344
|
+
`[SessionMapper] Failed to emit session ${action} event:`,
|
|
345
|
+
error instanceof Error ? error.message : String(error)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
242
349
|
}
|
package/src/acp/types.ts
CHANGED
|
@@ -605,6 +605,35 @@ export interface CancelPermissionResponse {
|
|
|
605
605
|
error?: string;
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
+
// ─────────────────────────────────────────────────────────────────
|
|
609
|
+
// ACP Extension: _macro/resume
|
|
610
|
+
// ─────────────────────────────────────────────────────────────────
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Request for _macro/resume extension
|
|
614
|
+
*
|
|
615
|
+
* Resumes a stopped/failed agent by spawning a new process and
|
|
616
|
+
* loading the existing session. Called on the head manager's ACP stream.
|
|
617
|
+
*/
|
|
618
|
+
export interface ResumeAgentRequest {
|
|
619
|
+
/** Agent ID to resume */
|
|
620
|
+
agentId: AgentId;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Response for _macro/resume extension
|
|
625
|
+
*/
|
|
626
|
+
export interface ResumeAgentResponse {
|
|
627
|
+
/** Whether the resume was successful */
|
|
628
|
+
success: boolean;
|
|
629
|
+
|
|
630
|
+
/** The resumed agent's ID */
|
|
631
|
+
agentId: AgentId;
|
|
632
|
+
|
|
633
|
+
/** The agent's session ID */
|
|
634
|
+
sessionId: string;
|
|
635
|
+
}
|
|
636
|
+
|
|
608
637
|
// ─────────────────────────────────────────────────────────────────
|
|
609
638
|
// Extension Method Types (Union)
|
|
610
639
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -627,7 +656,8 @@ export type ACPExtensionMethod =
|
|
|
627
656
|
| "_macro/getCapabilities"
|
|
628
657
|
| "_macro/checkCapability"
|
|
629
658
|
| "_macro/respondToPermission"
|
|
630
|
-
| "_macro/cancelPermission"
|
|
659
|
+
| "_macro/cancelPermission"
|
|
660
|
+
| "_macro/resume";
|
|
631
661
|
|
|
632
662
|
/**
|
|
633
663
|
* Map of extension methods to their request types
|
|
@@ -648,6 +678,7 @@ export interface ACPExtensionRequests {
|
|
|
648
678
|
"_macro/checkCapability": CheckCapabilityRequest;
|
|
649
679
|
"_macro/respondToPermission": RespondToPermissionRequest;
|
|
650
680
|
"_macro/cancelPermission": CancelPermissionRequest;
|
|
681
|
+
"_macro/resume": ResumeAgentRequest;
|
|
651
682
|
}
|
|
652
683
|
|
|
653
684
|
/**
|
|
@@ -669,6 +700,7 @@ export interface ACPExtensionResponses {
|
|
|
669
700
|
"_macro/checkCapability": CheckCapabilityResponse;
|
|
670
701
|
"_macro/respondToPermission": RespondToPermissionResponse;
|
|
671
702
|
"_macro/cancelPermission": CancelPermissionResponse;
|
|
703
|
+
"_macro/resume": ResumeAgentResponse;
|
|
672
704
|
}
|
|
673
705
|
|
|
674
706
|
// ─────────────────────────────────────────────────────────────────
|