macro-agent 0.1.7 → 0.1.10
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.md +179 -38
- package/README.md +781 -131
- package/dist/acp/claude-code-replay.d.ts +11 -0
- package/dist/acp/claude-code-replay.d.ts.map +1 -0
- package/dist/acp/claude-code-replay.js +190 -0
- package/dist/acp/claude-code-replay.js.map +1 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +155 -6
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/types.d.ts +9 -0
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js.map +1 -1
- package/dist/agent/agent-manager-v2.d.ts +21 -0
- package/dist/agent/agent-manager-v2.d.ts.map +1 -1
- package/dist/agent/agent-manager-v2.js +234 -71
- package/dist/agent/agent-manager-v2.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +12 -0
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +15 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/boot-v2.d.ts +41 -0
- package/dist/boot-v2.d.ts.map +1 -1
- package/dist/boot-v2.js +34 -37
- package/dist/boot-v2.js.map +1 -1
- package/dist/cli/index.js +56 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cognitive/macro-agent-backend.d.ts.map +1 -1
- package/dist/cognitive/macro-agent-backend.js +40 -22
- package/dist/cognitive/macro-agent-backend.js.map +1 -1
- package/dist/integrations/skilltree.d.ts.map +1 -1
- package/dist/integrations/skilltree.js +1 -0
- package/dist/integrations/skilltree.js.map +1 -1
- package/dist/lifecycle/cleanup.d.ts +33 -2
- package/dist/lifecycle/cleanup.d.ts.map +1 -1
- package/dist/lifecycle/cleanup.js +28 -6
- package/dist/lifecycle/cleanup.js.map +1 -1
- package/dist/lifecycle/handlers-v2.d.ts +7 -0
- package/dist/lifecycle/handlers-v2.d.ts.map +1 -1
- package/dist/lifecycle/handlers-v2.js +28 -2
- package/dist/lifecycle/handlers-v2.js.map +1 -1
- package/dist/lifecycle/types.d.ts +11 -0
- package/dist/lifecycle/types.d.ts.map +1 -1
- package/dist/lifecycle/types.js.map +1 -1
- package/dist/map/acp-bridge.d.ts +9 -0
- package/dist/map/acp-bridge.d.ts.map +1 -1
- package/dist/map/acp-bridge.js +15 -2
- package/dist/map/acp-bridge.js.map +1 -1
- package/dist/map/cascade-bridge.d.ts +44 -0
- package/dist/map/cascade-bridge.d.ts.map +1 -0
- package/dist/map/cascade-bridge.js +257 -0
- package/dist/map/cascade-bridge.js.map +1 -0
- package/dist/map/lifecycle-bridge.d.ts +1 -8
- package/dist/map/lifecycle-bridge.d.ts.map +1 -1
- package/dist/map/lifecycle-bridge.js +76 -22
- package/dist/map/lifecycle-bridge.js.map +1 -1
- package/dist/map/server.d.ts.map +1 -1
- package/dist/map/server.js +47 -6
- package/dist/map/server.js.map +1 -1
- package/dist/map/sidecar.d.ts.map +1 -1
- package/dist/map/sidecar.js +33 -4
- package/dist/map/sidecar.js.map +1 -1
- package/dist/map/types.d.ts +20 -0
- package/dist/map/types.d.ts.map +1 -1
- package/dist/mcp/tools/done-v2.d.ts.map +1 -1
- package/dist/mcp/tools/done-v2.js +8 -0
- package/dist/mcp/tools/done-v2.js.map +1 -1
- package/dist/teams/team-manager-v2.d.ts.map +1 -1
- package/dist/teams/team-manager-v2.js +26 -0
- package/dist/teams/team-manager-v2.js.map +1 -1
- package/dist/teams/team-runtime-v2.d.ts.map +1 -1
- package/dist/teams/team-runtime-v2.js +16 -3
- package/dist/teams/team-runtime-v2.js.map +1 -1
- package/dist/workspace/config.d.ts +10 -10
- package/dist/workspace/config.d.ts.map +1 -1
- package/dist/workspace/config.js +4 -4
- package/dist/workspace/config.js.map +1 -1
- package/dist/workspace/git-cascade-adapter.d.ts +510 -0
- package/dist/workspace/git-cascade-adapter.d.ts.map +1 -0
- package/dist/workspace/git-cascade-adapter.js +908 -0
- package/dist/workspace/git-cascade-adapter.js.map +1 -0
- package/dist/workspace/index.d.ts +3 -3
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +4 -4
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/landing/direct-push.d.ts +20 -0
- package/dist/workspace/landing/direct-push.d.ts.map +1 -0
- package/dist/workspace/landing/direct-push.js +74 -0
- package/dist/workspace/landing/direct-push.js.map +1 -0
- package/dist/workspace/landing/index.d.ts +29 -0
- package/dist/workspace/landing/index.d.ts.map +1 -0
- package/dist/workspace/landing/index.js +37 -0
- package/dist/workspace/landing/index.js.map +1 -0
- package/dist/workspace/landing/merge-to-parent.d.ts +41 -0
- package/dist/workspace/landing/merge-to-parent.d.ts.map +1 -0
- package/dist/workspace/landing/merge-to-parent.js +185 -0
- package/dist/workspace/landing/merge-to-parent.js.map +1 -0
- package/dist/workspace/landing/optimistic-push.d.ts +16 -0
- package/dist/workspace/landing/optimistic-push.d.ts.map +1 -0
- package/dist/workspace/landing/optimistic-push.js +27 -0
- package/dist/workspace/landing/optimistic-push.js.map +1 -0
- package/dist/workspace/landing/queue-to-branch.d.ts +24 -0
- package/dist/workspace/landing/queue-to-branch.d.ts.map +1 -0
- package/dist/workspace/landing/queue-to-branch.js +79 -0
- package/dist/workspace/landing/queue-to-branch.js.map +1 -0
- package/dist/workspace/merge-queue/merge-queue.d.ts +10 -0
- package/dist/workspace/merge-queue/merge-queue.d.ts.map +1 -1
- package/dist/workspace/merge-queue/merge-queue.js +10 -0
- package/dist/workspace/merge-queue/merge-queue.js.map +1 -1
- package/dist/workspace/merge-queue/types.d.ts +16 -2
- package/dist/workspace/merge-queue/types.d.ts.map +1 -1
- package/dist/workspace/merge-queue/types.js +9 -0
- package/dist/workspace/merge-queue/types.js.map +1 -1
- package/dist/workspace/pool/types.d.ts +1 -0
- package/dist/workspace/pool/types.d.ts.map +1 -1
- package/dist/workspace/pool/worktree-pool.d.ts.map +1 -1
- package/dist/workspace/pool/worktree-pool.js +1 -0
- package/dist/workspace/pool/worktree-pool.js.map +1 -1
- package/dist/workspace/recovery/abandon.d.ts +15 -0
- package/dist/workspace/recovery/abandon.d.ts.map +1 -0
- package/dist/workspace/recovery/abandon.js +45 -0
- package/dist/workspace/recovery/abandon.js.map +1 -0
- package/dist/workspace/recovery/auto-resolve.d.ts +27 -0
- package/dist/workspace/recovery/auto-resolve.d.ts.map +1 -0
- package/dist/workspace/recovery/auto-resolve.js +99 -0
- package/dist/workspace/recovery/auto-resolve.js.map +1 -0
- package/dist/workspace/recovery/defer.d.ts +15 -0
- package/dist/workspace/recovery/defer.d.ts.map +1 -0
- package/dist/workspace/recovery/defer.js +16 -0
- package/dist/workspace/recovery/defer.js.map +1 -0
- package/dist/workspace/recovery/escalate.d.ts +16 -0
- package/dist/workspace/recovery/escalate.d.ts.map +1 -0
- package/dist/workspace/recovery/escalate.js +24 -0
- package/dist/workspace/recovery/escalate.js.map +1 -0
- package/dist/workspace/recovery/index.d.ts +32 -0
- package/dist/workspace/recovery/index.d.ts.map +1 -0
- package/dist/workspace/recovery/index.js +45 -0
- package/dist/workspace/recovery/index.js.map +1 -0
- package/dist/workspace/recovery/spawn-resolver.d.ts +45 -0
- package/dist/workspace/recovery/spawn-resolver.d.ts.map +1 -0
- package/dist/workspace/recovery/spawn-resolver.js +111 -0
- package/dist/workspace/recovery/spawn-resolver.js.map +1 -0
- package/dist/workspace/recovery/types.d.ts +63 -0
- package/dist/workspace/recovery/types.d.ts.map +1 -0
- package/dist/workspace/recovery/types.js +12 -0
- package/dist/workspace/recovery/types.js.map +1 -0
- package/dist/workspace/topology/index.d.ts +9 -0
- package/dist/workspace/topology/index.d.ts.map +1 -0
- package/dist/workspace/topology/index.js +8 -0
- package/dist/workspace/topology/index.js.map +1 -0
- package/dist/workspace/topology/no-workspace.d.ts +18 -0
- package/dist/workspace/topology/no-workspace.d.ts.map +1 -0
- package/dist/workspace/topology/no-workspace.js +25 -0
- package/dist/workspace/topology/no-workspace.js.map +1 -0
- package/dist/workspace/topology/types.d.ts +97 -0
- package/dist/workspace/topology/types.d.ts.map +1 -0
- package/dist/workspace/topology/types.js +20 -0
- package/dist/workspace/topology/types.js.map +1 -0
- package/dist/workspace/topology/yaml-driven.d.ts +69 -0
- package/dist/workspace/topology/yaml-driven.d.ts.map +1 -0
- package/dist/workspace/topology/yaml-driven.js +273 -0
- package/dist/workspace/topology/yaml-driven.js.map +1 -0
- package/dist/workspace/types-v3.d.ts +110 -0
- package/dist/workspace/types-v3.d.ts.map +1 -0
- package/dist/workspace/types-v3.js +20 -0
- package/dist/workspace/types-v3.js.map +1 -0
- package/dist/workspace/types.d.ts +145 -17
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.d.ts +92 -13
- package/dist/workspace/workspace-manager.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.js +373 -13
- package/dist/workspace/workspace-manager.js.map +1 -1
- package/dist/workspace/yaml-schema.d.ts +254 -0
- package/dist/workspace/yaml-schema.d.ts.map +1 -0
- package/dist/workspace/yaml-schema.js +170 -0
- package/dist/workspace/yaml-schema.js.map +1 -0
- package/docs/conflict-recovery.md +472 -0
- package/docs/git-cascade-integration-gaps.md +678 -0
- package/docs/workspace-interfaces.md +731 -0
- package/docs/workspace-redesign-plan.md +302 -0
- package/package.json +4 -4
- package/src/__tests__/e2e/auto-sync.e2e.test.ts +257 -0
- package/src/__tests__/e2e/cascade-rebase.e2e.test.ts +254 -0
- package/src/__tests__/e2e/cli-run.e2e.test.ts +167 -0
- package/src/__tests__/e2e/self-driving-v3.e2e.test.ts +197 -0
- package/src/__tests__/e2e/spawn-resolver.e2e.test.ts +200 -0
- package/src/__tests__/e2e/workspace-lifecycle.e2e.test.ts +30 -22
- package/src/__tests__/e2e/workspace-v3.e2e.test.ts +413 -0
- package/src/acp/__tests__/claude-code-replay.test.ts +225 -0
- package/src/acp/__tests__/macro-agent.test.ts +39 -1
- package/src/acp/claude-code-replay.ts +208 -0
- package/src/acp/macro-agent.ts +167 -9
- package/src/acp/types.ts +10 -0
- package/src/agent/__tests__/agent-manager-topology.test.ts +73 -0
- package/src/agent/__tests__/agent-manager-v2.test.ts +71 -11
- package/src/agent/__tests__/task-ref-resolution.test.ts +231 -0
- package/src/agent/agent-manager-v2.ts +293 -77
- package/src/agent/agent-manager.ts +14 -0
- package/src/agent/types.ts +16 -2
- package/src/boot-v2.ts +87 -36
- package/src/cli/index.ts +61 -0
- package/src/cognitive/__tests__/macro-agent-backend.test.ts +47 -5
- package/src/cognitive/macro-agent-backend.ts +45 -29
- package/src/integrations/skilltree.ts +1 -0
- package/src/lifecycle/cleanup.ts +52 -3
- package/src/lifecycle/handlers-v2.ts +40 -3
- package/src/lifecycle/types.ts +12 -0
- package/src/map/__tests__/cascade-bridge.test.ts +229 -0
- package/src/map/__tests__/lifecycle-bridge.test.ts +165 -22
- package/src/map/acp-bridge.ts +26 -3
- package/src/map/cascade-bridge.ts +301 -0
- package/src/map/lifecycle-bridge.ts +77 -27
- package/src/map/server.ts +47 -6
- package/src/map/sidecar.ts +31 -3
- package/src/map/types.ts +20 -0
- package/src/mcp/tools/done-v2.ts +9 -0
- package/src/teams/team-manager-v2.ts +37 -0
- package/src/teams/team-runtime-v2.ts +23 -3
- package/src/workspace/__tests__/{dataplane-adapter.test.ts → git-cascade-adapter.test.ts} +209 -14
- package/src/workspace/__tests__/self-driving-yaml.test.ts +114 -0
- package/src/workspace/__tests__/shared-worktree-refcount.test.ts +154 -0
- package/src/workspace/__tests__/standalone-mode.test.ts +118 -0
- package/src/workspace/__tests__/workspace-manager-v3.test.ts +245 -0
- package/src/workspace/__tests__/yaml-schema.test.ts +210 -0
- package/src/workspace/config.ts +11 -11
- package/src/workspace/git-cascade-adapter.ts +1186 -0
- package/src/workspace/index.ts +11 -11
- package/src/workspace/landing/__tests__/strategies.test.ts +142 -0
- package/src/workspace/landing/direct-push.ts +91 -0
- package/src/workspace/landing/index.ts +40 -0
- package/src/workspace/landing/merge-to-parent.ts +228 -0
- package/src/workspace/landing/optimistic-push.ts +36 -0
- package/src/workspace/landing/queue-to-branch.ts +108 -0
- package/src/workspace/merge-queue/merge-queue.ts +10 -0
- package/src/workspace/merge-queue/types.ts +16 -2
- package/src/workspace/pool/__tests__/worktree-pool.integration.test.ts +5 -5
- package/src/workspace/pool/types.ts +1 -0
- package/src/workspace/pool/worktree-pool.ts +1 -0
- package/src/workspace/recovery/__tests__/auto-resolve-integration.test.ts +127 -0
- package/src/workspace/recovery/__tests__/spawn-resolver.test.ts +139 -0
- package/src/workspace/recovery/__tests__/strategies.test.ts +145 -0
- package/src/workspace/recovery/abandon.ts +51 -0
- package/src/workspace/recovery/auto-resolve.ts +119 -0
- package/src/workspace/recovery/defer.ts +23 -0
- package/src/workspace/recovery/escalate.ts +30 -0
- package/src/workspace/recovery/index.ts +58 -0
- package/src/workspace/recovery/spawn-resolver.ts +145 -0
- package/src/workspace/recovery/types.ts +54 -0
- package/src/workspace/topology/__tests__/yaml-driven.test.ts +345 -0
- package/src/workspace/topology/index.ts +18 -0
- package/src/workspace/topology/no-workspace.ts +39 -0
- package/src/workspace/topology/types.ts +116 -0
- package/src/workspace/topology/yaml-driven.ts +316 -0
- package/src/workspace/types-v3.ts +155 -0
- package/src/workspace/types.ts +191 -20
- package/src/workspace/workspace-manager.ts +474 -19
- package/src/workspace/yaml-schema.ts +216 -0
- package/src/workspace/dataplane-adapter.ts +0 -546
package/src/boot-v2.ts
CHANGED
|
@@ -121,6 +121,52 @@ export interface BootV2Config {
|
|
|
121
121
|
};
|
|
122
122
|
};
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Cascade event binding config. Controls how cascade events emitted by
|
|
126
|
+
* git-cascade-backed agents get tagged with external task references for
|
|
127
|
+
* hub projection (changelog, task↔stream binding). Independent of MAP
|
|
128
|
+
* transport: cascade events are data/identity, not transport.
|
|
129
|
+
*/
|
|
130
|
+
cascade?: {
|
|
131
|
+
/**
|
|
132
|
+
* Default OpenTasks resource ID for this swarm. When set, the agent
|
|
133
|
+
* manager auto-builds `taskRef = { resource_id, node_id: task_id }`
|
|
134
|
+
* for spawned agents so cascade events carry the binding without
|
|
135
|
+
* callers constructing refs by hand.
|
|
136
|
+
*
|
|
137
|
+
* Leave undefined if:
|
|
138
|
+
* - The swarm touches multiple opentasks graphs (use `resolveTaskRef`).
|
|
139
|
+
* - Every caller sets `SpawnAgentOptions.taskRef` explicitly.
|
|
140
|
+
* - You don't care about hub task↔stream binding.
|
|
141
|
+
*/
|
|
142
|
+
taskResourceId?: string;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Custom resolver for multi-graph deployments. Called at every spawn;
|
|
146
|
+
* return a `TaskRef` to set the binding or `undefined` to skip.
|
|
147
|
+
* Precedence: explicit `SpawnAgentOptions.taskRef` > `resolveTaskRef` >
|
|
148
|
+
* `taskResourceId` fallback (combined with `spawnOptions.task_id`).
|
|
149
|
+
*
|
|
150
|
+
* Keep implementations cheap — this runs on every spawn.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* resolveTaskRef: (opts) => {
|
|
154
|
+
* const graph = graphForCwd(opts.cwd ?? process.cwd());
|
|
155
|
+
* return graph ? { resource_id: graph.resourceId, node_id: String(opts.task_id) } : undefined;
|
|
156
|
+
* }
|
|
157
|
+
*/
|
|
158
|
+
resolveTaskRef?: (
|
|
159
|
+
spawnOptions: import("./agent/types.js").SpawnAgentOptions
|
|
160
|
+
) => import("git-cascade/events").TaskRef | undefined;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Override the default `x-cascade` event prefix. Useful for branded
|
|
164
|
+
* deployments or isolating cascade namespaces in testing. Affects all
|
|
165
|
+
* events emitted by the tracker embedded in this swarm.
|
|
166
|
+
*/
|
|
167
|
+
eventPrefix?: string;
|
|
168
|
+
};
|
|
169
|
+
|
|
124
170
|
/** minimem (agent memory) — registers as MCP server for all agents */
|
|
125
171
|
minimem?: {
|
|
126
172
|
enabled?: boolean;
|
|
@@ -270,6 +316,8 @@ export async function bootV2(
|
|
|
270
316
|
serverUrl: config.serverUrl,
|
|
271
317
|
serverToken: config.serverToken,
|
|
272
318
|
controlSocketPath,
|
|
319
|
+
taskResourceId: config.cascade?.taskResourceId,
|
|
320
|
+
resolveTaskRef: config.cascade?.resolveTaskRef,
|
|
273
321
|
}
|
|
274
322
|
);
|
|
275
323
|
|
|
@@ -344,23 +392,25 @@ export async function bootV2(
|
|
|
344
392
|
}, HEALTH_CHECK_INTERVAL_MS);
|
|
345
393
|
healthCheckTimer.unref(); // Don't prevent process exit
|
|
346
394
|
|
|
395
|
+
// Shared mutable system reference — passed to ACP server, MAP server, API server.
|
|
396
|
+
// Components created before the sidecar (steps 9-11) receive this object.
|
|
397
|
+
// When the sidecar is created (step 13), it's attached here so all components
|
|
398
|
+
// see it via the same reference (e.g., ACP handler accessing system.mapSidecar).
|
|
399
|
+
const systemRef = {
|
|
400
|
+
agentManager,
|
|
401
|
+
agentStore,
|
|
402
|
+
inboxAdapter,
|
|
403
|
+
tasksAdapter,
|
|
404
|
+
triggerSystem,
|
|
405
|
+
controlServer,
|
|
406
|
+
roleRegistry,
|
|
407
|
+
controlSocketPath,
|
|
408
|
+
} as any;
|
|
409
|
+
|
|
347
410
|
// 9. REST API server (optional)
|
|
348
411
|
let apiServer: ApiServer | null = null;
|
|
349
412
|
if (config.api?.enabled) {
|
|
350
413
|
const { createApiServer } = await import("./api/server.js");
|
|
351
|
-
// Build a partial system reference for the API server.
|
|
352
|
-
// The full system object is returned below; we create the API server
|
|
353
|
-
// first so it can be included in the return value and shut down cleanly.
|
|
354
|
-
const systemRef = {
|
|
355
|
-
agentManager,
|
|
356
|
-
agentStore,
|
|
357
|
-
inboxAdapter,
|
|
358
|
-
tasksAdapter,
|
|
359
|
-
triggerSystem,
|
|
360
|
-
controlServer,
|
|
361
|
-
roleRegistry,
|
|
362
|
-
controlSocketPath,
|
|
363
|
-
} as any;
|
|
364
414
|
apiServer = createApiServer(systemRef, {
|
|
365
415
|
port: config.api.port,
|
|
366
416
|
host: config.api.host,
|
|
@@ -373,17 +423,7 @@ export async function bootV2(
|
|
|
373
423
|
if (config.acp?.enabled) {
|
|
374
424
|
const { createWebSocketACPServer } = await import("./acp/websocket-server.js");
|
|
375
425
|
acpServer = createWebSocketACPServer(
|
|
376
|
-
|
|
377
|
-
{
|
|
378
|
-
agentManager,
|
|
379
|
-
agentStore,
|
|
380
|
-
inboxAdapter,
|
|
381
|
-
tasksAdapter,
|
|
382
|
-
triggerSystem,
|
|
383
|
-
controlServer,
|
|
384
|
-
roleRegistry,
|
|
385
|
-
controlSocketPath,
|
|
386
|
-
} as any,
|
|
426
|
+
systemRef,
|
|
387
427
|
{
|
|
388
428
|
port: config.acp.port,
|
|
389
429
|
host: config.acp.host,
|
|
@@ -404,17 +444,7 @@ export async function bootV2(
|
|
|
404
444
|
agentStore,
|
|
405
445
|
inboxAdapter,
|
|
406
446
|
tasksAdapter,
|
|
407
|
-
|
|
408
|
-
system: {
|
|
409
|
-
agentManager,
|
|
410
|
-
agentStore,
|
|
411
|
-
inboxAdapter,
|
|
412
|
-
tasksAdapter,
|
|
413
|
-
triggerSystem,
|
|
414
|
-
controlServer,
|
|
415
|
-
roleRegistry,
|
|
416
|
-
controlSocketPath,
|
|
417
|
-
} as any,
|
|
447
|
+
system: systemRef,
|
|
418
448
|
},
|
|
419
449
|
{
|
|
420
450
|
port: config.mapServer.port,
|
|
@@ -468,8 +498,27 @@ export async function bootV2(
|
|
|
468
498
|
if (config.map?.enabled && config.map.server) {
|
|
469
499
|
try {
|
|
470
500
|
const { createMAPSidecar } = await import("./map/sidecar.js");
|
|
501
|
+
// If a workspace manager is present, pull out its GitCascadeAdapter
|
|
502
|
+
// so the sidecar can forward cascade events to the hub.
|
|
503
|
+
const wsMgr = config.workspaceManager as
|
|
504
|
+
| {
|
|
505
|
+
getGitCascadeAdapter?: () =>
|
|
506
|
+
| import("./workspace/git-cascade-adapter.js").GitCascadeAdapter
|
|
507
|
+
| undefined;
|
|
508
|
+
}
|
|
509
|
+
| undefined;
|
|
510
|
+
const gitCascadeAdapter = wsMgr?.getGitCascadeAdapter?.();
|
|
471
511
|
mapSidecar = createMAPSidecar(
|
|
472
|
-
{
|
|
512
|
+
{
|
|
513
|
+
agentManager,
|
|
514
|
+
agentStore,
|
|
515
|
+
inboxAdapter,
|
|
516
|
+
tasksAdapter,
|
|
517
|
+
getLocalMapId: mapServerInstance
|
|
518
|
+
? (id: string) => mapServerInstance!.getLocalMapId(id)
|
|
519
|
+
: undefined,
|
|
520
|
+
gitCascadeAdapter,
|
|
521
|
+
},
|
|
473
522
|
{
|
|
474
523
|
server: config.map.server,
|
|
475
524
|
token: config.map.token,
|
|
@@ -487,6 +536,8 @@ export async function bootV2(
|
|
|
487
536
|
await mapSidecar.start();
|
|
488
537
|
// Wire sidecar into agent manager for session-end checkpoints
|
|
489
538
|
agentManager.setSidecar(mapSidecar);
|
|
539
|
+
// Attach to shared system ref so ACP/MAP handlers can access it
|
|
540
|
+
systemRef.mapSidecar = mapSidecar;
|
|
490
541
|
} catch (err) {
|
|
491
542
|
// Non-fatal — MAP hub connectivity is optional
|
|
492
543
|
console.warn(
|
package/src/cli/index.ts
CHANGED
|
@@ -498,6 +498,67 @@ program
|
|
|
498
498
|
}
|
|
499
499
|
});
|
|
500
500
|
|
|
501
|
+
// ─────────────────────────────────────────────────────────────────
|
|
502
|
+
// Run Team Command (Phase 10)
|
|
503
|
+
// ─────────────────────────────────────────────────────────────────
|
|
504
|
+
|
|
505
|
+
program
|
|
506
|
+
.command("run <teamName>")
|
|
507
|
+
.description("Boot the system, start a team by name, and optionally prompt the root agent")
|
|
508
|
+
.option("--task <task>", "Task to prompt the root agent with")
|
|
509
|
+
.option("--cwd <path>", "Working directory for agents")
|
|
510
|
+
.option("--base-path <path>", "Base path for team YAML lookup (default: cwd)")
|
|
511
|
+
.action(async (teamName: string, options: { task?: string; cwd?: string; basePath?: string }) => {
|
|
512
|
+
const cwd = options.cwd ?? process.cwd();
|
|
513
|
+
console.log(chalk.blue(`Booting macro-agent and starting team: ${teamName}`));
|
|
514
|
+
|
|
515
|
+
let system: Awaited<ReturnType<typeof bootV2>> | null = null;
|
|
516
|
+
try {
|
|
517
|
+
system = await bootV2({ cwd });
|
|
518
|
+
console.log(chalk.green("System booted."));
|
|
519
|
+
|
|
520
|
+
// Construct & install a TeamManagerV2; start the requested team.
|
|
521
|
+
const { TeamManagerV2 } = await import("../teams/team-manager-v2.js");
|
|
522
|
+
const teamManager = new TeamManagerV2({
|
|
523
|
+
agentManager: system.agentManager,
|
|
524
|
+
inboxAdapter: system.inboxAdapter,
|
|
525
|
+
tasksAdapter: system.tasksAdapter,
|
|
526
|
+
});
|
|
527
|
+
teamManager.install();
|
|
528
|
+
|
|
529
|
+
const instanceId = await teamManager.startTeam(teamName, options.basePath ?? cwd);
|
|
530
|
+
console.log(chalk.green(`Team started: ${teamName} (instance ${instanceId})`));
|
|
531
|
+
|
|
532
|
+
// Find the root agent (first spawned agent in the instance)
|
|
533
|
+
const agents = system.agentStore.listAgents({ state: "running" });
|
|
534
|
+
const root = agents[0];
|
|
535
|
+
|
|
536
|
+
if (options.task && root) {
|
|
537
|
+
console.log(chalk.gray(`Prompting root agent (${root.id}) with task...`));
|
|
538
|
+
const iter = system.agentManager.prompt(root.id, options.task);
|
|
539
|
+
for await (const chunk of iter) {
|
|
540
|
+
process.stdout.write(typeof chunk === "string" ? chunk : JSON.stringify(chunk));
|
|
541
|
+
}
|
|
542
|
+
console.log();
|
|
543
|
+
} else if (!root) {
|
|
544
|
+
console.log(chalk.yellow("No root agent found to prompt."));
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
console.log(chalk.gray("Press Ctrl+C to shut down."));
|
|
548
|
+
|
|
549
|
+
// Graceful shutdown on SIGINT
|
|
550
|
+
process.on("SIGINT", async () => {
|
|
551
|
+
console.log(chalk.yellow("\nShutting down..."));
|
|
552
|
+
if (system) await system.shutdown();
|
|
553
|
+
process.exit(0);
|
|
554
|
+
});
|
|
555
|
+
} catch (error) {
|
|
556
|
+
console.error(chalk.red(`Failed to run team: ${error}`));
|
|
557
|
+
if (system) await system.shutdown();
|
|
558
|
+
process.exit(1);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
|
|
501
562
|
// ─────────────────────────────────────────────────────────────────
|
|
502
563
|
// Parse and Run
|
|
503
564
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -126,13 +126,31 @@ describe("MacroAgentBackend", () => {
|
|
|
126
126
|
|
|
127
127
|
describe("spawn", () => {
|
|
128
128
|
it("spawns analyst via agentManager", async () => {
|
|
129
|
-
|
|
129
|
+
// Use a deferred promise so promptUntilDone hangs, keeping session in "running"
|
|
130
|
+
let resolvePrompt!: () => void;
|
|
131
|
+
const hangingPrompt = new Promise<void>((r) => { resolvePrompt = r; });
|
|
132
|
+
|
|
133
|
+
const am = createMockAgentManager({
|
|
134
|
+
promptUntilDone: vi.fn().mockImplementation(async () => {
|
|
135
|
+
await hangingPrompt;
|
|
136
|
+
return {
|
|
137
|
+
doneCalled: true,
|
|
138
|
+
doneStatus: "completed",
|
|
139
|
+
exceededMax: false,
|
|
140
|
+
followUpCount: 0,
|
|
141
|
+
updates: [],
|
|
142
|
+
};
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
const b = new MacroAgentBackend(am);
|
|
146
|
+
|
|
147
|
+
const session = await b.spawn({
|
|
130
148
|
agentType: "claude-code",
|
|
131
149
|
task: { description: "Analyze trajectory" },
|
|
132
150
|
cwd: "/workspace",
|
|
133
151
|
});
|
|
134
152
|
|
|
135
|
-
expect(
|
|
153
|
+
expect(am.spawn).toHaveBeenCalledWith(
|
|
136
154
|
expect.objectContaining({
|
|
137
155
|
task: "Analyze trajectory",
|
|
138
156
|
role: "analyst",
|
|
@@ -143,6 +161,9 @@ describe("MacroAgentBackend", () => {
|
|
|
143
161
|
expect(session.state).toBe("running");
|
|
144
162
|
expect(session.agentType).toBe("claude-code");
|
|
145
163
|
expect(session.task.description).toBe("Analyze trajectory");
|
|
164
|
+
|
|
165
|
+
// Let the hanging prompt resolve to avoid dangling promises
|
|
166
|
+
resolvePrompt();
|
|
146
167
|
});
|
|
147
168
|
|
|
148
169
|
it("returns session with unique ID", async () => {
|
|
@@ -382,17 +403,38 @@ describe("MacroAgentBackend", () => {
|
|
|
382
403
|
|
|
383
404
|
describe("terminate", () => {
|
|
384
405
|
it("terminates the macro-agent process", async () => {
|
|
385
|
-
|
|
406
|
+
// Use a deferred promise so promptUntilDone hangs until after terminate
|
|
407
|
+
let resolvePrompt!: () => void;
|
|
408
|
+
const hangingPrompt = new Promise<void>((r) => { resolvePrompt = r; });
|
|
409
|
+
|
|
410
|
+
const am = createMockAgentManager({
|
|
411
|
+
promptUntilDone: vi.fn().mockImplementation(async () => {
|
|
412
|
+
await hangingPrompt;
|
|
413
|
+
return {
|
|
414
|
+
doneCalled: true,
|
|
415
|
+
doneStatus: "completed",
|
|
416
|
+
exceededMax: false,
|
|
417
|
+
followUpCount: 0,
|
|
418
|
+
updates: [],
|
|
419
|
+
};
|
|
420
|
+
}),
|
|
421
|
+
});
|
|
422
|
+
const b = new MacroAgentBackend(am);
|
|
423
|
+
|
|
424
|
+
const session = await b.spawn({
|
|
386
425
|
agentType: "claude-code",
|
|
387
426
|
task: { description: "test" },
|
|
388
427
|
});
|
|
389
428
|
|
|
390
|
-
await
|
|
429
|
+
await b.terminate(session.id);
|
|
391
430
|
|
|
392
|
-
expect(
|
|
431
|
+
expect(am.terminate).toHaveBeenCalledWith(
|
|
393
432
|
"agent_test123",
|
|
394
433
|
"cancelled",
|
|
395
434
|
);
|
|
435
|
+
|
|
436
|
+
// Let the hanging prompt resolve to avoid dangling promises
|
|
437
|
+
resolvePrompt();
|
|
396
438
|
});
|
|
397
439
|
|
|
398
440
|
it("sets session to failed", async () => {
|
|
@@ -240,6 +240,46 @@ export class MacroAgentBackend {
|
|
|
240
240
|
const timeout = config.timeout;
|
|
241
241
|
let softTimer: ReturnType<typeof setTimeout> | undefined;
|
|
242
242
|
let hardTimer: ReturnType<typeof setTimeout> | undefined;
|
|
243
|
+
let completionNotified = false;
|
|
244
|
+
|
|
245
|
+
// Helper: fire the completion callback + inbox notification exactly once.
|
|
246
|
+
// Called from both the hard-timer path and the finally block to avoid a
|
|
247
|
+
// race where waitForSession returns (state != "running") before finally
|
|
248
|
+
// runs and fires the callback.
|
|
249
|
+
const notifyCompletion = async (): Promise<void> => {
|
|
250
|
+
if (completionNotified) return;
|
|
251
|
+
if (session.state !== "completed" && session.state !== "failed") return;
|
|
252
|
+
completionNotified = true;
|
|
253
|
+
|
|
254
|
+
const completeEvent: SessionCompleteEvent = {
|
|
255
|
+
sessionId: session.id,
|
|
256
|
+
agentId: agentId as string,
|
|
257
|
+
state: session.state,
|
|
258
|
+
duration_ms: session.endTime
|
|
259
|
+
? session.endTime.getTime() - session.startTime.getTime()
|
|
260
|
+
: 0,
|
|
261
|
+
message_count: session.messages.length,
|
|
262
|
+
tool_call_count: session.toolCalls.length,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
this.onSessionComplete?.(completeEvent);
|
|
266
|
+
|
|
267
|
+
if (this.inboxAdapter) {
|
|
268
|
+
try {
|
|
269
|
+
await this.inboxAdapter.send(
|
|
270
|
+
agentId as string,
|
|
271
|
+
agentId as string,
|
|
272
|
+
{
|
|
273
|
+
type: "session.complete",
|
|
274
|
+
sessionId: session.id,
|
|
275
|
+
state: session.state,
|
|
276
|
+
duration_ms: completeEvent.duration_ms,
|
|
277
|
+
outcome: session.state === "completed" ? "success" : "failure",
|
|
278
|
+
},
|
|
279
|
+
);
|
|
280
|
+
} catch { /* best-effort */ }
|
|
281
|
+
}
|
|
282
|
+
};
|
|
243
283
|
|
|
244
284
|
try {
|
|
245
285
|
if (timeout && timeout > 0) {
|
|
@@ -263,6 +303,9 @@ export class MacroAgentBackend {
|
|
|
263
303
|
session.state = "failed";
|
|
264
304
|
session.error = "Timeout exceeded";
|
|
265
305
|
session.endTime = new Date();
|
|
306
|
+
// Fire completion callback immediately — the finally block's
|
|
307
|
+
// deferred callback could race with waitForSession returning.
|
|
308
|
+
void notifyCompletion();
|
|
266
309
|
this.agentManager.terminate(agentId, "timeout").catch(() => {});
|
|
267
310
|
}, timeout);
|
|
268
311
|
}
|
|
@@ -307,35 +350,8 @@ export class MacroAgentBackend {
|
|
|
307
350
|
}
|
|
308
351
|
|
|
309
352
|
// Notify completion (no trajectory extraction — OpenHive handles that via sessionlog)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
sessionId: session.id,
|
|
313
|
-
agentId: agentId as string,
|
|
314
|
-
state: session.state,
|
|
315
|
-
duration_ms: session.endTime
|
|
316
|
-
? session.endTime.getTime() - session.startTime.getTime()
|
|
317
|
-
: 0,
|
|
318
|
-
message_count: session.messages.length,
|
|
319
|
-
tool_call_count: session.toolCalls.length,
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
this.onSessionComplete?.(completeEvent);
|
|
323
|
-
|
|
324
|
-
if (this.inboxAdapter) {
|
|
325
|
-
await this.inboxAdapter.send(
|
|
326
|
-
agentId as string,
|
|
327
|
-
agentId as string,
|
|
328
|
-
{
|
|
329
|
-
type: "session.complete",
|
|
330
|
-
sessionId: session.id,
|
|
331
|
-
state: session.state,
|
|
332
|
-
duration_ms: completeEvent.duration_ms,
|
|
333
|
-
outcome: session.state === "completed" ? "success" : "failure",
|
|
334
|
-
},
|
|
335
|
-
{ subject: "session.complete" },
|
|
336
|
-
).catch(() => {});
|
|
337
|
-
}
|
|
338
|
-
}
|
|
353
|
+
// This is a no-op if the hard-timer path already fired it.
|
|
354
|
+
await notifyCompletion();
|
|
339
355
|
|
|
340
356
|
// Clean up agent process
|
|
341
357
|
if (session.state !== "running") {
|
package/src/lifecycle/cleanup.ts
CHANGED
|
@@ -124,15 +124,45 @@ export function detectCleanupStatus(
|
|
|
124
124
|
// =============================================================================
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
*
|
|
127
|
+
* Optional handle for routing commits through git-cascade so the resulting
|
|
128
|
+
* commit gets a Change-Id trailer and emits an `x-cascade/stream.committed`
|
|
129
|
+
* event. When omitted, commits are made via raw git (no Change-Id, no
|
|
130
|
+
* cascade event) — used by legacy/null-workspace paths.
|
|
131
|
+
*/
|
|
132
|
+
export interface TrackedCommitHandle {
|
|
133
|
+
/** WorkspaceManager-style commitChanges signature */
|
|
134
|
+
commitChanges(opts: {
|
|
135
|
+
streamId: string;
|
|
136
|
+
agentId: string;
|
|
137
|
+
worktree: string;
|
|
138
|
+
message: string;
|
|
139
|
+
metadata?: Record<string, unknown>;
|
|
140
|
+
}): { commit: string; changeId: string };
|
|
141
|
+
/** Stream this commit belongs to */
|
|
142
|
+
streamId: string;
|
|
143
|
+
/** Agent making the commit */
|
|
144
|
+
agentId: string;
|
|
145
|
+
/** Optional metadata threaded into the cascade event (e.g. `{ task_ref }`) */
|
|
146
|
+
metadata?: Record<string, unknown>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Commit all uncommitted changes in a workspace.
|
|
151
|
+
*
|
|
152
|
+
* When a `TrackedCommitHandle` is supplied, the commit goes through
|
|
153
|
+
* git-cascade's tracker — gaining a stable Change-Id trailer and emitting
|
|
154
|
+
* `x-cascade/stream.committed` so OpenHive sees the work. Without a handle,
|
|
155
|
+
* falls back to raw git (legacy behavior).
|
|
128
156
|
*
|
|
129
157
|
* @param workspacePath - Path to the workspace
|
|
130
158
|
* @param message - Commit message
|
|
159
|
+
* @param tracked - Optional handle to commit via the cascade tracker
|
|
131
160
|
* @returns Commit hash if successful, undefined if nothing to commit
|
|
132
161
|
*/
|
|
133
162
|
export function commitChanges(
|
|
134
163
|
workspacePath: string,
|
|
135
|
-
message: string
|
|
164
|
+
message: string,
|
|
165
|
+
tracked?: TrackedCommitHandle
|
|
136
166
|
): string | undefined {
|
|
137
167
|
try {
|
|
138
168
|
// Check if there are changes to commit
|
|
@@ -140,7 +170,26 @@ export function commitChanges(
|
|
|
140
170
|
return undefined;
|
|
141
171
|
}
|
|
142
172
|
|
|
143
|
-
//
|
|
173
|
+
// Tracked path: stage + commit through git-cascade so Change-Id +
|
|
174
|
+
// x-cascade events fire.
|
|
175
|
+
if (tracked) {
|
|
176
|
+
try {
|
|
177
|
+
const { commit } = tracked.commitChanges({
|
|
178
|
+
streamId: tracked.streamId,
|
|
179
|
+
agentId: tracked.agentId,
|
|
180
|
+
worktree: workspacePath,
|
|
181
|
+
message,
|
|
182
|
+
metadata: tracked.metadata,
|
|
183
|
+
});
|
|
184
|
+
return commit;
|
|
185
|
+
} catch {
|
|
186
|
+
// Fall through to raw-git path on tracker failure (e.g., stream
|
|
187
|
+
// conflicted) so callers still get a commit. Caveat: no Change-Id
|
|
188
|
+
// and no cascade event in this fallback.
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Raw-git path: stage all changes
|
|
144
193
|
execFileSync("git", ["add", "--all"], {
|
|
145
194
|
cwd: workspacePath,
|
|
146
195
|
encoding: "utf-8",
|
|
@@ -22,8 +22,9 @@ import type {
|
|
|
22
22
|
CleanupStatus,
|
|
23
23
|
DoneHandlerResult,
|
|
24
24
|
} from "./types.js";
|
|
25
|
-
import { commitChanges, attemptMerge, abortMerge } from "./cleanup.js";
|
|
25
|
+
import { commitChanges, attemptMerge, abortMerge, type TrackedCommitHandle } from "./cleanup.js";
|
|
26
26
|
import type { MergeQueueInterface } from "../workspace/merge-queue/types.js";
|
|
27
|
+
import type { WorkspaceManager } from "../workspace/types.js";
|
|
27
28
|
import {
|
|
28
29
|
getAllDescendants,
|
|
29
30
|
needsCascadeTermination,
|
|
@@ -40,6 +41,40 @@ export interface HandlerDepsV2 {
|
|
|
40
41
|
agentManager: AgentManager;
|
|
41
42
|
taskMode?: "push" | "pull";
|
|
42
43
|
mergeQueue?: MergeQueueInterface;
|
|
44
|
+
/**
|
|
45
|
+
* Optional workspace manager. When provided AND `context.streamId` is set,
|
|
46
|
+
* commits route through the cascade tracker (Change-Id + x-cascade events).
|
|
47
|
+
* Without it, commits use raw git (legacy / null-workspace path).
|
|
48
|
+
*/
|
|
49
|
+
workspaceManager?: WorkspaceManager;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Tracked Commit Helper
|
|
54
|
+
// =============================================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Build a TrackedCommitHandle when the agent has a streamId + workspaceManager.
|
|
58
|
+
* Returns undefined if either is missing — caller falls back to raw git.
|
|
59
|
+
*/
|
|
60
|
+
function buildTrackedHandle(
|
|
61
|
+
context: LifecycleContext,
|
|
62
|
+
deps: HandlerDepsV2
|
|
63
|
+
): TrackedCommitHandle | undefined {
|
|
64
|
+
if (!context.streamId || !deps.workspaceManager) return undefined;
|
|
65
|
+
const ws = deps.workspaceManager;
|
|
66
|
+
// Build metadata with task_ref if known. Empty object is fine — the hub
|
|
67
|
+
// ignores unknown fields, and back-fill kicks in if task_ref appears later.
|
|
68
|
+
const metadata: Record<string, unknown> = {};
|
|
69
|
+
if (context.taskRef) {
|
|
70
|
+
metadata.task_ref = context.taskRef;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
streamId: context.streamId,
|
|
74
|
+
agentId: context.agentId,
|
|
75
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
|
|
76
|
+
commitChanges: (opts) => ws.commitChanges(opts),
|
|
77
|
+
};
|
|
43
78
|
}
|
|
44
79
|
|
|
45
80
|
// =============================================================================
|
|
@@ -110,10 +145,12 @@ async function handleWorkerDone(
|
|
|
110
145
|
? `WIP: ${args.summary}`
|
|
111
146
|
: `WIP: Auto-commit from done() with ${uncommittedCount} uncommitted file(s)`;
|
|
112
147
|
|
|
113
|
-
const
|
|
148
|
+
const tracked = buildTrackedHandle(context, deps);
|
|
149
|
+
const commitHash = commitChanges(context.workspacePath, commitMessage, tracked);
|
|
114
150
|
if (commitHash) {
|
|
151
|
+
const via = tracked ? "tracker" : "raw-git";
|
|
115
152
|
cleanupActions.push(
|
|
116
|
-
`Committed ${uncommittedCount} file(s): ${commitHash.slice(0, 8)}`
|
|
153
|
+
`Committed ${uncommittedCount} file(s) via ${via}: ${commitHash.slice(0, 8)}`
|
|
117
154
|
);
|
|
118
155
|
} else {
|
|
119
156
|
warnings.push("Failed to auto-commit uncommitted changes");
|
package/src/lifecycle/types.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import type { AgentId, TaskId } from "../store/types/index.js";
|
|
12
|
+
import type { TaskRef } from "git-cascade/events";
|
|
12
13
|
|
|
13
14
|
// =============================================================================
|
|
14
15
|
// Done Status Types
|
|
@@ -120,6 +121,17 @@ export interface LifecycleContext {
|
|
|
120
121
|
|
|
121
122
|
/** Resolved capabilities for the agent's role (for capability-based handler dispatch) */
|
|
122
123
|
capabilities?: string[];
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Optional reference to an external task this agent is working on. When
|
|
127
|
+
* present, threaded into commit metadata so cascade events carry the
|
|
128
|
+
* binding (enabling task↔stream queries on the OpenHive hub).
|
|
129
|
+
*
|
|
130
|
+
* Sourced from `SpawnAgentOptions.taskRef` at spawn time and propagated
|
|
131
|
+
* via the agent manager. Late-binding (mid-session pull-mode claim) can
|
|
132
|
+
* mutate this on the live context.
|
|
133
|
+
*/
|
|
134
|
+
taskRef?: TaskRef;
|
|
123
135
|
}
|
|
124
136
|
|
|
125
137
|
/**
|