@orc-brain/core 1.0.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 +21 -0
- package/dist/autoLoop.d.ts +70 -0
- package/dist/autoLoop.d.ts.map +1 -0
- package/dist/autoLoop.js +178 -0
- package/dist/autoLoop.js.map +1 -0
- package/dist/backpressure.d.ts +38 -0
- package/dist/backpressure.d.ts.map +1 -0
- package/dist/backpressure.js +103 -0
- package/dist/backpressure.js.map +1 -0
- package/dist/budgetTracker.d.ts +53 -0
- package/dist/budgetTracker.d.ts.map +1 -0
- package/dist/budgetTracker.js +93 -0
- package/dist/budgetTracker.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +107 -0
- package/dist/config.js.map +1 -0
- package/dist/escalation.d.ts +43 -0
- package/dist/escalation.d.ts.map +1 -0
- package/dist/escalation.js +81 -0
- package/dist/escalation.js.map +1 -0
- package/dist/eventBus.d.ts +30 -0
- package/dist/eventBus.d.ts.map +1 -0
- package/dist/eventBus.js +42 -0
- package/dist/eventBus.js.map +1 -0
- package/dist/goalJudge.d.ts +92 -0
- package/dist/goalJudge.d.ts.map +1 -0
- package/dist/goalJudge.js +254 -0
- package/dist/goalJudge.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/modelRouter.d.ts +40 -0
- package/dist/modelRouter.d.ts.map +1 -0
- package/dist/modelRouter.js +114 -0
- package/dist/modelRouter.js.map +1 -0
- package/dist/orchestrator.d.ts +242 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +975 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pacing.d.ts +34 -0
- package/dist/pacing.d.ts.map +1 -0
- package/dist/pacing.js +49 -0
- package/dist/pacing.js.map +1 -0
- package/dist/planValidation.d.ts +24 -0
- package/dist/planValidation.d.ts.map +1 -0
- package/dist/planValidation.js +134 -0
- package/dist/planValidation.js.map +1 -0
- package/dist/planner.d.ts +70 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +210 -0
- package/dist/planner.js.map +1 -0
- package/dist/plugins/host.d.ts +39 -0
- package/dist/plugins/host.d.ts.map +1 -0
- package/dist/plugins/host.js +109 -0
- package/dist/plugins/host.js.map +1 -0
- package/dist/plugins/registry.d.ts +71 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +269 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/secrets.d.ts +30 -0
- package/dist/plugins/secrets.d.ts.map +1 -0
- package/dist/plugins/secrets.js +99 -0
- package/dist/plugins/secrets.js.map +1 -0
- package/dist/preflight.d.ts +38 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +108 -0
- package/dist/preflight.js.map +1 -0
- package/dist/reporting.d.ts +41 -0
- package/dist/reporting.d.ts.map +1 -0
- package/dist/reporting.js +229 -0
- package/dist/reporting.js.map +1 -0
- package/dist/safety/denyRules.d.ts +57 -0
- package/dist/safety/denyRules.d.ts.map +1 -0
- package/dist/safety/denyRules.js +498 -0
- package/dist/safety/denyRules.js.map +1 -0
- package/dist/safety/envClassifier.d.ts +45 -0
- package/dist/safety/envClassifier.d.ts.map +1 -0
- package/dist/safety/envClassifier.js +99 -0
- package/dist/safety/envClassifier.js.map +1 -0
- package/dist/safety/index.d.ts +83 -0
- package/dist/safety/index.d.ts.map +1 -0
- package/dist/safety/index.js +184 -0
- package/dist/safety/index.js.map +1 -0
- package/dist/safety/limitSignals.d.ts +36 -0
- package/dist/safety/limitSignals.d.ts.map +1 -0
- package/dist/safety/limitSignals.js +79 -0
- package/dist/safety/limitSignals.js.map +1 -0
- package/dist/safety/paths.d.ts +32 -0
- package/dist/safety/paths.d.ts.map +1 -0
- package/dist/safety/paths.js +102 -0
- package/dist/safety/paths.js.map +1 -0
- package/dist/safety/redact.d.ts +17 -0
- package/dist/safety/redact.d.ts.map +1 -0
- package/dist/safety/redact.js +85 -0
- package/dist/safety/redact.js.map +1 -0
- package/dist/spawnEnv.d.ts +18 -0
- package/dist/spawnEnv.d.ts.map +1 -0
- package/dist/spawnEnv.js +43 -0
- package/dist/spawnEnv.js.map +1 -0
- package/dist/store/auditLog.d.ts +28 -0
- package/dist/store/auditLog.d.ts.map +1 -0
- package/dist/store/auditLog.js +48 -0
- package/dist/store/auditLog.js.map +1 -0
- package/dist/store/index.d.ts +140 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +648 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/schema.d.ts +17 -0
- package/dist/store/schema.d.ts.map +1 -0
- package/dist/store/schema.js +197 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/system.d.ts +69 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +135 -0
- package/dist/system.js.map +1 -0
- package/dist/workerManager.d.ts +80 -0
- package/dist/workerManager.d.ts.map +1 -0
- package/dist/workerManager.js +280 -0
- package/dist/workerManager.js.map +1 -0
- package/dist/worktrees.d.ts +74 -0
- package/dist/worktrees.d.ts.map +1 -0
- package/dist/worktrees.js +210 -0
- package/dist/worktrees.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker manager (§3). One worker = one Agent SDK `query()` call = one child
|
|
3
|
+
* Claude Code CLI subprocess (the TS SDK bundles the binary). Each worker gets
|
|
4
|
+
* exactly the scope's config — cwd, allowed/disallowed tools, permission mode,
|
|
5
|
+
* model, maxTurns, maxBudgetUsd — plus the safety layer's hooks + canUseTool,
|
|
6
|
+
* which are constructor-injected and cannot be omitted.
|
|
7
|
+
*
|
|
8
|
+
* The Orchestrator does its own fan-out with independent top-level sessions per
|
|
9
|
+
* task (Open Decision 4, accepted): per-task model/permission/cwd control,
|
|
10
|
+
* per-task `session_id` for pause/resume, and per-task cost attribution.
|
|
11
|
+
*/
|
|
12
|
+
import { query as sdkQuery } from "@anthropic-ai/claude-agent-sdk";
|
|
13
|
+
import { ulid } from "ulid";
|
|
14
|
+
import { buildSpawnEnv } from "./spawnEnv.js";
|
|
15
|
+
/** Truncates a value to a short one-line summary for events. */
|
|
16
|
+
function summarize(value, max = 120) {
|
|
17
|
+
const s = typeof value === "string" ? value : JSON.stringify(value);
|
|
18
|
+
const oneLine = (s ?? "").replace(/\s+/g, " ").trim();
|
|
19
|
+
return oneLine.length > max ? oneLine.slice(0, max) + "…" : oneLine;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Spawns and supervises workers. Constructed with a {@link SafetyLayer} that is
|
|
23
|
+
* a required argument — a worker cannot be built without one.
|
|
24
|
+
*/
|
|
25
|
+
export class WorkerManager {
|
|
26
|
+
safety;
|
|
27
|
+
bus;
|
|
28
|
+
store;
|
|
29
|
+
budget;
|
|
30
|
+
queryFn;
|
|
31
|
+
constructor(safety, bus, store, budget, queryFn) {
|
|
32
|
+
this.safety = safety;
|
|
33
|
+
this.bus = bus;
|
|
34
|
+
this.store = store;
|
|
35
|
+
this.budget = budget;
|
|
36
|
+
this.queryFn = queryFn ?? sdkQuery;
|
|
37
|
+
}
|
|
38
|
+
/** The safety layer gating all workers managed here. */
|
|
39
|
+
get safetyLayer() {
|
|
40
|
+
return this.safety;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Spawns one worker for a task. Builds the SDK options from the spec, attaches
|
|
44
|
+
* the safety layer's hooks + canUseTool, strips provider credentials from the
|
|
45
|
+
* child env, and streams messages onto the bus. Returns a handle immediately;
|
|
46
|
+
* `handle.done` resolves when the session ends.
|
|
47
|
+
*/
|
|
48
|
+
spawn(spec) {
|
|
49
|
+
// Mode floor assertion (§8.3) — throws before any child is spawned.
|
|
50
|
+
this.safety.assertPermissionMode(spec.permission_mode);
|
|
51
|
+
const ctx = {
|
|
52
|
+
run_id: spec.run_id,
|
|
53
|
+
task_id: spec.task_id,
|
|
54
|
+
session_id: spec.resume_session_id ?? null,
|
|
55
|
+
environment: spec.environment,
|
|
56
|
+
cwd: spec.cwd,
|
|
57
|
+
path_allowlist: spec.path_allowlist,
|
|
58
|
+
path_denylist: spec.path_denylist,
|
|
59
|
+
};
|
|
60
|
+
const options = {
|
|
61
|
+
cwd: spec.cwd,
|
|
62
|
+
model: spec.model,
|
|
63
|
+
permissionMode: spec.permission_mode,
|
|
64
|
+
allowedTools: spec.allowed_tools,
|
|
65
|
+
disallowedTools: spec.disallowed_tools,
|
|
66
|
+
maxTurns: spec.max_turns,
|
|
67
|
+
maxBudgetUsd: spec.max_budget_usd,
|
|
68
|
+
includePartialMessages: true,
|
|
69
|
+
// Strip ANTHROPIC_API_KEY et al so billing stays on subscription (§2).
|
|
70
|
+
env: buildSpawnEnv(),
|
|
71
|
+
hooks: this.safety.buildHooks(ctx),
|
|
72
|
+
canUseTool: this.safety.buildCanUseTool(ctx),
|
|
73
|
+
...(spec.resume_session_id ? { resume: spec.resume_session_id } : {}),
|
|
74
|
+
};
|
|
75
|
+
const subagentId = ulid();
|
|
76
|
+
const now = new Date().toISOString();
|
|
77
|
+
const record = {
|
|
78
|
+
id: subagentId,
|
|
79
|
+
created_at: now,
|
|
80
|
+
updated_at: now,
|
|
81
|
+
task_id: spec.task_id,
|
|
82
|
+
session_id: spec.resume_session_id ?? null,
|
|
83
|
+
model: spec.model,
|
|
84
|
+
pid: null,
|
|
85
|
+
state: "spawning",
|
|
86
|
+
started_at: now,
|
|
87
|
+
ended_at: null,
|
|
88
|
+
num_turns: 0,
|
|
89
|
+
cost_usd: 0,
|
|
90
|
+
last_tool_call: null,
|
|
91
|
+
transcript_path: null,
|
|
92
|
+
};
|
|
93
|
+
this.store.upsertSubagent(record);
|
|
94
|
+
const q = this.queryFn({ prompt: spec.prompt, options });
|
|
95
|
+
const state = { sessionId: spec.resume_session_id ?? null };
|
|
96
|
+
const done = this.drain(q, spec, ctx, record, state).catch((err) => {
|
|
97
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
98
|
+
this.store.updateTask(spec.task_id, {
|
|
99
|
+
status: "failed",
|
|
100
|
+
error: { message: error },
|
|
101
|
+
});
|
|
102
|
+
record.state = "exited";
|
|
103
|
+
record.ended_at = new Date().toISOString();
|
|
104
|
+
this.store.upsertSubagent(record);
|
|
105
|
+
this.bus.publish({
|
|
106
|
+
type: "task.state",
|
|
107
|
+
run_id: spec.run_id,
|
|
108
|
+
payload: {
|
|
109
|
+
task_id: spec.task_id,
|
|
110
|
+
scope_id: "",
|
|
111
|
+
status: "failed",
|
|
112
|
+
error: { message: error },
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
session_id: state.sessionId,
|
|
117
|
+
status: "failed",
|
|
118
|
+
cost_usd: 0,
|
|
119
|
+
num_turns: 0,
|
|
120
|
+
error,
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
task_id: spec.task_id,
|
|
125
|
+
sessionId: () => state.sessionId,
|
|
126
|
+
interrupt: async () => {
|
|
127
|
+
record.state = "interrupting";
|
|
128
|
+
this.store.upsertSubagent(record);
|
|
129
|
+
await q.interrupt();
|
|
130
|
+
},
|
|
131
|
+
done,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Consumes the SDK message stream, projecting it onto the bus and store. */
|
|
135
|
+
async drain(q, spec, ctx, record, state) {
|
|
136
|
+
let result = {
|
|
137
|
+
session_id: state.sessionId,
|
|
138
|
+
status: "failed",
|
|
139
|
+
cost_usd: 0,
|
|
140
|
+
num_turns: 0,
|
|
141
|
+
};
|
|
142
|
+
this.store.updateTask(spec.task_id, { status: "running" });
|
|
143
|
+
this.bus.publish({
|
|
144
|
+
type: "task.state",
|
|
145
|
+
run_id: spec.run_id,
|
|
146
|
+
payload: {
|
|
147
|
+
task_id: spec.task_id,
|
|
148
|
+
scope_id: "",
|
|
149
|
+
status: "running",
|
|
150
|
+
model: spec.model,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
for await (const message of q) {
|
|
154
|
+
switch (message.type) {
|
|
155
|
+
case "system": {
|
|
156
|
+
if (message.subtype === "init") {
|
|
157
|
+
state.sessionId = message.session_id;
|
|
158
|
+
ctx.session_id = message.session_id;
|
|
159
|
+
record.session_id = message.session_id;
|
|
160
|
+
record.state = "running";
|
|
161
|
+
this.store.upsertSubagent(record);
|
|
162
|
+
this.store.updateTask(spec.task_id, {
|
|
163
|
+
session_id: message.session_id,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "assistant": {
|
|
169
|
+
const blocks = (message.message?.content ?? []);
|
|
170
|
+
for (const b of blocks) {
|
|
171
|
+
const block = b;
|
|
172
|
+
if (block.type === "tool_use") {
|
|
173
|
+
record.last_tool_call = {
|
|
174
|
+
name: block.name,
|
|
175
|
+
input: summarize(block.input),
|
|
176
|
+
};
|
|
177
|
+
this.store.upsertSubagent(record);
|
|
178
|
+
this.bus.publish({
|
|
179
|
+
type: "tool.call",
|
|
180
|
+
run_id: spec.run_id,
|
|
181
|
+
payload: {
|
|
182
|
+
task_id: spec.task_id,
|
|
183
|
+
session_id: state.sessionId,
|
|
184
|
+
tool_name: block.name,
|
|
185
|
+
input_summary: summarize(block.input),
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else if (block.type === "text" && block.text) {
|
|
190
|
+
this.bus.publish({
|
|
191
|
+
type: "text.delta",
|
|
192
|
+
run_id: spec.run_id,
|
|
193
|
+
payload: {
|
|
194
|
+
task_id: spec.task_id,
|
|
195
|
+
session_id: state.sessionId,
|
|
196
|
+
delta: block.text,
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
case "user": {
|
|
204
|
+
const blocks = (message.message?.content ?? []);
|
|
205
|
+
if (!Array.isArray(blocks))
|
|
206
|
+
break;
|
|
207
|
+
for (const b of blocks) {
|
|
208
|
+
const block = b;
|
|
209
|
+
if (block.type === "tool_result") {
|
|
210
|
+
this.bus.publish({
|
|
211
|
+
type: "tool.result",
|
|
212
|
+
run_id: spec.run_id,
|
|
213
|
+
payload: {
|
|
214
|
+
task_id: spec.task_id,
|
|
215
|
+
session_id: state.sessionId,
|
|
216
|
+
tool_name: "",
|
|
217
|
+
is_error: block.is_error ?? false,
|
|
218
|
+
summary: summarize(block.content),
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case "result": {
|
|
226
|
+
const isSuccess = message.subtype === "success";
|
|
227
|
+
record.num_turns = message.num_turns;
|
|
228
|
+
record.cost_usd = message.total_cost_usd;
|
|
229
|
+
record.state = "exited";
|
|
230
|
+
record.ended_at = new Date().toISOString();
|
|
231
|
+
this.store.upsertSubagent(record);
|
|
232
|
+
this.budget.recordResult({
|
|
233
|
+
run_id: spec.run_id,
|
|
234
|
+
task_id: spec.task_id,
|
|
235
|
+
session_id: state.sessionId,
|
|
236
|
+
model: spec.model,
|
|
237
|
+
result: {
|
|
238
|
+
total_cost_usd: message.total_cost_usd,
|
|
239
|
+
num_turns: message.num_turns,
|
|
240
|
+
usage: message.usage,
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
const summary = isSuccess
|
|
244
|
+
? message.result
|
|
245
|
+
: undefined;
|
|
246
|
+
const error = isSuccess ? undefined : { subtype: message.subtype };
|
|
247
|
+
result = {
|
|
248
|
+
session_id: state.sessionId,
|
|
249
|
+
status: isSuccess ? "done" : "failed",
|
|
250
|
+
cost_usd: message.total_cost_usd,
|
|
251
|
+
num_turns: message.num_turns,
|
|
252
|
+
result_summary: summary,
|
|
253
|
+
error,
|
|
254
|
+
};
|
|
255
|
+
this.store.updateTask(spec.task_id, {
|
|
256
|
+
status: result.status,
|
|
257
|
+
result_summary: summary ?? null,
|
|
258
|
+
error: error ?? null,
|
|
259
|
+
session_id: state.sessionId,
|
|
260
|
+
});
|
|
261
|
+
this.bus.publish({
|
|
262
|
+
type: "task.state",
|
|
263
|
+
run_id: spec.run_id,
|
|
264
|
+
payload: {
|
|
265
|
+
task_id: spec.task_id,
|
|
266
|
+
scope_id: "",
|
|
267
|
+
status: result.status,
|
|
268
|
+
error,
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
default:
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=workerManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerManager.js","sourceRoot":"","sources":["../src/workerManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAMnE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAW5B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA0C9C,gEAAgE;AAChE,SAAS,SAAS,CAAC,KAAc,EAAE,GAAG,GAAG,GAAG;IAC1C,MAAM,CAAC,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACtD,OAAO,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AACtE,CAAC;AAoBD;;;GAGG;AACH,MAAM,OAAO,aAAa;IAIL;IACA;IACA;IACA;IANF,OAAO,CAAU;IAElC,YACmB,MAAmB,EACnB,GAAa,EACb,KAAY,EACZ,MAAqB,EACtC,OAAiB;QAJA,WAAM,GAAN,MAAM,CAAa;QACnB,QAAG,GAAH,GAAG,CAAU;QACb,UAAK,GAAL,KAAK,CAAO;QACZ,WAAM,GAAN,MAAM,CAAe;QAGtC,IAAI,CAAC,OAAO,GAAG,OAAO,IAAK,QAA+B,CAAC;IAC7D,CAAC;IAED,wDAAwD;IACxD,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAgB;QACpB,oEAAoE;QACpE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAEvD,MAAM,GAAG,GAAuB;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI;YAC1C,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC;QAEF,MAAM,OAAO,GAAY;YACvB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,cAAc,EAAE,IAAI,CAAC,eAAe;YACpC,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,eAAe,EAAE,IAAI,CAAC,gBAAgB;YACtC,QAAQ,EAAE,IAAI,CAAC,SAAS;YACxB,YAAY,EAAE,IAAI,CAAC,cAAc;YACjC,sBAAsB,EAAE,IAAI;YAC5B,uEAAuE;YACvE,GAAG,EAAE,aAAa,EAAwC;YAC1D,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;YAClC,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC;YAC5C,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,MAAM,GAAmB;YAC7B,EAAE,EAAE,UAAU;YACd,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,UAAU,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI;YAC1C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI;YACT,KAAK,EAAE,UAAU;YACjB,UAAU,EAAE,GAAG;YACf,QAAQ,EAAE,IAAI;YACd,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,CAAC;YACX,cAAc,EAAE,IAAI;YACpB,eAAe,EAAE,IAAI;SACtB,CAAC;QACF,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI,EAAE,CAAC;QAE5D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,KAAK,CACxD,CAAC,GAAG,EAAgB,EAAE;YACpB,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE;gBAClC,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;aAC1B,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC;YACxB,MAAM,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gBACf,IAAI,EAAE,YAAY;gBAClB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE;oBACP,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,QAAQ,EAAE,EAAE;oBACZ,MAAM,EAAE,QAAQ;oBAChB,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;iBAC1B;aACF,CAAC,CAAC;YACH,OAAO;gBACL,UAAU,EAAE,KAAK,CAAC,SAAS;gBAC3B,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,CAAC;gBACX,SAAS,EAAE,CAAC;gBACZ,KAAK;aACN,CAAC;QACJ,CAAC,CACF,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS;YAChC,SAAS,EAAE,KAAK,IAAI,EAAE;gBACpB,MAAM,CAAC,KAAK,GAAG,cAAc,CAAC;gBAC9B,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;gBAClC,MAAM,CAAC,CAAC,SAAS,EAAE,CAAC;YACtB,CAAC;YACD,IAAI;SACL,CAAC;IACJ,CAAC;IAED,6EAA6E;IACrE,KAAK,CAAC,KAAK,CACjB,CAAQ,EACR,IAAgB,EAChB,GAAuB,EACvB,MAAsB,EACtB,KAAmC;QAEnC,IAAI,MAAM,GAAiB;YACzB,UAAU,EAAE,KAAK,CAAC,SAAS;YAC3B,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,CAAC;YACX,SAAS,EAAE,CAAC;SACb,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;YACf,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE;gBACP,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,QAAQ,EAAE,EAAE;gBACZ,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB;SACF,CAAC,CAAC;QAEH,IAAI,KAAK,EAAE,MAAM,OAAO,IAAI,CAA8B,EAAE,CAAC;YAC3D,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;gBACrB,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;wBAC/B,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;wBACrC,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;wBACpC,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;wBACvC,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC;wBACzB,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;wBAClC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE;4BAClC,UAAU,EAAE,OAAO,CAAC,UAAU;yBAC/B,CAAC,CAAC;oBACL,CAAC;oBACD,MAAM;gBACR,CAAC;gBACD,KAAK,WAAW,CAAC,CAAC,CAAC;oBACjB,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAc,CAAC;oBAC7D,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;wBACvB,MAAM,KAAK,GAAG,CAA6B,CAAC;wBAC5C,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;4BAC9B,MAAM,CAAC,cAAc,GAAG;gCACtB,IAAI,EAAE,KAAK,CAAC,IAAI;gCAChB,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;6BAC9B,CAAC;4BACF,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;4BAClC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gCACf,IAAI,EAAE,WAAW;gCACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gCACnB,OAAO,EAAE;oCACP,OAAO,EAAE,IAAI,CAAC,OAAO;oCACrB,UAAU,EAAE,KAAK,CAAC,SAAS;oCAC3B,SAAS,EAAE,KAAK,CAAC,IAAI;oCACrB,aAAa,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;iCACtC;6BACF,CAAC,CAAC;wBACL,CAAC;6BAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;4BAC/C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gCACf,IAAI,EAAE,YAAY;gCAClB,MAAM,EAAE,IAAI,CAAC,MAAM;gCACnB,OAAO,EAAE;oCACP,OAAO,EAAE,IAAI,CAAC,OAAO;oCACrB,UAAU,EAAE,KAAK,CAAC,SAAS;oCAC3B,KAAK,EAAE,KAAK,CAAC,IAAI;iCAClB;6BACF,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBACD,MAAM;gBACR,CAAC;gBACD,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAc,CAAC;oBAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;wBAAE,MAAM;oBAClC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;wBACvB,MAAM,KAAK,GAAG,CAAoB,CAAC;wBACnC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;4BACjC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gCACf,IAAI,EAAE,aAAa;gCACnB,MAAM,EAAE,IAAI,CAAC,MAAM;gCACnB,OAAO,EAAE;oCACP,OAAO,EAAE,IAAI,CAAC,OAAO;oCACrB,UAAU,EAAE,KAAK,CAAC,SAAS;oCAC3B,SAAS,EAAE,EAAE;oCACb,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;oCACjC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC;iCAClC;6BACF,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBACD,MAAM;gBACR,CAAC;gBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC;oBAChD,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;oBACrC,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC;oBACzC,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC;oBACxB,MAAM,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;oBAC3C,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;oBAElC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;wBACvB,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,OAAO,EAAE,IAAI,CAAC,OAAO;wBACrB,UAAU,EAAE,KAAK,CAAC,SAAS;wBAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;wBACjB,MAAM,EAAE;4BACN,cAAc,EAAE,OAAO,CAAC,cAAc;4BACtC,SAAS,EAAE,OAAO,CAAC,SAAS;4BAC5B,KAAK,EAAE,OAAO,CAAC,KAAc;yBAC9B;qBACF,CAAC,CAAC;oBAEH,MAAM,OAAO,GAAG,SAAS;wBACvB,CAAC,CAAE,OAA+B,CAAC,MAAM;wBACzC,CAAC,CAAC,SAAS,CAAC;oBACd,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;oBACnE,MAAM,GAAG;wBACP,UAAU,EAAE,KAAK,CAAC,SAAS;wBAC3B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;wBACrC,QAAQ,EAAE,OAAO,CAAC,cAAc;wBAChC,SAAS,EAAE,OAAO,CAAC,SAAS;wBAC5B,cAAc,EAAE,OAAO;wBACvB,KAAK;qBACN,CAAC;oBACF,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE;wBAClC,MAAM,EAAE,MAAM,CAAC,MAAM;wBACrB,cAAc,EAAE,OAAO,IAAI,IAAI;wBAC/B,KAAK,EAAE,KAAK,IAAI,IAAI;wBACpB,UAAU,EAAE,KAAK,CAAC,SAAS;qBAC5B,CAAC,CAAC;oBACH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;wBACf,IAAI,EAAE,YAAY;wBAClB,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,OAAO,EAAE;4BACP,OAAO,EAAE,IAAI,CAAC,OAAO;4BACrB,QAAQ,EAAE,EAAE;4BACZ,MAAM,EAAE,MAAM,CAAC,MAAM;4BACrB,KAAK;yBACN;qBACF,CAAC,CAAC;oBACH,MAAM;gBACR,CAAC;gBACD;oBACE,MAAM;YACV,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree lifecycle for scope isolation (spec 002 §R7–§R8, §R12).
|
|
3
|
+
* Projects in `worktree` mode run each scope's workers in a dedicated worktree
|
|
4
|
+
* on an `orc/<goal>/<scope>` branch forked from the run's base branch. On scope
|
|
5
|
+
* success the worktree is removed (after a safety-net commit if dirty) and the
|
|
6
|
+
* branch is kept for manual merge; on failure the worktree stays for debugging.
|
|
7
|
+
* Git subprocesses run with the stripped spawn env (§N1) — uniform with workers.
|
|
8
|
+
*/
|
|
9
|
+
/** Injectable git runner (tests exercise failure paths without a repo). */
|
|
10
|
+
export type GitRunner = (args: string[], cwd: string) => string;
|
|
11
|
+
/** Runs git synchronously with provider credentials stripped (§N1). */
|
|
12
|
+
export declare const defaultGitRunner: GitRunner;
|
|
13
|
+
/** Kebab-case slug for branch components (§R8): ≤ 40 chars, git-ref safe. */
|
|
14
|
+
export declare function slugify(name: string, cap?: number): string;
|
|
15
|
+
/** A created/attached scope worktree. */
|
|
16
|
+
export interface ScopeWorktree {
|
|
17
|
+
path: string;
|
|
18
|
+
branch: string;
|
|
19
|
+
}
|
|
20
|
+
/** Manages scope worktrees under `<stateDir>/worktrees/<run>/<scope>` (§R8). */
|
|
21
|
+
export declare class WorktreeManager {
|
|
22
|
+
private readonly stateDir;
|
|
23
|
+
private readonly git;
|
|
24
|
+
constructor(stateDir: string, git?: GitRunner);
|
|
25
|
+
/** Root directory holding all scope worktrees. */
|
|
26
|
+
worktreesRoot(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Creates (or re-attaches after a crash) the worktree for a scope, on branch
|
|
29
|
+
* `orc/<goal-slug>/<scope-slug>` forked from `baseBranch` (§R8). Branch-name
|
|
30
|
+
* collisions (two scopes slugging identically) get a numeric suffix.
|
|
31
|
+
*/
|
|
32
|
+
ensureScopeWorktree(input: {
|
|
33
|
+
repoRoot: string;
|
|
34
|
+
runId: string;
|
|
35
|
+
scopeId: string;
|
|
36
|
+
goalTitle: string;
|
|
37
|
+
scopeName: string;
|
|
38
|
+
baseBranch: string | null;
|
|
39
|
+
}): ScopeWorktree;
|
|
40
|
+
/**
|
|
41
|
+
* Releases a scope worktree on success (§R8): commits any leftover dirt as a
|
|
42
|
+
* safety net (uncommitted work must never be lost with the worktree), then
|
|
43
|
+
* removes the worktree. The branch is always kept.
|
|
44
|
+
*/
|
|
45
|
+
releaseScopeWorktree(worktreePath: string, repoRoot: string, scopeName: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Attempts to merge a settled scope branch into the base branch (spec 002
|
|
48
|
+
* v2, opt-in per project). Deliberately conservative — it only merges when
|
|
49
|
+
* the checkout at `repoRoot` is ON the base branch and CLEAN, and a
|
|
50
|
+
* conflicted merge is aborted. In every skip/failure case the branch simply
|
|
51
|
+
* stays for manual merge, exactly like the default flow.
|
|
52
|
+
*/
|
|
53
|
+
mergeScopeBranch(repoRoot: string, branch: string, baseBranch: string, scopeName: string): {
|
|
54
|
+
merged: boolean;
|
|
55
|
+
reason?: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Deletes `orc/*` branches already fully merged into `baseBranch`
|
|
59
|
+
* (`orc project gc --prune-merged`, spec 002 v2). `git branch -d` only —
|
|
60
|
+
* an unmerged branch can never be deleted here.
|
|
61
|
+
*/
|
|
62
|
+
pruneMergedBranches(repoRoot: string, baseBranch: string): string[];
|
|
63
|
+
/**
|
|
64
|
+
* Worktree directories on disk that no live scope references (§R12) — the
|
|
65
|
+
* residue of crashes or kept-on-failure scopes whose runs are long gone.
|
|
66
|
+
*/
|
|
67
|
+
listOrphans(livePaths: ReadonlySet<string>): string[];
|
|
68
|
+
/**
|
|
69
|
+
* Removes an orphaned worktree directory (§R12). Never deletes branches.
|
|
70
|
+
* Falls back to a plain directory removal when git no longer tracks it.
|
|
71
|
+
*/
|
|
72
|
+
removeOrphan(path: string, repoRoot: string): void;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=worktrees.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktrees.d.ts","sourceRoot":"","sources":["../src/worktrees.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,2EAA2E;AAC3E,MAAM,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;AAEhE,uEAAuE;AACvE,eAAO,MAAM,gBAAgB,EAAE,SAM3B,CAAC;AAEL,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,CAQtD;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gFAAgF;AAChF,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,SAA4B;IAGpD,kDAAkD;IAClD,aAAa,IAAI,MAAM;IAIvB;;;;OAIG;IACH,mBAAmB,CAAC,KAAK,EAAE;QACzB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,GAAG,aAAa;IAgCjB;;;;OAIG;IACH,oBAAoB,CAClB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,IAAI;IAsBP;;;;;;OAMG;IACH,gBAAgB,CACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAwCvC;;;;OAIG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IA2BnE;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE;IAerD;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAYnD"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git worktree lifecycle for scope isolation (spec 002 §R7–§R8, §R12).
|
|
3
|
+
* Projects in `worktree` mode run each scope's workers in a dedicated worktree
|
|
4
|
+
* on an `orc/<goal>/<scope>` branch forked from the run's base branch. On scope
|
|
5
|
+
* success the worktree is removed (after a safety-net commit if dirty) and the
|
|
6
|
+
* branch is kept for manual merge; on failure the worktree stays for debugging.
|
|
7
|
+
* Git subprocesses run with the stripped spawn env (§N1) — uniform with workers.
|
|
8
|
+
*/
|
|
9
|
+
import { execFileSync } from "node:child_process";
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { buildSpawnEnv } from "./spawnEnv.js";
|
|
13
|
+
/** Runs git synchronously with provider credentials stripped (§N1). */
|
|
14
|
+
export const defaultGitRunner = (args, cwd) => execFileSync("git", args, {
|
|
15
|
+
cwd,
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
18
|
+
env: buildSpawnEnv(),
|
|
19
|
+
});
|
|
20
|
+
/** Kebab-case slug for branch components (§R8): ≤ 40 chars, git-ref safe. */
|
|
21
|
+
export function slugify(name, cap = 40) {
|
|
22
|
+
const slug = name
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
25
|
+
.replace(/^-+|-+$/g, "")
|
|
26
|
+
.slice(0, cap)
|
|
27
|
+
.replace(/-+$/, "");
|
|
28
|
+
return slug || "unnamed";
|
|
29
|
+
}
|
|
30
|
+
/** Manages scope worktrees under `<stateDir>/worktrees/<run>/<scope>` (§R8). */
|
|
31
|
+
export class WorktreeManager {
|
|
32
|
+
stateDir;
|
|
33
|
+
git;
|
|
34
|
+
constructor(stateDir, git = defaultGitRunner) {
|
|
35
|
+
this.stateDir = stateDir;
|
|
36
|
+
this.git = git;
|
|
37
|
+
}
|
|
38
|
+
/** Root directory holding all scope worktrees. */
|
|
39
|
+
worktreesRoot() {
|
|
40
|
+
return join(this.stateDir, "worktrees");
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates (or re-attaches after a crash) the worktree for a scope, on branch
|
|
44
|
+
* `orc/<goal-slug>/<scope-slug>` forked from `baseBranch` (§R8). Branch-name
|
|
45
|
+
* collisions (two scopes slugging identically) get a numeric suffix.
|
|
46
|
+
*/
|
|
47
|
+
ensureScopeWorktree(input) {
|
|
48
|
+
const path = join(this.worktreesRoot(), input.runId, input.scopeId);
|
|
49
|
+
// Crash recovery: the worktree already exists — reuse it and its branch.
|
|
50
|
+
if (existsSync(join(path, ".git"))) {
|
|
51
|
+
const branch = this.git(["rev-parse", "--abbrev-ref", "HEAD"], path).trim();
|
|
52
|
+
return { path, branch };
|
|
53
|
+
}
|
|
54
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
55
|
+
const base = `orc/${slugify(input.goalTitle)}/${slugify(input.scopeName)}`;
|
|
56
|
+
let lastError;
|
|
57
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
58
|
+
const branch = attempt === 0 ? base : `${base}-${attempt + 1}`;
|
|
59
|
+
const args = ["worktree", "add", path, "-b", branch];
|
|
60
|
+
if (input.baseBranch)
|
|
61
|
+
args.push(input.baseBranch);
|
|
62
|
+
try {
|
|
63
|
+
this.git(args, input.repoRoot);
|
|
64
|
+
return { path, branch };
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
lastError = err;
|
|
68
|
+
// Only a branch-name collision is retried with a suffix.
|
|
69
|
+
if (!/already exists/i.test(String(err)))
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`git worktree add failed for scope ${input.scopeId}: ${String(lastError)}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Releases a scope worktree on success (§R8): commits any leftover dirt as a
|
|
77
|
+
* safety net (uncommitted work must never be lost with the worktree), then
|
|
78
|
+
* removes the worktree. The branch is always kept.
|
|
79
|
+
*/
|
|
80
|
+
releaseScopeWorktree(worktreePath, repoRoot, scopeName) {
|
|
81
|
+
if (!existsSync(worktreePath))
|
|
82
|
+
return;
|
|
83
|
+
const status = this.git(["status", "--porcelain"], worktreePath);
|
|
84
|
+
if (status.trim()) {
|
|
85
|
+
this.git(["add", "-A"], worktreePath);
|
|
86
|
+
// Explicit identity so the safety-net commit works without repo config.
|
|
87
|
+
this.git([
|
|
88
|
+
"-c",
|
|
89
|
+
"user.name=orc-brain",
|
|
90
|
+
"-c",
|
|
91
|
+
"user.email=orc@localhost",
|
|
92
|
+
"commit",
|
|
93
|
+
"-m",
|
|
94
|
+
`orc: auto-commit remaining changes for ${scopeName}`,
|
|
95
|
+
], worktreePath);
|
|
96
|
+
}
|
|
97
|
+
this.git(["worktree", "remove", "--force", worktreePath], repoRoot);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Attempts to merge a settled scope branch into the base branch (spec 002
|
|
101
|
+
* v2, opt-in per project). Deliberately conservative — it only merges when
|
|
102
|
+
* the checkout at `repoRoot` is ON the base branch and CLEAN, and a
|
|
103
|
+
* conflicted merge is aborted. In every skip/failure case the branch simply
|
|
104
|
+
* stays for manual merge, exactly like the default flow.
|
|
105
|
+
*/
|
|
106
|
+
mergeScopeBranch(repoRoot, branch, baseBranch, scopeName) {
|
|
107
|
+
const current = this.git(["rev-parse", "--abbrev-ref", "HEAD"], repoRoot).trim();
|
|
108
|
+
if (current !== baseBranch) {
|
|
109
|
+
return {
|
|
110
|
+
merged: false,
|
|
111
|
+
reason: `checkout is on '${current}', not base branch '${baseBranch}'`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (this.git(["status", "--porcelain"], repoRoot).trim()) {
|
|
115
|
+
return { merged: false, reason: "checkout has uncommitted changes" };
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
this.git([
|
|
119
|
+
"-c",
|
|
120
|
+
"user.name=orc-brain",
|
|
121
|
+
"-c",
|
|
122
|
+
"user.email=orc@localhost",
|
|
123
|
+
"merge",
|
|
124
|
+
"--no-ff",
|
|
125
|
+
"-m",
|
|
126
|
+
`orc: merge ${branch} (scope ${scopeName})`,
|
|
127
|
+
branch,
|
|
128
|
+
], repoRoot);
|
|
129
|
+
return { merged: true };
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
try {
|
|
133
|
+
this.git(["merge", "--abort"], repoRoot);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Nothing in progress to abort.
|
|
137
|
+
}
|
|
138
|
+
return { merged: false, reason: `merge failed: ${String(err)}` };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Deletes `orc/*` branches already fully merged into `baseBranch`
|
|
143
|
+
* (`orc project gc --prune-merged`, spec 002 v2). `git branch -d` only —
|
|
144
|
+
* an unmerged branch can never be deleted here.
|
|
145
|
+
*/
|
|
146
|
+
pruneMergedBranches(repoRoot, baseBranch) {
|
|
147
|
+
const out = this.git([
|
|
148
|
+
"branch",
|
|
149
|
+
"--merged",
|
|
150
|
+
baseBranch,
|
|
151
|
+
"--list",
|
|
152
|
+
"orc/*",
|
|
153
|
+
"--format=%(refname:short)",
|
|
154
|
+
], repoRoot);
|
|
155
|
+
const pruned = [];
|
|
156
|
+
for (const branch of out
|
|
157
|
+
.split("\n")
|
|
158
|
+
.map((b) => b.trim())
|
|
159
|
+
.filter(Boolean)) {
|
|
160
|
+
try {
|
|
161
|
+
this.git(["branch", "-d", branch], repoRoot);
|
|
162
|
+
pruned.push(branch);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Checked out in a live worktree, etc. — leave it.
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return pruned;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Worktree directories on disk that no live scope references (§R12) — the
|
|
172
|
+
* residue of crashes or kept-on-failure scopes whose runs are long gone.
|
|
173
|
+
*/
|
|
174
|
+
listOrphans(livePaths) {
|
|
175
|
+
const root = this.worktreesRoot();
|
|
176
|
+
if (!existsSync(root))
|
|
177
|
+
return [];
|
|
178
|
+
const orphans = [];
|
|
179
|
+
for (const runDir of readdirSync(root)) {
|
|
180
|
+
const runPath = join(root, runDir);
|
|
181
|
+
if (!statSync(runPath).isDirectory())
|
|
182
|
+
continue;
|
|
183
|
+
for (const scopeDir of readdirSync(runPath)) {
|
|
184
|
+
const p = join(runPath, scopeDir);
|
|
185
|
+
if (!livePaths.has(p))
|
|
186
|
+
orphans.push(p);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return orphans;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Removes an orphaned worktree directory (§R12). Never deletes branches.
|
|
193
|
+
* Falls back to a plain directory removal when git no longer tracks it.
|
|
194
|
+
*/
|
|
195
|
+
removeOrphan(path, repoRoot) {
|
|
196
|
+
try {
|
|
197
|
+
this.git(["worktree", "remove", "--force", path], repoRoot);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
rmSync(path, { recursive: true, force: true });
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
this.git(["worktree", "prune"], repoRoot);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Best-effort: the repo may be gone entirely.
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=worktrees.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktrees.js","sourceRoot":"","sources":["../src/worktrees.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@orc-brain/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Orchestration engine for orc-brain: planner, dispatch loop, safety layer, store.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Paulo Lima",
|
|
8
|
+
"homepage": "https://github.com/anplabs/orc-brain#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/anplabs/orc-brain.git",
|
|
12
|
+
"directory": "packages/core"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.201",
|
|
33
|
+
"better-sqlite3": "^12.11.1",
|
|
34
|
+
"shell-quote": "^1.9.0",
|
|
35
|
+
"ulid": "^3.0.2",
|
|
36
|
+
"@orc-brain/plugin-linear": "1.0.0",
|
|
37
|
+
"@orc-brain/shared": "1.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
41
|
+
"@types/node": "^22.10.7",
|
|
42
|
+
"@types/shell-quote": "^1.7.5"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc -p tsconfig.json",
|
|
46
|
+
"clean": "rm -rf dist"
|
|
47
|
+
}
|
|
48
|
+
}
|