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
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpawnResolverStrategy real-spawn e2e.
|
|
3
|
+
*
|
|
4
|
+
* Exercises the full conflict recovery flow:
|
|
5
|
+
* 1. Set up a real conflict (two streams with conflicting changes)
|
|
6
|
+
* 2. SpawnResolverStrategy.recover() actually spawns a resolver agent
|
|
7
|
+
* via AgentManager (mocked Claude Code)
|
|
8
|
+
* 3. The resolver calls workspaceManager.resolveConflict() which emits
|
|
9
|
+
* conflict:resolved
|
|
10
|
+
* 4. The awaiting recover() Promise resolves
|
|
11
|
+
*
|
|
12
|
+
* Uses mocked acp-factory — focus is on the orchestration, not on an LLM
|
|
13
|
+
* actually resolving conflicts.
|
|
14
|
+
*
|
|
15
|
+
* REQUIRES: RUN_E2E_TESTS=true
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
19
|
+
import * as fs from 'fs';
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
import * as os from 'os';
|
|
22
|
+
import { execSync } from 'child_process';
|
|
23
|
+
import { bootV2, type MacroAgentSystemV2 } from '../../boot-v2.js';
|
|
24
|
+
import { GitCascadeAdapter } from '../../workspace/git-cascade-adapter.js';
|
|
25
|
+
import {
|
|
26
|
+
DefaultWorkspaceManager,
|
|
27
|
+
createWorkspaceManagerWithAdapter,
|
|
28
|
+
} from '../../workspace/workspace-manager.js';
|
|
29
|
+
import { createSpawnResolverStrategy } from '../../workspace/recovery/spawn-resolver.js';
|
|
30
|
+
import type { ConflictContext } from '../../workspace/recovery/types.js';
|
|
31
|
+
|
|
32
|
+
const RUN_E2E = !!process.env.RUN_E2E_TESTS;
|
|
33
|
+
const describeFn = RUN_E2E ? describe : describe.skip;
|
|
34
|
+
|
|
35
|
+
vi.mock('acp-factory', () => ({
|
|
36
|
+
AgentFactory: {
|
|
37
|
+
spawn: vi.fn().mockResolvedValue({
|
|
38
|
+
createSession: vi.fn().mockResolvedValue({
|
|
39
|
+
id: `session-${Date.now()}`,
|
|
40
|
+
prompt: vi.fn().mockReturnValue({
|
|
41
|
+
[Symbol.asyncIterator]: () => ({
|
|
42
|
+
next: () => Promise.resolve({ done: true, value: undefined }),
|
|
43
|
+
}),
|
|
44
|
+
}),
|
|
45
|
+
forkWithFlush: vi.fn().mockResolvedValue({ id: `forked-${Date.now()}` }),
|
|
46
|
+
}),
|
|
47
|
+
loadSession: vi.fn().mockResolvedValue({ id: `loaded-${Date.now()}` }),
|
|
48
|
+
close: vi.fn().mockResolvedValue(undefined),
|
|
49
|
+
isRunning: vi.fn().mockReturnValue(true),
|
|
50
|
+
}),
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
vi.mock('opentasks', () => ({
|
|
55
|
+
OpenTasksClient: vi.fn().mockImplementation(() => ({
|
|
56
|
+
connect: vi.fn().mockRejectedValue(new Error('No daemon')),
|
|
57
|
+
disconnect: vi.fn(),
|
|
58
|
+
query: vi.fn().mockResolvedValue({ items: [] }),
|
|
59
|
+
link: vi.fn().mockResolvedValue({ success: true }),
|
|
60
|
+
task: vi.fn().mockResolvedValue({ id: 't-1' }),
|
|
61
|
+
})),
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
describeFn('SpawnResolver real-spawn e2e', () => {
|
|
65
|
+
let system: MacroAgentSystemV2;
|
|
66
|
+
let testDir: string;
|
|
67
|
+
let repoPath: string;
|
|
68
|
+
let adapter: GitCascadeAdapter;
|
|
69
|
+
let workspaceManager: DefaultWorkspaceManager;
|
|
70
|
+
|
|
71
|
+
beforeEach(async () => {
|
|
72
|
+
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'spawn-resolver-e2e-'));
|
|
73
|
+
repoPath = path.join(testDir, 'repo');
|
|
74
|
+
fs.mkdirSync(repoPath);
|
|
75
|
+
|
|
76
|
+
execSync('git init -b main', { cwd: repoPath, stdio: 'pipe' });
|
|
77
|
+
execSync('git config user.email "t@t.com"', { cwd: repoPath, stdio: 'pipe' });
|
|
78
|
+
execSync('git config user.name "T"', { cwd: repoPath, stdio: 'pipe' });
|
|
79
|
+
fs.writeFileSync(path.join(repoPath, 'README.md'), '# test');
|
|
80
|
+
execSync('git add .', { cwd: repoPath, stdio: 'pipe' });
|
|
81
|
+
execSync('git commit -m "init"', { cwd: repoPath, stdio: 'pipe' });
|
|
82
|
+
|
|
83
|
+
adapter = new GitCascadeAdapter({
|
|
84
|
+
enabled: true,
|
|
85
|
+
repoPath,
|
|
86
|
+
dbPath: path.join(testDir, 'gc.db'),
|
|
87
|
+
skipRecovery: true,
|
|
88
|
+
});
|
|
89
|
+
workspaceManager = createWorkspaceManagerWithAdapter(adapter, {
|
|
90
|
+
worktreeBaseDir: path.join(repoPath, '.worktrees'),
|
|
91
|
+
}) as DefaultWorkspaceManager;
|
|
92
|
+
|
|
93
|
+
system = await bootV2({
|
|
94
|
+
cwd: repoPath,
|
|
95
|
+
baseDir: testDir,
|
|
96
|
+
inbox: { socketPath: path.join(testDir, 'inbox.sock') },
|
|
97
|
+
workspaceManager,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
afterEach(async () => {
|
|
102
|
+
if (system) await system.shutdown();
|
|
103
|
+
if (workspaceManager) workspaceManager.close();
|
|
104
|
+
if (adapter) adapter.close();
|
|
105
|
+
if (fs.existsSync(testDir)) fs.rmSync(testDir, { recursive: true, force: true });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('spawns a real resolver agent and resolves via workspaceManager.resolveConflict', async () => {
|
|
109
|
+
// Set up: conflicted stream
|
|
110
|
+
const streamId = workspaceManager.createStreamV3({
|
|
111
|
+
name: 'conflicted-feature',
|
|
112
|
+
ownerId: 'team:test',
|
|
113
|
+
forkFrom: 'main',
|
|
114
|
+
});
|
|
115
|
+
const conflictId = adapter.createConflict({
|
|
116
|
+
streamId,
|
|
117
|
+
conflictingCommit: '0'.repeat(40),
|
|
118
|
+
targetCommit: '0'.repeat(40),
|
|
119
|
+
conflictedFiles: ['auth.ts'],
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Construct the strategy with AgentManager injection
|
|
123
|
+
const strategy = createSpawnResolverStrategy({
|
|
124
|
+
agentManager: system.agentManager,
|
|
125
|
+
defaultRole: 'worker', // using built-in worker role (has spawn capability)
|
|
126
|
+
defaultTimeoutMs: 10_000,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const ctx: ConflictContext = {
|
|
130
|
+
conflictId,
|
|
131
|
+
streamId,
|
|
132
|
+
paths: ['auth.ts'],
|
|
133
|
+
operation: 'merge',
|
|
134
|
+
recoveryDepth: 0,
|
|
135
|
+
workspaceManager,
|
|
136
|
+
strategyConfig: { role: 'worker', timeout_ms: 10_000 },
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Kick off recovery. Strategy spawns a resolver agent, then awaits
|
|
140
|
+
// conflict:resolved. We simulate the resolver's tool call by invoking
|
|
141
|
+
// workspaceManager.resolveConflict directly after a small delay.
|
|
142
|
+
const recoveryPromise = strategy.recover(ctx);
|
|
143
|
+
|
|
144
|
+
// Give the strategy time to spawn + subscribe
|
|
145
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
146
|
+
|
|
147
|
+
// Simulate resolver finishing its work
|
|
148
|
+
workspaceManager.resolveConflict({
|
|
149
|
+
conflictId,
|
|
150
|
+
resolvedBy: 'agent_resolver_stub',
|
|
151
|
+
resolutionCommit: 'abc123def456',
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const resolution = await recoveryPromise;
|
|
155
|
+
expect(resolution.kind).toBe('resolved');
|
|
156
|
+
if (resolution.kind === 'resolved') {
|
|
157
|
+
expect(resolution.resolutionCommit).toBe('abc123def456');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// A resolver agent should have actually been spawned by AgentManager
|
|
161
|
+
const agents = system.agentStore.listAgents({});
|
|
162
|
+
const resolverAgents = agents.filter((a) => a.role === 'worker');
|
|
163
|
+
expect(resolverAgents.length).toBeGreaterThan(0);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('escalates to human on timeout (no resolve_conflict call)', async () => {
|
|
167
|
+
const streamId = workspaceManager.createStreamV3({
|
|
168
|
+
name: 'timeout-feature',
|
|
169
|
+
ownerId: 'team:test',
|
|
170
|
+
forkFrom: 'main',
|
|
171
|
+
});
|
|
172
|
+
const conflictId = adapter.createConflict({
|
|
173
|
+
streamId,
|
|
174
|
+
conflictingCommit: '0'.repeat(40),
|
|
175
|
+
targetCommit: '0'.repeat(40),
|
|
176
|
+
conflictedFiles: ['x.ts'],
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const strategy = createSpawnResolverStrategy({
|
|
180
|
+
agentManager: system.agentManager,
|
|
181
|
+
defaultRole: 'worker',
|
|
182
|
+
defaultTimeoutMs: 200, // short timeout to force escalation
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const resolution = await strategy.recover({
|
|
186
|
+
conflictId,
|
|
187
|
+
streamId,
|
|
188
|
+
paths: ['x.ts'],
|
|
189
|
+
operation: 'merge',
|
|
190
|
+
recoveryDepth: 0,
|
|
191
|
+
workspaceManager,
|
|
192
|
+
strategyConfig: { role: 'worker' },
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
expect(resolution.kind).toBe('escalated');
|
|
196
|
+
if (resolution.kind === 'escalated') {
|
|
197
|
+
expect(resolution.escalatedTo).toBe('human');
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workspace Lifecycle E2E Tests
|
|
2
|
+
* Workspace Lifecycle E2E Tests — LEGACY capability-dispatch path.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* These tests exercise the programmatic/capability-based spawn flow:
|
|
5
|
+
* callers pass `capabilities: ["workspace.worktree"|"workspace.stream"|
|
|
6
|
+
* "workspace.integrate"]` + `streamId`/`streamConfig` to `agentManager.spawn`,
|
|
7
|
+
* and AgentManagerV2's `legacyCapabilityDispatch` allocates workspaces via
|
|
8
|
+
* `WorkspaceManager.createWorkerWorkspace` / `createIntegratorWorkspace` /
|
|
9
|
+
* `createCoordinatorWorkspace`.
|
|
10
|
+
*
|
|
11
|
+
* This path remains supported for programmatic callers that don't use team
|
|
12
|
+
* YAML (e.g., tools, libraries). The V3 YAML-driven path is covered by
|
|
13
|
+
* `workspace-v3.e2e.test.ts`.
|
|
14
|
+
*
|
|
15
|
+
* Scenarios verified:
|
|
5
16
|
* - Boot with WorkspaceManager wired correctly
|
|
6
|
-
* - Worker spawn creates worktree
|
|
7
|
-
* - Worker terminate submits merge request
|
|
8
|
-
* - Cascade terminate cleans up worktrees
|
|
9
|
-
* - Coordinator creates integration stream
|
|
17
|
+
* - Worker spawn creates worktree (capability-based)
|
|
18
|
+
* - Worker terminate submits merge request to (legacy) MergeQueue
|
|
19
|
+
* - Cascade terminate cleans up child worktrees
|
|
20
|
+
* - Coordinator creates integration stream via `workspace.stream` capability
|
|
10
21
|
*
|
|
11
22
|
* REQUIRES: RUN_E2E_TESTS=true (no real Claude Code agents)
|
|
12
|
-
*
|
|
13
|
-
* Run with:
|
|
14
|
-
* RUN_E2E_TESTS=true npx vitest run --config vitest.e2e.config.ts src/__tests__/e2e/workspace-lifecycle.e2e.test.ts
|
|
15
23
|
*/
|
|
16
24
|
|
|
17
25
|
import {
|
|
@@ -27,7 +35,7 @@ import * as os from "os";
|
|
|
27
35
|
import * as fs from "fs";
|
|
28
36
|
import { execSync } from "child_process";
|
|
29
37
|
import { bootV2, type MacroAgentSystemV2 } from "../../boot-v2.js";
|
|
30
|
-
import {
|
|
38
|
+
import { GitCascadeAdapter } from "../../workspace/git-cascade-adapter.js";
|
|
31
39
|
import {
|
|
32
40
|
DefaultWorkspaceManager,
|
|
33
41
|
createWorkspaceManagerWithAdapter,
|
|
@@ -121,17 +129,17 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
121
129
|
let system: MacroAgentSystemV2;
|
|
122
130
|
let testDir: string;
|
|
123
131
|
let repoPath: string;
|
|
124
|
-
let adapter:
|
|
132
|
+
let adapter: GitCascadeAdapter;
|
|
125
133
|
let workspaceManager: DefaultWorkspaceManager;
|
|
126
134
|
|
|
127
135
|
beforeEach(async () => {
|
|
128
136
|
testDir = createTestDir();
|
|
129
137
|
repoPath = createGitRepo(testDir);
|
|
130
138
|
|
|
131
|
-
const dbPath = path.join(testDir, "
|
|
139
|
+
const dbPath = path.join(testDir, "git-cascade.db");
|
|
132
140
|
|
|
133
|
-
// Create
|
|
134
|
-
adapter = new
|
|
141
|
+
// Create GitCascadeAdapter and WorkspaceManager
|
|
142
|
+
adapter = new GitCascadeAdapter({
|
|
135
143
|
enabled: true,
|
|
136
144
|
repoPath,
|
|
137
145
|
dbPath,
|
|
@@ -191,17 +199,17 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
191
199
|
});
|
|
192
200
|
expect(streamId).toBeDefined();
|
|
193
201
|
|
|
194
|
-
// Pre-create a
|
|
202
|
+
// Pre-create a git-cascade task so the claimTask call can find it
|
|
195
203
|
const dpTaskId = workspaceManager.createTask(streamId, {
|
|
196
204
|
title: "Implement feature",
|
|
197
205
|
});
|
|
198
206
|
|
|
199
|
-
// Spawn a worker with the streamId and
|
|
207
|
+
// Spawn a worker with the streamId and gitCascadeTaskId
|
|
200
208
|
const worker = await system.agentManager.spawn({
|
|
201
209
|
task: "Implement feature",
|
|
202
210
|
role: "worker",
|
|
203
211
|
streamId,
|
|
204
|
-
|
|
212
|
+
gitCascadeTaskId: dpTaskId,
|
|
205
213
|
capabilities: ["workspace.worktree"],
|
|
206
214
|
});
|
|
207
215
|
|
|
@@ -234,7 +242,7 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
234
242
|
name: "merge-feature",
|
|
235
243
|
});
|
|
236
244
|
|
|
237
|
-
// Pre-create
|
|
245
|
+
// Pre-create git-cascade task
|
|
238
246
|
const dpTaskId = workspaceManager.createTask(streamId, {
|
|
239
247
|
title: "Do work for merge",
|
|
240
248
|
});
|
|
@@ -244,7 +252,7 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
244
252
|
task: "Do work for merge",
|
|
245
253
|
role: "worker",
|
|
246
254
|
streamId,
|
|
247
|
-
|
|
255
|
+
gitCascadeTaskId: dpTaskId,
|
|
248
256
|
capabilities: ["workspace.worktree"],
|
|
249
257
|
});
|
|
250
258
|
|
|
@@ -294,7 +302,7 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
294
302
|
{ name: "cascade-feature" }
|
|
295
303
|
);
|
|
296
304
|
|
|
297
|
-
// Pre-create
|
|
305
|
+
// Pre-create git-cascade tasks
|
|
298
306
|
const dpTaskId1 = workspaceManager.createTask(streamId, {
|
|
299
307
|
title: "Child 1",
|
|
300
308
|
});
|
|
@@ -308,7 +316,7 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
308
316
|
role: "worker",
|
|
309
317
|
parent: coordinator.id,
|
|
310
318
|
streamId,
|
|
311
|
-
|
|
319
|
+
gitCascadeTaskId: dpTaskId1,
|
|
312
320
|
capabilities: ["workspace.worktree"],
|
|
313
321
|
});
|
|
314
322
|
const child2 = await system.agentManager.spawn({
|
|
@@ -316,7 +324,7 @@ describeFn("Workspace Lifecycle E2E", () => {
|
|
|
316
324
|
role: "worker",
|
|
317
325
|
parent: coordinator.id,
|
|
318
326
|
streamId,
|
|
319
|
-
|
|
327
|
+
gitCascadeTaskId: dpTaskId2,
|
|
320
328
|
capabilities: ["workspace.worktree"],
|
|
321
329
|
});
|
|
322
330
|
|