opencastle 0.12.0 → 0.13.0

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.
Files changed (35) hide show
  1. package/dist/cli/convoy/merge.d.ts +15 -0
  2. package/dist/cli/convoy/merge.d.ts.map +1 -0
  3. package/dist/cli/convoy/merge.js +62 -0
  4. package/dist/cli/convoy/merge.js.map +1 -0
  5. package/dist/cli/convoy/merge.test.d.ts +2 -0
  6. package/dist/cli/convoy/merge.test.d.ts.map +1 -0
  7. package/dist/cli/convoy/merge.test.js +134 -0
  8. package/dist/cli/convoy/merge.test.js.map +1 -0
  9. package/dist/cli/convoy/worktree.d.ts +13 -0
  10. package/dist/cli/convoy/worktree.d.ts.map +1 -0
  11. package/dist/cli/convoy/worktree.js +90 -0
  12. package/dist/cli/convoy/worktree.js.map +1 -0
  13. package/dist/cli/convoy/worktree.test.d.ts +2 -0
  14. package/dist/cli/convoy/worktree.test.d.ts.map +1 -0
  15. package/dist/cli/convoy/worktree.test.js +146 -0
  16. package/dist/cli/convoy/worktree.test.js.map +1 -0
  17. package/dist/cli/run/adapters/claude-code.js +1 -1
  18. package/dist/cli/run/adapters/claude-code.js.map +1 -1
  19. package/dist/cli/run/adapters/copilot.d.ts.map +1 -1
  20. package/dist/cli/run/adapters/copilot.js +5 -0
  21. package/dist/cli/run/adapters/copilot.js.map +1 -1
  22. package/dist/cli/run/adapters/cursor.js +1 -1
  23. package/dist/cli/run/adapters/cursor.js.map +1 -1
  24. package/dist/cli/types.d.ts +2 -0
  25. package/dist/cli/types.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/cli/convoy/merge.test.ts +184 -0
  28. package/src/cli/convoy/merge.ts +89 -0
  29. package/src/cli/convoy/worktree.test.ts +177 -0
  30. package/src/cli/convoy/worktree.ts +116 -0
  31. package/src/cli/run/adapters/claude-code.ts +1 -1
  32. package/src/cli/run/adapters/copilot.ts +5 -0
  33. package/src/cli/run/adapters/cursor.ts +1 -1
  34. package/src/cli/types.ts +2 -0
  35. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
@@ -0,0 +1,15 @@
1
+ export interface MergeResult {
2
+ success: boolean;
3
+ conflicted: boolean;
4
+ message: string;
5
+ }
6
+ export interface MergeQueue {
7
+ /**
8
+ * Merge a single worktree's changes back onto the target branch.
9
+ * Stages all changes in the worktree, commits them if necessary, then merges
10
+ * the worktree branch into the target branch.
11
+ */
12
+ merge(worktreePath: string, worktreeBranch: string, targetBranch: string): Promise<MergeResult>;
13
+ }
14
+ export declare function createMergeQueue(repoPath: string): MergeQueue;
15
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CAChG;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAmE7D"}
@@ -0,0 +1,62 @@
1
+ import { execFile as execFileCb } from 'node:child_process';
2
+ import { resolve, join, sep } from 'node:path';
3
+ import { promisify } from 'node:util';
4
+ const execFile = promisify(execFileCb);
5
+ export function createMergeQueue(repoPath) {
6
+ const worktreesDir = resolve(join(repoPath, '.opencastle', 'worktrees'));
7
+ async function merge(worktreePath, worktreeBranch, targetBranch) {
8
+ const resolvedWorktree = resolve(worktreePath);
9
+ if (!resolvedWorktree.startsWith(worktreesDir + sep)) {
10
+ throw new Error(`Path "${worktreePath}" is outside the managed worktrees directory`);
11
+ }
12
+ // Stage all untracked/modified files in the worktree
13
+ await execFile('git', ['-C', resolvedWorktree, 'add', '-A']);
14
+ // List staged files — non-empty output means there are changes to commit.
15
+ // Uses --name-only (exits 0 regardless of diff size) rather than --quiet
16
+ // (exits 1 when changes exist) so the check is output-based, not exit-code-based.
17
+ const { stdout: staged } = await execFile('git', [
18
+ '-C',
19
+ resolvedWorktree,
20
+ 'diff',
21
+ '--cached',
22
+ '--name-only',
23
+ ]);
24
+ const hasUncommitted = staged.trim().length > 0;
25
+ if (hasUncommitted) {
26
+ await execFile('git', [
27
+ '-C',
28
+ resolvedWorktree,
29
+ 'commit',
30
+ '-m',
31
+ `convoy: ${worktreeBranch} completed`,
32
+ ]);
33
+ }
34
+ // Merge the worktree branch into the target branch in the main repo
35
+ await execFile('git', ['-C', repoPath, 'checkout', targetBranch]);
36
+ try {
37
+ const { stdout } = await execFile('git', [
38
+ '-C',
39
+ repoPath,
40
+ 'merge',
41
+ worktreeBranch,
42
+ '--no-edit',
43
+ ]);
44
+ if (stdout.includes('Already up to date')) {
45
+ return { success: true, conflicted: false, message: 'No changes to merge' };
46
+ }
47
+ return { success: true, conflicted: false, message: 'Merged successfully' };
48
+ }
49
+ catch (err) {
50
+ const error = err;
51
+ const isConflict = error.code === 1 &&
52
+ ((error.stderr ?? '').includes('CONFLICT') || (error.stdout ?? '').includes('CONFLICT'));
53
+ if (isConflict) {
54
+ await execFile('git', ['-C', repoPath, 'merge', '--abort']);
55
+ return { success: false, conflicted: true, message: 'Merge conflict detected; merge aborted' };
56
+ }
57
+ throw err;
58
+ }
59
+ }
60
+ return { merge };
61
+ }
62
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=merge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/merge.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,134 @@
1
+ import { mkdtempSync, rmSync, realpathSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { execFile as execFileCb } from 'node:child_process';
5
+ import { promisify } from 'node:util';
6
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { createMergeQueue } from './merge.js';
8
+ const execFile = promisify(execFileCb);
9
+ // ── helpers ───────────────────────────────────────────────────────────────────
10
+ let repoPath;
11
+ let featureBranch;
12
+ let queue;
13
+ async function setupTestRepo() {
14
+ const path = realpathSync(mkdtempSync(join(tmpdir(), 'merge-test-')));
15
+ await execFile('git', ['init', path]);
16
+ await execFile('git', ['-C', path, 'config', 'user.email', 'test@test.com']);
17
+ await execFile('git', ['-C', path, 'config', 'user.name', 'Test']);
18
+ writeFileSync(join(path, 'README.md'), '# Test');
19
+ await execFile('git', ['-C', path, 'add', '-A']);
20
+ await execFile('git', ['-C', path, 'commit', '-m', 'Initial commit']);
21
+ await execFile('git', ['-C', path, 'checkout', '-b', 'feat/test']);
22
+ return { repoPath: path, featureBranch: 'feat/test' };
23
+ }
24
+ async function addWorktree(repo, workerId, branch) {
25
+ const worktreesDir = join(repo, '.opencastle', 'worktrees');
26
+ mkdirSync(worktreesDir, { recursive: true });
27
+ const worktreePath = join(worktreesDir, workerId);
28
+ await execFile('git', ['-C', repo, 'worktree', 'add', worktreePath, '-b', `convoy-${workerId}`, branch]);
29
+ return worktreePath;
30
+ }
31
+ beforeEach(async () => {
32
+ const result = await setupTestRepo();
33
+ repoPath = result.repoPath;
34
+ featureBranch = result.featureBranch;
35
+ queue = createMergeQueue(repoPath);
36
+ });
37
+ afterEach(() => {
38
+ rmSync(repoPath, { recursive: true, force: true });
39
+ });
40
+ // ── successful merge ──────────────────────────────────────────────────────────
41
+ describe('merge - successful merge', () => {
42
+ it('stages, commits, and merges worktree changes to the target branch', async () => {
43
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
44
+ writeFileSync(join(worktreePath, 'output.txt'), 'worker output');
45
+ const result = await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
46
+ expect(result).toEqual({ success: true, conflicted: false, message: 'Merged successfully' });
47
+ });
48
+ it('makes the merged file available in the target branch working tree', async () => {
49
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
50
+ writeFileSync(join(worktreePath, 'output.txt'), 'worker output');
51
+ await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
52
+ const { existsSync } = await import('node:fs');
53
+ expect(existsSync(join(repoPath, 'output.txt'))).toBe(true);
54
+ });
55
+ it('creates an auto-commit on the worktree branch with the convoy message', async () => {
56
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
57
+ writeFileSync(join(worktreePath, 'output.txt'), 'worker output');
58
+ await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
59
+ const { stdout } = await execFile('git', ['-C', repoPath, 'log', '--oneline', 'convoy-worker1']);
60
+ expect(stdout).toContain('convoy: convoy-worker1 completed');
61
+ });
62
+ });
63
+ // ── no changes ────────────────────────────────────────────────────────────────
64
+ describe('merge - no changes', () => {
65
+ it('returns success with "No changes to merge" when the worker made no file changes', async () => {
66
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
67
+ const result = await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
68
+ expect(result).toEqual({ success: true, conflicted: false, message: 'No changes to merge' });
69
+ });
70
+ it('does not create a commit when there is nothing to stage', async () => {
71
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
72
+ await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
73
+ const { stdout } = await execFile('git', ['-C', repoPath, 'log', '--oneline', 'convoy-worker1']);
74
+ expect(stdout).not.toContain('convoy: convoy-worker1 completed');
75
+ });
76
+ });
77
+ // ── merge conflict ────────────────────────────────────────────────────────────
78
+ describe('merge - conflict', () => {
79
+ it('returns conflicted: true and aborts when two worktrees edit the same file', async () => {
80
+ const worktree1 = await addWorktree(repoPath, 'worker1', featureBranch);
81
+ const worktree2 = await addWorktree(repoPath, 'worker2', featureBranch);
82
+ writeFileSync(join(worktree1, 'shared.txt'), 'content from worker 1');
83
+ writeFileSync(join(worktree2, 'shared.txt'), 'content from worker 2');
84
+ const first = await queue.merge(worktree1, 'convoy-worker1', featureBranch);
85
+ expect(first).toEqual({ success: true, conflicted: false, message: 'Merged successfully' });
86
+ const second = await queue.merge(worktree2, 'convoy-worker2', featureBranch);
87
+ expect(second.success).toBe(false);
88
+ expect(second.conflicted).toBe(true);
89
+ expect(second.message).toContain('conflict');
90
+ });
91
+ it('leaves the repo in a clean state (no pending merge) after aborting a conflict', async () => {
92
+ const worktree1 = await addWorktree(repoPath, 'worker1', featureBranch);
93
+ const worktree2 = await addWorktree(repoPath, 'worker2', featureBranch);
94
+ writeFileSync(join(worktree1, 'shared.txt'), 'content from worker 1');
95
+ writeFileSync(join(worktree2, 'shared.txt'), 'content from worker 2');
96
+ await queue.merge(worktree1, 'convoy-worker1', featureBranch);
97
+ await queue.merge(worktree2, 'convoy-worker2', featureBranch);
98
+ // --untracked-files=no excludes the .opencastle/worktrees/ dir from the check;
99
+ // we only want to verify there is no pending merge (no staged/modified tracked files).
100
+ const { stdout } = await execFile('git', ['-C', repoPath, 'status', '--porcelain', '--untracked-files=no']);
101
+ expect(stdout.trim()).toBe('');
102
+ });
103
+ });
104
+ // ── already committed changes ─────────────────────────────────────────────────
105
+ describe('merge - already committed changes', () => {
106
+ it('merges pre-committed changes without auto-committing', async () => {
107
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
108
+ writeFileSync(join(worktreePath, 'output.txt'), 'pre-committed content');
109
+ await execFile('git', ['-C', worktreePath, 'add', '-A']);
110
+ await execFile('git', ['-C', worktreePath, 'commit', '-m', 'Worker manual commit']);
111
+ const result = await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
112
+ expect(result).toEqual({ success: true, conflicted: false, message: 'Merged successfully' });
113
+ });
114
+ it('makes pre-committed files available in the target branch after merge', async () => {
115
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
116
+ writeFileSync(join(worktreePath, 'output.txt'), 'pre-committed content');
117
+ await execFile('git', ['-C', worktreePath, 'add', '-A']);
118
+ await execFile('git', ['-C', worktreePath, 'commit', '-m', 'Worker manual commit']);
119
+ await queue.merge(worktreePath, 'convoy-worker1', featureBranch);
120
+ const { existsSync } = await import('node:fs');
121
+ expect(existsSync(join(repoPath, 'output.txt'))).toBe(true);
122
+ });
123
+ });
124
+ // ── error handling ────────────────────────────────────────────────────────────
125
+ describe('merge - error handling', () => {
126
+ it('throws when the worktree branch does not exist in the repo', async () => {
127
+ const worktreePath = await addWorktree(repoPath, 'worker1', featureBranch);
128
+ await expect(queue.merge(worktreePath, 'nonexistent-branch', featureBranch)).rejects.toThrow();
129
+ });
130
+ it('throws when path is outside the managed worktrees directory', async () => {
131
+ await expect(queue.merge('/tmp/evil', 'some-branch', featureBranch)).rejects.toThrow(/outside the managed worktrees directory/);
132
+ });
133
+ });
134
+ //# sourceMappingURL=merge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/merge.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface WorktreeInfo {
2
+ path: string;
3
+ branch: string;
4
+ head: string;
5
+ }
6
+ export interface WorktreeManager {
7
+ create(workerId: string, featureBranch: string): Promise<string>;
8
+ remove(worktreePath: string): Promise<void>;
9
+ list(): Promise<WorktreeInfo[]>;
10
+ removeAll(): Promise<void>;
11
+ }
12
+ export declare function createWorktreeManager(basePath: string): WorktreeManager;
13
+ //# sourceMappingURL=worktree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/worktree.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChE,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IAC/B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAiEvE"}
@@ -0,0 +1,90 @@
1
+ import { execFile as execFileCb } from 'node:child_process';
2
+ import { mkdir } from 'node:fs/promises';
3
+ import { realpathSync } from 'node:fs';
4
+ import { join, basename, resolve, sep } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ const execFile = promisify(execFileCb);
7
+ export function createWorktreeManager(basePath) {
8
+ const resolvedBase = realpathSync(resolve(basePath));
9
+ const worktreesDir = join(resolvedBase, '.opencastle', 'worktrees');
10
+ async function create(workerId, featureBranch) {
11
+ if (!/^[a-zA-Z0-9_-]+$/.test(workerId)) {
12
+ throw new Error(`Invalid workerId "${workerId}": must only contain alphanumeric characters, hyphens, and underscores`);
13
+ }
14
+ const worktreePath = join(worktreesDir, workerId);
15
+ await mkdir(worktreesDir, { recursive: true });
16
+ await execFile('git', ['worktree', 'add', worktreePath, '-b', `convoy-${workerId}`, featureBranch], { cwd: resolvedBase });
17
+ return worktreePath;
18
+ }
19
+ async function remove(worktreePath) {
20
+ let resolved;
21
+ try {
22
+ resolved = realpathSync(worktreePath);
23
+ }
24
+ catch {
25
+ resolved = resolve(worktreePath);
26
+ }
27
+ if (!resolved.startsWith(worktreesDir + sep)) {
28
+ throw new Error(`Path "${worktreePath}" is outside the managed worktrees directory`);
29
+ }
30
+ const workerId = basename(resolved);
31
+ try {
32
+ await execFile('git', ['worktree', 'remove', resolved, '--force'], {
33
+ cwd: resolvedBase,
34
+ });
35
+ }
36
+ catch (err) {
37
+ const stderr = err.stderr ?? '';
38
+ if (stderr.includes('is not a working tree')) {
39
+ return;
40
+ }
41
+ throw err;
42
+ }
43
+ try {
44
+ await execFile('git', ['branch', '-D', `convoy-${workerId}`], { cwd: resolvedBase });
45
+ }
46
+ catch {
47
+ // Branch may already be deleted — ignore
48
+ }
49
+ }
50
+ async function list() {
51
+ const { stdout } = await execFile('git', ['worktree', 'list', '--porcelain'], {
52
+ cwd: resolvedBase,
53
+ });
54
+ return parseWorktreeList(stdout, worktreesDir);
55
+ }
56
+ async function removeAll() {
57
+ const worktrees = await list();
58
+ for (const wt of worktrees) {
59
+ await remove(wt.path);
60
+ }
61
+ }
62
+ return { create, remove, list, removeAll };
63
+ }
64
+ function parseWorktreeList(output, worktreesDir) {
65
+ const results = [];
66
+ const blocks = output.trim().split(/\n\n+/).filter(Boolean);
67
+ for (const block of blocks) {
68
+ const lines = block.split('\n');
69
+ let path = '';
70
+ let head = '';
71
+ let branch = '';
72
+ for (const line of lines) {
73
+ if (line.startsWith('worktree ')) {
74
+ path = line.slice('worktree '.length);
75
+ }
76
+ else if (line.startsWith('HEAD ')) {
77
+ head = line.slice('HEAD '.length);
78
+ }
79
+ else if (line.startsWith('branch ')) {
80
+ branch = line.slice('branch '.length);
81
+ }
82
+ }
83
+ // Only include worktrees that live under .opencastle/worktrees/
84
+ if (path.startsWith(worktreesDir + sep)) {
85
+ results.push({ path, branch, head });
86
+ }
87
+ }
88
+ return results;
89
+ }
90
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../../src/cli/convoy/worktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,QAAQ,GAAG,SAAS,CAAC,UAAU,CAAC,CAAA;AAetC,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IACpD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IAEnE,KAAK,UAAU,MAAM,CAAC,QAAgB,EAAE,aAAqB;QAC3D,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,wEAAwE,CACtG,CAAA;QACH,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;QACjD,MAAM,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9C,MAAM,QAAQ,CACZ,KAAK,EACL,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,QAAQ,EAAE,EAAE,aAAa,CAAC,EAC5E,EAAE,GAAG,EAAE,YAAY,EAAE,CACtB,CAAA;QACD,OAAO,YAAY,CAAA;IACrB,CAAC;IAED,KAAK,UAAU,MAAM,CAAC,YAAoB;QACxC,IAAI,QAAgB,CAAA;QACpB,IAAI,CAAC;YACH,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAA;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;QAClC,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,YAAY,GAAG,GAAG,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,SAAS,YAAY,8CAA8C,CAAC,CAAA;QACtF,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;QACnC,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE;gBACjE,GAAG,EAAE,YAAY;aAClB,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAI,GAA2B,CAAC,MAAM,IAAI,EAAE,CAAA;YACxD,IAAI,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;gBAC7C,OAAM;YACR,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,QAAQ,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAA;QACtF,CAAC;QAAC,MAAM,CAAC;YACP,yCAAyC;QAC3C,CAAC;IACH,CAAC;IAGD,KAAK,UAAU,IAAI;QACjB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE;YAC5E,GAAG,EAAE,YAAY;SAClB,CAAC,CAAA;QACF,OAAO,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;IAChD,CAAC;IAED,KAAK,UAAU,SAAS;QACtB,MAAM,SAAS,GAAG,MAAM,IAAI,EAAE,CAAA;QAC9B,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAC5C,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAc,EAAE,YAAoB;IAC7D,MAAM,OAAO,GAAmB,EAAE,CAAA;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAE3D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC/B,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,IAAI,MAAM,GAAG,EAAE,CAAA;QAEf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBACjC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;YACvC,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YACnC,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACtC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;QAED,gEAAgE;QAChE,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,GAAG,GAAG,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worktree.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.test.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/worktree.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ import { mkdtempSync, rmSync, realpathSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { execFile as execFileCb } from 'node:child_process';
5
+ import { promisify } from 'node:util';
6
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
+ import { createWorktreeManager } from './worktree.js';
8
+ const execFile = promisify(execFileCb);
9
+ // ── helpers ───────────────────────────────────────────────────────────────────
10
+ let tmpDir;
11
+ let manager;
12
+ async function initGitRepo(dir) {
13
+ await execFile('git', ['init'], { cwd: dir });
14
+ await execFile('git', ['config', 'user.email', 'test@test.com'], { cwd: dir });
15
+ await execFile('git', ['config', 'user.name', 'Test User'], { cwd: dir });
16
+ await execFile('git', ['commit', '--allow-empty', '-m', 'Initial commit'], { cwd: dir });
17
+ }
18
+ beforeEach(async () => {
19
+ tmpDir = realpathSync(mkdtempSync(join(tmpdir(), 'convoy-worktree-test-')));
20
+ await initGitRepo(tmpDir);
21
+ manager = createWorktreeManager(tmpDir);
22
+ });
23
+ afterEach(() => {
24
+ rmSync(tmpDir, { recursive: true, force: true });
25
+ });
26
+ // ── create ────────────────────────────────────────────────────────────────────
27
+ describe('create', () => {
28
+ it('creates a worktree and returns its absolute path', async () => {
29
+ const worktreePath = await manager.create('worker1', 'HEAD');
30
+ expect(worktreePath).toBe(join(tmpDir, '.opencastle', 'worktrees', 'worker1'));
31
+ });
32
+ it('creates the .opencastle/worktrees directory when it does not exist', async () => {
33
+ const { existsSync } = await import('node:fs');
34
+ const worktreePath = await manager.create('worker1', 'HEAD');
35
+ expect(existsSync(worktreePath)).toBe(true);
36
+ });
37
+ it('creates the new branch in the worktree', async () => {
38
+ await manager.create('worker1', 'HEAD');
39
+ const { stdout } = await execFile('git', ['branch', '--list', 'convoy-worker1'], { cwd: tmpDir });
40
+ // git prefixes branches checked out in a worktree with '+ '
41
+ expect(stdout.trim().replace(/^[*+]\s+/, '')).toBe('convoy-worker1');
42
+ });
43
+ it('throws when featureBranch does not exist', async () => {
44
+ await expect(manager.create('worker1', 'nonexistent-branch')).rejects.toThrow();
45
+ });
46
+ it('throws when workerId is already in use', async () => {
47
+ await manager.create('worker1', 'HEAD');
48
+ await expect(manager.create('worker1', 'HEAD')).rejects.toThrow();
49
+ });
50
+ it('throws for workerId with path traversal characters', async () => {
51
+ await expect(manager.create('../escape', 'HEAD')).rejects.toThrow(/Invalid workerId/);
52
+ });
53
+ it('throws for workerId with slashes', async () => {
54
+ await expect(manager.create('a/b', 'HEAD')).rejects.toThrow(/Invalid workerId/);
55
+ });
56
+ });
57
+ // ── remove ────────────────────────────────────────────────────────────────────
58
+ describe('remove', () => {
59
+ it('removes the worktree so it no longer appears in list()', async () => {
60
+ const path = await manager.create('worker1', 'HEAD');
61
+ await manager.remove(path);
62
+ const worktrees = await manager.list();
63
+ expect(worktrees).toHaveLength(0);
64
+ });
65
+ it('deletes the convoy branch after removing the worktree', async () => {
66
+ const path = await manager.create('worker1', 'HEAD');
67
+ await manager.remove(path);
68
+ const { stdout } = await execFile('git', ['branch', '--list', 'convoy-worker1'], { cwd: tmpDir });
69
+ expect(stdout.trim()).toBe('');
70
+ });
71
+ it('is idempotent — does not throw for a non-existent worktree path', async () => {
72
+ const nonExistent = join(tmpDir, '.opencastle', 'worktrees', 'ghost');
73
+ await expect(manager.remove(nonExistent)).resolves.toBeUndefined();
74
+ });
75
+ it('re-throws git errors that are not "not a working tree"', async () => {
76
+ const path = await manager.create('worker1', 'HEAD');
77
+ // Lock the worktree so that single --force removal fails
78
+ await execFile('git', ['worktree', 'lock', path], { cwd: tmpDir });
79
+ await expect(manager.remove(path)).rejects.toThrow();
80
+ // Cleanup: unlock and remove manually
81
+ await execFile('git', ['worktree', 'unlock', path], { cwd: tmpDir });
82
+ });
83
+ it('throws when path is outside the managed worktrees directory', async () => {
84
+ await expect(manager.remove('/some/arbitrary/path')).rejects.toThrow(/outside the managed worktrees directory/);
85
+ });
86
+ });
87
+ // ── list ──────────────────────────────────────────────────────────────────────
88
+ describe('list', () => {
89
+ it('returns an empty array when no convoy worktrees exist', async () => {
90
+ const worktrees = await manager.list();
91
+ expect(worktrees).toHaveLength(0);
92
+ });
93
+ it('does not include the main worktree', async () => {
94
+ const worktrees = await manager.list();
95
+ for (const wt of worktrees) {
96
+ expect(wt.path).toContain('.opencastle/worktrees');
97
+ }
98
+ });
99
+ it('returns the correct WorktreeInfo for a created worktree', async () => {
100
+ await manager.create('worker1', 'HEAD');
101
+ const worktrees = await manager.list();
102
+ expect(worktrees).toHaveLength(1);
103
+ expect(worktrees[0].path).toBe(join(tmpDir, '.opencastle', 'worktrees', 'worker1'));
104
+ expect(worktrees[0].branch).toBe('refs/heads/convoy-worker1');
105
+ expect(worktrees[0].head).toMatch(/^[0-9a-f]{40}$/);
106
+ });
107
+ it('returns multiple worktrees when several have been created', async () => {
108
+ await manager.create('worker1', 'HEAD');
109
+ await manager.create('worker2', 'HEAD');
110
+ const worktrees = await manager.list();
111
+ expect(worktrees).toHaveLength(2);
112
+ const paths = worktrees.map(w => w.path);
113
+ expect(paths).toContain(join(tmpDir, '.opencastle', 'worktrees', 'worker1'));
114
+ expect(paths).toContain(join(tmpDir, '.opencastle', 'worktrees', 'worker2'));
115
+ });
116
+ it('handles detached HEAD worktrees by returning empty branch string', async () => {
117
+ // git worktree list --porcelain outputs 'detached' (not 'branch refs/...') for
118
+ // detached-HEAD worktrees — this exercises the else-if fallthrough in parseWorktreeList
119
+ const { existsSync, mkdirSync } = await import('node:fs');
120
+ const detachedPath = join(tmpDir, '.opencastle', 'worktrees', 'detached-test');
121
+ if (!existsSync(join(tmpDir, '.opencastle', 'worktrees'))) {
122
+ mkdirSync(join(tmpDir, '.opencastle', 'worktrees'), { recursive: true });
123
+ }
124
+ const { stdout: sha } = await execFile('git', ['rev-parse', 'HEAD'], { cwd: tmpDir });
125
+ await execFile('git', ['worktree', 'add', '--detach', detachedPath, sha.trim()], { cwd: tmpDir });
126
+ const worktrees = await manager.list();
127
+ const detached = worktrees.find(w => w.path === detachedPath);
128
+ expect(detached).toBeDefined();
129
+ expect(detached.branch).toBe('');
130
+ expect(detached.head).toMatch(/^[0-9a-f]{40}$/);
131
+ });
132
+ });
133
+ // ── removeAll ─────────────────────────────────────────────────────────────────
134
+ describe('removeAll', () => {
135
+ it('removes all convoy worktrees', async () => {
136
+ await manager.create('worker1', 'HEAD');
137
+ await manager.create('worker2', 'HEAD');
138
+ await manager.removeAll();
139
+ const worktrees = await manager.list();
140
+ expect(worktrees).toHaveLength(0);
141
+ });
142
+ it('is a no-op when no convoy worktrees exist', async () => {
143
+ await expect(manager.removeAll()).resolves.toBeUndefined();
144
+ });
145
+ });
146
+ //# sourceMappingURL=worktree.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.test.js","sourceRoot":"","sources":["../../../src/cli/convoy/worktree.test.ts"],"names":[],"mappings":"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"}
@@ -31,7 +31,7 @@ export async function execute(task, options = {}) {
31
31
  const proc = spawn('claude', args, {
32
32
  stdio: ['ignore', 'pipe', 'pipe'],
33
33
  env: { ...process.env },
34
- cwd: process.cwd(),
34
+ cwd: options?.cwd ?? process.cwd(),
35
35
  });
36
36
  let stdout = '';
37
37
  let stderr = '';
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../../src/cli/run/adapters/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAG1C,mBAAmB;AACnB,MAAM,CAAC,MAAM,IAAI,GAAG,aAAa,CAAA;AAEjC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC1D,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;QAC/C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAU,EAAE,UAA0B,EAAE;IACpE,IAAI,MAAM,GAAG,aAAa,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE,CAAA;IAEtD,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,gCAAgC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;IACnE,CAAC;IAED,MAAM,IAAI,GAAG;QACX,IAAI;QACJ,MAAM;QACN,iBAAiB;QACjB,MAAM;QACN,aAAa;QACb,IAAI;KACL,CAAA;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE;YACjC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;YACvB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SACnB,CAAC,CAAA;QAEF,IAAI,MAAM,GAAG,EAAE,CAAA;QACf,IAAI,MAAM,GAAG,EAAE,CAAA;QAEf,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAA;YAC1B,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAA;YAC1B,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1D,OAAO,CAAC;gBACN,OAAO,EAAE,IAAI,KAAK,CAAC;gBACnB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,kBAAkB;gBAClD,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC;aACrB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,OAAO,CAAC;gBACN,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,2BAA2B,GAAG,CAAC,OAAO,EAAE;gBAChD,QAAQ,EAAE,CAAC,CAAC;aACb,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,+CAA+C;QAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;IACtB,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,IAAI,CAAC,IAAU;IAC7B,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC7B,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAA;IACV,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../../src/cli/run/adapters/claude-code.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"copilot.d.ts","sourceRoot":"","sources":["../../../../src/cli/run/adapters/copilot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEzE,mBAAmB;AACnB,eAAO,MAAM,IAAI,YAAY,CAAA;AAe7B;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAMpD;AAsBD;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAmD9F;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAOrC"}
1
+ {"version":3,"file":"copilot.d.ts","sourceRoot":"","sources":["../../../../src/cli/run/adapters/copilot.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEzE,mBAAmB;AACnB,eAAO,MAAM,IAAI,YAAY,CAAA;AAe7B;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAMpD;AAsBD;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAwD9F;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAOrC"}
@@ -52,6 +52,11 @@ async function getClient() {
52
52
  * - Streaming enabled in verbose mode for live output
53
53
  */
54
54
  export async function execute(task, options = {}) {
55
+ // NOTE: The Copilot SDK CopilotClient is a shared singleton. Per-task cwd
56
+ // isolation requires SDK support for per-session workingDirectory, which is
57
+ // not yet available. When running in convoy mode with worktrees, prefer
58
+ // subprocess-based adapters (claude-code, cursor) that support options.cwd
59
+ // natively. Copilot SDK per-session cwd support is tracked for Phase 3.
55
60
  let prompt = `You are a ${task.agent}. ${task.prompt}`;
56
61
  if (task.files && task.files.length > 0) {
57
62
  prompt += `\n\nOnly modify files under: ${task.files.join(', ')}`;
@@ -1 +1 @@
1
- {"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../../../src/cli/run/adapters/copilot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../../../src/cli/run/adapters/copilot.ts"],"names":[],"mappings":"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"}
@@ -30,7 +30,7 @@ export async function execute(task, options = {}) {
30
30
  const proc = spawn('agent', args, {
31
31
  stdio: ['ignore', 'pipe', 'pipe'],
32
32
  env: { ...process.env },
33
- cwd: process.cwd(),
33
+ cwd: options?.cwd ?? process.cwd(),
34
34
  });
35
35
  let stdout = '';
36
36
  let stderr = '';