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,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone-mode regression test (G11).
|
|
3
|
+
*
|
|
4
|
+
* Asserts that GitCascadeAdapter (and the cascade event flow it drives)
|
|
5
|
+
* works correctly when no MAP sidecar / cascade bridge is configured —
|
|
6
|
+
* i.e., macro-agent runs without an OpenHive hub.
|
|
7
|
+
*
|
|
8
|
+
* The contract: cascade emits its own structured event stream regardless,
|
|
9
|
+
* and operations succeed without any hub roundtrip. If a future change
|
|
10
|
+
* accidentally introduces a hard dependency on the bridge or sidecar
|
|
11
|
+
* (e.g., awaiting a hub call inside cascade), this test catches it.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
15
|
+
import * as fs from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
import * as os from "os";
|
|
18
|
+
import { execSync } from "child_process";
|
|
19
|
+
import { GitCascadeAdapter } from "../git-cascade-adapter.js";
|
|
20
|
+
import type { GitCascadeEvent } from "../git-cascade-adapter.js";
|
|
21
|
+
|
|
22
|
+
function mkTempRepo(): string {
|
|
23
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "macro-standalone-"));
|
|
24
|
+
execSync("git init", { cwd: dir, stdio: "pipe" });
|
|
25
|
+
execSync('git config user.email "test@test.com"', { cwd: dir, stdio: "pipe" });
|
|
26
|
+
execSync('git config user.name "Test"', { cwd: dir, stdio: "pipe" });
|
|
27
|
+
fs.writeFileSync(path.join(dir, ".gitignore"), ".git-cascade/\n");
|
|
28
|
+
fs.writeFileSync(path.join(dir, "README.md"), "# test\n");
|
|
29
|
+
execSync("git add .", { cwd: dir, stdio: "pipe" });
|
|
30
|
+
execSync('git commit -m "init"', { cwd: dir, stdio: "pipe" });
|
|
31
|
+
fs.mkdirSync(path.join(dir, ".git-cascade"), { recursive: true });
|
|
32
|
+
return dir;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("standalone mode: GitCascadeAdapter without sidecar/bridge", () => {
|
|
36
|
+
let repoPath: string;
|
|
37
|
+
let adapter: GitCascadeAdapter;
|
|
38
|
+
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
repoPath = mkTempRepo();
|
|
41
|
+
// Construct the adapter with no MAP sidecar — same shape as boot-v2 when
|
|
42
|
+
// `config.map?.enabled !== true`. No CascadeBridge is ever wired.
|
|
43
|
+
adapter = new GitCascadeAdapter({ repoPath });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
fs.rmSync(repoPath, { recursive: true, force: true });
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("runs full stream lifecycle without errors and produces local events", () => {
|
|
51
|
+
const events: GitCascadeEvent[] = [];
|
|
52
|
+
adapter.onEvent((e) => events.push(e));
|
|
53
|
+
|
|
54
|
+
// Open a stream
|
|
55
|
+
const streamId = adapter.createStream({
|
|
56
|
+
name: "standalone-feat",
|
|
57
|
+
agentId: "a1",
|
|
58
|
+
});
|
|
59
|
+
expect(streamId).toBeTruthy();
|
|
60
|
+
|
|
61
|
+
// Create worktree + commit through tracker
|
|
62
|
+
const wt = path.join(repoPath, ".worktrees", "a1");
|
|
63
|
+
adapter.createWorktree({
|
|
64
|
+
agentId: "a1",
|
|
65
|
+
path: wt,
|
|
66
|
+
branch: `stream/${streamId}`,
|
|
67
|
+
});
|
|
68
|
+
fs.writeFileSync(path.join(wt, "x.txt"), "hi\n");
|
|
69
|
+
execSync("git add .", { cwd: wt, stdio: "pipe" });
|
|
70
|
+
const result = adapter.commitChanges({
|
|
71
|
+
streamId,
|
|
72
|
+
agentId: "a1",
|
|
73
|
+
worktree: wt,
|
|
74
|
+
message: "feat: add x",
|
|
75
|
+
metadata: { task_ref: { resource_id: "r", node_id: "n" } },
|
|
76
|
+
});
|
|
77
|
+
expect(result.commit).toBeTruthy();
|
|
78
|
+
expect(result.changeId).toBeTruthy();
|
|
79
|
+
|
|
80
|
+
// Abandon
|
|
81
|
+
adapter.abandonStream(streamId, { reason: "test" });
|
|
82
|
+
|
|
83
|
+
// Verify expected events fired locally (no hub involved)
|
|
84
|
+
const types = events.map((e) => e.type);
|
|
85
|
+
expect(types).toContain("stream:created");
|
|
86
|
+
expect(types).toContain("stream:committed");
|
|
87
|
+
expect(types).toContain("stream:abandoned");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("does not throw when no event listener is attached", () => {
|
|
91
|
+
// No onEvent subscribers — adapter must not assume any.
|
|
92
|
+
const streamId = adapter.createStream({ name: "lonely", agentId: "a" });
|
|
93
|
+
expect(streamId).toBeTruthy();
|
|
94
|
+
adapter.abandonStream(streamId, { reason: "test" });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("preserves Change-Id even with no hub forwarding", () => {
|
|
98
|
+
// Confirms the tracker's emit hook works locally even when nothing
|
|
99
|
+
// forwards events — the Change-Id is computed by git-cascade itself, not
|
|
100
|
+
// by the bridge.
|
|
101
|
+
const streamId = adapter.createStream({ name: "chgid", agentId: "a" });
|
|
102
|
+
const wt = path.join(repoPath, ".worktrees", "a");
|
|
103
|
+
adapter.createWorktree({
|
|
104
|
+
agentId: "a",
|
|
105
|
+
path: wt,
|
|
106
|
+
branch: `stream/${streamId}`,
|
|
107
|
+
});
|
|
108
|
+
fs.writeFileSync(path.join(wt, "y.txt"), "y\n");
|
|
109
|
+
execSync("git add .", { cwd: wt, stdio: "pipe" });
|
|
110
|
+
const { changeId } = adapter.commitChanges({
|
|
111
|
+
streamId,
|
|
112
|
+
agentId: "a",
|
|
113
|
+
worktree: wt,
|
|
114
|
+
message: "test",
|
|
115
|
+
});
|
|
116
|
+
expect(changeId).toMatch(/^c-/);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkspaceManager V3 surface tests (Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* Covers the stream-first methods added alongside the legacy role-shaped API.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import * as os from 'os';
|
|
11
|
+
import { execSync } from 'child_process';
|
|
12
|
+
import { createGitCascadeAdapter, type GitCascadeAdapter } from '../git-cascade-adapter.js';
|
|
13
|
+
import {
|
|
14
|
+
DefaultWorkspaceManager,
|
|
15
|
+
createWorkspaceManagerWithAdapter,
|
|
16
|
+
} from '../workspace-manager.js';
|
|
17
|
+
|
|
18
|
+
describe('WorkspaceManager V3 surface', () => {
|
|
19
|
+
let tempDir: string;
|
|
20
|
+
let repoPath: string;
|
|
21
|
+
let dbPath: string;
|
|
22
|
+
let adapter: GitCascadeAdapter;
|
|
23
|
+
let manager: DefaultWorkspaceManager;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ws-v3-test-'));
|
|
27
|
+
repoPath = path.join(tempDir, 'repo');
|
|
28
|
+
dbPath = path.join(tempDir, 'test.db');
|
|
29
|
+
fs.mkdirSync(repoPath);
|
|
30
|
+
|
|
31
|
+
execSync('git init -b main', { cwd: repoPath, stdio: 'pipe' });
|
|
32
|
+
execSync('git config user.email "test@test.com"', { cwd: repoPath, stdio: 'pipe' });
|
|
33
|
+
execSync('git config user.name "Test User"', { cwd: repoPath, stdio: 'pipe' });
|
|
34
|
+
fs.writeFileSync(path.join(repoPath, 'README.md'), '# Test');
|
|
35
|
+
execSync('git add .', { cwd: repoPath, stdio: 'pipe' });
|
|
36
|
+
execSync('git commit -m "init"', { cwd: repoPath, stdio: 'pipe' });
|
|
37
|
+
|
|
38
|
+
adapter = createGitCascadeAdapter({
|
|
39
|
+
enabled: true,
|
|
40
|
+
repoPath,
|
|
41
|
+
dbPath,
|
|
42
|
+
skipRecovery: true,
|
|
43
|
+
});
|
|
44
|
+
manager = createWorkspaceManagerWithAdapter(adapter, {
|
|
45
|
+
worktreeBaseDir: path.join(tempDir, 'worktrees'),
|
|
46
|
+
}) as DefaultWorkspaceManager;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
manager.close();
|
|
51
|
+
adapter.close();
|
|
52
|
+
if (tempDir && fs.existsSync(tempDir)) {
|
|
53
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('streams', () => {
|
|
58
|
+
it('creates a stream with a pseudo-principal owner', () => {
|
|
59
|
+
const streamId = manager.createStreamV3({
|
|
60
|
+
name: 'team-root',
|
|
61
|
+
ownerId: 'team:peer-swarm',
|
|
62
|
+
forkFrom: 'main',
|
|
63
|
+
});
|
|
64
|
+
expect(streamId).toBeDefined();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('forks a child stream off a parent', () => {
|
|
68
|
+
const parent = manager.createStreamV3({
|
|
69
|
+
name: 'parent',
|
|
70
|
+
ownerId: 'team:solo-stack',
|
|
71
|
+
});
|
|
72
|
+
const child = manager.forkStream({
|
|
73
|
+
parentStreamId: parent,
|
|
74
|
+
name: 'child',
|
|
75
|
+
ownerId: 'agent-1',
|
|
76
|
+
});
|
|
77
|
+
const childStream = adapter.getStream(child);
|
|
78
|
+
expect(childStream?.parentStream).toBe(parent);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('emits stream:created and stream:forked events', () => {
|
|
82
|
+
const events: string[] = [];
|
|
83
|
+
manager.onEvent((e) => events.push(e.type));
|
|
84
|
+
|
|
85
|
+
const parent = manager.createStreamV3({ name: 'parent', ownerId: 'team:x' });
|
|
86
|
+
manager.forkStream({ parentStreamId: parent, name: 'child', ownerId: 'agent-1' });
|
|
87
|
+
|
|
88
|
+
expect(events).toContain('stream:created');
|
|
89
|
+
expect(events).toContain('stream:forked');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('pauses and resumes a stream with events', () => {
|
|
93
|
+
const streamId = manager.createStreamV3({ name: 'x', ownerId: 'agent-1' });
|
|
94
|
+
const events: string[] = [];
|
|
95
|
+
manager.onEvent((e) => events.push(e.type));
|
|
96
|
+
|
|
97
|
+
manager.pauseStream(streamId, 'manual');
|
|
98
|
+
expect(adapter.getStream(streamId)?.status).toBe('paused');
|
|
99
|
+
expect(events).toContain('stream:paused');
|
|
100
|
+
|
|
101
|
+
manager.resumeStream(streamId);
|
|
102
|
+
expect(adapter.getStream(streamId)?.status).toBe('active');
|
|
103
|
+
expect(events).toContain('stream:resumed');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('lists streams by owner', () => {
|
|
107
|
+
manager.createStreamV3({ name: 'a', ownerId: 'agent-1' });
|
|
108
|
+
manager.createStreamV3({ name: 'b', ownerId: 'agent-2' });
|
|
109
|
+
const owned = manager.listStreams({ ownerId: 'agent-1' });
|
|
110
|
+
expect(owned.length).toBe(1);
|
|
111
|
+
expect(owned[0].name).toBe('a');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('worktree allocation', () => {
|
|
116
|
+
it('allocates a worktree attached to a stream', () => {
|
|
117
|
+
const streamId = manager.createStreamV3({ name: 'feat', ownerId: 'agent-1' });
|
|
118
|
+
const wt = manager.allocateWorktree({
|
|
119
|
+
agentId: 'agent-1',
|
|
120
|
+
streamId,
|
|
121
|
+
});
|
|
122
|
+
expect(wt.path).toContain('agent-1');
|
|
123
|
+
expect(wt.agentId).toBe('agent-1');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('shares a worktree between two agents (ref-counted)', () => {
|
|
127
|
+
const streamId = manager.createStreamV3({ name: 'feat', ownerId: 'agent-1' });
|
|
128
|
+
const primary = manager.allocateWorktree({ agentId: 'agent-1', streamId });
|
|
129
|
+
|
|
130
|
+
const shared = manager.allocateWorktree({
|
|
131
|
+
agentId: 'agent-2',
|
|
132
|
+
sharedWithAgent: 'agent-1',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(shared.path).toBe(primary.path);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('throws when sharing from an unallocated agent', () => {
|
|
139
|
+
expect(() =>
|
|
140
|
+
manager.allocateWorktree({ agentId: 'agent-x', sharedWithAgent: 'nonexistent' })
|
|
141
|
+
).toThrow(/has no allocated worktree/);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('emits worktree:allocated and worktree:shared events', () => {
|
|
145
|
+
const streamId = manager.createStreamV3({ name: 'feat', ownerId: 'agent-1' });
|
|
146
|
+
const events: string[] = [];
|
|
147
|
+
manager.onEvent((e) => events.push(e.type));
|
|
148
|
+
|
|
149
|
+
manager.allocateWorktree({ agentId: 'agent-1', streamId });
|
|
150
|
+
manager.allocateWorktree({ agentId: 'agent-2', sharedWithAgent: 'agent-1' });
|
|
151
|
+
|
|
152
|
+
expect(events).toContain('worktree:allocated');
|
|
153
|
+
expect(events).toContain('worktree:shared');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('changes (Change-Id tracking)', () => {
|
|
158
|
+
it('commits via commitChanges and assigns a Change-Id', () => {
|
|
159
|
+
const streamId = manager.createStreamV3({ name: 'feat', ownerId: 'agent-1' });
|
|
160
|
+
const wt = manager.allocateWorktree({ agentId: 'agent-1', streamId });
|
|
161
|
+
|
|
162
|
+
fs.writeFileSync(path.join(wt.path, 'hello.txt'), 'hi');
|
|
163
|
+
|
|
164
|
+
const result = manager.commitChanges({
|
|
165
|
+
agentId: 'agent-1',
|
|
166
|
+
streamId,
|
|
167
|
+
worktree: wt.path,
|
|
168
|
+
message: 'add hello',
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(result.commit).toBeDefined();
|
|
172
|
+
expect(result.changeId).toBeDefined();
|
|
173
|
+
expect(result.changeId.startsWith('c-')).toBe(true);
|
|
174
|
+
|
|
175
|
+
const change = manager.getChangeByCommit(result.commit);
|
|
176
|
+
expect(change?.id).toBe(result.changeId);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('emits stream:committed event on commit', () => {
|
|
180
|
+
const streamId = manager.createStreamV3({ name: 'feat', ownerId: 'agent-1' });
|
|
181
|
+
const wt = manager.allocateWorktree({ agentId: 'agent-1', streamId });
|
|
182
|
+
|
|
183
|
+
fs.writeFileSync(path.join(wt.path, 'x.txt'), 'x');
|
|
184
|
+
|
|
185
|
+
const events: Array<{ type: string; data: Record<string, unknown> }> = [];
|
|
186
|
+
manager.onEvent((e) => events.push(e));
|
|
187
|
+
|
|
188
|
+
manager.commitChanges({
|
|
189
|
+
agentId: 'agent-1',
|
|
190
|
+
streamId,
|
|
191
|
+
worktree: wt.path,
|
|
192
|
+
message: 'x',
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const committed = events.find((e) => e.type === 'stream:committed');
|
|
196
|
+
expect(committed).toBeDefined();
|
|
197
|
+
expect(committed?.data.streamId).toBe(streamId);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('marks changes merged and emits events', () => {
|
|
201
|
+
const streamId = manager.createStreamV3({ name: 'feat', ownerId: 'agent-1' });
|
|
202
|
+
const wt = manager.allocateWorktree({ agentId: 'agent-1', streamId });
|
|
203
|
+
fs.writeFileSync(path.join(wt.path, 'x.txt'), 'x');
|
|
204
|
+
const { changeId } = manager.commitChanges({
|
|
205
|
+
agentId: 'agent-1',
|
|
206
|
+
streamId,
|
|
207
|
+
worktree: wt.path,
|
|
208
|
+
message: 'x',
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const events: string[] = [];
|
|
212
|
+
manager.onEvent((e) => events.push(e.type));
|
|
213
|
+
|
|
214
|
+
manager.markChangesMerged([changeId]);
|
|
215
|
+
expect(events).toContain('change:merged');
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('landing strategy registry', () => {
|
|
220
|
+
it('registers landing strategies', () => {
|
|
221
|
+
const mockStrategy = {
|
|
222
|
+
name: 'test-strategy',
|
|
223
|
+
async land() {
|
|
224
|
+
return { success: true };
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
manager.registerLandingStrategy(mockStrategy);
|
|
228
|
+
// Registration is internal; successful if no throw. Full integration
|
|
229
|
+
// covered in Phase 5.
|
|
230
|
+
expect(true).toBe(true);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe('reconcileV3', () => {
|
|
235
|
+
it('returns a MacroReconcileResult with zero issues on a clean db', () => {
|
|
236
|
+
manager.createStreamV3({ name: 'a', ownerId: 'agent-1' });
|
|
237
|
+
const result = manager.reconcileV3();
|
|
238
|
+
|
|
239
|
+
expect(result).toBeDefined();
|
|
240
|
+
expect(result.errors.length).toBe(0);
|
|
241
|
+
// Fresh streams are in sync → no fixes needed
|
|
242
|
+
expect(result.worktreesOrphaned).toBe(0);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML schema validation tests (Phase 2).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
parseTeamWorkspaceConfig,
|
|
8
|
+
extractWorkspaceConfig,
|
|
9
|
+
TeamWorkspaceConfigSchema,
|
|
10
|
+
RoleWorkspaceConfigSchema,
|
|
11
|
+
} from '../yaml-schema.js';
|
|
12
|
+
|
|
13
|
+
describe('YAML schema', () => {
|
|
14
|
+
describe('parseTeamWorkspaceConfig', () => {
|
|
15
|
+
it('returns null when input is undefined', () => {
|
|
16
|
+
expect(parseTeamWorkspaceConfig(undefined)).toBeNull();
|
|
17
|
+
expect(parseTeamWorkspaceConfig(null)).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('accepts a minimal peer-swarm-style config', () => {
|
|
21
|
+
const config = parseTeamWorkspaceConfig({
|
|
22
|
+
roles: {
|
|
23
|
+
peer: {
|
|
24
|
+
workspace: 'new_stream',
|
|
25
|
+
stream_lineage: 'fork_from_team_root',
|
|
26
|
+
landing: 'merge_to_parent_stream',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
expect(config).not.toBeNull();
|
|
31
|
+
expect(config!.on_team_complete).toBe('keep'); // default
|
|
32
|
+
expect(config!.roles.peer.workspace).toBe('new_stream');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('applies defaults for default_stream', () => {
|
|
36
|
+
const config = parseTeamWorkspaceConfig({
|
|
37
|
+
default_stream: {},
|
|
38
|
+
roles: { x: { workspace: 'none' } },
|
|
39
|
+
});
|
|
40
|
+
expect(config!.default_stream?.fork_from).toBe('main');
|
|
41
|
+
expect(config!.default_stream?.change_id_tracking).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('requires share_with when workspace is share_with_agent', () => {
|
|
45
|
+
expect(() =>
|
|
46
|
+
parseTeamWorkspaceConfig({
|
|
47
|
+
roles: {
|
|
48
|
+
reviewer: { workspace: 'share_with_agent' },
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
).toThrow(/share_with is required/);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('requires track_branch when stream_lineage is track_existing_branch', () => {
|
|
55
|
+
expect(() =>
|
|
56
|
+
parseTeamWorkspaceConfig({
|
|
57
|
+
roles: {
|
|
58
|
+
resolver: {
|
|
59
|
+
workspace: 'new_stream',
|
|
60
|
+
stream_lineage: 'track_existing_branch',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
).toThrow(/track_branch is required/);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('requires stream_lineage when workspace is new_stream', () => {
|
|
68
|
+
expect(() =>
|
|
69
|
+
parseTeamWorkspaceConfig({
|
|
70
|
+
roles: {
|
|
71
|
+
x: { workspace: 'new_stream' },
|
|
72
|
+
},
|
|
73
|
+
})
|
|
74
|
+
).toThrow(/stream_lineage is required/);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('accepts triad shape with queue_to_branch + merge_queue.drain', () => {
|
|
78
|
+
const config = parseTeamWorkspaceConfig({
|
|
79
|
+
on_team_complete: 'keep',
|
|
80
|
+
roles: {
|
|
81
|
+
coordinator: { workspace: 'attach_to_team_root' },
|
|
82
|
+
worker: {
|
|
83
|
+
workspace: 'new_stream',
|
|
84
|
+
stream_lineage: 'fork_from_parent',
|
|
85
|
+
landing: 'queue_to_branch',
|
|
86
|
+
landing_config: { target: 'team_root' },
|
|
87
|
+
capabilities: ['workspace.commit', 'workspace.land'],
|
|
88
|
+
},
|
|
89
|
+
integrator: {
|
|
90
|
+
workspace: 'attach_to_team_root',
|
|
91
|
+
capabilities: ['workspace.merge', 'merge_queue.drain'],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
expect(config).not.toBeNull();
|
|
96
|
+
expect(config!.roles.worker.landing).toBe('queue_to_branch');
|
|
97
|
+
expect(config!.roles.integrator.capabilities).toContain('merge_queue.drain');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('accepts pipeline shape with share_with_agent', () => {
|
|
101
|
+
const config = parseTeamWorkspaceConfig({
|
|
102
|
+
roles: {
|
|
103
|
+
planner: { workspace: 'none' },
|
|
104
|
+
coder: {
|
|
105
|
+
workspace: 'new_stream',
|
|
106
|
+
stream_lineage: 'fork_from_team_root',
|
|
107
|
+
landing: 'queue_to_branch',
|
|
108
|
+
},
|
|
109
|
+
reviewer: {
|
|
110
|
+
workspace: 'share_with_agent',
|
|
111
|
+
share_with: 'coder',
|
|
112
|
+
capabilities: ['workspace.read'],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
expect(config!.roles.reviewer.share_with).toBe('coder');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('accepts long-lived feature config with cascade + auto-sync', () => {
|
|
120
|
+
const config = parseTeamWorkspaceConfig({
|
|
121
|
+
roles: {
|
|
122
|
+
feature_owner: {
|
|
123
|
+
workspace: 'new_stream',
|
|
124
|
+
stream_lineage: 'fork_from_team_root',
|
|
125
|
+
landing: 'merge_to_parent_stream',
|
|
126
|
+
cascade_on_parent_update: true,
|
|
127
|
+
on_parent_advanced: 'sync_with_parent',
|
|
128
|
+
},
|
|
129
|
+
subtask: {
|
|
130
|
+
workspace: 'new_stream',
|
|
131
|
+
stream_lineage: 'fork_from_parent',
|
|
132
|
+
landing: 'merge_to_parent_stream',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
expect(config!.roles.feature_owner.cascade_on_parent_update).toBe(true);
|
|
137
|
+
expect(config!.roles.feature_owner.on_parent_advanced).toBe('sync_with_parent');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('accepts conflict_recovery team defaults', () => {
|
|
141
|
+
const config = parseTeamWorkspaceConfig({
|
|
142
|
+
roles: { peer: { workspace: 'none' } },
|
|
143
|
+
conflict_recovery: {
|
|
144
|
+
default_strategy: 'spawn-resolver',
|
|
145
|
+
default_config: { role: 'resolver', timeout_ms: 1200000 },
|
|
146
|
+
max_recovery_depth: 5,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
expect(config!.conflict_recovery?.default_strategy).toBe('spawn-resolver');
|
|
150
|
+
expect(config!.conflict_recovery?.max_recovery_depth).toBe(5);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('rejects unknown workspace kinds', () => {
|
|
154
|
+
expect(() =>
|
|
155
|
+
parseTeamWorkspaceConfig({
|
|
156
|
+
roles: { x: { workspace: 'made-up' } },
|
|
157
|
+
})
|
|
158
|
+
).toThrow();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('rejects unknown landing strategy names', () => {
|
|
162
|
+
expect(() =>
|
|
163
|
+
parseTeamWorkspaceConfig({
|
|
164
|
+
roles: {
|
|
165
|
+
x: {
|
|
166
|
+
workspace: 'new_stream',
|
|
167
|
+
stream_lineage: 'fork_from_team_root',
|
|
168
|
+
landing: 'unknown-strategy',
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
).toThrow();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('extractWorkspaceConfig', () => {
|
|
177
|
+
it('extracts workspace block from a manifest with macro_agent.workspace', () => {
|
|
178
|
+
const manifest = {
|
|
179
|
+
macro_agent: {
|
|
180
|
+
workspace: {
|
|
181
|
+
roles: { x: { workspace: 'none' } },
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
const config = extractWorkspaceConfig(manifest);
|
|
186
|
+
expect(config).not.toBeNull();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('returns null when macro_agent.workspace is absent', () => {
|
|
190
|
+
const manifest = { macro_agent: { integration: { strategy: 'trunk' } } };
|
|
191
|
+
expect(extractWorkspaceConfig(manifest)).toBeNull();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('returns null when macro_agent is absent', () => {
|
|
195
|
+
expect(extractWorkspaceConfig({})).toBeNull();
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
describe('schema shape', () => {
|
|
200
|
+
it('TeamWorkspaceConfigSchema is a zod object', () => {
|
|
201
|
+
expect(TeamWorkspaceConfigSchema).toBeDefined();
|
|
202
|
+
expect(typeof TeamWorkspaceConfigSchema.safeParse).toBe('function');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('RoleWorkspaceConfigSchema is a zod schema', () => {
|
|
206
|
+
expect(RoleWorkspaceConfigSchema).toBeDefined();
|
|
207
|
+
expect(typeof RoleWorkspaceConfigSchema.safeParse).toBe('function');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
package/src/workspace/config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Workspace Configuration Types
|
|
3
3
|
*
|
|
4
|
-
* Configuration for
|
|
4
|
+
* Configuration for git-cascade integration and workspace management.
|
|
5
5
|
*
|
|
6
6
|
* @module workspace/config
|
|
7
7
|
*/
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
import type Database from 'better-sqlite3';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Configuration for
|
|
12
|
+
* Configuration for git-cascade integration
|
|
13
13
|
*/
|
|
14
|
-
export interface
|
|
14
|
+
export interface GitCascadeConfig {
|
|
15
15
|
/**
|
|
16
|
-
* Whether
|
|
16
|
+
* Whether the git-cascade adapter is enabled.
|
|
17
17
|
* When disabled, workspace operations are no-ops.
|
|
18
18
|
*/
|
|
19
19
|
enabled: boolean;
|
|
@@ -25,21 +25,21 @@ export interface DataplaneConfig {
|
|
|
25
25
|
repoPath?: string;
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Table prefix for
|
|
29
|
-
* Defaults to '
|
|
28
|
+
* Table prefix for git-cascade tables in shared SQLite database.
|
|
29
|
+
* Defaults to 'git_cascade_'.
|
|
30
30
|
*/
|
|
31
31
|
tablePrefix?: string;
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Path to SQLite database file.
|
|
35
35
|
* If not provided and db is not provided, creates database at
|
|
36
|
-
* `<repoPath>/.
|
|
36
|
+
* `<repoPath>/.git-cascade/tracker.db`.
|
|
37
37
|
*/
|
|
38
38
|
dbPath?: string;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Existing database connection to share.
|
|
42
|
-
* If provided,
|
|
42
|
+
* If provided, the adapter will use this connection instead of creating its own.
|
|
43
43
|
* The caller is responsible for closing this connection.
|
|
44
44
|
*/
|
|
45
45
|
db?: Database.Database;
|
|
@@ -57,11 +57,11 @@ export interface DataplaneConfig {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
* Default
|
|
60
|
+
* Default git-cascade configuration
|
|
61
61
|
*/
|
|
62
|
-
export const
|
|
62
|
+
export const DEFAULT_GIT_CASCADE_CONFIG: Partial<GitCascadeConfig> = {
|
|
63
63
|
enabled: true,
|
|
64
|
-
tablePrefix: '
|
|
64
|
+
tablePrefix: 'git_cascade_',
|
|
65
65
|
verbose: false,
|
|
66
66
|
skipRecovery: false,
|
|
67
67
|
};
|