opencode-swarm 7.0.1 → 7.0.3
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/README.md +4 -3
- package/dist/__tests__/convene-general-council.test.d.ts +4 -2
- package/dist/agents/council-prompts.d.ts +26 -0
- package/dist/agents/council-prompts.test.d.ts +9 -0
- package/dist/agents/council-registration.test.d.ts +23 -0
- package/dist/agents/index.d.ts +1 -2
- package/dist/cli/index.js +1018 -565
- package/dist/commands/registry.d.ts +3 -3
- package/dist/config/constants.d.ts +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/loader.d.ts +8 -0
- package/dist/council/general-council-advisory.d.ts +1 -1
- package/dist/council/general-council-types.d.ts +44 -17
- package/dist/hooks/__tests__/repo-graph-builder.test.d.ts +12 -0
- package/dist/hooks/repo-graph-builder.d.ts +13 -1
- package/dist/index.js +1976 -1536
- package/dist/tools/__tests__/repo-graph-walk.test.d.ts +16 -0
- package/dist/tools/convene-general-council.d.ts +5 -4
- package/dist/tools/repo-graph.d.ts +16 -2
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/utils/__tests__/bun-compat.test.d.ts +11 -0
- package/dist/utils/__tests__/timeout.test.d.ts +12 -0
- package/dist/utils/bun-compat.d.ts +106 -0
- package/dist/utils/timeout.d.ts +23 -0
- package/package.json +3 -2
- package/dist/agents/council-member.d.ts +0 -30
- package/dist/agents/council-member.test.d.ts +0 -8
- package/dist/agents/council-moderator.d.ts +0 -20
package/dist/cli/index.js
CHANGED
|
@@ -99,8 +99,335 @@ var init_utils = __esm(() => {
|
|
|
99
99
|
init_logger();
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
// src/
|
|
102
|
+
// src/utils/bun-compat.ts
|
|
103
|
+
import {
|
|
104
|
+
spawn as nodeSpawn,
|
|
105
|
+
spawnSync as nodeSpawnSync
|
|
106
|
+
} from "child_process";
|
|
107
|
+
import * as fsSync from "fs";
|
|
108
|
+
import * as fsPromises from "fs/promises";
|
|
103
109
|
import * as path from "path";
|
|
110
|
+
function getBun() {
|
|
111
|
+
const g = globalThis;
|
|
112
|
+
return g.Bun;
|
|
113
|
+
}
|
|
114
|
+
function bunFile(filePath) {
|
|
115
|
+
const bun = getBun();
|
|
116
|
+
if (bun?.file) {
|
|
117
|
+
return bun.file(filePath);
|
|
118
|
+
}
|
|
119
|
+
let cachedSize;
|
|
120
|
+
return {
|
|
121
|
+
async text() {
|
|
122
|
+
return fsPromises.readFile(filePath, "utf-8");
|
|
123
|
+
},
|
|
124
|
+
async arrayBuffer() {
|
|
125
|
+
const buf = await fsPromises.readFile(filePath);
|
|
126
|
+
const ab = new ArrayBuffer(buf.byteLength);
|
|
127
|
+
new Uint8Array(ab).set(buf);
|
|
128
|
+
return ab;
|
|
129
|
+
},
|
|
130
|
+
async exists() {
|
|
131
|
+
try {
|
|
132
|
+
await fsPromises.access(filePath, fsSync.constants.F_OK);
|
|
133
|
+
return true;
|
|
134
|
+
} catch {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
get size() {
|
|
139
|
+
if (cachedSize !== undefined)
|
|
140
|
+
return cachedSize;
|
|
141
|
+
try {
|
|
142
|
+
cachedSize = fsSync.statSync(filePath).size;
|
|
143
|
+
} catch {
|
|
144
|
+
cachedSize = 0;
|
|
145
|
+
}
|
|
146
|
+
return cachedSize;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
async function bunWrite(filePath, data) {
|
|
151
|
+
const bun = getBun();
|
|
152
|
+
if (bun?.write) {
|
|
153
|
+
return bun.write(filePath, data);
|
|
154
|
+
}
|
|
155
|
+
const dir = path.dirname(filePath);
|
|
156
|
+
const tempName = `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${tempCounter++}.${Math.random().toString(36).slice(2, 10)}.tmp`;
|
|
157
|
+
const tempPath = path.join(dir, tempName);
|
|
158
|
+
let buffer;
|
|
159
|
+
if (typeof data === "string") {
|
|
160
|
+
buffer = data;
|
|
161
|
+
} else if (data instanceof ArrayBuffer) {
|
|
162
|
+
buffer = new Uint8Array(data);
|
|
163
|
+
} else if (ArrayBuffer.isView(data)) {
|
|
164
|
+
buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
165
|
+
} else {
|
|
166
|
+
buffer = new Uint8Array(0);
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
170
|
+
} catch {}
|
|
171
|
+
await fsPromises.writeFile(tempPath, buffer);
|
|
172
|
+
let lastError;
|
|
173
|
+
for (let attempt = 0;attempt < WINDOWS_RENAME_MAX_RETRIES; attempt++) {
|
|
174
|
+
try {
|
|
175
|
+
await fsPromises.rename(tempPath, filePath);
|
|
176
|
+
lastError = undefined;
|
|
177
|
+
break;
|
|
178
|
+
} catch (err) {
|
|
179
|
+
lastError = err;
|
|
180
|
+
const code = err.code;
|
|
181
|
+
if (code !== "EEXIST" && code !== "EBUSY" && code !== "EPERM") {
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
await new Promise((r) => setTimeout(r, WINDOWS_RENAME_RETRY_DELAY_MS));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (lastError) {
|
|
188
|
+
try {
|
|
189
|
+
await fsPromises.unlink(tempPath);
|
|
190
|
+
} catch {}
|
|
191
|
+
throw lastError;
|
|
192
|
+
}
|
|
193
|
+
const stats = await fsPromises.stat(filePath);
|
|
194
|
+
return stats.size;
|
|
195
|
+
}
|
|
196
|
+
function bunHash(input) {
|
|
197
|
+
const bun = getBun();
|
|
198
|
+
if (bun?.hash) {
|
|
199
|
+
const r = bun.hash(input);
|
|
200
|
+
return typeof r === "bigint" ? r : BigInt(r);
|
|
201
|
+
}
|
|
202
|
+
let bytes;
|
|
203
|
+
if (typeof input === "string") {
|
|
204
|
+
bytes = new TextEncoder().encode(input);
|
|
205
|
+
} else if (input instanceof ArrayBuffer) {
|
|
206
|
+
bytes = new Uint8Array(input);
|
|
207
|
+
} else {
|
|
208
|
+
bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
209
|
+
}
|
|
210
|
+
let hash = 5381n;
|
|
211
|
+
for (const b of bytes) {
|
|
212
|
+
hash = hash * 33n + BigInt(b) & 0xffffffffffffffffn;
|
|
213
|
+
}
|
|
214
|
+
return hash;
|
|
215
|
+
}
|
|
216
|
+
function streamFromNode(pipe) {
|
|
217
|
+
const collected = new Promise((resolve) => {
|
|
218
|
+
if (!pipe) {
|
|
219
|
+
resolve(Buffer.alloc(0));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const chunks = [];
|
|
223
|
+
pipe.on("data", (chunk) => {
|
|
224
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
225
|
+
});
|
|
226
|
+
pipe.on("end", () => resolve(Buffer.concat(chunks)));
|
|
227
|
+
pipe.on("error", () => resolve(Buffer.concat(chunks)));
|
|
228
|
+
});
|
|
229
|
+
const toWebReadable = () => {
|
|
230
|
+
if (!pipe) {
|
|
231
|
+
return new ReadableStream({
|
|
232
|
+
start(controller) {
|
|
233
|
+
controller.close();
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const r = pipe;
|
|
238
|
+
if (typeof r.toWeb === "function") {
|
|
239
|
+
return r.toWeb();
|
|
240
|
+
}
|
|
241
|
+
return new ReadableStream({
|
|
242
|
+
start(controller) {
|
|
243
|
+
pipe.on("data", (chunk) => {
|
|
244
|
+
controller.enqueue(typeof chunk === "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
245
|
+
});
|
|
246
|
+
pipe.on("end", () => controller.close());
|
|
247
|
+
pipe.on("error", (err) => controller.error(err));
|
|
248
|
+
},
|
|
249
|
+
cancel() {
|
|
250
|
+
const destroyable = pipe;
|
|
251
|
+
if (typeof destroyable.destroy === "function") {
|
|
252
|
+
try {
|
|
253
|
+
destroyable.destroy();
|
|
254
|
+
} catch {}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
return {
|
|
260
|
+
async text() {
|
|
261
|
+
return (await collected).toString("utf-8");
|
|
262
|
+
},
|
|
263
|
+
async bytes() {
|
|
264
|
+
const b = await collected;
|
|
265
|
+
return new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
|
|
266
|
+
},
|
|
267
|
+
getReader() {
|
|
268
|
+
return toWebReadable().getReader();
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function mapStdio(v) {
|
|
273
|
+
return v ?? "pipe";
|
|
274
|
+
}
|
|
275
|
+
function streamFromBun(stream) {
|
|
276
|
+
if (!stream || typeof stream !== "object") {
|
|
277
|
+
const empty = {
|
|
278
|
+
async text() {
|
|
279
|
+
return "";
|
|
280
|
+
},
|
|
281
|
+
async bytes() {
|
|
282
|
+
return new Uint8Array(0);
|
|
283
|
+
},
|
|
284
|
+
getReader() {
|
|
285
|
+
return new ReadableStream({
|
|
286
|
+
start(controller) {
|
|
287
|
+
controller.close();
|
|
288
|
+
}
|
|
289
|
+
}).getReader();
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
return empty;
|
|
293
|
+
}
|
|
294
|
+
const candidate = stream;
|
|
295
|
+
const collect = async () => {
|
|
296
|
+
if (typeof candidate.getReader !== "function") {
|
|
297
|
+
return new Uint8Array(0);
|
|
298
|
+
}
|
|
299
|
+
const reader = candidate.getReader();
|
|
300
|
+
const chunks = [];
|
|
301
|
+
for (;; ) {
|
|
302
|
+
const { done, value } = await reader.read();
|
|
303
|
+
if (done)
|
|
304
|
+
break;
|
|
305
|
+
if (value)
|
|
306
|
+
chunks.push(value);
|
|
307
|
+
}
|
|
308
|
+
const total = chunks.reduce((acc, c) => acc + c.byteLength, 0);
|
|
309
|
+
const out = new Uint8Array(total);
|
|
310
|
+
let off = 0;
|
|
311
|
+
for (const c of chunks) {
|
|
312
|
+
out.set(c, off);
|
|
313
|
+
off += c.byteLength;
|
|
314
|
+
}
|
|
315
|
+
return out;
|
|
316
|
+
};
|
|
317
|
+
const text = typeof candidate.text === "function" ? () => candidate.text() : async () => new TextDecoder().decode(await collect());
|
|
318
|
+
const bytes = typeof candidate.bytes === "function" ? () => candidate.bytes() : collect;
|
|
319
|
+
const getReader = typeof candidate.getReader === "function" ? () => candidate.getReader() : () => new ReadableStream({
|
|
320
|
+
start(controller) {
|
|
321
|
+
controller.close();
|
|
322
|
+
}
|
|
323
|
+
}).getReader();
|
|
324
|
+
return { text, bytes, getReader };
|
|
325
|
+
}
|
|
326
|
+
function bunSpawn(cmd, options) {
|
|
327
|
+
const bun = getBun();
|
|
328
|
+
if (bun?.spawn) {
|
|
329
|
+
const proc2 = bun.spawn(cmd, options);
|
|
330
|
+
return {
|
|
331
|
+
stdout: streamFromBun(proc2.stdout),
|
|
332
|
+
stderr: streamFromBun(proc2.stderr),
|
|
333
|
+
exited: proc2.exited,
|
|
334
|
+
get exitCode() {
|
|
335
|
+
return proc2.exitCode;
|
|
336
|
+
},
|
|
337
|
+
kill(sig) {
|
|
338
|
+
proc2.kill(sig);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
const [file, ...args] = cmd;
|
|
343
|
+
const proc = nodeSpawn(file, args, {
|
|
344
|
+
cwd: options?.cwd,
|
|
345
|
+
env: options?.env,
|
|
346
|
+
stdio: [
|
|
347
|
+
mapStdio(options?.stdin),
|
|
348
|
+
mapStdio(options?.stdout),
|
|
349
|
+
mapStdio(options?.stderr)
|
|
350
|
+
]
|
|
351
|
+
});
|
|
352
|
+
let timeoutHandle;
|
|
353
|
+
const exited = new Promise((resolve) => {
|
|
354
|
+
proc.on("exit", (code) => resolve(code ?? 0));
|
|
355
|
+
proc.on("error", () => resolve(1));
|
|
356
|
+
if (options?.timeout && options.timeout > 0) {
|
|
357
|
+
timeoutHandle = setTimeout(() => {
|
|
358
|
+
try {
|
|
359
|
+
proc.kill("SIGKILL");
|
|
360
|
+
} catch {}
|
|
361
|
+
}, options.timeout);
|
|
362
|
+
if (typeof timeoutHandle.unref === "function") {
|
|
363
|
+
timeoutHandle.unref();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}).finally(() => {
|
|
367
|
+
if (timeoutHandle !== undefined)
|
|
368
|
+
clearTimeout(timeoutHandle);
|
|
369
|
+
});
|
|
370
|
+
return {
|
|
371
|
+
stdout: streamFromNode(proc.stdout),
|
|
372
|
+
stderr: streamFromNode(proc.stderr),
|
|
373
|
+
exited,
|
|
374
|
+
get exitCode() {
|
|
375
|
+
return proc.exitCode;
|
|
376
|
+
},
|
|
377
|
+
kill(signal) {
|
|
378
|
+
try {
|
|
379
|
+
proc.kill(signal);
|
|
380
|
+
} catch {}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function bunSpawnSync(cmd, options) {
|
|
385
|
+
const bun = getBun();
|
|
386
|
+
if (bun?.spawnSync) {
|
|
387
|
+
const result2 = bun.spawnSync(cmd, options);
|
|
388
|
+
return result2;
|
|
389
|
+
}
|
|
390
|
+
let argv;
|
|
391
|
+
let mergedOptions;
|
|
392
|
+
if (Array.isArray(cmd)) {
|
|
393
|
+
argv = cmd;
|
|
394
|
+
mergedOptions = { ...options ?? {} };
|
|
395
|
+
} else {
|
|
396
|
+
argv = cmd.cmd;
|
|
397
|
+
mergedOptions = {
|
|
398
|
+
cwd: cmd.cwd,
|
|
399
|
+
env: cmd.env,
|
|
400
|
+
stdin: "pipe",
|
|
401
|
+
timeout: cmd.timeout,
|
|
402
|
+
...options ?? {}
|
|
403
|
+
};
|
|
404
|
+
if (cmd.stdin !== undefined) {
|
|
405
|
+
mergedOptions.stdin = cmd.stdin;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const [file, ...args] = argv;
|
|
409
|
+
const result = nodeSpawnSync(file, args, {
|
|
410
|
+
cwd: mergedOptions.cwd,
|
|
411
|
+
env: mergedOptions.env,
|
|
412
|
+
input: mergedOptions.stdin instanceof Uint8Array || typeof mergedOptions.stdin === "string" ? mergedOptions.stdin : undefined,
|
|
413
|
+
timeout: mergedOptions.timeout,
|
|
414
|
+
windowsHide: true
|
|
415
|
+
});
|
|
416
|
+
const stdout = result.stdout instanceof Buffer ? new Uint8Array(result.stdout.buffer, result.stdout.byteOffset, result.stdout.byteLength) : typeof result.stdout === "string" ? new TextEncoder().encode(result.stdout) : new Uint8Array(0);
|
|
417
|
+
const stderr = result.stderr instanceof Buffer ? new Uint8Array(result.stderr.buffer, result.stderr.byteOffset, result.stderr.byteLength) : typeof result.stderr === "string" ? new TextEncoder().encode(result.stderr) : new Uint8Array(0);
|
|
418
|
+
const exitCode = result.status ?? (result.signal ? 128 : 1);
|
|
419
|
+
return {
|
|
420
|
+
stdout,
|
|
421
|
+
stderr,
|
|
422
|
+
exitCode,
|
|
423
|
+
success: exitCode === 0 && !result.error
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
var WINDOWS_RENAME_MAX_RETRIES = 3, WINDOWS_RENAME_RETRY_DELAY_MS = 50, tempCounter = 0;
|
|
427
|
+
var init_bun_compat = () => {};
|
|
428
|
+
|
|
429
|
+
// src/hooks/utils.ts
|
|
430
|
+
import * as path2 from "path";
|
|
104
431
|
function validateSwarmPath(directory, filename) {
|
|
105
432
|
if (/[\0]/.test(filename)) {
|
|
106
433
|
throw new Error("Invalid filename: contains null bytes");
|
|
@@ -114,14 +441,14 @@ function validateSwarmPath(directory, filename) {
|
|
|
114
441
|
if (filename.startsWith("/")) {
|
|
115
442
|
throw new Error("Invalid filename: path escapes .swarm directory");
|
|
116
443
|
}
|
|
117
|
-
const baseDir =
|
|
118
|
-
const resolved =
|
|
444
|
+
const baseDir = path2.normalize(path2.resolve(directory, ".swarm"));
|
|
445
|
+
const resolved = path2.normalize(path2.resolve(baseDir, filename));
|
|
119
446
|
if (process.platform === "win32") {
|
|
120
|
-
if (!resolved.toLowerCase().startsWith((baseDir +
|
|
447
|
+
if (!resolved.toLowerCase().startsWith((baseDir + path2.sep).toLowerCase())) {
|
|
121
448
|
throw new Error("Invalid filename: path escapes .swarm directory");
|
|
122
449
|
}
|
|
123
450
|
} else {
|
|
124
|
-
if (!resolved.startsWith(baseDir +
|
|
451
|
+
if (!resolved.startsWith(baseDir + path2.sep)) {
|
|
125
452
|
throw new Error("Invalid filename: path escapes .swarm directory");
|
|
126
453
|
}
|
|
127
454
|
}
|
|
@@ -130,7 +457,7 @@ function validateSwarmPath(directory, filename) {
|
|
|
130
457
|
async function readSwarmFileAsync(directory, filename) {
|
|
131
458
|
try {
|
|
132
459
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
133
|
-
const file =
|
|
460
|
+
const file = bunFile(resolvedPath);
|
|
134
461
|
const content = await file.text();
|
|
135
462
|
return content;
|
|
136
463
|
} catch {
|
|
@@ -139,6 +466,7 @@ async function readSwarmFileAsync(directory, filename) {
|
|
|
139
466
|
}
|
|
140
467
|
var init_utils2 = __esm(() => {
|
|
141
468
|
init_utils();
|
|
469
|
+
init_bun_compat();
|
|
142
470
|
});
|
|
143
471
|
|
|
144
472
|
// node_modules/zod/v4/core/core.js
|
|
@@ -388,10 +716,10 @@ function mergeDefs(...defs) {
|
|
|
388
716
|
function cloneDef(schema) {
|
|
389
717
|
return mergeDefs(schema._zod.def);
|
|
390
718
|
}
|
|
391
|
-
function getElementAtPath(obj,
|
|
392
|
-
if (!
|
|
719
|
+
function getElementAtPath(obj, path3) {
|
|
720
|
+
if (!path3)
|
|
393
721
|
return obj;
|
|
394
|
-
return
|
|
722
|
+
return path3.reduce((acc, key) => acc?.[key], obj);
|
|
395
723
|
}
|
|
396
724
|
function promiseAllObject(promisesObj) {
|
|
397
725
|
const keys = Object.keys(promisesObj);
|
|
@@ -702,11 +1030,11 @@ function aborted(x, startIndex = 0) {
|
|
|
702
1030
|
}
|
|
703
1031
|
return false;
|
|
704
1032
|
}
|
|
705
|
-
function prefixIssues(
|
|
1033
|
+
function prefixIssues(path3, issues) {
|
|
706
1034
|
return issues.map((iss) => {
|
|
707
1035
|
var _a;
|
|
708
1036
|
(_a = iss).path ?? (_a.path = []);
|
|
709
|
-
iss.path.unshift(
|
|
1037
|
+
iss.path.unshift(path3);
|
|
710
1038
|
return iss;
|
|
711
1039
|
});
|
|
712
1040
|
}
|
|
@@ -944,7 +1272,7 @@ function formatError(error2, mapper = (issue2) => issue2.message) {
|
|
|
944
1272
|
}
|
|
945
1273
|
function treeifyError(error2, mapper = (issue2) => issue2.message) {
|
|
946
1274
|
const result = { errors: [] };
|
|
947
|
-
const processError = (error3,
|
|
1275
|
+
const processError = (error3, path3 = []) => {
|
|
948
1276
|
var _a, _b;
|
|
949
1277
|
for (const issue2 of error3.issues) {
|
|
950
1278
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -954,7 +1282,7 @@ function treeifyError(error2, mapper = (issue2) => issue2.message) {
|
|
|
954
1282
|
} else if (issue2.code === "invalid_element") {
|
|
955
1283
|
processError({ issues: issue2.issues }, issue2.path);
|
|
956
1284
|
} else {
|
|
957
|
-
const fullpath = [...
|
|
1285
|
+
const fullpath = [...path3, ...issue2.path];
|
|
958
1286
|
if (fullpath.length === 0) {
|
|
959
1287
|
result.errors.push(mapper(issue2));
|
|
960
1288
|
continue;
|
|
@@ -986,8 +1314,8 @@ function treeifyError(error2, mapper = (issue2) => issue2.message) {
|
|
|
986
1314
|
}
|
|
987
1315
|
function toDotPath(_path) {
|
|
988
1316
|
const segs = [];
|
|
989
|
-
const
|
|
990
|
-
for (const seg of
|
|
1317
|
+
const path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1318
|
+
for (const seg of path3) {
|
|
991
1319
|
if (typeof seg === "number")
|
|
992
1320
|
segs.push(`[${seg}]`);
|
|
993
1321
|
else if (typeof seg === "symbol")
|
|
@@ -13262,13 +13590,13 @@ function resolveRef(ref, ctx) {
|
|
|
13262
13590
|
if (!ref.startsWith("#")) {
|
|
13263
13591
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
13264
13592
|
}
|
|
13265
|
-
const
|
|
13266
|
-
if (
|
|
13593
|
+
const path3 = ref.slice(1).split("/").filter(Boolean);
|
|
13594
|
+
if (path3.length === 0) {
|
|
13267
13595
|
return ctx.rootSchema;
|
|
13268
13596
|
}
|
|
13269
13597
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
13270
|
-
if (
|
|
13271
|
-
const key =
|
|
13598
|
+
if (path3[0] === defsKey) {
|
|
13599
|
+
const key = path3[1];
|
|
13272
13600
|
if (!key || !ctx.defs[key]) {
|
|
13273
13601
|
throw new Error(`Reference not found: ${ref}`);
|
|
13274
13602
|
}
|
|
@@ -14103,13 +14431,13 @@ var init_telemetry = __esm(() => {
|
|
|
14103
14431
|
|
|
14104
14432
|
// src/utils/spec-hash.ts
|
|
14105
14433
|
import { createHash } from "crypto";
|
|
14106
|
-
import { readFile } from "fs/promises";
|
|
14107
|
-
import { join } from "path";
|
|
14434
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
14435
|
+
import { join as join2 } from "path";
|
|
14108
14436
|
async function computeSpecHash(directory) {
|
|
14109
|
-
const specPath =
|
|
14437
|
+
const specPath = join2(directory, ".swarm", "spec.md");
|
|
14110
14438
|
let hash2 = null;
|
|
14111
14439
|
try {
|
|
14112
|
-
const content = await
|
|
14440
|
+
const content = await readFile2(specPath, "utf-8");
|
|
14113
14441
|
hash2 = createHash("sha256").update(content, "utf-8").digest("hex");
|
|
14114
14442
|
} catch (error49) {
|
|
14115
14443
|
if (error49.code !== "ENOENT") {
|
|
@@ -14144,12 +14472,12 @@ var init_spec_hash = () => {};
|
|
|
14144
14472
|
// src/plan/ledger.ts
|
|
14145
14473
|
import * as crypto2 from "crypto";
|
|
14146
14474
|
import * as fs from "fs";
|
|
14147
|
-
import * as
|
|
14475
|
+
import * as path3 from "path";
|
|
14148
14476
|
function getLedgerPath(directory) {
|
|
14149
|
-
return
|
|
14477
|
+
return path3.join(directory, ".swarm", LEDGER_FILENAME);
|
|
14150
14478
|
}
|
|
14151
14479
|
function getPlanJsonPath(directory) {
|
|
14152
|
-
return
|
|
14480
|
+
return path3.join(directory, ".swarm", PLAN_JSON_FILENAME);
|
|
14153
14481
|
}
|
|
14154
14482
|
function computePlanHash(plan) {
|
|
14155
14483
|
const normalized = {
|
|
@@ -14280,7 +14608,7 @@ async function initLedger(directory, planId, initialPlanHash, initialPlan) {
|
|
|
14280
14608
|
schema_version: LEDGER_SCHEMA_VERSION,
|
|
14281
14609
|
...payload ? { payload } : {}
|
|
14282
14610
|
};
|
|
14283
|
-
fs.mkdirSync(
|
|
14611
|
+
fs.mkdirSync(path3.join(directory, ".swarm"), { recursive: true });
|
|
14284
14612
|
const tempPath = `${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
14285
14613
|
const line = `${JSON.stringify(event)}
|
|
14286
14614
|
`;
|
|
@@ -14307,7 +14635,7 @@ async function appendLedgerEvent(directory, eventInput, options) {
|
|
|
14307
14635
|
plan_hash_after: planHashAfter,
|
|
14308
14636
|
schema_version: LEDGER_SCHEMA_VERSION
|
|
14309
14637
|
};
|
|
14310
|
-
fs.mkdirSync(
|
|
14638
|
+
fs.mkdirSync(path3.join(directory, ".swarm"), { recursive: true });
|
|
14311
14639
|
const tempPath = `${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
14312
14640
|
const line = `${JSON.stringify(event)}
|
|
14313
14641
|
`;
|
|
@@ -14500,9 +14828,9 @@ async function readLedgerEventsWithIntegrity(directory) {
|
|
|
14500
14828
|
}
|
|
14501
14829
|
async function quarantineLedgerSuffix(directory, badSuffix) {
|
|
14502
14830
|
try {
|
|
14503
|
-
const quarantinePath =
|
|
14831
|
+
const quarantinePath = path3.join(directory, ".swarm", "plan-ledger.quarantine");
|
|
14504
14832
|
fs.writeFileSync(quarantinePath, badSuffix, "utf8");
|
|
14505
|
-
console.warn(`[ledger] Corrupted suffix quarantined to ${
|
|
14833
|
+
console.warn(`[ledger] Corrupted suffix quarantined to ${path3.relative(directory, quarantinePath)}`);
|
|
14506
14834
|
} catch {}
|
|
14507
14835
|
}
|
|
14508
14836
|
async function loadLastApprovedPlan(directory, expectedPlanId) {
|
|
@@ -14558,8 +14886,8 @@ import {
|
|
|
14558
14886
|
renameSync as renameSync2,
|
|
14559
14887
|
unlinkSync
|
|
14560
14888
|
} from "fs";
|
|
14561
|
-
import * as
|
|
14562
|
-
import * as
|
|
14889
|
+
import * as fsPromises2 from "fs/promises";
|
|
14890
|
+
import * as path4 from "path";
|
|
14563
14891
|
async function retryCasWithBackoff(directory, eventInput, options) {
|
|
14564
14892
|
const maxRetries = options.maxRetries ?? CAS_MAX_RETRIES;
|
|
14565
14893
|
let currentExpected = options.expectedHash;
|
|
@@ -14660,7 +14988,7 @@ function computePlanContentHash(plan) {
|
|
|
14660
14988
|
})).sort((a, b) => a.id - b.id)
|
|
14661
14989
|
};
|
|
14662
14990
|
const jsonString = JSON.stringify(content);
|
|
14663
|
-
return
|
|
14991
|
+
return bunHash(jsonString).toString(36);
|
|
14664
14992
|
}
|
|
14665
14993
|
function extractPlanHashFromMarkdown(markdown) {
|
|
14666
14994
|
const match = markdown.match(/<!--\s*PLAN_HASH:\s*(\S+)\s*-->/);
|
|
@@ -14685,15 +15013,15 @@ async function isPlanMdInSync(directory, plan) {
|
|
|
14685
15013
|
return normalizedActual.includes(normalizedExpected) || normalizedExpected.includes(normalizedActual.replace(/^#.*$/gm, "").trim());
|
|
14686
15014
|
}
|
|
14687
15015
|
async function regeneratePlanMarkdown(directory, plan) {
|
|
14688
|
-
const swarmDir =
|
|
15016
|
+
const swarmDir = path4.resolve(directory, ".swarm");
|
|
14689
15017
|
const contentHash = computePlanContentHash(plan);
|
|
14690
15018
|
const markdown = derivePlanMarkdown(plan);
|
|
14691
15019
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
14692
15020
|
${markdown}`;
|
|
14693
|
-
const mdPath =
|
|
14694
|
-
const mdTempPath =
|
|
15021
|
+
const mdPath = path4.join(swarmDir, "plan.md");
|
|
15022
|
+
const mdTempPath = path4.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
14695
15023
|
try {
|
|
14696
|
-
await
|
|
15024
|
+
await bunWrite(mdTempPath, markdownWithHash);
|
|
14697
15025
|
renameSync2(mdTempPath, mdPath);
|
|
14698
15026
|
} finally {
|
|
14699
15027
|
try {
|
|
@@ -14721,7 +15049,7 @@ async function loadPlan(directory) {
|
|
|
14721
15049
|
if (await ledgerExists(directory)) {
|
|
14722
15050
|
const planHash = computePlanHash(validated);
|
|
14723
15051
|
const ledgerHash = await getLatestLedgerHash(directory);
|
|
14724
|
-
const resolvedWorkspace =
|
|
15052
|
+
const resolvedWorkspace = path4.resolve(directory);
|
|
14725
15053
|
if (!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)) {
|
|
14726
15054
|
startupLedgerCheckedWorkspaces.add(resolvedWorkspace);
|
|
14727
15055
|
if (ledgerHash !== "" && planHash !== ledgerHash) {
|
|
@@ -14774,8 +15102,8 @@ async function loadPlan(directory) {
|
|
|
14774
15102
|
runtimePlan._specStale = true;
|
|
14775
15103
|
runtimePlan._specStaleReason = staleResult.reason;
|
|
14776
15104
|
try {
|
|
14777
|
-
const specStalenessPath =
|
|
14778
|
-
await
|
|
15105
|
+
const specStalenessPath = path4.join(directory, ".swarm", "spec-staleness.json");
|
|
15106
|
+
await fsPromises2.writeFile(specStalenessPath, JSON.stringify({
|
|
14779
15107
|
type: "spec_stale_detected",
|
|
14780
15108
|
timestamp: new Date().toISOString(),
|
|
14781
15109
|
phase: validated.current_phase ?? 1,
|
|
@@ -14786,7 +15114,7 @@ async function loadPlan(directory) {
|
|
|
14786
15114
|
}, null, 2), "utf-8");
|
|
14787
15115
|
} catch {}
|
|
14788
15116
|
try {
|
|
14789
|
-
const eventsPath =
|
|
15117
|
+
const eventsPath = path4.join(directory, ".swarm", "events.jsonl");
|
|
14790
15118
|
const event = {
|
|
14791
15119
|
type: "spec_stale_detected",
|
|
14792
15120
|
timestamp: new Date().toISOString(),
|
|
@@ -14796,7 +15124,7 @@ async function loadPlan(directory) {
|
|
|
14796
15124
|
reason: staleResult.reason ?? "unknown",
|
|
14797
15125
|
planTitle: validated.title
|
|
14798
15126
|
};
|
|
14799
|
-
await
|
|
15127
|
+
await fsPromises2.appendFile(eventsPath, `${JSON.stringify(event)}
|
|
14800
15128
|
`, "utf-8");
|
|
14801
15129
|
} catch {}
|
|
14802
15130
|
}
|
|
@@ -14842,7 +15170,7 @@ async function loadPlan(directory) {
|
|
|
14842
15170
|
return migrated;
|
|
14843
15171
|
}
|
|
14844
15172
|
if (await ledgerExists(directory)) {
|
|
14845
|
-
const resolvedDir =
|
|
15173
|
+
const resolvedDir = path4.resolve(directory);
|
|
14846
15174
|
const existingMutex = recoveryMutexes.get(resolvedDir);
|
|
14847
15175
|
if (existingMutex) {
|
|
14848
15176
|
await existingMutex;
|
|
@@ -14948,9 +15276,9 @@ async function savePlan(directory, plan, options) {
|
|
|
14948
15276
|
} else {
|
|
14949
15277
|
const existingEvents = await readLedgerEvents(directory);
|
|
14950
15278
|
if (existingEvents.length > 0 && existingEvents[0].plan_id !== planId) {
|
|
14951
|
-
const swarmDir2 =
|
|
14952
|
-
const oldLedgerPath =
|
|
14953
|
-
const oldLedgerBackupPath =
|
|
15279
|
+
const swarmDir2 = path4.resolve(directory, ".swarm");
|
|
15280
|
+
const oldLedgerPath = path4.join(swarmDir2, "plan-ledger.jsonl");
|
|
15281
|
+
const oldLedgerBackupPath = path4.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
|
|
14954
15282
|
let backupExists = false;
|
|
14955
15283
|
if (existsSync2(oldLedgerPath)) {
|
|
14956
15284
|
try {
|
|
@@ -14988,7 +15316,7 @@ async function savePlan(directory, plan, options) {
|
|
|
14988
15316
|
}
|
|
14989
15317
|
}
|
|
14990
15318
|
if (initSucceeded && backupExists) {
|
|
14991
|
-
const archivePath =
|
|
15319
|
+
const archivePath = path4.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
|
|
14992
15320
|
try {
|
|
14993
15321
|
renameSync2(oldLedgerBackupPath, archivePath);
|
|
14994
15322
|
warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
|
|
@@ -15013,7 +15341,7 @@ async function savePlan(directory, plan, options) {
|
|
|
15013
15341
|
const toRemove = archivedSiblings.slice(0, archivedSiblings.length - MAX_ARCHIVED_SIBLINGS);
|
|
15014
15342
|
for (const file2 of toRemove) {
|
|
15015
15343
|
try {
|
|
15016
|
-
unlinkSync(
|
|
15344
|
+
unlinkSync(path4.join(swarmDir2, file2));
|
|
15017
15345
|
} catch {}
|
|
15018
15346
|
}
|
|
15019
15347
|
}
|
|
@@ -15082,11 +15410,11 @@ async function savePlan(directory, plan, options) {
|
|
|
15082
15410
|
}
|
|
15083
15411
|
});
|
|
15084
15412
|
}
|
|
15085
|
-
const swarmDir =
|
|
15086
|
-
const planPath =
|
|
15087
|
-
const tempPath =
|
|
15413
|
+
const swarmDir = path4.resolve(directory, ".swarm");
|
|
15414
|
+
const planPath = path4.join(swarmDir, "plan.json");
|
|
15415
|
+
const tempPath = path4.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
15088
15416
|
try {
|
|
15089
|
-
await
|
|
15417
|
+
await bunWrite(tempPath, JSON.stringify(validated, null, 2));
|
|
15090
15418
|
renameSync2(tempPath, planPath);
|
|
15091
15419
|
} finally {
|
|
15092
15420
|
try {
|
|
@@ -15098,10 +15426,10 @@ async function savePlan(directory, plan, options) {
|
|
|
15098
15426
|
const markdown = derivePlanMarkdown(validated);
|
|
15099
15427
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
15100
15428
|
${markdown}`;
|
|
15101
|
-
const mdPath =
|
|
15102
|
-
const mdTempPath =
|
|
15429
|
+
const mdPath = path4.join(swarmDir, "plan.md");
|
|
15430
|
+
const mdTempPath = path4.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
15103
15431
|
try {
|
|
15104
|
-
await
|
|
15432
|
+
await bunWrite(mdTempPath, markdownWithHash);
|
|
15105
15433
|
renameSync2(mdTempPath, mdPath);
|
|
15106
15434
|
} finally {
|
|
15107
15435
|
try {
|
|
@@ -15120,7 +15448,7 @@ ${markdown}`;
|
|
|
15120
15448
|
} catch {}
|
|
15121
15449
|
}
|
|
15122
15450
|
try {
|
|
15123
|
-
const markerPath =
|
|
15451
|
+
const markerPath = path4.join(swarmDir, ".plan-write-marker");
|
|
15124
15452
|
const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
15125
15453
|
const marker = JSON.stringify({
|
|
15126
15454
|
source: "plan_manager",
|
|
@@ -15128,28 +15456,28 @@ ${markdown}`;
|
|
|
15128
15456
|
phases_count: validated.phases.length,
|
|
15129
15457
|
tasks_count: tasksCount
|
|
15130
15458
|
});
|
|
15131
|
-
await
|
|
15459
|
+
await bunWrite(markerPath, marker);
|
|
15132
15460
|
} catch {}
|
|
15133
15461
|
}
|
|
15134
15462
|
async function rebuildPlan(directory, plan) {
|
|
15135
15463
|
const targetPlan = plan ?? await replayFromLedger(directory);
|
|
15136
15464
|
if (!targetPlan)
|
|
15137
15465
|
return null;
|
|
15138
|
-
const swarmDir =
|
|
15139
|
-
const planPath =
|
|
15140
|
-
const mdPath =
|
|
15141
|
-
const tempPlanPath =
|
|
15142
|
-
await
|
|
15466
|
+
const swarmDir = path4.join(directory, ".swarm");
|
|
15467
|
+
const planPath = path4.join(swarmDir, "plan.json");
|
|
15468
|
+
const mdPath = path4.join(swarmDir, "plan.md");
|
|
15469
|
+
const tempPlanPath = path4.join(swarmDir, `plan.json.rebuild.${Date.now()}`);
|
|
15470
|
+
await bunWrite(tempPlanPath, JSON.stringify(targetPlan, null, 2));
|
|
15143
15471
|
renameSync2(tempPlanPath, planPath);
|
|
15144
15472
|
const contentHash = computePlanContentHash(targetPlan);
|
|
15145
15473
|
const markdown = derivePlanMarkdown(targetPlan);
|
|
15146
15474
|
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
15147
15475
|
${markdown}`;
|
|
15148
|
-
const tempMdPath =
|
|
15149
|
-
await
|
|
15476
|
+
const tempMdPath = path4.join(swarmDir, `plan.md.rebuild.${Date.now()}`);
|
|
15477
|
+
await bunWrite(tempMdPath, markdownWithHash);
|
|
15150
15478
|
renameSync2(tempMdPath, mdPath);
|
|
15151
15479
|
try {
|
|
15152
|
-
const markerPath =
|
|
15480
|
+
const markerPath = path4.join(swarmDir, ".plan-write-marker");
|
|
15153
15481
|
const tasksCount = targetPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
15154
15482
|
const marker = JSON.stringify({
|
|
15155
15483
|
source: "plan_manager",
|
|
@@ -15157,7 +15485,7 @@ ${markdown}`;
|
|
|
15157
15485
|
phases_count: targetPlan.phases.length,
|
|
15158
15486
|
tasks_count: tasksCount
|
|
15159
15487
|
});
|
|
15160
|
-
await
|
|
15488
|
+
await bunWrite(markerPath, marker);
|
|
15161
15489
|
} catch {}
|
|
15162
15490
|
return targetPlan;
|
|
15163
15491
|
}
|
|
@@ -15435,6 +15763,7 @@ var init_manager = __esm(() => {
|
|
|
15435
15763
|
init_utils2();
|
|
15436
15764
|
init_telemetry();
|
|
15437
15765
|
init_utils();
|
|
15766
|
+
init_bun_compat();
|
|
15438
15767
|
init_spec_hash();
|
|
15439
15768
|
init_ledger();
|
|
15440
15769
|
PlanConcurrentModificationError = class PlanConcurrentModificationError extends Error {
|
|
@@ -15703,7 +16032,7 @@ var init_evidence_schema = __esm(() => {
|
|
|
15703
16032
|
|
|
15704
16033
|
// node_modules/graceful-fs/polyfills.js
|
|
15705
16034
|
var require_polyfills = __commonJS((exports, module) => {
|
|
15706
|
-
var
|
|
16035
|
+
var constants2 = __require("constants");
|
|
15707
16036
|
var origCwd = process.cwd;
|
|
15708
16037
|
var cwd = null;
|
|
15709
16038
|
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
@@ -15727,7 +16056,7 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15727
16056
|
var chdir;
|
|
15728
16057
|
module.exports = patch;
|
|
15729
16058
|
function patch(fs3) {
|
|
15730
|
-
if (
|
|
16059
|
+
if (constants2.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
15731
16060
|
patchLchmod(fs3);
|
|
15732
16061
|
}
|
|
15733
16062
|
if (!fs3.lutimes) {
|
|
@@ -15752,14 +16081,14 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15752
16081
|
fs3.fstatSync = statFixSync(fs3.fstatSync);
|
|
15753
16082
|
fs3.lstatSync = statFixSync(fs3.lstatSync);
|
|
15754
16083
|
if (fs3.chmod && !fs3.lchmod) {
|
|
15755
|
-
fs3.lchmod = function(
|
|
16084
|
+
fs3.lchmod = function(path6, mode, cb) {
|
|
15756
16085
|
if (cb)
|
|
15757
16086
|
process.nextTick(cb);
|
|
15758
16087
|
};
|
|
15759
16088
|
fs3.lchmodSync = function() {};
|
|
15760
16089
|
}
|
|
15761
16090
|
if (fs3.chown && !fs3.lchown) {
|
|
15762
|
-
fs3.lchown = function(
|
|
16091
|
+
fs3.lchown = function(path6, uid, gid, cb) {
|
|
15763
16092
|
if (cb)
|
|
15764
16093
|
process.nextTick(cb);
|
|
15765
16094
|
};
|
|
@@ -15767,7 +16096,7 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15767
16096
|
}
|
|
15768
16097
|
if (platform === "win32") {
|
|
15769
16098
|
fs3.rename = typeof fs3.rename !== "function" ? fs3.rename : function(fs$rename) {
|
|
15770
|
-
function
|
|
16099
|
+
function rename2(from, to, cb) {
|
|
15771
16100
|
var start = Date.now();
|
|
15772
16101
|
var backoff = 0;
|
|
15773
16102
|
fs$rename(from, to, function CB(er) {
|
|
@@ -15789,8 +16118,8 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15789
16118
|
});
|
|
15790
16119
|
}
|
|
15791
16120
|
if (Object.setPrototypeOf)
|
|
15792
|
-
Object.setPrototypeOf(
|
|
15793
|
-
return
|
|
16121
|
+
Object.setPrototypeOf(rename2, fs$rename);
|
|
16122
|
+
return rename2;
|
|
15794
16123
|
}(fs3.rename);
|
|
15795
16124
|
}
|
|
15796
16125
|
fs3.read = typeof fs3.read !== "function" ? fs3.read : function(fs$read) {
|
|
@@ -15829,8 +16158,8 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15829
16158
|
};
|
|
15830
16159
|
}(fs3.readSync);
|
|
15831
16160
|
function patchLchmod(fs4) {
|
|
15832
|
-
fs4.lchmod = function(
|
|
15833
|
-
fs4.open(
|
|
16161
|
+
fs4.lchmod = function(path6, mode, callback) {
|
|
16162
|
+
fs4.open(path6, constants2.O_WRONLY | constants2.O_SYMLINK, mode, function(err, fd) {
|
|
15834
16163
|
if (err) {
|
|
15835
16164
|
if (callback)
|
|
15836
16165
|
callback(err);
|
|
@@ -15844,8 +16173,8 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15844
16173
|
});
|
|
15845
16174
|
});
|
|
15846
16175
|
};
|
|
15847
|
-
fs4.lchmodSync = function(
|
|
15848
|
-
var fd = fs4.openSync(
|
|
16176
|
+
fs4.lchmodSync = function(path6, mode) {
|
|
16177
|
+
var fd = fs4.openSync(path6, constants2.O_WRONLY | constants2.O_SYMLINK, mode);
|
|
15849
16178
|
var threw = true;
|
|
15850
16179
|
var ret;
|
|
15851
16180
|
try {
|
|
@@ -15864,9 +16193,9 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15864
16193
|
};
|
|
15865
16194
|
}
|
|
15866
16195
|
function patchLutimes(fs4) {
|
|
15867
|
-
if (
|
|
15868
|
-
fs4.lutimes = function(
|
|
15869
|
-
fs4.open(
|
|
16196
|
+
if (constants2.hasOwnProperty("O_SYMLINK") && fs4.futimes) {
|
|
16197
|
+
fs4.lutimes = function(path6, at, mt, cb) {
|
|
16198
|
+
fs4.open(path6, constants2.O_SYMLINK, function(er, fd) {
|
|
15870
16199
|
if (er) {
|
|
15871
16200
|
if (cb)
|
|
15872
16201
|
cb(er);
|
|
@@ -15880,8 +16209,8 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15880
16209
|
});
|
|
15881
16210
|
});
|
|
15882
16211
|
};
|
|
15883
|
-
fs4.lutimesSync = function(
|
|
15884
|
-
var fd = fs4.openSync(
|
|
16212
|
+
fs4.lutimesSync = function(path6, at, mt) {
|
|
16213
|
+
var fd = fs4.openSync(path6, constants2.O_SYMLINK);
|
|
15885
16214
|
var ret;
|
|
15886
16215
|
var threw = true;
|
|
15887
16216
|
try {
|
|
@@ -16013,12 +16342,12 @@ var require_legacy_streams = __commonJS((exports, module) => {
|
|
|
16013
16342
|
ReadStream,
|
|
16014
16343
|
WriteStream
|
|
16015
16344
|
};
|
|
16016
|
-
function ReadStream(
|
|
16345
|
+
function ReadStream(path6, options) {
|
|
16017
16346
|
if (!(this instanceof ReadStream))
|
|
16018
|
-
return new ReadStream(
|
|
16347
|
+
return new ReadStream(path6, options);
|
|
16019
16348
|
Stream.call(this);
|
|
16020
16349
|
var self = this;
|
|
16021
|
-
this.path =
|
|
16350
|
+
this.path = path6;
|
|
16022
16351
|
this.fd = null;
|
|
16023
16352
|
this.readable = true;
|
|
16024
16353
|
this.paused = false;
|
|
@@ -16064,11 +16393,11 @@ var require_legacy_streams = __commonJS((exports, module) => {
|
|
|
16064
16393
|
self._read();
|
|
16065
16394
|
});
|
|
16066
16395
|
}
|
|
16067
|
-
function WriteStream(
|
|
16396
|
+
function WriteStream(path6, options) {
|
|
16068
16397
|
if (!(this instanceof WriteStream))
|
|
16069
|
-
return new WriteStream(
|
|
16398
|
+
return new WriteStream(path6, options);
|
|
16070
16399
|
Stream.call(this);
|
|
16071
|
-
this.path =
|
|
16400
|
+
this.path = path6;
|
|
16072
16401
|
this.fd = null;
|
|
16073
16402
|
this.writable = true;
|
|
16074
16403
|
this.flags = "w";
|
|
@@ -16205,15 +16534,15 @@ GFS4: `);
|
|
|
16205
16534
|
fs4.createReadStream = createReadStream;
|
|
16206
16535
|
fs4.createWriteStream = createWriteStream;
|
|
16207
16536
|
var fs$readFile = fs4.readFile;
|
|
16208
|
-
fs4.readFile =
|
|
16209
|
-
function
|
|
16537
|
+
fs4.readFile = readFile3;
|
|
16538
|
+
function readFile3(path6, options, cb) {
|
|
16210
16539
|
if (typeof options === "function")
|
|
16211
16540
|
cb = options, options = null;
|
|
16212
|
-
return go$readFile(
|
|
16213
|
-
function go$readFile(
|
|
16214
|
-
return fs$readFile(
|
|
16541
|
+
return go$readFile(path6, options, cb);
|
|
16542
|
+
function go$readFile(path7, options2, cb2, startTime) {
|
|
16543
|
+
return fs$readFile(path7, options2, function(err) {
|
|
16215
16544
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16216
|
-
enqueue([go$readFile, [
|
|
16545
|
+
enqueue([go$readFile, [path7, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16217
16546
|
else {
|
|
16218
16547
|
if (typeof cb2 === "function")
|
|
16219
16548
|
cb2.apply(this, arguments);
|
|
@@ -16222,15 +16551,15 @@ GFS4: `);
|
|
|
16222
16551
|
}
|
|
16223
16552
|
}
|
|
16224
16553
|
var fs$writeFile = fs4.writeFile;
|
|
16225
|
-
fs4.writeFile =
|
|
16226
|
-
function
|
|
16554
|
+
fs4.writeFile = writeFile3;
|
|
16555
|
+
function writeFile3(path6, data, options, cb) {
|
|
16227
16556
|
if (typeof options === "function")
|
|
16228
16557
|
cb = options, options = null;
|
|
16229
|
-
return go$writeFile(
|
|
16230
|
-
function go$writeFile(
|
|
16231
|
-
return fs$writeFile(
|
|
16558
|
+
return go$writeFile(path6, data, options, cb);
|
|
16559
|
+
function go$writeFile(path7, data2, options2, cb2, startTime) {
|
|
16560
|
+
return fs$writeFile(path7, data2, options2, function(err) {
|
|
16232
16561
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16233
|
-
enqueue([go$writeFile, [
|
|
16562
|
+
enqueue([go$writeFile, [path7, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16234
16563
|
else {
|
|
16235
16564
|
if (typeof cb2 === "function")
|
|
16236
16565
|
cb2.apply(this, arguments);
|
|
@@ -16241,14 +16570,14 @@ GFS4: `);
|
|
|
16241
16570
|
var fs$appendFile = fs4.appendFile;
|
|
16242
16571
|
if (fs$appendFile)
|
|
16243
16572
|
fs4.appendFile = appendFile2;
|
|
16244
|
-
function appendFile2(
|
|
16573
|
+
function appendFile2(path6, data, options, cb) {
|
|
16245
16574
|
if (typeof options === "function")
|
|
16246
16575
|
cb = options, options = null;
|
|
16247
|
-
return go$appendFile(
|
|
16248
|
-
function go$appendFile(
|
|
16249
|
-
return fs$appendFile(
|
|
16576
|
+
return go$appendFile(path6, data, options, cb);
|
|
16577
|
+
function go$appendFile(path7, data2, options2, cb2, startTime) {
|
|
16578
|
+
return fs$appendFile(path7, data2, options2, function(err) {
|
|
16250
16579
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16251
|
-
enqueue([go$appendFile, [
|
|
16580
|
+
enqueue([go$appendFile, [path7, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16252
16581
|
else {
|
|
16253
16582
|
if (typeof cb2 === "function")
|
|
16254
16583
|
cb2.apply(this, arguments);
|
|
@@ -16279,21 +16608,21 @@ GFS4: `);
|
|
|
16279
16608
|
var fs$readdir = fs4.readdir;
|
|
16280
16609
|
fs4.readdir = readdir;
|
|
16281
16610
|
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
16282
|
-
function readdir(
|
|
16611
|
+
function readdir(path6, options, cb) {
|
|
16283
16612
|
if (typeof options === "function")
|
|
16284
16613
|
cb = options, options = null;
|
|
16285
|
-
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(
|
|
16286
|
-
return fs$readdir(
|
|
16287
|
-
} : function go$readdir2(
|
|
16288
|
-
return fs$readdir(
|
|
16614
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path7, options2, cb2, startTime) {
|
|
16615
|
+
return fs$readdir(path7, fs$readdirCallback(path7, options2, cb2, startTime));
|
|
16616
|
+
} : function go$readdir2(path7, options2, cb2, startTime) {
|
|
16617
|
+
return fs$readdir(path7, options2, fs$readdirCallback(path7, options2, cb2, startTime));
|
|
16289
16618
|
};
|
|
16290
|
-
return go$readdir(
|
|
16291
|
-
function fs$readdirCallback(
|
|
16619
|
+
return go$readdir(path6, options, cb);
|
|
16620
|
+
function fs$readdirCallback(path7, options2, cb2, startTime) {
|
|
16292
16621
|
return function(err, files) {
|
|
16293
16622
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16294
16623
|
enqueue([
|
|
16295
16624
|
go$readdir,
|
|
16296
|
-
[
|
|
16625
|
+
[path7, options2, cb2],
|
|
16297
16626
|
err,
|
|
16298
16627
|
startTime || Date.now(),
|
|
16299
16628
|
Date.now()
|
|
@@ -16364,7 +16693,7 @@ GFS4: `);
|
|
|
16364
16693
|
enumerable: true,
|
|
16365
16694
|
configurable: true
|
|
16366
16695
|
});
|
|
16367
|
-
function ReadStream(
|
|
16696
|
+
function ReadStream(path6, options) {
|
|
16368
16697
|
if (this instanceof ReadStream)
|
|
16369
16698
|
return fs$ReadStream.apply(this, arguments), this;
|
|
16370
16699
|
else
|
|
@@ -16384,7 +16713,7 @@ GFS4: `);
|
|
|
16384
16713
|
}
|
|
16385
16714
|
});
|
|
16386
16715
|
}
|
|
16387
|
-
function WriteStream(
|
|
16716
|
+
function WriteStream(path6, options) {
|
|
16388
16717
|
if (this instanceof WriteStream)
|
|
16389
16718
|
return fs$WriteStream.apply(this, arguments), this;
|
|
16390
16719
|
else
|
|
@@ -16402,22 +16731,22 @@ GFS4: `);
|
|
|
16402
16731
|
}
|
|
16403
16732
|
});
|
|
16404
16733
|
}
|
|
16405
|
-
function createReadStream(
|
|
16406
|
-
return new fs4.ReadStream(
|
|
16734
|
+
function createReadStream(path6, options) {
|
|
16735
|
+
return new fs4.ReadStream(path6, options);
|
|
16407
16736
|
}
|
|
16408
|
-
function createWriteStream(
|
|
16409
|
-
return new fs4.WriteStream(
|
|
16737
|
+
function createWriteStream(path6, options) {
|
|
16738
|
+
return new fs4.WriteStream(path6, options);
|
|
16410
16739
|
}
|
|
16411
16740
|
var fs$open = fs4.open;
|
|
16412
16741
|
fs4.open = open;
|
|
16413
|
-
function open(
|
|
16742
|
+
function open(path6, flags, mode, cb) {
|
|
16414
16743
|
if (typeof mode === "function")
|
|
16415
16744
|
cb = mode, mode = null;
|
|
16416
|
-
return go$open(
|
|
16417
|
-
function go$open(
|
|
16418
|
-
return fs$open(
|
|
16745
|
+
return go$open(path6, flags, mode, cb);
|
|
16746
|
+
function go$open(path7, flags2, mode2, cb2, startTime) {
|
|
16747
|
+
return fs$open(path7, flags2, mode2, function(err, fd) {
|
|
16419
16748
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16420
|
-
enqueue([go$open, [
|
|
16749
|
+
enqueue([go$open, [path7, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16421
16750
|
else {
|
|
16422
16751
|
if (typeof cb2 === "function")
|
|
16423
16752
|
cb2.apply(this, arguments);
|
|
@@ -16868,11 +17197,11 @@ var require_mtime_precision = __commonJS((exports, module) => {
|
|
|
16868
17197
|
function probe(file2, fs3, callback) {
|
|
16869
17198
|
const cachedPrecision = fs3[cacheSymbol];
|
|
16870
17199
|
if (cachedPrecision) {
|
|
16871
|
-
return fs3.stat(file2, (err,
|
|
17200
|
+
return fs3.stat(file2, (err, stat2) => {
|
|
16872
17201
|
if (err) {
|
|
16873
17202
|
return callback(err);
|
|
16874
17203
|
}
|
|
16875
|
-
callback(null,
|
|
17204
|
+
callback(null, stat2.mtime, cachedPrecision);
|
|
16876
17205
|
});
|
|
16877
17206
|
}
|
|
16878
17207
|
const mtime = new Date(Math.ceil(Date.now() / 1000) * 1000 + 5);
|
|
@@ -16880,13 +17209,13 @@ var require_mtime_precision = __commonJS((exports, module) => {
|
|
|
16880
17209
|
if (err) {
|
|
16881
17210
|
return callback(err);
|
|
16882
17211
|
}
|
|
16883
|
-
fs3.stat(file2, (err2,
|
|
17212
|
+
fs3.stat(file2, (err2, stat2) => {
|
|
16884
17213
|
if (err2) {
|
|
16885
17214
|
return callback(err2);
|
|
16886
17215
|
}
|
|
16887
|
-
const precision =
|
|
17216
|
+
const precision = stat2.mtime.getTime() % 1000 === 0 ? "s" : "ms";
|
|
16888
17217
|
Object.defineProperty(fs3, cacheSymbol, { value: precision });
|
|
16889
|
-
callback(null,
|
|
17218
|
+
callback(null, stat2.mtime, precision);
|
|
16890
17219
|
});
|
|
16891
17220
|
});
|
|
16892
17221
|
}
|
|
@@ -16903,7 +17232,7 @@ var require_mtime_precision = __commonJS((exports, module) => {
|
|
|
16903
17232
|
|
|
16904
17233
|
// node_modules/proper-lockfile/lib/lockfile.js
|
|
16905
17234
|
var require_lockfile = __commonJS((exports, module) => {
|
|
16906
|
-
var
|
|
17235
|
+
var path6 = __require("path");
|
|
16907
17236
|
var fs3 = require_graceful_fs();
|
|
16908
17237
|
var retry = require_retry();
|
|
16909
17238
|
var onExit = require_signal_exit();
|
|
@@ -16914,7 +17243,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
16914
17243
|
}
|
|
16915
17244
|
function resolveCanonicalPath(file2, options, callback) {
|
|
16916
17245
|
if (!options.realpath) {
|
|
16917
|
-
return callback(null,
|
|
17246
|
+
return callback(null, path6.resolve(file2));
|
|
16918
17247
|
}
|
|
16919
17248
|
options.fs.realpath(file2, callback);
|
|
16920
17249
|
}
|
|
@@ -16936,14 +17265,14 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
16936
17265
|
if (options.stale <= 0) {
|
|
16937
17266
|
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file: file2 }));
|
|
16938
17267
|
}
|
|
16939
|
-
options.fs.stat(lockfilePath, (err2,
|
|
17268
|
+
options.fs.stat(lockfilePath, (err2, stat2) => {
|
|
16940
17269
|
if (err2) {
|
|
16941
17270
|
if (err2.code === "ENOENT") {
|
|
16942
17271
|
return acquireLock(file2, { ...options, stale: 0 }, callback);
|
|
16943
17272
|
}
|
|
16944
17273
|
return callback(err2);
|
|
16945
17274
|
}
|
|
16946
|
-
if (!isLockStale(
|
|
17275
|
+
if (!isLockStale(stat2, options)) {
|
|
16947
17276
|
return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file: file2 }));
|
|
16948
17277
|
}
|
|
16949
17278
|
removeLock(file2, options, (err3) => {
|
|
@@ -16955,8 +17284,8 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
16955
17284
|
});
|
|
16956
17285
|
});
|
|
16957
17286
|
}
|
|
16958
|
-
function isLockStale(
|
|
16959
|
-
return
|
|
17287
|
+
function isLockStale(stat2, options) {
|
|
17288
|
+
return stat2.mtime.getTime() < Date.now() - options.stale;
|
|
16960
17289
|
}
|
|
16961
17290
|
function removeLock(file2, options, callback) {
|
|
16962
17291
|
options.fs.rmdir(getLockFile(file2, options), (err) => {
|
|
@@ -16974,7 +17303,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
16974
17303
|
lock2.updateDelay = lock2.updateDelay || options.update;
|
|
16975
17304
|
lock2.updateTimeout = setTimeout(() => {
|
|
16976
17305
|
lock2.updateTimeout = null;
|
|
16977
|
-
options.fs.stat(lock2.lockfilePath, (err,
|
|
17306
|
+
options.fs.stat(lock2.lockfilePath, (err, stat2) => {
|
|
16978
17307
|
const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
|
|
16979
17308
|
if (err) {
|
|
16980
17309
|
if (err.code === "ENOENT" || isOverThreshold) {
|
|
@@ -16983,7 +17312,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
16983
17312
|
lock2.updateDelay = 1000;
|
|
16984
17313
|
return updateLock(file2, options);
|
|
16985
17314
|
}
|
|
16986
|
-
const isMtimeOurs = lock2.mtime.getTime() ===
|
|
17315
|
+
const isMtimeOurs = lock2.mtime.getTime() === stat2.mtime.getTime();
|
|
16987
17316
|
if (!isMtimeOurs) {
|
|
16988
17317
|
return setLockAsCompromised(file2, lock2, Object.assign(new Error("Unable to update lock within the stale threshold"), { code: "ECOMPROMISED" }));
|
|
16989
17318
|
}
|
|
@@ -17101,11 +17430,11 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
17101
17430
|
if (err) {
|
|
17102
17431
|
return callback(err);
|
|
17103
17432
|
}
|
|
17104
|
-
options.fs.stat(getLockFile(file3, options), (err2,
|
|
17433
|
+
options.fs.stat(getLockFile(file3, options), (err2, stat2) => {
|
|
17105
17434
|
if (err2) {
|
|
17106
17435
|
return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
|
|
17107
17436
|
}
|
|
17108
|
-
return callback(null, !isLockStale(
|
|
17437
|
+
return callback(null, !isLockStale(stat2, options));
|
|
17109
17438
|
});
|
|
17110
17439
|
});
|
|
17111
17440
|
}
|
|
@@ -17223,20 +17552,20 @@ var require_proper_lockfile = __commonJS((exports, module) => {
|
|
|
17223
17552
|
|
|
17224
17553
|
// src/parallel/file-locks.ts
|
|
17225
17554
|
import * as fs3 from "fs";
|
|
17226
|
-
import * as
|
|
17555
|
+
import * as path6 from "path";
|
|
17227
17556
|
function getLockFilePath(directory, filePath) {
|
|
17228
|
-
const normalized =
|
|
17229
|
-
const baseDir =
|
|
17557
|
+
const normalized = path6.resolve(directory, filePath);
|
|
17558
|
+
const baseDir = path6.resolve(directory) + path6.sep;
|
|
17230
17559
|
const pathOk = process.platform === "win32" ? normalized.toLowerCase().startsWith(baseDir.toLowerCase()) : normalized.startsWith(baseDir);
|
|
17231
17560
|
if (!pathOk) {
|
|
17232
17561
|
throw new Error("Invalid file path: path traversal not allowed");
|
|
17233
17562
|
}
|
|
17234
17563
|
const hash2 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
17235
|
-
return
|
|
17564
|
+
return path6.join(directory, LOCKS_DIR, `${hash2}.lock`);
|
|
17236
17565
|
}
|
|
17237
17566
|
async function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
17238
17567
|
const lockPath = getLockFilePath(directory, filePath);
|
|
17239
|
-
const locksDir =
|
|
17568
|
+
const locksDir = path6.dirname(lockPath);
|
|
17240
17569
|
if (!fs3.existsSync(locksDir)) {
|
|
17241
17570
|
fs3.mkdirSync(locksDir, { recursive: true });
|
|
17242
17571
|
}
|
|
@@ -17386,19 +17715,19 @@ var init_task_id = __esm(() => {
|
|
|
17386
17715
|
});
|
|
17387
17716
|
|
|
17388
17717
|
// src/evidence/manager.ts
|
|
17389
|
-
import { mkdirSync as mkdirSync3, readdirSync as readdirSync3, rmSync, statSync as
|
|
17718
|
+
import { mkdirSync as mkdirSync3, readdirSync as readdirSync3, rmSync, statSync as statSync4 } from "fs";
|
|
17390
17719
|
import * as fs4 from "fs/promises";
|
|
17391
|
-
import * as
|
|
17720
|
+
import * as path7 from "path";
|
|
17392
17721
|
function isValidEvidenceType(type) {
|
|
17393
17722
|
return VALID_EVIDENCE_TYPES.includes(type);
|
|
17394
17723
|
}
|
|
17395
17724
|
async function saveEvidence(directory, taskId, evidence) {
|
|
17396
17725
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
17397
|
-
const relativePath =
|
|
17726
|
+
const relativePath = path7.join("evidence", sanitizedTaskId, "evidence.json");
|
|
17398
17727
|
validateSwarmPath(directory, relativePath);
|
|
17399
17728
|
return withEvidenceLock(directory, relativePath, "evidence-manager", sanitizedTaskId, async () => {
|
|
17400
17729
|
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
17401
|
-
const evidenceDir =
|
|
17730
|
+
const evidenceDir = path7.dirname(evidencePath);
|
|
17402
17731
|
let bundle;
|
|
17403
17732
|
const existingContent = await readSwarmFileAsync(directory, relativePath);
|
|
17404
17733
|
if (existingContent !== null) {
|
|
@@ -17441,9 +17770,9 @@ async function saveEvidence(directory, taskId, evidence) {
|
|
|
17441
17770
|
throw new Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);
|
|
17442
17771
|
}
|
|
17443
17772
|
mkdirSync3(evidenceDir, { recursive: true });
|
|
17444
|
-
const tempPath =
|
|
17773
|
+
const tempPath = path7.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
17445
17774
|
try {
|
|
17446
|
-
await
|
|
17775
|
+
await bunWrite(tempPath, bundleJson);
|
|
17447
17776
|
await fs4.rename(tempPath, evidencePath);
|
|
17448
17777
|
} catch (error49) {
|
|
17449
17778
|
try {
|
|
@@ -17480,7 +17809,7 @@ function wrapFlatRetrospective(flatEntry, taskId) {
|
|
|
17480
17809
|
}
|
|
17481
17810
|
async function loadEvidence(directory, taskId) {
|
|
17482
17811
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
17483
|
-
const relativePath =
|
|
17812
|
+
const relativePath = path7.join("evidence", sanitizedTaskId, "evidence.json");
|
|
17484
17813
|
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
17485
17814
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
17486
17815
|
if (content === null) {
|
|
@@ -17498,11 +17827,11 @@ async function loadEvidence(directory, taskId) {
|
|
|
17498
17827
|
const validated = EvidenceBundleSchema.parse(wrappedBundle);
|
|
17499
17828
|
try {
|
|
17500
17829
|
await withEvidenceLock(directory, relativePath, "evidence-loader", sanitizedTaskId, async () => {
|
|
17501
|
-
const evidenceDir =
|
|
17830
|
+
const evidenceDir = path7.dirname(evidencePath);
|
|
17502
17831
|
const bundleJson = JSON.stringify(validated);
|
|
17503
|
-
const tempPath =
|
|
17832
|
+
const tempPath = path7.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
17504
17833
|
try {
|
|
17505
|
-
await
|
|
17834
|
+
await bunWrite(tempPath, bundleJson);
|
|
17506
17835
|
await fs4.rename(tempPath, evidencePath);
|
|
17507
17836
|
} catch (writeError) {
|
|
17508
17837
|
try {
|
|
@@ -17533,7 +17862,7 @@ async function loadEvidence(directory, taskId) {
|
|
|
17533
17862
|
async function listEvidenceTaskIds(directory) {
|
|
17534
17863
|
const evidenceBasePath = validateSwarmPath(directory, "evidence");
|
|
17535
17864
|
try {
|
|
17536
|
-
|
|
17865
|
+
statSync4(evidenceBasePath);
|
|
17537
17866
|
} catch {
|
|
17538
17867
|
return [];
|
|
17539
17868
|
}
|
|
@@ -17545,9 +17874,9 @@ async function listEvidenceTaskIds(directory) {
|
|
|
17545
17874
|
}
|
|
17546
17875
|
const taskIds = [];
|
|
17547
17876
|
for (const entry of entries) {
|
|
17548
|
-
const entryPath =
|
|
17877
|
+
const entryPath = path7.join(evidenceBasePath, entry);
|
|
17549
17878
|
try {
|
|
17550
|
-
const stats =
|
|
17879
|
+
const stats = statSync4(entryPath);
|
|
17551
17880
|
if (!stats.isDirectory()) {
|
|
17552
17881
|
continue;
|
|
17553
17882
|
}
|
|
@@ -17563,10 +17892,10 @@ async function listEvidenceTaskIds(directory) {
|
|
|
17563
17892
|
}
|
|
17564
17893
|
async function deleteEvidence(directory, taskId) {
|
|
17565
17894
|
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
17566
|
-
const relativePath =
|
|
17895
|
+
const relativePath = path7.join("evidence", sanitizedTaskId);
|
|
17567
17896
|
const evidenceDir = validateSwarmPath(directory, relativePath);
|
|
17568
17897
|
try {
|
|
17569
|
-
|
|
17898
|
+
statSync4(evidenceDir);
|
|
17570
17899
|
} catch {
|
|
17571
17900
|
return false;
|
|
17572
17901
|
}
|
|
@@ -17579,8 +17908,8 @@ async function deleteEvidence(directory, taskId) {
|
|
|
17579
17908
|
}
|
|
17580
17909
|
}
|
|
17581
17910
|
async function checkRequirementCoverage(phase, directory) {
|
|
17582
|
-
const relativePath =
|
|
17583
|
-
const absolutePath =
|
|
17911
|
+
const relativePath = path7.join("evidence", `req-coverage-phase-${phase}.json`);
|
|
17912
|
+
const absolutePath = path7.resolve(directory, ".swarm", relativePath);
|
|
17584
17913
|
try {
|
|
17585
17914
|
await fs4.access(absolutePath);
|
|
17586
17915
|
return { exists: true, path: absolutePath };
|
|
@@ -17630,6 +17959,7 @@ var init_manager2 = __esm(() => {
|
|
|
17630
17959
|
init_evidence_schema();
|
|
17631
17960
|
init_utils2();
|
|
17632
17961
|
init_utils();
|
|
17962
|
+
init_bun_compat();
|
|
17633
17963
|
init_lock();
|
|
17634
17964
|
init_task_id();
|
|
17635
17965
|
VALID_EVIDENCE_TYPES = [
|
|
@@ -17671,13 +18001,13 @@ __export(exports_config_doctor, {
|
|
|
17671
18001
|
import * as crypto3 from "crypto";
|
|
17672
18002
|
import * as fs8 from "fs";
|
|
17673
18003
|
import * as os6 from "os";
|
|
17674
|
-
import * as
|
|
18004
|
+
import * as path20 from "path";
|
|
17675
18005
|
function getUserConfigDir3() {
|
|
17676
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
18006
|
+
return process.env.XDG_CONFIG_HOME || path20.join(os6.homedir(), ".config");
|
|
17677
18007
|
}
|
|
17678
18008
|
function getConfigPaths(directory) {
|
|
17679
|
-
const userConfigPath =
|
|
17680
|
-
const projectConfigPath =
|
|
18009
|
+
const userConfigPath = path20.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
18010
|
+
const projectConfigPath = path20.join(directory, ".opencode", "opencode-swarm.json");
|
|
17681
18011
|
return { userConfigPath, projectConfigPath };
|
|
17682
18012
|
}
|
|
17683
18013
|
function computeHash(content) {
|
|
@@ -17702,9 +18032,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
17702
18032
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
17703
18033
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
17704
18034
|
try {
|
|
17705
|
-
const resolvedConfig =
|
|
17706
|
-
const resolvedUser =
|
|
17707
|
-
const resolvedProject =
|
|
18035
|
+
const resolvedConfig = path20.resolve(configPath);
|
|
18036
|
+
const resolvedUser = path20.resolve(normalizedUser);
|
|
18037
|
+
const resolvedProject = path20.resolve(normalizedProject);
|
|
17708
18038
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
17709
18039
|
} catch {
|
|
17710
18040
|
return false;
|
|
@@ -17744,12 +18074,12 @@ function createConfigBackup(directory) {
|
|
|
17744
18074
|
};
|
|
17745
18075
|
}
|
|
17746
18076
|
function writeBackupArtifact(directory, backup) {
|
|
17747
|
-
const swarmDir =
|
|
18077
|
+
const swarmDir = path20.join(directory, ".swarm");
|
|
17748
18078
|
if (!fs8.existsSync(swarmDir)) {
|
|
17749
18079
|
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
17750
18080
|
}
|
|
17751
18081
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
17752
|
-
const backupPath =
|
|
18082
|
+
const backupPath = path20.join(swarmDir, backupFilename);
|
|
17753
18083
|
const artifact = {
|
|
17754
18084
|
createdAt: backup.createdAt,
|
|
17755
18085
|
configPath: backup.configPath,
|
|
@@ -17779,7 +18109,7 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
17779
18109
|
return null;
|
|
17780
18110
|
}
|
|
17781
18111
|
const targetPath = artifact.configPath;
|
|
17782
|
-
const targetDir =
|
|
18112
|
+
const targetDir = path20.dirname(targetPath);
|
|
17783
18113
|
if (!fs8.existsSync(targetDir)) {
|
|
17784
18114
|
fs8.mkdirSync(targetDir, { recursive: true });
|
|
17785
18115
|
}
|
|
@@ -17810,9 +18140,9 @@ function readConfigFromFile(directory) {
|
|
|
17810
18140
|
return null;
|
|
17811
18141
|
}
|
|
17812
18142
|
}
|
|
17813
|
-
function validateConfigKey(
|
|
18143
|
+
function validateConfigKey(path21, value, _config) {
|
|
17814
18144
|
const findings = [];
|
|
17815
|
-
switch (
|
|
18145
|
+
switch (path21) {
|
|
17816
18146
|
case "agents": {
|
|
17817
18147
|
if (value !== undefined) {
|
|
17818
18148
|
findings.push({
|
|
@@ -18059,27 +18389,27 @@ function validateConfigKey(path20, value, _config) {
|
|
|
18059
18389
|
}
|
|
18060
18390
|
return findings;
|
|
18061
18391
|
}
|
|
18062
|
-
function walkConfigAndValidate(obj,
|
|
18392
|
+
function walkConfigAndValidate(obj, path21, config3, findings) {
|
|
18063
18393
|
if (obj === null || obj === undefined) {
|
|
18064
18394
|
return;
|
|
18065
18395
|
}
|
|
18066
|
-
if (
|
|
18067
|
-
const keyFindings = validateConfigKey(
|
|
18396
|
+
if (path21 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
18397
|
+
const keyFindings = validateConfigKey(path21, obj, config3);
|
|
18068
18398
|
findings.push(...keyFindings);
|
|
18069
18399
|
}
|
|
18070
18400
|
if (typeof obj !== "object") {
|
|
18071
|
-
const keyFindings = validateConfigKey(
|
|
18401
|
+
const keyFindings = validateConfigKey(path21, obj, config3);
|
|
18072
18402
|
findings.push(...keyFindings);
|
|
18073
18403
|
return;
|
|
18074
18404
|
}
|
|
18075
18405
|
if (Array.isArray(obj)) {
|
|
18076
18406
|
obj.forEach((item, index) => {
|
|
18077
|
-
walkConfigAndValidate(item, `${
|
|
18407
|
+
walkConfigAndValidate(item, `${path21}[${index}]`, config3, findings);
|
|
18078
18408
|
});
|
|
18079
18409
|
return;
|
|
18080
18410
|
}
|
|
18081
18411
|
for (const [key, value] of Object.entries(obj)) {
|
|
18082
|
-
const newPath =
|
|
18412
|
+
const newPath = path21 ? `${path21}.${key}` : key;
|
|
18083
18413
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
18084
18414
|
}
|
|
18085
18415
|
}
|
|
@@ -18199,7 +18529,7 @@ function applySafeAutoFixes(directory, result) {
|
|
|
18199
18529
|
}
|
|
18200
18530
|
}
|
|
18201
18531
|
if (appliedFixes.length > 0) {
|
|
18202
|
-
const configDir =
|
|
18532
|
+
const configDir = path20.dirname(configPath);
|
|
18203
18533
|
if (!fs8.existsSync(configDir)) {
|
|
18204
18534
|
fs8.mkdirSync(configDir, { recursive: true });
|
|
18205
18535
|
}
|
|
@@ -18209,12 +18539,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
18209
18539
|
return { appliedFixes, updatedConfigPath };
|
|
18210
18540
|
}
|
|
18211
18541
|
function writeDoctorArtifact(directory, result) {
|
|
18212
|
-
const swarmDir =
|
|
18542
|
+
const swarmDir = path20.join(directory, ".swarm");
|
|
18213
18543
|
if (!fs8.existsSync(swarmDir)) {
|
|
18214
18544
|
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
18215
18545
|
}
|
|
18216
18546
|
const artifactFilename = "config-doctor.json";
|
|
18217
|
-
const artifactPath =
|
|
18547
|
+
const artifactPath = path20.join(swarmDir, artifactFilename);
|
|
18218
18548
|
const guiOutput = {
|
|
18219
18549
|
timestamp: result.timestamp,
|
|
18220
18550
|
summary: result.summary,
|
|
@@ -18577,11 +18907,11 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
18577
18907
|
// src/cli/index.ts
|
|
18578
18908
|
import * as fs21 from "fs";
|
|
18579
18909
|
import * as os7 from "os";
|
|
18580
|
-
import * as
|
|
18910
|
+
import * as path35 from "path";
|
|
18581
18911
|
// package.json
|
|
18582
18912
|
var package_default = {
|
|
18583
18913
|
name: "opencode-swarm",
|
|
18584
|
-
version: "7.0.
|
|
18914
|
+
version: "7.0.3",
|
|
18585
18915
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
18586
18916
|
main: "dist/index.js",
|
|
18587
18917
|
types: "dist/index.d.ts",
|
|
@@ -18626,7 +18956,8 @@ var package_default = {
|
|
|
18626
18956
|
format: "biome format . --write",
|
|
18627
18957
|
check: "biome check --write .",
|
|
18628
18958
|
dev: "bun run build && opencode",
|
|
18629
|
-
prepublishOnly: "bun run build"
|
|
18959
|
+
prepublishOnly: "bun run build",
|
|
18960
|
+
"repro:704": "node scripts/repro-704.mjs"
|
|
18630
18961
|
},
|
|
18631
18962
|
dependencies: {
|
|
18632
18963
|
"@opencode-ai/plugin": "^1.1.53",
|
|
@@ -18652,12 +18983,12 @@ var package_default = {
|
|
|
18652
18983
|
init_utils2();
|
|
18653
18984
|
init_manager();
|
|
18654
18985
|
init_spec_hash();
|
|
18655
|
-
import { promises as
|
|
18986
|
+
import { promises as fsPromises3 } from "fs";
|
|
18656
18987
|
async function handleAcknowledgeSpecDriftCommand(directory, _args) {
|
|
18657
18988
|
const specStalenessPath = validateSwarmPath(directory, "spec-staleness.json");
|
|
18658
18989
|
let stalenessContent;
|
|
18659
18990
|
try {
|
|
18660
|
-
stalenessContent = await
|
|
18991
|
+
stalenessContent = await fsPromises3.readFile(specStalenessPath, "utf-8");
|
|
18661
18992
|
} catch (error49) {
|
|
18662
18993
|
if (error49?.code === "ENOENT") {
|
|
18663
18994
|
return "No spec drift detected.";
|
|
@@ -18668,11 +18999,11 @@ async function handleAcknowledgeSpecDriftCommand(directory, _args) {
|
|
|
18668
18999
|
try {
|
|
18669
19000
|
stalenessData = JSON.parse(stalenessContent);
|
|
18670
19001
|
} catch {
|
|
18671
|
-
await
|
|
19002
|
+
await fsPromises3.unlink(specStalenessPath).catch(() => {});
|
|
18672
19003
|
return "Spec staleness file was corrupted. It has been removed.";
|
|
18673
19004
|
}
|
|
18674
19005
|
const { planTitle, phase } = stalenessData;
|
|
18675
|
-
await
|
|
19006
|
+
await fsPromises3.unlink(specStalenessPath);
|
|
18676
19007
|
let currentHash = null;
|
|
18677
19008
|
let planUpdateSkipped = false;
|
|
18678
19009
|
try {
|
|
@@ -18698,7 +19029,7 @@ async function handleAcknowledgeSpecDriftCommand(directory, _args) {
|
|
|
18698
19029
|
};
|
|
18699
19030
|
let eventWriteFailed = false;
|
|
18700
19031
|
try {
|
|
18701
|
-
await
|
|
19032
|
+
await fsPromises3.appendFile(eventsPath, `${JSON.stringify(acknowledgmentEvent)}
|
|
18702
19033
|
`, "utf-8");
|
|
18703
19034
|
} catch (appendError) {
|
|
18704
19035
|
console.error("[acknowledge-spec-drift] Failed to write acknowledgment event:", appendError instanceof Error ? appendError.message : String(appendError));
|
|
@@ -18799,8 +19130,9 @@ var ALL_SUBAGENT_NAMES = [
|
|
|
18799
19130
|
"critic_hallucination_verifier",
|
|
18800
19131
|
"curator_init",
|
|
18801
19132
|
"curator_phase",
|
|
18802
|
-
"
|
|
18803
|
-
"
|
|
19133
|
+
"council_generalist",
|
|
19134
|
+
"council_skeptic",
|
|
19135
|
+
"council_domain_expert",
|
|
18804
19136
|
...QA_AGENTS,
|
|
18805
19137
|
...PIPELINE_AGENTS
|
|
18806
19138
|
];
|
|
@@ -18873,7 +19205,8 @@ var AGENT_TOOL_MAP = {
|
|
|
18873
19205
|
"repo_map",
|
|
18874
19206
|
"get_qa_gate_profile",
|
|
18875
19207
|
"set_qa_gates",
|
|
18876
|
-
"convene_general_council"
|
|
19208
|
+
"convene_general_council",
|
|
19209
|
+
"web_search"
|
|
18877
19210
|
],
|
|
18878
19211
|
explorer: [
|
|
18879
19212
|
"complexity_hotspots",
|
|
@@ -19024,8 +19357,9 @@ var AGENT_TOOL_MAP = {
|
|
|
19024
19357
|
],
|
|
19025
19358
|
curator_init: ["knowledge_recall"],
|
|
19026
19359
|
curator_phase: ["knowledge_recall"],
|
|
19027
|
-
|
|
19028
|
-
|
|
19360
|
+
council_generalist: [],
|
|
19361
|
+
council_skeptic: [],
|
|
19362
|
+
council_domain_expert: []
|
|
19029
19363
|
};
|
|
19030
19364
|
for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
19031
19365
|
const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
|
|
@@ -19723,11 +20057,11 @@ function handleAgentsCommand(agents, guardrails) {
|
|
|
19723
20057
|
const temp = agent.config.temperature !== undefined ? agent.config.temperature.toString() : "default";
|
|
19724
20058
|
const tools = agent.config.tools || {};
|
|
19725
20059
|
const isReadOnly = tools.write === false || tools.edit === false;
|
|
19726
|
-
const
|
|
20060
|
+
const access2 = isReadOnly ? "\uD83D\uDD12 read-only" : "\u270F\uFE0F read-write";
|
|
19727
20061
|
const desc = agent.description || agent.config.description || "";
|
|
19728
20062
|
const hasCustomProfile = guardrails?.profiles?.[key] !== undefined;
|
|
19729
20063
|
const profileIndicator = hasCustomProfile ? " | \u26A1 custom limits" : "";
|
|
19730
|
-
lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${
|
|
20064
|
+
lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access2}${profileIndicator}`);
|
|
19731
20065
|
if (desc) {
|
|
19732
20066
|
lines.push(` ${desc}`);
|
|
19733
20067
|
}
|
|
@@ -19777,11 +20111,11 @@ async function handleAnalyzeCommand(_directory, args) {
|
|
|
19777
20111
|
// src/config/loader.ts
|
|
19778
20112
|
import * as fs2 from "fs";
|
|
19779
20113
|
import * as os2 from "os";
|
|
19780
|
-
import * as
|
|
20114
|
+
import * as path5 from "path";
|
|
19781
20115
|
var CONFIG_FILENAME = "opencode-swarm.json";
|
|
19782
20116
|
var MAX_CONFIG_FILE_BYTES = 102400;
|
|
19783
20117
|
function getUserConfigDir() {
|
|
19784
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
20118
|
+
return process.env.XDG_CONFIG_HOME || path5.join(os2.homedir(), ".config");
|
|
19785
20119
|
}
|
|
19786
20120
|
function loadRawConfigFromPath(configPath) {
|
|
19787
20121
|
try {
|
|
@@ -19840,8 +20174,8 @@ function migratePresetsConfig(raw) {
|
|
|
19840
20174
|
return raw;
|
|
19841
20175
|
}
|
|
19842
20176
|
function loadPluginConfig(directory) {
|
|
19843
|
-
const userConfigPath =
|
|
19844
|
-
const projectConfigPath =
|
|
20177
|
+
const userConfigPath = path5.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
20178
|
+
const projectConfigPath = path5.join(directory, ".opencode", CONFIG_FILENAME);
|
|
19845
20179
|
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
19846
20180
|
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
19847
20181
|
const rawUserConfig = userResult.config;
|
|
@@ -19878,8 +20212,8 @@ function loadPluginConfig(directory) {
|
|
|
19878
20212
|
return result.data;
|
|
19879
20213
|
}
|
|
19880
20214
|
function loadPluginConfigWithMeta(directory) {
|
|
19881
|
-
const userConfigPath =
|
|
19882
|
-
const projectConfigPath =
|
|
20215
|
+
const userConfigPath = path5.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
20216
|
+
const projectConfigPath = path5.join(directory, ".opencode", CONFIG_FILENAME);
|
|
19883
20217
|
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
19884
20218
|
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
19885
20219
|
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
@@ -19970,7 +20304,7 @@ import { createHash as createHash3 } from "crypto";
|
|
|
19970
20304
|
// src/db/project-db.ts
|
|
19971
20305
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
|
|
19972
20306
|
import { createRequire } from "module";
|
|
19973
|
-
import { join as
|
|
20307
|
+
import { join as join8, resolve as resolve5 } from "path";
|
|
19974
20308
|
var _DatabaseCtor = null;
|
|
19975
20309
|
function loadDatabaseCtor() {
|
|
19976
20310
|
if (_DatabaseCtor)
|
|
@@ -20037,7 +20371,7 @@ function runProjectMigrations(db) {
|
|
|
20037
20371
|
}
|
|
20038
20372
|
}
|
|
20039
20373
|
function projectDbPath(directory) {
|
|
20040
|
-
return
|
|
20374
|
+
return join8(resolve5(directory), ".swarm", "swarm.db");
|
|
20041
20375
|
}
|
|
20042
20376
|
function projectDbExists(directory) {
|
|
20043
20377
|
return existsSync5(projectDbPath(directory));
|
|
@@ -20047,10 +20381,10 @@ function getProjectDb(directory) {
|
|
|
20047
20381
|
const existing = _projectDbs.get(key);
|
|
20048
20382
|
if (existing)
|
|
20049
20383
|
return existing;
|
|
20050
|
-
const swarmDir =
|
|
20384
|
+
const swarmDir = join8(key, ".swarm");
|
|
20051
20385
|
mkdirSync4(swarmDir, { recursive: true });
|
|
20052
20386
|
const Db = loadDatabaseCtor();
|
|
20053
|
-
const db = new Db(
|
|
20387
|
+
const db = new Db(join8(swarmDir, "swarm.db"));
|
|
20054
20388
|
db.run("PRAGMA journal_mode = WAL;");
|
|
20055
20389
|
db.run("PRAGMA synchronous = NORMAL;");
|
|
20056
20390
|
db.run("PRAGMA busy_timeout = 5000;");
|
|
@@ -20484,6 +20818,115 @@ var DeltaSpecSchema = exports_external.union([
|
|
|
20484
20818
|
// src/services/warning-buffer.ts
|
|
20485
20819
|
var deferredWarnings = [];
|
|
20486
20820
|
|
|
20821
|
+
// src/agents/council-prompts.ts
|
|
20822
|
+
var ROUND_PROTOCOL = `================================================================
|
|
20823
|
+
ROUND PROTOCOL
|
|
20824
|
+
================================================================
|
|
20825
|
+
|
|
20826
|
+
ROUND 1 \u2014 Independent Analysis and Answer
|
|
20827
|
+
- Use the RESEARCH CONTEXT block provided by the architect in your dispatch message as your external evidence source. The architect has already gathered the relevant web search results.
|
|
20828
|
+
- Cite EVERY factual claim that depends on external evidence with a source from the RESEARCH CONTEXT (use the title and URL exactly as given).
|
|
20829
|
+
- State your confidence (0.0\u20131.0) explicitly. Be honest \u2014 overconfident answers hurt the council.
|
|
20830
|
+
- Enumerate areas of uncertainty so the architect knows where you're guessing vs. where you're sure.
|
|
20831
|
+
- Do NOT coordinate with other members. You will not see their responses until Round 2.
|
|
20832
|
+
- Do NOT pad. Be concise. Substance over volume.
|
|
20833
|
+
|
|
20834
|
+
ROUND 2 \u2014 Targeted Deliberation (ONLY when this round is invoked for you)
|
|
20835
|
+
- The architect will pass you the disagreement topic and the opposing position(s) in the dispatch message.
|
|
20836
|
+
- Re-read the RESEARCH CONTEXT for any evidence relevant to the disagreement.
|
|
20837
|
+
- Declare your stance explicitly using one of these keywords as the FIRST word of a paragraph:
|
|
20838
|
+
MAINTAIN \u2014 your Round 1 position holds; cite the evidence supporting it
|
|
20839
|
+
CONCEDE \u2014 the opposing position is correct; state specifically what you got wrong
|
|
20840
|
+
NUANCE \u2014 both positions are partially right; state the boundary condition that distinguishes them
|
|
20841
|
+
- Never CONCEDE without evidence. Sycophantic capitulation degrades the council below an individual member's baseline (NSED arXiv:2601.16863).
|
|
20842
|
+
- Never MAINTAIN without engaging the opposing argument on its merits.`;
|
|
20843
|
+
var RESPONSE_FORMAT = `================================================================
|
|
20844
|
+
RESPONSE FORMAT (always \u2014 both rounds)
|
|
20845
|
+
================================================================
|
|
20846
|
+
|
|
20847
|
+
Reply with a single fenced JSON block. No prose outside the block.
|
|
20848
|
+
|
|
20849
|
+
\`\`\`json
|
|
20850
|
+
{
|
|
20851
|
+
"memberId": "<your hardcoded memberId>",
|
|
20852
|
+
"role": "<your hardcoded role>",
|
|
20853
|
+
"round": 1,
|
|
20854
|
+
"response": "Your full answer (Round 1) or stance + reasoning (Round 2). Markdown OK inside the string.",
|
|
20855
|
+
"searchQueries": [],
|
|
20856
|
+
"sources": [
|
|
20857
|
+
{ "title": "...", "url": "...", "snippet": "...", "query": "..." }
|
|
20858
|
+
],
|
|
20859
|
+
"confidence": 0.85,
|
|
20860
|
+
"areasOfUncertainty": [
|
|
20861
|
+
"What I'm not sure about, in plain language."
|
|
20862
|
+
],
|
|
20863
|
+
"disagreementTopics": []
|
|
20864
|
+
}
|
|
20865
|
+
\`\`\`
|
|
20866
|
+
|
|
20867
|
+
Notes:
|
|
20868
|
+
- \`searchQueries\` is optional \u2014 list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.
|
|
20869
|
+
- \`sources\` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.
|
|
20870
|
+
- For Round 1: leave \`disagreementTopics\` as []. For Round 2: list the specific disagreement topics this response addresses.`;
|
|
20871
|
+
var HARD_RULES = `================================================================
|
|
20872
|
+
HARD RULES
|
|
20873
|
+
================================================================
|
|
20874
|
+
- You have no tools. Reason from the provided RESEARCH CONTEXT and your training knowledge.
|
|
20875
|
+
- Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in \`areasOfUncertainty\`.
|
|
20876
|
+
- Never echo other members' responses verbatim. Paraphrase or quote with attribution.
|
|
20877
|
+
- Stay within your role and persona. The architect chose you for a specific perspective.`;
|
|
20878
|
+
var GENERALIST_COUNCIL_PROMPT = `You are the GENERALIST voice on a multi-model General Council.
|
|
20879
|
+
|
|
20880
|
+
You are the GENERALIST voice on this council. Your perspective is broad and synthesizing:
|
|
20881
|
+
- You reason from first principles and across disciplines.
|
|
20882
|
+
- You weigh competing considerations without domain bias.
|
|
20883
|
+
- You surface tensions between different valid approaches.
|
|
20884
|
+
- You are the integrating voice \u2014 you see what the specialists might miss by being too deep in their domain.
|
|
20885
|
+
Member ID: "council_generalist" | Role: "generalist"
|
|
20886
|
+
|
|
20887
|
+
You are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.
|
|
20888
|
+
|
|
20889
|
+
${ROUND_PROTOCOL}
|
|
20890
|
+
|
|
20891
|
+
${RESPONSE_FORMAT}
|
|
20892
|
+
|
|
20893
|
+
${HARD_RULES}
|
|
20894
|
+
`;
|
|
20895
|
+
var SKEPTIC_COUNCIL_PROMPT = `You are the SKEPTIC voice on a multi-model General Council.
|
|
20896
|
+
|
|
20897
|
+
You are the SKEPTIC voice on this council. Your job is rigorous stress-testing:
|
|
20898
|
+
- You challenge assumptions the other members take for granted.
|
|
20899
|
+
- You look for weak points, edge cases, and unstated dependencies.
|
|
20900
|
+
- You are NOT contrarian for its own sake \u2014 your pushback must be evidence-grounded.
|
|
20901
|
+
- You make the council's final answer more robust by finding what could go wrong before the user does.
|
|
20902
|
+
Member ID: "council_skeptic" | Role: "skeptic"
|
|
20903
|
+
|
|
20904
|
+
You are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.
|
|
20905
|
+
|
|
20906
|
+
${ROUND_PROTOCOL}
|
|
20907
|
+
|
|
20908
|
+
${RESPONSE_FORMAT}
|
|
20909
|
+
|
|
20910
|
+
${HARD_RULES}
|
|
20911
|
+
`;
|
|
20912
|
+
var DOMAIN_EXPERT_COUNCIL_PROMPT = `You are the DOMAIN EXPERT voice on a multi-model General Council.
|
|
20913
|
+
|
|
20914
|
+
You are the DOMAIN EXPERT voice on this council. Your perspective is technically precise:
|
|
20915
|
+
- You go deep where others stay broad.
|
|
20916
|
+
- You cite specific mechanisms, constraints, and implementation-level detail.
|
|
20917
|
+
- You surface edge cases and gotchas that only emerge at depth.
|
|
20918
|
+
- Your answers are concrete \u2014 no hand-waving, no vague recommendations.
|
|
20919
|
+
Member ID: "council_domain_expert" | Role: "domain_expert"
|
|
20920
|
+
|
|
20921
|
+
You are participating in a structured deliberation. Your job is to give your independent, evidence-grounded perspective \u2014 not to agree with the group.
|
|
20922
|
+
|
|
20923
|
+
${ROUND_PROTOCOL}
|
|
20924
|
+
|
|
20925
|
+
${RESPONSE_FORMAT}
|
|
20926
|
+
|
|
20927
|
+
${HARD_RULES}
|
|
20928
|
+
`;
|
|
20929
|
+
|
|
20487
20930
|
// src/agents/index.ts
|
|
20488
20931
|
var warnedAgents = new Set;
|
|
20489
20932
|
|
|
@@ -20491,9 +20934,10 @@ var warnedAgents = new Set;
|
|
|
20491
20934
|
init_manager();
|
|
20492
20935
|
|
|
20493
20936
|
// src/scope/scope-persistence.ts
|
|
20937
|
+
init_bun_compat();
|
|
20494
20938
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
20495
20939
|
import * as fs5 from "fs";
|
|
20496
|
-
import * as
|
|
20940
|
+
import * as path8 from "path";
|
|
20497
20941
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
20498
20942
|
var LOCK_STALE_MS = 30 * 1000;
|
|
20499
20943
|
var SCOPES_DIR = ".swarm/scopes";
|
|
@@ -20524,7 +20968,7 @@ var WINDOWS_RESERVED = new Set([
|
|
|
20524
20968
|
"LPT9"
|
|
20525
20969
|
]);
|
|
20526
20970
|
function getScopesDir(directory) {
|
|
20527
|
-
return
|
|
20971
|
+
return path8.join(directory, SCOPES_DIR);
|
|
20528
20972
|
}
|
|
20529
20973
|
function clearAllScopes(directory) {
|
|
20530
20974
|
try {
|
|
@@ -20535,6 +20979,7 @@ function clearAllScopes(directory) {
|
|
|
20535
20979
|
// src/hooks/guardrails.ts
|
|
20536
20980
|
init_telemetry();
|
|
20537
20981
|
init_utils();
|
|
20982
|
+
init_bun_compat();
|
|
20538
20983
|
init_logger();
|
|
20539
20984
|
|
|
20540
20985
|
// src/hooks/conflict-resolution.ts
|
|
@@ -21049,7 +21494,7 @@ init_zod();
|
|
|
21049
21494
|
init_zod();
|
|
21050
21495
|
import * as child_process from "child_process";
|
|
21051
21496
|
import * as fs6 from "fs";
|
|
21052
|
-
import * as
|
|
21497
|
+
import * as path9 from "path";
|
|
21053
21498
|
|
|
21054
21499
|
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
|
|
21055
21500
|
var exports_external2 = {};
|
|
@@ -21780,10 +22225,10 @@ function mergeDefs2(...defs) {
|
|
|
21780
22225
|
function cloneDef2(schema) {
|
|
21781
22226
|
return mergeDefs2(schema._zod.def);
|
|
21782
22227
|
}
|
|
21783
|
-
function getElementAtPath2(obj,
|
|
21784
|
-
if (!
|
|
22228
|
+
function getElementAtPath2(obj, path9) {
|
|
22229
|
+
if (!path9)
|
|
21785
22230
|
return obj;
|
|
21786
|
-
return
|
|
22231
|
+
return path9.reduce((acc, key) => acc?.[key], obj);
|
|
21787
22232
|
}
|
|
21788
22233
|
function promiseAllObject2(promisesObj) {
|
|
21789
22234
|
const keys = Object.keys(promisesObj);
|
|
@@ -22142,11 +22587,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
22142
22587
|
}
|
|
22143
22588
|
return false;
|
|
22144
22589
|
}
|
|
22145
|
-
function prefixIssues2(
|
|
22590
|
+
function prefixIssues2(path9, issues) {
|
|
22146
22591
|
return issues.map((iss) => {
|
|
22147
22592
|
var _a2;
|
|
22148
22593
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
22149
|
-
iss.path.unshift(
|
|
22594
|
+
iss.path.unshift(path9);
|
|
22150
22595
|
return iss;
|
|
22151
22596
|
});
|
|
22152
22597
|
}
|
|
@@ -22314,7 +22759,7 @@ function treeifyError2(error49, _mapper) {
|
|
|
22314
22759
|
return issue3.message;
|
|
22315
22760
|
};
|
|
22316
22761
|
const result = { errors: [] };
|
|
22317
|
-
const processError = (error50,
|
|
22762
|
+
const processError = (error50, path9 = []) => {
|
|
22318
22763
|
var _a2, _b;
|
|
22319
22764
|
for (const issue3 of error50.issues) {
|
|
22320
22765
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -22324,7 +22769,7 @@ function treeifyError2(error49, _mapper) {
|
|
|
22324
22769
|
} else if (issue3.code === "invalid_element") {
|
|
22325
22770
|
processError({ issues: issue3.issues }, issue3.path);
|
|
22326
22771
|
} else {
|
|
22327
|
-
const fullpath = [...
|
|
22772
|
+
const fullpath = [...path9, ...issue3.path];
|
|
22328
22773
|
if (fullpath.length === 0) {
|
|
22329
22774
|
result.errors.push(mapper(issue3));
|
|
22330
22775
|
continue;
|
|
@@ -22356,8 +22801,8 @@ function treeifyError2(error49, _mapper) {
|
|
|
22356
22801
|
}
|
|
22357
22802
|
function toDotPath2(_path) {
|
|
22358
22803
|
const segs = [];
|
|
22359
|
-
const
|
|
22360
|
-
for (const seg of
|
|
22804
|
+
const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
22805
|
+
for (const seg of path9) {
|
|
22361
22806
|
if (typeof seg === "number")
|
|
22362
22807
|
segs.push(`[${seg}]`);
|
|
22363
22808
|
else if (typeof seg === "symbol")
|
|
@@ -33455,7 +33900,7 @@ function validateLabel(label) {
|
|
|
33455
33900
|
return null;
|
|
33456
33901
|
}
|
|
33457
33902
|
function getCheckpointLogPath(directory) {
|
|
33458
|
-
return
|
|
33903
|
+
return path9.join(directory, CHECKPOINT_LOG_PATH);
|
|
33459
33904
|
}
|
|
33460
33905
|
function readCheckpointLog(directory) {
|
|
33461
33906
|
const logPath = getCheckpointLogPath(directory);
|
|
@@ -33473,7 +33918,7 @@ function readCheckpointLog(directory) {
|
|
|
33473
33918
|
}
|
|
33474
33919
|
function writeCheckpointLog(log2, directory) {
|
|
33475
33920
|
const logPath = getCheckpointLogPath(directory);
|
|
33476
|
-
const dir =
|
|
33921
|
+
const dir = path9.dirname(logPath);
|
|
33477
33922
|
if (!fs6.existsSync(dir)) {
|
|
33478
33923
|
fs6.mkdirSync(dir, { recursive: true });
|
|
33479
33924
|
}
|
|
@@ -33828,7 +34273,7 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
33828
34273
|
|
|
33829
34274
|
// src/commands/close.ts
|
|
33830
34275
|
import { promises as fs7 } from "fs";
|
|
33831
|
-
import
|
|
34276
|
+
import path13 from "path";
|
|
33832
34277
|
init_manager2();
|
|
33833
34278
|
|
|
33834
34279
|
// src/git/branch.ts
|
|
@@ -34077,36 +34522,36 @@ function resetToRemoteBranch(cwd, options) {
|
|
|
34077
34522
|
// src/hooks/knowledge-store.ts
|
|
34078
34523
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
34079
34524
|
import { existsSync as existsSync7 } from "fs";
|
|
34080
|
-
import { appendFile as appendFile2, mkdir, readFile as
|
|
34525
|
+
import { appendFile as appendFile2, mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
34081
34526
|
import * as os3 from "os";
|
|
34082
|
-
import * as
|
|
34527
|
+
import * as path10 from "path";
|
|
34083
34528
|
function resolveSwarmKnowledgePath(directory) {
|
|
34084
|
-
return
|
|
34529
|
+
return path10.join(directory, ".swarm", "knowledge.jsonl");
|
|
34085
34530
|
}
|
|
34086
34531
|
function resolveSwarmRejectedPath(directory) {
|
|
34087
|
-
return
|
|
34532
|
+
return path10.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
34088
34533
|
}
|
|
34089
34534
|
function resolveHiveKnowledgePath() {
|
|
34090
34535
|
const platform = process.platform;
|
|
34091
34536
|
const home = process.env.HOME || os3.homedir();
|
|
34092
34537
|
let dataDir;
|
|
34093
34538
|
if (platform === "win32") {
|
|
34094
|
-
dataDir =
|
|
34539
|
+
dataDir = path10.join(process.env.LOCALAPPDATA || path10.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
34095
34540
|
} else if (platform === "darwin") {
|
|
34096
|
-
dataDir =
|
|
34541
|
+
dataDir = path10.join(home, "Library", "Application Support", "opencode-swarm");
|
|
34097
34542
|
} else {
|
|
34098
|
-
dataDir =
|
|
34543
|
+
dataDir = path10.join(process.env.XDG_DATA_HOME || path10.join(home, ".local", "share"), "opencode-swarm");
|
|
34099
34544
|
}
|
|
34100
|
-
return
|
|
34545
|
+
return path10.join(dataDir, "shared-learnings.jsonl");
|
|
34101
34546
|
}
|
|
34102
34547
|
function resolveHiveRejectedPath() {
|
|
34103
34548
|
const hivePath = resolveHiveKnowledgePath();
|
|
34104
|
-
return
|
|
34549
|
+
return path10.join(path10.dirname(hivePath), "shared-learnings-rejected.jsonl");
|
|
34105
34550
|
}
|
|
34106
34551
|
async function readKnowledge(filePath) {
|
|
34107
34552
|
if (!existsSync7(filePath))
|
|
34108
34553
|
return [];
|
|
34109
|
-
const content = await
|
|
34554
|
+
const content = await readFile3(filePath, "utf-8");
|
|
34110
34555
|
const results = [];
|
|
34111
34556
|
for (const line of content.split(`
|
|
34112
34557
|
`)) {
|
|
@@ -34125,13 +34570,13 @@ async function readRejectedLessons(directory) {
|
|
|
34125
34570
|
return readKnowledge(resolveSwarmRejectedPath(directory));
|
|
34126
34571
|
}
|
|
34127
34572
|
async function appendKnowledge(filePath, entry) {
|
|
34128
|
-
await
|
|
34573
|
+
await mkdir2(path10.dirname(filePath), { recursive: true });
|
|
34129
34574
|
await appendFile2(filePath, `${JSON.stringify(entry)}
|
|
34130
34575
|
`, "utf-8");
|
|
34131
34576
|
}
|
|
34132
34577
|
async function rewriteKnowledge(filePath, entries) {
|
|
34133
|
-
const dir =
|
|
34134
|
-
await
|
|
34578
|
+
const dir = path10.dirname(filePath);
|
|
34579
|
+
await mkdir2(dir, { recursive: true });
|
|
34135
34580
|
let release = null;
|
|
34136
34581
|
try {
|
|
34137
34582
|
release = await import_proper_lockfile3.default.lock(dir, {
|
|
@@ -34141,7 +34586,7 @@ async function rewriteKnowledge(filePath, entries) {
|
|
|
34141
34586
|
const content = entries.map((e) => JSON.stringify(e)).join(`
|
|
34142
34587
|
`) + (entries.length > 0 ? `
|
|
34143
34588
|
` : "");
|
|
34144
|
-
await
|
|
34589
|
+
await writeFile3(filePath, content, "utf-8");
|
|
34145
34590
|
} finally {
|
|
34146
34591
|
if (release) {
|
|
34147
34592
|
try {
|
|
@@ -34240,8 +34685,8 @@ function inferTags(lesson) {
|
|
|
34240
34685
|
|
|
34241
34686
|
// src/hooks/knowledge-validator.ts
|
|
34242
34687
|
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
34243
|
-
import { appendFile as appendFile3, mkdir as
|
|
34244
|
-
import * as
|
|
34688
|
+
import { appendFile as appendFile3, mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
|
|
34689
|
+
import * as path11 from "path";
|
|
34245
34690
|
var DANGEROUS_COMMAND_PATTERNS = [
|
|
34246
34691
|
/\brm\s+-rf\b/,
|
|
34247
34692
|
/\bsudo\s+rm\b/,
|
|
@@ -34496,11 +34941,11 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
|
|
|
34496
34941
|
return;
|
|
34497
34942
|
}
|
|
34498
34943
|
const sanitizedReason = reason.slice(0, 500).replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/g, "");
|
|
34499
|
-
const knowledgePath =
|
|
34500
|
-
const quarantinePath =
|
|
34501
|
-
const rejectedPath =
|
|
34502
|
-
const swarmDir =
|
|
34503
|
-
await
|
|
34944
|
+
const knowledgePath = path11.join(directory, ".swarm", "knowledge.jsonl");
|
|
34945
|
+
const quarantinePath = path11.join(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
34946
|
+
const rejectedPath = path11.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
34947
|
+
const swarmDir = path11.join(directory, ".swarm");
|
|
34948
|
+
await mkdir3(swarmDir, { recursive: true });
|
|
34504
34949
|
let release;
|
|
34505
34950
|
try {
|
|
34506
34951
|
release = await import_proper_lockfile4.default.lock(swarmDir, {
|
|
@@ -34521,7 +34966,7 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
|
|
|
34521
34966
|
const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
|
|
34522
34967
|
`)}
|
|
34523
34968
|
` : "";
|
|
34524
|
-
await
|
|
34969
|
+
await writeFile4(knowledgePath, jsonlContent, "utf-8");
|
|
34525
34970
|
await appendFile3(quarantinePath, `${JSON.stringify(quarantined)}
|
|
34526
34971
|
`, "utf-8");
|
|
34527
34972
|
const quarantinedEntries = await readKnowledge(quarantinePath);
|
|
@@ -34530,7 +34975,7 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
|
|
|
34530
34975
|
const capContent = trimmed.length > 0 ? `${trimmed.map((e) => JSON.stringify(e)).join(`
|
|
34531
34976
|
`)}
|
|
34532
34977
|
` : "";
|
|
34533
|
-
await
|
|
34978
|
+
await writeFile4(quarantinePath, capContent, "utf-8");
|
|
34534
34979
|
}
|
|
34535
34980
|
const rejectedRecord = {
|
|
34536
34981
|
id: entryId,
|
|
@@ -34556,11 +35001,11 @@ async function restoreEntry(directory, entryId) {
|
|
|
34556
35001
|
console.warn("[knowledge-validator] restoreEntry: invalid entryId rejected");
|
|
34557
35002
|
return;
|
|
34558
35003
|
}
|
|
34559
|
-
const knowledgePath =
|
|
34560
|
-
const quarantinePath =
|
|
34561
|
-
const rejectedPath =
|
|
34562
|
-
const swarmDir =
|
|
34563
|
-
await
|
|
35004
|
+
const knowledgePath = path11.join(directory, ".swarm", "knowledge.jsonl");
|
|
35005
|
+
const quarantinePath = path11.join(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
35006
|
+
const rejectedPath = path11.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
35007
|
+
const swarmDir = path11.join(directory, ".swarm");
|
|
35008
|
+
await mkdir3(swarmDir, { recursive: true });
|
|
34564
35009
|
let release;
|
|
34565
35010
|
try {
|
|
34566
35011
|
release = await import_proper_lockfile4.default.lock(swarmDir, {
|
|
@@ -34576,7 +35021,7 @@ async function restoreEntry(directory, entryId) {
|
|
|
34576
35021
|
const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
|
|
34577
35022
|
`)}
|
|
34578
35023
|
` : "";
|
|
34579
|
-
await
|
|
35024
|
+
await writeFile4(quarantinePath, jsonlContent, "utf-8");
|
|
34580
35025
|
await appendFile3(knowledgePath, `${JSON.stringify(original)}
|
|
34581
35026
|
`, "utf-8");
|
|
34582
35027
|
const rejectedEntries = await readKnowledge(rejectedPath);
|
|
@@ -34584,7 +35029,7 @@ async function restoreEntry(directory, entryId) {
|
|
|
34584
35029
|
const rejectedContent = filtered.length > 0 ? `${filtered.map((e) => JSON.stringify(e)).join(`
|
|
34585
35030
|
`)}
|
|
34586
35031
|
` : "";
|
|
34587
|
-
await
|
|
35032
|
+
await writeFile4(rejectedPath, rejectedContent, "utf-8");
|
|
34588
35033
|
} finally {
|
|
34589
35034
|
if (release) {
|
|
34590
35035
|
await release();
|
|
@@ -34717,8 +35162,9 @@ init_utils2();
|
|
|
34717
35162
|
// src/session/snapshot-writer.ts
|
|
34718
35163
|
init_utils2();
|
|
34719
35164
|
import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
|
|
34720
|
-
import * as
|
|
35165
|
+
import * as path12 from "path";
|
|
34721
35166
|
init_utils();
|
|
35167
|
+
init_bun_compat();
|
|
34722
35168
|
var _writeInFlight = Promise.resolve();
|
|
34723
35169
|
function serializeAgentSession(s) {
|
|
34724
35170
|
const gateLog = {};
|
|
@@ -34809,10 +35255,10 @@ async function writeSnapshot(directory, state) {
|
|
|
34809
35255
|
}
|
|
34810
35256
|
const content = JSON.stringify(snapshot, null, 2);
|
|
34811
35257
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
34812
|
-
const dir =
|
|
35258
|
+
const dir = path12.dirname(resolvedPath);
|
|
34813
35259
|
mkdirSync7(dir, { recursive: true });
|
|
34814
35260
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
34815
|
-
await
|
|
35261
|
+
await bunWrite(tempPath, content);
|
|
34816
35262
|
renameSync5(tempPath, resolvedPath);
|
|
34817
35263
|
} catch (error93) {
|
|
34818
35264
|
log("[snapshot-writer] write failed", {
|
|
@@ -35222,10 +35668,10 @@ function guaranteeAllPlansComplete(planData) {
|
|
|
35222
35668
|
}
|
|
35223
35669
|
async function handleCloseCommand(directory, args) {
|
|
35224
35670
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
35225
|
-
const swarmDir =
|
|
35671
|
+
const swarmDir = path13.join(directory, ".swarm");
|
|
35226
35672
|
let planExists = false;
|
|
35227
35673
|
let planData = {
|
|
35228
|
-
title:
|
|
35674
|
+
title: path13.basename(directory) || "Ad-hoc session",
|
|
35229
35675
|
phases: []
|
|
35230
35676
|
};
|
|
35231
35677
|
try {
|
|
@@ -35330,7 +35776,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35330
35776
|
warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
35331
35777
|
}
|
|
35332
35778
|
}
|
|
35333
|
-
const lessonsFilePath =
|
|
35779
|
+
const lessonsFilePath = path13.join(swarmDir, "close-lessons.md");
|
|
35334
35780
|
let explicitLessons = [];
|
|
35335
35781
|
try {
|
|
35336
35782
|
const lessonsText = await fs7.readFile(lessonsFilePath, "utf-8");
|
|
@@ -35339,11 +35785,11 @@ async function handleCloseCommand(directory, args) {
|
|
|
35339
35785
|
} catch {}
|
|
35340
35786
|
const retroLessons = [];
|
|
35341
35787
|
try {
|
|
35342
|
-
const evidenceDir =
|
|
35788
|
+
const evidenceDir = path13.join(swarmDir, "evidence");
|
|
35343
35789
|
const evidenceEntries = await fs7.readdir(evidenceDir);
|
|
35344
|
-
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-"));
|
|
35790
|
+
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
35345
35791
|
for (const retroDir of retroDirs) {
|
|
35346
|
-
const evidencePath =
|
|
35792
|
+
const evidencePath = path13.join(evidenceDir, retroDir, "evidence.json");
|
|
35347
35793
|
try {
|
|
35348
35794
|
const content = await fs7.readFile(evidencePath, "utf-8");
|
|
35349
35795
|
const parsed = JSON.parse(content);
|
|
@@ -35397,15 +35843,15 @@ async function handleCloseCommand(directory, args) {
|
|
|
35397
35843
|
}
|
|
35398
35844
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
35399
35845
|
const suffix = Math.random().toString(36).slice(2, 8);
|
|
35400
|
-
const archiveDir =
|
|
35846
|
+
const archiveDir = path13.join(swarmDir, "archive", `swarm-${timestamp}-${suffix}`);
|
|
35401
35847
|
let archiveResult = "";
|
|
35402
35848
|
let archivedFileCount = 0;
|
|
35403
35849
|
const archivedActiveStateFiles = new Set;
|
|
35404
35850
|
try {
|
|
35405
35851
|
await fs7.mkdir(archiveDir, { recursive: true });
|
|
35406
35852
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
35407
|
-
const srcPath =
|
|
35408
|
-
const destPath =
|
|
35853
|
+
const srcPath = path13.join(swarmDir, artifact);
|
|
35854
|
+
const destPath = path13.join(archiveDir, artifact);
|
|
35409
35855
|
try {
|
|
35410
35856
|
await fs7.copyFile(srcPath, destPath);
|
|
35411
35857
|
archivedFileCount++;
|
|
@@ -35414,22 +35860,22 @@ async function handleCloseCommand(directory, args) {
|
|
|
35414
35860
|
}
|
|
35415
35861
|
} catch {}
|
|
35416
35862
|
}
|
|
35417
|
-
const evidenceDir =
|
|
35418
|
-
const archiveEvidenceDir =
|
|
35863
|
+
const evidenceDir = path13.join(swarmDir, "evidence");
|
|
35864
|
+
const archiveEvidenceDir = path13.join(archiveDir, "evidence");
|
|
35419
35865
|
try {
|
|
35420
35866
|
const evidenceEntries = await fs7.readdir(evidenceDir);
|
|
35421
35867
|
if (evidenceEntries.length > 0) {
|
|
35422
35868
|
await fs7.mkdir(archiveEvidenceDir, { recursive: true });
|
|
35423
35869
|
for (const entry of evidenceEntries) {
|
|
35424
|
-
const srcEntry =
|
|
35425
|
-
const destEntry =
|
|
35870
|
+
const srcEntry = path13.join(evidenceDir, entry);
|
|
35871
|
+
const destEntry = path13.join(archiveEvidenceDir, entry);
|
|
35426
35872
|
try {
|
|
35427
|
-
const
|
|
35428
|
-
if (
|
|
35873
|
+
const stat2 = await fs7.stat(srcEntry);
|
|
35874
|
+
if (stat2.isDirectory()) {
|
|
35429
35875
|
await fs7.mkdir(destEntry, { recursive: true });
|
|
35430
35876
|
const subEntries = await fs7.readdir(srcEntry);
|
|
35431
35877
|
for (const sub of subEntries) {
|
|
35432
|
-
await fs7.copyFile(
|
|
35878
|
+
await fs7.copyFile(path13.join(srcEntry, sub), path13.join(destEntry, sub)).catch(() => {});
|
|
35433
35879
|
}
|
|
35434
35880
|
} else {
|
|
35435
35881
|
await fs7.copyFile(srcEntry, destEntry);
|
|
@@ -35439,11 +35885,11 @@ async function handleCloseCommand(directory, args) {
|
|
|
35439
35885
|
}
|
|
35440
35886
|
}
|
|
35441
35887
|
} catch {}
|
|
35442
|
-
const sessionStatePath =
|
|
35888
|
+
const sessionStatePath = path13.join(swarmDir, "session", "state.json");
|
|
35443
35889
|
try {
|
|
35444
|
-
const archiveSessionDir =
|
|
35890
|
+
const archiveSessionDir = path13.join(archiveDir, "session");
|
|
35445
35891
|
await fs7.mkdir(archiveSessionDir, { recursive: true });
|
|
35446
|
-
await fs7.copyFile(sessionStatePath,
|
|
35892
|
+
await fs7.copyFile(sessionStatePath, path13.join(archiveSessionDir, "state.json"));
|
|
35447
35893
|
archivedFileCount++;
|
|
35448
35894
|
} catch {}
|
|
35449
35895
|
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
@@ -35466,7 +35912,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35466
35912
|
warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
|
|
35467
35913
|
continue;
|
|
35468
35914
|
}
|
|
35469
|
-
const filePath =
|
|
35915
|
+
const filePath = path13.join(swarmDir, artifact);
|
|
35470
35916
|
try {
|
|
35471
35917
|
await fs7.unlink(filePath);
|
|
35472
35918
|
cleanedFiles.push(artifact);
|
|
@@ -35480,23 +35926,23 @@ async function handleCloseCommand(directory, args) {
|
|
|
35480
35926
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
35481
35927
|
for (const backup of configBackups) {
|
|
35482
35928
|
try {
|
|
35483
|
-
await fs7.unlink(
|
|
35929
|
+
await fs7.unlink(path13.join(swarmDir, backup));
|
|
35484
35930
|
configBackupsRemoved++;
|
|
35485
35931
|
} catch {}
|
|
35486
35932
|
}
|
|
35487
35933
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
35488
35934
|
for (const sibling of ledgerSiblings) {
|
|
35489
35935
|
try {
|
|
35490
|
-
await fs7.unlink(
|
|
35936
|
+
await fs7.unlink(path13.join(swarmDir, sibling));
|
|
35491
35937
|
} catch {}
|
|
35492
35938
|
}
|
|
35493
35939
|
} catch {}
|
|
35494
35940
|
let swarmPlanFilesRemoved = 0;
|
|
35495
35941
|
const candidates = [
|
|
35496
|
-
|
|
35497
|
-
|
|
35498
|
-
|
|
35499
|
-
|
|
35942
|
+
path13.join(directory, ".swarm", "SWARM_PLAN.json"),
|
|
35943
|
+
path13.join(directory, ".swarm", "SWARM_PLAN.md"),
|
|
35944
|
+
path13.join(directory, "SWARM_PLAN.json"),
|
|
35945
|
+
path13.join(directory, "SWARM_PLAN.md")
|
|
35500
35946
|
];
|
|
35501
35947
|
for (const candidate of candidates) {
|
|
35502
35948
|
try {
|
|
@@ -35504,12 +35950,12 @@ async function handleCloseCommand(directory, args) {
|
|
|
35504
35950
|
swarmPlanFilesRemoved++;
|
|
35505
35951
|
} catch (err) {
|
|
35506
35952
|
if (err?.code !== "ENOENT") {
|
|
35507
|
-
warnings.push(`Failed to remove ${
|
|
35953
|
+
warnings.push(`Failed to remove ${path13.basename(candidate)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
35508
35954
|
}
|
|
35509
35955
|
}
|
|
35510
35956
|
}
|
|
35511
35957
|
clearAllScopes(directory);
|
|
35512
|
-
const contextPath =
|
|
35958
|
+
const contextPath = path13.join(swarmDir, "context.md");
|
|
35513
35959
|
const contextContent = [
|
|
35514
35960
|
"# Context",
|
|
35515
35961
|
"",
|
|
@@ -35644,14 +36090,14 @@ ${otherWarnings.map((w) => `- ${w}`).join(`
|
|
|
35644
36090
|
|
|
35645
36091
|
// src/commands/config.ts
|
|
35646
36092
|
import * as os4 from "os";
|
|
35647
|
-
import * as
|
|
36093
|
+
import * as path14 from "path";
|
|
35648
36094
|
function getUserConfigDir2() {
|
|
35649
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
36095
|
+
return process.env.XDG_CONFIG_HOME || path14.join(os4.homedir(), ".config");
|
|
35650
36096
|
}
|
|
35651
36097
|
async function handleConfigCommand(directory, _args) {
|
|
35652
36098
|
const config3 = loadPluginConfig(directory);
|
|
35653
|
-
const userConfigPath =
|
|
35654
|
-
const projectConfigPath =
|
|
36099
|
+
const userConfigPath = path14.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
36100
|
+
const projectConfigPath = path14.join(directory, ".opencode", "opencode-swarm.json");
|
|
35655
36101
|
const lines = [
|
|
35656
36102
|
"## Swarm Configuration",
|
|
35657
36103
|
"",
|
|
@@ -35737,7 +36183,7 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
35737
36183
|
}
|
|
35738
36184
|
|
|
35739
36185
|
// src/hooks/hive-promoter.ts
|
|
35740
|
-
import
|
|
36186
|
+
import path15 from "path";
|
|
35741
36187
|
|
|
35742
36188
|
// src/background/event-bus.ts
|
|
35743
36189
|
init_utils();
|
|
@@ -35810,6 +36256,7 @@ function getGlobalEventBus() {
|
|
|
35810
36256
|
|
|
35811
36257
|
// src/hooks/curator.ts
|
|
35812
36258
|
init_manager();
|
|
36259
|
+
init_bun_compat();
|
|
35813
36260
|
init_logger();
|
|
35814
36261
|
init_utils2();
|
|
35815
36262
|
|
|
@@ -35993,7 +36440,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
35993
36440
|
schema_version: 1,
|
|
35994
36441
|
created_at: new Date().toISOString(),
|
|
35995
36442
|
updated_at: new Date().toISOString(),
|
|
35996
|
-
source_project:
|
|
36443
|
+
source_project: path15.basename(directory) || "unknown",
|
|
35997
36444
|
encounter_score: 1
|
|
35998
36445
|
};
|
|
35999
36446
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
@@ -36071,14 +36518,14 @@ function formatCurationSummary(summary) {
|
|
|
36071
36518
|
}
|
|
36072
36519
|
|
|
36073
36520
|
// src/commands/dark-matter.ts
|
|
36074
|
-
import
|
|
36521
|
+
import path17 from "path";
|
|
36075
36522
|
|
|
36076
36523
|
// src/tools/co-change-analyzer.ts
|
|
36077
36524
|
init_zod();
|
|
36078
36525
|
import * as child_process3 from "child_process";
|
|
36079
36526
|
import { randomUUID } from "crypto";
|
|
36080
|
-
import { readdir, readFile as
|
|
36081
|
-
import * as
|
|
36527
|
+
import { readdir, readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
36528
|
+
import * as path16 from "path";
|
|
36082
36529
|
import { promisify } from "util";
|
|
36083
36530
|
function getExecFileAsync() {
|
|
36084
36531
|
return promisify(child_process3.execFile);
|
|
@@ -36180,7 +36627,7 @@ async function scanSourceFiles(dir) {
|
|
|
36180
36627
|
try {
|
|
36181
36628
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
36182
36629
|
for (const entry of entries) {
|
|
36183
|
-
const fullPath =
|
|
36630
|
+
const fullPath = path16.join(dir, entry.name);
|
|
36184
36631
|
if (entry.isDirectory()) {
|
|
36185
36632
|
if (skipDirs.has(entry.name)) {
|
|
36186
36633
|
continue;
|
|
@@ -36188,7 +36635,7 @@ async function scanSourceFiles(dir) {
|
|
|
36188
36635
|
const subFiles = await scanSourceFiles(fullPath);
|
|
36189
36636
|
results.push(...subFiles);
|
|
36190
36637
|
} else if (entry.isFile()) {
|
|
36191
|
-
const ext =
|
|
36638
|
+
const ext = path16.extname(entry.name);
|
|
36192
36639
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
36193
36640
|
results.push(fullPath);
|
|
36194
36641
|
}
|
|
@@ -36202,7 +36649,7 @@ async function getStaticEdges(directory) {
|
|
|
36202
36649
|
const sourceFiles = await scanSourceFiles(directory);
|
|
36203
36650
|
for (const sourceFile of sourceFiles) {
|
|
36204
36651
|
try {
|
|
36205
|
-
const content = await
|
|
36652
|
+
const content = await readFile4(sourceFile, "utf-8");
|
|
36206
36653
|
const importRegex = /(?:import|require)\s*(?:\(?\s*['"`]|.*?from\s+['"`])([^'"`]+)['"`]/g;
|
|
36207
36654
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
36208
36655
|
const importPath = match[1].trim();
|
|
@@ -36210,8 +36657,8 @@ async function getStaticEdges(directory) {
|
|
|
36210
36657
|
continue;
|
|
36211
36658
|
}
|
|
36212
36659
|
try {
|
|
36213
|
-
const sourceDir =
|
|
36214
|
-
const resolvedPath =
|
|
36660
|
+
const sourceDir = path16.dirname(sourceFile);
|
|
36661
|
+
const resolvedPath = path16.resolve(sourceDir, importPath);
|
|
36215
36662
|
const extensions = [
|
|
36216
36663
|
"",
|
|
36217
36664
|
".ts",
|
|
@@ -36226,7 +36673,7 @@ async function getStaticEdges(directory) {
|
|
|
36226
36673
|
for (const ext of extensions) {
|
|
36227
36674
|
const testPath = resolvedPath + ext;
|
|
36228
36675
|
try {
|
|
36229
|
-
const testStat = await
|
|
36676
|
+
const testStat = await stat2(testPath);
|
|
36230
36677
|
if (testStat.isFile()) {
|
|
36231
36678
|
targetFile = testPath;
|
|
36232
36679
|
break;
|
|
@@ -36236,8 +36683,8 @@ async function getStaticEdges(directory) {
|
|
|
36236
36683
|
if (!targetFile) {
|
|
36237
36684
|
continue;
|
|
36238
36685
|
}
|
|
36239
|
-
const relSource =
|
|
36240
|
-
const relTarget =
|
|
36686
|
+
const relSource = path16.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
36687
|
+
const relTarget = path16.relative(directory, targetFile).replace(/\\/g, "/");
|
|
36241
36688
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
36242
36689
|
edges.add(key);
|
|
36243
36690
|
} catch {}
|
|
@@ -36249,7 +36696,7 @@ async function getStaticEdges(directory) {
|
|
|
36249
36696
|
function isTestImplementationPair(fileA, fileB) {
|
|
36250
36697
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
36251
36698
|
const getBaseName = (filePath) => {
|
|
36252
|
-
const base =
|
|
36699
|
+
const base = path16.basename(filePath);
|
|
36253
36700
|
for (const pattern of testPatterns) {
|
|
36254
36701
|
if (base.endsWith(pattern)) {
|
|
36255
36702
|
return base.slice(0, -pattern.length);
|
|
@@ -36259,16 +36706,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
36259
36706
|
};
|
|
36260
36707
|
const baseA = getBaseName(fileA);
|
|
36261
36708
|
const baseB = getBaseName(fileB);
|
|
36262
|
-
return baseA === baseB && baseA !==
|
|
36709
|
+
return baseA === baseB && baseA !== path16.basename(fileA) && baseA !== path16.basename(fileB);
|
|
36263
36710
|
}
|
|
36264
36711
|
function hasSharedPrefix(fileA, fileB) {
|
|
36265
|
-
const dirA =
|
|
36266
|
-
const dirB =
|
|
36712
|
+
const dirA = path16.dirname(fileA);
|
|
36713
|
+
const dirB = path16.dirname(fileB);
|
|
36267
36714
|
if (dirA !== dirB) {
|
|
36268
36715
|
return false;
|
|
36269
36716
|
}
|
|
36270
|
-
const baseA =
|
|
36271
|
-
const baseB =
|
|
36717
|
+
const baseA = path16.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
36718
|
+
const baseB = path16.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
36272
36719
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
36273
36720
|
return true;
|
|
36274
36721
|
}
|
|
@@ -36322,8 +36769,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
36322
36769
|
const entries = [];
|
|
36323
36770
|
const now = new Date().toISOString();
|
|
36324
36771
|
for (const pair of pairs.slice(0, 10)) {
|
|
36325
|
-
const baseA =
|
|
36326
|
-
const baseB =
|
|
36772
|
+
const baseA = path16.basename(pair.fileA);
|
|
36773
|
+
const baseB = path16.basename(pair.fileB);
|
|
36327
36774
|
let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
36328
36775
|
if (lesson.length > 280) {
|
|
36329
36776
|
lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
@@ -36433,7 +36880,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36433
36880
|
const output = formatDarkMatterOutput(pairs);
|
|
36434
36881
|
if (pairs.length > 0) {
|
|
36435
36882
|
try {
|
|
36436
|
-
const projectName =
|
|
36883
|
+
const projectName = path17.basename(path17.resolve(directory));
|
|
36437
36884
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
36438
36885
|
if (entries.length > 0) {
|
|
36439
36886
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -36454,50 +36901,50 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36454
36901
|
|
|
36455
36902
|
// src/services/diagnose-service.ts
|
|
36456
36903
|
import * as child_process4 from "child_process";
|
|
36457
|
-
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as
|
|
36458
|
-
import
|
|
36904
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync6 } from "fs";
|
|
36905
|
+
import path19 from "path";
|
|
36459
36906
|
import { fileURLToPath } from "url";
|
|
36460
36907
|
|
|
36461
36908
|
// src/config/cache-paths.ts
|
|
36462
36909
|
import * as os5 from "os";
|
|
36463
|
-
import * as
|
|
36910
|
+
import * as path18 from "path";
|
|
36464
36911
|
function getPluginConfigDir() {
|
|
36465
|
-
return
|
|
36912
|
+
return path18.join(process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config"), "opencode");
|
|
36466
36913
|
}
|
|
36467
36914
|
function getPluginCachePaths() {
|
|
36468
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
36915
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path18.join(os5.homedir(), ".cache");
|
|
36469
36916
|
const configDir = getPluginConfigDir();
|
|
36470
36917
|
const paths = [
|
|
36471
|
-
|
|
36472
|
-
|
|
36473
|
-
|
|
36918
|
+
path18.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
36919
|
+
path18.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
36920
|
+
path18.join(configDir, "node_modules", "opencode-swarm")
|
|
36474
36921
|
];
|
|
36475
36922
|
if (process.platform === "darwin") {
|
|
36476
|
-
const libCaches =
|
|
36477
|
-
paths.push(
|
|
36923
|
+
const libCaches = path18.join(os5.homedir(), "Library", "Caches");
|
|
36924
|
+
paths.push(path18.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path18.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
36478
36925
|
}
|
|
36479
36926
|
if (process.platform === "win32") {
|
|
36480
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
36481
|
-
const appData = process.env.APPDATA ||
|
|
36482
|
-
paths.push(
|
|
36927
|
+
const localAppData = process.env.LOCALAPPDATA || path18.join(os5.homedir(), "AppData", "Local");
|
|
36928
|
+
const appData = process.env.APPDATA || path18.join(os5.homedir(), "AppData", "Roaming");
|
|
36929
|
+
paths.push(path18.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path18.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path18.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
36483
36930
|
}
|
|
36484
36931
|
return paths;
|
|
36485
36932
|
}
|
|
36486
36933
|
function getPluginLockFilePaths() {
|
|
36487
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
36934
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path18.join(os5.homedir(), ".cache");
|
|
36488
36935
|
const configDir = getPluginConfigDir();
|
|
36489
36936
|
const paths = [
|
|
36490
|
-
|
|
36491
|
-
|
|
36492
|
-
|
|
36937
|
+
path18.join(cacheBase, "opencode", "bun.lock"),
|
|
36938
|
+
path18.join(cacheBase, "opencode", "bun.lockb"),
|
|
36939
|
+
path18.join(configDir, "package-lock.json")
|
|
36493
36940
|
];
|
|
36494
36941
|
if (process.platform === "darwin") {
|
|
36495
|
-
const libCaches =
|
|
36496
|
-
paths.push(
|
|
36942
|
+
const libCaches = path18.join(os5.homedir(), "Library", "Caches");
|
|
36943
|
+
paths.push(path18.join(libCaches, "opencode", "bun.lock"), path18.join(libCaches, "opencode", "bun.lockb"));
|
|
36497
36944
|
}
|
|
36498
36945
|
if (process.platform === "win32") {
|
|
36499
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
36500
|
-
paths.push(
|
|
36946
|
+
const localAppData = process.env.LOCALAPPDATA || path18.join(os5.homedir(), "AppData", "Local");
|
|
36947
|
+
paths.push(path18.join(localAppData, "opencode", "bun.lock"), path18.join(localAppData, "opencode", "bun.lockb"));
|
|
36501
36948
|
}
|
|
36502
36949
|
return paths;
|
|
36503
36950
|
}
|
|
@@ -36510,22 +36957,22 @@ init_manager();
|
|
|
36510
36957
|
// src/services/version-check.ts
|
|
36511
36958
|
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
36512
36959
|
import { homedir as homedir5 } from "os";
|
|
36513
|
-
import { join as
|
|
36960
|
+
import { join as join16 } from "path";
|
|
36514
36961
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
36515
36962
|
function cacheDir() {
|
|
36516
36963
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
36517
|
-
const base = xdg && xdg.length > 0 ? xdg :
|
|
36518
|
-
return
|
|
36964
|
+
const base = xdg && xdg.length > 0 ? xdg : join16(homedir5(), ".cache");
|
|
36965
|
+
return join16(base, "opencode-swarm");
|
|
36519
36966
|
}
|
|
36520
36967
|
function cacheFile() {
|
|
36521
|
-
return
|
|
36968
|
+
return join16(cacheDir(), "version-check.json");
|
|
36522
36969
|
}
|
|
36523
36970
|
function readVersionCache() {
|
|
36524
36971
|
try {
|
|
36525
|
-
const
|
|
36526
|
-
if (!existsSync8(
|
|
36972
|
+
const path19 = cacheFile();
|
|
36973
|
+
if (!existsSync8(path19))
|
|
36527
36974
|
return null;
|
|
36528
|
-
const raw = readFileSync5(
|
|
36975
|
+
const raw = readFileSync5(path19, "utf-8");
|
|
36529
36976
|
const parsed = JSON.parse(raw);
|
|
36530
36977
|
if (typeof parsed?.checkedAt !== "number")
|
|
36531
36978
|
return null;
|
|
@@ -36791,7 +37238,7 @@ async function checkConfigBackups(directory) {
|
|
|
36791
37238
|
}
|
|
36792
37239
|
async function checkGitRepository(directory) {
|
|
36793
37240
|
try {
|
|
36794
|
-
if (!existsSync9(directory) || !
|
|
37241
|
+
if (!existsSync9(directory) || !statSync6(directory).isDirectory()) {
|
|
36795
37242
|
return {
|
|
36796
37243
|
name: "Git Repository",
|
|
36797
37244
|
status: "\u274C",
|
|
@@ -36855,7 +37302,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
36855
37302
|
};
|
|
36856
37303
|
}
|
|
36857
37304
|
async function checkConfigParseability(directory) {
|
|
36858
|
-
const configPath =
|
|
37305
|
+
const configPath = path19.join(directory, ".opencode/opencode-swarm.json");
|
|
36859
37306
|
if (!existsSync9(configPath)) {
|
|
36860
37307
|
return {
|
|
36861
37308
|
name: "Config Parseability",
|
|
@@ -36884,7 +37331,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
36884
37331
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
36885
37332
|
const isSource = normalized.endsWith("/src/services");
|
|
36886
37333
|
const isCliBundle = normalized.endsWith("/cli");
|
|
36887
|
-
return isSource || isCliBundle ?
|
|
37334
|
+
return isSource || isCliBundle ? path19.join(thisDir, "..", "lang", "grammars") : path19.join(thisDir, "lang", "grammars");
|
|
36888
37335
|
}
|
|
36889
37336
|
async function checkGrammarWasmFiles() {
|
|
36890
37337
|
const grammarFiles = [
|
|
@@ -36908,14 +37355,14 @@ async function checkGrammarWasmFiles() {
|
|
|
36908
37355
|
"tree-sitter-ini.wasm",
|
|
36909
37356
|
"tree-sitter-regex.wasm"
|
|
36910
37357
|
];
|
|
36911
|
-
const thisDir =
|
|
37358
|
+
const thisDir = path19.dirname(fileURLToPath(import.meta.url));
|
|
36912
37359
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
36913
37360
|
const missing = [];
|
|
36914
|
-
if (!existsSync9(
|
|
37361
|
+
if (!existsSync9(path19.join(grammarDir, "tree-sitter.wasm"))) {
|
|
36915
37362
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
36916
37363
|
}
|
|
36917
37364
|
for (const file3 of grammarFiles) {
|
|
36918
|
-
if (!existsSync9(
|
|
37365
|
+
if (!existsSync9(path19.join(grammarDir, file3))) {
|
|
36919
37366
|
missing.push(file3);
|
|
36920
37367
|
}
|
|
36921
37368
|
}
|
|
@@ -36933,7 +37380,7 @@ async function checkGrammarWasmFiles() {
|
|
|
36933
37380
|
};
|
|
36934
37381
|
}
|
|
36935
37382
|
async function checkCheckpointManifest(directory) {
|
|
36936
|
-
const manifestPath =
|
|
37383
|
+
const manifestPath = path19.join(directory, ".swarm/checkpoints.json");
|
|
36937
37384
|
if (!existsSync9(manifestPath)) {
|
|
36938
37385
|
return {
|
|
36939
37386
|
name: "Checkpoint Manifest",
|
|
@@ -36985,7 +37432,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36985
37432
|
}
|
|
36986
37433
|
}
|
|
36987
37434
|
async function checkEventStreamIntegrity(directory) {
|
|
36988
|
-
const eventsPath =
|
|
37435
|
+
const eventsPath = path19.join(directory, ".swarm/events.jsonl");
|
|
36989
37436
|
if (!existsSync9(eventsPath)) {
|
|
36990
37437
|
return {
|
|
36991
37438
|
name: "Event Stream",
|
|
@@ -37026,7 +37473,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
37026
37473
|
}
|
|
37027
37474
|
}
|
|
37028
37475
|
async function checkSteeringDirectives(directory) {
|
|
37029
|
-
const eventsPath =
|
|
37476
|
+
const eventsPath = path19.join(directory, ".swarm/events.jsonl");
|
|
37030
37477
|
if (!existsSync9(eventsPath)) {
|
|
37031
37478
|
return {
|
|
37032
37479
|
name: "Steering Directives",
|
|
@@ -37082,7 +37529,7 @@ async function checkCurator(directory) {
|
|
|
37082
37529
|
detail: "Disabled (enable via curator.enabled)"
|
|
37083
37530
|
};
|
|
37084
37531
|
}
|
|
37085
|
-
const summaryPath =
|
|
37532
|
+
const summaryPath = path19.join(directory, ".swarm/curator-summary.json");
|
|
37086
37533
|
if (!existsSync9(summaryPath)) {
|
|
37087
37534
|
return {
|
|
37088
37535
|
name: "Curator",
|
|
@@ -37248,7 +37695,7 @@ async function getDiagnoseData(directory) {
|
|
|
37248
37695
|
checks5.push(await checkSteeringDirectives(directory));
|
|
37249
37696
|
checks5.push(await checkCurator(directory));
|
|
37250
37697
|
try {
|
|
37251
|
-
const evidenceDir =
|
|
37698
|
+
const evidenceDir = path19.join(directory, ".swarm", "evidence");
|
|
37252
37699
|
const snapshotFiles = existsSync9(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
37253
37700
|
if (snapshotFiles.length > 0) {
|
|
37254
37701
|
const latest = snapshotFiles.sort().pop();
|
|
@@ -37286,7 +37733,7 @@ async function getDiagnoseData(directory) {
|
|
|
37286
37733
|
cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
|
|
37287
37734
|
continue;
|
|
37288
37735
|
}
|
|
37289
|
-
const pkgJsonPath =
|
|
37736
|
+
const pkgJsonPath = path19.join(cachePath, "package.json");
|
|
37290
37737
|
try {
|
|
37291
37738
|
const raw = readFileSync6(pkgJsonPath, "utf-8");
|
|
37292
37739
|
const parsed = JSON.parse(raw);
|
|
@@ -37345,15 +37792,15 @@ init_config_doctor();
|
|
|
37345
37792
|
|
|
37346
37793
|
// src/services/tool-doctor.ts
|
|
37347
37794
|
import * as fs10 from "fs";
|
|
37348
|
-
import * as
|
|
37795
|
+
import * as path22 from "path";
|
|
37349
37796
|
|
|
37350
37797
|
// src/build/discovery.ts
|
|
37351
37798
|
import * as fs9 from "fs";
|
|
37352
|
-
import * as
|
|
37799
|
+
import * as path21 from "path";
|
|
37353
37800
|
|
|
37354
37801
|
// src/lang/detector.ts
|
|
37355
|
-
import { access as
|
|
37356
|
-
import { extname as extname2, join as
|
|
37802
|
+
import { access as access3, readdir as readdir2 } from "fs/promises";
|
|
37803
|
+
import { extname as extname2, join as join18 } from "path";
|
|
37357
37804
|
|
|
37358
37805
|
// src/lang/profiles.ts
|
|
37359
37806
|
class LanguageRegistry {
|
|
@@ -38333,7 +38780,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
38333
38780
|
if (detectFile.includes("*") || detectFile.includes("?"))
|
|
38334
38781
|
continue;
|
|
38335
38782
|
try {
|
|
38336
|
-
await
|
|
38783
|
+
await access3(join18(dir, detectFile));
|
|
38337
38784
|
detected.add(profile.id);
|
|
38338
38785
|
break;
|
|
38339
38786
|
} catch {}
|
|
@@ -38354,7 +38801,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
38354
38801
|
const topEntries = await readdir2(projectDir, { withFileTypes: true });
|
|
38355
38802
|
for (const entry of topEntries) {
|
|
38356
38803
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
38357
|
-
await scanDir(
|
|
38804
|
+
await scanDir(join18(projectDir, entry.name));
|
|
38358
38805
|
}
|
|
38359
38806
|
}
|
|
38360
38807
|
} catch {}
|
|
@@ -38370,6 +38817,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
38370
38817
|
|
|
38371
38818
|
// src/build/discovery.ts
|
|
38372
38819
|
init_utils();
|
|
38820
|
+
init_bun_compat();
|
|
38373
38821
|
var ECOSYSTEMS = [
|
|
38374
38822
|
{
|
|
38375
38823
|
ecosystem: "node",
|
|
@@ -38488,8 +38936,7 @@ function isCommandAvailable(command) {
|
|
|
38488
38936
|
const isWindows = process.platform === "win32";
|
|
38489
38937
|
const cmd = isWindows ? `${command}.exe` : command;
|
|
38490
38938
|
try {
|
|
38491
|
-
const result =
|
|
38492
|
-
cmd: isWindows ? ["where", cmd] : ["which", cmd],
|
|
38939
|
+
const result = bunSpawnSync(isWindows ? ["where", cmd] : ["which", cmd], {
|
|
38493
38940
|
stdout: "pipe",
|
|
38494
38941
|
stderr: "pipe"
|
|
38495
38942
|
});
|
|
@@ -38513,11 +38960,11 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38513
38960
|
const regex = simpleGlobToRegex(pattern);
|
|
38514
38961
|
const matches = files.filter((f) => regex.test(f));
|
|
38515
38962
|
if (matches.length > 0) {
|
|
38516
|
-
return
|
|
38963
|
+
return path21.join(dir, matches[0]);
|
|
38517
38964
|
}
|
|
38518
38965
|
} catch {}
|
|
38519
38966
|
} else {
|
|
38520
|
-
const filePath =
|
|
38967
|
+
const filePath = path21.join(workingDir, pattern);
|
|
38521
38968
|
if (fs9.existsSync(filePath)) {
|
|
38522
38969
|
return filePath;
|
|
38523
38970
|
}
|
|
@@ -38526,7 +38973,7 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38526
38973
|
return null;
|
|
38527
38974
|
}
|
|
38528
38975
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
38529
|
-
const packageJsonPath =
|
|
38976
|
+
const packageJsonPath = path21.join(workingDir, "package.json");
|
|
38530
38977
|
if (!fs9.existsSync(packageJsonPath)) {
|
|
38531
38978
|
return [];
|
|
38532
38979
|
}
|
|
@@ -38567,7 +39014,7 @@ function findAllBuildFiles(workingDir) {
|
|
|
38567
39014
|
const regex = simpleGlobToRegex(pattern);
|
|
38568
39015
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
38569
39016
|
} else {
|
|
38570
|
-
const filePath =
|
|
39017
|
+
const filePath = path21.join(workingDir, pattern);
|
|
38571
39018
|
if (fs9.existsSync(filePath)) {
|
|
38572
39019
|
allBuildFiles.add(filePath);
|
|
38573
39020
|
}
|
|
@@ -38580,7 +39027,7 @@ function findFilesRecursive(dir, regex, results) {
|
|
|
38580
39027
|
try {
|
|
38581
39028
|
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
38582
39029
|
for (const entry of entries) {
|
|
38583
|
-
const fullPath =
|
|
39030
|
+
const fullPath = path21.join(dir, entry.name);
|
|
38584
39031
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
38585
39032
|
findFilesRecursive(fullPath, regex, results);
|
|
38586
39033
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -38603,7 +39050,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
38603
39050
|
let foundCommand = false;
|
|
38604
39051
|
for (const cmd of sortedCommands) {
|
|
38605
39052
|
if (cmd.detectFile) {
|
|
38606
|
-
const detectFilePath =
|
|
39053
|
+
const detectFilePath = path21.join(workingDir, cmd.detectFile);
|
|
38607
39054
|
if (!fs9.existsSync(detectFilePath)) {
|
|
38608
39055
|
continue;
|
|
38609
39056
|
}
|
|
@@ -38778,8 +39225,8 @@ function checkBinaryReadiness() {
|
|
|
38778
39225
|
}
|
|
38779
39226
|
function runToolDoctor(_directory, pluginRoot) {
|
|
38780
39227
|
const findings = [];
|
|
38781
|
-
const resolvedPluginRoot = pluginRoot ??
|
|
38782
|
-
const indexPath =
|
|
39228
|
+
const resolvedPluginRoot = pluginRoot ?? path22.resolve(import.meta.dir, "..", "..");
|
|
39229
|
+
const indexPath = path22.join(resolvedPluginRoot, "src", "index.ts");
|
|
38783
39230
|
if (!fs10.existsSync(indexPath)) {
|
|
38784
39231
|
return {
|
|
38785
39232
|
findings: [
|
|
@@ -39539,17 +39986,18 @@ ${lines.join(`
|
|
|
39539
39986
|
}
|
|
39540
39987
|
|
|
39541
39988
|
// src/commands/handoff.ts
|
|
39989
|
+
init_bun_compat();
|
|
39542
39990
|
async function handleHandoffCommand(directory, _args) {
|
|
39543
39991
|
const handoffData = await getHandoffData(directory);
|
|
39544
39992
|
const markdown = formatHandoffMarkdown(handoffData);
|
|
39545
39993
|
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
39546
39994
|
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
39547
|
-
await
|
|
39995
|
+
await bunWrite(tempPath, markdown);
|
|
39548
39996
|
renameSync6(tempPath, resolvedPath);
|
|
39549
39997
|
const continuationPrompt = formatContinuationPrompt(handoffData);
|
|
39550
39998
|
const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
|
|
39551
39999
|
const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
|
|
39552
|
-
await
|
|
40000
|
+
await bunWrite(promptTempPath, continuationPrompt);
|
|
39553
40001
|
renameSync6(promptTempPath, promptPath);
|
|
39554
40002
|
await writeSnapshot(directory, swarmState);
|
|
39555
40003
|
await flushPendingSnapshot(directory);
|
|
@@ -39907,17 +40355,17 @@ ${USAGE2}`;
|
|
|
39907
40355
|
}
|
|
39908
40356
|
|
|
39909
40357
|
// src/commands/knowledge.ts
|
|
39910
|
-
import { join as
|
|
40358
|
+
import { join as join22 } from "path";
|
|
39911
40359
|
|
|
39912
40360
|
// src/hooks/knowledge-migrator.ts
|
|
39913
40361
|
init_logger();
|
|
39914
40362
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
39915
40363
|
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
39916
|
-
import { mkdir as
|
|
39917
|
-
import * as
|
|
40364
|
+
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
40365
|
+
import * as path23 from "path";
|
|
39918
40366
|
async function migrateContextToKnowledge(directory, config3) {
|
|
39919
|
-
const sentinelPath =
|
|
39920
|
-
const contextPath =
|
|
40367
|
+
const sentinelPath = path23.join(directory, ".swarm", ".knowledge-migrated");
|
|
40368
|
+
const contextPath = path23.join(directory, ".swarm", "context.md");
|
|
39921
40369
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
39922
40370
|
if (existsSync13(sentinelPath)) {
|
|
39923
40371
|
return {
|
|
@@ -39937,7 +40385,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
39937
40385
|
skippedReason: "no-context-file"
|
|
39938
40386
|
};
|
|
39939
40387
|
}
|
|
39940
|
-
const contextContent = await
|
|
40388
|
+
const contextContent = await readFile5(contextPath, "utf-8");
|
|
39941
40389
|
if (contextContent.trim().length === 0) {
|
|
39942
40390
|
return {
|
|
39943
40391
|
migrated: false,
|
|
@@ -40113,7 +40561,7 @@ function truncateLesson(text) {
|
|
|
40113
40561
|
return `${text.slice(0, 277)}...`;
|
|
40114
40562
|
}
|
|
40115
40563
|
function inferProjectName(directory) {
|
|
40116
|
-
const packageJsonPath =
|
|
40564
|
+
const packageJsonPath = path23.join(directory, "package.json");
|
|
40117
40565
|
if (existsSync13(packageJsonPath)) {
|
|
40118
40566
|
try {
|
|
40119
40567
|
const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
@@ -40122,7 +40570,7 @@ function inferProjectName(directory) {
|
|
|
40122
40570
|
}
|
|
40123
40571
|
} catch {}
|
|
40124
40572
|
}
|
|
40125
|
-
return
|
|
40573
|
+
return path23.basename(directory);
|
|
40126
40574
|
}
|
|
40127
40575
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
40128
40576
|
const sentinel = {
|
|
@@ -40134,8 +40582,8 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
40134
40582
|
schema_version: 1,
|
|
40135
40583
|
migration_tool: "knowledge-migrator.ts"
|
|
40136
40584
|
};
|
|
40137
|
-
await
|
|
40138
|
-
await
|
|
40585
|
+
await mkdir4(path23.dirname(sentinelPath), { recursive: true });
|
|
40586
|
+
await writeFile5(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
40139
40587
|
}
|
|
40140
40588
|
|
|
40141
40589
|
// src/commands/knowledge.ts
|
|
@@ -40189,7 +40637,7 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
40189
40637
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
40190
40638
|
}
|
|
40191
40639
|
try {
|
|
40192
|
-
const quarantinePath =
|
|
40640
|
+
const quarantinePath = join22(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
40193
40641
|
const entries = await readKnowledge(quarantinePath);
|
|
40194
40642
|
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
40195
40643
|
if ("error" in resolved) {
|
|
@@ -40556,6 +41004,13 @@ function parseGitRemoteUrl2(remoteUrl) {
|
|
|
40556
41004
|
repo: sshMatch[2].replace(/\.git$/, "")
|
|
40557
41005
|
};
|
|
40558
41006
|
}
|
|
41007
|
+
const pathMatch = remoteUrl.match(/\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
41008
|
+
if (pathMatch) {
|
|
41009
|
+
return {
|
|
41010
|
+
owner: pathMatch[1],
|
|
41011
|
+
repo: pathMatch[2].replace(/\.git$/, "")
|
|
41012
|
+
};
|
|
41013
|
+
}
|
|
40559
41014
|
return null;
|
|
40560
41015
|
}
|
|
40561
41016
|
function handlePrReviewCommand(_directory, args) {
|
|
@@ -40586,13 +41041,14 @@ ${USAGE3}`;
|
|
|
40586
41041
|
init_manager2();
|
|
40587
41042
|
init_manager();
|
|
40588
41043
|
import * as fs17 from "fs";
|
|
40589
|
-
import * as
|
|
41044
|
+
import * as path30 from "path";
|
|
40590
41045
|
|
|
40591
41046
|
// src/tools/lint.ts
|
|
40592
41047
|
init_zod();
|
|
40593
41048
|
import * as fs11 from "fs";
|
|
40594
|
-
import * as
|
|
41049
|
+
import * as path24 from "path";
|
|
40595
41050
|
init_utils();
|
|
41051
|
+
init_bun_compat();
|
|
40596
41052
|
|
|
40597
41053
|
// src/utils/path-security.ts
|
|
40598
41054
|
function containsPathTraversal(str) {
|
|
@@ -40637,9 +41093,9 @@ function validateArgs(args) {
|
|
|
40637
41093
|
}
|
|
40638
41094
|
function getLinterCommand(linter, mode, projectDir) {
|
|
40639
41095
|
const isWindows = process.platform === "win32";
|
|
40640
|
-
const binDir =
|
|
40641
|
-
const biomeBin = isWindows ?
|
|
40642
|
-
const eslintBin = isWindows ?
|
|
41096
|
+
const binDir = path24.join(projectDir, "node_modules", ".bin");
|
|
41097
|
+
const biomeBin = isWindows ? path24.join(binDir, "biome.EXE") : path24.join(binDir, "biome");
|
|
41098
|
+
const eslintBin = isWindows ? path24.join(binDir, "eslint.cmd") : path24.join(binDir, "eslint");
|
|
40643
41099
|
switch (linter) {
|
|
40644
41100
|
case "biome":
|
|
40645
41101
|
if (mode === "fix") {
|
|
@@ -40655,7 +41111,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
40655
41111
|
}
|
|
40656
41112
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
40657
41113
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
40658
|
-
const gradlew = fs11.existsSync(
|
|
41114
|
+
const gradlew = fs11.existsSync(path24.join(cwd, gradlewName)) ? path24.join(cwd, gradlewName) : null;
|
|
40659
41115
|
switch (linter) {
|
|
40660
41116
|
case "ruff":
|
|
40661
41117
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -40689,10 +41145,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
40689
41145
|
}
|
|
40690
41146
|
}
|
|
40691
41147
|
function detectRuff(cwd) {
|
|
40692
|
-
if (fs11.existsSync(
|
|
41148
|
+
if (fs11.existsSync(path24.join(cwd, "ruff.toml")))
|
|
40693
41149
|
return isCommandAvailable("ruff");
|
|
40694
41150
|
try {
|
|
40695
|
-
const pyproject =
|
|
41151
|
+
const pyproject = path24.join(cwd, "pyproject.toml");
|
|
40696
41152
|
if (fs11.existsSync(pyproject)) {
|
|
40697
41153
|
const content = fs11.readFileSync(pyproject, "utf-8");
|
|
40698
41154
|
if (content.includes("[tool.ruff]"))
|
|
@@ -40702,19 +41158,19 @@ function detectRuff(cwd) {
|
|
|
40702
41158
|
return false;
|
|
40703
41159
|
}
|
|
40704
41160
|
function detectClippy(cwd) {
|
|
40705
|
-
return fs11.existsSync(
|
|
41161
|
+
return fs11.existsSync(path24.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
40706
41162
|
}
|
|
40707
41163
|
function detectGolangciLint(cwd) {
|
|
40708
|
-
return fs11.existsSync(
|
|
41164
|
+
return fs11.existsSync(path24.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
40709
41165
|
}
|
|
40710
41166
|
function detectCheckstyle(cwd) {
|
|
40711
|
-
const hasMaven = fs11.existsSync(
|
|
40712
|
-
const hasGradle = fs11.existsSync(
|
|
40713
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(
|
|
41167
|
+
const hasMaven = fs11.existsSync(path24.join(cwd, "pom.xml"));
|
|
41168
|
+
const hasGradle = fs11.existsSync(path24.join(cwd, "build.gradle")) || fs11.existsSync(path24.join(cwd, "build.gradle.kts"));
|
|
41169
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(path24.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
40714
41170
|
return (hasMaven || hasGradle) && hasBinary;
|
|
40715
41171
|
}
|
|
40716
41172
|
function detectKtlint(cwd) {
|
|
40717
|
-
const hasKotlin = fs11.existsSync(
|
|
41173
|
+
const hasKotlin = fs11.existsSync(path24.join(cwd, "build.gradle.kts")) || fs11.existsSync(path24.join(cwd, "build.gradle")) || (() => {
|
|
40718
41174
|
try {
|
|
40719
41175
|
return fs11.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
40720
41176
|
} catch {
|
|
@@ -40733,11 +41189,11 @@ function detectDotnetFormat(cwd) {
|
|
|
40733
41189
|
}
|
|
40734
41190
|
}
|
|
40735
41191
|
function detectCppcheck(cwd) {
|
|
40736
|
-
if (fs11.existsSync(
|
|
41192
|
+
if (fs11.existsSync(path24.join(cwd, "CMakeLists.txt"))) {
|
|
40737
41193
|
return isCommandAvailable("cppcheck");
|
|
40738
41194
|
}
|
|
40739
41195
|
try {
|
|
40740
|
-
const dirsToCheck = [cwd,
|
|
41196
|
+
const dirsToCheck = [cwd, path24.join(cwd, "src")];
|
|
40741
41197
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
40742
41198
|
try {
|
|
40743
41199
|
return fs11.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -40751,13 +41207,13 @@ function detectCppcheck(cwd) {
|
|
|
40751
41207
|
}
|
|
40752
41208
|
}
|
|
40753
41209
|
function detectSwiftlint(cwd) {
|
|
40754
|
-
return fs11.existsSync(
|
|
41210
|
+
return fs11.existsSync(path24.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
40755
41211
|
}
|
|
40756
41212
|
function detectDartAnalyze(cwd) {
|
|
40757
|
-
return fs11.existsSync(
|
|
41213
|
+
return fs11.existsSync(path24.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
40758
41214
|
}
|
|
40759
41215
|
function detectRubocop(cwd) {
|
|
40760
|
-
return (fs11.existsSync(
|
|
41216
|
+
return (fs11.existsSync(path24.join(cwd, "Gemfile")) || fs11.existsSync(path24.join(cwd, "gems.rb")) || fs11.existsSync(path24.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
40761
41217
|
}
|
|
40762
41218
|
function detectAdditionalLinter(cwd) {
|
|
40763
41219
|
if (detectRuff(cwd))
|
|
@@ -40785,10 +41241,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
40785
41241
|
function findBinInAncestors(startDir, binName) {
|
|
40786
41242
|
let dir = startDir;
|
|
40787
41243
|
while (true) {
|
|
40788
|
-
const candidate =
|
|
41244
|
+
const candidate = path24.join(dir, "node_modules", ".bin", binName);
|
|
40789
41245
|
if (fs11.existsSync(candidate))
|
|
40790
41246
|
return candidate;
|
|
40791
|
-
const parent =
|
|
41247
|
+
const parent = path24.dirname(dir);
|
|
40792
41248
|
if (parent === dir)
|
|
40793
41249
|
break;
|
|
40794
41250
|
dir = parent;
|
|
@@ -40797,10 +41253,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
40797
41253
|
}
|
|
40798
41254
|
function findBinInEnvPath(binName) {
|
|
40799
41255
|
const searchPath = process.env.PATH ?? "";
|
|
40800
|
-
for (const dir of searchPath.split(
|
|
41256
|
+
for (const dir of searchPath.split(path24.delimiter)) {
|
|
40801
41257
|
if (!dir)
|
|
40802
41258
|
continue;
|
|
40803
|
-
const candidate =
|
|
41259
|
+
const candidate = path24.join(dir, binName);
|
|
40804
41260
|
if (fs11.existsSync(candidate))
|
|
40805
41261
|
return candidate;
|
|
40806
41262
|
}
|
|
@@ -40813,13 +41269,13 @@ async function detectAvailableLinter(directory) {
|
|
|
40813
41269
|
return null;
|
|
40814
41270
|
const projectDir = directory;
|
|
40815
41271
|
const isWindows = process.platform === "win32";
|
|
40816
|
-
const biomeBin = isWindows ?
|
|
40817
|
-
const eslintBin = isWindows ?
|
|
41272
|
+
const biomeBin = isWindows ? path24.join(projectDir, "node_modules", ".bin", "biome.EXE") : path24.join(projectDir, "node_modules", ".bin", "biome");
|
|
41273
|
+
const eslintBin = isWindows ? path24.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path24.join(projectDir, "node_modules", ".bin", "eslint");
|
|
40818
41274
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
40819
41275
|
if (localResult)
|
|
40820
41276
|
return localResult;
|
|
40821
|
-
const biomeAncestor = findBinInAncestors(
|
|
40822
|
-
const eslintAncestor = findBinInAncestors(
|
|
41277
|
+
const biomeAncestor = findBinInAncestors(path24.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
41278
|
+
const eslintAncestor = findBinInAncestors(path24.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
40823
41279
|
if (biomeAncestor || eslintAncestor) {
|
|
40824
41280
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
40825
41281
|
}
|
|
@@ -40833,7 +41289,7 @@ async function detectAvailableLinter(directory) {
|
|
|
40833
41289
|
async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
40834
41290
|
const DETECT_TIMEOUT = 2000;
|
|
40835
41291
|
try {
|
|
40836
|
-
const biomeProc =
|
|
41292
|
+
const biomeProc = bunSpawn([biomeBin, "--version"], {
|
|
40837
41293
|
stdout: "pipe",
|
|
40838
41294
|
stderr: "pipe"
|
|
40839
41295
|
});
|
|
@@ -40847,7 +41303,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
40847
41303
|
}
|
|
40848
41304
|
} catch {}
|
|
40849
41305
|
try {
|
|
40850
|
-
const eslintProc =
|
|
41306
|
+
const eslintProc = bunSpawn([eslintBin, "--version"], {
|
|
40851
41307
|
stdout: "pipe",
|
|
40852
41308
|
stderr: "pipe"
|
|
40853
41309
|
});
|
|
@@ -40875,14 +41331,14 @@ async function runLint(linter, mode, directory) {
|
|
|
40875
41331
|
};
|
|
40876
41332
|
}
|
|
40877
41333
|
try {
|
|
40878
|
-
const proc =
|
|
41334
|
+
const proc = bunSpawn(command, {
|
|
40879
41335
|
stdout: "pipe",
|
|
40880
41336
|
stderr: "pipe",
|
|
40881
41337
|
cwd: directory
|
|
40882
41338
|
});
|
|
40883
41339
|
const [stdout, stderr] = await Promise.all([
|
|
40884
|
-
|
|
40885
|
-
|
|
41340
|
+
proc.stdout.text(),
|
|
41341
|
+
proc.stderr.text()
|
|
40886
41342
|
]);
|
|
40887
41343
|
const exitCode = await proc.exited;
|
|
40888
41344
|
let output = stdout;
|
|
@@ -40933,14 +41389,14 @@ async function runAdditionalLint(linter, mode, cwd) {
|
|
|
40933
41389
|
};
|
|
40934
41390
|
}
|
|
40935
41391
|
try {
|
|
40936
|
-
const proc =
|
|
41392
|
+
const proc = bunSpawn(command, {
|
|
40937
41393
|
stdout: "pipe",
|
|
40938
41394
|
stderr: "pipe",
|
|
40939
41395
|
cwd
|
|
40940
41396
|
});
|
|
40941
41397
|
const [stdout, stderr] = await Promise.all([
|
|
40942
|
-
|
|
40943
|
-
|
|
41398
|
+
proc.stdout.text(),
|
|
41399
|
+
proc.stderr.text()
|
|
40944
41400
|
]);
|
|
40945
41401
|
const exitCode = await proc.exited;
|
|
40946
41402
|
let output = stdout;
|
|
@@ -41028,7 +41484,7 @@ For Rust: rustup component add clippy`
|
|
|
41028
41484
|
// src/tools/secretscan.ts
|
|
41029
41485
|
init_zod();
|
|
41030
41486
|
import * as fs12 from "fs";
|
|
41031
|
-
import * as
|
|
41487
|
+
import * as path25 from "path";
|
|
41032
41488
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
41033
41489
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
41034
41490
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -41255,7 +41711,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
41255
41711
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
41256
41712
|
}
|
|
41257
41713
|
function loadSecretScanIgnore(scanDir) {
|
|
41258
|
-
const ignorePath =
|
|
41714
|
+
const ignorePath = path25.join(scanDir, ".secretscanignore");
|
|
41259
41715
|
try {
|
|
41260
41716
|
if (!fs12.existsSync(ignorePath))
|
|
41261
41717
|
return [];
|
|
@@ -41278,7 +41734,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
41278
41734
|
if (exactNames.has(entry))
|
|
41279
41735
|
return true;
|
|
41280
41736
|
for (const pattern of globPatterns) {
|
|
41281
|
-
if (
|
|
41737
|
+
if (path25.matchesGlob(relPath, pattern))
|
|
41282
41738
|
return true;
|
|
41283
41739
|
}
|
|
41284
41740
|
return false;
|
|
@@ -41299,7 +41755,7 @@ function validateDirectoryInput(dir) {
|
|
|
41299
41755
|
return null;
|
|
41300
41756
|
}
|
|
41301
41757
|
function isBinaryFile(filePath, buffer) {
|
|
41302
|
-
const ext =
|
|
41758
|
+
const ext = path25.extname(filePath).toLowerCase();
|
|
41303
41759
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
41304
41760
|
return true;
|
|
41305
41761
|
}
|
|
@@ -41436,9 +41892,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
41436
41892
|
return false;
|
|
41437
41893
|
}
|
|
41438
41894
|
function isPathWithinScope(realPath, scanDir) {
|
|
41439
|
-
const resolvedScanDir =
|
|
41440
|
-
const resolvedRealPath =
|
|
41441
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
41895
|
+
const resolvedScanDir = path25.resolve(scanDir);
|
|
41896
|
+
const resolvedRealPath = path25.resolve(realPath);
|
|
41897
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path25.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
41442
41898
|
}
|
|
41443
41899
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
41444
41900
|
skippedDirs: 0,
|
|
@@ -41464,8 +41920,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
41464
41920
|
return a.localeCompare(b);
|
|
41465
41921
|
});
|
|
41466
41922
|
for (const entry of entries) {
|
|
41467
|
-
const fullPath =
|
|
41468
|
-
const relPath =
|
|
41923
|
+
const fullPath = path25.join(dir, entry);
|
|
41924
|
+
const relPath = path25.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
41469
41925
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
41470
41926
|
stats.skippedDirs++;
|
|
41471
41927
|
continue;
|
|
@@ -41500,7 +41956,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
41500
41956
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
41501
41957
|
files.push(...subFiles);
|
|
41502
41958
|
} else if (lstat.isFile()) {
|
|
41503
|
-
const ext =
|
|
41959
|
+
const ext = path25.extname(fullPath).toLowerCase();
|
|
41504
41960
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
41505
41961
|
files.push(fullPath);
|
|
41506
41962
|
} else {
|
|
@@ -41566,7 +42022,7 @@ var secretscan = createSwarmTool({
|
|
|
41566
42022
|
}
|
|
41567
42023
|
}
|
|
41568
42024
|
try {
|
|
41569
|
-
const _scanDirRaw =
|
|
42025
|
+
const _scanDirRaw = path25.resolve(directory);
|
|
41570
42026
|
const scanDir = (() => {
|
|
41571
42027
|
try {
|
|
41572
42028
|
return fs12.realpathSync(_scanDirRaw);
|
|
@@ -41636,8 +42092,8 @@ var secretscan = createSwarmTool({
|
|
|
41636
42092
|
break;
|
|
41637
42093
|
const fileFindings = scanFileForSecrets(filePath);
|
|
41638
42094
|
try {
|
|
41639
|
-
const
|
|
41640
|
-
if (
|
|
42095
|
+
const stat3 = fs12.statSync(filePath);
|
|
42096
|
+
if (stat3.size > MAX_FILE_SIZE_BYTES) {
|
|
41641
42097
|
skippedFiles++;
|
|
41642
42098
|
continue;
|
|
41643
42099
|
}
|
|
@@ -41726,11 +42182,11 @@ async function runSecretscan(directory) {
|
|
|
41726
42182
|
// src/tools/test-runner.ts
|
|
41727
42183
|
init_zod();
|
|
41728
42184
|
import * as fs16 from "fs";
|
|
41729
|
-
import * as
|
|
42185
|
+
import * as path29 from "path";
|
|
41730
42186
|
|
|
41731
42187
|
// src/test-impact/analyzer.ts
|
|
41732
42188
|
import fs13 from "fs";
|
|
41733
|
-
import
|
|
42189
|
+
import path26 from "path";
|
|
41734
42190
|
var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
41735
42191
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
41736
42192
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -41741,8 +42197,8 @@ function normalizePath(p) {
|
|
|
41741
42197
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
41742
42198
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
41743
42199
|
try {
|
|
41744
|
-
const
|
|
41745
|
-
if (
|
|
42200
|
+
const stat3 = fs13.statSync(sourcePath);
|
|
42201
|
+
if (stat3.mtimeMs > generatedAtMs) {
|
|
41746
42202
|
return true;
|
|
41747
42203
|
}
|
|
41748
42204
|
} catch {
|
|
@@ -41755,8 +42211,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
41755
42211
|
if (!importPath.startsWith(".")) {
|
|
41756
42212
|
return null;
|
|
41757
42213
|
}
|
|
41758
|
-
const resolved =
|
|
41759
|
-
if (
|
|
42214
|
+
const resolved = path26.resolve(fromDir, importPath);
|
|
42215
|
+
if (path26.extname(resolved)) {
|
|
41760
42216
|
if (fs13.existsSync(resolved) && fs13.statSync(resolved).isFile()) {
|
|
41761
42217
|
return normalizePath(resolved);
|
|
41762
42218
|
}
|
|
@@ -41801,12 +42257,12 @@ function findTestFilesSync(cwd) {
|
|
|
41801
42257
|
for (const entry of entries) {
|
|
41802
42258
|
if (entry.isDirectory()) {
|
|
41803
42259
|
if (!skipDirs.has(entry.name)) {
|
|
41804
|
-
walk(
|
|
42260
|
+
walk(path26.join(dir, entry.name), visitedInodes);
|
|
41805
42261
|
}
|
|
41806
42262
|
} else if (entry.isFile()) {
|
|
41807
42263
|
const name = entry.name;
|
|
41808
42264
|
if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
|
|
41809
|
-
testFiles.push(normalizePath(
|
|
42265
|
+
testFiles.push(normalizePath(path26.join(dir, entry.name)));
|
|
41810
42266
|
}
|
|
41811
42267
|
}
|
|
41812
42268
|
}
|
|
@@ -41844,7 +42300,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
41844
42300
|
continue;
|
|
41845
42301
|
}
|
|
41846
42302
|
const imports = extractImports(content);
|
|
41847
|
-
const testDir =
|
|
42303
|
+
const testDir = path26.dirname(testFile);
|
|
41848
42304
|
for (const importPath of imports) {
|
|
41849
42305
|
const resolvedSource = resolveRelativeImport(testDir, importPath);
|
|
41850
42306
|
if (resolvedSource === null) {
|
|
@@ -41866,7 +42322,7 @@ async function buildImpactMap(cwd) {
|
|
|
41866
42322
|
return impactMap;
|
|
41867
42323
|
}
|
|
41868
42324
|
async function loadImpactMap(cwd) {
|
|
41869
|
-
const cachePath =
|
|
42325
|
+
const cachePath = path26.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
41870
42326
|
if (fs13.existsSync(cachePath)) {
|
|
41871
42327
|
try {
|
|
41872
42328
|
const content = fs13.readFileSync(cachePath, "utf-8");
|
|
@@ -41881,8 +42337,8 @@ async function loadImpactMap(cwd) {
|
|
|
41881
42337
|
return buildImpactMap(cwd);
|
|
41882
42338
|
}
|
|
41883
42339
|
async function saveImpactMap(cwd, impactMap) {
|
|
41884
|
-
const cacheDir2 =
|
|
41885
|
-
const cachePath =
|
|
42340
|
+
const cacheDir2 = path26.join(cwd, ".swarm", "cache");
|
|
42341
|
+
const cachePath = path26.join(cacheDir2, "impact-map.json");
|
|
41886
42342
|
if (!fs13.existsSync(cacheDir2)) {
|
|
41887
42343
|
fs13.mkdirSync(cacheDir2, { recursive: true });
|
|
41888
42344
|
}
|
|
@@ -41908,7 +42364,7 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
41908
42364
|
const impactedTestsSet = new Set;
|
|
41909
42365
|
const untestedFiles = [];
|
|
41910
42366
|
for (const changedFile of validFiles) {
|
|
41911
|
-
const normalizedChanged = normalizePath(
|
|
42367
|
+
const normalizedChanged = normalizePath(path26.resolve(changedFile));
|
|
41912
42368
|
const tests = impactMap[normalizedChanged];
|
|
41913
42369
|
if (tests && tests.length > 0) {
|
|
41914
42370
|
for (const test of tests) {
|
|
@@ -42155,13 +42611,13 @@ function detectFlakyTests(allHistory) {
|
|
|
42155
42611
|
|
|
42156
42612
|
// src/test-impact/history-store.ts
|
|
42157
42613
|
import fs14 from "fs";
|
|
42158
|
-
import
|
|
42614
|
+
import path27 from "path";
|
|
42159
42615
|
var MAX_HISTORY_PER_TEST = 20;
|
|
42160
42616
|
var MAX_ERROR_LENGTH = 500;
|
|
42161
42617
|
var MAX_STACK_LENGTH = 200;
|
|
42162
42618
|
var MAX_CHANGED_FILES = 50;
|
|
42163
42619
|
function getHistoryPath(workingDir) {
|
|
42164
|
-
return
|
|
42620
|
+
return path27.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
|
|
42165
42621
|
}
|
|
42166
42622
|
function sanitizeErrorMessage(errorMessage) {
|
|
42167
42623
|
if (errorMessage === undefined) {
|
|
@@ -42221,7 +42677,7 @@ function appendTestRun(record3, workingDir) {
|
|
|
42221
42677
|
changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
|
|
42222
42678
|
};
|
|
42223
42679
|
const historyPath = getHistoryPath(workingDir);
|
|
42224
|
-
const historyDir =
|
|
42680
|
+
const historyDir = path27.dirname(historyPath);
|
|
42225
42681
|
if (!fs14.existsSync(historyDir)) {
|
|
42226
42682
|
fs14.mkdirSync(historyDir, { recursive: true });
|
|
42227
42683
|
}
|
|
@@ -42293,9 +42749,12 @@ function getAllHistory(workingDir) {
|
|
|
42293
42749
|
return records;
|
|
42294
42750
|
}
|
|
42295
42751
|
|
|
42752
|
+
// src/tools/test-runner.ts
|
|
42753
|
+
init_bun_compat();
|
|
42754
|
+
|
|
42296
42755
|
// src/tools/resolve-working-directory.ts
|
|
42297
42756
|
import * as fs15 from "fs";
|
|
42298
|
-
import * as
|
|
42757
|
+
import * as path28 from "path";
|
|
42299
42758
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
42300
42759
|
if (workingDirectory == null || workingDirectory === "") {
|
|
42301
42760
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -42315,15 +42774,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
42315
42774
|
};
|
|
42316
42775
|
}
|
|
42317
42776
|
}
|
|
42318
|
-
const normalizedDir =
|
|
42319
|
-
const pathParts = normalizedDir.split(
|
|
42777
|
+
const normalizedDir = path28.normalize(workingDirectory);
|
|
42778
|
+
const pathParts = normalizedDir.split(path28.sep);
|
|
42320
42779
|
if (pathParts.includes("..")) {
|
|
42321
42780
|
return {
|
|
42322
42781
|
success: false,
|
|
42323
42782
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
42324
42783
|
};
|
|
42325
42784
|
}
|
|
42326
|
-
const resolvedDir =
|
|
42785
|
+
const resolvedDir = path28.resolve(normalizedDir);
|
|
42327
42786
|
let statResult;
|
|
42328
42787
|
try {
|
|
42329
42788
|
statResult = fs15.statSync(resolvedDir);
|
|
@@ -42339,7 +42798,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
42339
42798
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
42340
42799
|
};
|
|
42341
42800
|
}
|
|
42342
|
-
const resolvedFallback =
|
|
42801
|
+
const resolvedFallback = path28.resolve(fallbackDirectory);
|
|
42343
42802
|
let fallbackExists = false;
|
|
42344
42803
|
try {
|
|
42345
42804
|
fs15.statSync(resolvedFallback);
|
|
@@ -42349,7 +42808,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
42349
42808
|
}
|
|
42350
42809
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
42351
42810
|
if (fallbackExists) {
|
|
42352
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
42811
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path28.sep);
|
|
42353
42812
|
if (isSubdirectory) {
|
|
42354
42813
|
return {
|
|
42355
42814
|
success: false,
|
|
@@ -42439,14 +42898,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
42439
42898
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
42440
42899
|
}
|
|
42441
42900
|
function detectGoTest(cwd) {
|
|
42442
|
-
return fs16.existsSync(
|
|
42901
|
+
return fs16.existsSync(path29.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
42443
42902
|
}
|
|
42444
42903
|
function detectJavaMaven(cwd) {
|
|
42445
|
-
return fs16.existsSync(
|
|
42904
|
+
return fs16.existsSync(path29.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
42446
42905
|
}
|
|
42447
42906
|
function detectGradle(cwd) {
|
|
42448
|
-
const hasBuildFile = fs16.existsSync(
|
|
42449
|
-
const hasGradlew = fs16.existsSync(
|
|
42907
|
+
const hasBuildFile = fs16.existsSync(path29.join(cwd, "build.gradle")) || fs16.existsSync(path29.join(cwd, "build.gradle.kts"));
|
|
42908
|
+
const hasGradlew = fs16.existsSync(path29.join(cwd, "gradlew")) || fs16.existsSync(path29.join(cwd, "gradlew.bat"));
|
|
42450
42909
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
42451
42910
|
}
|
|
42452
42911
|
function detectDotnetTest(cwd) {
|
|
@@ -42459,30 +42918,30 @@ function detectDotnetTest(cwd) {
|
|
|
42459
42918
|
}
|
|
42460
42919
|
}
|
|
42461
42920
|
function detectCTest(cwd) {
|
|
42462
|
-
const hasSource = fs16.existsSync(
|
|
42463
|
-
const hasBuildCache = fs16.existsSync(
|
|
42921
|
+
const hasSource = fs16.existsSync(path29.join(cwd, "CMakeLists.txt"));
|
|
42922
|
+
const hasBuildCache = fs16.existsSync(path29.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path29.join(cwd, "build", "CMakeCache.txt"));
|
|
42464
42923
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
42465
42924
|
}
|
|
42466
42925
|
function detectSwiftTest(cwd) {
|
|
42467
|
-
return fs16.existsSync(
|
|
42926
|
+
return fs16.existsSync(path29.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
42468
42927
|
}
|
|
42469
42928
|
function detectDartTest(cwd) {
|
|
42470
|
-
return fs16.existsSync(
|
|
42929
|
+
return fs16.existsSync(path29.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
42471
42930
|
}
|
|
42472
42931
|
function detectRSpec(cwd) {
|
|
42473
|
-
const hasRSpecFile = fs16.existsSync(
|
|
42474
|
-
const hasGemfile = fs16.existsSync(
|
|
42475
|
-
const hasSpecDir = fs16.existsSync(
|
|
42932
|
+
const hasRSpecFile = fs16.existsSync(path29.join(cwd, ".rspec"));
|
|
42933
|
+
const hasGemfile = fs16.existsSync(path29.join(cwd, "Gemfile"));
|
|
42934
|
+
const hasSpecDir = fs16.existsSync(path29.join(cwd, "spec"));
|
|
42476
42935
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
42477
42936
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
42478
42937
|
}
|
|
42479
42938
|
function detectMinitest(cwd) {
|
|
42480
|
-
return fs16.existsSync(
|
|
42939
|
+
return fs16.existsSync(path29.join(cwd, "test")) && (fs16.existsSync(path29.join(cwd, "Gemfile")) || fs16.existsSync(path29.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
42481
42940
|
}
|
|
42482
42941
|
async function detectTestFramework(cwd) {
|
|
42483
42942
|
const baseDir = cwd;
|
|
42484
42943
|
try {
|
|
42485
|
-
const packageJsonPath =
|
|
42944
|
+
const packageJsonPath = path29.join(baseDir, "package.json");
|
|
42486
42945
|
if (fs16.existsSync(packageJsonPath)) {
|
|
42487
42946
|
const content = fs16.readFileSync(packageJsonPath, "utf-8");
|
|
42488
42947
|
const pkg = JSON.parse(content);
|
|
@@ -42503,16 +42962,16 @@ async function detectTestFramework(cwd) {
|
|
|
42503
42962
|
return "jest";
|
|
42504
42963
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
42505
42964
|
return "mocha";
|
|
42506
|
-
if (fs16.existsSync(
|
|
42965
|
+
if (fs16.existsSync(path29.join(baseDir, "bun.lockb")) || fs16.existsSync(path29.join(baseDir, "bun.lock"))) {
|
|
42507
42966
|
if (scripts.test?.includes("bun"))
|
|
42508
42967
|
return "bun";
|
|
42509
42968
|
}
|
|
42510
42969
|
}
|
|
42511
42970
|
} catch {}
|
|
42512
42971
|
try {
|
|
42513
|
-
const pyprojectTomlPath =
|
|
42514
|
-
const setupCfgPath =
|
|
42515
|
-
const requirementsTxtPath =
|
|
42972
|
+
const pyprojectTomlPath = path29.join(baseDir, "pyproject.toml");
|
|
42973
|
+
const setupCfgPath = path29.join(baseDir, "setup.cfg");
|
|
42974
|
+
const requirementsTxtPath = path29.join(baseDir, "requirements.txt");
|
|
42516
42975
|
if (fs16.existsSync(pyprojectTomlPath)) {
|
|
42517
42976
|
const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
|
|
42518
42977
|
if (content.includes("[tool.pytest"))
|
|
@@ -42532,7 +42991,7 @@ async function detectTestFramework(cwd) {
|
|
|
42532
42991
|
}
|
|
42533
42992
|
} catch {}
|
|
42534
42993
|
try {
|
|
42535
|
-
const cargoTomlPath =
|
|
42994
|
+
const cargoTomlPath = path29.join(baseDir, "Cargo.toml");
|
|
42536
42995
|
if (fs16.existsSync(cargoTomlPath)) {
|
|
42537
42996
|
const content = fs16.readFileSync(cargoTomlPath, "utf-8");
|
|
42538
42997
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -42543,9 +43002,9 @@ async function detectTestFramework(cwd) {
|
|
|
42543
43002
|
}
|
|
42544
43003
|
} catch {}
|
|
42545
43004
|
try {
|
|
42546
|
-
const pesterConfigPath =
|
|
42547
|
-
const pesterConfigJsonPath =
|
|
42548
|
-
const pesterPs1Path =
|
|
43005
|
+
const pesterConfigPath = path29.join(baseDir, "pester.config.ps1");
|
|
43006
|
+
const pesterConfigJsonPath = path29.join(baseDir, "pester.config.ps1.json");
|
|
43007
|
+
const pesterPs1Path = path29.join(baseDir, "tests.ps1");
|
|
42549
43008
|
if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
|
|
42550
43009
|
return "pester";
|
|
42551
43010
|
}
|
|
@@ -42588,12 +43047,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
42588
43047
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
42589
43048
|
}
|
|
42590
43049
|
function resolveWorkspacePath(file3, workingDir) {
|
|
42591
|
-
return
|
|
43050
|
+
return path29.isAbsolute(file3) ? path29.resolve(file3) : path29.resolve(workingDir, file3);
|
|
42592
43051
|
}
|
|
42593
43052
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
42594
43053
|
if (!preferRelative)
|
|
42595
43054
|
return absolutePath;
|
|
42596
|
-
return
|
|
43055
|
+
return path29.relative(workingDir, absolutePath);
|
|
42597
43056
|
}
|
|
42598
43057
|
function dedupePush(target, value) {
|
|
42599
43058
|
if (!target.includes(value)) {
|
|
@@ -42630,18 +43089,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
42630
43089
|
}
|
|
42631
43090
|
}
|
|
42632
43091
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
42633
|
-
const relativeDir =
|
|
43092
|
+
const relativeDir = path29.dirname(relativePath);
|
|
42634
43093
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
42635
43094
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
42636
|
-
const rootDir =
|
|
42637
|
-
return nestedRelativeDir ? [rootDir,
|
|
43095
|
+
const rootDir = path29.join(workingDir, dirName);
|
|
43096
|
+
return nestedRelativeDir ? [rootDir, path29.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
42638
43097
|
});
|
|
42639
43098
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
42640
43099
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
42641
|
-
directories.push(
|
|
43100
|
+
directories.push(path29.join(workingDir, "src/test/java", path29.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
42642
43101
|
}
|
|
42643
43102
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
42644
|
-
directories.push(
|
|
43103
|
+
directories.push(path29.join(workingDir, "src/test/kotlin", path29.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
42645
43104
|
}
|
|
42646
43105
|
return [...new Set(directories)];
|
|
42647
43106
|
}
|
|
@@ -42649,19 +43108,19 @@ function hasCompoundTestExtension(filename) {
|
|
|
42649
43108
|
const lower = filename.toLowerCase();
|
|
42650
43109
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
42651
43110
|
}
|
|
42652
|
-
function isLanguageSpecificTestFile(
|
|
42653
|
-
const lower =
|
|
43111
|
+
function isLanguageSpecificTestFile(basename5) {
|
|
43112
|
+
const lower = basename5.toLowerCase();
|
|
42654
43113
|
if (lower.endsWith("_test.go"))
|
|
42655
43114
|
return true;
|
|
42656
43115
|
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
42657
43116
|
return true;
|
|
42658
43117
|
if (lower.endsWith("_spec.rb"))
|
|
42659
43118
|
return true;
|
|
42660
|
-
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(
|
|
43119
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename5) || basename5.endsWith("Test.java") || basename5.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
42661
43120
|
return true;
|
|
42662
43121
|
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
42663
43122
|
return true;
|
|
42664
|
-
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(
|
|
43123
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename5) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
42665
43124
|
return true;
|
|
42666
43125
|
if (lower.endsWith(".tests.ps1"))
|
|
42667
43126
|
return true;
|
|
@@ -42669,23 +43128,23 @@ function isLanguageSpecificTestFile(basename4) {
|
|
|
42669
43128
|
}
|
|
42670
43129
|
function isConventionTestFilePath(filePath) {
|
|
42671
43130
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
42672
|
-
const
|
|
42673
|
-
return hasCompoundTestExtension(
|
|
43131
|
+
const basename5 = path29.basename(filePath);
|
|
43132
|
+
return hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || isLanguageSpecificTestFile(basename5) || isTestDirectoryPath(normalizedPath);
|
|
42674
43133
|
}
|
|
42675
43134
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
42676
43135
|
const testFiles = [];
|
|
42677
43136
|
for (const file3 of sourceFiles) {
|
|
42678
43137
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
42679
|
-
const relativeFile =
|
|
42680
|
-
const
|
|
42681
|
-
const
|
|
42682
|
-
const preferRelativeOutput = !
|
|
43138
|
+
const relativeFile = path29.relative(workingDir, absoluteFile);
|
|
43139
|
+
const basename5 = path29.basename(absoluteFile);
|
|
43140
|
+
const dirname12 = path29.dirname(absoluteFile);
|
|
43141
|
+
const preferRelativeOutput = !path29.isAbsolute(file3);
|
|
42683
43142
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
42684
43143
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
42685
43144
|
continue;
|
|
42686
43145
|
}
|
|
42687
|
-
const nameWithoutExt =
|
|
42688
|
-
const ext =
|
|
43146
|
+
const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
|
|
43147
|
+
const ext = path29.extname(basename5);
|
|
42689
43148
|
const genericTestNames = [
|
|
42690
43149
|
`${nameWithoutExt}.spec${ext}`,
|
|
42691
43150
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -42694,17 +43153,17 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
42694
43153
|
const colocatedCandidates = [
|
|
42695
43154
|
...genericTestNames,
|
|
42696
43155
|
...languageSpecificTestNames
|
|
42697
|
-
].map((candidateName) =>
|
|
43156
|
+
].map((candidateName) => path29.join(dirname12, candidateName));
|
|
42698
43157
|
const testDirectoryNames = [
|
|
42699
|
-
|
|
43158
|
+
basename5,
|
|
42700
43159
|
...genericTestNames,
|
|
42701
43160
|
...languageSpecificTestNames
|
|
42702
43161
|
];
|
|
42703
43162
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
42704
43163
|
const possibleTestFiles = [
|
|
42705
43164
|
...colocatedCandidates,
|
|
42706
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
42707
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
43165
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path29.join(dirname12, dirName, candidateName))),
|
|
43166
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path29.join(candidateDir, candidateName)))
|
|
42708
43167
|
];
|
|
42709
43168
|
for (const testFile of possibleTestFiles) {
|
|
42710
43169
|
if (fs16.existsSync(testFile)) {
|
|
@@ -42725,7 +43184,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
42725
43184
|
try {
|
|
42726
43185
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
42727
43186
|
const content = fs16.readFileSync(absoluteTestFile, "utf-8");
|
|
42728
|
-
const testDir =
|
|
43187
|
+
const testDir = path29.dirname(absoluteTestFile);
|
|
42729
43188
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
42730
43189
|
let match;
|
|
42731
43190
|
match = importRegex.exec(content);
|
|
@@ -42733,8 +43192,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
42733
43192
|
const importPath = match[1];
|
|
42734
43193
|
let resolvedImport;
|
|
42735
43194
|
if (importPath.startsWith(".")) {
|
|
42736
|
-
resolvedImport =
|
|
42737
|
-
const existingExt =
|
|
43195
|
+
resolvedImport = path29.resolve(testDir, importPath);
|
|
43196
|
+
const existingExt = path29.extname(resolvedImport);
|
|
42738
43197
|
if (!existingExt) {
|
|
42739
43198
|
for (const extToTry of [
|
|
42740
43199
|
".ts",
|
|
@@ -42754,12 +43213,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
42754
43213
|
} else {
|
|
42755
43214
|
continue;
|
|
42756
43215
|
}
|
|
42757
|
-
const importBasename =
|
|
42758
|
-
const importDir =
|
|
43216
|
+
const importBasename = path29.basename(resolvedImport, path29.extname(resolvedImport));
|
|
43217
|
+
const importDir = path29.dirname(resolvedImport);
|
|
42759
43218
|
for (const sourceFile of absoluteSourceFiles) {
|
|
42760
|
-
const sourceDir =
|
|
42761
|
-
const sourceBasename =
|
|
42762
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
43219
|
+
const sourceDir = path29.dirname(sourceFile);
|
|
43220
|
+
const sourceBasename = path29.basename(sourceFile, path29.extname(sourceFile));
|
|
43221
|
+
const isRelatedDir = importDir === sourceDir || importDir === path29.join(sourceDir, "__tests__") || importDir === path29.join(sourceDir, "tests") || importDir === path29.join(sourceDir, "test") || importDir === path29.join(sourceDir, "spec");
|
|
42763
43222
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
42764
43223
|
dedupePush(testFiles, testFile);
|
|
42765
43224
|
break;
|
|
@@ -42772,8 +43231,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
42772
43231
|
while (match !== null) {
|
|
42773
43232
|
const importPath = match[1];
|
|
42774
43233
|
if (importPath.startsWith(".")) {
|
|
42775
|
-
let resolvedImport =
|
|
42776
|
-
const existingExt =
|
|
43234
|
+
let resolvedImport = path29.resolve(testDir, importPath);
|
|
43235
|
+
const existingExt = path29.extname(resolvedImport);
|
|
42777
43236
|
if (!existingExt) {
|
|
42778
43237
|
for (const extToTry of [
|
|
42779
43238
|
".ts",
|
|
@@ -42790,12 +43249,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
42790
43249
|
}
|
|
42791
43250
|
}
|
|
42792
43251
|
}
|
|
42793
|
-
const importDir =
|
|
42794
|
-
const importBasename =
|
|
43252
|
+
const importDir = path29.dirname(resolvedImport);
|
|
43253
|
+
const importBasename = path29.basename(resolvedImport, path29.extname(resolvedImport));
|
|
42795
43254
|
for (const sourceFile of absoluteSourceFiles) {
|
|
42796
|
-
const sourceDir =
|
|
42797
|
-
const sourceBasename =
|
|
42798
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
43255
|
+
const sourceDir = path29.dirname(sourceFile);
|
|
43256
|
+
const sourceBasename = path29.basename(sourceFile, path29.extname(sourceFile));
|
|
43257
|
+
const isRelatedDir = importDir === sourceDir || importDir === path29.join(sourceDir, "__tests__") || importDir === path29.join(sourceDir, "tests") || importDir === path29.join(sourceDir, "test") || importDir === path29.join(sourceDir, "spec");
|
|
42799
43258
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
42800
43259
|
dedupePush(testFiles, testFile);
|
|
42801
43260
|
break;
|
|
@@ -42898,8 +43357,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
42898
43357
|
return ["mvn", "test"];
|
|
42899
43358
|
case "gradle": {
|
|
42900
43359
|
const isWindows = process.platform === "win32";
|
|
42901
|
-
const hasGradlewBat = fs16.existsSync(
|
|
42902
|
-
const hasGradlew = fs16.existsSync(
|
|
43360
|
+
const hasGradlewBat = fs16.existsSync(path29.join(baseDir, "gradlew.bat"));
|
|
43361
|
+
const hasGradlew = fs16.existsSync(path29.join(baseDir, "gradlew"));
|
|
42903
43362
|
if (hasGradlewBat && isWindows)
|
|
42904
43363
|
return ["gradlew.bat", "test"];
|
|
42905
43364
|
if (hasGradlew)
|
|
@@ -42916,7 +43375,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
42916
43375
|
"cmake-build-release",
|
|
42917
43376
|
"out"
|
|
42918
43377
|
];
|
|
42919
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(
|
|
43378
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path29.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
42920
43379
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
42921
43380
|
}
|
|
42922
43381
|
case "swift-test":
|
|
@@ -43232,7 +43691,7 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
43232
43691
|
}
|
|
43233
43692
|
const startTime = Date.now();
|
|
43234
43693
|
try {
|
|
43235
|
-
const proc =
|
|
43694
|
+
const proc = bunSpawn(command, {
|
|
43236
43695
|
stdout: "pipe",
|
|
43237
43696
|
stderr: "pipe",
|
|
43238
43697
|
cwd
|
|
@@ -43544,7 +44003,7 @@ var test_runner = createSwarmTool({
|
|
|
43544
44003
|
const sourceFiles = args.files.filter((file3) => {
|
|
43545
44004
|
if (directTestFiles.includes(file3))
|
|
43546
44005
|
return false;
|
|
43547
|
-
const ext =
|
|
44006
|
+
const ext = path29.extname(file3).toLowerCase();
|
|
43548
44007
|
return SOURCE_EXTENSIONS.has(ext);
|
|
43549
44008
|
});
|
|
43550
44009
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -43579,7 +44038,7 @@ var test_runner = createSwarmTool({
|
|
|
43579
44038
|
if (isConventionTestFilePath(f)) {
|
|
43580
44039
|
return false;
|
|
43581
44040
|
}
|
|
43582
|
-
const ext =
|
|
44041
|
+
const ext = path29.extname(f).toLowerCase();
|
|
43583
44042
|
return SOURCE_EXTENSIONS.has(ext);
|
|
43584
44043
|
});
|
|
43585
44044
|
if (sourceFiles.length === 0) {
|
|
@@ -43606,7 +44065,7 @@ var test_runner = createSwarmTool({
|
|
|
43606
44065
|
if (isConventionTestFilePath(f)) {
|
|
43607
44066
|
return false;
|
|
43608
44067
|
}
|
|
43609
|
-
const ext =
|
|
44068
|
+
const ext = path29.extname(f).toLowerCase();
|
|
43610
44069
|
return SOURCE_EXTENSIONS.has(ext);
|
|
43611
44070
|
});
|
|
43612
44071
|
if (sourceFiles.length === 0) {
|
|
@@ -43624,8 +44083,8 @@ var test_runner = createSwarmTool({
|
|
|
43624
44083
|
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
43625
44084
|
if (impactResult.impactedTests.length > 0) {
|
|
43626
44085
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
43627
|
-
const relativePath =
|
|
43628
|
-
return
|
|
44086
|
+
const relativePath = path29.relative(workingDir, absPath);
|
|
44087
|
+
return path29.isAbsolute(relativePath) ? absPath : relativePath;
|
|
43629
44088
|
});
|
|
43630
44089
|
} else {
|
|
43631
44090
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -43718,8 +44177,8 @@ function validateDirectoryPath(dir) {
|
|
|
43718
44177
|
if (dir.includes("..")) {
|
|
43719
44178
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
43720
44179
|
}
|
|
43721
|
-
const normalized =
|
|
43722
|
-
const absolutePath =
|
|
44180
|
+
const normalized = path30.normalize(dir);
|
|
44181
|
+
const absolutePath = path30.isAbsolute(normalized) ? normalized : path30.resolve(normalized);
|
|
43723
44182
|
return absolutePath;
|
|
43724
44183
|
}
|
|
43725
44184
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -43742,7 +44201,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
43742
44201
|
}
|
|
43743
44202
|
function getPackageVersion(dir) {
|
|
43744
44203
|
try {
|
|
43745
|
-
const packagePath =
|
|
44204
|
+
const packagePath = path30.join(dir, "package.json");
|
|
43746
44205
|
if (fs17.existsSync(packagePath)) {
|
|
43747
44206
|
const content = fs17.readFileSync(packagePath, "utf-8");
|
|
43748
44207
|
const pkg = JSON.parse(content);
|
|
@@ -43753,7 +44212,7 @@ function getPackageVersion(dir) {
|
|
|
43753
44212
|
}
|
|
43754
44213
|
function getChangelogVersion(dir) {
|
|
43755
44214
|
try {
|
|
43756
|
-
const changelogPath =
|
|
44215
|
+
const changelogPath = path30.join(dir, "CHANGELOG.md");
|
|
43757
44216
|
if (fs17.existsSync(changelogPath)) {
|
|
43758
44217
|
const content = fs17.readFileSync(changelogPath, "utf-8");
|
|
43759
44218
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -43767,7 +44226,7 @@ function getChangelogVersion(dir) {
|
|
|
43767
44226
|
function getVersionFileVersion(dir) {
|
|
43768
44227
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
43769
44228
|
for (const file3 of possibleFiles) {
|
|
43770
|
-
const filePath =
|
|
44229
|
+
const filePath = path30.join(dir, file3);
|
|
43771
44230
|
if (fs17.existsSync(filePath)) {
|
|
43772
44231
|
try {
|
|
43773
44232
|
const content = fs17.readFileSync(filePath, "utf-8").trim();
|
|
@@ -44094,7 +44553,7 @@ async function runEvidenceCheck(dir) {
|
|
|
44094
44553
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
44095
44554
|
const startTime = Date.now();
|
|
44096
44555
|
try {
|
|
44097
|
-
const specPath =
|
|
44556
|
+
const specPath = path30.join(dir, ".swarm", "spec.md");
|
|
44098
44557
|
if (!fs17.existsSync(specPath)) {
|
|
44099
44558
|
return {
|
|
44100
44559
|
type: "req_coverage",
|
|
@@ -44478,7 +44937,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
44478
44937
|
|
|
44479
44938
|
// src/commands/reset.ts
|
|
44480
44939
|
import * as fs18 from "fs";
|
|
44481
|
-
import * as
|
|
44940
|
+
import * as path31 from "path";
|
|
44482
44941
|
|
|
44483
44942
|
// src/background/manager.ts
|
|
44484
44943
|
init_utils();
|
|
@@ -45199,7 +45658,7 @@ async function handleResetCommand(directory, args) {
|
|
|
45199
45658
|
}
|
|
45200
45659
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
45201
45660
|
try {
|
|
45202
|
-
const rootPath =
|
|
45661
|
+
const rootPath = path31.join(directory, filename);
|
|
45203
45662
|
if (fs18.existsSync(rootPath)) {
|
|
45204
45663
|
fs18.unlinkSync(rootPath);
|
|
45205
45664
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -45236,7 +45695,7 @@ async function handleResetCommand(directory, args) {
|
|
|
45236
45695
|
// src/commands/reset-session.ts
|
|
45237
45696
|
init_utils2();
|
|
45238
45697
|
import * as fs19 from "fs";
|
|
45239
|
-
import * as
|
|
45698
|
+
import * as path32 from "path";
|
|
45240
45699
|
async function handleResetSessionCommand(directory, _args) {
|
|
45241
45700
|
const results = [];
|
|
45242
45701
|
try {
|
|
@@ -45251,13 +45710,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
45251
45710
|
results.push("\u274C Failed to delete state.json");
|
|
45252
45711
|
}
|
|
45253
45712
|
try {
|
|
45254
|
-
const sessionDir =
|
|
45713
|
+
const sessionDir = path32.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
45255
45714
|
if (fs19.existsSync(sessionDir)) {
|
|
45256
45715
|
const files = fs19.readdirSync(sessionDir);
|
|
45257
45716
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
45258
45717
|
let deletedCount = 0;
|
|
45259
45718
|
for (const file3 of otherFiles) {
|
|
45260
|
-
const filePath =
|
|
45719
|
+
const filePath = path32.join(sessionDir, file3);
|
|
45261
45720
|
if (fs19.lstatSync(filePath).isFile()) {
|
|
45262
45721
|
fs19.unlinkSync(filePath);
|
|
45263
45722
|
deletedCount++;
|
|
@@ -45287,7 +45746,8 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
45287
45746
|
// src/summaries/manager.ts
|
|
45288
45747
|
init_utils2();
|
|
45289
45748
|
init_utils();
|
|
45290
|
-
|
|
45749
|
+
init_bun_compat();
|
|
45750
|
+
import * as path33 from "path";
|
|
45291
45751
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
45292
45752
|
function sanitizeSummaryId(id) {
|
|
45293
45753
|
if (!id || id.length === 0) {
|
|
@@ -45311,7 +45771,7 @@ function sanitizeSummaryId(id) {
|
|
|
45311
45771
|
}
|
|
45312
45772
|
async function loadFullOutput(directory, id) {
|
|
45313
45773
|
const sanitizedId = sanitizeSummaryId(id);
|
|
45314
|
-
const relativePath =
|
|
45774
|
+
const relativePath = path33.join("summaries", `${sanitizedId}.json`);
|
|
45315
45775
|
validateSwarmPath(directory, relativePath);
|
|
45316
45776
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
45317
45777
|
if (content === null) {
|
|
@@ -45367,7 +45827,7 @@ init_plan_schema();
|
|
|
45367
45827
|
init_utils2();
|
|
45368
45828
|
init_ledger();
|
|
45369
45829
|
import * as fs20 from "fs";
|
|
45370
|
-
import * as
|
|
45830
|
+
import * as path34 from "path";
|
|
45371
45831
|
async function handleRollbackCommand(directory, args) {
|
|
45372
45832
|
const phaseArg = args[0];
|
|
45373
45833
|
if (!phaseArg) {
|
|
@@ -45432,8 +45892,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
45432
45892
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
45433
45893
|
continue;
|
|
45434
45894
|
}
|
|
45435
|
-
const src =
|
|
45436
|
-
const dest =
|
|
45895
|
+
const src = path34.join(checkpointDir, file3);
|
|
45896
|
+
const dest = path34.join(swarmDir, file3);
|
|
45437
45897
|
try {
|
|
45438
45898
|
fs20.cpSync(src, dest, { recursive: true, force: true });
|
|
45439
45899
|
successes.push(file3);
|
|
@@ -45452,12 +45912,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
45452
45912
|
].join(`
|
|
45453
45913
|
`);
|
|
45454
45914
|
}
|
|
45455
|
-
const existingLedgerPath =
|
|
45915
|
+
const existingLedgerPath = path34.join(swarmDir, "plan-ledger.jsonl");
|
|
45456
45916
|
if (fs20.existsSync(existingLedgerPath)) {
|
|
45457
45917
|
fs20.unlinkSync(existingLedgerPath);
|
|
45458
45918
|
}
|
|
45459
45919
|
try {
|
|
45460
|
-
const planJsonPath =
|
|
45920
|
+
const planJsonPath = path34.join(swarmDir, "plan.json");
|
|
45461
45921
|
if (fs20.existsSync(planJsonPath)) {
|
|
45462
45922
|
const planRaw = fs20.readFileSync(planJsonPath, "utf-8");
|
|
45463
45923
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -45530,9 +45990,9 @@ async function handleSimulateCommand(directory, args) {
|
|
|
45530
45990
|
const report = reportLines.filter(Boolean).join(`
|
|
45531
45991
|
`);
|
|
45532
45992
|
const fs21 = await import("fs/promises");
|
|
45533
|
-
const
|
|
45534
|
-
const reportPath =
|
|
45535
|
-
await fs21.mkdir(
|
|
45993
|
+
const path35 = await import("path");
|
|
45994
|
+
const reportPath = path35.join(directory, ".swarm", "simulate-report.md");
|
|
45995
|
+
await fs21.mkdir(path35.dirname(reportPath), { recursive: true });
|
|
45536
45996
|
await fs21.writeFile(reportPath, report, "utf-8");
|
|
45537
45997
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
45538
45998
|
}
|
|
@@ -45592,6 +46052,7 @@ function getCompactionMetrics(sessionId) {
|
|
|
45592
46052
|
|
|
45593
46053
|
// src/services/context-budget-service.ts
|
|
45594
46054
|
init_utils2();
|
|
46055
|
+
init_bun_compat();
|
|
45595
46056
|
var DEFAULT_CONTEXT_BUDGET_CONFIG = {
|
|
45596
46057
|
enabled: true,
|
|
45597
46058
|
budgetTokens: 40000,
|
|
@@ -45946,9 +46407,9 @@ var COMMAND_REGISTRY = {
|
|
|
45946
46407
|
},
|
|
45947
46408
|
council: {
|
|
45948
46409
|
handler: (ctx) => handleCouncilCommand(ctx.directory, ctx.args),
|
|
45949
|
-
description: "Enter architect MODE: COUNCIL \u2014 multi-model deliberation [question] [--
|
|
45950
|
-
args: "<question> [--
|
|
45951
|
-
details: "Triggers the architect to convene a
|
|
46410
|
+
description: "Enter architect MODE: COUNCIL \u2014 multi-model deliberation [question] [--spec-review]",
|
|
46411
|
+
args: "<question> [--spec-review]",
|
|
46412
|
+
details: "Triggers the architect to convene a three-agent General Council: " + "Generalist (reviewer model), Skeptic (critic model), and Domain Expert (SME model). " + "The architect first runs 1\u20133 targeted web searches and passes a compiled RESEARCH CONTEXT " + "to all three agents before dispatching them in parallel. " + "Agents deliberate using the NSED peer-review protocol (Round 1 independent analysis, " + "Round 2 MAINTAIN/CONCEDE/NUANCE for disagreements). " + "The architect synthesizes the final answer directly from convene_general_council output. " + "--spec-review switches to single-pass advisory mode for spec review. " + "Requires council.general.enabled: true and a search API key in opencode-swarm.json."
|
|
45952
46413
|
},
|
|
45953
46414
|
"pr-review": {
|
|
45954
46415
|
handler: async (ctx) => handlePrReviewCommand(ctx.directory, ctx.args),
|
|
@@ -46080,50 +46541,50 @@ function resolveCommand(tokens) {
|
|
|
46080
46541
|
// src/cli/index.ts
|
|
46081
46542
|
var { version: version4 } = package_default;
|
|
46082
46543
|
var CONFIG_DIR = getPluginConfigDir();
|
|
46083
|
-
var OPENCODE_CONFIG_PATH =
|
|
46084
|
-
var PLUGIN_CONFIG_PATH =
|
|
46085
|
-
var PROMPTS_DIR =
|
|
46544
|
+
var OPENCODE_CONFIG_PATH = path35.join(CONFIG_DIR, "opencode.json");
|
|
46545
|
+
var PLUGIN_CONFIG_PATH = path35.join(CONFIG_DIR, "opencode-swarm.json");
|
|
46546
|
+
var PROMPTS_DIR = path35.join(CONFIG_DIR, "opencode-swarm");
|
|
46086
46547
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
46087
46548
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
46088
46549
|
function isSafeCachePath(p) {
|
|
46089
|
-
const resolved =
|
|
46090
|
-
const home =
|
|
46550
|
+
const resolved = path35.resolve(p);
|
|
46551
|
+
const home = path35.resolve(os7.homedir());
|
|
46091
46552
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
46092
46553
|
return false;
|
|
46093
46554
|
}
|
|
46094
|
-
const segments = resolved.split(
|
|
46555
|
+
const segments = resolved.split(path35.sep).filter((s) => s.length > 0);
|
|
46095
46556
|
if (segments.length < 4) {
|
|
46096
46557
|
return false;
|
|
46097
46558
|
}
|
|
46098
|
-
const leaf =
|
|
46559
|
+
const leaf = path35.basename(resolved);
|
|
46099
46560
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
46100
46561
|
return false;
|
|
46101
46562
|
}
|
|
46102
|
-
const parent =
|
|
46563
|
+
const parent = path35.basename(path35.dirname(resolved));
|
|
46103
46564
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
46104
46565
|
return false;
|
|
46105
46566
|
}
|
|
46106
|
-
const grandparent =
|
|
46567
|
+
const grandparent = path35.basename(path35.dirname(path35.dirname(resolved)));
|
|
46107
46568
|
if (grandparent !== "opencode") {
|
|
46108
46569
|
return false;
|
|
46109
46570
|
}
|
|
46110
46571
|
return true;
|
|
46111
46572
|
}
|
|
46112
46573
|
function isSafeLockFilePath(p) {
|
|
46113
|
-
const resolved =
|
|
46114
|
-
const home =
|
|
46574
|
+
const resolved = path35.resolve(p);
|
|
46575
|
+
const home = path35.resolve(os7.homedir());
|
|
46115
46576
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
46116
46577
|
return false;
|
|
46117
46578
|
}
|
|
46118
|
-
const segments = resolved.split(
|
|
46579
|
+
const segments = resolved.split(path35.sep).filter((s) => s.length > 0);
|
|
46119
46580
|
if (segments.length < 4) {
|
|
46120
46581
|
return false;
|
|
46121
46582
|
}
|
|
46122
|
-
const leaf =
|
|
46583
|
+
const leaf = path35.basename(resolved);
|
|
46123
46584
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
46124
46585
|
return false;
|
|
46125
46586
|
}
|
|
46126
|
-
const parent =
|
|
46587
|
+
const parent = path35.basename(path35.dirname(resolved));
|
|
46127
46588
|
if (parent !== "opencode") {
|
|
46128
46589
|
return false;
|
|
46129
46590
|
}
|
|
@@ -46149,8 +46610,8 @@ function saveJson(filepath, data) {
|
|
|
46149
46610
|
}
|
|
46150
46611
|
function writeProjectConfigIfMissing(cwd) {
|
|
46151
46612
|
try {
|
|
46152
|
-
const opencodeDir =
|
|
46153
|
-
const projectConfigPath =
|
|
46613
|
+
const opencodeDir = path35.join(cwd, ".opencode");
|
|
46614
|
+
const projectConfigPath = path35.join(opencodeDir, "opencode-swarm.json");
|
|
46154
46615
|
if (fs21.existsSync(projectConfigPath)) {
|
|
46155
46616
|
return;
|
|
46156
46617
|
}
|
|
@@ -46168,7 +46629,7 @@ async function install() {
|
|
|
46168
46629
|
`);
|
|
46169
46630
|
ensureDir(CONFIG_DIR);
|
|
46170
46631
|
ensureDir(PROMPTS_DIR);
|
|
46171
|
-
const LEGACY_CONFIG_PATH =
|
|
46632
|
+
const LEGACY_CONFIG_PATH = path35.join(CONFIG_DIR, "config.json");
|
|
46172
46633
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
46173
46634
|
if (!opencodeConfig) {
|
|
46174
46635
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -46273,14 +46734,6 @@ async function install() {
|
|
|
46273
46734
|
curator_phase: {
|
|
46274
46735
|
model: "opencode/gpt-5-nano",
|
|
46275
46736
|
fallback_models: ["opencode/big-pickle"]
|
|
46276
|
-
},
|
|
46277
|
-
council_member: {
|
|
46278
|
-
model: "opencode/gpt-5-nano",
|
|
46279
|
-
fallback_models: ["opencode/big-pickle"]
|
|
46280
|
-
},
|
|
46281
|
-
council_moderator: {
|
|
46282
|
-
model: "opencode/gpt-5-nano",
|
|
46283
|
-
fallback_models: ["opencode/big-pickle"]
|
|
46284
46737
|
}
|
|
46285
46738
|
},
|
|
46286
46739
|
max_iterations: 5
|