macro-agent 0.1.8 → 0.1.11
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 +263 -33
- 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 +192 -7
- 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/adapters/tasks-adapter.d.ts.map +1 -1
- package/dist/adapters/tasks-adapter.js +3 -0
- package/dist/adapters/tasks-adapter.js.map +1 -1
- package/dist/adapters/types.d.ts +1 -0
- package/dist/adapters/types.d.ts.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 +308 -54
- 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/agent-store.d.ts +10 -0
- package/dist/agent/agent-store.d.ts.map +1 -1
- package/dist/agent/agent-store.js +22 -0
- package/dist/agent/agent-store.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 +129 -1
- package/dist/boot-v2.d.ts.map +1 -1
- package/dist/boot-v2.js +359 -8
- package/dist/boot-v2.js.map +1 -1
- package/dist/cli/acp.js +4 -0
- package/dist/cli/acp.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/cascade.d.ts +25 -2
- package/dist/lifecycle/cascade.d.ts.map +1 -1
- package/dist/lifecycle/cascade.js +70 -2
- package/dist/lifecycle/cascade.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-action-handler.d.ts +24 -0
- package/dist/map/cascade-action-handler.d.ts.map +1 -0
- package/dist/map/cascade-action-handler.js +170 -0
- package/dist/map/cascade-action-handler.js.map +1 -0
- 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 +294 -0
- package/dist/map/cascade-bridge.js.map +1 -0
- package/dist/map/coordination-handler.d.ts.map +1 -1
- package/dist/map/coordination-handler.js +12 -1
- package/dist/map/coordination-handler.js.map +1 -1
- package/dist/map/lifecycle-bridge.d.ts +1 -1
- package/dist/map/lifecycle-bridge.d.ts.map +1 -1
- package/dist/map/lifecycle-bridge.js +58 -23
- package/dist/map/lifecycle-bridge.js.map +1 -1
- package/dist/map/server.d.ts.map +1 -1
- package/dist/map/server.js +219 -7
- package/dist/map/server.js.map +1 -1
- package/dist/map/sidecar.d.ts.map +1 -1
- package/dist/map/sidecar.js +49 -2
- package/dist/map/sidecar.js.map +1 -1
- package/dist/map/types.d.ts +22 -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 +934 -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 +186 -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 +118 -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 +117 -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 +162 -17
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.d.ts +101 -13
- package/dist/workspace/workspace-manager.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.js +416 -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/design/task-dispatcher.md +880 -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 +6 -5
- package/src/__tests__/boot-v2.test.ts +435 -0
- package/src/__tests__/e2e/acp-over-map.e2e.test.ts +92 -0
- package/src/__tests__/e2e/auto-sync.e2e.test.ts +257 -0
- package/src/__tests__/e2e/bootstrap.e2e.test.ts +319 -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/dispatch-coordination.e2e.test.ts +495 -0
- package/src/__tests__/e2e/dispatch-live.e2e.test.ts +564 -0
- package/src/__tests__/e2e/dispatch-opentasks.e2e.test.ts +496 -0
- package/src/__tests__/e2e/dispatch-phase2-live.e2e.test.ts +456 -0
- package/src/__tests__/e2e/dispatch-phase2.e2e.test.ts +386 -0
- package/src/__tests__/e2e/dispatch.e2e.test.ts +376 -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 +203 -10
- package/src/acp/types.ts +10 -0
- package/src/adapters/__tests__/tasks-adapter.test.ts +1 -0
- package/src/adapters/tasks-adapter.ts +3 -0
- package/src/adapters/types.ts +1 -0
- package/src/agent/__tests__/agent-manager-topology.test.ts +73 -0
- package/src/agent/__tests__/agent-manager-v2.test.ts +66 -0
- package/src/agent/__tests__/agent-store.test.ts +52 -0
- package/src/agent/__tests__/task-ref-resolution.test.ts +231 -0
- package/src/agent/agent-manager-v2.ts +372 -59
- package/src/agent/agent-manager.ts +14 -0
- package/src/agent/agent-store.ts +24 -0
- package/src/agent/types.ts +16 -2
- package/src/boot-v2.ts +589 -35
- package/src/cli/acp.ts +4 -0
- package/src/cli/index.ts +61 -0
- package/src/cognitive/macro-agent-backend.ts +45 -29
- package/src/integrations/skilltree.ts +1 -0
- package/src/lifecycle/__tests__/cascade-consolidation.test.ts +240 -0
- package/src/lifecycle/cascade.ts +77 -2
- 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__/emit-event.test.ts +71 -0
- package/src/map/__tests__/lifecycle-bridge.test.ts +86 -10
- package/src/map/acp-bridge.ts +26 -3
- package/src/map/cascade-action-handler.ts +205 -0
- package/src/map/cascade-bridge.ts +339 -0
- package/src/map/coordination-handler.ts +13 -1
- package/src/map/lifecycle-bridge.ts +52 -17
- package/src/map/server.ts +225 -7
- package/src/map/sidecar.ts +48 -1
- package/src/map/types.ts +23 -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__/land-dispatch.test.ts +214 -0
- 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 +1213 -0
- package/src/workspace/index.ts +11 -11
- package/src/workspace/landing/__tests__/strategies.test.ts +184 -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 +229 -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 +152 -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 +162 -0
- package/src/workspace/types.ts +211 -20
- package/src/workspace/workspace-manager.ts +533 -19
- package/src/workspace/yaml-schema.ts +216 -0
- package/dist/workspace/dataplane-adapter.d.ts +0 -260
- package/dist/workspace/dataplane-adapter.d.ts.map +0 -1
- package/dist/workspace/dataplane-adapter.js +0 -416
- package/dist/workspace/dataplane-adapter.js.map +0 -1
- package/src/workspace/dataplane-adapter.ts +0 -546
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
# Workspace Interfaces (Draft)
|
|
2
|
+
|
|
3
|
+
Concrete TypeScript sketches for the redesigned workspace layer described in `docs/git-cascade-integration-gaps.md`. This file is the interface contract; the narrative doc is the rationale.
|
|
4
|
+
|
|
5
|
+
**Status**: draft for iteration. Not yet implemented. Not yet ported to call sites.
|
|
6
|
+
|
|
7
|
+
Three things are defined here:
|
|
8
|
+
|
|
9
|
+
1. **`WorkspaceManager`** — stream-first API that sits above git-cascade. Used by programmatic consumers (cognitive-core), TopologyPolicy compilers, and MCP tool handlers.
|
|
10
|
+
2. **`TopologyPolicy`** — compiles team YAML (`macro_agent.workspace`) into spawn-time workspace decisions and lifecycle hooks. The compiler is the only thing that reads YAML; everything downstream sees resolved policy objects.
|
|
11
|
+
3. **`LandingStrategy`** — pluggable landing algorithm. Strategies register globally; YAML role config picks which strategy each stream uses.
|
|
12
|
+
|
|
13
|
+
Plus supporting surfaces:
|
|
14
|
+
|
|
15
|
+
- **YAML Zod schema** for `macro_agent.workspace` validation.
|
|
16
|
+
- **MCP tool schemas** for agent-facing workspace tools.
|
|
17
|
+
- **Built-in registrations** (5 landing strategies, 5 topology policies).
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Core primitives
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// Identity types
|
|
25
|
+
export type AgentId = string;
|
|
26
|
+
export type StreamId = string;
|
|
27
|
+
export type ChangeId = string;
|
|
28
|
+
export type QueueEntryId = string;
|
|
29
|
+
|
|
30
|
+
// Pseudo-principals for entities that aren't real agents (team roots, system owners).
|
|
31
|
+
// Tagged via prefix; never terminates.
|
|
32
|
+
export type PseudoAgentId =
|
|
33
|
+
| `team:${string}`
|
|
34
|
+
| `system:${string}`;
|
|
35
|
+
|
|
36
|
+
export type Principal = AgentId | PseudoAgentId;
|
|
37
|
+
|
|
38
|
+
export const isPseudo = (p: Principal): p is PseudoAgentId =>
|
|
39
|
+
p.startsWith("team:") || p.startsWith("system:");
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 2. Stream & worktree types
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
export type StreamStatus = "active" | "merged" | "abandoned" | "conflicted" | "paused";
|
|
48
|
+
|
|
49
|
+
export interface Stream {
|
|
50
|
+
id: StreamId;
|
|
51
|
+
name: string;
|
|
52
|
+
ownerId: Principal;
|
|
53
|
+
parentStreamId?: StreamId;
|
|
54
|
+
baseCommit: string;
|
|
55
|
+
branch: string;
|
|
56
|
+
status: StreamStatus;
|
|
57
|
+
metadata: Record<string, unknown>;
|
|
58
|
+
createdAt: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface StreamNode {
|
|
62
|
+
stream: Stream;
|
|
63
|
+
children: StreamNode[];
|
|
64
|
+
activeTaskCount: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface Change {
|
|
68
|
+
id: ChangeId;
|
|
69
|
+
streamId: StreamId;
|
|
70
|
+
currentCommit: string;
|
|
71
|
+
historicalCommits: string[];
|
|
72
|
+
status: "active" | "merged" | "dropped";
|
|
73
|
+
createdAt: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface StreamSpec {
|
|
77
|
+
name: string;
|
|
78
|
+
ownerId: Principal;
|
|
79
|
+
parent?: StreamId; // fork from this stream (takes precedence)
|
|
80
|
+
forkFrom?: string; // otherwise fork from this branch
|
|
81
|
+
metadata?: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface Worktree {
|
|
85
|
+
agentId: Principal;
|
|
86
|
+
path: string;
|
|
87
|
+
streamId?: StreamId; // worktrees may be detached
|
|
88
|
+
branch: string;
|
|
89
|
+
pooled: boolean;
|
|
90
|
+
sharedWithAgents: AgentId[]; // ref-counted shares
|
|
91
|
+
createdAt: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface AllocateWorktreeOpts {
|
|
95
|
+
agentId: Principal;
|
|
96
|
+
streamId?: StreamId;
|
|
97
|
+
baseDir?: string;
|
|
98
|
+
pooled?: boolean;
|
|
99
|
+
sharedWithAgent?: AgentId; // if set, co-locates on that agent's worktree; ref-counted
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 3. Results & conflict types
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
export type ConflictStrategy = "abort" | "ours" | "theirs" | "defer" | "agent";
|
|
109
|
+
export type CascadeStrategy = "stop_on_conflict" | "skip_conflicting" | "defer_conflicts";
|
|
110
|
+
|
|
111
|
+
export interface MergeResult {
|
|
112
|
+
success: boolean;
|
|
113
|
+
mergeCommit?: string;
|
|
114
|
+
changeIds?: ChangeId[];
|
|
115
|
+
conflictId?: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface RebaseResult {
|
|
119
|
+
success: boolean;
|
|
120
|
+
rebasedCommits?: string[];
|
|
121
|
+
conflictId?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface CascadeResult {
|
|
125
|
+
rootStreamId: StreamId;
|
|
126
|
+
succeeded: StreamId[];
|
|
127
|
+
failed: Array<{ streamId: StreamId; conflictId?: string; error?: string }>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface ConflictRecord {
|
|
131
|
+
id: string;
|
|
132
|
+
streamId: StreamId;
|
|
133
|
+
sourceCommit?: string;
|
|
134
|
+
targetCommit?: string;
|
|
135
|
+
paths: string[];
|
|
136
|
+
createdAt: number;
|
|
137
|
+
resolvedAt?: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface ReconcileResult {
|
|
141
|
+
streamsChecked: number;
|
|
142
|
+
streamsFixed: number;
|
|
143
|
+
worktreesOrphaned: number;
|
|
144
|
+
worktreesCleaned: number;
|
|
145
|
+
poolEntriesPurged: number;
|
|
146
|
+
errors: Array<{ context: string; message: string }>;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 4. Events
|
|
153
|
+
|
|
154
|
+
All three control layers (YAML-compiled, MCP tools, programmatic) emit the same stream.
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
export type WorkspaceEvent =
|
|
158
|
+
| { kind: "stream.created"; streamId: StreamId; ownerId: Principal; parentStreamId?: StreamId }
|
|
159
|
+
| { kind: "stream.committed"; streamId: StreamId; commit: string; changeId: ChangeId; agentId: Principal }
|
|
160
|
+
| { kind: "stream.merged"; sourceStreamId: StreamId; targetStreamId: StreamId; mergeCommit: string }
|
|
161
|
+
| { kind: "stream.conflicted"; streamId: StreamId; conflictId: string }
|
|
162
|
+
| { kind: "stream.abandoned"; streamId: StreamId; reason?: string }
|
|
163
|
+
| { kind: "stream.paused"; streamId: StreamId; reason?: string }
|
|
164
|
+
| { kind: "stream.resumed"; streamId: StreamId }
|
|
165
|
+
| { kind: "worktree.allocated"; agentId: Principal; path: string; streamId?: StreamId }
|
|
166
|
+
| { kind: "worktree.deallocated"; agentId: Principal; path: string }
|
|
167
|
+
| { kind: "worktree.shared"; ownerAgentId: AgentId; sharingAgentId: AgentId; path: string }
|
|
168
|
+
| { kind: "landing.started"; agentId: AgentId; streamId: StreamId; strategyName: string }
|
|
169
|
+
| { kind: "landing.completed"; agentId: AgentId; streamId: StreamId; result: MergeResult | RebaseResult }
|
|
170
|
+
| { kind: "cascade.started"; rootStreamId: StreamId }
|
|
171
|
+
| { kind: "cascade.completed"; result: CascadeResult };
|
|
172
|
+
|
|
173
|
+
export type WorkspaceEventCallback = (e: WorkspaceEvent) => void;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## 5. `WorkspaceManager` interface
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
export interface WorkspaceManager {
|
|
182
|
+
// ── Stream management ──────────────────────────────────────────
|
|
183
|
+
createStream(spec: StreamSpec): StreamId;
|
|
184
|
+
|
|
185
|
+
forkStream(opts: {
|
|
186
|
+
parentStreamId: StreamId;
|
|
187
|
+
name: string;
|
|
188
|
+
ownerId: Principal;
|
|
189
|
+
metadata?: Record<string, unknown>;
|
|
190
|
+
}): StreamId;
|
|
191
|
+
|
|
192
|
+
mergeStream(opts: {
|
|
193
|
+
sourceStreamId: StreamId;
|
|
194
|
+
targetStreamId: StreamId;
|
|
195
|
+
agentId: Principal;
|
|
196
|
+
worktree: string;
|
|
197
|
+
}): MergeResult;
|
|
198
|
+
|
|
199
|
+
syncWithParent(opts: {
|
|
200
|
+
streamId: StreamId;
|
|
201
|
+
agentId: Principal;
|
|
202
|
+
worktree: string;
|
|
203
|
+
onConflict?: ConflictStrategy;
|
|
204
|
+
}): RebaseResult;
|
|
205
|
+
|
|
206
|
+
rebaseOntoStream(opts: {
|
|
207
|
+
streamId: StreamId;
|
|
208
|
+
targetStreamId: StreamId;
|
|
209
|
+
agentId: Principal;
|
|
210
|
+
worktree: string;
|
|
211
|
+
onConflict?: ConflictStrategy;
|
|
212
|
+
}): RebaseResult;
|
|
213
|
+
|
|
214
|
+
cascadeRebase(opts: {
|
|
215
|
+
rootStreamId: StreamId;
|
|
216
|
+
strategy: CascadeStrategy;
|
|
217
|
+
worktreeProvider: (streamId: StreamId) => string | null;
|
|
218
|
+
}): CascadeResult;
|
|
219
|
+
|
|
220
|
+
abandonStream(streamId: StreamId, opts?: { cascade?: boolean; reason?: string }): void;
|
|
221
|
+
pauseStream(streamId: StreamId, reason?: string): void;
|
|
222
|
+
resumeStream(streamId: StreamId): void;
|
|
223
|
+
|
|
224
|
+
getStream(streamId: StreamId): Stream | null;
|
|
225
|
+
listStreams(filter?: { ownerId?: Principal; status?: StreamStatus; parentStreamId?: StreamId }): Stream[];
|
|
226
|
+
getStreamHierarchy(rootStreamId?: StreamId): StreamNode | StreamNode[];
|
|
227
|
+
getDependents(streamId: StreamId): StreamId[];
|
|
228
|
+
|
|
229
|
+
// ── Changes (Change-Id tracking) ───────────────────────────────
|
|
230
|
+
commitChanges(opts: {
|
|
231
|
+
agentId: Principal;
|
|
232
|
+
streamId: StreamId;
|
|
233
|
+
worktree: string;
|
|
234
|
+
message: string;
|
|
235
|
+
}): { commit: string; changeId: ChangeId };
|
|
236
|
+
|
|
237
|
+
markChangesMerged(changeIds: ChangeId[]): void;
|
|
238
|
+
getChange(changeId: ChangeId): Change | null;
|
|
239
|
+
getChangeByCommit(commit: string): Change | null;
|
|
240
|
+
|
|
241
|
+
// ── Worktree management ────────────────────────────────────────
|
|
242
|
+
allocateWorktree(opts: AllocateWorktreeOpts): Worktree;
|
|
243
|
+
deallocateWorktree(agentId: Principal): void;
|
|
244
|
+
getWorktreeForAgent(agentId: Principal): Worktree | null;
|
|
245
|
+
listWorktrees(): Worktree[];
|
|
246
|
+
|
|
247
|
+
// ── Conflicts ──────────────────────────────────────────────────
|
|
248
|
+
getConflictForStream(streamId: StreamId): ConflictRecord | null;
|
|
249
|
+
resolveConflict(opts: { conflictId: string; resolvedBy: Principal; resolutionCommit?: string }): void;
|
|
250
|
+
|
|
251
|
+
// ── Landing ────────────────────────────────────────────────────
|
|
252
|
+
registerLandingStrategy(strategy: LandingStrategy): void;
|
|
253
|
+
unregisterLandingStrategy(name: string): void;
|
|
254
|
+
getLandingStrategy(name: string): LandingStrategy | null;
|
|
255
|
+
|
|
256
|
+
land(opts: {
|
|
257
|
+
agentId: AgentId;
|
|
258
|
+
streamId: StreamId;
|
|
259
|
+
strategyName?: string;
|
|
260
|
+
targetStreamId?: StreamId;
|
|
261
|
+
strategyConfig?: Record<string, unknown>;
|
|
262
|
+
}): Promise<MergeResult>;
|
|
263
|
+
|
|
264
|
+
// ── Merge queue (delegates to git-cascade's built-in) ──────────
|
|
265
|
+
addToMergeQueue(opts: {
|
|
266
|
+
streamId: StreamId;
|
|
267
|
+
targetBranch: string;
|
|
268
|
+
priority?: number;
|
|
269
|
+
}): QueueEntryId;
|
|
270
|
+
|
|
271
|
+
getNextToMerge(targetBranch?: string): MergeQueueEntry | null;
|
|
272
|
+
markMergeQueueReady(entryId: QueueEntryId): void;
|
|
273
|
+
cancelMergeQueueEntry(entryId: QueueEntryId): void;
|
|
274
|
+
getMergeQueuePosition(streamId: StreamId, targetBranch?: string): number | null;
|
|
275
|
+
|
|
276
|
+
// ── Reconciliation & health ────────────────────────────────────
|
|
277
|
+
reconcile(): ReconcileResult;
|
|
278
|
+
healthCheck(): HealthCheckResult;
|
|
279
|
+
|
|
280
|
+
// ── Events ─────────────────────────────────────────────────────
|
|
281
|
+
onEvent(cb: WorkspaceEventCallback): () => void;
|
|
282
|
+
|
|
283
|
+
// ── Lifecycle ──────────────────────────────────────────────────
|
|
284
|
+
close(): void;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface MergeQueueEntry {
|
|
288
|
+
id: QueueEntryId;
|
|
289
|
+
streamId: StreamId;
|
|
290
|
+
targetBranch: string;
|
|
291
|
+
status: "pending" | "ready" | "in_progress" | "merged" | "cancelled" | "failed";
|
|
292
|
+
priority: number;
|
|
293
|
+
submittedAt: number;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export interface HealthCheckResult {
|
|
297
|
+
streamsActive: number;
|
|
298
|
+
streamsArchived: number;
|
|
299
|
+
agentsActive: number;
|
|
300
|
+
staleLocks: number;
|
|
301
|
+
incompleteOperations: number;
|
|
302
|
+
orphanedConflicts: number;
|
|
303
|
+
orphanedWorktrees: number;
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 6. `LandingStrategy` interface
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
export interface LandingContext {
|
|
313
|
+
agentId: AgentId;
|
|
314
|
+
streamId: StreamId;
|
|
315
|
+
sourceWorktree: string;
|
|
316
|
+
targetStreamId?: StreamId;
|
|
317
|
+
strategyConfig?: Record<string, unknown>; // from YAML `landing_config`
|
|
318
|
+
workspaceManager: WorkspaceManager;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export interface LandingStrategy {
|
|
322
|
+
readonly name: string;
|
|
323
|
+
|
|
324
|
+
// Optional: strategy decides if it applies given the context
|
|
325
|
+
canLand?(ctx: LandingContext): boolean;
|
|
326
|
+
|
|
327
|
+
// Execute the landing
|
|
328
|
+
land(ctx: LandingContext): Promise<MergeResult>;
|
|
329
|
+
|
|
330
|
+
// Optional lifecycle hooks
|
|
331
|
+
initialize?(): Promise<void>;
|
|
332
|
+
close?(): Promise<void>;
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### 6.1 Built-in strategies
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
// merge-to-parent: merge sourceStream → targetStream (or parent of source).
|
|
340
|
+
// On success: optionally cascadeRebase if strategyConfig.cascade === true.
|
|
341
|
+
// Used by: peer swarm, long-lived feature, solo stack.
|
|
342
|
+
|
|
343
|
+
// queue-to-branch: add to merge queue; return immediately. Actual merge is drained
|
|
344
|
+
// by an integrator-capable agent calling processMergeQueue / merge_stream.
|
|
345
|
+
// strategyConfig: { target: "stream:<id>" | "branch:<name>" | "role:<role>" }.
|
|
346
|
+
// Used by: triad (workers), pipeline (coders).
|
|
347
|
+
|
|
348
|
+
// cherry-pick-stack: createStackFromStream + cherryPickStackToTarget. Preserves
|
|
349
|
+
// commit identity via Change-Ids. strategyConfig: { target_branch: string }.
|
|
350
|
+
// Used by: stacked-diff review workflows.
|
|
351
|
+
|
|
352
|
+
// direct-push: rebase onto target + push. Raw execSync (current trunk strategy).
|
|
353
|
+
// strategyConfig: { target_branch: string; max_retries?: number }.
|
|
354
|
+
// Used by: trunk-based flows without a merge queue.
|
|
355
|
+
|
|
356
|
+
// optimistic-push: direct-push + emit `validation:requested` event.
|
|
357
|
+
// Validation delegated to a judge role.
|
|
358
|
+
// Used by: self-driving team today.
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Strategy registration happens once at boot; all 5 are registered by default. Teams pick via YAML `landing: <strategy_name>`.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## 7. `TopologyPolicy` interface
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
export interface TopologyPolicy {
|
|
369
|
+
readonly name: string;
|
|
370
|
+
|
|
371
|
+
onTeamStart(ctx: TeamStartContext): Promise<TeamStartPlan>;
|
|
372
|
+
onAgentSpawn(ctx: SpawnContext): Promise<WorkspaceDecision>;
|
|
373
|
+
onAgentComplete(ctx: AgentCompleteContext): Promise<void>;
|
|
374
|
+
onTeamStop(ctx: TeamStopContext): Promise<void>;
|
|
375
|
+
|
|
376
|
+
// Optional: subscribed if the topology cares about parent stream updates
|
|
377
|
+
onParentStreamAdvanced?(ctx: ParentAdvancedContext): Promise<void>;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export interface TeamStartContext {
|
|
381
|
+
teamName: string;
|
|
382
|
+
teamId: string; // instance id
|
|
383
|
+
manifest: TeamManifest; // openteams-resolved
|
|
384
|
+
workspaceConfig: TeamWorkspaceConfig; // macro-agent's Zod-validated section
|
|
385
|
+
workspaceManager: WorkspaceManager;
|
|
386
|
+
inboxAdapter: InboxAdapter;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface TeamStartPlan {
|
|
390
|
+
teamStreamId?: StreamId; // the team's root stream if created
|
|
391
|
+
additionalStreams?: StreamId[];
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export interface SpawnContext {
|
|
395
|
+
agentId: AgentId;
|
|
396
|
+
role: string;
|
|
397
|
+
roleConfig: RoleWorkspaceConfig; // parsed YAML for this role
|
|
398
|
+
parent?: AgentId;
|
|
399
|
+
parentStreamId?: StreamId;
|
|
400
|
+
teamStreamId?: StreamId;
|
|
401
|
+
workspaceManager: WorkspaceManager;
|
|
402
|
+
options: SpawnAgentOptions;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export type WorkspaceDecision =
|
|
406
|
+
| { kind: "none" }
|
|
407
|
+
| { kind: "share-parent-cwd" }
|
|
408
|
+
| { kind: "share-with-agent"; agentId: AgentId; worktreeRole?: "read" | "write" }
|
|
409
|
+
| { kind: "attach-to-stream"; streamId: StreamId; worktree: WorktreeOpts }
|
|
410
|
+
| { kind: "new-stream"; streamSpec: StreamSpec; worktree: WorktreeOpts };
|
|
411
|
+
|
|
412
|
+
export interface WorktreeOpts {
|
|
413
|
+
baseDir?: string;
|
|
414
|
+
pooled?: boolean;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export interface AgentCompleteContext {
|
|
418
|
+
agentId: AgentId;
|
|
419
|
+
role: string;
|
|
420
|
+
reason: "completed" | "failed" | "cascade" | "interrupted";
|
|
421
|
+
streamId?: StreamId;
|
|
422
|
+
workspaceManager: WorkspaceManager;
|
|
423
|
+
landingResult?: MergeResult;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export interface TeamStopContext {
|
|
427
|
+
teamName: string;
|
|
428
|
+
teamStreamId?: StreamId;
|
|
429
|
+
onTeamComplete: "keep" | "merge_to_main" | "abandon";
|
|
430
|
+
workspaceManager: WorkspaceManager;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export interface ParentAdvancedContext {
|
|
434
|
+
parentStreamId: StreamId;
|
|
435
|
+
childStreamIds: StreamId[];
|
|
436
|
+
workspaceManager: WorkspaceManager;
|
|
437
|
+
triggerSystem: TriggerSystemV2;
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### 7.1 Built-in topology policies
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
// YamlDrivenTopology: the default. Compiles TeamWorkspaceConfig into
|
|
445
|
+
// per-spawn decisions by looking up role config. Covers peer-swarm,
|
|
446
|
+
// triad, pipeline, research, long-lived, solo-stack via YAML alone.
|
|
447
|
+
|
|
448
|
+
// CognitiveCoreTopology: minimal policy for cognitive-core's analyst
|
|
449
|
+
// workflow; spawns analysts with no stream, allocates detached worktrees.
|
|
450
|
+
// Skips YAML; configured programmatically.
|
|
451
|
+
|
|
452
|
+
// NoWorkspaceTopology: returns { kind: "none" } for everything. Used when
|
|
453
|
+
// no workspace is needed but the team still needs structured spawning.
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`YamlDrivenTopology` is the primary; the others are escape hatches for library consumers.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## 8. YAML Zod schema (`macro_agent.workspace`)
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
import { z } from "zod";
|
|
464
|
+
|
|
465
|
+
export const StreamLineageSchema = z.enum([
|
|
466
|
+
"from_team_root", // attach to existing team root (no new stream)
|
|
467
|
+
"fork_from_team_root", // fork new stream off team root
|
|
468
|
+
"fork_from_parent", // fork new stream off spawner's stream
|
|
469
|
+
"independent", // fork new stream off main branch
|
|
470
|
+
"track_existing_branch",// track an existing branch (no new stream/<id>)
|
|
471
|
+
]);
|
|
472
|
+
|
|
473
|
+
export const LandingStrategyNameSchema = z.enum([
|
|
474
|
+
"merge_to_parent_stream",
|
|
475
|
+
"queue_to_branch",
|
|
476
|
+
"cherry_pick_stack",
|
|
477
|
+
"direct_push",
|
|
478
|
+
"optimistic_push",
|
|
479
|
+
"none",
|
|
480
|
+
]);
|
|
481
|
+
|
|
482
|
+
export const ConflictStrategySchema = z.enum(["abort", "ours", "theirs", "defer", "agent"]);
|
|
483
|
+
|
|
484
|
+
export const WorkspaceKindSchema = z.enum([
|
|
485
|
+
"new_stream",
|
|
486
|
+
"attach_to_team_root",
|
|
487
|
+
"share_with_agent",
|
|
488
|
+
"share_parent_cwd",
|
|
489
|
+
"none",
|
|
490
|
+
]);
|
|
491
|
+
|
|
492
|
+
export const AllocationSchema = z.enum([
|
|
493
|
+
"new_worktree",
|
|
494
|
+
"inherit_parent_cwd",
|
|
495
|
+
"pooled_worktree",
|
|
496
|
+
]);
|
|
497
|
+
|
|
498
|
+
export const OnParentAdvancedSchema = z.enum([
|
|
499
|
+
"sync_with_parent",
|
|
500
|
+
"none",
|
|
501
|
+
]);
|
|
502
|
+
|
|
503
|
+
export const OnTeamCompleteSchema = z.enum([
|
|
504
|
+
"keep",
|
|
505
|
+
"merge_to_main",
|
|
506
|
+
"abandon",
|
|
507
|
+
]);
|
|
508
|
+
|
|
509
|
+
export const RoleWorkspaceConfigSchema = z.object({
|
|
510
|
+
workspace: WorkspaceKindSchema,
|
|
511
|
+
stream_lineage: StreamLineageSchema.optional(),
|
|
512
|
+
allocation: AllocationSchema.optional(),
|
|
513
|
+
landing: LandingStrategyNameSchema.optional(),
|
|
514
|
+
landing_config: z.record(z.unknown()).optional(),
|
|
515
|
+
on_conflict: ConflictStrategySchema.optional(),
|
|
516
|
+
cascade_on_parent_update: z.boolean().optional(),
|
|
517
|
+
on_parent_advanced: OnParentAdvancedSchema.optional(),
|
|
518
|
+
share_with: z.string().optional(), // role name — for workspace: share_with_agent
|
|
519
|
+
track_branch: z.string().optional(), // branch name — for stream_lineage: track_existing_branch
|
|
520
|
+
}).superRefine((val, ctx) => {
|
|
521
|
+
if (val.workspace === "share_with_agent" && !val.share_with) {
|
|
522
|
+
ctx.addIssue({ code: "custom", message: "share_with is required when workspace=share_with_agent" });
|
|
523
|
+
}
|
|
524
|
+
if (val.stream_lineage === "track_existing_branch" && !val.track_branch) {
|
|
525
|
+
ctx.addIssue({ code: "custom", message: "track_branch is required when stream_lineage=track_existing_branch" });
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
export const PoolConfigSchema = z.object({
|
|
530
|
+
enabled: z.boolean().default(true),
|
|
531
|
+
max_size: z.number().default(10),
|
|
532
|
+
reuse_across_streams: z.boolean().default(false),
|
|
533
|
+
}).optional();
|
|
534
|
+
|
|
535
|
+
export const DefaultStreamSchema = z.object({
|
|
536
|
+
fork_from: z.string().default("main"),
|
|
537
|
+
name_template: z.string().default("{team}"),
|
|
538
|
+
change_id_tracking: z.boolean().default(true),
|
|
539
|
+
}).optional();
|
|
540
|
+
|
|
541
|
+
export const TeamWorkspaceConfigSchema = z.object({
|
|
542
|
+
default_stream: DefaultStreamSchema,
|
|
543
|
+
on_team_complete: OnTeamCompleteSchema.default("keep"),
|
|
544
|
+
pool: PoolConfigSchema,
|
|
545
|
+
roles: z.record(z.string(), RoleWorkspaceConfigSchema),
|
|
546
|
+
capabilities: z.record(z.string(), z.array(z.string())).optional(),
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
export type TeamWorkspaceConfig = z.infer<typeof TeamWorkspaceConfigSchema>;
|
|
550
|
+
export type RoleWorkspaceConfig = z.infer<typeof RoleWorkspaceConfigSchema>;
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Loaded from `TeamManifest.macro_agent.workspace`. Validated once at team start; errors rejected loudly.
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## 9. MCP tool schemas
|
|
558
|
+
|
|
559
|
+
Registered per-role based on capabilities in team YAML. Tool filtering already exists in `mcp-server-v2.ts` via `isToolAllowedForRole()`.
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
import { z } from "zod";
|
|
563
|
+
|
|
564
|
+
// ── Capability: workspace.commit ──────────────────────────────────
|
|
565
|
+
export const commitToolInput = z.object({
|
|
566
|
+
message: z.string().min(1),
|
|
567
|
+
});
|
|
568
|
+
// Handler: commitChanges({ agentId, streamId: ctx.streamId, worktree: ctx.cwd, message })
|
|
569
|
+
// → returns { commit, changeId }
|
|
570
|
+
|
|
571
|
+
// ── Capability: workspace.land ────────────────────────────────────
|
|
572
|
+
export const landToolInput = z.object({
|
|
573
|
+
strategy: z.string().optional(), // override role default
|
|
574
|
+
targetStreamId: z.string().optional(),
|
|
575
|
+
strategyConfig: z.record(z.unknown()).optional(),
|
|
576
|
+
});
|
|
577
|
+
// Handler: workspaceManager.land({ agentId, streamId: ctx.streamId, ... })
|
|
578
|
+
|
|
579
|
+
// ── Capability: workspace.fork ────────────────────────────────────
|
|
580
|
+
export const forkStreamToolInput = z.object({
|
|
581
|
+
name: z.string().min(1),
|
|
582
|
+
parent: z.string().optional(), // defaults to current stream
|
|
583
|
+
});
|
|
584
|
+
// Handler: forkStream + allocateWorktree + implicitly moves agent's active stream
|
|
585
|
+
|
|
586
|
+
// ── Capability: workspace.sync ────────────────────────────────────
|
|
587
|
+
export const syncWithParentToolInput = z.object({
|
|
588
|
+
onConflict: ConflictStrategySchema.optional(),
|
|
589
|
+
});
|
|
590
|
+
// Handler: syncWithParent({ streamId: ctx.streamId, ... })
|
|
591
|
+
|
|
592
|
+
// ── Capability: workspace.merge ───────────────────────────────────
|
|
593
|
+
export const mergeStreamToolInput = z.object({
|
|
594
|
+
sourceStreamId: z.string(),
|
|
595
|
+
targetStreamId: z.string().optional(),
|
|
596
|
+
});
|
|
597
|
+
// Handler: mergeStream(...). For integrator roles draining queue.
|
|
598
|
+
|
|
599
|
+
// ── Capability: merge_queue.drain ─────────────────────────────────
|
|
600
|
+
export const nextMergeRequestToolInput = z.object({
|
|
601
|
+
targetBranch: z.string().optional(),
|
|
602
|
+
});
|
|
603
|
+
// Handler: getNextToMerge(targetBranch) + mark in_progress
|
|
604
|
+
|
|
605
|
+
export const markMergeCompleteToolInput = z.object({
|
|
606
|
+
entryId: z.string(),
|
|
607
|
+
mergeCommit: z.string().optional(),
|
|
608
|
+
success: z.boolean(),
|
|
609
|
+
error: z.string().optional(),
|
|
610
|
+
});
|
|
611
|
+
// Handler: updates queue entry state
|
|
612
|
+
|
|
613
|
+
// ── Capability: workspace.cascade ─────────────────────────────────
|
|
614
|
+
export const requestCascadeToolInput = z.object({
|
|
615
|
+
rootStreamId: z.string(),
|
|
616
|
+
strategy: z.enum(["stop_on_conflict", "skip_conflicting", "defer_conflicts"]).optional(),
|
|
617
|
+
});
|
|
618
|
+
// Handler: cascadeRebase({ rootStreamId, strategy, worktreeProvider })
|
|
619
|
+
|
|
620
|
+
// ── Capability: workspace.read (always available if role has any workspace cap) ─
|
|
621
|
+
export const streamStatusToolInput = z.object({
|
|
622
|
+
streamId: z.string().optional(), // defaults to agent's current stream
|
|
623
|
+
includeHierarchy: z.boolean().default(false),
|
|
624
|
+
});
|
|
625
|
+
// Handler: getStream + listStreams(filter) + optionally getStreamHierarchy
|
|
626
|
+
|
|
627
|
+
export const checkoutStreamToolInput = z.object({
|
|
628
|
+
streamId: z.string(),
|
|
629
|
+
});
|
|
630
|
+
// Handler: switches agent's active stream (for returning to parent after fork+land).
|
|
631
|
+
// Capability gate: workspace.fork OR workspace.sync.
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### 9.1 Capability → tool mapping
|
|
635
|
+
|
|
636
|
+
| Capability | Tools registered |
|
|
637
|
+
|---|---|
|
|
638
|
+
| `workspace.commit` | `commit` |
|
|
639
|
+
| `workspace.land` | `land` |
|
|
640
|
+
| `workspace.fork` | `fork_stream`, `checkout_stream` |
|
|
641
|
+
| `workspace.sync` | `sync_with_parent` |
|
|
642
|
+
| `workspace.merge` | `merge_stream` |
|
|
643
|
+
| `workspace.cascade` | `request_cascade` |
|
|
644
|
+
| `workspace.read` | `stream_status` |
|
|
645
|
+
| `merge_queue.drain` | `next_merge_request`, `mark_merge_complete` |
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## 10. Boot integration
|
|
650
|
+
|
|
651
|
+
```ts
|
|
652
|
+
// boot-v2.ts — new path
|
|
653
|
+
export async function bootV2(config: BootV2Config): Promise<MacroAgentSystemV2> {
|
|
654
|
+
// ... existing setup (agentStore, inbox, tasks, etc.) ...
|
|
655
|
+
|
|
656
|
+
// Load team config if provided
|
|
657
|
+
let teamManifest: TeamManifest | null = null;
|
|
658
|
+
let workspaceConfig: TeamWorkspaceConfig | null = null;
|
|
659
|
+
if (config.team) {
|
|
660
|
+
teamManifest = await loadTeamManifest(config.team);
|
|
661
|
+
const rawWorkspace = teamManifest.macro_agent?.workspace;
|
|
662
|
+
if (rawWorkspace) {
|
|
663
|
+
workspaceConfig = TeamWorkspaceConfigSchema.parse(rawWorkspace);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Construct WorkspaceManager if any role needs one
|
|
668
|
+
let workspaceManager: WorkspaceManager | undefined;
|
|
669
|
+
if (workspaceConfig || config.workspaceManager) {
|
|
670
|
+
workspaceManager = config.workspaceManager ?? createDefaultWorkspaceManager({
|
|
671
|
+
repoPath: config.cwd,
|
|
672
|
+
pool: workspaceConfig?.pool,
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
// Register built-in landing strategies
|
|
676
|
+
registerBuiltinLandingStrategies(workspaceManager);
|
|
677
|
+
|
|
678
|
+
// Reconcile on boot
|
|
679
|
+
const reconcileResult = workspaceManager.reconcile();
|
|
680
|
+
logReconcile(reconcileResult);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Construct agent manager
|
|
684
|
+
const agentManager = createAgentManagerV2({
|
|
685
|
+
// ... existing args ...
|
|
686
|
+
workspaceManager,
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
// Construct topology policy
|
|
690
|
+
let topologyPolicy: TopologyPolicy | undefined;
|
|
691
|
+
if (workspaceConfig && workspaceManager) {
|
|
692
|
+
topologyPolicy = new YamlDrivenTopology(workspaceConfig);
|
|
693
|
+
agentManager.setTopologyPolicy(topologyPolicy);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Start team if requested
|
|
697
|
+
if (config.team && teamManifest) {
|
|
698
|
+
const teamManager = new TeamManagerV2({
|
|
699
|
+
agentManager,
|
|
700
|
+
inboxAdapter,
|
|
701
|
+
tasksAdapter,
|
|
702
|
+
workspaceManager,
|
|
703
|
+
topologyPolicy,
|
|
704
|
+
});
|
|
705
|
+
await teamManager.startTeam(teamManifest);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// ... rest of boot ...
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
Callers like `cognitive-core` continue to pass their own `workspaceManager` and skip team YAML entirely — they drive the API directly.
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
## 11. Open gaps in this draft
|
|
717
|
+
|
|
718
|
+
- **`checkout_stream` semantics** — moves agent's *context* (streamId in spawn env), but does it relocate cwd or re-allocate worktree? Needs concrete decision when we implement solo-stack.
|
|
719
|
+
- **`attach-to-stream` worktree** — when workspace kind is `attach_to_team_root`, does the agent get a fresh worktree on team_root's branch, or share with whoever already has one? Default: fresh worktree on the team_root branch.
|
|
720
|
+
- **Conflict recovery hook** — no interface method on `WorkspaceManager` yet for "escalate conflict to recovery strategy." Probably a pluggable `ConflictRecoveryStrategy` parallel to `LandingStrategy`. Deferred.
|
|
721
|
+
- **cascadeRebase triggering from events** — `YamlDrivenTopology` subscribes to `stream.committed` on parent streams when any child has `on_parent_advanced: sync_with_parent`. Needs WakeManager integration for coalescing. Deferred to migration step.
|
|
722
|
+
- **Backward compat shim for cognitive-core** — the existing `DefaultWorkspaceManager` needs to implement both old and new interfaces during migration. TBD once we start migration.
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## 12. What's not defined here
|
|
727
|
+
|
|
728
|
+
- **Implementation** of `DefaultWorkspaceManager` — this doc is the interface only.
|
|
729
|
+
- **Migration order** — see `git-cascade-integration-gaps.md` §8.
|
|
730
|
+
- **Conflict recovery strategy interface** — parallel design, out of scope.
|
|
731
|
+
- **cc-swarm integration** — separate follow-up doc.
|