macro-agent 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +3 -1
- package/.sudocode/specs.jsonl +4 -0
- package/CLAUDE.md +16 -14
- package/README.md +11 -29
- package/dist/acp/macro-agent.d.ts +15 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +131 -35
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/types.d.ts +32 -1
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +65 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +464 -183
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/api/server.d.ts +3 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +37 -6
- package/dist/api/server.js.map +1 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/token.d.ts +41 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +73 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/cli/acp.d.ts +2 -23
- package/dist/cli/acp.d.ts.map +1 -1
- package/dist/cli/acp.js +127 -61
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +147 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +6 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +268 -181
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +43 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/stable-instance-id.d.ts +8 -0
- package/dist/cli/stable-instance-id.d.ts.map +1 -0
- package/dist/cli/stable-instance-id.js +14 -0
- package/dist/cli/stable-instance-id.js.map +1 -0
- package/dist/config/project-config.d.ts +74 -7
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +123 -20
- package/dist/config/project-config.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts +17 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +384 -23
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/connection-manager.d.ts.map +1 -1
- package/dist/map/adapter/connection-manager.js +3 -0
- package/dist/map/adapter/connection-manager.js.map +1 -1
- package/dist/map/adapter/event-log.d.ts +87 -0
- package/dist/map/adapter/event-log.d.ts.map +1 -0
- package/dist/map/adapter/event-log.js +122 -0
- package/dist/map/adapter/event-log.js.map +1 -0
- package/dist/map/adapter/event-translator.js +6 -6
- package/dist/map/adapter/event-translator.js.map +1 -1
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
- package/dist/map/adapter/extensions/index.d.ts +10 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +34 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
- package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
- package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
- package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
- package/dist/map/adapter/extensions/rename.d.ts +29 -0
- package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
- package/dist/map/adapter/extensions/rename.js +49 -0
- package/dist/map/adapter/extensions/rename.js.map +1 -0
- package/dist/map/adapter/extensions/task.d.ts.map +1 -1
- package/dist/map/adapter/extensions/task.js +10 -0
- package/dist/map/adapter/extensions/task.js.map +1 -1
- package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
- package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
- package/dist/map/adapter/extensions/update-metadata.js +67 -0
- package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
- package/dist/map/adapter/index.d.ts +2 -1
- package/dist/map/adapter/index.d.ts.map +1 -1
- package/dist/map/adapter/index.js +8 -2
- package/dist/map/adapter/index.js.map +1 -1
- package/dist/map/adapter/interface.d.ts +2 -0
- package/dist/map/adapter/interface.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.d.ts +3 -0
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +258 -35
- package/dist/map/adapter/map-adapter.js.map +1 -1
- package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
- package/dist/map/adapter/subscription-manager.js +5 -1
- package/dist/map/adapter/subscription-manager.js.map +1 -1
- package/dist/map/adapter/types.d.ts +2 -0
- package/dist/map/adapter/types.d.ts.map +1 -1
- package/dist/mcp/map-client.d.ts +39 -0
- package/dist/mcp/map-client.d.ts.map +1 -0
- package/dist/mcp/map-client.js +129 -0
- package/dist/mcp/map-client.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +14 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +113 -85
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/types.d.ts +9 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/metrics/metrics.js +1 -1
- package/dist/metrics/metrics.js.map +1 -1
- package/dist/roles/capabilities.d.ts +3 -1
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +17 -7
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/config-loader.d.ts +6 -6
- package/dist/roles/config-loader.d.ts.map +1 -1
- package/dist/roles/config-loader.js +6 -6
- package/dist/roles/config-loader.js.map +1 -1
- package/dist/roles/registry.d.ts +2 -2
- package/dist/roles/registry.js +2 -2
- package/dist/server/combined-server.d.ts +20 -0
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +107 -8
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts +2 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +69 -20
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +18 -0
- package/dist/store/types/agents.d.ts.map +1 -1
- package/dist/store/types/events.d.ts +1 -1
- package/dist/store/types/events.d.ts.map +1 -1
- package/dist/task/backend/index.d.ts +47 -29
- package/dist/task/backend/index.d.ts.map +1 -1
- package/dist/task/backend/index.js +109 -71
- package/dist/task/backend/index.js.map +1 -1
- package/dist/task/backend/memory.d.ts +1 -0
- package/dist/task/backend/memory.d.ts.map +1 -1
- package/dist/task/backend/memory.js +3 -0
- package/dist/task/backend/memory.js.map +1 -1
- package/dist/task/backend/opentasks/backend.d.ts +140 -0
- package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
- package/dist/task/backend/opentasks/backend.js +1023 -0
- package/dist/task/backend/opentasks/backend.js.map +1 -0
- package/dist/task/backend/opentasks/client.d.ts +337 -0
- package/dist/task/backend/opentasks/client.d.ts.map +1 -0
- package/dist/task/backend/opentasks/client.js +225 -0
- package/dist/task/backend/opentasks/client.js.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.js +195 -0
- package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
- package/dist/task/backend/opentasks/index.d.ts +21 -0
- package/dist/task/backend/opentasks/index.d.ts.map +1 -0
- package/dist/task/backend/opentasks/index.js +21 -0
- package/dist/task/backend/opentasks/index.js.map +1 -0
- package/dist/task/backend/opentasks/mapping.d.ts +48 -0
- package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
- package/dist/task/backend/opentasks/mapping.js +77 -0
- package/dist/task/backend/opentasks/mapping.js.map +1 -0
- package/dist/task/backend/types.d.ts +33 -53
- package/dist/task/backend/types.d.ts.map +1 -1
- package/dist/task/backend/types.js +7 -11
- package/dist/task/backend/types.js.map +1 -1
- package/dist/task/backend/unified-tool-provider.d.ts +57 -0
- package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
- package/dist/task/backend/unified-tool-provider.js +623 -0
- package/dist/task/backend/unified-tool-provider.js.map +1 -0
- package/dist/teams/team-loader.d.ts +2 -2
- package/dist/teams/team-loader.js +3 -3
- package/dist/teams/team-loader.js.map +1 -1
- package/dist/teams/team-runtime.d.ts.map +1 -1
- package/dist/teams/team-runtime.js +2 -0
- package/dist/teams/team-runtime.js.map +1 -1
- package/docs/architecture.md +7 -6
- package/docs/configuration.md +26 -62
- package/docs/implementation-details.md +5 -5
- package/docs/implementation-summary.md +17 -17
- package/docs/plan-self-driving-support.md +4 -4
- package/docs/spec-self-driving-support.md +10 -10
- package/docs/team-templates.md +2 -2
- package/docs/teams.md +3 -3
- package/docs/troubleshooting.md +10 -11
- package/package.json +6 -4
- package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
- package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
- package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
- package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
- package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
- package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
- package/src/acp/__tests__/integration.test.ts +56 -31
- package/src/acp/__tests__/macro-agent.test.ts +16 -7
- package/src/acp/macro-agent.ts +170 -36
- package/src/acp/types.ts +46 -1
- package/src/agent/__tests__/agent-manager.test.ts +228 -2
- package/src/agent/agent-manager.ts +714 -261
- package/src/agent/types.ts +3 -1
- package/src/api/server.ts +41 -7
- package/src/auth/__tests__/token.test.ts +100 -0
- package/src/auth/index.ts +1 -0
- package/src/auth/token.ts +82 -0
- package/src/cli/__tests__/acp.test.ts +1 -1
- package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
- package/src/cli/acp.ts +130 -72
- package/src/cli/index.ts +120 -14
- package/src/cli/mcp.ts +311 -207
- package/src/cli/parse-args.ts +54 -0
- package/src/cli/stable-instance-id.ts +14 -0
- package/src/config/project-config.ts +190 -27
- package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
- package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
- package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
- package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
- package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
- package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
- package/src/map/adapter/__tests__/event-log.test.ts +527 -0
- package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
- package/src/map/adapter/__tests__/extensions.test.ts +408 -0
- package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
- package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
- package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
- package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
- package/src/map/adapter/acp-over-map.ts +678 -66
- package/src/map/adapter/connection-manager.ts +3 -0
- package/src/map/adapter/event-log.ts +208 -0
- package/src/map/adapter/event-translator.ts +6 -6
- package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
- package/src/map/adapter/extensions/index.ts +60 -0
- package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
- package/src/map/adapter/extensions/task.ts +11 -0
- package/src/map/adapter/extensions/update-metadata.ts +126 -0
- package/src/map/adapter/index.ts +28 -0
- package/src/map/adapter/interface.ts +2 -0
- package/src/map/adapter/map-adapter.ts +312 -47
- package/src/map/adapter/subscription-manager.ts +5 -1
- package/src/map/adapter/types.ts +2 -0
- package/src/mcp/__tests__/map-client.test.ts +386 -0
- package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
- package/src/mcp/__tests__/mcp-server.test.ts +100 -1
- package/src/mcp/map-client.ts +177 -0
- package/src/mcp/mcp-server.ts +191 -100
- package/src/mcp/types.ts +6 -1
- package/src/metrics/metrics.ts +1 -1
- package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
- package/src/roles/__tests__/config-loader.test.ts +7 -7
- package/src/roles/capabilities.ts +17 -7
- package/src/roles/config-loader.ts +6 -6
- package/src/roles/registry.ts +2 -2
- package/src/server/__tests__/combined-server.test.ts +94 -21
- package/src/server/combined-server.ts +189 -33
- package/src/steering/__tests__/steering-integration.test.ts +1 -1
- package/src/store/__tests__/event-store.test.ts +196 -1
- package/src/store/__tests__/instance.test.ts +3 -3
- package/src/store/event-store.ts +80 -21
- package/src/store/types/agents.ts +15 -0
- package/src/store/types/events.ts +1 -1
- package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
- package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
- package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
- package/src/task/backend/index.ts +156 -106
- package/src/task/backend/memory.ts +4 -0
- package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
- package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
- package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
- package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
- package/src/task/backend/opentasks/backend.ts +1323 -0
- package/src/task/backend/opentasks/client.ts +652 -0
- package/src/task/backend/opentasks/daemon-manager.ts +253 -0
- package/src/task/backend/opentasks/index.ts +69 -0
- package/src/task/backend/opentasks/mapping.ts +94 -0
- package/src/task/backend/types.ts +42 -66
- package/src/task/backend/unified-tool-provider.ts +779 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
- package/src/teams/team-loader.ts +3 -3
- package/src/teams/team-runtime.ts +2 -0
- package/test_fixtures/README.md +2 -3
- package/test_fixtures/fixtures/index.ts +0 -3
- package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
- package/test_fixtures/fixtures/repos/index.ts +1 -3
- package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
- package/test_fixtures/fixtures/repos/types.ts +0 -11
- package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
- package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
- package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
- package/vitest.config.ts +1 -1
- package/vitest.e2e.config.ts +1 -1
- package/vitest.setup.ts +1 -30
- package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
- package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
- package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
- package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
- package/.macro-agent/teams/self-driving/team.yaml +0 -103
- package/.macro-agent/teams/structured/prompts/developer.md +0 -26
- package/.macro-agent/teams/structured/prompts/lead.md +0 -25
- package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
- package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
- package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
- package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
- package/.macro-agent/teams/structured/team.yaml +0 -89
- package/docs/sudocode-integration.md +0 -383
- package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
- package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
- package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
- package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
- package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
- package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
- package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
- package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
- package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
- package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
- package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
- package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
- package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
- package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
- package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
- package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
- package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
- package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
- package/src/task/backend/sudocode/backend.ts +0 -1237
- package/src/task/backend/sudocode/client.ts +0 -515
- package/src/task/backend/sudocode/index.ts +0 -120
- package/src/task/backend/sudocode/mapping.ts +0 -93
- package/src/task/backend/sudocode/server-client.ts +0 -522
- package/src/task/backend/sudocode/standalone-client.ts +0 -623
- package/src/task/backend/sudocode/sync-policy.ts +0 -387
- package/src/task/backend/sudocode/tools.ts +0 -896
- package/src/task/backend/tool-provider.ts +0 -506
- package/test_fixtures/fixtures/sudocode/index.ts +0 -29
- package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
- package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
|
@@ -26,6 +26,11 @@ import {
|
|
|
26
26
|
createMAPAdapter,
|
|
27
27
|
createMAPWebSocketHandler,
|
|
28
28
|
registerWorkspaceFileExtensions,
|
|
29
|
+
registerUpdateMetadataExtension,
|
|
30
|
+
registerMCPBridgeExtensions,
|
|
31
|
+
registerTaskExtensions,
|
|
32
|
+
registerResumeExtension,
|
|
33
|
+
registerAgentLifecycleExtensions,
|
|
29
34
|
type MAPAdapter,
|
|
30
35
|
type MAPAdapterServices,
|
|
31
36
|
type MAPWebSocketHandler,
|
|
@@ -33,8 +38,17 @@ import {
|
|
|
33
38
|
import type { Agent, AgentId } from "../store/types/index.js";
|
|
34
39
|
import type { Address, SendOptions } from "../map/types.js";
|
|
35
40
|
import { createMailService, type MailService } from "../mail/mail-service.js";
|
|
36
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
createConversationMap,
|
|
43
|
+
type ConversationMap,
|
|
44
|
+
} from "../mail/conversation-map.js";
|
|
37
45
|
import { createTurnRecorder } from "../mail/turn-recorder.js";
|
|
46
|
+
import {
|
|
47
|
+
AgentTokenManager,
|
|
48
|
+
generateToken as generateTokenFn,
|
|
49
|
+
secureCompare,
|
|
50
|
+
} from "../auth/token.js";
|
|
51
|
+
import { TaskBackend, TaskToolProvider } from "../task/backend/types.js";
|
|
38
52
|
|
|
39
53
|
// ─────────────────────────────────────────────────────────────────
|
|
40
54
|
// Types
|
|
@@ -49,6 +63,16 @@ export interface CombinedServerServices {
|
|
|
49
63
|
capabilityManager?: CapabilityManager;
|
|
50
64
|
/** Optional activity watcher for event-driven waking */
|
|
51
65
|
activityWatcher?: ActivityWatcher;
|
|
66
|
+
/** Optional task backend for task tool bridge extensions */
|
|
67
|
+
taskBackend?: TaskBackend;
|
|
68
|
+
/** Optional task tool provider for dynamic task tools in thin-client mode */
|
|
69
|
+
taskToolProvider?: TaskToolProvider;
|
|
70
|
+
/** Mutable context holder for task tool provider agent_id injection */
|
|
71
|
+
taskToolContext?: { agent_id: string };
|
|
72
|
+
/** Per-agent token manager for MCP bridge authentication */
|
|
73
|
+
agentTokenManager?: AgentTokenManager;
|
|
74
|
+
/** Get connected opentasks project paths (for health endpoint) */
|
|
75
|
+
getConnectedProjects?: () => string[];
|
|
52
76
|
}
|
|
53
77
|
|
|
54
78
|
export interface CombinedServerConfig {
|
|
@@ -69,6 +93,12 @@ export interface CombinedServerConfig {
|
|
|
69
93
|
|
|
70
94
|
/** Disable MAP protocol (default: false - MAP is enabled) */
|
|
71
95
|
disableMap?: boolean;
|
|
96
|
+
|
|
97
|
+
/** Server token for authentication. Auto-generated if not provided (unless noAuth is true). */
|
|
98
|
+
serverToken?: string;
|
|
99
|
+
|
|
100
|
+
/** Disable authentication entirely (for local development/testing) */
|
|
101
|
+
noAuth?: boolean;
|
|
72
102
|
}
|
|
73
103
|
|
|
74
104
|
export interface CombinedServer {
|
|
@@ -101,6 +131,9 @@ export interface CombinedServer {
|
|
|
101
131
|
|
|
102
132
|
/** Conversation map (for agent-to-conversation tracking) */
|
|
103
133
|
readonly conversationMap?: ConversationMap;
|
|
134
|
+
|
|
135
|
+
/** Server token used for authentication (exposed for tests). Undefined when auth is disabled. */
|
|
136
|
+
readonly serverToken?: string;
|
|
104
137
|
}
|
|
105
138
|
|
|
106
139
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -110,7 +143,10 @@ export interface CombinedServer {
|
|
|
110
143
|
/**
|
|
111
144
|
* Get all descendants of an agent recursively.
|
|
112
145
|
*/
|
|
113
|
-
function getDescendantsRecursive(
|
|
146
|
+
function getDescendantsRecursive(
|
|
147
|
+
agentId: AgentId,
|
|
148
|
+
agentManager: AgentManager,
|
|
149
|
+
): AgentId[] {
|
|
114
150
|
const descendants: AgentId[] = [];
|
|
115
151
|
const children = agentManager.getChildren(agentId);
|
|
116
152
|
for (const child of children) {
|
|
@@ -124,7 +160,9 @@ function getDescendantsRecursive(agentId: AgentId, agentManager: AgentManager):
|
|
|
124
160
|
* Create MAPAdapterServices from CombinedServerServices.
|
|
125
161
|
* Wires the internal services to the MAP adapter interface.
|
|
126
162
|
*/
|
|
127
|
-
function createMAPServices(
|
|
163
|
+
function createMAPServices(
|
|
164
|
+
services: CombinedServerServices,
|
|
165
|
+
): MAPAdapterServices {
|
|
128
166
|
// Create agent source for getAncestors (needs lineage lookup)
|
|
129
167
|
// RelevanceAgentSource expects getAgent to return null (not undefined) when not found
|
|
130
168
|
const agentSource: RelevanceAgentSource = {
|
|
@@ -137,10 +175,12 @@ function createMAPServices(services: CombinedServerServices): MAPAdapterServices
|
|
|
137
175
|
agent
|
|
138
176
|
? {
|
|
139
177
|
id: agent.id,
|
|
178
|
+
name: agent.name,
|
|
140
179
|
role: agent.role,
|
|
141
180
|
state: agent.state,
|
|
142
181
|
parent: agent.parent ?? undefined,
|
|
143
182
|
createdAt: agent.created_at,
|
|
183
|
+
metadata: agent.metadata,
|
|
144
184
|
}
|
|
145
185
|
: undefined;
|
|
146
186
|
|
|
@@ -152,7 +192,7 @@ function createMAPServices(services: CombinedServerServices): MAPAdapterServices
|
|
|
152
192
|
from: AgentId,
|
|
153
193
|
to: Address,
|
|
154
194
|
content: string,
|
|
155
|
-
options?: SendOptions
|
|
195
|
+
options?: SendOptions,
|
|
156
196
|
) => {
|
|
157
197
|
const result = await services.messageRouter.sendToAddress({
|
|
158
198
|
from,
|
|
@@ -178,7 +218,7 @@ function createMAPServices(services: CombinedServerServices): MAPAdapterServices
|
|
|
178
218
|
|
|
179
219
|
export function createCombinedServer(
|
|
180
220
|
services: CombinedServerServices,
|
|
181
|
-
config: CombinedServerConfig = {}
|
|
221
|
+
config: CombinedServerConfig = {},
|
|
182
222
|
): CombinedServer {
|
|
183
223
|
const {
|
|
184
224
|
port = 3001,
|
|
@@ -187,8 +227,15 @@ export function createCombinedServer(
|
|
|
187
227
|
cors = true,
|
|
188
228
|
mapPath = "/map",
|
|
189
229
|
disableMap = false,
|
|
230
|
+
serverToken: configToken,
|
|
231
|
+
noAuth = false,
|
|
190
232
|
} = config;
|
|
191
233
|
|
|
234
|
+
// Resolve server token: disabled > config > env > none (no auth by default)
|
|
235
|
+
const resolvedServerToken = noAuth
|
|
236
|
+
? undefined
|
|
237
|
+
: (configToken ?? process.env.MACRO_SERVER_SECRET ?? undefined);
|
|
238
|
+
|
|
192
239
|
// Set up mail service and conversation map (always created, independent of MAP)
|
|
193
240
|
const mailService = createMailService({ eventStore: services.eventStore });
|
|
194
241
|
const conversationMap = createConversationMap();
|
|
@@ -211,7 +258,7 @@ export function createCombinedServer(
|
|
|
211
258
|
// Create Express app with API routes (include mail services)
|
|
212
259
|
const app = createAPIApp(
|
|
213
260
|
{ ...services, mailService, conversationMap },
|
|
214
|
-
{ cors }
|
|
261
|
+
{ cors, serverToken: resolvedServerToken },
|
|
215
262
|
);
|
|
216
263
|
|
|
217
264
|
// Create HTTP server with Express
|
|
@@ -239,50 +286,144 @@ export function createCombinedServer(
|
|
|
239
286
|
};
|
|
240
287
|
mapAdapter = createMAPAdapter(
|
|
241
288
|
{ name: "macro-agent", version: "1.0.0" },
|
|
242
|
-
mapServices
|
|
289
|
+
mapServices,
|
|
243
290
|
);
|
|
244
291
|
|
|
245
292
|
// Register workspace file extensions for TUI file attachment.
|
|
246
293
|
// Uses defaultCwd (project root) as the workspace path for all agents,
|
|
247
294
|
// since the head manager doesn't have an isolated worktree.
|
|
248
295
|
registerWorkspaceFileExtensions(mapAdapter, {
|
|
249
|
-
getWorkspace: () => ({ path: defaultCwd } as any
|
|
296
|
+
getWorkspace: () => ({ path: defaultCwd }) as any,
|
|
250
297
|
agentExists: () => true,
|
|
251
298
|
});
|
|
252
299
|
|
|
300
|
+
// Register generic metadata update extension
|
|
301
|
+
registerUpdateMetadataExtension(mapAdapter, {
|
|
302
|
+
getAgent: (id) => services.agentManager.get(id),
|
|
303
|
+
updateAgentMetadata: (id, updates) =>
|
|
304
|
+
services.eventStore.updateAgentMetadata(id, updates),
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Register task extensions for direct MAP task management
|
|
308
|
+
if (services.taskBackend) {
|
|
309
|
+
registerTaskExtensions(mapAdapter, {
|
|
310
|
+
taskBackend: services.taskBackend,
|
|
311
|
+
sendMessage: async (from, to, content, options) => {
|
|
312
|
+
const result = await services.messageRouter.sendToAddress({
|
|
313
|
+
from: from as AgentId,
|
|
314
|
+
to,
|
|
315
|
+
content: typeof content === "string" ? content : JSON.stringify(content),
|
|
316
|
+
options: options ? { priority: options.priority as any } : undefined,
|
|
317
|
+
});
|
|
318
|
+
return { delivered: result.delivered };
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Register resume extension for restarting stopped agents
|
|
324
|
+
registerResumeExtension(mapAdapter, {
|
|
325
|
+
getAgent: (id) => {
|
|
326
|
+
const agent = services.agentManager.get(id);
|
|
327
|
+
if (!agent) return undefined;
|
|
328
|
+
return { id: agent.id, state: agent.state, session_id: agent.session_id };
|
|
329
|
+
},
|
|
330
|
+
resume: (id) => services.agentManager.resume(id),
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Register agent lifecycle extensions (spawn, fork, permission management)
|
|
334
|
+
registerAgentLifecycleExtensions(mapAdapter, {
|
|
335
|
+
getAgent: (id) => services.agentManager.get(id),
|
|
336
|
+
spawn: (opts) => services.agentManager.spawn(opts),
|
|
337
|
+
forkAgent: (id, opts) => services.agentManager.forkAgent(id, opts),
|
|
338
|
+
prompt: (id, msg) => services.agentManager.prompt(id, msg),
|
|
339
|
+
setPermissionMode: (id, mode) =>
|
|
340
|
+
services.agentManager.setPermissionMode(id, mode as any),
|
|
341
|
+
getPermissionMode: (id) => services.agentManager.getPermissionMode(id),
|
|
342
|
+
respondToPermission: (id, reqId, optId) =>
|
|
343
|
+
services.agentManager.respondToPermission(id, reqId, optId),
|
|
344
|
+
onAgentRegistered: (agent) => {
|
|
345
|
+
// Emit agent_registered event to all MAP subscribers
|
|
346
|
+
// mapAdapter is guaranteed non-null here (inside if (!disableMap) block)
|
|
347
|
+
mapAdapter!.emitEvent({
|
|
348
|
+
eventId: `agent-reg-${agent.id}-${Date.now()}`,
|
|
349
|
+
type: "agent_registered" as any,
|
|
350
|
+
timestamp: Date.now(),
|
|
351
|
+
data: agent,
|
|
352
|
+
});
|
|
353
|
+
},
|
|
354
|
+
listHeadManagers: () => services.agentManager.listHeadManagers(),
|
|
355
|
+
defaultCwd,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Register MCP bridge extensions for thin-client MCP subprocesses
|
|
359
|
+
registerMCPBridgeExtensions(mapAdapter, {
|
|
360
|
+
eventStore: services.eventStore,
|
|
361
|
+
agentManager: services.agentManager,
|
|
362
|
+
taskManager: services.taskManager,
|
|
363
|
+
messageRouter: services.messageRouter,
|
|
364
|
+
peerManager: services.peerManager,
|
|
365
|
+
activityWatcher: services.activityWatcher,
|
|
366
|
+
taskBackend: services.taskBackend,
|
|
367
|
+
taskToolProvider: services.taskToolProvider,
|
|
368
|
+
taskToolContext: services.taskToolContext,
|
|
369
|
+
agentTokenManager: services.agentTokenManager,
|
|
370
|
+
});
|
|
371
|
+
|
|
253
372
|
mapHandler = createMAPWebSocketHandler(mapAdapter);
|
|
254
373
|
}
|
|
255
374
|
|
|
256
375
|
// Handle upgrade requests - route by path
|
|
257
|
-
httpServer.on(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
376
|
+
httpServer.on(
|
|
377
|
+
"upgrade",
|
|
378
|
+
(request: IncomingMessage, socket: Duplex, head: Buffer) => {
|
|
379
|
+
const parsedUrl = new URL(
|
|
380
|
+
request.url ?? "/",
|
|
381
|
+
`http://${request.headers.host}`,
|
|
382
|
+
);
|
|
383
|
+
const pathname = parsedUrl.pathname;
|
|
384
|
+
|
|
385
|
+
// Validate server token on WebSocket upgrade (skip when auth disabled)
|
|
386
|
+
if (resolvedServerToken) {
|
|
387
|
+
const urlToken = parsedUrl.searchParams.get("token");
|
|
388
|
+
if (!urlToken || !secureCompare(urlToken, resolvedServerToken)) {
|
|
389
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
390
|
+
socket.destroy();
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (pathname === "/acp") {
|
|
396
|
+
acpWss.handleUpgrade(request, socket, head, (ws) => {
|
|
397
|
+
acpWss.emit("connection", ws, request);
|
|
398
|
+
});
|
|
399
|
+
} else if (pathname === "/api/ws") {
|
|
400
|
+
apiWss.handleUpgrade(request, socket, head, (ws) => {
|
|
401
|
+
apiWss.emit("connection", ws, request);
|
|
402
|
+
});
|
|
403
|
+
} else if (pathname === mapPath && mapHandler) {
|
|
404
|
+
// MAP protocol connection
|
|
405
|
+
acpWss.handleUpgrade(request, socket, head, (ws) => {
|
|
406
|
+
mapHandler.handleConnection(ws, request);
|
|
407
|
+
});
|
|
408
|
+
} else {
|
|
409
|
+
// Unknown WebSocket path
|
|
410
|
+
socket.write("HTTP/1.1 404 Not Found\r\n\r\n");
|
|
411
|
+
socket.destroy();
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
);
|
|
279
415
|
|
|
280
416
|
// Add health endpoint
|
|
281
417
|
app.get("/health", (_req, res) => {
|
|
418
|
+
const connectedProjects = services.getConnectedProjects?.() ?? [];
|
|
282
419
|
res.json({
|
|
283
420
|
status: "ok",
|
|
284
421
|
acp_connections: acpHandler.getConnectionCount(),
|
|
285
422
|
map_connections: mapHandler?.getConnectionCount() ?? 0,
|
|
423
|
+
opentasks: {
|
|
424
|
+
connected_projects: connectedProjects,
|
|
425
|
+
project_count: connectedProjects.length,
|
|
426
|
+
},
|
|
286
427
|
timestamp: Date.now(),
|
|
287
428
|
});
|
|
288
429
|
});
|
|
@@ -301,13 +442,23 @@ export function createCombinedServer(
|
|
|
301
442
|
httpServer.on("error", reject);
|
|
302
443
|
httpServer.listen(port, host, () => {
|
|
303
444
|
httpServer.removeListener("error", reject);
|
|
445
|
+
const tokenParam = resolvedServerToken ? `?token=${resolvedServerToken}` : "";
|
|
304
446
|
console.error(`[combined] Server listening on http://${host}:${port}`);
|
|
305
|
-
console.error(`[combined] ACP WebSocket: ws://${host}:${port}/acp`);
|
|
447
|
+
console.error(`[combined] ACP WebSocket: ws://${host}:${port}/acp${tokenParam}`);
|
|
306
448
|
if (mapHandler) {
|
|
307
|
-
console.error(
|
|
449
|
+
console.error(
|
|
450
|
+
`[combined] MAP WebSocket: ws://${host}:${port}${mapPath}${tokenParam}`,
|
|
451
|
+
);
|
|
308
452
|
}
|
|
309
|
-
console.error(
|
|
453
|
+
console.error(
|
|
454
|
+
`[combined] API WebSocket: ws://${host}:${port}/api/ws${tokenParam}`,
|
|
455
|
+
);
|
|
310
456
|
console.error(`[combined] REST API: http://${host}:${port}/api/*`);
|
|
457
|
+
if (resolvedServerToken) {
|
|
458
|
+
console.error(`[combined] Server token: ${resolvedServerToken.substring(0, 8)}...`);
|
|
459
|
+
} else {
|
|
460
|
+
console.error(`[combined] Auth: disabled`);
|
|
461
|
+
}
|
|
311
462
|
resolve();
|
|
312
463
|
});
|
|
313
464
|
});
|
|
@@ -348,6 +499,10 @@ export function createCombinedServer(
|
|
|
348
499
|
}
|
|
349
500
|
|
|
350
501
|
function getUrl(): string {
|
|
502
|
+
const addr = httpServer.address();
|
|
503
|
+
if (addr && typeof addr === "object") {
|
|
504
|
+
return `http://${host}:${addr.port}`;
|
|
505
|
+
}
|
|
351
506
|
return `http://${host}:${port}`;
|
|
352
507
|
}
|
|
353
508
|
|
|
@@ -370,5 +525,6 @@ export function createCombinedServer(
|
|
|
370
525
|
mapAdapter,
|
|
371
526
|
mailService,
|
|
372
527
|
conversationMap,
|
|
528
|
+
serverToken: resolvedServerToken,
|
|
373
529
|
};
|
|
374
530
|
}
|
|
@@ -671,7 +671,7 @@ describe("Steering Integration", () => {
|
|
|
671
671
|
payload: { status_type: "started" },
|
|
672
672
|
});
|
|
673
673
|
eventStore.emit({
|
|
674
|
-
type: "
|
|
674
|
+
type: "stop",
|
|
675
675
|
source: { agent_id: "stopped-agent" },
|
|
676
676
|
payload: { agent_id: "stopped-agent", reason: "completed" },
|
|
677
677
|
});
|
|
@@ -170,7 +170,7 @@ describe('EventStore', () => {
|
|
|
170
170
|
});
|
|
171
171
|
|
|
172
172
|
store.emit({
|
|
173
|
-
type: '
|
|
173
|
+
type: 'stop',
|
|
174
174
|
source: { agent_id: 'agent_1' },
|
|
175
175
|
payload: { reason: 'completed' },
|
|
176
176
|
});
|
|
@@ -1096,6 +1096,201 @@ describe('Event Archival', () => {
|
|
|
1096
1096
|
|
|
1097
1097
|
await planStore.close();
|
|
1098
1098
|
});
|
|
1099
|
+
|
|
1100
|
+
it('should update agent name via updateAgentMetadata', async () => {
|
|
1101
|
+
const metaStore = await createEventStore({ inMemory: true });
|
|
1102
|
+
|
|
1103
|
+
metaStore.emit({
|
|
1104
|
+
type: 'spawn',
|
|
1105
|
+
source: { agent_id: 'agent_meta' },
|
|
1106
|
+
payload: {
|
|
1107
|
+
agent_id: 'agent_meta',
|
|
1108
|
+
session_id: 'sess_meta',
|
|
1109
|
+
task: 'test metadata',
|
|
1110
|
+
},
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
// Name starts undefined
|
|
1114
|
+
expect(metaStore.getAgent('agent_meta')?.name).toBeUndefined();
|
|
1115
|
+
|
|
1116
|
+
// Set name via updateAgentMetadata
|
|
1117
|
+
metaStore.updateAgentMetadata('agent_meta', { name: 'MyAgent' });
|
|
1118
|
+
expect(metaStore.getAgent('agent_meta')?.name).toBe('MyAgent');
|
|
1119
|
+
|
|
1120
|
+
await metaStore.close();
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
it('should update agent metadata via updateAgentMetadata', async () => {
|
|
1124
|
+
const metaStore = await createEventStore({ inMemory: true });
|
|
1125
|
+
|
|
1126
|
+
metaStore.emit({
|
|
1127
|
+
type: 'spawn',
|
|
1128
|
+
source: { agent_id: 'agent_meta2' },
|
|
1129
|
+
payload: {
|
|
1130
|
+
agent_id: 'agent_meta2',
|
|
1131
|
+
session_id: 'sess_meta2',
|
|
1132
|
+
task: 'test metadata field',
|
|
1133
|
+
},
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
// Metadata starts undefined
|
|
1137
|
+
expect(metaStore.getAgent('agent_meta2')?.metadata).toBeUndefined();
|
|
1138
|
+
|
|
1139
|
+
// Set metadata
|
|
1140
|
+
metaStore.updateAgentMetadata('agent_meta2', {
|
|
1141
|
+
metadata: { color: 'blue', priority: 1 },
|
|
1142
|
+
});
|
|
1143
|
+
const after = metaStore.getAgent('agent_meta2');
|
|
1144
|
+
expect(after?.metadata).toEqual({ color: 'blue', priority: 1 });
|
|
1145
|
+
|
|
1146
|
+
await metaStore.close();
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
it('should shallow-merge metadata with existing values', async () => {
|
|
1150
|
+
const metaStore = await createEventStore({ inMemory: true });
|
|
1151
|
+
|
|
1152
|
+
metaStore.emit({
|
|
1153
|
+
type: 'spawn',
|
|
1154
|
+
source: { agent_id: 'agent_merge' },
|
|
1155
|
+
payload: {
|
|
1156
|
+
agent_id: 'agent_merge',
|
|
1157
|
+
session_id: 'sess_merge',
|
|
1158
|
+
task: 'test metadata merge',
|
|
1159
|
+
},
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
// Set initial metadata
|
|
1163
|
+
metaStore.updateAgentMetadata('agent_merge', {
|
|
1164
|
+
metadata: { color: 'blue', size: 'large' },
|
|
1165
|
+
});
|
|
1166
|
+
expect(metaStore.getAgent('agent_merge')?.metadata).toEqual({
|
|
1167
|
+
color: 'blue',
|
|
1168
|
+
size: 'large',
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
// Merge with new metadata — existing keys preserved, new keys added
|
|
1172
|
+
metaStore.updateAgentMetadata('agent_merge', {
|
|
1173
|
+
metadata: { color: 'red', shape: 'circle' },
|
|
1174
|
+
});
|
|
1175
|
+
expect(metaStore.getAgent('agent_merge')?.metadata).toEqual({
|
|
1176
|
+
color: 'red',
|
|
1177
|
+
size: 'large',
|
|
1178
|
+
shape: 'circle',
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
await metaStore.close();
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
it('should update multiple fields in a single updateAgentMetadata call', async () => {
|
|
1185
|
+
const metaStore = await createEventStore({ inMemory: true });
|
|
1186
|
+
|
|
1187
|
+
metaStore.emit({
|
|
1188
|
+
type: 'spawn',
|
|
1189
|
+
source: { agent_id: 'agent_multi' },
|
|
1190
|
+
payload: {
|
|
1191
|
+
agent_id: 'agent_multi',
|
|
1192
|
+
session_id: 'sess_multi',
|
|
1193
|
+
task: 'test multi-field update',
|
|
1194
|
+
},
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1197
|
+
const plan = [
|
|
1198
|
+
{ content: 'Step 1', priority: 'high', status: 'pending' },
|
|
1199
|
+
];
|
|
1200
|
+
|
|
1201
|
+
metaStore.updateAgentMetadata('agent_multi', {
|
|
1202
|
+
name: 'MultiAgent',
|
|
1203
|
+
plan,
|
|
1204
|
+
metadata: { tag: 'test' },
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
const agent = metaStore.getAgent('agent_multi');
|
|
1208
|
+
expect(agent?.name).toBe('MultiAgent');
|
|
1209
|
+
expect(agent?.plan).toEqual(plan);
|
|
1210
|
+
expect(agent?.metadata).toEqual({ tag: 'test' });
|
|
1211
|
+
|
|
1212
|
+
await metaStore.close();
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
it('should notify agent change listeners on metadata update', async () => {
|
|
1216
|
+
const metaStore = await createEventStore({ inMemory: true });
|
|
1217
|
+
|
|
1218
|
+
metaStore.emit({
|
|
1219
|
+
type: 'spawn',
|
|
1220
|
+
source: { agent_id: 'agent_notify' },
|
|
1221
|
+
payload: {
|
|
1222
|
+
agent_id: 'agent_notify',
|
|
1223
|
+
session_id: 'sess_notify',
|
|
1224
|
+
task: 'test notify',
|
|
1225
|
+
},
|
|
1226
|
+
});
|
|
1227
|
+
|
|
1228
|
+
const changes: string[] = [];
|
|
1229
|
+
metaStore.onAgentChange((agentId) => {
|
|
1230
|
+
changes.push(agentId);
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
metaStore.updateAgentMetadata('agent_notify', { name: 'Notified' });
|
|
1234
|
+
expect(changes).toContain('agent_notify');
|
|
1235
|
+
|
|
1236
|
+
await metaStore.close();
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
it('should preserve all out-of-band fields across reload', async () => {
|
|
1240
|
+
const metaStore = await createEventStore({
|
|
1241
|
+
baseDir: testDir,
|
|
1242
|
+
instanceId: 'metadata-reload-test',
|
|
1243
|
+
});
|
|
1244
|
+
|
|
1245
|
+
metaStore.emit({
|
|
1246
|
+
type: 'spawn',
|
|
1247
|
+
source: { agent_id: 'agent_reload' },
|
|
1248
|
+
payload: {
|
|
1249
|
+
agent_id: 'agent_reload',
|
|
1250
|
+
session_id: 'sess_reload',
|
|
1251
|
+
task: 'test reload persistence',
|
|
1252
|
+
},
|
|
1253
|
+
});
|
|
1254
|
+
|
|
1255
|
+
// Set all out-of-band fields
|
|
1256
|
+
const plan = [
|
|
1257
|
+
{ content: 'Research', priority: 'high', status: 'completed' },
|
|
1258
|
+
];
|
|
1259
|
+
metaStore.updateAgentMetadata('agent_reload', {
|
|
1260
|
+
name: 'ReloadAgent',
|
|
1261
|
+
plan,
|
|
1262
|
+
metadata: { version: 2, env: 'test' },
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
// Verify before reload
|
|
1266
|
+
const before = metaStore.getAgent('agent_reload');
|
|
1267
|
+
expect(before?.name).toBe('ReloadAgent');
|
|
1268
|
+
expect(before?.plan).toEqual(plan);
|
|
1269
|
+
expect(before?.metadata).toEqual({ version: 2, env: 'test' });
|
|
1270
|
+
|
|
1271
|
+
// Persist and reload (rebuildViews)
|
|
1272
|
+
await metaStore.persist();
|
|
1273
|
+
await metaStore.reload();
|
|
1274
|
+
|
|
1275
|
+
// All fields should survive
|
|
1276
|
+
const after = metaStore.getAgent('agent_reload');
|
|
1277
|
+
expect(after).toBeDefined();
|
|
1278
|
+
expect(after?.name).toBe('ReloadAgent');
|
|
1279
|
+
expect(after?.plan).toEqual(plan);
|
|
1280
|
+
expect(after?.metadata).toEqual({ version: 2, env: 'test' });
|
|
1281
|
+
|
|
1282
|
+
await metaStore.close();
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
it('should no-op when agent does not exist', async () => {
|
|
1286
|
+
const metaStore = await createEventStore({ inMemory: true });
|
|
1287
|
+
|
|
1288
|
+
// Should not throw
|
|
1289
|
+
metaStore.updateAgentMetadata('nonexistent', { name: 'Ghost' });
|
|
1290
|
+
expect(metaStore.getAgent('nonexistent')).toBeNull();
|
|
1291
|
+
|
|
1292
|
+
await metaStore.close();
|
|
1293
|
+
});
|
|
1099
1294
|
});
|
|
1100
1295
|
});
|
|
1101
1296
|
|
|
@@ -467,10 +467,10 @@ describe('Peer Visibility', () => {
|
|
|
467
467
|
it('should filter by whitelist when visibleEventTypes is specified', () => {
|
|
468
468
|
const visibility: PeerVisibilityConfig = {
|
|
469
469
|
exportEvents: true,
|
|
470
|
-
visibleEventTypes: ['spawn', '
|
|
470
|
+
visibleEventTypes: ['spawn', 'stop'],
|
|
471
471
|
};
|
|
472
472
|
expect(isEventTypeVisibleToPeers('spawn', visibility)).toBe(true);
|
|
473
|
-
expect(isEventTypeVisibleToPeers('
|
|
473
|
+
expect(isEventTypeVisibleToPeers('stop', visibility)).toBe(true);
|
|
474
474
|
expect(isEventTypeVisibleToPeers('message', visibility)).toBe(false);
|
|
475
475
|
});
|
|
476
476
|
});
|
|
@@ -503,7 +503,7 @@ describe('Peer Visibility', () => {
|
|
|
503
503
|
{ type: 'spawn', source: { agent_id: 'agent-1' }, payload: {} },
|
|
504
504
|
{ type: 'message', source: { agent_id: 'agent-1' }, payload: {} },
|
|
505
505
|
{ type: 'spawn', source: { agent_id: 'agent-2' }, payload: {} },
|
|
506
|
-
{ type: '
|
|
506
|
+
{ type: 'stop', source: { agent_id: 'agent-2' }, payload: {} },
|
|
507
507
|
];
|
|
508
508
|
|
|
509
509
|
it('should return empty array when export is disabled', () => {
|