symphony-github 0.1.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.
- package/LICENSE +201 -0
- package/README.md +341 -0
- package/config.example.yaml +101 -0
- package/dist/agents/launcher.d.ts +24 -0
- package/dist/agents/launcher.d.ts.map +1 -0
- package/dist/agents/launcher.js +152 -0
- package/dist/agents/launcher.js.map +1 -0
- package/dist/agents/registry.d.ts +10 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +324 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/runner.d.ts +58 -0
- package/dist/agents/runner.d.ts.map +1 -0
- package/dist/agents/runner.js +1190 -0
- package/dist/agents/runner.js.map +1 -0
- package/dist/app.d.ts +11 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +829 -0
- package/dist/app.js.map +1 -0
- package/dist/components/ActivityView.d.ts +9 -0
- package/dist/components/ActivityView.d.ts.map +1 -0
- package/dist/components/ActivityView.js +73 -0
- package/dist/components/ActivityView.js.map +1 -0
- package/dist/components/Header.d.ts +12 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +44 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/IssueList.d.ts +10 -0
- package/dist/components/IssueList.d.ts.map +1 -0
- package/dist/components/IssueList.js +119 -0
- package/dist/components/IssueList.js.map +1 -0
- package/dist/components/Onboarding.d.ts +26 -0
- package/dist/components/Onboarding.d.ts.map +1 -0
- package/dist/components/Onboarding.js +948 -0
- package/dist/components/Onboarding.js.map +1 -0
- package/dist/components/PaneView.d.ts +9 -0
- package/dist/components/PaneView.d.ts.map +1 -0
- package/dist/components/PaneView.js +74 -0
- package/dist/components/PaneView.js.map +1 -0
- package/dist/components/StartupRecoveryView.d.ts +13 -0
- package/dist/components/StartupRecoveryView.d.ts.map +1 -0
- package/dist/components/StartupRecoveryView.js +85 -0
- package/dist/components/StartupRecoveryView.js.map +1 -0
- package/dist/components/StatusBar.d.ts +9 -0
- package/dist/components/StatusBar.d.ts.map +1 -0
- package/dist/components/StatusBar.js +70 -0
- package/dist/components/StatusBar.js.map +1 -0
- package/dist/components/TableView.d.ts +8 -0
- package/dist/components/TableView.d.ts.map +1 -0
- package/dist/components/TableView.js +87 -0
- package/dist/components/TableView.js.map +1 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +357 -0
- package/dist/config/index.js.map +1 -0
- package/dist/git/merge.d.ts +23 -0
- package/dist/git/merge.d.ts.map +1 -0
- package/dist/git/merge.js +131 -0
- package/dist/git/merge.js.map +1 -0
- package/dist/git/utils.d.ts +34 -0
- package/dist/git/utils.d.ts.map +1 -0
- package/dist/git/utils.js +214 -0
- package/dist/git/utils.js.map +1 -0
- package/dist/git/worktree.d.ts +23 -0
- package/dist/git/worktree.d.ts.map +1 -0
- package/dist/git/worktree.js +116 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +225 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +21 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +59 -0
- package/dist/paths.js.map +1 -0
- package/dist/runModes.d.ts +7 -0
- package/dist/runModes.d.ts.map +1 -0
- package/dist/runModes.js +36 -0
- package/dist/runModes.js.map +1 -0
- package/dist/services/daemon.d.ts +85 -0
- package/dist/services/daemon.d.ts.map +1 -0
- package/dist/services/daemon.js +836 -0
- package/dist/services/daemon.js.map +1 -0
- package/dist/services/github.d.ts +101 -0
- package/dist/services/github.d.ts.map +1 -0
- package/dist/services/github.js +367 -0
- package/dist/services/github.js.map +1 -0
- package/dist/services/githubProgressReporter.d.ts +33 -0
- package/dist/services/githubProgressReporter.d.ts.map +1 -0
- package/dist/services/githubProgressReporter.js +272 -0
- package/dist/services/githubProgressReporter.js.map +1 -0
- package/dist/services/runtime.d.ts +43 -0
- package/dist/services/runtime.d.ts.map +1 -0
- package/dist/services/runtime.js +126 -0
- package/dist/services/runtime.js.map +1 -0
- package/dist/services/state.d.ts +43 -0
- package/dist/services/state.d.ts.map +1 -0
- package/dist/services/state.js +176 -0
- package/dist/services/state.js.map +1 -0
- package/dist/services/tmux.d.ts +50 -0
- package/dist/services/tmux.d.ts.map +1 -0
- package/dist/services/tmux.js +157 -0
- package/dist/services/tmux.js.map +1 -0
- package/dist/swarm/backlog.d.ts +25 -0
- package/dist/swarm/backlog.d.ts.map +1 -0
- package/dist/swarm/backlog.js +83 -0
- package/dist/swarm/backlog.js.map +1 -0
- package/dist/swarm/config.d.ts +14 -0
- package/dist/swarm/config.d.ts.map +1 -0
- package/dist/swarm/config.js +112 -0
- package/dist/swarm/config.js.map +1 -0
- package/dist/swarm/dependencies.d.ts +36 -0
- package/dist/swarm/dependencies.d.ts.map +1 -0
- package/dist/swarm/dependencies.js +141 -0
- package/dist/swarm/dependencies.js.map +1 -0
- package/dist/swarm/director.d.ts +67 -0
- package/dist/swarm/director.d.ts.map +1 -0
- package/dist/swarm/director.js +358 -0
- package/dist/swarm/director.js.map +1 -0
- package/dist/swarm/directorPrompt.d.ts +15 -0
- package/dist/swarm/directorPrompt.d.ts.map +1 -0
- package/dist/swarm/directorPrompt.js +60 -0
- package/dist/swarm/directorPrompt.js.map +1 -0
- package/dist/swarm/index.d.ts +7 -0
- package/dist/swarm/index.d.ts.map +1 -0
- package/dist/swarm/index.js +6 -0
- package/dist/swarm/index.js.map +1 -0
- package/dist/swarm/proposals.d.ts +29 -0
- package/dist/swarm/proposals.d.ts.map +1 -0
- package/dist/swarm/proposals.js +141 -0
- package/dist/swarm/proposals.js.map +1 -0
- package/dist/swarm/types.d.ts +65 -0
- package/dist/swarm/types.d.ts.map +1 -0
- package/dist/swarm/types.js +3 -0
- package/dist/swarm/types.js.map +1 -0
- package/dist/theme.d.ts +64 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +161 -0
- package/dist/theme.js.map +1 -0
- package/dist/triggers/index.d.ts +17 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +124 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/types.d.ts +327 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/duplicateDetection.d.ts +14 -0
- package/dist/utils/duplicateDetection.d.ts.map +1 -0
- package/dist/utils/duplicateDetection.js +45 -0
- package/dist/utils/duplicateDetection.js.map +1 -0
- package/dist/utils/shell.d.ts +46 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +79 -0
- package/dist/utils/shell.js.map +1 -0
- package/dist/utils/slug.d.ts +13 -0
- package/dist/utils/slug.d.ts.map +1 -0
- package/dist/utils/slug.js +32 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/version.d.ts +28 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +105 -0
- package/dist/version.js.map +1 -0
- package/examples/run-claude.example.sh +11 -0
- package/examples/run-codex.example.sh +11 -0
- package/package.json +68 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { run, runSafe } from '../utils/shell.js';
|
|
2
|
+
const GIT_NETWORK_TIMEOUT_MS = 60_000;
|
|
3
|
+
export async function getMainBranch(cwd) {
|
|
4
|
+
// Try symbolic-ref first
|
|
5
|
+
const result = await runSafe('git', [
|
|
6
|
+
'symbolic-ref', 'refs/remotes/origin/HEAD',
|
|
7
|
+
], { cwd });
|
|
8
|
+
if (result.exitCode === 0 && result.stdout) {
|
|
9
|
+
return result.stdout.replace('refs/remotes/origin/', '');
|
|
10
|
+
}
|
|
11
|
+
// Fall back to checking common names
|
|
12
|
+
for (const name of ['main', 'master']) {
|
|
13
|
+
const check = await runSafe('git', ['rev-parse', '--verify', `refs/heads/${name}`], { cwd });
|
|
14
|
+
if (check.exitCode === 0)
|
|
15
|
+
return name;
|
|
16
|
+
}
|
|
17
|
+
return 'main';
|
|
18
|
+
}
|
|
19
|
+
export async function getCurrentBranch(cwd) {
|
|
20
|
+
return run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd });
|
|
21
|
+
}
|
|
22
|
+
export async function branchExists(branch, cwd) {
|
|
23
|
+
const result = await runSafe('git', ['rev-parse', '--verify', `refs/heads/${branch}`], { cwd });
|
|
24
|
+
return result.exitCode === 0;
|
|
25
|
+
}
|
|
26
|
+
export async function hasUncommittedChanges(cwd) {
|
|
27
|
+
const result = await runSafe('git', ['status', '--porcelain'], { cwd });
|
|
28
|
+
return result.stdout
|
|
29
|
+
.split('\n')
|
|
30
|
+
.map(line => line.trim())
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.some(line => !isIgnoredSymphonyStatusLine(line));
|
|
33
|
+
}
|
|
34
|
+
export async function getConflictedFiles(cwd) {
|
|
35
|
+
const result = await runSafe('git', ['diff', '--name-only', '--diff-filter=U'], { cwd });
|
|
36
|
+
if (result.exitCode !== 0 || !result.stdout)
|
|
37
|
+
return [];
|
|
38
|
+
return result.stdout.split('\n').filter(Boolean);
|
|
39
|
+
}
|
|
40
|
+
function isIgnoredPath(path) {
|
|
41
|
+
return path === '.symphony' || path.startsWith('.symphony/');
|
|
42
|
+
}
|
|
43
|
+
function isIgnoredSymphonyStatusLine(line) {
|
|
44
|
+
const pathPortion = line.slice(3).trim();
|
|
45
|
+
if (!pathPortion)
|
|
46
|
+
return false;
|
|
47
|
+
const normalizedPath = pathPortion.includes(' -> ')
|
|
48
|
+
? pathPortion.split(' -> ').at(-1) || pathPortion
|
|
49
|
+
: pathPortion;
|
|
50
|
+
return isIgnoredPath(normalizedPath);
|
|
51
|
+
}
|
|
52
|
+
export async function getHeadSha(cwd) {
|
|
53
|
+
return run('git', ['rev-parse', 'HEAD'], { cwd });
|
|
54
|
+
}
|
|
55
|
+
export async function getCommitCount(from, to, cwd) {
|
|
56
|
+
const result = await runSafe('git', [
|
|
57
|
+
'rev-list', '--count', `${from}..${to}`,
|
|
58
|
+
], { cwd });
|
|
59
|
+
return parseInt(result.stdout, 10) || 0;
|
|
60
|
+
}
|
|
61
|
+
export async function hasDiffBetweenRefs(from, to, cwd) {
|
|
62
|
+
return hasCommittedChanges(from, to, cwd);
|
|
63
|
+
}
|
|
64
|
+
export async function getChangedFiles(from, to, cwd) {
|
|
65
|
+
const result = await runSafe('git', ['diff', '--name-only', from, to], { cwd });
|
|
66
|
+
if (result.exitCode !== 0 || !result.stdout)
|
|
67
|
+
return [];
|
|
68
|
+
return Array.from(new Set(result.stdout
|
|
69
|
+
.split('\n')
|
|
70
|
+
.map(line => line.trim())
|
|
71
|
+
.filter(Boolean)
|
|
72
|
+
.filter(path => !isIgnoredPath(path))));
|
|
73
|
+
}
|
|
74
|
+
export async function hasCommittedChanges(from, to, cwd) {
|
|
75
|
+
const files = await getChangedFiles(from, to, cwd);
|
|
76
|
+
return files.length > 0;
|
|
77
|
+
}
|
|
78
|
+
export async function getGitRoot(cwd) {
|
|
79
|
+
return run('git', ['rev-parse', '--show-toplevel'], { cwd });
|
|
80
|
+
}
|
|
81
|
+
export async function isGitWorktree(path) {
|
|
82
|
+
const fs = await import('node:fs');
|
|
83
|
+
const gitPath = `${path}/.git`;
|
|
84
|
+
try {
|
|
85
|
+
const stat = fs.statSync(gitPath);
|
|
86
|
+
return stat.isFile(); // .git is a file in worktrees, directory in main repos
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export async function fetchOrigin(cwd) {
|
|
93
|
+
const result = await runSafe('git', ['fetch', 'origin', '--prune'], {
|
|
94
|
+
cwd,
|
|
95
|
+
timeout: GIT_NETWORK_TIMEOUT_MS,
|
|
96
|
+
});
|
|
97
|
+
if (result.exitCode === 0) {
|
|
98
|
+
return { ok: true };
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
detail: result.stderr || result.stdout || 'git fetch origin failed',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export async function resolveBranchRef(cwd, branch) {
|
|
106
|
+
const candidates = [
|
|
107
|
+
`refs/remotes/origin/${branch}`,
|
|
108
|
+
`refs/heads/${branch}`,
|
|
109
|
+
`origin/${branch}`,
|
|
110
|
+
branch,
|
|
111
|
+
];
|
|
112
|
+
for (const candidate of candidates) {
|
|
113
|
+
const result = await runSafe('git', ['rev-parse', '--verify', `${candidate}^{commit}`], { cwd });
|
|
114
|
+
if (result.exitCode === 0) {
|
|
115
|
+
return candidate;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
export async function fetchBranchRef(cwd, remote, branch) {
|
|
121
|
+
const remoteRef = `refs/remotes/${remote}/${branch}`;
|
|
122
|
+
const explicitFetch = await runSafe('git', [
|
|
123
|
+
'fetch',
|
|
124
|
+
remote,
|
|
125
|
+
'--prune',
|
|
126
|
+
`refs/heads/${branch}:${remoteRef}`,
|
|
127
|
+
], {
|
|
128
|
+
cwd,
|
|
129
|
+
timeout: GIT_NETWORK_TIMEOUT_MS,
|
|
130
|
+
});
|
|
131
|
+
if (explicitFetch.exitCode === 0) {
|
|
132
|
+
return { ref: remoteRef };
|
|
133
|
+
}
|
|
134
|
+
const fallbackFetch = await runSafe('git', ['fetch', remote, '--prune', branch], {
|
|
135
|
+
cwd,
|
|
136
|
+
timeout: GIT_NETWORK_TIMEOUT_MS,
|
|
137
|
+
});
|
|
138
|
+
if (fallbackFetch.exitCode === 0) {
|
|
139
|
+
const fetchHead = await runSafe('git', ['rev-parse', '--verify', 'FETCH_HEAD^{commit}'], { cwd });
|
|
140
|
+
if (fetchHead.exitCode === 0) {
|
|
141
|
+
return { ref: 'FETCH_HEAD' };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const existingRef = await resolveBranchRef(cwd, branch);
|
|
145
|
+
if (existingRef) {
|
|
146
|
+
return {
|
|
147
|
+
ref: existingRef,
|
|
148
|
+
detail: explicitFetch.stderr || fallbackFetch.stderr || `Falling back to local ${branch} reference`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
detail: explicitFetch.stderr || fallbackFetch.stderr || `Unable to resolve ${remote}/${branch}`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
export async function findUnresolvedMergeMarkers(cwd) {
|
|
156
|
+
const script = [
|
|
157
|
+
'if command -v rg >/dev/null 2>&1; then',
|
|
158
|
+
" rg -n --hidden --no-messages --glob '!.git' --glob '!.symphony/**' --glob '!node_modules/**' --glob '!dist/**' --glob '!coverage/**' '^(<<<<<<< |=======|>>>>>>> )' .",
|
|
159
|
+
'else',
|
|
160
|
+
" grep -RInE '^(<<<<<<< |=======|>>>>>>> )' --exclude-dir=.git --exclude-dir=.symphony --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=coverage .",
|
|
161
|
+
'fi',
|
|
162
|
+
].join(' ');
|
|
163
|
+
const result = await runSafe('sh', ['-lc', script], { cwd });
|
|
164
|
+
if (result.exitCode !== 0 && !result.stdout) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
return result.stdout
|
|
168
|
+
.split('\n')
|
|
169
|
+
.map(line => line.trim())
|
|
170
|
+
.filter(Boolean);
|
|
171
|
+
}
|
|
172
|
+
export async function pushBranch(branch, cwd) {
|
|
173
|
+
const result = await runSafe('git', ['push', '--set-upstream', 'origin', branch], {
|
|
174
|
+
cwd,
|
|
175
|
+
timeout: GIT_NETWORK_TIMEOUT_MS,
|
|
176
|
+
});
|
|
177
|
+
if (result.exitCode === 0) {
|
|
178
|
+
return { ok: true };
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
detail: result.stderr || result.stdout || `git push origin ${branch} failed`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
export async function stageAll(cwd) {
|
|
186
|
+
await run('git', ['add', '-A'], { cwd });
|
|
187
|
+
}
|
|
188
|
+
export async function commit(message, cwd) {
|
|
189
|
+
await run('git', ['commit', '-m', message], { cwd });
|
|
190
|
+
}
|
|
191
|
+
export async function getDiffStats(baseSha, cwd) {
|
|
192
|
+
let added = 0;
|
|
193
|
+
let removed = 0;
|
|
194
|
+
// Committed changes since base
|
|
195
|
+
const committed = await runSafe('git', ['diff', '--numstat', baseSha, 'HEAD'], { cwd });
|
|
196
|
+
// Uncommitted changes (staged + unstaged)
|
|
197
|
+
const uncommitted = await runSafe('git', ['diff', '--numstat', 'HEAD'], { cwd });
|
|
198
|
+
for (const result of [committed, uncommitted]) {
|
|
199
|
+
if (result.exitCode !== 0)
|
|
200
|
+
continue;
|
|
201
|
+
for (const line of result.stdout.split('\n').filter(Boolean)) {
|
|
202
|
+
const [a, r] = line.split('\t');
|
|
203
|
+
if (a !== '-')
|
|
204
|
+
added += parseInt(a, 10) || 0;
|
|
205
|
+
if (r !== '-')
|
|
206
|
+
removed += parseInt(r, 10) || 0;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { added, removed };
|
|
210
|
+
}
|
|
211
|
+
export function isValidBranchName(name) {
|
|
212
|
+
return /^[a-zA-Z0-9._\/-]*$/.test(name) && !name.includes('..');
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/git/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PreparedWorktree } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Ensure a bare clone exists for the given repo.
|
|
4
|
+
* Returns the path to the clone.
|
|
5
|
+
*/
|
|
6
|
+
export declare function ensureClone(repo: string, cloneRoot: string): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Create a git worktree for an issue.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createWorktree(repo: string, issueNumber: number, issueTitle: string, cloneRoot: string, worktreeRoot: string, branchPrefix?: string): Promise<PreparedWorktree>;
|
|
11
|
+
/**
|
|
12
|
+
* Remove a worktree and optionally delete its branch.
|
|
13
|
+
*/
|
|
14
|
+
export declare function removeWorktree(worktreePath: string, clonePath: string, deleteBranch?: boolean, branchName?: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* List all worktrees for a clone.
|
|
17
|
+
*/
|
|
18
|
+
export declare function listWorktrees(clonePath: string): Promise<Array<{
|
|
19
|
+
path: string;
|
|
20
|
+
branch: string;
|
|
21
|
+
head: string;
|
|
22
|
+
}>>;
|
|
23
|
+
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/git/worktree.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,CAAC,CAiD3B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,YAAY,UAAQ,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC,CAuBF"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { run, runSafe } from '../utils/shell.js';
|
|
4
|
+
import { issueBranchName } from '../utils/slug.js';
|
|
5
|
+
import { branchExists, getMainBranch, hasUncommittedChanges } from './utils.js';
|
|
6
|
+
/**
|
|
7
|
+
* Ensure a bare clone exists for the given repo.
|
|
8
|
+
* Returns the path to the clone.
|
|
9
|
+
*/
|
|
10
|
+
export async function ensureClone(repo, cloneRoot) {
|
|
11
|
+
const clonePath = resolve(cloneRoot, repo.replace('/', '__'));
|
|
12
|
+
if (!existsSync(clonePath)) {
|
|
13
|
+
mkdirSync(clonePath, { recursive: true });
|
|
14
|
+
await run('git', ['clone', '--bare', `https://github.com/${repo}.git`, clonePath]);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
// Fetch latest
|
|
18
|
+
await runSafe('git', ['fetch', 'origin', '--prune'], { cwd: clonePath });
|
|
19
|
+
}
|
|
20
|
+
return clonePath;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a git worktree for an issue.
|
|
24
|
+
*/
|
|
25
|
+
export async function createWorktree(repo, issueNumber, issueTitle, cloneRoot, worktreeRoot, branchPrefix) {
|
|
26
|
+
const clonePath = await ensureClone(repo, cloneRoot);
|
|
27
|
+
const branch = issueBranchName(issueNumber, issueTitle, branchPrefix);
|
|
28
|
+
const worktreePath = resolve(worktreeRoot, repo.replace('/', '__'), branch);
|
|
29
|
+
if (existsSync(worktreePath)) {
|
|
30
|
+
const hasMergeInProgress = await runSafe('git', ['rev-parse', '-q', '--verify', 'MERGE_HEAD'], {
|
|
31
|
+
cwd: worktreePath,
|
|
32
|
+
});
|
|
33
|
+
const hasLocalChanges = await hasUncommittedChanges(worktreePath).catch(() => true);
|
|
34
|
+
if (hasMergeInProgress.exitCode !== 0 && !hasLocalChanges) {
|
|
35
|
+
return { path: worktreePath, branch, clone_path: clonePath };
|
|
36
|
+
}
|
|
37
|
+
await removeWorktree(worktreePath, clonePath, false).catch(() => { });
|
|
38
|
+
rmSync(worktreePath, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
mkdirSync(resolve(worktreePath, '..'), { recursive: true });
|
|
41
|
+
// Prune stale worktrees
|
|
42
|
+
await runSafe('git', ['worktree', 'prune'], { cwd: clonePath });
|
|
43
|
+
// Determine start point
|
|
44
|
+
const main = await getMainBranch(clonePath);
|
|
45
|
+
const remoteStartRef = `refs/remotes/origin/${main}`;
|
|
46
|
+
const localStartRef = `refs/heads/${main}`;
|
|
47
|
+
const remoteExists = await runSafe('git', ['rev-parse', '--verify', remoteStartRef], { cwd: clonePath });
|
|
48
|
+
const startRef = remoteExists.exitCode === 0 ? remoteStartRef : localStartRef;
|
|
49
|
+
// Check if branch already exists
|
|
50
|
+
const exists = await branchExists(branch, clonePath);
|
|
51
|
+
const remoteBranchRef = `refs/remotes/origin/${branch}`;
|
|
52
|
+
const remoteBranch = await runSafe('git', ['rev-parse', '--verify', remoteBranchRef], { cwd: clonePath });
|
|
53
|
+
if (exists) {
|
|
54
|
+
await run('git', ['worktree', 'add', worktreePath, branch], { cwd: clonePath });
|
|
55
|
+
}
|
|
56
|
+
else if (remoteBranch.exitCode === 0) {
|
|
57
|
+
await run('git', [
|
|
58
|
+
'worktree', 'add', '-b', branch, worktreePath, remoteBranchRef,
|
|
59
|
+
], { cwd: clonePath });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
await run('git', [
|
|
63
|
+
'worktree', 'add', '-b', branch, worktreePath, startRef,
|
|
64
|
+
], { cwd: clonePath });
|
|
65
|
+
}
|
|
66
|
+
return { path: worktreePath, branch, clone_path: clonePath };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Remove a worktree and optionally delete its branch.
|
|
70
|
+
*/
|
|
71
|
+
export async function removeWorktree(worktreePath, clonePath, deleteBranch = false, branchName) {
|
|
72
|
+
// Safety: only remove if path is within expected roots
|
|
73
|
+
let branchToDelete = branchName;
|
|
74
|
+
if (deleteBranch && !branchToDelete) {
|
|
75
|
+
const currentBranch = await runSafe('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: worktreePath });
|
|
76
|
+
if (currentBranch.exitCode === 0) {
|
|
77
|
+
branchToDelete = currentBranch.stdout.trim();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
await runSafe('git', ['worktree', 'remove', '--force', worktreePath], { cwd: clonePath });
|
|
81
|
+
if (deleteBranch && branchToDelete) {
|
|
82
|
+
await runSafe('git', ['branch', '-D', branchToDelete], { cwd: clonePath });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* List all worktrees for a clone.
|
|
87
|
+
*/
|
|
88
|
+
export async function listWorktrees(clonePath) {
|
|
89
|
+
const result = await runSafe('git', ['worktree', 'list', '--porcelain'], { cwd: clonePath });
|
|
90
|
+
if (result.exitCode !== 0)
|
|
91
|
+
return [];
|
|
92
|
+
const worktrees = [];
|
|
93
|
+
let current = {};
|
|
94
|
+
for (const line of result.stdout.split('\n')) {
|
|
95
|
+
if (line.startsWith('worktree ')) {
|
|
96
|
+
if (current.path)
|
|
97
|
+
worktrees.push(current);
|
|
98
|
+
current = { path: line.slice(9), branch: '', head: '' };
|
|
99
|
+
}
|
|
100
|
+
else if (line.startsWith('HEAD ')) {
|
|
101
|
+
current.head = line.slice(5);
|
|
102
|
+
}
|
|
103
|
+
else if (line.startsWith('branch ')) {
|
|
104
|
+
current.branch = line.slice(7).replace('refs/heads/', '');
|
|
105
|
+
}
|
|
106
|
+
else if (line === '') {
|
|
107
|
+
if (current.path)
|
|
108
|
+
worktrees.push(current);
|
|
109
|
+
current = {};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (current.path)
|
|
113
|
+
worktrees.push(current);
|
|
114
|
+
return worktrees.filter(w => w.branch); // Exclude bare repo entry
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=worktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/git/worktree.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { render } from 'ink';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
import { App } from './app.js';
|
|
8
|
+
import { loadConfigDocument, loadSettings, writeConfigAndLoad, generateSessionName, } from './config/index.js';
|
|
9
|
+
import { Onboarding } from './components/Onboarding.js';
|
|
10
|
+
import { TmuxService } from './services/tmux.js';
|
|
11
|
+
import { ensureSymphonyHome } from './paths.js';
|
|
12
|
+
import { recordCurrentVersion, checkForUpdate, getInstalledVersion } from './version.js';
|
|
13
|
+
function isInteractiveTerminal() {
|
|
14
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
15
|
+
}
|
|
16
|
+
function announceDetachedSession(sessionName) {
|
|
17
|
+
console.log(`Symphony session ready: ${sessionName}`);
|
|
18
|
+
console.log(`Attach with: tmux attach-session -t ${sessionName}`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Attach or switch to a tmux session depending on context.
|
|
22
|
+
*/
|
|
23
|
+
function goToSession(sessionName) {
|
|
24
|
+
if (process.env.TMUX) {
|
|
25
|
+
execSync(`tmux switch-client -t ${sessionName}`, { stdio: 'inherit' });
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
execSync(`tmux attach-session -t ${sessionName}`, { stdio: 'inherit' });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Detect whether the current pane belongs to our symphony session.
|
|
33
|
+
*/
|
|
34
|
+
function isInsideOurSession(sessionName) {
|
|
35
|
+
if (!process.env.TMUX)
|
|
36
|
+
return false;
|
|
37
|
+
try {
|
|
38
|
+
const current = execSync('tmux display-message -p "#{session_name}"', { encoding: 'utf-8' }).trim();
|
|
39
|
+
return current === sessionName;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create the tmux session and launch the TUI inside its control pane.
|
|
47
|
+
*/
|
|
48
|
+
async function createAndEnterSession(settings, configPath, options) {
|
|
49
|
+
const projectRoot = process.cwd();
|
|
50
|
+
const sessionName = generateSessionName(projectRoot);
|
|
51
|
+
const tmux = TmuxService.getInstance();
|
|
52
|
+
const shouldAttach = options?.attach ?? true;
|
|
53
|
+
// If session already exists, just go to it
|
|
54
|
+
if (await tmux.sessionExists(sessionName)) {
|
|
55
|
+
if (shouldAttach) {
|
|
56
|
+
goToSession(sessionName);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
announceDetachedSession(sessionName);
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
console.log(`Creating Symphony session: ${sessionName}`);
|
|
64
|
+
const controlPaneId = await tmux.createSession(sessionName, projectRoot);
|
|
65
|
+
await tmux.setGlobalOption('mouse', 'on');
|
|
66
|
+
await tmux.setWindowOption('pane-border-status', 'top');
|
|
67
|
+
await tmux.setWindowOption('pane-border-format', ' #{pane_title} ');
|
|
68
|
+
await tmux.setPaneTitle(controlPaneId, 'Symphony');
|
|
69
|
+
// Re-launch inside the control pane
|
|
70
|
+
const symphonyCmd = `node ${resolve(process.argv[1])} --config "${resolve(configPath)}"`;
|
|
71
|
+
await tmux.sendShellCommand(controlPaneId, symphonyCmd);
|
|
72
|
+
if (shouldAttach) {
|
|
73
|
+
goToSession(sessionName);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
announceDetachedSession(sessionName);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function runOnboarding(options) {
|
|
80
|
+
let onboardingResult = null;
|
|
81
|
+
const { waitUntilExit } = render(React.createElement(Onboarding, {
|
|
82
|
+
configPath: options.configPath,
|
|
83
|
+
flow: options.flow,
|
|
84
|
+
initialSettings: options.initialSettings,
|
|
85
|
+
baseConfig: options.baseConfig,
|
|
86
|
+
onComplete: (result) => {
|
|
87
|
+
onboardingResult = result;
|
|
88
|
+
},
|
|
89
|
+
onExit: () => {
|
|
90
|
+
process.exit(0);
|
|
91
|
+
},
|
|
92
|
+
}));
|
|
93
|
+
await waitUntilExit();
|
|
94
|
+
return onboardingResult;
|
|
95
|
+
}
|
|
96
|
+
async function main() {
|
|
97
|
+
// Ensure ~/.symphony/ exists and record version
|
|
98
|
+
ensureSymphonyHome();
|
|
99
|
+
recordCurrentVersion();
|
|
100
|
+
const args = process.argv.slice(2);
|
|
101
|
+
const command = args[0] === 'configure' ? 'configure' : 'start';
|
|
102
|
+
const parsedArgs = command === 'configure' ? args.slice(1) : args;
|
|
103
|
+
let configPath = 'config.yaml';
|
|
104
|
+
let noAttach = false;
|
|
105
|
+
for (let i = 0; i < parsedArgs.length; i++) {
|
|
106
|
+
if (parsedArgs[i] === '--config' || parsedArgs[i] === '-c') {
|
|
107
|
+
configPath = parsedArgs[i + 1] || configPath;
|
|
108
|
+
i++;
|
|
109
|
+
}
|
|
110
|
+
if (parsedArgs[i] === '--no-attach') {
|
|
111
|
+
noAttach = true;
|
|
112
|
+
}
|
|
113
|
+
if (parsedArgs[i] === '--help' || parsedArgs[i] === '-h') {
|
|
114
|
+
console.log(`
|
|
115
|
+
Symphony v${getInstalledVersion()} - AI Agent Orchestrator for GitHub Issues
|
|
116
|
+
|
|
117
|
+
Usage: symphony [options]
|
|
118
|
+
symphony configure [options]
|
|
119
|
+
|
|
120
|
+
Options:
|
|
121
|
+
-c, --config <path> Path to config.yaml (default: config.yaml)
|
|
122
|
+
--no-attach Start or reuse the tmux session without attaching to it
|
|
123
|
+
-h, --help Show this help message
|
|
124
|
+
|
|
125
|
+
Paths:
|
|
126
|
+
~/.symphony/ Global config, state & data directory
|
|
127
|
+
~/.symphony/config.yaml Global defaults (merged under project config)
|
|
128
|
+
~/.symphony/version.json Version & update tracking
|
|
129
|
+
~/.symphony/worktrees/ Git worktrees (<owner>__<repo>/<branch>)
|
|
130
|
+
~/.symphony/repos/ Bare clones of monitored repositories
|
|
131
|
+
~/.symphony/runs/ Run manifests & logs
|
|
132
|
+
~/.symphony/cache/ Cached data
|
|
133
|
+
|
|
134
|
+
Environment:
|
|
135
|
+
SYMPHONY_HOME Override the global config directory (default: ~/.symphony)
|
|
136
|
+
|
|
137
|
+
Symphony listens to GitHub issues on configured repositories,
|
|
138
|
+
triggers AI agents (Claude, Codex, etc.) to work on them in
|
|
139
|
+
isolated git worktrees, and manages the results.
|
|
140
|
+
`);
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const shouldAttach = !noAttach && isInteractiveTerminal();
|
|
145
|
+
const fullConfigPath = resolve(configPath);
|
|
146
|
+
// ── No config → Ink onboarding ──
|
|
147
|
+
if (!existsSync(fullConfigPath)) {
|
|
148
|
+
if (!isInteractiveTerminal()) {
|
|
149
|
+
console.error(`Config not found at ${fullConfigPath}, and onboarding requires an interactive terminal.`);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
const onboardingResult = await runOnboarding({ configPath: fullConfigPath });
|
|
153
|
+
if (!onboardingResult) {
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
// Write config after Ink has fully exited
|
|
157
|
+
const result = onboardingResult;
|
|
158
|
+
const settings = writeConfigAndLoad(fullConfigPath, result.yaml);
|
|
159
|
+
if (result.action === 'start') {
|
|
160
|
+
await createAndEnterSession(settings, fullConfigPath, { attach: shouldAttach });
|
|
161
|
+
}
|
|
162
|
+
// action === 'exit' → just fall through and exit
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// ── Config exists → load it ──
|
|
166
|
+
let settings;
|
|
167
|
+
let baseConfig;
|
|
168
|
+
try {
|
|
169
|
+
baseConfig = loadConfigDocument(fullConfigPath);
|
|
170
|
+
settings = loadSettings(fullConfigPath);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
console.error(`Failed to load config: ${err}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
// Background update check (non-blocking)
|
|
177
|
+
try {
|
|
178
|
+
const newerVersion = checkForUpdate();
|
|
179
|
+
if (newerVersion) {
|
|
180
|
+
console.log(`\x1b[33mUpdate available: ${getInstalledVersion()} → ${newerVersion}\x1b[0m` +
|
|
181
|
+
` Run \x1b[36mnpm i -g symphony-github\x1b[0m to update.`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// Silently ignore update check failures
|
|
186
|
+
}
|
|
187
|
+
if (command === 'configure') {
|
|
188
|
+
if (!isInteractiveTerminal()) {
|
|
189
|
+
console.error('Reconfiguration requires an interactive terminal.');
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
const onboardingResult = await runOnboarding({
|
|
193
|
+
configPath: fullConfigPath,
|
|
194
|
+
initialSettings: settings,
|
|
195
|
+
baseConfig,
|
|
196
|
+
});
|
|
197
|
+
if (!onboardingResult) {
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
const updatedSettings = writeConfigAndLoad(fullConfigPath, onboardingResult.yaml);
|
|
201
|
+
if (onboardingResult.action === 'start') {
|
|
202
|
+
await createAndEnterSession(updatedSettings, fullConfigPath, { attach: shouldAttach });
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const projectRoot = process.cwd();
|
|
207
|
+
const sessionName = generateSessionName(projectRoot);
|
|
208
|
+
// ── Inside our session → render TUI directly ──
|
|
209
|
+
if (isInsideOurSession(sessionName)) {
|
|
210
|
+
const controlPaneId = execSync('tmux display-message -p "#{pane_id}"', { encoding: 'utf-8' }).trim();
|
|
211
|
+
const { waitUntilExit } = render(React.createElement(App, { settings, sessionName, controlPaneId, configPath: fullConfigPath }));
|
|
212
|
+
await waitUntilExit();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// ── Outside → create/attach session ──
|
|
216
|
+
if (!shouldAttach && !noAttach) {
|
|
217
|
+
console.log('Non-interactive terminal detected; starting Symphony without attaching.');
|
|
218
|
+
}
|
|
219
|
+
await createAndEnterSession(settings, fullConfigPath, { attach: shouldAttach });
|
|
220
|
+
}
|
|
221
|
+
main().catch(err => {
|
|
222
|
+
console.error('Fatal error:', err);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
});
|
|
225
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the Symphony home directory.
|
|
3
|
+
* Respects SYMPHONY_HOME env var, falls back to ~/.symphony
|
|
4
|
+
*/
|
|
5
|
+
export declare function findSymphonyHome(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Create the ~/.symphony directory structure if it doesn't exist.
|
|
8
|
+
* Called once at startup. Safe to call multiple times.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureSymphonyHome(): string;
|
|
11
|
+
/** Path to the global config file */
|
|
12
|
+
export declare function globalConfigPath(): string;
|
|
13
|
+
/** Path to version.json */
|
|
14
|
+
export declare function versionFilePath(): string;
|
|
15
|
+
/** Path to the cache directory */
|
|
16
|
+
export declare function cacheDirPath(): string;
|
|
17
|
+
/** Path to the worktrees directory */
|
|
18
|
+
export declare function worktreesDirPath(): string;
|
|
19
|
+
/** Path to the bare clones directory */
|
|
20
|
+
export declare function reposDirPath(): string;
|
|
21
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAWzC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAmB3C;AAED,qCAAqC;AACrC,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,2BAA2B;AAC3B,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,kCAAkC;AAClC,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,sCAAsC;AACtC,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wCAAwC;AACxC,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|