millhouse 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 +8 -0
- package/README.md +248 -0
- package/commands/millhouse.md +223 -0
- package/dist/analysis/graph-builder.d.ts +42 -0
- package/dist/analysis/graph-builder.d.ts.map +1 -0
- package/dist/analysis/graph-builder.js +98 -0
- package/dist/analysis/graph-builder.js.map +1 -0
- package/dist/analysis/issue-analyzer.d.ts +20 -0
- package/dist/analysis/issue-analyzer.d.ts.map +1 -0
- package/dist/analysis/issue-analyzer.js +167 -0
- package/dist/analysis/issue-analyzer.js.map +1 -0
- package/dist/analysis/plan-parser.d.ts +8 -0
- package/dist/analysis/plan-parser.d.ts.map +1 -0
- package/dist/analysis/plan-parser.js +112 -0
- package/dist/analysis/plan-parser.js.map +1 -0
- package/dist/cli/cleanup.d.ts +20 -0
- package/dist/cli/cleanup.d.ts.map +1 -0
- package/dist/cli/cleanup.js +186 -0
- package/dist/cli/cleanup.js.map +1 -0
- package/dist/cli/commands/clean.d.ts +2 -0
- package/dist/cli/commands/clean.d.ts.map +1 -0
- package/dist/cli/commands/clean.js +16 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +2 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +82 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/run.d.ts +10 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +352 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +6 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +74 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +7 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +83 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/progress-display.d.ts +93 -0
- package/dist/cli/progress-display.d.ts.map +1 -0
- package/dist/cli/progress-display.js +318 -0
- package/dist/cli/progress-display.js.map +1 -0
- package/dist/core/orchestrator.d.ts +79 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +389 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/scheduler.d.ts +72 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +234 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/execution/claude-runner.d.ts +41 -0
- package/dist/execution/claude-runner.d.ts.map +1 -0
- package/dist/execution/claude-runner.js +241 -0
- package/dist/execution/claude-runner.js.map +1 -0
- package/dist/execution/worktree-manager.d.ts +52 -0
- package/dist/execution/worktree-manager.d.ts.map +1 -0
- package/dist/execution/worktree-manager.js +208 -0
- package/dist/execution/worktree-manager.js.map +1 -0
- package/dist/github/client.d.ts +27 -0
- package/dist/github/client.d.ts.map +1 -0
- package/dist/github/client.js +178 -0
- package/dist/github/client.js.map +1 -0
- package/dist/github/issue-discoverer.d.ts +20 -0
- package/dist/github/issue-discoverer.d.ts.map +1 -0
- package/dist/github/issue-discoverer.js +83 -0
- package/dist/github/issue-discoverer.js.map +1 -0
- package/dist/github/label-manager.d.ts +44 -0
- package/dist/github/label-manager.d.ts.map +1 -0
- package/dist/github/label-manager.js +93 -0
- package/dist/github/label-manager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/config.d.ts +4 -0
- package/dist/storage/config.d.ts.map +1 -0
- package/dist/storage/config.js +25 -0
- package/dist/storage/config.js.map +1 -0
- package/dist/storage/json-store.d.ts +20 -0
- package/dist/storage/json-store.d.ts.map +1 -0
- package/dist/storage/json-store.js +92 -0
- package/dist/storage/json-store.js.map +1 -0
- package/dist/types.d.ts +142 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +36 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
export class Scheduler extends EventEmitter {
|
|
3
|
+
concurrency;
|
|
4
|
+
continueOnError;
|
|
5
|
+
graph = null;
|
|
6
|
+
completed = new Set();
|
|
7
|
+
failed = new Set();
|
|
8
|
+
running = new Map();
|
|
9
|
+
blocked = new Set();
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super();
|
|
12
|
+
this.concurrency = options.concurrency;
|
|
13
|
+
this.continueOnError = options.continueOnError;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the scheduler with a dependency graph.
|
|
17
|
+
*/
|
|
18
|
+
initialize(graph, completed = [], failed = []) {
|
|
19
|
+
this.graph = graph;
|
|
20
|
+
this.completed = new Set(completed);
|
|
21
|
+
this.failed = new Set(failed);
|
|
22
|
+
this.running = new Map();
|
|
23
|
+
// Identify initially blocked issues
|
|
24
|
+
const allIssues = graph.getAllIssues();
|
|
25
|
+
for (const issue of allIssues) {
|
|
26
|
+
if (!this.completed.has(issue) && !this.failed.has(issue)) {
|
|
27
|
+
const deps = graph.getDependencies(issue);
|
|
28
|
+
const hasPendingDeps = deps.some(d => !this.completed.has(d) && !this.failed.has(d));
|
|
29
|
+
if (hasPendingDeps) {
|
|
30
|
+
this.blocked.add(issue);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get all tasks that are ready to run (dependencies satisfied, not running).
|
|
37
|
+
*/
|
|
38
|
+
getReadyTasks() {
|
|
39
|
+
if (!this.graph)
|
|
40
|
+
return [];
|
|
41
|
+
const ready = this.graph.getReady(Array.from(this.completed));
|
|
42
|
+
// Filter out already running, failed, and blocked-by-failed tasks
|
|
43
|
+
return ready.filter(issue => {
|
|
44
|
+
if (this.running.has(issue))
|
|
45
|
+
return false;
|
|
46
|
+
if (this.failed.has(issue))
|
|
47
|
+
return false;
|
|
48
|
+
// Check if blocked by a failed dependency
|
|
49
|
+
const deps = this.graph.getDependencies(issue);
|
|
50
|
+
const hasFailedDep = deps.some(d => this.failed.has(d));
|
|
51
|
+
if (hasFailedDep && !this.continueOnError) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get the number of available slots for new tasks.
|
|
59
|
+
*/
|
|
60
|
+
getAvailableSlots() {
|
|
61
|
+
return Math.max(0, this.concurrency - this.running.size);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if all tasks are complete (or failed if continueOnError is false).
|
|
65
|
+
*/
|
|
66
|
+
isComplete() {
|
|
67
|
+
if (!this.graph)
|
|
68
|
+
return true;
|
|
69
|
+
const allIssues = this.graph.getAllIssues();
|
|
70
|
+
const pending = allIssues.filter(i => !this.completed.has(i) &&
|
|
71
|
+
!this.failed.has(i) &&
|
|
72
|
+
!this.running.has(i));
|
|
73
|
+
// If nothing running and nothing pending, we're done
|
|
74
|
+
if (this.running.size === 0 && pending.length === 0) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
// If nothing running, check if all pending are blocked by failures
|
|
78
|
+
if (this.running.size === 0 && !this.continueOnError) {
|
|
79
|
+
// Check if any pending task is startable
|
|
80
|
+
const ready = this.getReadyTasks();
|
|
81
|
+
if (ready.length === 0) {
|
|
82
|
+
return true; // Deadlocked by failures
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Run the scheduler with the given task executor.
|
|
89
|
+
* Returns when all possible tasks are complete.
|
|
90
|
+
*/
|
|
91
|
+
async run(executor) {
|
|
92
|
+
if (!this.graph) {
|
|
93
|
+
throw new Error('Scheduler not initialized');
|
|
94
|
+
}
|
|
95
|
+
while (!this.isComplete()) {
|
|
96
|
+
// Start as many tasks as we can
|
|
97
|
+
const ready = this.getReadyTasks();
|
|
98
|
+
const slots = this.getAvailableSlots();
|
|
99
|
+
const toStart = ready.slice(0, slots);
|
|
100
|
+
for (const issueNumber of toStart) {
|
|
101
|
+
this.startTask(issueNumber, executor);
|
|
102
|
+
}
|
|
103
|
+
// If nothing is running and nothing can start, we're stuck
|
|
104
|
+
if (this.running.size === 0 && toStart.length === 0) {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
// Wait for any running task to complete
|
|
108
|
+
if (this.running.size > 0) {
|
|
109
|
+
await this.waitForAny();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
completed: Array.from(this.completed),
|
|
114
|
+
failed: Array.from(this.failed),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Start a single task.
|
|
119
|
+
*/
|
|
120
|
+
startTask(issueNumber, executor) {
|
|
121
|
+
this.blocked.delete(issueNumber);
|
|
122
|
+
const promise = executor(issueNumber);
|
|
123
|
+
this.running.set(issueNumber, { issueNumber, promise });
|
|
124
|
+
this.emit('event', { type: 'task-started', issueNumber });
|
|
125
|
+
// Handle completion
|
|
126
|
+
promise.then(result => {
|
|
127
|
+
this.handleTaskComplete(issueNumber, result);
|
|
128
|
+
}).catch(error => {
|
|
129
|
+
this.handleTaskComplete(issueNumber, {
|
|
130
|
+
success: false,
|
|
131
|
+
commits: [],
|
|
132
|
+
error: error instanceof Error ? error.message : String(error),
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Handle task completion.
|
|
138
|
+
*/
|
|
139
|
+
handleTaskComplete(issueNumber, result) {
|
|
140
|
+
this.running.delete(issueNumber);
|
|
141
|
+
if (result.success) {
|
|
142
|
+
this.completed.add(issueNumber);
|
|
143
|
+
this.emit('event', {
|
|
144
|
+
type: 'task-completed',
|
|
145
|
+
issueNumber,
|
|
146
|
+
commits: result.commits,
|
|
147
|
+
});
|
|
148
|
+
// Check for newly unblocked tasks
|
|
149
|
+
const unblocked = this.checkUnblockedTasks();
|
|
150
|
+
if (unblocked.length > 0) {
|
|
151
|
+
this.emit('event', { type: 'tasks-unblocked', issueNumbers: unblocked });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.failed.add(issueNumber);
|
|
156
|
+
this.emit('event', {
|
|
157
|
+
type: 'task-failed',
|
|
158
|
+
issueNumber,
|
|
159
|
+
error: result.error || 'Unknown error',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check which blocked tasks are now unblocked.
|
|
165
|
+
*/
|
|
166
|
+
checkUnblockedTasks() {
|
|
167
|
+
if (!this.graph)
|
|
168
|
+
return [];
|
|
169
|
+
const unblocked = [];
|
|
170
|
+
for (const issue of this.blocked) {
|
|
171
|
+
const deps = this.graph.getDependencies(issue);
|
|
172
|
+
const allDepsCompleted = deps.every(d => this.completed.has(d));
|
|
173
|
+
if (allDepsCompleted) {
|
|
174
|
+
this.blocked.delete(issue);
|
|
175
|
+
unblocked.push(issue);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return unblocked;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Wait for any running task to complete.
|
|
182
|
+
*/
|
|
183
|
+
async waitForAny() {
|
|
184
|
+
if (this.running.size === 0)
|
|
185
|
+
return;
|
|
186
|
+
const promises = Array.from(this.running.values()).map(t => t.promise.then(() => t.issueNumber).catch(() => t.issueNumber));
|
|
187
|
+
await Promise.race(promises);
|
|
188
|
+
// Small delay to allow completion handlers to run
|
|
189
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get current status of all tasks.
|
|
193
|
+
*/
|
|
194
|
+
getTaskStatuses() {
|
|
195
|
+
if (!this.graph)
|
|
196
|
+
return new Map();
|
|
197
|
+
const statuses = new Map();
|
|
198
|
+
for (const issue of this.graph.getAllIssues()) {
|
|
199
|
+
if (this.completed.has(issue)) {
|
|
200
|
+
statuses.set(issue, 'completed');
|
|
201
|
+
}
|
|
202
|
+
else if (this.failed.has(issue)) {
|
|
203
|
+
statuses.set(issue, 'failed');
|
|
204
|
+
}
|
|
205
|
+
else if (this.running.has(issue)) {
|
|
206
|
+
statuses.set(issue, 'in-progress');
|
|
207
|
+
}
|
|
208
|
+
else if (this.blocked.has(issue)) {
|
|
209
|
+
statuses.set(issue, 'blocked');
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
statuses.set(issue, 'ready');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return statuses;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get counts of tasks in each status.
|
|
219
|
+
*/
|
|
220
|
+
getStatusCounts() {
|
|
221
|
+
const counts = {
|
|
222
|
+
'queued': 0,
|
|
223
|
+
'blocked': this.blocked.size,
|
|
224
|
+
'ready': 0,
|
|
225
|
+
'in-progress': this.running.size,
|
|
226
|
+
'completed': this.completed.size,
|
|
227
|
+
'failed': this.failed.size,
|
|
228
|
+
};
|
|
229
|
+
// Count ready tasks
|
|
230
|
+
counts.ready = this.getReadyTasks().length;
|
|
231
|
+
return counts;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgB3C,MAAM,OAAO,SAAU,SAAQ,YAAY;IACxB,WAAW,CAAS;IACpB,eAAe,CAAU;IAElC,KAAK,GAA2B,IAAI,CAAC;IACrC,SAAS,GAAgB,IAAI,GAAG,EAAE,CAAC;IACnC,MAAM,GAAgB,IAAI,GAAG,EAAE,CAAC;IAChC,OAAO,GAA+B,IAAI,GAAG,EAAE,CAAC;IAChD,OAAO,GAAgB,IAAI,GAAG,EAAE,CAAC;IAEzC,YAAY,OAAyB;QACnC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,KAAsB,EAAE,YAAsB,EAAE,EAAE,SAAmB,EAAE;QAChF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QAEzB,oCAAoC;QACpC,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;gBAC1C,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACnC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAC9C,CAAC;gBACF,IAAI,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QAE9D,kEAAkE;QAClE,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAC1B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC1C,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAEzC,0CAA0C;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACxD,IAAI,YAAY,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC;YACf,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAE7B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACnC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YACtB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACnB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CACrB,CAAC;QAEF,qDAAqD;QACrD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,mEAAmE;QACnE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YACrD,yCAAyC;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,IAAI,CAAC,CAAC,yBAAyB;YACxC,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,QAAsB;QAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAC1B,gCAAgC;YAChC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACvC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAEtC,KAAK,MAAM,WAAW,IAAI,OAAO,EAAE,CAAC;gBAClC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YACxC,CAAC;YAED,2DAA2D;YAC3D,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpD,MAAM;YACR,CAAC;YAED,wCAAwC;YACxC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,OAAO;YACL,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YACrC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;SAChC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,SAAS,CAAC,WAAmB,EAAE,QAAsB;QAC3D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEjC,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;QAExD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAoB,CAAC,CAAC;QAE5E,oBAAoB;QACpB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACpB,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;YACf,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE;gBACnC,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,EAAE;gBACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,kBAAkB,CACxB,WAAmB,EACnB,MAA+D;QAE/D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEjC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjB,IAAI,EAAE,gBAAgB;gBACtB,WAAW;gBACX,OAAO,EAAE,MAAM,CAAC,OAAO;aACN,CAAC,CAAC;YAErB,kCAAkC;YAClC,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAoB,CAAC,CAAC;YAC7F,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjB,IAAI,EAAE,aAAa;gBACnB,WAAW;gBACX,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,eAAe;aACrB,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,mBAAmB;QACzB,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QAE3B,MAAM,SAAS,GAAa,EAAE,CAAC;QAE/B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAEhE,IAAI,gBAAgB,EAAE,CAAC;gBACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC3B,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAEpC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CACzD,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAC/D,CAAC;QAEF,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE7B,kDAAkD;QAClD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,eAAe;QACb,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAElC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAsB,CAAC;QAE/C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,CAAC;YAC9C,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YACnC,CAAC;iBAAM,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAChC,CAAC;iBAAM,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,MAAM,MAAM,GAA+B;YACzC,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;YAC5B,OAAO,EAAE,CAAC;YACV,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;YAChC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI;YAChC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;SAC3B,CAAC;QAEF,oBAAoB;QACpB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC;QAE3C,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AnalyzedIssue, Config } from '../types.js';
|
|
2
|
+
interface RunResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
commits: string[];
|
|
5
|
+
error?: string;
|
|
6
|
+
output?: string;
|
|
7
|
+
}
|
|
8
|
+
export type LogCallback = (issueNumber: number, message: string) => void;
|
|
9
|
+
interface ClaudeRunnerOptions {
|
|
10
|
+
dangerouslySkipPermissions?: boolean;
|
|
11
|
+
onLog?: LogCallback;
|
|
12
|
+
}
|
|
13
|
+
export declare class ClaudeRunner {
|
|
14
|
+
private promptTemplate;
|
|
15
|
+
private dangerouslySkipPermissions;
|
|
16
|
+
private onLog;
|
|
17
|
+
constructor(_config: Config, options?: ClaudeRunnerOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Load the implementation prompt template.
|
|
20
|
+
*/
|
|
21
|
+
private loadPromptTemplate;
|
|
22
|
+
/**
|
|
23
|
+
* Build the prompt for Claude to implement an issue.
|
|
24
|
+
*/
|
|
25
|
+
buildPrompt(issue: AnalyzedIssue, runId: string): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Run Claude to implement an issue in the given worktree.
|
|
28
|
+
*/
|
|
29
|
+
run(issue: AnalyzedIssue, runId: string, worktreePath: string): Promise<RunResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Get all commit hashes in the worktree.
|
|
32
|
+
*/
|
|
33
|
+
private getCommitHashes;
|
|
34
|
+
/**
|
|
35
|
+
* Commit any uncommitted changes in the worktree.
|
|
36
|
+
* Returns the new commit hashes.
|
|
37
|
+
*/
|
|
38
|
+
private commitChanges;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=claude-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-runner.d.ts","sourceRoot":"","sources":["../../src/execution/claude-runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMzD,UAAU,SAAS;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzE,UAAU,mBAAmB;IAC3B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,0BAA0B,CAAU;IAC5C,OAAO,CAAC,KAAK,CAAc;gBAEf,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB;IAO9D;;OAEG;YACW,kBAAkB;IAyBhC;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWvE;;OAEG;IACG,GAAG,CACP,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,SAAS,CAAC;IAmGrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;;OAGG;YACW,aAAa;CAgC5B"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import { promises as fs } from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
// ES modules equivalent of __dirname
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
export class ClaudeRunner {
|
|
10
|
+
promptTemplate = null;
|
|
11
|
+
dangerouslySkipPermissions;
|
|
12
|
+
onLog;
|
|
13
|
+
constructor(_config, options = {}) {
|
|
14
|
+
this.dangerouslySkipPermissions = options.dangerouslySkipPermissions ?? false;
|
|
15
|
+
this.onLog = options.onLog ?? ((issueNumber, message) => {
|
|
16
|
+
console.log(` [#${issueNumber}] ${message}`);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load the implementation prompt template.
|
|
21
|
+
*/
|
|
22
|
+
async loadPromptTemplate() {
|
|
23
|
+
if (this.promptTemplate) {
|
|
24
|
+
return this.promptTemplate;
|
|
25
|
+
}
|
|
26
|
+
// Try to load from templates directory
|
|
27
|
+
const templatePaths = [
|
|
28
|
+
path.join(process.cwd(), 'templates', 'implementation.prompt.md'),
|
|
29
|
+
path.join(__dirname, '..', '..', 'templates', 'implementation.prompt.md'),
|
|
30
|
+
];
|
|
31
|
+
for (const templatePath of templatePaths) {
|
|
32
|
+
try {
|
|
33
|
+
this.promptTemplate = await fs.readFile(templatePath, 'utf-8');
|
|
34
|
+
return this.promptTemplate;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Try next path
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Fall back to default template
|
|
41
|
+
this.promptTemplate = DEFAULT_PROMPT_TEMPLATE;
|
|
42
|
+
return this.promptTemplate;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build the prompt for Claude to implement an issue.
|
|
46
|
+
*/
|
|
47
|
+
async buildPrompt(issue, runId) {
|
|
48
|
+
const template = await this.loadPromptTemplate();
|
|
49
|
+
return template
|
|
50
|
+
.replace(/\{\{issue\.number\}\}/g, String(issue.number))
|
|
51
|
+
.replace(/\{\{issue\.title\}\}/g, issue.title)
|
|
52
|
+
.replace(/\{\{issue\.body\}\}/g, issue.body || '(No description)')
|
|
53
|
+
.replace(/\{\{runId\}\}/g, runId)
|
|
54
|
+
.replace(/\{\{affectedPaths\}\}/g, issue.affectedPaths.join(', ') || 'Not specified');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Run Claude to implement an issue in the given worktree.
|
|
58
|
+
*/
|
|
59
|
+
async run(issue, runId, worktreePath) {
|
|
60
|
+
const prompt = await this.buildPrompt(issue, runId);
|
|
61
|
+
try {
|
|
62
|
+
// Get commits before running Claude
|
|
63
|
+
const commitsBefore = this.getCommitHashes(worktreePath);
|
|
64
|
+
// Run Claude using the Agent SDK
|
|
65
|
+
const permissionMode = this.dangerouslySkipPermissions ? 'bypassPermissions' : 'acceptEdits';
|
|
66
|
+
const iterator = query({
|
|
67
|
+
prompt,
|
|
68
|
+
options: {
|
|
69
|
+
cwd: worktreePath,
|
|
70
|
+
model: 'claude-sonnet-4-20250514',
|
|
71
|
+
permissionMode,
|
|
72
|
+
maxTurns: 50,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
// Collect all messages
|
|
76
|
+
const messages = [];
|
|
77
|
+
let hasError = false;
|
|
78
|
+
let errorMessage = '';
|
|
79
|
+
for await (const message of iterator) {
|
|
80
|
+
// Handle different message types from the SDK using type guards
|
|
81
|
+
const msg = message;
|
|
82
|
+
if (msg.type === 'assistant') {
|
|
83
|
+
// Extract text content from assistant messages
|
|
84
|
+
const assistantMsg = msg.message;
|
|
85
|
+
if (assistantMsg?.content && Array.isArray(assistantMsg.content)) {
|
|
86
|
+
for (const block of assistantMsg.content) {
|
|
87
|
+
if (typeof block === 'object' && block && 'type' in block && block.type === 'text' && 'text' in block) {
|
|
88
|
+
const text = String(block.text);
|
|
89
|
+
messages.push(text);
|
|
90
|
+
// Log a preview of what Claude is saying
|
|
91
|
+
const preview = text.slice(0, 100).replace(/\n/g, ' ');
|
|
92
|
+
this.onLog(issue.number, `${preview}${text.length > 100 ? '...' : ''}`);
|
|
93
|
+
}
|
|
94
|
+
else if (typeof block === 'object' && block && 'type' in block && block.type === 'tool_use') {
|
|
95
|
+
const toolBlock = block;
|
|
96
|
+
const toolName = toolBlock.name || 'unknown';
|
|
97
|
+
// Log tool usage with relevant details
|
|
98
|
+
if (toolName === 'Edit' || toolName === 'Write') {
|
|
99
|
+
const filePath = toolBlock.input?.file_path || '';
|
|
100
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
101
|
+
this.onLog(issue.number, `📝 ${toolName}: ${fileName}`);
|
|
102
|
+
}
|
|
103
|
+
else if (toolName === 'Read') {
|
|
104
|
+
const filePath = toolBlock.input?.file_path || '';
|
|
105
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
106
|
+
this.onLog(issue.number, `📖 Reading: ${fileName}`);
|
|
107
|
+
}
|
|
108
|
+
else if (toolName === 'Bash') {
|
|
109
|
+
const cmd = (toolBlock.input?.command || '').slice(0, 50);
|
|
110
|
+
this.onLog(issue.number, `💻 ${cmd}${cmd.length >= 50 ? '...' : ''}`);
|
|
111
|
+
}
|
|
112
|
+
else if (toolName === 'Glob' || toolName === 'Grep') {
|
|
113
|
+
const pattern = toolBlock.input?.pattern || '';
|
|
114
|
+
this.onLog(issue.number, `🔍 ${toolName}: ${pattern}`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.onLog(issue.number, `🔧 ${toolName}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (msg.type === 'result') {
|
|
124
|
+
const subtype = msg.subtype;
|
|
125
|
+
if (subtype === 'error_during_execution' || subtype === 'error_max_turns') {
|
|
126
|
+
hasError = true;
|
|
127
|
+
errorMessage = msg.error || 'Claude execution failed';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (hasError) {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
commits: [],
|
|
135
|
+
error: errorMessage,
|
|
136
|
+
output: messages.join('\n'),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Commit any uncommitted changes Claude made
|
|
140
|
+
// (Claude may not have committed due to permission restrictions)
|
|
141
|
+
const newCommits = await this.commitChanges(worktreePath, issue.number, commitsBefore);
|
|
142
|
+
return {
|
|
143
|
+
success: true,
|
|
144
|
+
commits: newCommits,
|
|
145
|
+
output: messages.join('\n'),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
commits: [],
|
|
152
|
+
error: error instanceof Error ? error.message : String(error),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get all commit hashes in the worktree.
|
|
158
|
+
*/
|
|
159
|
+
getCommitHashes(worktreePath) {
|
|
160
|
+
try {
|
|
161
|
+
const output = execSync('git log --format=%H', {
|
|
162
|
+
cwd: worktreePath,
|
|
163
|
+
encoding: 'utf-8',
|
|
164
|
+
});
|
|
165
|
+
return output.trim().split('\n').filter(Boolean);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Commit any uncommitted changes in the worktree.
|
|
173
|
+
* Returns the new commit hashes.
|
|
174
|
+
*/
|
|
175
|
+
async commitChanges(worktreePath, issueNumber, commitsBefore) {
|
|
176
|
+
try {
|
|
177
|
+
// Check if there are uncommitted changes
|
|
178
|
+
const status = execSync('git status --porcelain', {
|
|
179
|
+
cwd: worktreePath,
|
|
180
|
+
encoding: 'utf-8',
|
|
181
|
+
}).trim();
|
|
182
|
+
if (status) {
|
|
183
|
+
// There are uncommitted changes - commit them
|
|
184
|
+
this.onLog(issueNumber, '📦 Committing changes...');
|
|
185
|
+
execSync('git add -A', { cwd: worktreePath });
|
|
186
|
+
execSync(`git commit -m "feat: implement issue #${issueNumber}\n\nFixes #${issueNumber}"`, { cwd: worktreePath });
|
|
187
|
+
}
|
|
188
|
+
// Get commits after
|
|
189
|
+
const commitsAfter = this.getCommitHashes(worktreePath);
|
|
190
|
+
return commitsAfter.filter(c => !commitsBefore.includes(c));
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
// If commit fails, still return any commits Claude may have made
|
|
194
|
+
const commitsAfter = this.getCommitHashes(worktreePath);
|
|
195
|
+
return commitsAfter.filter(c => !commitsBefore.includes(c));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const DEFAULT_PROMPT_TEMPLATE = `# Your Task
|
|
200
|
+
|
|
201
|
+
Implement GitHub issue #{{issue.number}}: {{issue.title}}
|
|
202
|
+
|
|
203
|
+
## Issue Description
|
|
204
|
+
{{issue.body}}
|
|
205
|
+
|
|
206
|
+
## Likely Affected Files
|
|
207
|
+
{{affectedPaths}}
|
|
208
|
+
|
|
209
|
+
## Instructions
|
|
210
|
+
|
|
211
|
+
1. **Understand**: Read the issue carefully, especially any **acceptance criteria**
|
|
212
|
+
2. **Implement**: Make the necessary changes to resolve this issue
|
|
213
|
+
3. **Test and Verify - CRITICAL**:
|
|
214
|
+
- Run all existing tests to ensure nothing is broken
|
|
215
|
+
- Think deeply about how to test the acceptance criteria
|
|
216
|
+
- Run any test commands specified in the issue
|
|
217
|
+
- If tests fail or acceptance criteria aren't met, fix and repeat
|
|
218
|
+
- If stuck in a loop or need human input, exit with an error
|
|
219
|
+
- **DO NOT SUCCEED IF TESTS FAIL OR ACCEPTANCE CRITERIA ARE NOT MET**
|
|
220
|
+
4. **Commit**: Create a single commit with a comprehensive message:
|
|
221
|
+
- Summary line describing the change
|
|
222
|
+
- Body with: what was implemented, files changed, how acceptance criteria were met
|
|
223
|
+
- End with "Fixes #{{issue.number}}"
|
|
224
|
+
|
|
225
|
+
## Important Rules
|
|
226
|
+
- You are working in a git worktree on branch \`millhouse/run-{{runId}}\`
|
|
227
|
+
- Do NOT create a pull request - the orchestrator handles that
|
|
228
|
+
- If you encounter blocking issues that need human input, exit with an error
|
|
229
|
+
- Your changes will be merged with other parallel tasks
|
|
230
|
+
- Focus only on this issue - don't fix unrelated problems
|
|
231
|
+
- Keep changes minimal and focused
|
|
232
|
+
|
|
233
|
+
## Git Commands
|
|
234
|
+
- Use \`git add <files>\` to stage specific files
|
|
235
|
+
- Use \`git commit -m "message"\` to commit
|
|
236
|
+
- Do NOT use \`git push\` - the orchestrator handles that
|
|
237
|
+
|
|
238
|
+
## When You're Done
|
|
239
|
+
Summarize what you changed, test results, and verification of acceptance criteria.
|
|
240
|
+
`;
|
|
241
|
+
//# sourceMappingURL=claude-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-runner.js","sourceRoot":"","sources":["../../src/execution/claude-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,qCAAqC;AACrC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAgB3C,MAAM,OAAO,YAAY;IACf,cAAc,GAAkB,IAAI,CAAC;IACrC,0BAA0B,CAAU;IACpC,KAAK,CAAc;IAE3B,YAAY,OAAe,EAAE,UAA+B,EAAE;QAC5D,IAAI,CAAC,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,IAAI,KAAK,CAAC;QAC9E,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE;YACtD,OAAO,CAAC,GAAG,CAAC,QAAQ,WAAW,KAAK,OAAO,EAAE,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,kBAAkB;QAC9B,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,cAAc,CAAC;QAC7B,CAAC;QAED,uCAAuC;QACvC,MAAM,aAAa,GAAG;YACpB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,0BAA0B,CAAC;YACjE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,0BAA0B,CAAC;SAC1E,CAAC;QAEF,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;YACzC,IAAI,CAAC;gBACH,IAAI,CAAC,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBAC/D,OAAO,IAAI,CAAC,cAAc,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,gBAAgB;YAClB,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,CAAC,cAAc,GAAG,uBAAuB,CAAC;QAC9C,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,KAAoB,EAAE,KAAa;QACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEjD,OAAO,QAAQ;aACZ,OAAO,CAAC,wBAAwB,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;aACvD,OAAO,CAAC,uBAAuB,EAAE,KAAK,CAAC,KAAK,CAAC;aAC7C,OAAO,CAAC,sBAAsB,EAAE,KAAK,CAAC,IAAI,IAAI,kBAAkB,CAAC;aACjE,OAAO,CAAC,gBAAgB,EAAE,KAAK,CAAC;aAChC,OAAO,CAAC,wBAAwB,EAAE,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,CAAC;IAC1F,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CACP,KAAoB,EACpB,KAAa,EACb,YAAoB;QAEpB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAEpD,IAAI,CAAC;YACH,oCAAoC;YACpC,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YAEzD,iCAAiC;YACjC,MAAM,cAAc,GAAG,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,aAAa,CAAC;YAC7F,MAAM,QAAQ,GAAG,KAAK,CAAC;gBACrB,MAAM;gBACN,OAAO,EAAE;oBACP,GAAG,EAAE,YAAY;oBACjB,KAAK,EAAE,0BAA0B;oBACjC,cAAc;oBACd,QAAQ,EAAE,EAAE;iBACb;aACF,CAAC,CAAC;YAEH,uBAAuB;YACvB,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,YAAY,GAAG,EAAE,CAAC;YAEtB,IAAI,KAAK,EAAE,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBACrC,gEAAgE;gBAChE,MAAM,GAAG,GAAG,OAA6C,CAAC;gBAE1D,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC7B,+CAA+C;oBAC/C,MAAM,YAAY,GAAG,GAAG,CAAC,OAA8C,CAAC;oBACxE,IAAI,YAAY,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;wBACjE,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;4BACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;gCACtG,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gCAChC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gCACpB,yCAAyC;gCACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gCACvD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC1E,CAAC;iCAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gCAC9F,MAAM,SAAS,GAAG,KAA2D,CAAC;gCAC9E,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC;gCAC7C,uCAAuC;gCACvC,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;oCAChD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,SAAmB,IAAI,EAAE,CAAC;oCAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;oCACvD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,QAAQ,KAAK,QAAQ,EAAE,CAAC,CAAC;gCAC1D,CAAC;qCAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;oCAC/B,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,SAAmB,IAAI,EAAE,CAAC;oCAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;oCACvD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,eAAe,QAAQ,EAAE,CAAC,CAAC;gCACtD,CAAC;qCAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;oCAC/B,MAAM,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,OAAiB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oCACpE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gCACxE,CAAC;qCAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;oCACtD,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,OAAiB,IAAI,EAAE,CAAC;oCACzD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;gCACzD,CAAC;qCAAM,CAAC;oCACN,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,QAAQ,EAAE,CAAC,CAAC;gCAC7C,CAAC;4BACH,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACjC,MAAM,OAAO,GAAG,GAAG,CAAC,OAA6B,CAAC;oBAClD,IAAI,OAAO,KAAK,wBAAwB,IAAI,OAAO,KAAK,iBAAiB,EAAE,CAAC;wBAC1E,QAAQ,GAAG,IAAI,CAAC;wBAChB,YAAY,GAAI,GAAG,CAAC,KAAgB,IAAI,yBAAyB,CAAC;oBACpE,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,EAAE;oBACX,KAAK,EAAE,YAAY;oBACnB,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;iBAC5B,CAAC;YACJ,CAAC;YAED,6CAA6C;YAC7C,iEAAiE;YACjE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;YAEvF,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,UAAU;gBACnB,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;aAC5B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,EAAE;gBACX,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,YAAoB;QAC1C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,QAAQ,CAAC,qBAAqB,EAAE;gBAC7C,GAAG,EAAE,YAAY;gBACjB,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,aAAa,CACzB,YAAoB,EACpB,WAAmB,EACnB,aAAuB;QAEvB,IAAI,CAAC;YACH,yCAAyC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,wBAAwB,EAAE;gBAChD,GAAG,EAAE,YAAY;gBACjB,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC,IAAI,EAAE,CAAC;YAEV,IAAI,MAAM,EAAE,CAAC;gBACX,8CAA8C;gBAC9C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC;gBAEpD,QAAQ,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC9C,QAAQ,CACN,yCAAyC,WAAW,cAAc,WAAW,GAAG,EAChF,EAAE,GAAG,EAAE,YAAY,EAAE,CACtB,CAAC;YACJ,CAAC;YAED,oBAAoB;YACpB,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YACxD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,iEAAiE;YACjE,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YACxD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;CACF;AAED,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyC/B,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { WorktreeInfo } from '../types.js';
|
|
2
|
+
export declare class WorktreeManager {
|
|
3
|
+
private basePath;
|
|
4
|
+
private worktreesDir;
|
|
5
|
+
constructor(basePath?: string);
|
|
6
|
+
/**
|
|
7
|
+
* Create the run branch from the base branch.
|
|
8
|
+
*/
|
|
9
|
+
createRunBranch(runId: string, baseBranch: string): Promise<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Create an isolated worktree for an issue.
|
|
12
|
+
* Each issue gets its own branch to allow parallel worktrees.
|
|
13
|
+
*/
|
|
14
|
+
createWorktree(runId: string, issueNumber: number, runBranch: string): Promise<WorktreeInfo>;
|
|
15
|
+
/**
|
|
16
|
+
* Get list of commits made in a worktree since it was created.
|
|
17
|
+
*/
|
|
18
|
+
getNewCommits(worktreePath: string, runBranch: string): Promise<string[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Merge changes from a worktree back into the run branch.
|
|
21
|
+
* Returns true if successful, false if there were conflicts.
|
|
22
|
+
*/
|
|
23
|
+
mergeWorktree(worktreePath: string, runBranch: string): Promise<{
|
|
24
|
+
success: boolean;
|
|
25
|
+
error?: string;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Remove a worktree and its associated branch.
|
|
29
|
+
*/
|
|
30
|
+
removeWorktree(worktreePath: string, issueBranch?: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Clean up all worktrees for a run.
|
|
33
|
+
*/
|
|
34
|
+
cleanupRun(_runId: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Push the run branch to remote.
|
|
37
|
+
*/
|
|
38
|
+
pushRunBranch(runBranch: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Check if there are uncommitted changes in the main repo.
|
|
41
|
+
*/
|
|
42
|
+
hasUncommittedChanges(): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the current branch name.
|
|
45
|
+
*/
|
|
46
|
+
getCurrentBranch(): Promise<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Restore to a specific branch, aborting any in-progress merge.
|
|
49
|
+
*/
|
|
50
|
+
restoreBranch(branchName: string): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=worktree-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-manager.d.ts","sourceRoot":"","sources":["../../src/execution/worktree-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,QAAQ,GAAE,MAAsB;IAK5C;;OAEG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BzE;;;OAGG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA+BlG;;OAEG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAc/E;;;OAGG;IACG,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA8C3G;;OAEG;IACG,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe/E;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa/C;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;IACG,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;IAS/C;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAKzC;;OAEG;IACG,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA6BvD"}
|