opencode-swarm 7.32.3 → 7.33.1
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 +1 -0
- package/dist/cli/index.js +1052 -517
- package/dist/config/schema.d.ts +16 -2
- package/dist/evidence/gate-bridge.d.ts +15 -0
- package/dist/index.js +1179 -545
- package/dist/memory/config.d.ts +5 -1
- package/dist/memory/gateway.d.ts +2 -0
- package/dist/memory/index.d.ts +2 -1
- package/dist/memory/provider.d.ts +1 -0
- package/dist/memory/sqlite-provider.d.ts +39 -0
- package/dist/plan/ledger.d.ts +9 -0
- package/dist/plan/manager.d.ts +28 -2
- package/dist/services/evidence-summary-service.d.ts +5 -0
- package/dist/telemetry.d.ts +1 -1
- package/dist/tools/save-plan.d.ts +12 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ var package_default;
|
|
|
48
48
|
var init_package = __esm(() => {
|
|
49
49
|
package_default = {
|
|
50
50
|
name: "opencode-swarm",
|
|
51
|
-
version: "7.
|
|
51
|
+
version: "7.33.1",
|
|
52
52
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
53
53
|
main: "dist/index.js",
|
|
54
54
|
types: "dist/index.d.ts",
|
|
@@ -15539,8 +15539,12 @@ var init_schema = __esm(() => {
|
|
|
15539
15539
|
});
|
|
15540
15540
|
MemoryConfigSchema = exports_external.object({
|
|
15541
15541
|
enabled: exports_external.boolean().default(false),
|
|
15542
|
-
provider: exports_external.
|
|
15542
|
+
provider: exports_external.enum(["local-jsonl", "sqlite"]).default("local-jsonl"),
|
|
15543
15543
|
storageDir: exports_external.string().default(".swarm/memory"),
|
|
15544
|
+
sqlite: exports_external.object({
|
|
15545
|
+
path: exports_external.string().default(".swarm/memory/memory.db"),
|
|
15546
|
+
busyTimeoutMs: exports_external.number().int().min(0).max(60000).default(5000)
|
|
15547
|
+
}).default({ path: ".swarm/memory/memory.db", busyTimeoutMs: 5000 }),
|
|
15544
15548
|
recall: exports_external.object({
|
|
15545
15549
|
defaultMaxItems: exports_external.number().int().min(1).max(20).default(8),
|
|
15546
15550
|
defaultTokenBudget: exports_external.number().int().min(100).max(5000).default(1200),
|
|
@@ -17366,6 +17370,32 @@ async function appendLedgerEvent(directory, eventInput, options) {
|
|
|
17366
17370
|
fs4.renameSync(tempPath, ledgerPath);
|
|
17367
17371
|
return event;
|
|
17368
17372
|
}
|
|
17373
|
+
async function takeSnapshotWithRetry(directory, plan, options) {
|
|
17374
|
+
const MAX_RETRIES = 3;
|
|
17375
|
+
const TOTAL_ATTEMPTS = 1 + MAX_RETRIES;
|
|
17376
|
+
const telemetrySource = options?.source ?? "save_plan_tool";
|
|
17377
|
+
const snapshotOptions = { planHashAfter: options?.planHashAfter };
|
|
17378
|
+
let lastError;
|
|
17379
|
+
for (let attempt = 1;attempt <= TOTAL_ATTEMPTS; attempt++) {
|
|
17380
|
+
try {
|
|
17381
|
+
await takeSnapshotEvent(directory, plan, snapshotOptions);
|
|
17382
|
+
return;
|
|
17383
|
+
} catch (err2) {
|
|
17384
|
+
lastError = err2 instanceof Error ? err2 : new Error(String(err2));
|
|
17385
|
+
if (attempt < TOTAL_ATTEMPTS) {
|
|
17386
|
+
await new Promise((r) => setTimeout(r, 10 * 2 ** (attempt - 1)));
|
|
17387
|
+
}
|
|
17388
|
+
}
|
|
17389
|
+
}
|
|
17390
|
+
console.warn(`[takeSnapshotWithRetry] Snapshot failed after ${MAX_RETRIES} retries (${TOTAL_ATTEMPTS} attempts): ${lastError.message}`);
|
|
17391
|
+
try {
|
|
17392
|
+
emit("snapshot_failed", {
|
|
17393
|
+
error: lastError.message,
|
|
17394
|
+
retries: MAX_RETRIES,
|
|
17395
|
+
source: telemetrySource
|
|
17396
|
+
});
|
|
17397
|
+
} catch {}
|
|
17398
|
+
}
|
|
17369
17399
|
async function takeSnapshotEvent(directory, plan, options) {
|
|
17370
17400
|
const payloadHash = computePlanHash(plan);
|
|
17371
17401
|
const snapshotPayload = {
|
|
@@ -17599,6 +17629,7 @@ async function loadLastApprovedPlan(directory, expectedPlanId) {
|
|
|
17599
17629
|
var LEDGER_SCHEMA_VERSION = "1.1.0", LEDGER_FILENAME = "plan-ledger.jsonl", PLAN_JSON_FILENAME = "plan.json", LedgerStaleWriterError;
|
|
17600
17630
|
var init_ledger = __esm(() => {
|
|
17601
17631
|
init_plan_schema();
|
|
17632
|
+
init_telemetry();
|
|
17602
17633
|
LedgerStaleWriterError = class LedgerStaleWriterError extends Error {
|
|
17603
17634
|
constructor(message) {
|
|
17604
17635
|
super(message);
|
|
@@ -17792,7 +17823,9 @@ async function loadPlan(directory) {
|
|
|
17792
17823
|
try {
|
|
17793
17824
|
const rebuilt = await replayFromLedger(directory);
|
|
17794
17825
|
if (rebuilt) {
|
|
17795
|
-
await rebuildPlan(directory, rebuilt
|
|
17826
|
+
await rebuildPlan(directory, rebuilt, {
|
|
17827
|
+
reason: "ledger_hash_mismatch_recovery"
|
|
17828
|
+
});
|
|
17796
17829
|
warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/SWARM_PLAN.md if it exists.");
|
|
17797
17830
|
return rebuilt;
|
|
17798
17831
|
}
|
|
@@ -17800,7 +17833,9 @@ async function loadPlan(directory) {
|
|
|
17800
17833
|
try {
|
|
17801
17834
|
const approved = await loadLastApprovedPlan(directory, currentPlanId);
|
|
17802
17835
|
if (approved) {
|
|
17803
|
-
await rebuildPlan(directory, approved.plan
|
|
17836
|
+
await rebuildPlan(directory, approved.plan, {
|
|
17837
|
+
reason: "approved_snapshot_fallback"
|
|
17838
|
+
});
|
|
17804
17839
|
try {
|
|
17805
17840
|
await takeSnapshotEvent(directory, approved.plan, {
|
|
17806
17841
|
source: "recovery_from_approved_snapshot",
|
|
@@ -17877,7 +17912,9 @@ async function loadPlan(directory) {
|
|
|
17877
17912
|
} else if (catchFirstEvent !== null && rawPlanId !== null) {
|
|
17878
17913
|
const rebuilt = await replayFromLedger(directory);
|
|
17879
17914
|
if (rebuilt) {
|
|
17880
|
-
await rebuildPlan(directory, rebuilt
|
|
17915
|
+
await rebuildPlan(directory, rebuilt, {
|
|
17916
|
+
reason: "validation_failure_recovery"
|
|
17917
|
+
});
|
|
17881
17918
|
warn("[loadPlan] Rebuilt plan from ledger after validation failure. Projection was stale.");
|
|
17882
17919
|
return rebuilt;
|
|
17883
17920
|
}
|
|
@@ -18238,12 +18275,9 @@ async function savePlan(directory, plan, options) {
|
|
|
18238
18275
|
const SNAPSHOT_INTERVAL = 50;
|
|
18239
18276
|
const latestSeq = await getLatestLedgerSeq(directory);
|
|
18240
18277
|
if (latestSeq > 0 && latestSeq % SNAPSHOT_INTERVAL === 0) {
|
|
18241
|
-
await
|
|
18242
|
-
planHashAfter: hashAfter
|
|
18243
|
-
|
|
18244
|
-
if (process.env.DEBUG_SWARM) {
|
|
18245
|
-
warn(`[savePlan] Periodic snapshot write failed (non-fatal): ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
18246
|
-
}
|
|
18278
|
+
await takeSnapshotWithRetry(directory, validated, {
|
|
18279
|
+
planHashAfter: hashAfter,
|
|
18280
|
+
source: "savePlan_manager"
|
|
18247
18281
|
});
|
|
18248
18282
|
}
|
|
18249
18283
|
const swarmDir = path6.resolve(directory, ".swarm");
|
|
@@ -18257,6 +18291,17 @@ async function savePlan(directory, plan, options) {
|
|
|
18257
18291
|
unlinkSync(tempPath);
|
|
18258
18292
|
} catch {}
|
|
18259
18293
|
}
|
|
18294
|
+
try {
|
|
18295
|
+
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
18296
|
+
const inProgressMarker = JSON.stringify({
|
|
18297
|
+
source: "plan_manager",
|
|
18298
|
+
timestamp: new Date().toISOString(),
|
|
18299
|
+
phases_count: validated.phases.length,
|
|
18300
|
+
tasks_count: validated.phases.reduce((sum, p) => sum + p.tasks.length, 0),
|
|
18301
|
+
in_progress: true
|
|
18302
|
+
});
|
|
18303
|
+
await bunWrite(markerPath, inProgressMarker);
|
|
18304
|
+
} catch {}
|
|
18260
18305
|
try {
|
|
18261
18306
|
const contentHash = computePlanContentHash(validated);
|
|
18262
18307
|
const markdown = derivePlanMarkdown(validated);
|
|
@@ -18290,41 +18335,146 @@ ${markdown}`;
|
|
|
18290
18335
|
source: "plan_manager",
|
|
18291
18336
|
timestamp: new Date().toISOString(),
|
|
18292
18337
|
phases_count: validated.phases.length,
|
|
18293
|
-
tasks_count: tasksCount
|
|
18338
|
+
tasks_count: tasksCount,
|
|
18339
|
+
in_progress: false
|
|
18294
18340
|
});
|
|
18295
18341
|
await bunWrite(markerPath, marker);
|
|
18296
18342
|
} catch {}
|
|
18297
18343
|
}
|
|
18298
|
-
async function rebuildPlan(directory, plan) {
|
|
18344
|
+
async function rebuildPlan(directory, plan, options) {
|
|
18299
18345
|
const targetPlan = plan ?? await replayFromLedger(directory);
|
|
18300
18346
|
if (!targetPlan)
|
|
18301
18347
|
return null;
|
|
18302
18348
|
const swarmDir = path6.join(directory, ".swarm");
|
|
18303
18349
|
const planPath = path6.join(swarmDir, "plan.json");
|
|
18304
18350
|
const mdPath = path6.join(swarmDir, "plan.md");
|
|
18305
|
-
const tempPlanPath = path6.join(swarmDir, `plan.json.rebuild.${Date.now()}`);
|
|
18351
|
+
const tempPlanPath = path6.join(swarmDir, `plan.json.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
18306
18352
|
await bunWrite(tempPlanPath, JSON.stringify(targetPlan, null, 2));
|
|
18307
18353
|
renameSync3(tempPlanPath, planPath);
|
|
18308
|
-
const contentHash = computePlanContentHash(targetPlan);
|
|
18309
|
-
const markdown = derivePlanMarkdown(targetPlan);
|
|
18310
|
-
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
18311
|
-
${markdown}`;
|
|
18312
|
-
const tempMdPath = path6.join(swarmDir, `plan.md.rebuild.${Date.now()}`);
|
|
18313
|
-
await bunWrite(tempMdPath, markdownWithHash);
|
|
18314
|
-
renameSync3(tempMdPath, mdPath);
|
|
18315
18354
|
try {
|
|
18316
18355
|
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
18317
|
-
const
|
|
18318
|
-
const marker = JSON.stringify({
|
|
18356
|
+
const inProgressMarker = JSON.stringify({
|
|
18319
18357
|
source: "plan_manager",
|
|
18320
18358
|
timestamp: new Date().toISOString(),
|
|
18321
18359
|
phases_count: targetPlan.phases.length,
|
|
18322
|
-
tasks_count:
|
|
18360
|
+
tasks_count: targetPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0),
|
|
18361
|
+
in_progress: true
|
|
18323
18362
|
});
|
|
18324
|
-
await bunWrite(markerPath,
|
|
18363
|
+
await bunWrite(markerPath, inProgressMarker);
|
|
18364
|
+
} catch {}
|
|
18365
|
+
try {
|
|
18366
|
+
const contentHash = computePlanContentHash(targetPlan);
|
|
18367
|
+
const markdown = derivePlanMarkdown(targetPlan);
|
|
18368
|
+
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
18369
|
+
${markdown}`;
|
|
18370
|
+
const tempMdPath = path6.join(swarmDir, `plan.md.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
18371
|
+
await bunWrite(tempMdPath, markdownWithHash);
|
|
18372
|
+
renameSync3(tempMdPath, mdPath);
|
|
18373
|
+
} finally {
|
|
18374
|
+
try {
|
|
18375
|
+
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
18376
|
+
const tasksCount = targetPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
18377
|
+
const marker = JSON.stringify({
|
|
18378
|
+
source: "plan_manager",
|
|
18379
|
+
timestamp: new Date().toISOString(),
|
|
18380
|
+
phases_count: targetPlan.phases.length,
|
|
18381
|
+
tasks_count: tasksCount,
|
|
18382
|
+
in_progress: false
|
|
18383
|
+
});
|
|
18384
|
+
await bunWrite(markerPath, marker);
|
|
18385
|
+
} catch {}
|
|
18386
|
+
}
|
|
18387
|
+
try {
|
|
18388
|
+
const planId = derivePlanId(targetPlan);
|
|
18389
|
+
const planHashAfter = computePlanHash(targetPlan);
|
|
18390
|
+
await appendLedgerEvent(directory, {
|
|
18391
|
+
event_type: "plan_rebuilt",
|
|
18392
|
+
source: "rebuildPlan",
|
|
18393
|
+
plan_id: planId,
|
|
18394
|
+
payload: {
|
|
18395
|
+
reason: options?.reason ?? "ledger_replay_recovery",
|
|
18396
|
+
phases_count: targetPlan.phases.length,
|
|
18397
|
+
tasks_count: targetPlan.phases.reduce((sum, p) => sum + p.tasks.length, 0)
|
|
18398
|
+
}
|
|
18399
|
+
}, { planHashAfter });
|
|
18325
18400
|
} catch {}
|
|
18326
18401
|
return targetPlan;
|
|
18327
18402
|
}
|
|
18403
|
+
async function closePlanTerminalState(directory, plan, options) {
|
|
18404
|
+
const planId = derivePlanId(plan);
|
|
18405
|
+
const validated = PlanSchema.parse(plan);
|
|
18406
|
+
const hashAfter = computePlanHash(validated);
|
|
18407
|
+
for (const taskId of options.closedTaskIds) {
|
|
18408
|
+
let taskPhaseId;
|
|
18409
|
+
for (const phase of validated.phases) {
|
|
18410
|
+
if (phase.tasks.some((t) => t.id === taskId)) {
|
|
18411
|
+
taskPhaseId = phase.id;
|
|
18412
|
+
break;
|
|
18413
|
+
}
|
|
18414
|
+
}
|
|
18415
|
+
const fromStatus = options.originalStatuses?.get(taskId) ?? "in_progress";
|
|
18416
|
+
await appendLedgerEvent(directory, {
|
|
18417
|
+
plan_id: planId,
|
|
18418
|
+
event_type: "task_status_changed",
|
|
18419
|
+
task_id: taskId,
|
|
18420
|
+
phase_id: taskPhaseId,
|
|
18421
|
+
from_status: fromStatus,
|
|
18422
|
+
to_status: "closed",
|
|
18423
|
+
source: "close_terminal"
|
|
18424
|
+
}, { planHashAfter: hashAfter });
|
|
18425
|
+
}
|
|
18426
|
+
for (const phaseId of options.closedPhaseIds) {
|
|
18427
|
+
await appendLedgerEvent(directory, {
|
|
18428
|
+
plan_id: planId,
|
|
18429
|
+
event_type: "phase_completed",
|
|
18430
|
+
phase_id: phaseId,
|
|
18431
|
+
source: "close_terminal"
|
|
18432
|
+
}, { planHashAfter: hashAfter });
|
|
18433
|
+
}
|
|
18434
|
+
await takeSnapshotEvent(directory, validated, {
|
|
18435
|
+
planHashAfter: hashAfter,
|
|
18436
|
+
source: "close_terminal"
|
|
18437
|
+
});
|
|
18438
|
+
const swarmDir = path6.join(directory, ".swarm");
|
|
18439
|
+
const planPath = path6.join(swarmDir, "plan.json");
|
|
18440
|
+
const tempPlanPath = path6.join(swarmDir, `plan.json.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
18441
|
+
await bunWrite(tempPlanPath, JSON.stringify(validated, null, 2));
|
|
18442
|
+
renameSync3(tempPlanPath, planPath);
|
|
18443
|
+
try {
|
|
18444
|
+
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
18445
|
+
const inProgressMarker = JSON.stringify({
|
|
18446
|
+
source: "plan_manager_close",
|
|
18447
|
+
timestamp: new Date().toISOString(),
|
|
18448
|
+
phases_count: validated.phases.length,
|
|
18449
|
+
tasks_count: validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0),
|
|
18450
|
+
in_progress: true
|
|
18451
|
+
});
|
|
18452
|
+
await bunWrite(markerPath, inProgressMarker);
|
|
18453
|
+
} catch {}
|
|
18454
|
+
try {
|
|
18455
|
+
const mdPath = path6.join(swarmDir, "plan.md");
|
|
18456
|
+
const contentHash = computePlanContentHash(validated);
|
|
18457
|
+
const markdown = derivePlanMarkdown(validated);
|
|
18458
|
+
const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
|
|
18459
|
+
${markdown}`;
|
|
18460
|
+
const mdTempPath = path6.join(swarmDir, `plan.md.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
18461
|
+
await bunWrite(mdTempPath, markdownWithHash);
|
|
18462
|
+
renameSync3(mdTempPath, mdPath);
|
|
18463
|
+
} finally {
|
|
18464
|
+
try {
|
|
18465
|
+
const markerPath = path6.join(swarmDir, ".plan-write-marker");
|
|
18466
|
+
const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
|
|
18467
|
+
const marker = JSON.stringify({
|
|
18468
|
+
source: "plan_manager_close",
|
|
18469
|
+
timestamp: new Date().toISOString(),
|
|
18470
|
+
phases_count: validated.phases.length,
|
|
18471
|
+
tasks_count: tasksCount,
|
|
18472
|
+
in_progress: false
|
|
18473
|
+
});
|
|
18474
|
+
await bunWrite(markerPath, marker);
|
|
18475
|
+
} catch {}
|
|
18476
|
+
}
|
|
18477
|
+
}
|
|
18328
18478
|
async function updateTaskStatus(directory, taskId, status) {
|
|
18329
18479
|
const derivePhaseStatusFromTasks = (tasks) => {
|
|
18330
18480
|
if (tasks.length > 0 && tasks.every((task) => task.status === "completed")) {
|
|
@@ -58840,6 +58990,12 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
58840
58990
|
}
|
|
58841
58991
|
}
|
|
58842
58992
|
if (planExists) {
|
|
58993
|
+
const originalStatuses = new Map;
|
|
58994
|
+
for (const phase of planData.phases ?? []) {
|
|
58995
|
+
for (const task of phase.tasks ?? []) {
|
|
58996
|
+
originalStatuses.set(task.id, task.status);
|
|
58997
|
+
}
|
|
58998
|
+
}
|
|
58843
58999
|
const guaranteeResult = guaranteeAllPlansComplete(planData);
|
|
58844
59000
|
for (const phaseId of guaranteeResult.closedPhaseIds) {
|
|
58845
59001
|
if (!closedPhases.includes(phaseId)) {
|
|
@@ -58853,11 +59009,15 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
58853
59009
|
}
|
|
58854
59010
|
if (!planAlreadyDone || guaranteeResult.closedPhaseIds.length > 0 || guaranteeResult.closedTaskIds.length > 0) {
|
|
58855
59011
|
try {
|
|
58856
|
-
await
|
|
59012
|
+
await closePlanTerminalState(directory, planData, {
|
|
59013
|
+
closedPhaseIds: guaranteeResult.closedPhaseIds,
|
|
59014
|
+
closedTaskIds: guaranteeResult.closedTaskIds,
|
|
59015
|
+
originalStatuses
|
|
59016
|
+
});
|
|
58857
59017
|
} catch (error93) {
|
|
58858
59018
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
58859
|
-
warnings.push(`Failed to persist terminal plan
|
|
58860
|
-
console.warn("[close-command] Failed to write plan
|
|
59019
|
+
warnings.push(`Failed to persist terminal plan state: ${msg}`);
|
|
59020
|
+
console.warn("[close-command] Failed to write terminal plan state:", error93);
|
|
58861
59021
|
}
|
|
58862
59022
|
}
|
|
58863
59023
|
}
|
|
@@ -59145,6 +59305,7 @@ var init_close = __esm(() => {
|
|
|
59145
59305
|
init_knowledge_curator();
|
|
59146
59306
|
init_knowledge_store();
|
|
59147
59307
|
init_utils2();
|
|
59308
|
+
init_manager();
|
|
59148
59309
|
init_scope_persistence();
|
|
59149
59310
|
init_skill_improver();
|
|
59150
59311
|
init_state();
|
|
@@ -59887,6 +60048,120 @@ function getPluginCachePaths() {
|
|
|
59887
60048
|
}
|
|
59888
60049
|
var init_cache_paths = () => {};
|
|
59889
60050
|
|
|
60051
|
+
// src/evidence/gate-bridge.ts
|
|
60052
|
+
async function readDurableGateEvidence(directory, taskId) {
|
|
60053
|
+
try {
|
|
60054
|
+
return await readTaskEvidence(directory, taskId);
|
|
60055
|
+
} catch {
|
|
60056
|
+
return null;
|
|
60057
|
+
}
|
|
60058
|
+
}
|
|
60059
|
+
function getDurableGateEvidenceStatus(evidence) {
|
|
60060
|
+
if (!evidence?.gates || typeof evidence.gates !== "object") {
|
|
60061
|
+
return {
|
|
60062
|
+
isComplete: false,
|
|
60063
|
+
missingGates: [],
|
|
60064
|
+
evidenceExists: evidence != null,
|
|
60065
|
+
invalid: false
|
|
60066
|
+
};
|
|
60067
|
+
}
|
|
60068
|
+
if (!Array.isArray(evidence.required_gates) || evidence.required_gates.length === 0) {
|
|
60069
|
+
return {
|
|
60070
|
+
isComplete: false,
|
|
60071
|
+
missingGates: ["required_gates"],
|
|
60072
|
+
evidenceExists: true,
|
|
60073
|
+
invalid: false
|
|
60074
|
+
};
|
|
60075
|
+
}
|
|
60076
|
+
const missingGates = evidence.required_gates.filter((gate) => evidence.gates[gate] == null);
|
|
60077
|
+
return {
|
|
60078
|
+
isComplete: missingGates.length === 0,
|
|
60079
|
+
missingGates,
|
|
60080
|
+
evidenceExists: true,
|
|
60081
|
+
invalid: false
|
|
60082
|
+
};
|
|
60083
|
+
}
|
|
60084
|
+
async function getDurableGateEvidenceStatusForTask(directory, taskId) {
|
|
60085
|
+
if (!isValidTaskId(taskId)) {
|
|
60086
|
+
return {
|
|
60087
|
+
isComplete: false,
|
|
60088
|
+
missingGates: [],
|
|
60089
|
+
evidenceExists: false,
|
|
60090
|
+
invalid: false
|
|
60091
|
+
};
|
|
60092
|
+
}
|
|
60093
|
+
try {
|
|
60094
|
+
return getDurableGateEvidenceStatus(readTaskEvidenceRaw(directory, taskId));
|
|
60095
|
+
} catch {
|
|
60096
|
+
return {
|
|
60097
|
+
isComplete: false,
|
|
60098
|
+
missingGates: ["invalid_gate_evidence"],
|
|
60099
|
+
evidenceExists: true,
|
|
60100
|
+
invalid: true
|
|
60101
|
+
};
|
|
60102
|
+
}
|
|
60103
|
+
}
|
|
60104
|
+
function gateEvidenceToEntry(taskId, gate, type, evidence) {
|
|
60105
|
+
const gateRecord = evidence.gates[gate];
|
|
60106
|
+
if (!gateRecord) {
|
|
60107
|
+
return null;
|
|
60108
|
+
}
|
|
60109
|
+
const base = {
|
|
60110
|
+
task_id: taskId,
|
|
60111
|
+
timestamp: gateRecord.timestamp,
|
|
60112
|
+
agent: gateRecord.agent || gate,
|
|
60113
|
+
verdict: "pass",
|
|
60114
|
+
summary: `Gate evidence recorded by ${gate}`,
|
|
60115
|
+
metadata: { source: "durable_gate_evidence", gate }
|
|
60116
|
+
};
|
|
60117
|
+
if (type === "review") {
|
|
60118
|
+
return {
|
|
60119
|
+
...base,
|
|
60120
|
+
type,
|
|
60121
|
+
risk: "low",
|
|
60122
|
+
issues: []
|
|
60123
|
+
};
|
|
60124
|
+
}
|
|
60125
|
+
if (type === "approval") {
|
|
60126
|
+
return {
|
|
60127
|
+
...base,
|
|
60128
|
+
type
|
|
60129
|
+
};
|
|
60130
|
+
}
|
|
60131
|
+
return {
|
|
60132
|
+
...base,
|
|
60133
|
+
type,
|
|
60134
|
+
tests_passed: 0,
|
|
60135
|
+
tests_failed: 0,
|
|
60136
|
+
failures: []
|
|
60137
|
+
};
|
|
60138
|
+
}
|
|
60139
|
+
function mergeDurableGateEntriesFromEvidence(taskId, entries, evidence) {
|
|
60140
|
+
if (!evidence?.gates) {
|
|
60141
|
+
return entries;
|
|
60142
|
+
}
|
|
60143
|
+
const merged = [...entries];
|
|
60144
|
+
for (const gate of Object.keys(evidence.gates).sort()) {
|
|
60145
|
+
const type = GATE_EVIDENCE_TYPE_BY_GATE[gate] ?? "approval";
|
|
60146
|
+
if ((type === "review" || type === "test") && merged.some((entry2) => entry2.type === type)) {
|
|
60147
|
+
continue;
|
|
60148
|
+
}
|
|
60149
|
+
const entry = gateEvidenceToEntry(taskId, gate, type, evidence);
|
|
60150
|
+
if (entry) {
|
|
60151
|
+
merged.push(entry);
|
|
60152
|
+
}
|
|
60153
|
+
}
|
|
60154
|
+
return merged;
|
|
60155
|
+
}
|
|
60156
|
+
var GATE_EVIDENCE_TYPE_BY_GATE;
|
|
60157
|
+
var init_gate_bridge = __esm(() => {
|
|
60158
|
+
init_gate_evidence();
|
|
60159
|
+
GATE_EVIDENCE_TYPE_BY_GATE = {
|
|
60160
|
+
reviewer: "review",
|
|
60161
|
+
test_engineer: "test"
|
|
60162
|
+
};
|
|
60163
|
+
});
|
|
60164
|
+
|
|
59890
60165
|
// src/services/version-check.ts
|
|
59891
60166
|
import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
59892
60167
|
import { homedir as homedir5 } from "node:os";
|
|
@@ -60034,7 +60309,21 @@ async function checkEvidenceCompleteness(directory, plan) {
|
|
|
60034
60309
|
}
|
|
60035
60310
|
if (completedTaskIds.length > 0) {
|
|
60036
60311
|
const evidenceTaskIds = new Set(await listEvidenceTaskIds(directory));
|
|
60037
|
-
const missingEvidence =
|
|
60312
|
+
const missingEvidence = [];
|
|
60313
|
+
for (const id of completedTaskIds) {
|
|
60314
|
+
const gateStatus = await getDurableGateEvidenceStatusForTask(directory, id);
|
|
60315
|
+
if (gateStatus.isComplete) {
|
|
60316
|
+
continue;
|
|
60317
|
+
}
|
|
60318
|
+
if (gateStatus.evidenceExists && gateStatus.missingGates.length > 0) {
|
|
60319
|
+
missingEvidence.push(id);
|
|
60320
|
+
continue;
|
|
60321
|
+
}
|
|
60322
|
+
if (evidenceTaskIds.has(id)) {
|
|
60323
|
+
continue;
|
|
60324
|
+
}
|
|
60325
|
+
missingEvidence.push(id);
|
|
60326
|
+
}
|
|
60038
60327
|
if (missingEvidence.length === 0) {
|
|
60039
60328
|
return {
|
|
60040
60329
|
name: "Evidence",
|
|
@@ -60789,6 +61078,7 @@ var init_diagnose_service = __esm(() => {
|
|
|
60789
61078
|
init_package();
|
|
60790
61079
|
init_cache_paths();
|
|
60791
61080
|
init_loader();
|
|
61081
|
+
init_gate_bridge();
|
|
60792
61082
|
init_manager2();
|
|
60793
61083
|
init_utils2();
|
|
60794
61084
|
init_manager();
|
|
@@ -63355,8 +63645,7 @@ function getTaskStatus(task, bundle) {
|
|
|
63355
63645
|
}
|
|
63356
63646
|
return "pending";
|
|
63357
63647
|
}
|
|
63358
|
-
function
|
|
63359
|
-
const entries = _internals20.normalizeBundleEntries(bundle);
|
|
63648
|
+
function evidenceCompleteFromEntries(entries) {
|
|
63360
63649
|
if (entries.length === 0) {
|
|
63361
63650
|
return {
|
|
63362
63651
|
isComplete: false,
|
|
@@ -63375,6 +63664,9 @@ function isEvidenceComplete(bundle) {
|
|
|
63375
63664
|
missingEvidence: missing
|
|
63376
63665
|
};
|
|
63377
63666
|
}
|
|
63667
|
+
function isEvidenceComplete(bundle) {
|
|
63668
|
+
return evidenceCompleteFromEntries(_internals20.normalizeBundleEntries(bundle));
|
|
63669
|
+
}
|
|
63378
63670
|
function getTaskBlockers(task, summary, status) {
|
|
63379
63671
|
const blockers = [];
|
|
63380
63672
|
if (task?.blocked_reason) {
|
|
@@ -63391,11 +63683,19 @@ function getTaskBlockers(task, summary, status) {
|
|
|
63391
63683
|
async function buildTaskSummary(directory, task, taskId) {
|
|
63392
63684
|
const result = await loadEvidence(directory, taskId);
|
|
63393
63685
|
const bundle = result.status === "found" ? result.bundle : null;
|
|
63686
|
+
const gateEvidence = await readDurableGateEvidence(directory, taskId);
|
|
63394
63687
|
const phase = task?.phase ?? 0;
|
|
63395
63688
|
const status = _internals20.getTaskStatus(task, bundle);
|
|
63396
|
-
const
|
|
63689
|
+
const entries = mergeDurableGateEntriesFromEvidence(taskId, _internals20.normalizeBundleEntries(bundle), gateEvidence);
|
|
63690
|
+
let evidenceCheck = _internals20.evidenceCompleteFromEntries(entries);
|
|
63691
|
+
if (gateEvidence) {
|
|
63692
|
+
const gateStatus = getDurableGateEvidenceStatus(gateEvidence);
|
|
63693
|
+
evidenceCheck = gateStatus.isComplete ? { isComplete: true, missingEvidence: [] } : {
|
|
63694
|
+
isComplete: false,
|
|
63695
|
+
missingEvidence: gateStatus.missingGates.map((gate) => `gate:${gate}`)
|
|
63696
|
+
};
|
|
63697
|
+
}
|
|
63397
63698
|
const blockers = _internals20.getTaskBlockers(task, evidenceCheck, status);
|
|
63398
|
-
const entries = _internals20.normalizeBundleEntries(bundle);
|
|
63399
63699
|
const hasReview = entries.some((e) => e.type === "review");
|
|
63400
63700
|
const hasTest = entries.some((e) => e.type === "test");
|
|
63401
63701
|
const hasApproval = entries.some((e) => e.type === "approval");
|
|
@@ -63573,6 +63873,7 @@ function isAutoSummaryEnabled(automationConfig) {
|
|
|
63573
63873
|
}
|
|
63574
63874
|
var VALID_EVIDENCE_TYPES2, REQUIRED_EVIDENCE_TYPES, EVIDENCE_SUMMARY_VERSION = "1.0.0", _internals20;
|
|
63575
63875
|
var init_evidence_summary_service = __esm(() => {
|
|
63876
|
+
init_gate_bridge();
|
|
63576
63877
|
init_manager2();
|
|
63577
63878
|
init_manager();
|
|
63578
63879
|
init_utils();
|
|
@@ -63590,6 +63891,7 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
63590
63891
|
isAutoSummaryEnabled,
|
|
63591
63892
|
normalizeBundleEntries,
|
|
63592
63893
|
getTaskStatus,
|
|
63894
|
+
evidenceCompleteFromEntries,
|
|
63593
63895
|
isEvidenceComplete,
|
|
63594
63896
|
getTaskBlockers,
|
|
63595
63897
|
buildTaskSummary,
|
|
@@ -71200,7 +71502,22 @@ async function runEvidenceCheck(dir) {
|
|
|
71200
71502
|
};
|
|
71201
71503
|
}
|
|
71202
71504
|
const evidenceTaskIds = new Set(await listEvidenceTaskIds(dir));
|
|
71203
|
-
const missingEvidence =
|
|
71505
|
+
const missingEvidence = [];
|
|
71506
|
+
for (const id of completedTaskIds) {
|
|
71507
|
+
const gateStatus = await getDurableGateEvidenceStatusForTask(dir, id);
|
|
71508
|
+
if (gateStatus.isComplete) {
|
|
71509
|
+
continue;
|
|
71510
|
+
}
|
|
71511
|
+
if (gateStatus.evidenceExists && gateStatus.missingGates.length > 0) {
|
|
71512
|
+
missingEvidence.push(id);
|
|
71513
|
+
continue;
|
|
71514
|
+
}
|
|
71515
|
+
if (evidenceTaskIds.has(id)) {
|
|
71516
|
+
continue;
|
|
71517
|
+
}
|
|
71518
|
+
missingEvidence.push(id);
|
|
71519
|
+
}
|
|
71520
|
+
const completedWithEvidence = completedTaskIds.length - missingEvidence.length;
|
|
71204
71521
|
if (missingEvidence.length > 0) {
|
|
71205
71522
|
return {
|
|
71206
71523
|
type: "evidence",
|
|
@@ -71208,7 +71525,7 @@ async function runEvidenceCheck(dir) {
|
|
|
71208
71525
|
message: `${missingEvidence.length} completed task(s) missing evidence`,
|
|
71209
71526
|
details: {
|
|
71210
71527
|
totalCompleted: completedTaskIds.length,
|
|
71211
|
-
totalWithEvidence:
|
|
71528
|
+
totalWithEvidence: completedWithEvidence,
|
|
71212
71529
|
missingTasks: missingEvidence.slice(0, 10),
|
|
71213
71530
|
missingCount: missingEvidence.length
|
|
71214
71531
|
},
|
|
@@ -71221,7 +71538,7 @@ async function runEvidenceCheck(dir) {
|
|
|
71221
71538
|
message: `All ${completedTaskIds.length} completed tasks have evidence`,
|
|
71222
71539
|
details: {
|
|
71223
71540
|
totalCompleted: completedTaskIds.length,
|
|
71224
|
-
totalWithEvidence:
|
|
71541
|
+
totalWithEvidence: completedWithEvidence
|
|
71225
71542
|
},
|
|
71226
71543
|
durationMs: Date.now() - startTime
|
|
71227
71544
|
};
|
|
@@ -71452,6 +71769,7 @@ async function handlePreflightCommand(directory, _args) {
|
|
|
71452
71769
|
}
|
|
71453
71770
|
var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG, _internals34;
|
|
71454
71771
|
var init_preflight_service = __esm(() => {
|
|
71772
|
+
init_gate_bridge();
|
|
71455
71773
|
init_manager2();
|
|
71456
71774
|
init_manager();
|
|
71457
71775
|
init_lint();
|
|
@@ -76397,121 +76715,14 @@ Do NOT share other agents' responses at this stage.
|
|
|
76397
76715
|
### MODE: DEEP_DIVE
|
|
76398
76716
|
Activates when: architect receives \`[MODE: DEEP_DIVE profile=X max_explorers=N output=X update_main=X allow_dirty=X] <scope>\` signal from the deep-dive command handler.
|
|
76399
76717
|
|
|
76400
|
-
Purpose:
|
|
76401
|
-
|
|
76402
|
-
|
|
76403
|
-
|
|
76404
|
-
|
|
76405
|
-
- \`profile\`: one of standard | security | ux | architecture | full (default: standard)
|
|
76406
|
-
- \`max_explorers\`: integer 1..8 (default: 6, or 8 for full profile)
|
|
76407
|
-
- \`output\`: markdown | json (default: markdown)
|
|
76408
|
-
- \`update_main\`: boolean (default: true) — whether to fetch/ff-only main before starting
|
|
76409
|
-
- \`allow_dirty\`: boolean (default: false) — whether to proceed with uncommitted changes
|
|
76410
|
-
|
|
76411
|
-
If the header is malformed or missing required fields, report the error and stop.
|
|
76412
|
-
|
|
76413
|
-
#### STEP 1 — REPO READINESS
|
|
76414
|
-
1. Check git working tree status. If dirty and \`allow_dirty\` is false, warn the user and ask whether to proceed. Do NOT proceed automatically.
|
|
76415
|
-
2. If \`update_main\` is true and tree is clean: check current branch. If not on \`main\`, report current branch to user and ASK FOR CONFIRMATION before switching. Only after explicit user approval: \`git fetch origin main && git checkout main && git merge --ff-only origin/main\`. If ff-only fails, warn the user and ask before proceeding.
|
|
76416
|
-
3. Record the current HEAD commit hash for the report.
|
|
76417
|
-
|
|
76418
|
-
#### STEP 2 — SCOPE RESOLUTION
|
|
76419
|
-
Use the following tools to map the audit scope:
|
|
76420
|
-
1. \`repo_map\` with action "build" to establish the code graph
|
|
76421
|
-
2. \`repo_map\` with action "localization" for the scope target
|
|
76422
|
-
3. \`symbols\` and \`batch_symbols\` on key files identified by localization
|
|
76423
|
-
4. \`imports\` to trace dependency boundaries
|
|
76424
|
-
5. \`doc_scan\` if documentation coverage is relevant
|
|
76425
|
-
6. \`knowledge_recall\` with query matching the scope domain
|
|
76426
|
-
|
|
76427
|
-
Produce a SCOPE MAP: list of files, modules, and interfaces within the audit boundary. Cap at 50 files total.
|
|
76428
|
-
|
|
76429
|
-
#### STEP 3 — EXPLORER MISSIONS (Parallel Waves)
|
|
76430
|
-
Dispatch explorer waves using parallel Task calls. Each wave contains up to \`max_explorers\` missions.
|
|
76431
|
-
|
|
76432
|
-
**File caps per mission:**
|
|
76433
|
-
- 8 files maximum per mission
|
|
76434
|
-
- ~3500 total lines across all files in a mission
|
|
76435
|
-
- Group files by import proximity (files that import each other go in the same mission)
|
|
76436
|
-
|
|
76437
|
-
**Profile-based lane selection — each profile activates specific lanes:**
|
|
76438
|
-
|
|
76439
|
-
| Lane | Template | standard | security | ux | architecture | full |
|
|
76440
|
-
|------|----------|----------|----------|----|-------------|------|
|
|
76441
|
-
| SCOPE_MAP | Map structure, exports, boundaries | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
76442
|
-
| WIRING_DATAFLOW | Trace data flow, API contracts, state propagation | ✓ | ✓ | | ✓ | ✓ |
|
|
76443
|
-
| RUNTIME_BEHAVIOR | Error handling, edge cases, lifecycle, async patterns | ✓ | | | ✓ | ✓ |
|
|
76444
|
-
| UX_FLOW | User-facing behavior, accessibility, responsiveness | | | ✓ | | ✓ |
|
|
76445
|
-
| SECURITY_TRUST | Auth boundaries, input validation, trust transitions | | ✓ | | | ✓ |
|
|
76446
|
-
| TEST_COVERAGE | Coverage gaps, flaky tests, missing assertions | ✓ | | | | ✓ |
|
|
76447
|
-
| PERFORMANCE_RELIABILITY | Resource leaks, N+1 queries, race conditions | | | | ✓ | ✓ |
|
|
76448
|
-
| DOCS_CONFIG_DEPLOYMENT | Config consistency, docs accuracy, deployment drift | | | | | ✓ |
|
|
76449
|
-
|
|
76450
|
-
Each explorer mission receives:
|
|
76451
|
-
- Lane template name and description
|
|
76452
|
-
- Assigned files (8 max, grouped by import proximity)
|
|
76453
|
-
- The scope map context from Step 2
|
|
76454
|
-
- Instruction: "You are performing a [LANE] audit. Report findings as candidate observations with severity (INFO/LOW/MEDIUM/HIGH/CRITICAL), location, and evidence."
|
|
76455
|
-
|
|
76456
|
-
Explorer missions are dispatched in parallel waves. Wait for ALL missions in a wave to complete before dispatching the next wave.
|
|
76457
|
-
|
|
76458
|
-
Explorers generate CANDIDATE FINDINGS only — they do NOT make verdicts. All findings are unverified until Step 5.
|
|
76459
|
-
|
|
76460
|
-
#### STEP 4 — NORMALIZE CANDIDATES
|
|
76461
|
-
1. Collect all candidate findings from all explorer missions.
|
|
76462
|
-
2. Deduplicate: merge findings that reference the same location and issue.
|
|
76463
|
-
3. Assign DD-C001 through DD-CNNN identifiers to unique findings.
|
|
76464
|
-
4. Cap at 10 findings per shard (see Step 5 for sharding).
|
|
76465
|
-
5. Sort by severity (CRITICAL → HIGH → MEDIUM → LOW → INFO).
|
|
76466
|
-
|
|
76467
|
-
#### STEP 5 — ALWAYS 2 PARALLEL REVIEWERS
|
|
76468
|
-
Split the verified candidates into 2 shards of ≤10 candidates each. Dispatch 2 parallel \`{{AGENT_PREFIX}}reviewer\` calls.
|
|
76469
|
-
|
|
76470
|
-
Each reviewer receives:
|
|
76471
|
-
- Their shard of candidates (up to 10)
|
|
76472
|
-
- The scope map context
|
|
76473
|
-
- The original scope description
|
|
76474
|
-
- Instruction: "Verify or reject each candidate finding. For each: verdict (VERIFIED / REJECTED / NEEDS_MORE_EVIDENCE), confidence (0-1), and brief reasoning."
|
|
76475
|
-
|
|
76476
|
-
Reviewers MUST NOT suggest fixes — they verify findings only.
|
|
76477
|
-
|
|
76478
|
-
#### STEP 5b — REVIEWER MERGE/DEDUP
|
|
76479
|
-
After both reviewers return, perform a lightweight sync pass:
|
|
76480
|
-
1. Cross-reference findings between reviewers — flag correlations
|
|
76481
|
-
2. Deduplicate any findings both reviewers verified independently
|
|
76482
|
-
3. For NEEDS_MORE_EVIDENCE findings: if the other reviewer verified a related finding, merge
|
|
76483
|
-
4. Produce a unified findings list with verified/rejected status
|
|
76484
|
-
|
|
76485
|
-
#### STEP 6 — CRITIC CHALLENGE (HIGH/CRITICAL only)
|
|
76486
|
-
For verified findings rated HIGH or CRITICAL, dispatch sequential critic passes:
|
|
76487
|
-
|
|
76488
|
-
**Pass 1 — False-positive / root-cause challenge:**
|
|
76489
|
-
- \`{{AGENT_PREFIX}}critic\` receives each HIGH/CRITICAL finding
|
|
76490
|
-
- Challenge: "Is this a false positive? Is the root cause correctly identified? Provide verdict: SURVIVES / DOWNGRADE / REJECT"
|
|
76491
|
-
- Only findings that SURVIVE proceed to Pass 2
|
|
76492
|
-
|
|
76493
|
-
**Pass 2 — Impact / severity challenge:**
|
|
76494
|
-
- \`{{AGENT_PREFIX}}critic\` receives surviving findings
|
|
76495
|
-
- Challenge: "Is the severity correctly rated? Could this be lower impact than claimed? Provide verdict: SURVIVES / DOWNGRADE / REJECT"
|
|
76496
|
-
- Final severity is the critic's assessed severity
|
|
76497
|
-
|
|
76498
|
-
CRITICAL: Do NOT challenge MEDIUM/LOW/INFO findings. Only HIGH and CRITICAL go through critic review.
|
|
76499
|
-
|
|
76500
|
-
#### STEP 7 — FINAL REPORT
|
|
76501
|
-
Assemble and present the audit report:
|
|
76502
|
-
|
|
76503
|
-
1. **Wiring Map**: Visual summary of the scope's module structure and data flow
|
|
76504
|
-
2. **Functionality Assessment**: High-level summary of what the scope does and how well
|
|
76505
|
-
3. **Verified Findings Table**: DD-ID, severity, location, description, evidence
|
|
76506
|
-
4. **Rejected Candidates**: Brief list with rejection reasons
|
|
76507
|
-
5. **Enhancements**: Non-blocking improvement suggestions
|
|
76508
|
-
6. **Recommended Implementation Phases**: If findings suggest follow-up work, outline phases
|
|
76509
|
-
7. **JSON Block** (when output=json): Structured machine-readable findings
|
|
76510
|
-
|
|
76511
|
-
IMPORTANT CONSTRAINTS for MODE: DEEP_DIVE:
|
|
76512
|
-
- Do NOT mutate source code under any circumstances
|
|
76718
|
+
Purpose: Read-only deep audit of the specified codebase scope using parallel explorer waves, always 2 parallel reviewers, and sequential critic challenge. This mode does NOT mutate source code, does NOT delegate to coder, and does NOT call declare_scope.
|
|
76719
|
+
|
|
76720
|
+
ACTION: Load skill \`file:.opencode/skills/deep-dive/SKILL.md\` immediately and follow its protocol.
|
|
76721
|
+
|
|
76722
|
+
HARD CONSTRAINTS (apply regardless of skill load success):
|
|
76513
76723
|
- Do NOT delegate to coder
|
|
76514
76724
|
- Do NOT call declare_scope
|
|
76725
|
+
- Do NOT mutate source code
|
|
76515
76726
|
- Do NOT create or modify any files outside .swarm/
|
|
76516
76727
|
- No final finding may appear in the report without reviewer verification
|
|
76517
76728
|
- Explorers generate candidate findings only — reviewers verify or reject
|
|
@@ -84599,7 +84810,7 @@ __export(exports_project_context, {
|
|
|
84599
84810
|
LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
|
|
84600
84811
|
});
|
|
84601
84812
|
import * as fs113 from "node:fs";
|
|
84602
|
-
import * as
|
|
84813
|
+
import * as path148 from "node:path";
|
|
84603
84814
|
function detectFileExists2(directory, pattern) {
|
|
84604
84815
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
84605
84816
|
try {
|
|
@@ -84611,7 +84822,7 @@ function detectFileExists2(directory, pattern) {
|
|
|
84611
84822
|
}
|
|
84612
84823
|
}
|
|
84613
84824
|
try {
|
|
84614
|
-
fs113.accessSync(
|
|
84825
|
+
fs113.accessSync(path148.join(directory, pattern));
|
|
84615
84826
|
return true;
|
|
84616
84827
|
} catch {
|
|
84617
84828
|
return false;
|
|
@@ -84620,7 +84831,7 @@ function detectFileExists2(directory, pattern) {
|
|
|
84620
84831
|
function selectTestCommandFromScriptsTest(backend, directory) {
|
|
84621
84832
|
let pkgRaw;
|
|
84622
84833
|
try {
|
|
84623
|
-
pkgRaw = fs113.readFileSync(
|
|
84834
|
+
pkgRaw = fs113.readFileSync(path148.join(directory, "package.json"), "utf-8");
|
|
84624
84835
|
} catch {
|
|
84625
84836
|
return null;
|
|
84626
84837
|
}
|
|
@@ -84729,7 +84940,7 @@ var init_project_context = __esm(() => {
|
|
|
84729
84940
|
init_package();
|
|
84730
84941
|
init_agents2();
|
|
84731
84942
|
init_critic();
|
|
84732
|
-
import * as
|
|
84943
|
+
import * as path149 from "node:path";
|
|
84733
84944
|
|
|
84734
84945
|
// src/background/index.ts
|
|
84735
84946
|
init_event_bus();
|
|
@@ -84992,6 +85203,10 @@ class PlanSyncWorker {
|
|
|
84992
85203
|
const planMtimeMs = Math.floor(planStats.mtimeMs);
|
|
84993
85204
|
const markerContent = fs37.readFileSync(markerPath, "utf8");
|
|
84994
85205
|
const marker = JSON.parse(markerContent);
|
|
85206
|
+
if (marker.in_progress === true) {
|
|
85207
|
+
log("[PlanSyncWorker] Skipping unauthorized-write check - plan write in progress");
|
|
85208
|
+
return;
|
|
85209
|
+
}
|
|
84995
85210
|
const markerTimestampMs = new Date(marker.timestamp).getTime();
|
|
84996
85211
|
if (planMtimeMs > markerTimestampMs + 5000) {
|
|
84997
85212
|
log("[PlanSyncWorker] WARNING: plan.json may have been written outside save_plan/savePlan - unauthorized direct write suspected", { planMtimeMs, markerTimestampMs });
|
|
@@ -97595,6 +97810,10 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
97595
97810
|
enabled: false,
|
|
97596
97811
|
provider: "local-jsonl",
|
|
97597
97812
|
storageDir: ".swarm/memory",
|
|
97813
|
+
sqlite: {
|
|
97814
|
+
path: ".swarm/memory/memory.db",
|
|
97815
|
+
busyTimeoutMs: 5000
|
|
97816
|
+
},
|
|
97598
97817
|
recall: {
|
|
97599
97818
|
defaultMaxItems: 8,
|
|
97600
97819
|
defaultTokenBudget: 1200,
|
|
@@ -97634,6 +97853,10 @@ function resolveMemoryConfig(input) {
|
|
|
97634
97853
|
return {
|
|
97635
97854
|
...DEFAULT_MEMORY_CONFIG,
|
|
97636
97855
|
...input ?? {},
|
|
97856
|
+
sqlite: {
|
|
97857
|
+
...DEFAULT_MEMORY_CONFIG.sqlite,
|
|
97858
|
+
...input?.sqlite ?? {}
|
|
97859
|
+
},
|
|
97637
97860
|
recall: {
|
|
97638
97861
|
...DEFAULT_MEMORY_CONFIG.recall,
|
|
97639
97862
|
...input?.recall ?? {},
|
|
@@ -97671,7 +97894,7 @@ class MemoryDisabledError extends Error {
|
|
|
97671
97894
|
// src/memory/gateway.ts
|
|
97672
97895
|
import { createHash as createHash9 } from "node:crypto";
|
|
97673
97896
|
import { existsSync as existsSync50, readFileSync as readFileSync39 } from "node:fs";
|
|
97674
|
-
import * as
|
|
97897
|
+
import * as path97 from "node:path";
|
|
97675
97898
|
|
|
97676
97899
|
// src/memory/local-jsonl-provider.ts
|
|
97677
97900
|
init_utils2();
|
|
@@ -98373,6 +98596,367 @@ function toRecallBundle(input) {
|
|
|
98373
98596
|
};
|
|
98374
98597
|
}
|
|
98375
98598
|
|
|
98599
|
+
// src/memory/sqlite-provider.ts
|
|
98600
|
+
init_utils2();
|
|
98601
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
98602
|
+
import { mkdirSync as mkdirSync24 } from "node:fs";
|
|
98603
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
98604
|
+
import * as path96 from "node:path";
|
|
98605
|
+
var _DatabaseCtor2 = null;
|
|
98606
|
+
function loadDatabaseCtor2() {
|
|
98607
|
+
if (_DatabaseCtor2)
|
|
98608
|
+
return _DatabaseCtor2;
|
|
98609
|
+
const req = createRequire3(import.meta.url);
|
|
98610
|
+
_DatabaseCtor2 = req("bun:sqlite").Database;
|
|
98611
|
+
return _DatabaseCtor2;
|
|
98612
|
+
}
|
|
98613
|
+
var MIGRATIONS2 = [
|
|
98614
|
+
{
|
|
98615
|
+
version: 1,
|
|
98616
|
+
name: "create_memory_provider_tables",
|
|
98617
|
+
sql: `
|
|
98618
|
+
CREATE TABLE IF NOT EXISTS memory_items (
|
|
98619
|
+
id TEXT PRIMARY KEY,
|
|
98620
|
+
scope_key TEXT NOT NULL,
|
|
98621
|
+
kind TEXT NOT NULL,
|
|
98622
|
+
updated_at TEXT NOT NULL,
|
|
98623
|
+
expires_at TEXT,
|
|
98624
|
+
superseded_by TEXT,
|
|
98625
|
+
deleted INTEGER NOT NULL DEFAULT 0,
|
|
98626
|
+
record_json TEXT NOT NULL
|
|
98627
|
+
);
|
|
98628
|
+
CREATE INDEX IF NOT EXISTS idx_memory_items_scope_kind
|
|
98629
|
+
ON memory_items(scope_key, kind);
|
|
98630
|
+
CREATE INDEX IF NOT EXISTS idx_memory_items_updated_at
|
|
98631
|
+
ON memory_items(updated_at);
|
|
98632
|
+
|
|
98633
|
+
CREATE TABLE IF NOT EXISTS memory_proposals (
|
|
98634
|
+
id TEXT PRIMARY KEY,
|
|
98635
|
+
status TEXT NOT NULL,
|
|
98636
|
+
created_at TEXT NOT NULL,
|
|
98637
|
+
proposal_json TEXT NOT NULL
|
|
98638
|
+
);
|
|
98639
|
+
CREATE INDEX IF NOT EXISTS idx_memory_proposals_status_created
|
|
98640
|
+
ON memory_proposals(status, created_at);
|
|
98641
|
+
|
|
98642
|
+
CREATE TABLE IF NOT EXISTS memory_events (
|
|
98643
|
+
id TEXT PRIMARY KEY,
|
|
98644
|
+
operation TEXT NOT NULL,
|
|
98645
|
+
target_id TEXT NOT NULL,
|
|
98646
|
+
reason TEXT,
|
|
98647
|
+
timestamp TEXT NOT NULL,
|
|
98648
|
+
event_json TEXT
|
|
98649
|
+
);
|
|
98650
|
+
|
|
98651
|
+
CREATE TABLE IF NOT EXISTS memory_recall_usage (
|
|
98652
|
+
id TEXT PRIMARY KEY,
|
|
98653
|
+
bundle_id TEXT NOT NULL,
|
|
98654
|
+
timestamp TEXT NOT NULL,
|
|
98655
|
+
usage_json TEXT NOT NULL
|
|
98656
|
+
);
|
|
98657
|
+
CREATE INDEX IF NOT EXISTS idx_memory_recall_usage_bundle
|
|
98658
|
+
ON memory_recall_usage(bundle_id);
|
|
98659
|
+
`
|
|
98660
|
+
}
|
|
98661
|
+
];
|
|
98662
|
+
|
|
98663
|
+
class SQLiteMemoryProvider {
|
|
98664
|
+
name = "sqlite";
|
|
98665
|
+
rootDirectory;
|
|
98666
|
+
config;
|
|
98667
|
+
initialized = false;
|
|
98668
|
+
db = null;
|
|
98669
|
+
memories = new Map;
|
|
98670
|
+
proposals = new Map;
|
|
98671
|
+
constructor(rootDirectory, config3 = {}) {
|
|
98672
|
+
this.rootDirectory = rootDirectory;
|
|
98673
|
+
this.config = {
|
|
98674
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
98675
|
+
...config3,
|
|
98676
|
+
sqlite: {
|
|
98677
|
+
...DEFAULT_MEMORY_CONFIG.sqlite,
|
|
98678
|
+
...config3.sqlite ?? {}
|
|
98679
|
+
},
|
|
98680
|
+
recall: {
|
|
98681
|
+
...DEFAULT_MEMORY_CONFIG.recall,
|
|
98682
|
+
...config3.recall ?? {},
|
|
98683
|
+
injection: {
|
|
98684
|
+
...DEFAULT_MEMORY_CONFIG.recall.injection,
|
|
98685
|
+
...config3.recall?.injection ?? {}
|
|
98686
|
+
}
|
|
98687
|
+
},
|
|
98688
|
+
writes: {
|
|
98689
|
+
...DEFAULT_MEMORY_CONFIG.writes,
|
|
98690
|
+
...config3.writes ?? {}
|
|
98691
|
+
},
|
|
98692
|
+
redaction: {
|
|
98693
|
+
...DEFAULT_MEMORY_CONFIG.redaction,
|
|
98694
|
+
...config3.redaction ?? {}
|
|
98695
|
+
}
|
|
98696
|
+
};
|
|
98697
|
+
}
|
|
98698
|
+
databasePath() {
|
|
98699
|
+
const relativePath = this.config.sqlite.path.replace(/^\.swarm[/\\]?/, "");
|
|
98700
|
+
return validateSwarmPath(this.rootDirectory, relativePath);
|
|
98701
|
+
}
|
|
98702
|
+
async initialize() {
|
|
98703
|
+
if (this.initialized)
|
|
98704
|
+
return;
|
|
98705
|
+
const dbPath = this.databasePath();
|
|
98706
|
+
mkdirSync24(path96.dirname(dbPath), { recursive: true });
|
|
98707
|
+
const Db = loadDatabaseCtor2();
|
|
98708
|
+
this.db = new Db(dbPath);
|
|
98709
|
+
this.db.run("PRAGMA journal_mode = WAL;");
|
|
98710
|
+
this.db.run("PRAGMA synchronous = NORMAL;");
|
|
98711
|
+
const busyTimeoutMs = Math.min(60000, Math.max(0, Math.trunc(this.config.sqlite.busyTimeoutMs)));
|
|
98712
|
+
this.db.run(`PRAGMA busy_timeout = ${busyTimeoutMs};`);
|
|
98713
|
+
this.db.run("PRAGMA foreign_keys = ON;");
|
|
98714
|
+
this.runMigrations();
|
|
98715
|
+
const memoryLoad = this.loadMemories();
|
|
98716
|
+
const proposalLoad = this.loadProposals();
|
|
98717
|
+
this.memories = new Map(memoryLoad.records.map((record3) => [record3.id, record3]));
|
|
98718
|
+
this.proposals = new Map(proposalLoad.records.map((proposal) => [proposal.id, proposal]));
|
|
98719
|
+
this.initialized = true;
|
|
98720
|
+
if (memoryLoad.invalidCount > 0) {
|
|
98721
|
+
await this.event("invalid_load", "memory_items", `${memoryLoad.invalidCount} invalid SQLite memory row(s) skipped`);
|
|
98722
|
+
}
|
|
98723
|
+
if (proposalLoad.invalidCount > 0) {
|
|
98724
|
+
await this.event("invalid_load", "memory_proposals", `${proposalLoad.invalidCount} invalid SQLite proposal row(s) skipped`);
|
|
98725
|
+
}
|
|
98726
|
+
}
|
|
98727
|
+
async upsert(record3) {
|
|
98728
|
+
await this.initialize();
|
|
98729
|
+
const existing = this.memories.get(record3.id);
|
|
98730
|
+
if (existing?.metadata.deleted === true) {
|
|
98731
|
+
throw new MemoryValidationError("memory is tombstoned and cannot be upserted");
|
|
98732
|
+
}
|
|
98733
|
+
const next = validateMemoryRecordRules({
|
|
98734
|
+
...record3,
|
|
98735
|
+
createdAt: existing?.createdAt ?? record3.createdAt
|
|
98736
|
+
}, { rejectDurableSecrets: this.config.redaction.rejectDurableSecrets });
|
|
98737
|
+
this.memories.set(next.id, next);
|
|
98738
|
+
this.writeMemory(next);
|
|
98739
|
+
await this.event("upsert", next.id);
|
|
98740
|
+
return next;
|
|
98741
|
+
}
|
|
98742
|
+
async get(id) {
|
|
98743
|
+
await this.initialize();
|
|
98744
|
+
return this.memories.get(id) ?? null;
|
|
98745
|
+
}
|
|
98746
|
+
async delete(id, reason) {
|
|
98747
|
+
await this.initialize();
|
|
98748
|
+
const existing = this.memories.get(id);
|
|
98749
|
+
if (!existing)
|
|
98750
|
+
return;
|
|
98751
|
+
if (this.config.hardDelete) {
|
|
98752
|
+
this.memories.delete(id);
|
|
98753
|
+
this.requireDb().run("DELETE FROM memory_items WHERE id = ?", [id]);
|
|
98754
|
+
} else {
|
|
98755
|
+
const tombstone = {
|
|
98756
|
+
...existing,
|
|
98757
|
+
updatedAt: new Date().toISOString(),
|
|
98758
|
+
metadata: { ...existing.metadata, deleted: true, deleteReason: reason }
|
|
98759
|
+
};
|
|
98760
|
+
this.memories.set(id, tombstone);
|
|
98761
|
+
this.writeMemory(tombstone);
|
|
98762
|
+
}
|
|
98763
|
+
await this.event("delete", id, reason);
|
|
98764
|
+
}
|
|
98765
|
+
async recall(request) {
|
|
98766
|
+
return (await this.recallWithDiagnostics(request)).items;
|
|
98767
|
+
}
|
|
98768
|
+
async recallWithDiagnostics(request) {
|
|
98769
|
+
await this.initialize();
|
|
98770
|
+
const records = await this.list({
|
|
98771
|
+
scopes: request.scopes,
|
|
98772
|
+
kinds: request.kinds,
|
|
98773
|
+
includeExpired: request.includeExpired
|
|
98774
|
+
});
|
|
98775
|
+
const result = scoreMemoryRecordsWithDiagnostics(records, request);
|
|
98776
|
+
return {
|
|
98777
|
+
items: result.items.slice(0, request.maxItems),
|
|
98778
|
+
diagnostics: {
|
|
98779
|
+
...result.diagnostics,
|
|
98780
|
+
returnedCount: Math.min(result.diagnostics.returnedCount, request.maxItems)
|
|
98781
|
+
}
|
|
98782
|
+
};
|
|
98783
|
+
}
|
|
98784
|
+
async recordRecallUsage(event) {
|
|
98785
|
+
await this.initialize();
|
|
98786
|
+
this.requireDb().run(`INSERT INTO memory_recall_usage (
|
|
98787
|
+
id,
|
|
98788
|
+
bundle_id,
|
|
98789
|
+
timestamp,
|
|
98790
|
+
usage_json
|
|
98791
|
+
) VALUES (?, ?, ?, ?)`, [randomUUID9(), event.bundleId, event.timestamp, JSON.stringify(event)]);
|
|
98792
|
+
await this.event("recall", event.bundleId, JSON.stringify(event));
|
|
98793
|
+
}
|
|
98794
|
+
async list(filter = {}) {
|
|
98795
|
+
await this.initialize();
|
|
98796
|
+
let records = Array.from(this.memories.values());
|
|
98797
|
+
if (filter.scopes && filter.scopes.length > 0) {
|
|
98798
|
+
records = records.filter((record3) => scopeAllowed(record3.scope, filter.scopes ?? []));
|
|
98799
|
+
}
|
|
98800
|
+
if (filter.kinds && filter.kinds.length > 0) {
|
|
98801
|
+
records = records.filter((record3) => filter.kinds?.includes(record3.kind));
|
|
98802
|
+
}
|
|
98803
|
+
if (!filter.includeExpired) {
|
|
98804
|
+
const now = Date.now();
|
|
98805
|
+
records = records.filter((record3) => {
|
|
98806
|
+
if (!record3.expiresAt)
|
|
98807
|
+
return true;
|
|
98808
|
+
const expires = Date.parse(record3.expiresAt);
|
|
98809
|
+
return !Number.isFinite(expires) || expires > now;
|
|
98810
|
+
});
|
|
98811
|
+
}
|
|
98812
|
+
records = records.filter((record3) => !record3.supersededBy && record3.metadata.deleted !== true);
|
|
98813
|
+
records.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
98814
|
+
return records.slice(0, filter.limit ?? records.length);
|
|
98815
|
+
}
|
|
98816
|
+
async createProposal(proposal) {
|
|
98817
|
+
await this.initialize();
|
|
98818
|
+
const next = validateMemoryProposal(proposal);
|
|
98819
|
+
if (next.proposedRecord) {
|
|
98820
|
+
validateMemoryRecordRules(next.proposedRecord, {
|
|
98821
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
98822
|
+
});
|
|
98823
|
+
}
|
|
98824
|
+
this.proposals.set(next.id, next);
|
|
98825
|
+
this.requireDb().run(`INSERT OR REPLACE INTO memory_proposals (
|
|
98826
|
+
id,
|
|
98827
|
+
status,
|
|
98828
|
+
created_at,
|
|
98829
|
+
proposal_json
|
|
98830
|
+
) VALUES (?, ?, ?, ?)`, [next.id, next.status, next.createdAt, JSON.stringify(next)]);
|
|
98831
|
+
await this.event("proposal", next.id);
|
|
98832
|
+
return next;
|
|
98833
|
+
}
|
|
98834
|
+
async listProposals(filter = {}) {
|
|
98835
|
+
await this.initialize();
|
|
98836
|
+
let proposals = Array.from(this.proposals.values());
|
|
98837
|
+
if (filter.status) {
|
|
98838
|
+
proposals = proposals.filter((proposal) => proposal.status === filter.status);
|
|
98839
|
+
}
|
|
98840
|
+
proposals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
98841
|
+
return proposals.slice(0, filter.limit ?? proposals.length);
|
|
98842
|
+
}
|
|
98843
|
+
close() {
|
|
98844
|
+
if (!this.db)
|
|
98845
|
+
return;
|
|
98846
|
+
this.db.close();
|
|
98847
|
+
this.db = null;
|
|
98848
|
+
this.initialized = false;
|
|
98849
|
+
}
|
|
98850
|
+
runMigrations() {
|
|
98851
|
+
const db = this.requireDb();
|
|
98852
|
+
db.run(`CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
98853
|
+
version INTEGER PRIMARY KEY,
|
|
98854
|
+
name TEXT NOT NULL,
|
|
98855
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
98856
|
+
)`);
|
|
98857
|
+
const row = db.query("SELECT MAX(version) as version FROM schema_migrations").get();
|
|
98858
|
+
const currentVersion = row?.version ?? 0;
|
|
98859
|
+
for (const migration of MIGRATIONS2) {
|
|
98860
|
+
if (migration.version <= currentVersion)
|
|
98861
|
+
continue;
|
|
98862
|
+
const apply = db.transaction(() => {
|
|
98863
|
+
for (const statement of splitSql(migration.sql)) {
|
|
98864
|
+
db.run(statement);
|
|
98865
|
+
}
|
|
98866
|
+
db.run("INSERT INTO schema_migrations (version, name) VALUES (?, ?)", [
|
|
98867
|
+
migration.version,
|
|
98868
|
+
migration.name
|
|
98869
|
+
]);
|
|
98870
|
+
this.insertEvent("migration", String(migration.version), migration.name);
|
|
98871
|
+
});
|
|
98872
|
+
apply();
|
|
98873
|
+
}
|
|
98874
|
+
}
|
|
98875
|
+
loadMemories() {
|
|
98876
|
+
const rows = this.requireDb().query("SELECT id, record_json FROM memory_items ORDER BY updated_at ASC").all();
|
|
98877
|
+
const records = [];
|
|
98878
|
+
let invalidCount = 0;
|
|
98879
|
+
for (const row of rows) {
|
|
98880
|
+
try {
|
|
98881
|
+
records.push(validateMemoryRecordRules(JSON.parse(row.record_json), {
|
|
98882
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
98883
|
+
}));
|
|
98884
|
+
} catch {
|
|
98885
|
+
invalidCount++;
|
|
98886
|
+
}
|
|
98887
|
+
}
|
|
98888
|
+
return { records, invalidCount };
|
|
98889
|
+
}
|
|
98890
|
+
loadProposals() {
|
|
98891
|
+
const rows = this.requireDb().query("SELECT id, proposal_json FROM memory_proposals ORDER BY created_at ASC").all();
|
|
98892
|
+
const records = [];
|
|
98893
|
+
let invalidCount = 0;
|
|
98894
|
+
for (const row of rows) {
|
|
98895
|
+
try {
|
|
98896
|
+
const proposal = validateMemoryProposal(JSON.parse(row.proposal_json));
|
|
98897
|
+
if (proposal.proposedRecord) {
|
|
98898
|
+
validateMemoryRecordRules(proposal.proposedRecord, {
|
|
98899
|
+
rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
|
|
98900
|
+
});
|
|
98901
|
+
}
|
|
98902
|
+
records.push(proposal);
|
|
98903
|
+
} catch {
|
|
98904
|
+
invalidCount++;
|
|
98905
|
+
}
|
|
98906
|
+
}
|
|
98907
|
+
return { records, invalidCount };
|
|
98908
|
+
}
|
|
98909
|
+
writeMemory(record3) {
|
|
98910
|
+
this.requireDb().run(`INSERT OR REPLACE INTO memory_items (
|
|
98911
|
+
id,
|
|
98912
|
+
scope_key,
|
|
98913
|
+
kind,
|
|
98914
|
+
updated_at,
|
|
98915
|
+
expires_at,
|
|
98916
|
+
superseded_by,
|
|
98917
|
+
deleted,
|
|
98918
|
+
record_json
|
|
98919
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
98920
|
+
record3.id,
|
|
98921
|
+
JSON.stringify(record3.scope),
|
|
98922
|
+
record3.kind,
|
|
98923
|
+
record3.updatedAt,
|
|
98924
|
+
record3.expiresAt ?? null,
|
|
98925
|
+
record3.supersededBy ?? null,
|
|
98926
|
+
record3.metadata.deleted === true ? 1 : 0,
|
|
98927
|
+
JSON.stringify(record3)
|
|
98928
|
+
]);
|
|
98929
|
+
}
|
|
98930
|
+
async event(operation, targetId, reason) {
|
|
98931
|
+
this.insertEvent(operation, targetId, reason);
|
|
98932
|
+
}
|
|
98933
|
+
insertEvent(operation, targetId, reason) {
|
|
98934
|
+
this.requireDb().run(`INSERT INTO memory_events (
|
|
98935
|
+
id,
|
|
98936
|
+
operation,
|
|
98937
|
+
target_id,
|
|
98938
|
+
reason,
|
|
98939
|
+
timestamp,
|
|
98940
|
+
event_json
|
|
98941
|
+
) VALUES (?, ?, ?, ?, ?, ?)`, [
|
|
98942
|
+
randomUUID9(),
|
|
98943
|
+
operation,
|
|
98944
|
+
targetId,
|
|
98945
|
+
reason ?? null,
|
|
98946
|
+
new Date().toISOString(),
|
|
98947
|
+
reason ? JSON.stringify({ reason }) : null
|
|
98948
|
+
]);
|
|
98949
|
+
}
|
|
98950
|
+
requireDb() {
|
|
98951
|
+
if (!this.db)
|
|
98952
|
+
throw new Error("SQLite memory provider is not initialized");
|
|
98953
|
+
return this.db;
|
|
98954
|
+
}
|
|
98955
|
+
}
|
|
98956
|
+
function splitSql(sql) {
|
|
98957
|
+
return sql.split(";").map((statement) => statement.trim()).filter(Boolean);
|
|
98958
|
+
}
|
|
98959
|
+
|
|
98376
98960
|
// src/memory/gateway.ts
|
|
98377
98961
|
class MemoryGateway {
|
|
98378
98962
|
context;
|
|
@@ -98382,16 +98966,19 @@ class MemoryGateway {
|
|
|
98382
98966
|
constructor(context, options = {}) {
|
|
98383
98967
|
this.context = context;
|
|
98384
98968
|
this.config = resolveMemoryConfig(options.config ?? DEFAULT_MEMORY_CONFIG);
|
|
98385
|
-
this.provider = options.provider ??
|
|
98969
|
+
this.provider = options.provider ?? createConfiguredMemoryProvider(context.directory, this.config);
|
|
98386
98970
|
this.now = options.now ?? (() => new Date);
|
|
98387
98971
|
}
|
|
98388
98972
|
isEnabled() {
|
|
98389
98973
|
return this.config.enabled;
|
|
98390
98974
|
}
|
|
98975
|
+
async dispose() {
|
|
98976
|
+
await this.provider.close?.();
|
|
98977
|
+
}
|
|
98391
98978
|
deriveAllowedScopes() {
|
|
98392
|
-
const resolvedRoot =
|
|
98393
|
-
const repoId = createStableId(readGitRemoteUrl(resolvedRoot) ??
|
|
98394
|
-
const workspaceId = createStableId(
|
|
98979
|
+
const resolvedRoot = path97.resolve(this.context.directory);
|
|
98980
|
+
const repoId = createStableId(readGitRemoteUrl(resolvedRoot) ?? path97.basename(resolvedRoot));
|
|
98981
|
+
const workspaceId = createStableId(path97.dirname(resolvedRoot));
|
|
98395
98982
|
const scopes = [
|
|
98396
98983
|
{ type: "workspace", workspaceId },
|
|
98397
98984
|
{
|
|
@@ -98591,6 +99178,12 @@ class MemoryGateway {
|
|
|
98591
99178
|
function createMemoryGateway(context, options = {}) {
|
|
98592
99179
|
return new MemoryGateway(context, options);
|
|
98593
99180
|
}
|
|
99181
|
+
function createConfiguredMemoryProvider(directory, config3) {
|
|
99182
|
+
if (config3.provider === "sqlite") {
|
|
99183
|
+
return new SQLiteMemoryProvider(directory, config3);
|
|
99184
|
+
}
|
|
99185
|
+
return new LocalJsonlMemoryProvider(directory, config3);
|
|
99186
|
+
}
|
|
98594
99187
|
function sourceFromEvidence(evidenceRefs, context) {
|
|
98595
99188
|
const first = evidenceRefs[0];
|
|
98596
99189
|
if (!first) {
|
|
@@ -98612,7 +99205,7 @@ var gitRemoteUrlCache = new Map;
|
|
|
98612
99205
|
function readGitRemoteUrl(directory) {
|
|
98613
99206
|
if (gitRemoteUrlCache.has(directory))
|
|
98614
99207
|
return gitRemoteUrlCache.get(directory);
|
|
98615
|
-
const gitConfigPath =
|
|
99208
|
+
const gitConfigPath = path97.join(directory, ".git", "config");
|
|
98616
99209
|
if (!existsSync50(gitConfigPath)) {
|
|
98617
99210
|
gitRemoteUrlCache.set(directory, undefined);
|
|
98618
99211
|
return;
|
|
@@ -98660,7 +99253,7 @@ function scopeKey(scope) {
|
|
|
98660
99253
|
workspaceId: scope.workspaceId,
|
|
98661
99254
|
projectId: scope.projectId,
|
|
98662
99255
|
repoId: scope.repoId,
|
|
98663
|
-
repoRoot: scope.repoRoot ?
|
|
99256
|
+
repoRoot: scope.repoRoot ? path97.resolve(scope.repoRoot) : undefined,
|
|
98664
99257
|
runId: scope.runId,
|
|
98665
99258
|
agentId: scope.agentId
|
|
98666
99259
|
});
|
|
@@ -98907,12 +99500,12 @@ function buildScopesFromInput(input) {
|
|
|
98907
99500
|
// src/memory/run-log.ts
|
|
98908
99501
|
init_utils2();
|
|
98909
99502
|
import { appendFile as appendFile12, mkdir as mkdir19 } from "node:fs/promises";
|
|
98910
|
-
import * as
|
|
99503
|
+
import * as path98 from "node:path";
|
|
98911
99504
|
async function appendMemoryRunLog(directory, runId, event) {
|
|
98912
99505
|
const safeRunId = sanitizeRunId(runId);
|
|
98913
|
-
const relativePath =
|
|
99506
|
+
const relativePath = path98.join("runs", safeRunId, "memory.jsonl");
|
|
98914
99507
|
const filePath = validateSwarmPath(directory, relativePath);
|
|
98915
|
-
await mkdir19(
|
|
99508
|
+
await mkdir19(path98.dirname(filePath), { recursive: true });
|
|
98916
99509
|
await appendFile12(filePath, `${JSON.stringify({
|
|
98917
99510
|
...event,
|
|
98918
99511
|
runId: safeRunId,
|
|
@@ -99690,16 +100283,16 @@ init_telemetry();
|
|
|
99690
100283
|
|
|
99691
100284
|
// src/prm/replay.ts
|
|
99692
100285
|
import { promises as fs68 } from "node:fs";
|
|
99693
|
-
import
|
|
100286
|
+
import path99 from "node:path";
|
|
99694
100287
|
function isPathSafe2(targetPath, basePath) {
|
|
99695
|
-
const resolvedTarget =
|
|
99696
|
-
const resolvedBase =
|
|
99697
|
-
const rel =
|
|
99698
|
-
return !rel.startsWith("..") && !
|
|
100288
|
+
const resolvedTarget = path99.resolve(targetPath);
|
|
100289
|
+
const resolvedBase = path99.resolve(basePath);
|
|
100290
|
+
const rel = path99.relative(resolvedBase, resolvedTarget);
|
|
100291
|
+
return !rel.startsWith("..") && !path99.isAbsolute(rel);
|
|
99699
100292
|
}
|
|
99700
100293
|
function isWithinReplaysDir(targetPath) {
|
|
99701
|
-
const resolved =
|
|
99702
|
-
const parts2 = resolved.split(
|
|
100294
|
+
const resolved = path99.resolve(targetPath);
|
|
100295
|
+
const parts2 = resolved.split(path99.sep);
|
|
99703
100296
|
for (let i2 = 0;i2 < parts2.length - 1; i2++) {
|
|
99704
100297
|
if (parts2[i2] === ".swarm" && parts2[i2 + 1] === "replays") {
|
|
99705
100298
|
return true;
|
|
@@ -99712,10 +100305,10 @@ function sanitizeFilename(input) {
|
|
|
99712
100305
|
}
|
|
99713
100306
|
async function startReplayRecording(sessionID, directory) {
|
|
99714
100307
|
try {
|
|
99715
|
-
const replayDir =
|
|
100308
|
+
const replayDir = path99.join(directory, ".swarm", "replays");
|
|
99716
100309
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
99717
100310
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
99718
|
-
const filepath =
|
|
100311
|
+
const filepath = path99.join(replayDir, filename);
|
|
99719
100312
|
if (!isPathSafe2(filepath, replayDir)) {
|
|
99720
100313
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
99721
100314
|
return null;
|
|
@@ -100096,7 +100689,7 @@ init_telemetry();
|
|
|
100096
100689
|
init_dist();
|
|
100097
100690
|
init_create_tool();
|
|
100098
100691
|
import * as fs69 from "node:fs";
|
|
100099
|
-
import * as
|
|
100692
|
+
import * as path100 from "node:path";
|
|
100100
100693
|
init_path_security();
|
|
100101
100694
|
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
100102
100695
|
function containsWindowsAttacks2(str) {
|
|
@@ -100113,14 +100706,14 @@ function containsWindowsAttacks2(str) {
|
|
|
100113
100706
|
}
|
|
100114
100707
|
function isPathInWorkspace2(filePath, workspace) {
|
|
100115
100708
|
try {
|
|
100116
|
-
const resolvedPath =
|
|
100709
|
+
const resolvedPath = path100.resolve(workspace, filePath);
|
|
100117
100710
|
if (!fs69.existsSync(resolvedPath)) {
|
|
100118
100711
|
return true;
|
|
100119
100712
|
}
|
|
100120
100713
|
const realWorkspace = fs69.realpathSync(workspace);
|
|
100121
100714
|
const realResolvedPath = fs69.realpathSync(resolvedPath);
|
|
100122
|
-
const relativePath =
|
|
100123
|
-
if (relativePath.startsWith("..") ||
|
|
100715
|
+
const relativePath = path100.relative(realWorkspace, realResolvedPath);
|
|
100716
|
+
if (relativePath.startsWith("..") || path100.isAbsolute(relativePath)) {
|
|
100124
100717
|
return false;
|
|
100125
100718
|
}
|
|
100126
100719
|
return true;
|
|
@@ -100129,7 +100722,7 @@ function isPathInWorkspace2(filePath, workspace) {
|
|
|
100129
100722
|
}
|
|
100130
100723
|
}
|
|
100131
100724
|
function processFile2(file3, cwd, exportedOnly) {
|
|
100132
|
-
const ext =
|
|
100725
|
+
const ext = path100.extname(file3);
|
|
100133
100726
|
if (containsControlChars(file3)) {
|
|
100134
100727
|
return {
|
|
100135
100728
|
file: file3,
|
|
@@ -100162,7 +100755,7 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
100162
100755
|
errorType: "path-outside-workspace"
|
|
100163
100756
|
};
|
|
100164
100757
|
}
|
|
100165
|
-
const fullPath =
|
|
100758
|
+
const fullPath = path100.join(cwd, file3);
|
|
100166
100759
|
if (!fs69.existsSync(fullPath)) {
|
|
100167
100760
|
return {
|
|
100168
100761
|
file: file3,
|
|
@@ -100454,15 +101047,15 @@ init_task_id();
|
|
|
100454
101047
|
init_create_tool();
|
|
100455
101048
|
init_resolve_working_directory();
|
|
100456
101049
|
import * as fs70 from "node:fs";
|
|
100457
|
-
import * as
|
|
101050
|
+
import * as path101 from "node:path";
|
|
100458
101051
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
100459
101052
|
function isValidTaskId3(taskId) {
|
|
100460
101053
|
return isStrictTaskId(taskId);
|
|
100461
101054
|
}
|
|
100462
101055
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
100463
|
-
const normalizedWorkspace =
|
|
100464
|
-
const swarmPath =
|
|
100465
|
-
const normalizedPath =
|
|
101056
|
+
const normalizedWorkspace = path101.resolve(workspaceRoot);
|
|
101057
|
+
const swarmPath = path101.join(normalizedWorkspace, ".swarm", "evidence");
|
|
101058
|
+
const normalizedPath = path101.resolve(filePath);
|
|
100466
101059
|
return normalizedPath.startsWith(swarmPath);
|
|
100467
101060
|
}
|
|
100468
101061
|
function readEvidenceFile(evidencePath) {
|
|
@@ -100543,7 +101136,7 @@ var check_gate_status = createSwarmTool({
|
|
|
100543
101136
|
};
|
|
100544
101137
|
return JSON.stringify(errorResult, null, 2);
|
|
100545
101138
|
}
|
|
100546
|
-
const evidencePath =
|
|
101139
|
+
const evidencePath = path101.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
100547
101140
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
100548
101141
|
const errorResult = {
|
|
100549
101142
|
taskId: taskIdInput,
|
|
@@ -100640,7 +101233,7 @@ init_state();
|
|
|
100640
101233
|
init_create_tool();
|
|
100641
101234
|
init_resolve_working_directory();
|
|
100642
101235
|
import * as fs71 from "node:fs";
|
|
100643
|
-
import * as
|
|
101236
|
+
import * as path102 from "node:path";
|
|
100644
101237
|
function extractMatches(regex, text) {
|
|
100645
101238
|
return Array.from(text.matchAll(regex));
|
|
100646
101239
|
}
|
|
@@ -100792,10 +101385,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
100792
101385
|
let hasFileReadFailure = false;
|
|
100793
101386
|
for (const filePath of fileTargets) {
|
|
100794
101387
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
100795
|
-
const resolvedPath =
|
|
100796
|
-
const projectRoot =
|
|
100797
|
-
const relative21 =
|
|
100798
|
-
const withinProject = relative21 === "" || !relative21.startsWith("..") && !
|
|
101388
|
+
const resolvedPath = path102.resolve(directory, normalizedPath);
|
|
101389
|
+
const projectRoot = path102.resolve(directory);
|
|
101390
|
+
const relative21 = path102.relative(projectRoot, resolvedPath);
|
|
101391
|
+
const withinProject = relative21 === "" || !relative21.startsWith("..") && !path102.isAbsolute(relative21);
|
|
100799
101392
|
if (!withinProject) {
|
|
100800
101393
|
blockedTasks.push({
|
|
100801
101394
|
task_id: task.id,
|
|
@@ -100850,8 +101443,8 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
100850
101443
|
blockedTasks
|
|
100851
101444
|
};
|
|
100852
101445
|
try {
|
|
100853
|
-
const evidenceDir =
|
|
100854
|
-
const evidencePath =
|
|
101446
|
+
const evidenceDir = path102.join(directory, ".swarm", "evidence", `${phase}`);
|
|
101447
|
+
const evidencePath = path102.join(evidenceDir, "completion-verify.json");
|
|
100855
101448
|
fs71.mkdirSync(evidenceDir, { recursive: true });
|
|
100856
101449
|
const evidenceBundle = {
|
|
100857
101450
|
schema_version: "1.0.0",
|
|
@@ -100928,11 +101521,11 @@ var completion_verify = createSwarmTool({
|
|
|
100928
101521
|
// src/tools/complexity-hotspots.ts
|
|
100929
101522
|
init_zod();
|
|
100930
101523
|
import * as fs73 from "node:fs";
|
|
100931
|
-
import * as
|
|
101524
|
+
import * as path104 from "node:path";
|
|
100932
101525
|
|
|
100933
101526
|
// src/quality/metrics.ts
|
|
100934
101527
|
import * as fs72 from "node:fs";
|
|
100935
|
-
import * as
|
|
101528
|
+
import * as path103 from "node:path";
|
|
100936
101529
|
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
100937
101530
|
var MIN_DUPLICATION_LINES = 10;
|
|
100938
101531
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -100984,7 +101577,7 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
100984
101577
|
let totalComplexity = 0;
|
|
100985
101578
|
const analyzedFiles = [];
|
|
100986
101579
|
for (const file3 of files) {
|
|
100987
|
-
const fullPath =
|
|
101580
|
+
const fullPath = path103.isAbsolute(file3) ? file3 : path103.join(workingDir, file3);
|
|
100988
101581
|
if (!fs72.existsSync(fullPath)) {
|
|
100989
101582
|
continue;
|
|
100990
101583
|
}
|
|
@@ -101107,7 +101700,7 @@ function countGoExports(content) {
|
|
|
101107
101700
|
function getExportCountForFile(filePath) {
|
|
101108
101701
|
try {
|
|
101109
101702
|
const content = fs72.readFileSync(filePath, "utf-8");
|
|
101110
|
-
const ext =
|
|
101703
|
+
const ext = path103.extname(filePath).toLowerCase();
|
|
101111
101704
|
switch (ext) {
|
|
101112
101705
|
case ".ts":
|
|
101113
101706
|
case ".tsx":
|
|
@@ -101133,7 +101726,7 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
101133
101726
|
let totalExports = 0;
|
|
101134
101727
|
const analyzedFiles = [];
|
|
101135
101728
|
for (const file3 of files) {
|
|
101136
|
-
const fullPath =
|
|
101729
|
+
const fullPath = path103.isAbsolute(file3) ? file3 : path103.join(workingDir, file3);
|
|
101137
101730
|
if (!fs72.existsSync(fullPath)) {
|
|
101138
101731
|
continue;
|
|
101139
101732
|
}
|
|
@@ -101167,7 +101760,7 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
101167
101760
|
let duplicateLines = 0;
|
|
101168
101761
|
const analyzedFiles = [];
|
|
101169
101762
|
for (const file3 of files) {
|
|
101170
|
-
const fullPath =
|
|
101763
|
+
const fullPath = path103.isAbsolute(file3) ? file3 : path103.join(workingDir, file3);
|
|
101171
101764
|
if (!fs72.existsSync(fullPath)) {
|
|
101172
101765
|
continue;
|
|
101173
101766
|
}
|
|
@@ -101200,8 +101793,8 @@ function countCodeLines(content) {
|
|
|
101200
101793
|
return lines.length;
|
|
101201
101794
|
}
|
|
101202
101795
|
function isTestFile(filePath) {
|
|
101203
|
-
const basename15 =
|
|
101204
|
-
const _ext =
|
|
101796
|
+
const basename15 = path103.basename(filePath);
|
|
101797
|
+
const _ext = path103.extname(filePath).toLowerCase();
|
|
101205
101798
|
const testPatterns = [
|
|
101206
101799
|
".test.",
|
|
101207
101800
|
".spec.",
|
|
@@ -101282,8 +101875,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
101282
101875
|
}
|
|
101283
101876
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
101284
101877
|
}
|
|
101285
|
-
function matchesGlobSegment(
|
|
101286
|
-
const normalizedPath =
|
|
101878
|
+
function matchesGlobSegment(path104, glob) {
|
|
101879
|
+
const normalizedPath = path104.replace(/\\/g, "/");
|
|
101287
101880
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
101288
101881
|
if (normalizedPath.includes("//")) {
|
|
101289
101882
|
return false;
|
|
@@ -101314,8 +101907,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
101314
101907
|
function hasGlobstar(glob) {
|
|
101315
101908
|
return glob.includes("**");
|
|
101316
101909
|
}
|
|
101317
|
-
function globMatches(
|
|
101318
|
-
const normalizedPath =
|
|
101910
|
+
function globMatches(path104, glob) {
|
|
101911
|
+
const normalizedPath = path104.replace(/\\/g, "/");
|
|
101319
101912
|
if (!glob || glob === "") {
|
|
101320
101913
|
if (normalizedPath.includes("//")) {
|
|
101321
101914
|
return false;
|
|
@@ -101351,7 +101944,7 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
101351
101944
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
101352
101945
|
let testLines = 0;
|
|
101353
101946
|
let codeLines = 0;
|
|
101354
|
-
const srcDir =
|
|
101947
|
+
const srcDir = path103.join(workingDir, "src");
|
|
101355
101948
|
if (fs72.existsSync(srcDir)) {
|
|
101356
101949
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
101357
101950
|
codeLines += lines;
|
|
@@ -101359,14 +101952,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
101359
101952
|
}
|
|
101360
101953
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
101361
101954
|
for (const dir of possibleSrcDirs) {
|
|
101362
|
-
const dirPath =
|
|
101955
|
+
const dirPath = path103.join(workingDir, dir);
|
|
101363
101956
|
if (fs72.existsSync(dirPath)) {
|
|
101364
101957
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
101365
101958
|
codeLines += lines;
|
|
101366
101959
|
});
|
|
101367
101960
|
}
|
|
101368
101961
|
}
|
|
101369
|
-
const testsDir =
|
|
101962
|
+
const testsDir = path103.join(workingDir, "tests");
|
|
101370
101963
|
if (fs72.existsSync(testsDir)) {
|
|
101371
101964
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
101372
101965
|
testLines += lines;
|
|
@@ -101374,7 +101967,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
101374
101967
|
}
|
|
101375
101968
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
101376
101969
|
for (const dir of possibleTestDirs) {
|
|
101377
|
-
const dirPath =
|
|
101970
|
+
const dirPath = path103.join(workingDir, dir);
|
|
101378
101971
|
if (fs72.existsSync(dirPath) && dirPath !== testsDir) {
|
|
101379
101972
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
101380
101973
|
testLines += lines;
|
|
@@ -101389,7 +101982,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
101389
101982
|
try {
|
|
101390
101983
|
const entries = fs72.readdirSync(dirPath, { withFileTypes: true });
|
|
101391
101984
|
for (const entry of entries) {
|
|
101392
|
-
const fullPath =
|
|
101985
|
+
const fullPath = path103.join(dirPath, entry.name);
|
|
101393
101986
|
if (entry.isDirectory()) {
|
|
101394
101987
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
101395
101988
|
continue;
|
|
@@ -101397,7 +101990,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
101397
101990
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
101398
101991
|
} else if (entry.isFile()) {
|
|
101399
101992
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
101400
|
-
const ext =
|
|
101993
|
+
const ext = path103.extname(entry.name).toLowerCase();
|
|
101401
101994
|
const validExts = [
|
|
101402
101995
|
".ts",
|
|
101403
101996
|
".tsx",
|
|
@@ -101648,7 +102241,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
101648
102241
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
101649
102242
|
const filteredChurn = new Map;
|
|
101650
102243
|
for (const [file3, count] of churnMap) {
|
|
101651
|
-
const ext =
|
|
102244
|
+
const ext = path104.extname(file3).toLowerCase();
|
|
101652
102245
|
if (extSet.has(ext)) {
|
|
101653
102246
|
filteredChurn.set(file3, count);
|
|
101654
102247
|
}
|
|
@@ -101659,7 +102252,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
101659
102252
|
for (const [file3, churnCount] of filteredChurn) {
|
|
101660
102253
|
let fullPath = file3;
|
|
101661
102254
|
if (!fs73.existsSync(fullPath)) {
|
|
101662
|
-
fullPath =
|
|
102255
|
+
fullPath = path104.join(cwd, file3);
|
|
101663
102256
|
}
|
|
101664
102257
|
const complexity = getComplexityForFile2(fullPath);
|
|
101665
102258
|
if (complexity !== null) {
|
|
@@ -101827,7 +102420,7 @@ ${body2}`);
|
|
|
101827
102420
|
|
|
101828
102421
|
// src/council/council-evidence-writer.ts
|
|
101829
102422
|
init_task_file();
|
|
101830
|
-
import { appendFileSync as appendFileSync12, existsSync as existsSync55, mkdirSync as
|
|
102423
|
+
import { appendFileSync as appendFileSync12, existsSync as existsSync55, mkdirSync as mkdirSync26, readFileSync as readFileSync45 } from "node:fs";
|
|
101831
102424
|
import { join as join88 } from "node:path";
|
|
101832
102425
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
101833
102426
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -101866,7 +102459,7 @@ async function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
101866
102459
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
|
|
101867
102460
|
}
|
|
101868
102461
|
const dir = join88(workingDir, EVIDENCE_DIR2);
|
|
101869
|
-
|
|
102462
|
+
mkdirSync26(dir, { recursive: true });
|
|
101870
102463
|
const filePath = taskEvidencePath(workingDir, synthesis.taskId);
|
|
101871
102464
|
await _internals45.withTaskEvidenceLock(workingDir, synthesis.taskId, COUNCIL_AGENT_ID, async () => {
|
|
101872
102465
|
const existingRoot = Object.create(null);
|
|
@@ -101904,7 +102497,7 @@ async function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
101904
102497
|
});
|
|
101905
102498
|
try {
|
|
101906
102499
|
const councilDir = join88(workingDir, ".swarm", "council");
|
|
101907
|
-
|
|
102500
|
+
mkdirSync26(councilDir, { recursive: true });
|
|
101908
102501
|
const auditLine = JSON.stringify({
|
|
101909
102502
|
round: synthesis.roundNumber,
|
|
101910
102503
|
verdict: synthesis.overallVerdict,
|
|
@@ -102233,12 +102826,12 @@ function buildFinalCouncilFeedback(projectSummary, verdict, vetoedBy, requiredFi
|
|
|
102233
102826
|
}
|
|
102234
102827
|
|
|
102235
102828
|
// src/council/criteria-store.ts
|
|
102236
|
-
import { existsSync as existsSync56, mkdirSync as
|
|
102829
|
+
import { existsSync as existsSync56, mkdirSync as mkdirSync27, readFileSync as readFileSync46, writeFileSync as writeFileSync17 } from "node:fs";
|
|
102237
102830
|
import { join as join89 } from "node:path";
|
|
102238
102831
|
var COUNCIL_DIR = ".swarm/council";
|
|
102239
102832
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
102240
102833
|
const dir = join89(workingDir, COUNCIL_DIR);
|
|
102241
|
-
|
|
102834
|
+
mkdirSync27(dir, { recursive: true });
|
|
102242
102835
|
const payload = {
|
|
102243
102836
|
taskId,
|
|
102244
102837
|
criteria,
|
|
@@ -102400,7 +102993,7 @@ var submit_council_verdicts = createSwarmTool({
|
|
|
102400
102993
|
init_zod();
|
|
102401
102994
|
init_loader();
|
|
102402
102995
|
import * as fs74 from "node:fs";
|
|
102403
|
-
import * as
|
|
102996
|
+
import * as path105 from "node:path";
|
|
102404
102997
|
|
|
102405
102998
|
// src/council/general-council-advisory.ts
|
|
102406
102999
|
var ADVISORY_HEADER = "[general_council] (advisory; not blocking)";
|
|
@@ -102828,10 +103421,10 @@ var convene_general_council = createSwarmTool({
|
|
|
102828
103421
|
const round1 = input.round1Responses;
|
|
102829
103422
|
const round2 = input.round2Responses ?? [];
|
|
102830
103423
|
const result = synthesizeGeneralCouncil(input.question, input.mode, round1, round2);
|
|
102831
|
-
const evidenceDir =
|
|
103424
|
+
const evidenceDir = path105.join(workingDir, ".swarm", "council", "general");
|
|
102832
103425
|
const safeTimestamp = result.timestamp.replace(/[:.]/g, "-");
|
|
102833
103426
|
const evidenceFile = `${safeTimestamp}-${input.mode}.json`;
|
|
102834
|
-
const evidencePath =
|
|
103427
|
+
const evidencePath = path105.join(evidenceDir, evidenceFile);
|
|
102835
103428
|
try {
|
|
102836
103429
|
await fs74.promises.mkdir(evidenceDir, { recursive: true });
|
|
102837
103430
|
await fs74.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
|
|
@@ -103076,7 +103669,7 @@ init_state();
|
|
|
103076
103669
|
init_task_id();
|
|
103077
103670
|
init_create_tool();
|
|
103078
103671
|
import * as fs75 from "node:fs";
|
|
103079
|
-
import * as
|
|
103672
|
+
import * as path106 from "node:path";
|
|
103080
103673
|
function validateTaskIdFormat2(taskId) {
|
|
103081
103674
|
return validateTaskIdFormat(taskId);
|
|
103082
103675
|
}
|
|
@@ -103150,8 +103743,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
103150
103743
|
};
|
|
103151
103744
|
}
|
|
103152
103745
|
}
|
|
103153
|
-
normalizedDir =
|
|
103154
|
-
const pathParts = normalizedDir.split(
|
|
103746
|
+
normalizedDir = path106.normalize(args2.working_directory);
|
|
103747
|
+
const pathParts = normalizedDir.split(path106.sep);
|
|
103155
103748
|
if (pathParts.includes("..")) {
|
|
103156
103749
|
return {
|
|
103157
103750
|
success: false,
|
|
@@ -103161,10 +103754,10 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
103161
103754
|
]
|
|
103162
103755
|
};
|
|
103163
103756
|
}
|
|
103164
|
-
const resolvedDir =
|
|
103757
|
+
const resolvedDir = path106.resolve(normalizedDir);
|
|
103165
103758
|
try {
|
|
103166
103759
|
const realPath = fs75.realpathSync(resolvedDir);
|
|
103167
|
-
const planPath2 =
|
|
103760
|
+
const planPath2 = path106.join(realPath, ".swarm", "plan.json");
|
|
103168
103761
|
if (!fs75.existsSync(planPath2)) {
|
|
103169
103762
|
return {
|
|
103170
103763
|
success: false,
|
|
@@ -103185,9 +103778,9 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
103185
103778
|
}
|
|
103186
103779
|
if (normalizedDir && fallbackDir) {
|
|
103187
103780
|
try {
|
|
103188
|
-
const canonicalWorkingDir = fs75.realpathSync(
|
|
103189
|
-
const canonicalProjectRoot = fs75.realpathSync(
|
|
103190
|
-
if (canonicalWorkingDir.startsWith(canonicalProjectRoot +
|
|
103781
|
+
const canonicalWorkingDir = fs75.realpathSync(path106.resolve(normalizedDir));
|
|
103782
|
+
const canonicalProjectRoot = fs75.realpathSync(path106.resolve(fallbackDir));
|
|
103783
|
+
if (canonicalWorkingDir.startsWith(canonicalProjectRoot + path106.sep)) {
|
|
103191
103784
|
return {
|
|
103192
103785
|
success: false,
|
|
103193
103786
|
message: `working_directory "${normalizedDir}" is a subdirectory of the project root. Use the project root "${fallbackDir}" instead.`,
|
|
@@ -103209,7 +103802,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
103209
103802
|
};
|
|
103210
103803
|
}
|
|
103211
103804
|
const directory = normalizedDir || fallbackDir;
|
|
103212
|
-
const planPath =
|
|
103805
|
+
const planPath = path106.resolve(directory, ".swarm", "plan.json");
|
|
103213
103806
|
if (!fs75.existsSync(planPath)) {
|
|
103214
103807
|
return {
|
|
103215
103808
|
success: false,
|
|
@@ -103249,8 +103842,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
103249
103842
|
const normalizeErrors = [];
|
|
103250
103843
|
const dir = directory;
|
|
103251
103844
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
103252
|
-
if (
|
|
103253
|
-
const relativePath =
|
|
103845
|
+
if (path106.isAbsolute(file3)) {
|
|
103846
|
+
const relativePath = path106.relative(dir, file3).replace(/\\/g, "/");
|
|
103254
103847
|
if (relativePath.startsWith("..")) {
|
|
103255
103848
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
103256
103849
|
return file3;
|
|
@@ -103311,7 +103904,7 @@ var declare_scope = createSwarmTool({
|
|
|
103311
103904
|
init_zod();
|
|
103312
103905
|
import * as child_process7 from "node:child_process";
|
|
103313
103906
|
import * as fs76 from "node:fs";
|
|
103314
|
-
import * as
|
|
103907
|
+
import * as path107 from "node:path";
|
|
103315
103908
|
init_create_tool();
|
|
103316
103909
|
var MAX_DIFF_LINES = 500;
|
|
103317
103910
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -103340,20 +103933,20 @@ function validateBase(base) {
|
|
|
103340
103933
|
function validatePaths(paths) {
|
|
103341
103934
|
if (!paths)
|
|
103342
103935
|
return null;
|
|
103343
|
-
for (const
|
|
103344
|
-
if (!
|
|
103936
|
+
for (const path108 of paths) {
|
|
103937
|
+
if (!path108 || path108.length === 0) {
|
|
103345
103938
|
return "empty path not allowed";
|
|
103346
103939
|
}
|
|
103347
|
-
if (
|
|
103940
|
+
if (path108.length > MAX_PATH_LENGTH) {
|
|
103348
103941
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
103349
103942
|
}
|
|
103350
|
-
if (SHELL_METACHARACTERS2.test(
|
|
103943
|
+
if (SHELL_METACHARACTERS2.test(path108)) {
|
|
103351
103944
|
return "path contains shell metacharacters";
|
|
103352
103945
|
}
|
|
103353
|
-
if (
|
|
103946
|
+
if (path108.startsWith("-")) {
|
|
103354
103947
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
103355
103948
|
}
|
|
103356
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
103949
|
+
if (CONTROL_CHAR_PATTERN2.test(path108)) {
|
|
103357
103950
|
return "path contains control characters";
|
|
103358
103951
|
}
|
|
103359
103952
|
}
|
|
@@ -103461,8 +104054,8 @@ var diff = createSwarmTool({
|
|
|
103461
104054
|
if (parts2.length >= 3) {
|
|
103462
104055
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
103463
104056
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
103464
|
-
const
|
|
103465
|
-
files.push({ path:
|
|
104057
|
+
const path108 = parts2[2];
|
|
104058
|
+
files.push({ path: path108, additions, deletions });
|
|
103466
104059
|
}
|
|
103467
104060
|
}
|
|
103468
104061
|
const contractChanges = [];
|
|
@@ -103502,7 +104095,7 @@ var diff = createSwarmTool({
|
|
|
103502
104095
|
} else if (base === "unstaged") {
|
|
103503
104096
|
const oldRef = `:${file3.path}`;
|
|
103504
104097
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
103505
|
-
newContent = fs76.readFileSync(
|
|
104098
|
+
newContent = fs76.readFileSync(path107.join(directory, file3.path), "utf-8");
|
|
103506
104099
|
} else {
|
|
103507
104100
|
const oldRef = `${base}:${file3.path}`;
|
|
103508
104101
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -103577,7 +104170,7 @@ var diff = createSwarmTool({
|
|
|
103577
104170
|
init_zod();
|
|
103578
104171
|
import * as child_process8 from "node:child_process";
|
|
103579
104172
|
import * as fs77 from "node:fs";
|
|
103580
|
-
import * as
|
|
104173
|
+
import * as path108 from "node:path";
|
|
103581
104174
|
init_create_tool();
|
|
103582
104175
|
init_resolve_working_directory();
|
|
103583
104176
|
var diff_summary = createSwarmTool({
|
|
@@ -103630,7 +104223,7 @@ var diff_summary = createSwarmTool({
|
|
|
103630
104223
|
}
|
|
103631
104224
|
try {
|
|
103632
104225
|
let oldContent;
|
|
103633
|
-
const newContent = fs77.readFileSync(
|
|
104226
|
+
const newContent = fs77.readFileSync(path108.join(workingDir, filePath), "utf-8");
|
|
103634
104227
|
if (fileExistsInHead) {
|
|
103635
104228
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
103636
104229
|
encoding: "utf-8",
|
|
@@ -103859,7 +104452,7 @@ init_zod();
|
|
|
103859
104452
|
init_create_tool();
|
|
103860
104453
|
init_path_security();
|
|
103861
104454
|
import * as fs78 from "node:fs";
|
|
103862
|
-
import * as
|
|
104455
|
+
import * as path109 from "node:path";
|
|
103863
104456
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
103864
104457
|
var MAX_EVIDENCE_FILES = 1000;
|
|
103865
104458
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -103886,9 +104479,9 @@ function validateRequiredTypes(input) {
|
|
|
103886
104479
|
return null;
|
|
103887
104480
|
}
|
|
103888
104481
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
103889
|
-
const normalizedCwd =
|
|
103890
|
-
const swarmPath =
|
|
103891
|
-
const normalizedPath =
|
|
104482
|
+
const normalizedCwd = path109.resolve(cwd);
|
|
104483
|
+
const swarmPath = path109.join(normalizedCwd, ".swarm");
|
|
104484
|
+
const normalizedPath = path109.resolve(filePath);
|
|
103892
104485
|
return normalizedPath.startsWith(swarmPath);
|
|
103893
104486
|
}
|
|
103894
104487
|
function parseCompletedTasks(planContent) {
|
|
@@ -103918,10 +104511,10 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
103918
104511
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
103919
104512
|
continue;
|
|
103920
104513
|
}
|
|
103921
|
-
const filePath =
|
|
104514
|
+
const filePath = path109.join(evidenceDir, filename);
|
|
103922
104515
|
try {
|
|
103923
|
-
const resolvedPath =
|
|
103924
|
-
const evidenceDirResolved =
|
|
104516
|
+
const resolvedPath = path109.resolve(filePath);
|
|
104517
|
+
const evidenceDirResolved = path109.resolve(evidenceDir);
|
|
103925
104518
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
103926
104519
|
continue;
|
|
103927
104520
|
}
|
|
@@ -104039,7 +104632,7 @@ var evidence_check = createSwarmTool({
|
|
|
104039
104632
|
return JSON.stringify(errorResult, null, 2);
|
|
104040
104633
|
}
|
|
104041
104634
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
104042
|
-
const planPath =
|
|
104635
|
+
const planPath = path109.join(cwd, PLAN_FILE);
|
|
104043
104636
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
104044
104637
|
const errorResult = {
|
|
104045
104638
|
error: "plan file path validation failed",
|
|
@@ -104071,7 +104664,7 @@ var evidence_check = createSwarmTool({
|
|
|
104071
104664
|
};
|
|
104072
104665
|
return JSON.stringify(result2, null, 2);
|
|
104073
104666
|
}
|
|
104074
|
-
const evidenceDir =
|
|
104667
|
+
const evidenceDir = path109.join(cwd, EVIDENCE_DIR3);
|
|
104075
104668
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
104076
104669
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
104077
104670
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -104089,7 +104682,7 @@ var evidence_check = createSwarmTool({
|
|
|
104089
104682
|
init_zod();
|
|
104090
104683
|
init_create_tool();
|
|
104091
104684
|
import * as fs79 from "node:fs";
|
|
104092
|
-
import * as
|
|
104685
|
+
import * as path110 from "node:path";
|
|
104093
104686
|
var EXT_MAP = {
|
|
104094
104687
|
python: ".py",
|
|
104095
104688
|
py: ".py",
|
|
@@ -104170,12 +104763,12 @@ var extract_code_blocks = createSwarmTool({
|
|
|
104170
104763
|
if (prefix) {
|
|
104171
104764
|
filename = `${prefix}_${filename}`;
|
|
104172
104765
|
}
|
|
104173
|
-
let filepath =
|
|
104174
|
-
const base =
|
|
104175
|
-
const ext =
|
|
104766
|
+
let filepath = path110.join(targetDir, filename);
|
|
104767
|
+
const base = path110.basename(filepath, path110.extname(filepath));
|
|
104768
|
+
const ext = path110.extname(filepath);
|
|
104176
104769
|
let counter = 1;
|
|
104177
104770
|
while (fs79.existsSync(filepath)) {
|
|
104178
|
-
filepath =
|
|
104771
|
+
filepath = path110.join(targetDir, `${base}_${counter}${ext}`);
|
|
104179
104772
|
counter++;
|
|
104180
104773
|
}
|
|
104181
104774
|
try {
|
|
@@ -104433,7 +105026,7 @@ init_zod();
|
|
|
104433
105026
|
init_create_tool();
|
|
104434
105027
|
init_path_security();
|
|
104435
105028
|
import * as fs80 from "node:fs";
|
|
104436
|
-
import * as
|
|
105029
|
+
import * as path111 from "node:path";
|
|
104437
105030
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
104438
105031
|
var MAX_SYMBOL_LENGTH = 256;
|
|
104439
105032
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -104481,7 +105074,7 @@ function validateSymbolInput(symbol3) {
|
|
|
104481
105074
|
return null;
|
|
104482
105075
|
}
|
|
104483
105076
|
function isBinaryFile2(filePath, buffer) {
|
|
104484
|
-
const ext =
|
|
105077
|
+
const ext = path111.extname(filePath).toLowerCase();
|
|
104485
105078
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
104486
105079
|
return false;
|
|
104487
105080
|
}
|
|
@@ -104505,15 +105098,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
104505
105098
|
const imports = [];
|
|
104506
105099
|
let _resolvedTarget;
|
|
104507
105100
|
try {
|
|
104508
|
-
_resolvedTarget =
|
|
105101
|
+
_resolvedTarget = path111.resolve(targetFile);
|
|
104509
105102
|
} catch {
|
|
104510
105103
|
_resolvedTarget = targetFile;
|
|
104511
105104
|
}
|
|
104512
|
-
const targetBasename =
|
|
105105
|
+
const targetBasename = path111.basename(targetFile, path111.extname(targetFile));
|
|
104513
105106
|
const targetWithExt = targetFile;
|
|
104514
105107
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
104515
|
-
const normalizedTargetWithExt =
|
|
104516
|
-
const normalizedTargetWithoutExt =
|
|
105108
|
+
const normalizedTargetWithExt = path111.normalize(targetWithExt).replace(/\\/g, "/");
|
|
105109
|
+
const normalizedTargetWithoutExt = path111.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
104517
105110
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
104518
105111
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
104519
105112
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -104536,9 +105129,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
104536
105129
|
}
|
|
104537
105130
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
104538
105131
|
let isMatch = false;
|
|
104539
|
-
const _targetDir =
|
|
104540
|
-
const targetExt =
|
|
104541
|
-
const targetBasenameNoExt =
|
|
105132
|
+
const _targetDir = path111.dirname(targetFile);
|
|
105133
|
+
const targetExt = path111.extname(targetFile);
|
|
105134
|
+
const targetBasenameNoExt = path111.basename(targetFile, targetExt);
|
|
104542
105135
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
104543
105136
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
104544
105137
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -104606,10 +105199,10 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
104606
105199
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
104607
105200
|
for (const entry of entries) {
|
|
104608
105201
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
104609
|
-
stats.skippedDirs.push(
|
|
105202
|
+
stats.skippedDirs.push(path111.join(dir, entry));
|
|
104610
105203
|
continue;
|
|
104611
105204
|
}
|
|
104612
|
-
const fullPath =
|
|
105205
|
+
const fullPath = path111.join(dir, entry);
|
|
104613
105206
|
let stat8;
|
|
104614
105207
|
try {
|
|
104615
105208
|
stat8 = fs80.statSync(fullPath);
|
|
@@ -104623,7 +105216,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
104623
105216
|
if (stat8.isDirectory()) {
|
|
104624
105217
|
findSourceFiles2(fullPath, files, stats);
|
|
104625
105218
|
} else if (stat8.isFile()) {
|
|
104626
|
-
const ext =
|
|
105219
|
+
const ext = path111.extname(fullPath).toLowerCase();
|
|
104627
105220
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
104628
105221
|
files.push(fullPath);
|
|
104629
105222
|
}
|
|
@@ -104680,7 +105273,7 @@ var imports = createSwarmTool({
|
|
|
104680
105273
|
return JSON.stringify(errorResult, null, 2);
|
|
104681
105274
|
}
|
|
104682
105275
|
try {
|
|
104683
|
-
const targetFile =
|
|
105276
|
+
const targetFile = path111.resolve(file3);
|
|
104684
105277
|
if (!fs80.existsSync(targetFile)) {
|
|
104685
105278
|
const errorResult = {
|
|
104686
105279
|
error: `target file not found: ${file3}`,
|
|
@@ -104702,7 +105295,7 @@ var imports = createSwarmTool({
|
|
|
104702
105295
|
};
|
|
104703
105296
|
return JSON.stringify(errorResult, null, 2);
|
|
104704
105297
|
}
|
|
104705
|
-
const baseDir =
|
|
105298
|
+
const baseDir = path111.dirname(targetFile);
|
|
104706
105299
|
const scanStats = {
|
|
104707
105300
|
skippedDirs: [],
|
|
104708
105301
|
skippedFiles: 0,
|
|
@@ -104787,7 +105380,7 @@ var imports = createSwarmTool({
|
|
|
104787
105380
|
});
|
|
104788
105381
|
// src/tools/knowledge-ack.ts
|
|
104789
105382
|
init_zod();
|
|
104790
|
-
import { randomUUID as
|
|
105383
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
104791
105384
|
init_state();
|
|
104792
105385
|
init_logger();
|
|
104793
105386
|
init_create_tool();
|
|
@@ -104820,7 +105413,7 @@ var knowledge_ack = createSwarmTool({
|
|
|
104820
105413
|
let sessionId = ctx?.sessionID;
|
|
104821
105414
|
if (!sessionId) {
|
|
104822
105415
|
warn("[knowledge-ack] No sessionID in tool context — dedup disabled for this acknowledgment");
|
|
104823
|
-
sessionId =
|
|
105416
|
+
sessionId = randomUUID10();
|
|
104824
105417
|
}
|
|
104825
105418
|
const dedupKey = buildAckDedupKey(sessionId, a.id, a.result);
|
|
104826
105419
|
if (swarmState.knowledgeAckDedup.has(dedupKey)) {
|
|
@@ -104850,7 +105443,7 @@ init_knowledge_store();
|
|
|
104850
105443
|
init_knowledge_validator();
|
|
104851
105444
|
init_manager();
|
|
104852
105445
|
init_create_tool();
|
|
104853
|
-
import { randomUUID as
|
|
105446
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
104854
105447
|
var VALID_CATEGORIES2 = [
|
|
104855
105448
|
"process",
|
|
104856
105449
|
"architecture",
|
|
@@ -104924,7 +105517,7 @@ var knowledge_add = createSwarmTool({
|
|
|
104924
105517
|
project_name = plan?.title ?? "";
|
|
104925
105518
|
} catch {}
|
|
104926
105519
|
const entry = {
|
|
104927
|
-
id:
|
|
105520
|
+
id: randomUUID11(),
|
|
104928
105521
|
tier: "swarm",
|
|
104929
105522
|
lesson,
|
|
104930
105523
|
category,
|
|
@@ -105327,22 +105920,22 @@ init_schema();
|
|
|
105327
105920
|
init_qa_gate_profile();
|
|
105328
105921
|
init_manager2();
|
|
105329
105922
|
import * as fs85 from "node:fs";
|
|
105330
|
-
import * as
|
|
105923
|
+
import * as path116 from "node:path";
|
|
105331
105924
|
|
|
105332
105925
|
// src/full-auto/phase-approval.ts
|
|
105333
105926
|
init_utils2();
|
|
105334
105927
|
init_logger();
|
|
105335
105928
|
init_state2();
|
|
105336
105929
|
import * as fs81 from "node:fs";
|
|
105337
|
-
import * as
|
|
105930
|
+
import * as path112 from "node:path";
|
|
105338
105931
|
var APPROVAL_TTL_MS = 24 * 60 * 60 * 1000;
|
|
105339
105932
|
function readEvidenceDir(directory, phase) {
|
|
105340
105933
|
try {
|
|
105341
|
-
const dirPath = validateSwarmPath(directory,
|
|
105934
|
+
const dirPath = validateSwarmPath(directory, path112.posix.join("evidence", String(phase)));
|
|
105342
105935
|
if (!fs81.existsSync(dirPath))
|
|
105343
105936
|
return [];
|
|
105344
105937
|
const entries = fs81.readdirSync(dirPath);
|
|
105345
|
-
return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) =>
|
|
105938
|
+
return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path112.join(dirPath, e));
|
|
105346
105939
|
} catch {
|
|
105347
105940
|
return [];
|
|
105348
105941
|
}
|
|
@@ -105481,16 +106074,16 @@ init_plan_schema();
|
|
|
105481
106074
|
init_ledger();
|
|
105482
106075
|
init_manager();
|
|
105483
106076
|
import * as fs82 from "node:fs";
|
|
105484
|
-
import * as
|
|
106077
|
+
import * as path113 from "node:path";
|
|
105485
106078
|
async function writeCheckpoint(directory) {
|
|
105486
106079
|
try {
|
|
105487
106080
|
const plan = await loadPlan(directory);
|
|
105488
106081
|
if (!plan)
|
|
105489
106082
|
return;
|
|
105490
|
-
const swarmDir =
|
|
106083
|
+
const swarmDir = path113.join(directory, ".swarm");
|
|
105491
106084
|
fs82.mkdirSync(swarmDir, { recursive: true });
|
|
105492
|
-
const jsonPath =
|
|
105493
|
-
const mdPath =
|
|
106085
|
+
const jsonPath = path113.join(swarmDir, "SWARM_PLAN.json");
|
|
106086
|
+
const mdPath = path113.join(swarmDir, "SWARM_PLAN.md");
|
|
105494
106087
|
fs82.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
105495
106088
|
const md = derivePlanMarkdown(plan);
|
|
105496
106089
|
fs82.writeFileSync(mdPath, md, "utf8");
|
|
@@ -105509,15 +106102,15 @@ init_telemetry();
|
|
|
105509
106102
|
// src/turbo/lean/phase-ready.ts
|
|
105510
106103
|
init_file_locks();
|
|
105511
106104
|
import * as fs84 from "node:fs";
|
|
105512
|
-
import * as
|
|
106105
|
+
import * as path115 from "node:path";
|
|
105513
106106
|
|
|
105514
106107
|
// src/turbo/lean/evidence.ts
|
|
105515
106108
|
init_bun_compat();
|
|
105516
106109
|
import { rmSync as rmSync6 } from "node:fs";
|
|
105517
106110
|
import * as fs83 from "node:fs/promises";
|
|
105518
|
-
import * as
|
|
106111
|
+
import * as path114 from "node:path";
|
|
105519
106112
|
function leanTurboEvidenceDir(directory, phase) {
|
|
105520
|
-
return
|
|
106113
|
+
return path114.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
105521
106114
|
}
|
|
105522
106115
|
function validateLaneId(laneId) {
|
|
105523
106116
|
if (laneId.length === 0) {
|
|
@@ -105539,16 +106132,16 @@ function validateLaneId(laneId) {
|
|
|
105539
106132
|
function laneEvidencePath(directory, phase, laneId) {
|
|
105540
106133
|
validateLaneId(laneId);
|
|
105541
106134
|
const expectedDir = leanTurboEvidenceDir(directory, phase);
|
|
105542
|
-
const resolvedPath =
|
|
105543
|
-
const resolvedDir =
|
|
105544
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
106135
|
+
const resolvedPath = path114.resolve(path114.join(expectedDir, `${laneId}.json`));
|
|
106136
|
+
const resolvedDir = path114.resolve(expectedDir);
|
|
106137
|
+
if (!resolvedPath.startsWith(resolvedDir + path114.sep) && resolvedPath !== resolvedDir) {
|
|
105545
106138
|
throw new Error(`Invalid laneId: path traversal detected (got "${laneId}")`);
|
|
105546
106139
|
}
|
|
105547
106140
|
return resolvedPath;
|
|
105548
106141
|
}
|
|
105549
106142
|
async function atomicWriteJson(filePath, data) {
|
|
105550
106143
|
const content = JSON.stringify(data, null, 2);
|
|
105551
|
-
const dir =
|
|
106144
|
+
const dir = path114.dirname(filePath);
|
|
105552
106145
|
await fs83.mkdir(dir, { recursive: true });
|
|
105553
106146
|
const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
105554
106147
|
try {
|
|
@@ -105562,7 +106155,7 @@ async function atomicWriteJson(filePath, data) {
|
|
|
105562
106155
|
}
|
|
105563
106156
|
}
|
|
105564
106157
|
function phaseEvidencePath(directory, phase) {
|
|
105565
|
-
return
|
|
106158
|
+
return path114.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
|
|
105566
106159
|
}
|
|
105567
106160
|
async function writeLaneEvidence(directory, phase, evidence) {
|
|
105568
106161
|
const targetPath = laneEvidencePath(directory, phase, evidence.laneId);
|
|
@@ -105606,7 +106199,7 @@ async function listLaneEvidence(directory, phase) {
|
|
|
105606
106199
|
if (entry === "lean-turbo-phase.json") {
|
|
105607
106200
|
continue;
|
|
105608
106201
|
}
|
|
105609
|
-
const filePath =
|
|
106202
|
+
const filePath = path114.join(evidenceDir, entry);
|
|
105610
106203
|
let content;
|
|
105611
106204
|
try {
|
|
105612
106205
|
content = await fs83.readFile(filePath, "utf-8");
|
|
@@ -105630,7 +106223,7 @@ var DEFAULT_CONFIG2 = {
|
|
|
105630
106223
|
};
|
|
105631
106224
|
function defaultReadPlanJson(dir) {
|
|
105632
106225
|
try {
|
|
105633
|
-
const planPath =
|
|
106226
|
+
const planPath = path115.join(dir, ".swarm", "plan.json");
|
|
105634
106227
|
if (!fs84.existsSync(planPath))
|
|
105635
106228
|
return null;
|
|
105636
106229
|
const raw = fs84.readFileSync(planPath, "utf-8");
|
|
@@ -105645,7 +106238,7 @@ function defaultReadPlanJson(dir) {
|
|
|
105645
106238
|
}
|
|
105646
106239
|
function readReviewerEvidenceFromFile(directory, phase) {
|
|
105647
106240
|
try {
|
|
105648
|
-
const evidencePath =
|
|
106241
|
+
const evidencePath = path115.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
|
|
105649
106242
|
if (!fs84.existsSync(evidencePath)) {
|
|
105650
106243
|
return null;
|
|
105651
106244
|
}
|
|
@@ -105665,7 +106258,7 @@ function readReviewerEvidenceFromFile(directory, phase) {
|
|
|
105665
106258
|
}
|
|
105666
106259
|
function readCriticEvidenceFromFile(directory, phase) {
|
|
105667
106260
|
try {
|
|
105668
|
-
const evidencePath =
|
|
106261
|
+
const evidencePath = path115.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
|
|
105669
106262
|
if (!fs84.existsSync(evidencePath)) {
|
|
105670
106263
|
return null;
|
|
105671
106264
|
}
|
|
@@ -105684,7 +106277,7 @@ function readCriticEvidenceFromFile(directory, phase) {
|
|
|
105684
106277
|
}
|
|
105685
106278
|
}
|
|
105686
106279
|
function listLaneEvidenceSync(directory, phase) {
|
|
105687
|
-
const evidenceDir =
|
|
106280
|
+
const evidenceDir = path115.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
105688
106281
|
let entries;
|
|
105689
106282
|
try {
|
|
105690
106283
|
entries = fs84.readdirSync(evidenceDir);
|
|
@@ -105754,7 +106347,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
105754
106347
|
...DEFAULT_CONFIG2,
|
|
105755
106348
|
...actualConfig
|
|
105756
106349
|
};
|
|
105757
|
-
const statePath =
|
|
106350
|
+
const statePath = path115.join(directory, ".swarm", "turbo-state.json");
|
|
105758
106351
|
if (!fs84.existsSync(statePath)) {
|
|
105759
106352
|
return {
|
|
105760
106353
|
ok: false,
|
|
@@ -105942,7 +106535,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
105942
106535
|
}
|
|
105943
106536
|
}
|
|
105944
106537
|
if (mergedConfig.integrated_diff_required) {
|
|
105945
|
-
const evidencePath =
|
|
106538
|
+
const evidencePath = path115.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
|
|
105946
106539
|
let hasDiff = false;
|
|
105947
106540
|
try {
|
|
105948
106541
|
const content = fs84.readFileSync(evidencePath, "utf-8");
|
|
@@ -106237,7 +106830,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106237
106830
|
let driftCheckEnabled = true;
|
|
106238
106831
|
let driftHasSpecMd = false;
|
|
106239
106832
|
try {
|
|
106240
|
-
const specMdPath =
|
|
106833
|
+
const specMdPath = path116.join(dir, ".swarm", "spec.md");
|
|
106241
106834
|
driftHasSpecMd = fs85.existsSync(specMdPath);
|
|
106242
106835
|
const gatePlan = await loadPlan(dir);
|
|
106243
106836
|
if (gatePlan) {
|
|
@@ -106258,7 +106851,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106258
106851
|
} else {
|
|
106259
106852
|
let phaseType;
|
|
106260
106853
|
try {
|
|
106261
|
-
const planPath =
|
|
106854
|
+
const planPath = path116.join(dir, ".swarm", "plan.json");
|
|
106262
106855
|
if (fs85.existsSync(planPath)) {
|
|
106263
106856
|
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
106264
106857
|
const plan = JSON.parse(planRaw);
|
|
@@ -106270,7 +106863,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106270
106863
|
warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
|
|
106271
106864
|
} else {
|
|
106272
106865
|
try {
|
|
106273
|
-
const driftEvidencePath =
|
|
106866
|
+
const driftEvidencePath = path116.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
106274
106867
|
let driftVerdictFound = false;
|
|
106275
106868
|
let driftVerdictApproved = false;
|
|
106276
106869
|
try {
|
|
@@ -106308,7 +106901,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106308
106901
|
let incompleteTaskCount = 0;
|
|
106309
106902
|
let planParseable = false;
|
|
106310
106903
|
try {
|
|
106311
|
-
const planPath =
|
|
106904
|
+
const planPath = path116.join(dir, ".swarm", "plan.json");
|
|
106312
106905
|
if (fs85.existsSync(planPath)) {
|
|
106313
106906
|
const planRaw = fs85.readFileSync(planPath, "utf-8");
|
|
106314
106907
|
const plan = JSON.parse(planRaw);
|
|
@@ -106375,7 +106968,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106375
106968
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
106376
106969
|
const effective = getEffectiveGates(profile, overrides);
|
|
106377
106970
|
if (effective.hallucination_guard === true) {
|
|
106378
|
-
const hgPath =
|
|
106971
|
+
const hgPath = path116.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
106379
106972
|
let hgVerdictFound = false;
|
|
106380
106973
|
let hgVerdictApproved = false;
|
|
106381
106974
|
try {
|
|
@@ -106447,7 +107040,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106447
107040
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
106448
107041
|
const effective = getEffectiveGates(profile, overrides);
|
|
106449
107042
|
if (effective.mutation_test === true) {
|
|
106450
|
-
const mgPath =
|
|
107043
|
+
const mgPath = path116.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
|
|
106451
107044
|
let mgVerdictFound = false;
|
|
106452
107045
|
let mgVerdict;
|
|
106453
107046
|
try {
|
|
@@ -106521,7 +107114,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
106521
107114
|
const effective = getEffectiveGates(profile, overrides);
|
|
106522
107115
|
if (effective.council_mode === true) {
|
|
106523
107116
|
councilModeEnabled = true;
|
|
106524
|
-
const pcPath =
|
|
107117
|
+
const pcPath = path116.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
|
|
106525
107118
|
let pcVerdictFound = false;
|
|
106526
107119
|
let _pcVerdict;
|
|
106527
107120
|
let pcQuorumSize;
|
|
@@ -106729,7 +107322,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
106729
107322
|
const effective = getEffectiveGates(profile, overrides);
|
|
106730
107323
|
if (effective.final_council === true) {
|
|
106731
107324
|
finalCouncilEnabled = true;
|
|
106732
|
-
const fcPath =
|
|
107325
|
+
const fcPath = path116.join(dir, ".swarm", "evidence", "final-council.json");
|
|
106733
107326
|
let fcVerdictFound = false;
|
|
106734
107327
|
let _fcVerdict;
|
|
106735
107328
|
try {
|
|
@@ -106917,7 +107510,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
106917
107510
|
}
|
|
106918
107511
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
106919
107512
|
try {
|
|
106920
|
-
const projectName =
|
|
107513
|
+
const projectName = path116.basename(dir);
|
|
106921
107514
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
106922
107515
|
if (curationResult) {
|
|
106923
107516
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -107287,7 +107880,7 @@ init_utils();
|
|
|
107287
107880
|
init_bun_compat();
|
|
107288
107881
|
init_create_tool();
|
|
107289
107882
|
import * as fs86 from "node:fs";
|
|
107290
|
-
import * as
|
|
107883
|
+
import * as path117 from "node:path";
|
|
107291
107884
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
107292
107885
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
107293
107886
|
function isValidEcosystem(value) {
|
|
@@ -107315,16 +107908,16 @@ function validateArgs3(args2) {
|
|
|
107315
107908
|
function detectEcosystems(directory) {
|
|
107316
107909
|
const ecosystems = [];
|
|
107317
107910
|
const cwd = directory;
|
|
107318
|
-
if (fs86.existsSync(
|
|
107911
|
+
if (fs86.existsSync(path117.join(cwd, "package.json"))) {
|
|
107319
107912
|
ecosystems.push("npm");
|
|
107320
107913
|
}
|
|
107321
|
-
if (fs86.existsSync(
|
|
107914
|
+
if (fs86.existsSync(path117.join(cwd, "pyproject.toml")) || fs86.existsSync(path117.join(cwd, "requirements.txt"))) {
|
|
107322
107915
|
ecosystems.push("pip");
|
|
107323
107916
|
}
|
|
107324
|
-
if (fs86.existsSync(
|
|
107917
|
+
if (fs86.existsSync(path117.join(cwd, "Cargo.toml"))) {
|
|
107325
107918
|
ecosystems.push("cargo");
|
|
107326
107919
|
}
|
|
107327
|
-
if (fs86.existsSync(
|
|
107920
|
+
if (fs86.existsSync(path117.join(cwd, "go.mod"))) {
|
|
107328
107921
|
ecosystems.push("go");
|
|
107329
107922
|
}
|
|
107330
107923
|
try {
|
|
@@ -107333,13 +107926,13 @@ function detectEcosystems(directory) {
|
|
|
107333
107926
|
ecosystems.push("dotnet");
|
|
107334
107927
|
}
|
|
107335
107928
|
} catch {}
|
|
107336
|
-
if (fs86.existsSync(
|
|
107929
|
+
if (fs86.existsSync(path117.join(cwd, "Gemfile")) || fs86.existsSync(path117.join(cwd, "Gemfile.lock"))) {
|
|
107337
107930
|
ecosystems.push("ruby");
|
|
107338
107931
|
}
|
|
107339
|
-
if (fs86.existsSync(
|
|
107932
|
+
if (fs86.existsSync(path117.join(cwd, "pubspec.yaml"))) {
|
|
107340
107933
|
ecosystems.push("dart");
|
|
107341
107934
|
}
|
|
107342
|
-
if (fs86.existsSync(
|
|
107935
|
+
if (fs86.existsSync(path117.join(cwd, "composer.lock"))) {
|
|
107343
107936
|
ecosystems.push("composer");
|
|
107344
107937
|
}
|
|
107345
107938
|
return ecosystems;
|
|
@@ -108475,7 +109068,7 @@ var pkg_audit = createSwarmTool({
|
|
|
108475
109068
|
init_zod();
|
|
108476
109069
|
init_manager2();
|
|
108477
109070
|
import * as fs87 from "node:fs";
|
|
108478
|
-
import * as
|
|
109071
|
+
import * as path118 from "node:path";
|
|
108479
109072
|
init_utils();
|
|
108480
109073
|
init_create_tool();
|
|
108481
109074
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -108598,7 +109191,7 @@ function isScaffoldFile(filePath) {
|
|
|
108598
109191
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
108599
109192
|
return true;
|
|
108600
109193
|
}
|
|
108601
|
-
const filename =
|
|
109194
|
+
const filename = path118.basename(filePath);
|
|
108602
109195
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
108603
109196
|
return true;
|
|
108604
109197
|
}
|
|
@@ -108615,7 +109208,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
108615
109208
|
if (regex.test(normalizedPath)) {
|
|
108616
109209
|
return true;
|
|
108617
109210
|
}
|
|
108618
|
-
const filename =
|
|
109211
|
+
const filename = path118.basename(filePath);
|
|
108619
109212
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
108620
109213
|
if (filenameRegex.test(filename)) {
|
|
108621
109214
|
return true;
|
|
@@ -108624,7 +109217,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
108624
109217
|
return false;
|
|
108625
109218
|
}
|
|
108626
109219
|
function isParserSupported(filePath) {
|
|
108627
|
-
const ext =
|
|
109220
|
+
const ext = path118.extname(filePath).toLowerCase();
|
|
108628
109221
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
108629
109222
|
}
|
|
108630
109223
|
function isPlanFile(filePath) {
|
|
@@ -108871,9 +109464,9 @@ async function placeholderScan(input, directory) {
|
|
|
108871
109464
|
let filesScanned = 0;
|
|
108872
109465
|
const filesWithFindings = new Set;
|
|
108873
109466
|
for (const filePath of changed_files) {
|
|
108874
|
-
const fullPath =
|
|
108875
|
-
const resolvedDirectory =
|
|
108876
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
109467
|
+
const fullPath = path118.isAbsolute(filePath) ? filePath : path118.resolve(directory, filePath);
|
|
109468
|
+
const resolvedDirectory = path118.resolve(directory);
|
|
109469
|
+
if (!fullPath.startsWith(resolvedDirectory + path118.sep) && fullPath !== resolvedDirectory) {
|
|
108877
109470
|
continue;
|
|
108878
109471
|
}
|
|
108879
109472
|
if (!fs87.existsSync(fullPath)) {
|
|
@@ -108882,7 +109475,7 @@ async function placeholderScan(input, directory) {
|
|
|
108882
109475
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
108883
109476
|
continue;
|
|
108884
109477
|
}
|
|
108885
|
-
const relativeFilePath =
|
|
109478
|
+
const relativeFilePath = path118.relative(directory, fullPath).replace(/\\/g, "/");
|
|
108886
109479
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
108887
109480
|
continue;
|
|
108888
109481
|
}
|
|
@@ -108954,7 +109547,7 @@ var placeholder_scan = createSwarmTool({
|
|
|
108954
109547
|
});
|
|
108955
109548
|
// src/tools/pre-check-batch.ts
|
|
108956
109549
|
import * as fs91 from "node:fs";
|
|
108957
|
-
import * as
|
|
109550
|
+
import * as path122 from "node:path";
|
|
108958
109551
|
init_zod();
|
|
108959
109552
|
init_manager2();
|
|
108960
109553
|
init_utils();
|
|
@@ -109095,7 +109688,7 @@ init_zod();
|
|
|
109095
109688
|
init_manager2();
|
|
109096
109689
|
init_detector();
|
|
109097
109690
|
import * as fs90 from "node:fs";
|
|
109098
|
-
import * as
|
|
109691
|
+
import * as path121 from "node:path";
|
|
109099
109692
|
import { extname as extname20 } from "node:path";
|
|
109100
109693
|
|
|
109101
109694
|
// src/sast/rules/c.ts
|
|
@@ -109811,7 +110404,7 @@ function executeRulesSync(filePath, content, language) {
|
|
|
109811
110404
|
// src/sast/semgrep.ts
|
|
109812
110405
|
import * as child_process9 from "node:child_process";
|
|
109813
110406
|
import * as fs88 from "node:fs";
|
|
109814
|
-
import * as
|
|
110407
|
+
import * as path119 from "node:path";
|
|
109815
110408
|
var semgrepAvailableCache = null;
|
|
109816
110409
|
var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
|
|
109817
110410
|
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
@@ -109998,7 +110591,7 @@ async function runSemgrep(options) {
|
|
|
109998
110591
|
}
|
|
109999
110592
|
function getRulesDirectory(projectRoot) {
|
|
110000
110593
|
if (projectRoot) {
|
|
110001
|
-
return
|
|
110594
|
+
return path119.resolve(projectRoot, DEFAULT_RULES_DIR);
|
|
110002
110595
|
}
|
|
110003
110596
|
return DEFAULT_RULES_DIR;
|
|
110004
110597
|
}
|
|
@@ -110019,24 +110612,24 @@ init_create_tool();
|
|
|
110019
110612
|
init_utils2();
|
|
110020
110613
|
import * as crypto10 from "node:crypto";
|
|
110021
110614
|
import * as fs89 from "node:fs";
|
|
110022
|
-
import * as
|
|
110615
|
+
import * as path120 from "node:path";
|
|
110023
110616
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
110024
110617
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
110025
110618
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
110026
110619
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
110027
110620
|
function normalizeFindingPath(directory, file3) {
|
|
110028
|
-
const resolved =
|
|
110029
|
-
const rel =
|
|
110621
|
+
const resolved = path120.isAbsolute(file3) ? file3 : path120.resolve(directory, file3);
|
|
110622
|
+
const rel = path120.relative(path120.resolve(directory), resolved);
|
|
110030
110623
|
return rel.replace(/\\/g, "/");
|
|
110031
110624
|
}
|
|
110032
110625
|
function baselineRelPath(phase) {
|
|
110033
|
-
return
|
|
110626
|
+
return path120.join("evidence", String(phase), "sast-baseline.json");
|
|
110034
110627
|
}
|
|
110035
110628
|
function tempRelPath(phase) {
|
|
110036
|
-
return
|
|
110629
|
+
return path120.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
110037
110630
|
}
|
|
110038
110631
|
function lockRelPath(phase) {
|
|
110039
|
-
return
|
|
110632
|
+
return path120.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
110040
110633
|
}
|
|
110041
110634
|
function getLine(lines, idx) {
|
|
110042
110635
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -110157,8 +110750,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
110157
110750
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
110158
110751
|
};
|
|
110159
110752
|
}
|
|
110160
|
-
fs89.mkdirSync(
|
|
110161
|
-
fs89.mkdirSync(
|
|
110753
|
+
fs89.mkdirSync(path120.dirname(baselinePath), { recursive: true });
|
|
110754
|
+
fs89.mkdirSync(path120.dirname(tempPath), { recursive: true });
|
|
110162
110755
|
const releaseLock = await acquireLock2(lockPath);
|
|
110163
110756
|
try {
|
|
110164
110757
|
let existing = null;
|
|
@@ -110431,9 +111024,9 @@ async function sastScan(input, directory, config3) {
|
|
|
110431
111024
|
_filesSkipped++;
|
|
110432
111025
|
continue;
|
|
110433
111026
|
}
|
|
110434
|
-
const resolvedPath =
|
|
110435
|
-
const resolvedDirectory =
|
|
110436
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
111027
|
+
const resolvedPath = path121.isAbsolute(filePath) ? filePath : path121.resolve(directory, filePath);
|
|
111028
|
+
const resolvedDirectory = path121.resolve(directory);
|
|
111029
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path121.sep) && resolvedPath !== resolvedDirectory) {
|
|
110437
111030
|
_filesSkipped++;
|
|
110438
111031
|
continue;
|
|
110439
111032
|
}
|
|
@@ -110748,18 +111341,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
110748
111341
|
let resolved;
|
|
110749
111342
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
110750
111343
|
if (isWinAbs) {
|
|
110751
|
-
resolved =
|
|
110752
|
-
} else if (
|
|
110753
|
-
resolved =
|
|
111344
|
+
resolved = path122.win32.resolve(inputPath);
|
|
111345
|
+
} else if (path122.isAbsolute(inputPath)) {
|
|
111346
|
+
resolved = path122.resolve(inputPath);
|
|
110754
111347
|
} else {
|
|
110755
|
-
resolved =
|
|
111348
|
+
resolved = path122.resolve(baseDir, inputPath);
|
|
110756
111349
|
}
|
|
110757
|
-
const workspaceResolved =
|
|
111350
|
+
const workspaceResolved = path122.resolve(workspaceDir);
|
|
110758
111351
|
let relative25;
|
|
110759
111352
|
if (isWinAbs) {
|
|
110760
|
-
relative25 =
|
|
111353
|
+
relative25 = path122.win32.relative(workspaceResolved, resolved);
|
|
110761
111354
|
} else {
|
|
110762
|
-
relative25 =
|
|
111355
|
+
relative25 = path122.relative(workspaceResolved, resolved);
|
|
110763
111356
|
}
|
|
110764
111357
|
if (relative25.startsWith("..")) {
|
|
110765
111358
|
return "path traversal detected";
|
|
@@ -110824,7 +111417,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
110824
111417
|
if (typeof file3 !== "string") {
|
|
110825
111418
|
continue;
|
|
110826
111419
|
}
|
|
110827
|
-
const resolvedPath =
|
|
111420
|
+
const resolvedPath = path122.resolve(file3);
|
|
110828
111421
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
110829
111422
|
if (validationError) {
|
|
110830
111423
|
continue;
|
|
@@ -110981,7 +111574,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
110981
111574
|
skippedFiles++;
|
|
110982
111575
|
continue;
|
|
110983
111576
|
}
|
|
110984
|
-
const resolvedPath =
|
|
111577
|
+
const resolvedPath = path122.resolve(file3);
|
|
110985
111578
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
110986
111579
|
if (validationError) {
|
|
110987
111580
|
skippedFiles++;
|
|
@@ -110999,7 +111592,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
110999
111592
|
};
|
|
111000
111593
|
}
|
|
111001
111594
|
for (const file3 of validatedFiles) {
|
|
111002
|
-
const ext =
|
|
111595
|
+
const ext = path122.extname(file3).toLowerCase();
|
|
111003
111596
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
111004
111597
|
skippedFiles++;
|
|
111005
111598
|
continue;
|
|
@@ -111218,7 +111811,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
111218
111811
|
const preexistingFindings = [];
|
|
111219
111812
|
for (const finding of findings) {
|
|
111220
111813
|
const filePath = finding.location.file;
|
|
111221
|
-
const normalised =
|
|
111814
|
+
const normalised = path122.relative(directory, filePath).replace(/\\/g, "/");
|
|
111222
111815
|
const changedLines = changedLineRanges.get(normalised);
|
|
111223
111816
|
if (changedLines?.has(finding.location.line)) {
|
|
111224
111817
|
newFindings.push(finding);
|
|
@@ -111269,7 +111862,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
111269
111862
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
111270
111863
|
continue;
|
|
111271
111864
|
}
|
|
111272
|
-
changedFiles.push(
|
|
111865
|
+
changedFiles.push(path122.resolve(directory, file3));
|
|
111273
111866
|
}
|
|
111274
111867
|
if (changedFiles.length === 0) {
|
|
111275
111868
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -111470,9 +112063,9 @@ var pre_check_batch = createSwarmTool({
|
|
|
111470
112063
|
};
|
|
111471
112064
|
return JSON.stringify(errorResult, null, 2);
|
|
111472
112065
|
}
|
|
111473
|
-
const resolvedDirectory =
|
|
111474
|
-
const workspaceAnchor =
|
|
111475
|
-
if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor +
|
|
112066
|
+
const resolvedDirectory = path122.resolve(typedArgs.directory);
|
|
112067
|
+
const workspaceAnchor = path122.resolve(directory);
|
|
112068
|
+
if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor + path122.sep)) {
|
|
111476
112069
|
const subDirError = `directory "${typedArgs.directory}" is a subdirectory of the project root — pre_check_batch requires the project root directory "${workspaceAnchor}"`;
|
|
111477
112070
|
const subDirResult = {
|
|
111478
112071
|
gates_passed: false,
|
|
@@ -111523,7 +112116,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
111523
112116
|
});
|
|
111524
112117
|
// src/tools/repo-map.ts
|
|
111525
112118
|
init_zod();
|
|
111526
|
-
import * as
|
|
112119
|
+
import * as path123 from "node:path";
|
|
111527
112120
|
init_path_security();
|
|
111528
112121
|
init_create_tool();
|
|
111529
112122
|
var VALID_ACTIONS = [
|
|
@@ -111548,7 +112141,7 @@ function validateFile(p) {
|
|
|
111548
112141
|
return "file contains control characters";
|
|
111549
112142
|
if (containsPathTraversal(p))
|
|
111550
112143
|
return "file contains path traversal";
|
|
111551
|
-
if (
|
|
112144
|
+
if (path123.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
111552
112145
|
return "file must be a workspace-relative path, not absolute";
|
|
111553
112146
|
}
|
|
111554
112147
|
return null;
|
|
@@ -111571,8 +112164,8 @@ function ok(action, payload) {
|
|
|
111571
112164
|
}
|
|
111572
112165
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
111573
112166
|
const normalized = input.replace(/\\/g, "/");
|
|
111574
|
-
if (
|
|
111575
|
-
const rel =
|
|
112167
|
+
if (path123.isAbsolute(normalized)) {
|
|
112168
|
+
const rel = path123.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
111576
112169
|
return normalizeGraphPath2(rel);
|
|
111577
112170
|
}
|
|
111578
112171
|
return normalizeGraphPath2(normalized);
|
|
@@ -111717,7 +112310,7 @@ var repo_map = createSwarmTool({
|
|
|
111717
112310
|
init_zod();
|
|
111718
112311
|
init_create_tool();
|
|
111719
112312
|
import * as fs92 from "node:fs";
|
|
111720
|
-
import * as
|
|
112313
|
+
import * as path124 from "node:path";
|
|
111721
112314
|
var SPEC_FILE = ".swarm/spec.md";
|
|
111722
112315
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
111723
112316
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -111786,7 +112379,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
111786
112379
|
return [];
|
|
111787
112380
|
}
|
|
111788
112381
|
for (const entry of entries) {
|
|
111789
|
-
const entryPath =
|
|
112382
|
+
const entryPath = path124.join(evidenceDir, entry);
|
|
111790
112383
|
try {
|
|
111791
112384
|
const stat8 = fs92.statSync(entryPath);
|
|
111792
112385
|
if (!stat8.isDirectory()) {
|
|
@@ -111802,11 +112395,11 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
111802
112395
|
if (entryPhase !== String(phase)) {
|
|
111803
112396
|
continue;
|
|
111804
112397
|
}
|
|
111805
|
-
const evidenceFilePath =
|
|
112398
|
+
const evidenceFilePath = path124.join(entryPath, "evidence.json");
|
|
111806
112399
|
try {
|
|
111807
|
-
const resolvedPath =
|
|
111808
|
-
const evidenceDirResolved =
|
|
111809
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
112400
|
+
const resolvedPath = path124.resolve(evidenceFilePath);
|
|
112401
|
+
const evidenceDirResolved = path124.resolve(evidenceDir);
|
|
112402
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path124.sep)) {
|
|
111810
112403
|
continue;
|
|
111811
112404
|
}
|
|
111812
112405
|
const stat8 = fs92.lstatSync(evidenceFilePath);
|
|
@@ -111840,7 +112433,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
111840
112433
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
111841
112434
|
for (const file3 of diffEntry.files_changed) {
|
|
111842
112435
|
if (typeof file3 === "string") {
|
|
111843
|
-
touchedFiles.add(
|
|
112436
|
+
touchedFiles.add(path124.resolve(cwd, file3));
|
|
111844
112437
|
}
|
|
111845
112438
|
}
|
|
111846
112439
|
}
|
|
@@ -111853,8 +112446,8 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
111853
112446
|
}
|
|
111854
112447
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
111855
112448
|
try {
|
|
111856
|
-
const resolvedPath =
|
|
111857
|
-
const cwdResolved =
|
|
112449
|
+
const resolvedPath = path124.resolve(filePath);
|
|
112450
|
+
const cwdResolved = path124.resolve(cwd);
|
|
111858
112451
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
111859
112452
|
return false;
|
|
111860
112453
|
}
|
|
@@ -111988,7 +112581,7 @@ var req_coverage = createSwarmTool({
|
|
|
111988
112581
|
}, null, 2);
|
|
111989
112582
|
}
|
|
111990
112583
|
const cwd = inputDirectory || directory;
|
|
111991
|
-
const specPath =
|
|
112584
|
+
const specPath = path124.join(cwd, SPEC_FILE);
|
|
111992
112585
|
let specContent;
|
|
111993
112586
|
try {
|
|
111994
112587
|
specContent = fs92.readFileSync(specPath, "utf-8");
|
|
@@ -112015,7 +112608,7 @@ var req_coverage = createSwarmTool({
|
|
|
112015
112608
|
message: "No FR requirements found in spec.md"
|
|
112016
112609
|
}, null, 2);
|
|
112017
112610
|
}
|
|
112018
|
-
const evidenceDir =
|
|
112611
|
+
const evidenceDir = path124.join(cwd, EVIDENCE_DIR4);
|
|
112019
112612
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
112020
112613
|
const analyzedRequirements = [];
|
|
112021
112614
|
let coveredCount = 0;
|
|
@@ -112041,7 +112634,7 @@ var req_coverage = createSwarmTool({
|
|
|
112041
112634
|
requirements: analyzedRequirements
|
|
112042
112635
|
};
|
|
112043
112636
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
112044
|
-
const reportPath =
|
|
112637
|
+
const reportPath = path124.join(evidenceDir, reportFilename);
|
|
112045
112638
|
try {
|
|
112046
112639
|
if (!fs92.existsSync(evidenceDir)) {
|
|
112047
112640
|
fs92.mkdirSync(evidenceDir, { recursive: true });
|
|
@@ -112129,11 +112722,14 @@ init_qa_gate_profile();
|
|
|
112129
112722
|
init_file_locks();
|
|
112130
112723
|
import * as crypto11 from "node:crypto";
|
|
112131
112724
|
import * as fs93 from "node:fs";
|
|
112132
|
-
import * as
|
|
112725
|
+
import * as path125 from "node:path";
|
|
112133
112726
|
init_ledger();
|
|
112134
112727
|
init_manager();
|
|
112135
112728
|
init_state();
|
|
112136
112729
|
init_create_tool();
|
|
112730
|
+
function executionProfilesEqual(a, b) {
|
|
112731
|
+
return a.parallelization_enabled === b.parallelization_enabled && a.max_concurrent_tasks === b.max_concurrent_tasks && a.council_parallel === b.council_parallel && a.locked === b.locked;
|
|
112732
|
+
}
|
|
112137
112733
|
function detectPlaceholderContent(args2) {
|
|
112138
112734
|
const issues = [];
|
|
112139
112735
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -112207,8 +112803,8 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112207
112803
|
};
|
|
112208
112804
|
}
|
|
112209
112805
|
if (args2.working_directory && fallbackDir) {
|
|
112210
|
-
const resolvedTarget =
|
|
112211
|
-
const resolvedRoot =
|
|
112806
|
+
const resolvedTarget = path125.resolve(args2.working_directory);
|
|
112807
|
+
const resolvedRoot = path125.resolve(fallbackDir);
|
|
112212
112808
|
let fallbackExists = false;
|
|
112213
112809
|
try {
|
|
112214
112810
|
fs93.accessSync(resolvedRoot, fs93.constants.F_OK);
|
|
@@ -112217,7 +112813,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112217
112813
|
fallbackExists = false;
|
|
112218
112814
|
}
|
|
112219
112815
|
if (fallbackExists) {
|
|
112220
|
-
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot +
|
|
112816
|
+
const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path125.sep);
|
|
112221
112817
|
if (isSubdirectory) {
|
|
112222
112818
|
return {
|
|
112223
112819
|
success: false,
|
|
@@ -112233,7 +112829,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112233
112829
|
let specMtime;
|
|
112234
112830
|
let specHash;
|
|
112235
112831
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
112236
|
-
const specPath =
|
|
112832
|
+
const specPath = path125.join(targetWorkspace, ".swarm", "spec.md");
|
|
112237
112833
|
try {
|
|
112238
112834
|
const stat8 = await fs93.promises.stat(specPath);
|
|
112239
112835
|
specMtime = stat8.mtime.toISOString();
|
|
@@ -112249,7 +112845,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112249
112845
|
}
|
|
112250
112846
|
}
|
|
112251
112847
|
if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
|
|
112252
|
-
const contextPath =
|
|
112848
|
+
const contextPath = path125.join(targetWorkspace, ".swarm", "context.md");
|
|
112253
112849
|
let contextContent = "";
|
|
112254
112850
|
try {
|
|
112255
112851
|
contextContent = await fs93.promises.readFile(contextPath, "utf8");
|
|
@@ -112298,18 +112894,51 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112298
112894
|
}
|
|
112299
112895
|
}
|
|
112300
112896
|
}
|
|
112301
|
-
if (
|
|
112302
|
-
|
|
112897
|
+
if (args2.confirm_identity_change !== true) {
|
|
112898
|
+
const existingId = derivePlanId(existing);
|
|
112899
|
+
const incomingId = derivePlanId({
|
|
112900
|
+
swarm: args2.swarm_id,
|
|
112901
|
+
title: args2.title
|
|
112902
|
+
});
|
|
112903
|
+
if (existingId !== incomingId) {
|
|
112303
112904
|
return {
|
|
112304
112905
|
success: false,
|
|
112305
|
-
message: "
|
|
112906
|
+
message: "PLAN_IDENTITY_MISMATCH: The incoming plan identity does not match the existing plan. " + "To overwrite with a new identity, set confirm_identity_change: true.",
|
|
112306
112907
|
errors: [
|
|
112307
|
-
|
|
112908
|
+
`Existing plan identity: ${existingId} (swarm: "${existing.swarm}", title: "${existing.title}")`,
|
|
112909
|
+
`Incoming plan identity: ${incomingId} (swarm: "${args2.swarm_id}", title: "${args2.title}")`
|
|
112308
112910
|
],
|
|
112309
|
-
recovery_guidance: "
|
|
112911
|
+
recovery_guidance: "Verify the title and swarm_id match the intended plan. " + "If the identity change is intentional, retry with confirm_identity_change: true. " + "Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
112310
112912
|
};
|
|
112311
112913
|
}
|
|
112312
|
-
|
|
112914
|
+
}
|
|
112915
|
+
if (existing.execution_profile?.locked) {
|
|
112916
|
+
if (args2.execution_profile !== undefined && !args2.reset_statuses) {
|
|
112917
|
+
const requestedProfile = ExecutionProfileSchema.safeParse({
|
|
112918
|
+
...existing.execution_profile,
|
|
112919
|
+
...args2.execution_profile
|
|
112920
|
+
});
|
|
112921
|
+
if (!requestedProfile.success) {
|
|
112922
|
+
return {
|
|
112923
|
+
success: false,
|
|
112924
|
+
message: "Invalid execution_profile: schema validation failed",
|
|
112925
|
+
errors: requestedProfile.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`),
|
|
112926
|
+
recovery_guidance: "Check execution_profile fields: parallelization_enabled (boolean), " + "max_concurrent_tasks (integer 1-64), council_parallel (boolean), locked (boolean)."
|
|
112927
|
+
};
|
|
112928
|
+
}
|
|
112929
|
+
if (executionProfilesEqual(existing.execution_profile, requestedProfile.data)) {
|
|
112930
|
+
preservedExecutionProfile = existing.execution_profile;
|
|
112931
|
+
} else {
|
|
112932
|
+
return {
|
|
112933
|
+
success: false,
|
|
112934
|
+
message: "EXECUTION_PROFILE_LOCKED: The execution_profile for this plan is locked and cannot be changed.",
|
|
112935
|
+
errors: [
|
|
112936
|
+
"execution_profile.locked is true — to change the profile you must first unlock it via a separate plan revision that explicitly sets locked: false, or reset the plan with reset_statuses."
|
|
112937
|
+
],
|
|
112938
|
+
recovery_guidance: "Remove the execution_profile field from this save_plan call to preserve the locked profile, " + "or use reset_statuses: true to start fresh (this clears the lock). " + "Never modify execution_profile directly in plan.json."
|
|
112939
|
+
};
|
|
112940
|
+
}
|
|
112941
|
+
} else if (!args2.reset_statuses) {
|
|
112313
112942
|
preservedExecutionProfile = existing.execution_profile;
|
|
112314
112943
|
}
|
|
112315
112944
|
} else {
|
|
@@ -112481,7 +113110,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112481
113110
|
});
|
|
112482
113111
|
const savedPlan = await loadPlanJsonOnly(dir);
|
|
112483
113112
|
if (savedPlan) {
|
|
112484
|
-
await
|
|
113113
|
+
await takeSnapshotWithRetry(dir, savedPlan);
|
|
112485
113114
|
}
|
|
112486
113115
|
if (resolvedProfile !== undefined && savedPlan) {
|
|
112487
113116
|
const planId = derivePlanId(plan);
|
|
@@ -112506,7 +113135,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112506
113135
|
}
|
|
112507
113136
|
await writeCheckpoint(dir).catch(() => {});
|
|
112508
113137
|
try {
|
|
112509
|
-
const markerPath =
|
|
113138
|
+
const markerPath = path125.join(dir, ".swarm", ".plan-write-marker");
|
|
112510
113139
|
const marker = JSON.stringify({
|
|
112511
113140
|
source: "save_plan",
|
|
112512
113141
|
timestamp: new Date().toISOString(),
|
|
@@ -112529,7 +113158,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
112529
113158
|
return {
|
|
112530
113159
|
success: true,
|
|
112531
113160
|
message: "Plan saved successfully",
|
|
112532
|
-
plan_path:
|
|
113161
|
+
plan_path: path125.join(dir, ".swarm", "plan.json"),
|
|
112533
113162
|
phases_count: plan.phases.length,
|
|
112534
113163
|
tasks_count: tasksCount,
|
|
112535
113164
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -112579,6 +113208,7 @@ var save_plan = createSwarmTool({
|
|
|
112579
113208
|
removed_task_ids: exports_external.array(exports_external.string()).optional().describe("Task IDs that are present in the prior plan but intentionally being " + "removed by this save. Every task missing from `phases` MUST be enumerated " + "here, otherwise save_plan rejects with PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED. " + "Tasks not yet finished (status pending/in_progress/blocked) MUST NOT be " + "removed without explicit user confirmation."),
|
|
112580
113209
|
removal_reason: exports_external.string().optional().describe("Required when removed_task_ids is non-empty. Human-readable reason recorded " + "on each task_removed ledger event."),
|
|
112581
113210
|
confirm_destructive_reset: exports_external.boolean().optional().describe("Required when reset_statuses is true AND at least one task is missing from " + "the new plan. Set true to acknowledge that the destructive reset drops " + "unfinished work. When set together with reset_statuses, save_plan auto-" + "populates removed_task_ids from the missing set."),
|
|
113211
|
+
confirm_identity_change: exports_external.boolean().optional().describe("When true, allows overwriting an existing plan that has a different " + "identity (swarm_id + title). Without this flag, save_plan rejects " + "with PLAN_IDENTITY_MISMATCH if the identity differs."),
|
|
112582
113212
|
execution_profile: exports_external.object({
|
|
112583
113213
|
parallelization_enabled: exports_external.boolean().optional().describe("When true, enables parallel task dispatch for this plan. Default false (serial)."),
|
|
112584
113214
|
max_concurrent_tasks: exports_external.number().int().min(1).max(64).optional().describe("Maximum tasks that may run concurrently when parallelization is enabled. Default 1."),
|
|
@@ -112594,7 +113224,7 @@ var save_plan = createSwarmTool({
|
|
|
112594
113224
|
init_zod();
|
|
112595
113225
|
init_manager2();
|
|
112596
113226
|
import * as fs94 from "node:fs";
|
|
112597
|
-
import * as
|
|
113227
|
+
import * as path126 from "node:path";
|
|
112598
113228
|
|
|
112599
113229
|
// src/sbom/detectors/index.ts
|
|
112600
113230
|
init_utils();
|
|
@@ -113444,7 +114074,7 @@ function findManifestFiles(rootDir) {
|
|
|
113444
114074
|
try {
|
|
113445
114075
|
const entries = fs94.readdirSync(dir, { withFileTypes: true });
|
|
113446
114076
|
for (const entry of entries) {
|
|
113447
|
-
const fullPath =
|
|
114077
|
+
const fullPath = path126.join(dir, entry.name);
|
|
113448
114078
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
113449
114079
|
continue;
|
|
113450
114080
|
}
|
|
@@ -113453,7 +114083,7 @@ function findManifestFiles(rootDir) {
|
|
|
113453
114083
|
} else if (entry.isFile()) {
|
|
113454
114084
|
for (const pattern of patterns) {
|
|
113455
114085
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
113456
|
-
manifestFiles.push(
|
|
114086
|
+
manifestFiles.push(path126.relative(rootDir, fullPath));
|
|
113457
114087
|
break;
|
|
113458
114088
|
}
|
|
113459
114089
|
}
|
|
@@ -113471,11 +114101,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
113471
114101
|
try {
|
|
113472
114102
|
const entries = fs94.readdirSync(dir, { withFileTypes: true });
|
|
113473
114103
|
for (const entry of entries) {
|
|
113474
|
-
const fullPath =
|
|
114104
|
+
const fullPath = path126.join(dir, entry.name);
|
|
113475
114105
|
if (entry.isFile()) {
|
|
113476
114106
|
for (const pattern of patterns) {
|
|
113477
114107
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
113478
|
-
found.push(
|
|
114108
|
+
found.push(path126.relative(workingDir, fullPath));
|
|
113479
114109
|
break;
|
|
113480
114110
|
}
|
|
113481
114111
|
}
|
|
@@ -113488,11 +114118,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
113488
114118
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
113489
114119
|
const dirs = new Set;
|
|
113490
114120
|
for (const file3 of changedFiles) {
|
|
113491
|
-
let currentDir =
|
|
114121
|
+
let currentDir = path126.dirname(file3);
|
|
113492
114122
|
while (true) {
|
|
113493
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
113494
|
-
dirs.add(
|
|
113495
|
-
const parent =
|
|
114123
|
+
if (currentDir && currentDir !== "." && currentDir !== path126.sep) {
|
|
114124
|
+
dirs.add(path126.join(workingDir, currentDir));
|
|
114125
|
+
const parent = path126.dirname(currentDir);
|
|
113496
114126
|
if (parent === currentDir)
|
|
113497
114127
|
break;
|
|
113498
114128
|
currentDir = parent;
|
|
@@ -113576,7 +114206,7 @@ var sbom_generate = createSwarmTool({
|
|
|
113576
114206
|
const changedFiles = obj.changed_files;
|
|
113577
114207
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
113578
114208
|
const workingDir = directory;
|
|
113579
|
-
const outputDir =
|
|
114209
|
+
const outputDir = path126.isAbsolute(relativeOutputDir) ? relativeOutputDir : path126.join(workingDir, relativeOutputDir);
|
|
113580
114210
|
let manifestFiles = [];
|
|
113581
114211
|
if (scope === "all") {
|
|
113582
114212
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -113599,7 +114229,7 @@ var sbom_generate = createSwarmTool({
|
|
|
113599
114229
|
const processedFiles = [];
|
|
113600
114230
|
for (const manifestFile of manifestFiles) {
|
|
113601
114231
|
try {
|
|
113602
|
-
const fullPath =
|
|
114232
|
+
const fullPath = path126.isAbsolute(manifestFile) ? manifestFile : path126.join(workingDir, manifestFile);
|
|
113603
114233
|
if (!fs94.existsSync(fullPath)) {
|
|
113604
114234
|
continue;
|
|
113605
114235
|
}
|
|
@@ -113616,7 +114246,7 @@ var sbom_generate = createSwarmTool({
|
|
|
113616
114246
|
const bom = generateCycloneDX(allComponents);
|
|
113617
114247
|
const bomJson = serializeCycloneDX(bom);
|
|
113618
114248
|
const filename = generateSbomFilename();
|
|
113619
|
-
const outputPath =
|
|
114249
|
+
const outputPath = path126.join(outputDir, filename);
|
|
113620
114250
|
fs94.writeFileSync(outputPath, bomJson, "utf-8");
|
|
113621
114251
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
113622
114252
|
try {
|
|
@@ -113660,7 +114290,7 @@ var sbom_generate = createSwarmTool({
|
|
|
113660
114290
|
init_zod();
|
|
113661
114291
|
init_create_tool();
|
|
113662
114292
|
import * as fs95 from "node:fs";
|
|
113663
|
-
import * as
|
|
114293
|
+
import * as path127 from "node:path";
|
|
113664
114294
|
var SPEC_CANDIDATES = [
|
|
113665
114295
|
"openapi.json",
|
|
113666
114296
|
"openapi.yaml",
|
|
@@ -113692,12 +114322,12 @@ function normalizePath4(p) {
|
|
|
113692
114322
|
}
|
|
113693
114323
|
function discoverSpecFile(cwd, specFileArg) {
|
|
113694
114324
|
if (specFileArg) {
|
|
113695
|
-
const resolvedPath =
|
|
113696
|
-
const normalizedCwd = cwd.endsWith(
|
|
114325
|
+
const resolvedPath = path127.resolve(cwd, specFileArg);
|
|
114326
|
+
const normalizedCwd = cwd.endsWith(path127.sep) ? cwd : cwd + path127.sep;
|
|
113697
114327
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
113698
114328
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
113699
114329
|
}
|
|
113700
|
-
const ext =
|
|
114330
|
+
const ext = path127.extname(resolvedPath).toLowerCase();
|
|
113701
114331
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
113702
114332
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
113703
114333
|
}
|
|
@@ -113711,7 +114341,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
113711
114341
|
return resolvedPath;
|
|
113712
114342
|
}
|
|
113713
114343
|
for (const candidate of SPEC_CANDIDATES) {
|
|
113714
|
-
const candidatePath =
|
|
114344
|
+
const candidatePath = path127.resolve(cwd, candidate);
|
|
113715
114345
|
if (fs95.existsSync(candidatePath)) {
|
|
113716
114346
|
const stats = fs95.statSync(candidatePath);
|
|
113717
114347
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
@@ -113723,7 +114353,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
113723
114353
|
}
|
|
113724
114354
|
function parseSpec(specFile) {
|
|
113725
114355
|
const content = fs95.readFileSync(specFile, "utf-8");
|
|
113726
|
-
const ext =
|
|
114356
|
+
const ext = path127.extname(specFile).toLowerCase();
|
|
113727
114357
|
if (ext === ".json") {
|
|
113728
114358
|
return parseJsonSpec(content);
|
|
113729
114359
|
}
|
|
@@ -113799,7 +114429,7 @@ function extractRoutes(cwd) {
|
|
|
113799
114429
|
return;
|
|
113800
114430
|
}
|
|
113801
114431
|
for (const entry of entries) {
|
|
113802
|
-
const fullPath =
|
|
114432
|
+
const fullPath = path127.join(dir, entry.name);
|
|
113803
114433
|
if (entry.isSymbolicLink()) {
|
|
113804
114434
|
continue;
|
|
113805
114435
|
}
|
|
@@ -113809,7 +114439,7 @@ function extractRoutes(cwd) {
|
|
|
113809
114439
|
}
|
|
113810
114440
|
walkDir(fullPath);
|
|
113811
114441
|
} else if (entry.isFile()) {
|
|
113812
|
-
const ext =
|
|
114442
|
+
const ext = path127.extname(entry.name).toLowerCase();
|
|
113813
114443
|
const baseName = entry.name.toLowerCase();
|
|
113814
114444
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
113815
114445
|
continue;
|
|
@@ -113977,7 +114607,7 @@ init_bun_compat();
|
|
|
113977
114607
|
init_path_security();
|
|
113978
114608
|
init_create_tool();
|
|
113979
114609
|
import * as fs96 from "node:fs";
|
|
113980
|
-
import * as
|
|
114610
|
+
import * as path128 from "node:path";
|
|
113981
114611
|
var DEFAULT_MAX_RESULTS = 100;
|
|
113982
114612
|
var DEFAULT_MAX_LINES = 200;
|
|
113983
114613
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -114013,11 +114643,11 @@ function containsWindowsAttacks3(str) {
|
|
|
114013
114643
|
}
|
|
114014
114644
|
function isPathInWorkspace3(filePath, workspace) {
|
|
114015
114645
|
try {
|
|
114016
|
-
const resolvedPath =
|
|
114646
|
+
const resolvedPath = path128.resolve(workspace, filePath);
|
|
114017
114647
|
const realWorkspace = fs96.realpathSync(workspace);
|
|
114018
114648
|
const realResolvedPath = fs96.realpathSync(resolvedPath);
|
|
114019
|
-
const relativePath =
|
|
114020
|
-
if (relativePath.startsWith("..") ||
|
|
114649
|
+
const relativePath = path128.relative(realWorkspace, realResolvedPath);
|
|
114650
|
+
if (relativePath.startsWith("..") || path128.isAbsolute(relativePath)) {
|
|
114021
114651
|
return false;
|
|
114022
114652
|
}
|
|
114023
114653
|
return true;
|
|
@@ -114030,11 +114660,11 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
114030
114660
|
}
|
|
114031
114661
|
function findRgInEnvPath() {
|
|
114032
114662
|
const searchPath = process.env.PATH ?? "";
|
|
114033
|
-
for (const dir of searchPath.split(
|
|
114663
|
+
for (const dir of searchPath.split(path128.delimiter)) {
|
|
114034
114664
|
if (!dir)
|
|
114035
114665
|
continue;
|
|
114036
114666
|
const isWindows = process.platform === "win32";
|
|
114037
|
-
const candidate =
|
|
114667
|
+
const candidate = path128.join(dir, isWindows ? "rg.exe" : "rg");
|
|
114038
114668
|
if (fs96.existsSync(candidate))
|
|
114039
114669
|
return candidate;
|
|
114040
114670
|
}
|
|
@@ -114164,8 +114794,8 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
114164
114794
|
try {
|
|
114165
114795
|
const entries = fs96.readdirSync(dir, { withFileTypes: true });
|
|
114166
114796
|
for (const entry of entries) {
|
|
114167
|
-
const fullPath =
|
|
114168
|
-
const relativePath =
|
|
114797
|
+
const fullPath = path128.join(dir, entry.name);
|
|
114798
|
+
const relativePath = path128.relative(workspace, fullPath);
|
|
114169
114799
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
114170
114800
|
continue;
|
|
114171
114801
|
}
|
|
@@ -114206,7 +114836,7 @@ async function fallbackSearch(opts) {
|
|
|
114206
114836
|
const matches = [];
|
|
114207
114837
|
let total = 0;
|
|
114208
114838
|
for (const file3 of files) {
|
|
114209
|
-
const fullPath =
|
|
114839
|
+
const fullPath = path128.join(opts.workspace, file3);
|
|
114210
114840
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
114211
114841
|
continue;
|
|
114212
114842
|
}
|
|
@@ -114574,7 +115204,7 @@ init_config();
|
|
|
114574
115204
|
init_schema();
|
|
114575
115205
|
init_create_tool();
|
|
114576
115206
|
import { mkdir as mkdir21, rename as rename9, writeFile as writeFile16 } from "node:fs/promises";
|
|
114577
|
-
import * as
|
|
115207
|
+
import * as path129 from "node:path";
|
|
114578
115208
|
var MAX_SPEC_BYTES = 256 * 1024;
|
|
114579
115209
|
var spec_write = createSwarmTool({
|
|
114580
115210
|
description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
|
|
@@ -114615,8 +115245,8 @@ var spec_write = createSwarmTool({
|
|
|
114615
115245
|
reason: 'spec must contain at least one top-level "# Heading"'
|
|
114616
115246
|
}, null, 2);
|
|
114617
115247
|
}
|
|
114618
|
-
const target =
|
|
114619
|
-
await mkdir21(
|
|
115248
|
+
const target = path129.join(directory, ".swarm", "spec.md");
|
|
115249
|
+
await mkdir21(path129.dirname(target), { recursive: true });
|
|
114620
115250
|
const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
114621
115251
|
let finalContent = content;
|
|
114622
115252
|
if (mode === "append") {
|
|
@@ -114645,13 +115275,13 @@ init_zod();
|
|
|
114645
115275
|
init_loader();
|
|
114646
115276
|
import {
|
|
114647
115277
|
existsSync as existsSync74,
|
|
114648
|
-
mkdirSync as
|
|
115278
|
+
mkdirSync as mkdirSync33,
|
|
114649
115279
|
readFileSync as readFileSync64,
|
|
114650
115280
|
renameSync as renameSync20,
|
|
114651
115281
|
unlinkSync as unlinkSync16,
|
|
114652
115282
|
writeFileSync as writeFileSync24
|
|
114653
115283
|
} from "node:fs";
|
|
114654
|
-
import
|
|
115284
|
+
import path130 from "node:path";
|
|
114655
115285
|
init_create_tool();
|
|
114656
115286
|
init_resolve_working_directory();
|
|
114657
115287
|
var VerdictSchema2 = exports_external.object({
|
|
@@ -114781,7 +115411,7 @@ var submit_phase_council_verdicts = createSwarmTool({
|
|
|
114781
115411
|
}
|
|
114782
115412
|
});
|
|
114783
115413
|
function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
114784
|
-
const mutationGatePath =
|
|
115414
|
+
const mutationGatePath = path130.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
|
|
114785
115415
|
try {
|
|
114786
115416
|
const raw = readFileSync64(mutationGatePath, "utf-8");
|
|
114787
115417
|
const parsed = JSON.parse(raw);
|
|
@@ -114843,9 +115473,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
|
114843
115473
|
}
|
|
114844
115474
|
}
|
|
114845
115475
|
function writePhaseCouncilEvidence(workingDir, synthesis) {
|
|
114846
|
-
const evidenceDir =
|
|
114847
|
-
|
|
114848
|
-
const evidenceFile =
|
|
115476
|
+
const evidenceDir = path130.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
|
|
115477
|
+
mkdirSync33(evidenceDir, { recursive: true });
|
|
115478
|
+
const evidenceFile = path130.join(evidenceDir, "phase-council.json");
|
|
114849
115479
|
const evidenceBundle = {
|
|
114850
115480
|
entries: [
|
|
114851
115481
|
{
|
|
@@ -114998,16 +115628,20 @@ var swarm_memory_propose = createSwarmTool({
|
|
|
114998
115628
|
}, {
|
|
114999
115629
|
config: config3.memory
|
|
115000
115630
|
});
|
|
115001
|
-
|
|
115002
|
-
|
|
115003
|
-
|
|
115004
|
-
|
|
115005
|
-
|
|
115006
|
-
|
|
115007
|
-
|
|
115008
|
-
|
|
115009
|
-
|
|
115010
|
-
|
|
115631
|
+
try {
|
|
115632
|
+
const proposal = await gateway.propose(parsed.data);
|
|
115633
|
+
return JSON.stringify({
|
|
115634
|
+
success: proposal.status !== "rejected",
|
|
115635
|
+
proposal_id: proposal.id,
|
|
115636
|
+
status: proposal.status,
|
|
115637
|
+
operation: proposal.operation,
|
|
115638
|
+
memory_id: proposal.proposedRecord?.id,
|
|
115639
|
+
rejection_reason: proposal.rejectionReason,
|
|
115640
|
+
message: proposal.status === "pending" ? "Memory proposal created. Durable memory was not written." : "Memory proposal was captured with policy rejection metadata."
|
|
115641
|
+
}, null, 2);
|
|
115642
|
+
} finally {
|
|
115643
|
+
await gateway.dispose();
|
|
115644
|
+
}
|
|
115011
115645
|
}
|
|
115012
115646
|
});
|
|
115013
115647
|
var _internals51 = {
|
|
@@ -115071,19 +115705,23 @@ var swarm_memory_recall = createSwarmTool({
|
|
|
115071
115705
|
}, {
|
|
115072
115706
|
config: config3.memory
|
|
115073
115707
|
});
|
|
115074
|
-
|
|
115075
|
-
|
|
115076
|
-
|
|
115077
|
-
|
|
115078
|
-
|
|
115079
|
-
|
|
115080
|
-
|
|
115081
|
-
|
|
115082
|
-
|
|
115083
|
-
|
|
115084
|
-
|
|
115085
|
-
|
|
115086
|
-
|
|
115708
|
+
try {
|
|
115709
|
+
const bundle = await gateway.recall(parsed.data);
|
|
115710
|
+
return JSON.stringify({
|
|
115711
|
+
success: true,
|
|
115712
|
+
bundle_id: bundle.id,
|
|
115713
|
+
memory_ids: bundle.items.map((item) => item.record.id),
|
|
115714
|
+
total: bundle.items.length,
|
|
115715
|
+
token_estimate: bundle.tokenEstimate,
|
|
115716
|
+
signals: bundle.items.map((item) => ({
|
|
115717
|
+
memory_id: item.record.id,
|
|
115718
|
+
...item.signals
|
|
115719
|
+
})),
|
|
115720
|
+
prompt_block: bundle.promptBlock
|
|
115721
|
+
}, null, 2);
|
|
115722
|
+
} finally {
|
|
115723
|
+
await gateway.dispose();
|
|
115724
|
+
}
|
|
115087
115725
|
}
|
|
115088
115726
|
});
|
|
115089
115727
|
var RecallArgsSchema = exports_external.object({
|
|
@@ -115106,7 +115744,7 @@ init_zod();
|
|
|
115106
115744
|
init_path_security();
|
|
115107
115745
|
init_create_tool();
|
|
115108
115746
|
import * as fs97 from "node:fs";
|
|
115109
|
-
import * as
|
|
115747
|
+
import * as path131 from "node:path";
|
|
115110
115748
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
115111
115749
|
function containsWindowsAttacks4(str) {
|
|
115112
115750
|
if (/:[^\\/]/.test(str))
|
|
@@ -115120,14 +115758,14 @@ function containsWindowsAttacks4(str) {
|
|
|
115120
115758
|
}
|
|
115121
115759
|
function isPathInWorkspace4(filePath, workspace) {
|
|
115122
115760
|
try {
|
|
115123
|
-
const resolvedPath =
|
|
115761
|
+
const resolvedPath = path131.resolve(workspace, filePath);
|
|
115124
115762
|
if (!fs97.existsSync(resolvedPath)) {
|
|
115125
115763
|
return true;
|
|
115126
115764
|
}
|
|
115127
115765
|
const realWorkspace = fs97.realpathSync(workspace);
|
|
115128
115766
|
const realResolvedPath = fs97.realpathSync(resolvedPath);
|
|
115129
|
-
const relativePath =
|
|
115130
|
-
if (relativePath.startsWith("..") ||
|
|
115767
|
+
const relativePath = path131.relative(realWorkspace, realResolvedPath);
|
|
115768
|
+
if (relativePath.startsWith("..") || path131.isAbsolute(relativePath)) {
|
|
115131
115769
|
return false;
|
|
115132
115770
|
}
|
|
115133
115771
|
return true;
|
|
@@ -115335,7 +115973,7 @@ var suggestPatch = createSwarmTool({
|
|
|
115335
115973
|
});
|
|
115336
115974
|
continue;
|
|
115337
115975
|
}
|
|
115338
|
-
const fullPath =
|
|
115976
|
+
const fullPath = path131.resolve(directory, change.file);
|
|
115339
115977
|
if (!fs97.existsSync(fullPath)) {
|
|
115340
115978
|
errors5.push({
|
|
115341
115979
|
success: false,
|
|
@@ -115639,11 +116277,11 @@ var lean_turbo_acquire_locks = createSwarmTool({
|
|
|
115639
116277
|
init_zod();
|
|
115640
116278
|
init_constants();
|
|
115641
116279
|
import * as fs99 from "node:fs";
|
|
115642
|
-
import * as
|
|
116280
|
+
import * as path133 from "node:path";
|
|
115643
116281
|
|
|
115644
116282
|
// src/turbo/lean/conflicts.ts
|
|
115645
116283
|
import * as fs98 from "node:fs";
|
|
115646
|
-
import * as
|
|
116284
|
+
import * as path132 from "node:path";
|
|
115647
116285
|
var DEFAULT_GLOBAL_FILES = [
|
|
115648
116286
|
"package.json",
|
|
115649
116287
|
"package-lock.json",
|
|
@@ -115770,7 +116408,7 @@ function isProtectedPath2(normalizedPath) {
|
|
|
115770
116408
|
return false;
|
|
115771
116409
|
}
|
|
115772
116410
|
function readTaskScopes(directory, taskId) {
|
|
115773
|
-
const scopePath =
|
|
116411
|
+
const scopePath = path132.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
|
|
115774
116412
|
try {
|
|
115775
116413
|
if (!fs98.existsSync(scopePath)) {
|
|
115776
116414
|
return null;
|
|
@@ -116158,7 +116796,7 @@ function createEmptyPlan(phaseNumber, planId) {
|
|
|
116158
116796
|
// src/tools/lean-turbo-plan-lanes.ts
|
|
116159
116797
|
init_create_tool();
|
|
116160
116798
|
function readPlanJson(directory) {
|
|
116161
|
-
const planPath =
|
|
116799
|
+
const planPath = path133.join(directory, ".swarm", "plan.json");
|
|
116162
116800
|
if (!fs99.existsSync(planPath)) {
|
|
116163
116801
|
return null;
|
|
116164
116802
|
}
|
|
@@ -116213,7 +116851,7 @@ init_config();
|
|
|
116213
116851
|
// src/turbo/lean/reviewer.ts
|
|
116214
116852
|
init_state();
|
|
116215
116853
|
import * as fs100 from "node:fs/promises";
|
|
116216
|
-
import * as
|
|
116854
|
+
import * as path134 from "node:path";
|
|
116217
116855
|
init_state3();
|
|
116218
116856
|
var DEFAULT_CONFIG3 = {
|
|
116219
116857
|
reviewerAgent: "",
|
|
@@ -116329,9 +116967,9 @@ function parseReviewerVerdict(responseText) {
|
|
|
116329
116967
|
return { verdict, reason };
|
|
116330
116968
|
}
|
|
116331
116969
|
async function writeReviewerEvidence(directory, phase, verdict, reason) {
|
|
116332
|
-
const evidenceDir =
|
|
116970
|
+
const evidenceDir = path134.join(directory, ".swarm", "evidence", String(phase));
|
|
116333
116971
|
await fs100.mkdir(evidenceDir, { recursive: true });
|
|
116334
|
-
const evidencePath =
|
|
116972
|
+
const evidencePath = path134.join(evidenceDir, "lean-turbo-reviewer.json");
|
|
116335
116973
|
const content = JSON.stringify({
|
|
116336
116974
|
phase,
|
|
116337
116975
|
verdict,
|
|
@@ -117136,7 +117774,7 @@ var lean_turbo_status = createSwarmTool({
|
|
|
117136
117774
|
init_spec_schema();
|
|
117137
117775
|
init_create_tool();
|
|
117138
117776
|
import * as fs101 from "node:fs";
|
|
117139
|
-
import * as
|
|
117777
|
+
import * as path135 from "node:path";
|
|
117140
117778
|
var SPEC_FILE_NAME = "spec.md";
|
|
117141
117779
|
var SWARM_DIR2 = ".swarm";
|
|
117142
117780
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -117189,7 +117827,7 @@ var lint_spec = createSwarmTool({
|
|
|
117189
117827
|
async execute(_args, directory) {
|
|
117190
117828
|
const errors5 = [];
|
|
117191
117829
|
const warnings = [];
|
|
117192
|
-
const specPath =
|
|
117830
|
+
const specPath = path135.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
117193
117831
|
if (!fs101.existsSync(specPath)) {
|
|
117194
117832
|
const result2 = {
|
|
117195
117833
|
valid: false,
|
|
@@ -117260,12 +117898,12 @@ var lint_spec = createSwarmTool({
|
|
|
117260
117898
|
// src/tools/mutation-test.ts
|
|
117261
117899
|
init_zod();
|
|
117262
117900
|
import * as fs102 from "node:fs";
|
|
117263
|
-
import * as
|
|
117901
|
+
import * as path137 from "node:path";
|
|
117264
117902
|
|
|
117265
117903
|
// src/mutation/engine.ts
|
|
117266
117904
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
117267
117905
|
import { unlinkSync as unlinkSync17, writeFileSync as writeFileSync25 } from "node:fs";
|
|
117268
|
-
import * as
|
|
117906
|
+
import * as path136 from "node:path";
|
|
117269
117907
|
|
|
117270
117908
|
// src/mutation/equivalence.ts
|
|
117271
117909
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -117411,7 +118049,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
117411
118049
|
let patchFile;
|
|
117412
118050
|
try {
|
|
117413
118051
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
117414
|
-
patchFile =
|
|
118052
|
+
patchFile = path136.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
117415
118053
|
try {
|
|
117416
118054
|
writeFileSync25(patchFile, patch.patch);
|
|
117417
118055
|
} catch (writeErr) {
|
|
@@ -117815,7 +118453,7 @@ var mutation_test = createSwarmTool({
|
|
|
117815
118453
|
];
|
|
117816
118454
|
for (const filePath of uniquePaths) {
|
|
117817
118455
|
try {
|
|
117818
|
-
const resolvedPath =
|
|
118456
|
+
const resolvedPath = path137.resolve(cwd, filePath);
|
|
117819
118457
|
sourceFiles.set(filePath, fs102.readFileSync(resolvedPath, "utf-8"));
|
|
117820
118458
|
} catch {}
|
|
117821
118459
|
}
|
|
@@ -117835,7 +118473,7 @@ init_zod();
|
|
|
117835
118473
|
init_manager2();
|
|
117836
118474
|
init_detector();
|
|
117837
118475
|
import * as fs103 from "node:fs";
|
|
117838
|
-
import * as
|
|
118476
|
+
import * as path138 from "node:path";
|
|
117839
118477
|
init_create_tool();
|
|
117840
118478
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
117841
118479
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -117901,7 +118539,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
117901
118539
|
if (languages?.length) {
|
|
117902
118540
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
117903
118541
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
117904
|
-
const ext =
|
|
118542
|
+
const ext = path138.extname(file3.path).toLowerCase();
|
|
117905
118543
|
const langDef = getLanguageForExtension(ext);
|
|
117906
118544
|
const fileProfile = getProfileForFile(file3.path);
|
|
117907
118545
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -117914,7 +118552,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
117914
118552
|
let skippedCount = 0;
|
|
117915
118553
|
for (const fileInfo of filesToCheck) {
|
|
117916
118554
|
const { path: filePath } = fileInfo;
|
|
117917
|
-
const fullPath =
|
|
118555
|
+
const fullPath = path138.isAbsolute(filePath) ? filePath : path138.join(directory, filePath);
|
|
117918
118556
|
const result = {
|
|
117919
118557
|
path: filePath,
|
|
117920
118558
|
language: "",
|
|
@@ -117963,7 +118601,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
117963
118601
|
results.push(result);
|
|
117964
118602
|
continue;
|
|
117965
118603
|
}
|
|
117966
|
-
const ext =
|
|
118604
|
+
const ext = path138.extname(filePath).toLowerCase();
|
|
117967
118605
|
const langDef = getLanguageForExtension(ext);
|
|
117968
118606
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
117969
118607
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -118061,7 +118699,7 @@ init_utils();
|
|
|
118061
118699
|
init_create_tool();
|
|
118062
118700
|
init_path_security();
|
|
118063
118701
|
import * as fs104 from "node:fs";
|
|
118064
|
-
import * as
|
|
118702
|
+
import * as path139 from "node:path";
|
|
118065
118703
|
var MAX_TEXT_LENGTH = 200;
|
|
118066
118704
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
118067
118705
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -118127,9 +118765,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
118127
118765
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
118128
118766
|
}
|
|
118129
118767
|
try {
|
|
118130
|
-
const resolvedPath =
|
|
118131
|
-
const normalizedCwd =
|
|
118132
|
-
const normalizedResolved =
|
|
118768
|
+
const resolvedPath = path139.resolve(paths);
|
|
118769
|
+
const normalizedCwd = path139.resolve(cwd);
|
|
118770
|
+
const normalizedResolved = path139.resolve(resolvedPath);
|
|
118133
118771
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
118134
118772
|
return {
|
|
118135
118773
|
error: "paths must be within the current working directory",
|
|
@@ -118145,7 +118783,7 @@ function validatePathsInput(paths, cwd) {
|
|
|
118145
118783
|
}
|
|
118146
118784
|
}
|
|
118147
118785
|
function isSupportedExtension(filePath) {
|
|
118148
|
-
const ext =
|
|
118786
|
+
const ext = path139.extname(filePath).toLowerCase();
|
|
118149
118787
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
118150
118788
|
}
|
|
118151
118789
|
function findSourceFiles3(dir, files = []) {
|
|
@@ -118160,7 +118798,7 @@ function findSourceFiles3(dir, files = []) {
|
|
|
118160
118798
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
118161
118799
|
continue;
|
|
118162
118800
|
}
|
|
118163
|
-
const fullPath =
|
|
118801
|
+
const fullPath = path139.join(dir, entry);
|
|
118164
118802
|
let stat8;
|
|
118165
118803
|
try {
|
|
118166
118804
|
stat8 = fs104.statSync(fullPath);
|
|
@@ -118272,7 +118910,7 @@ var todo_extract = createSwarmTool({
|
|
|
118272
118910
|
filesToScan.push(scanPath);
|
|
118273
118911
|
} else {
|
|
118274
118912
|
const errorResult = {
|
|
118275
|
-
error: `unsupported file extension: ${
|
|
118913
|
+
error: `unsupported file extension: ${path139.extname(scanPath)}`,
|
|
118276
118914
|
total: 0,
|
|
118277
118915
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
118278
118916
|
entries: []
|
|
@@ -118321,17 +118959,17 @@ init_schema();
|
|
|
118321
118959
|
init_qa_gate_profile();
|
|
118322
118960
|
init_gate_evidence();
|
|
118323
118961
|
import * as fs108 from "node:fs";
|
|
118324
|
-
import * as
|
|
118962
|
+
import * as path143 from "node:path";
|
|
118325
118963
|
|
|
118326
118964
|
// src/hooks/diff-scope.ts
|
|
118327
118965
|
init_bun_compat();
|
|
118328
118966
|
import * as fs106 from "node:fs";
|
|
118329
|
-
import * as
|
|
118967
|
+
import * as path141 from "node:path";
|
|
118330
118968
|
|
|
118331
118969
|
// src/utils/gitignore-warning.ts
|
|
118332
118970
|
init_bun_compat();
|
|
118333
118971
|
import * as fs105 from "node:fs";
|
|
118334
|
-
import * as
|
|
118972
|
+
import * as path140 from "node:path";
|
|
118335
118973
|
var _internals58 = { bunSpawn };
|
|
118336
118974
|
var _swarmGitExcludedChecked = false;
|
|
118337
118975
|
function fileCoversSwarm(content) {
|
|
@@ -118405,10 +119043,10 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
118405
119043
|
const excludeRelPath = excludePathRaw.trim();
|
|
118406
119044
|
if (!excludeRelPath)
|
|
118407
119045
|
return;
|
|
118408
|
-
const excludePath =
|
|
119046
|
+
const excludePath = path140.isAbsolute(excludeRelPath) ? excludeRelPath : path140.join(directory, excludeRelPath);
|
|
118409
119047
|
if (checkIgnoreExitCode !== 0) {
|
|
118410
119048
|
try {
|
|
118411
|
-
fs105.mkdirSync(
|
|
119049
|
+
fs105.mkdirSync(path140.dirname(excludePath), { recursive: true });
|
|
118412
119050
|
let existing = "";
|
|
118413
119051
|
try {
|
|
118414
119052
|
existing = fs105.readFileSync(excludePath, "utf8");
|
|
@@ -118452,7 +119090,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
118452
119090
|
var _internals59 = { bunSpawn };
|
|
118453
119091
|
function getDeclaredScope(taskId, directory) {
|
|
118454
119092
|
try {
|
|
118455
|
-
const planPath =
|
|
119093
|
+
const planPath = path141.join(directory, ".swarm", "plan.json");
|
|
118456
119094
|
if (!fs106.existsSync(planPath))
|
|
118457
119095
|
return null;
|
|
118458
119096
|
const raw = fs106.readFileSync(planPath, "utf-8");
|
|
@@ -118558,7 +119196,7 @@ init_telemetry();
|
|
|
118558
119196
|
// src/turbo/lean/task-completion.ts
|
|
118559
119197
|
init_file_locks();
|
|
118560
119198
|
import * as fs107 from "node:fs";
|
|
118561
|
-
import * as
|
|
119199
|
+
import * as path142 from "node:path";
|
|
118562
119200
|
var _internals60 = {
|
|
118563
119201
|
listActiveLocks,
|
|
118564
119202
|
verifyLeanTurboTaskCompletion
|
|
@@ -118577,7 +119215,7 @@ var TIER_3_PATTERNS = [
|
|
|
118577
119215
|
];
|
|
118578
119216
|
function matchesTier3Pattern(files) {
|
|
118579
119217
|
for (const file3 of files) {
|
|
118580
|
-
const fileName =
|
|
119218
|
+
const fileName = path142.basename(file3);
|
|
118581
119219
|
for (const pattern of TIER_3_PATTERNS) {
|
|
118582
119220
|
if (pattern.test(fileName)) {
|
|
118583
119221
|
return true;
|
|
@@ -118589,7 +119227,7 @@ function matchesTier3Pattern(files) {
|
|
|
118589
119227
|
function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
118590
119228
|
let persisted = null;
|
|
118591
119229
|
try {
|
|
118592
|
-
const statePath =
|
|
119230
|
+
const statePath = path142.join(directory, ".swarm", "turbo-state.json");
|
|
118593
119231
|
if (!fs107.existsSync(statePath)) {
|
|
118594
119232
|
return {
|
|
118595
119233
|
ok: false,
|
|
@@ -118673,11 +119311,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
118673
119311
|
};
|
|
118674
119312
|
}
|
|
118675
119313
|
const phase = runState.phase ?? 0;
|
|
118676
|
-
const evidencePath =
|
|
118677
|
-
const expectedDir =
|
|
118678
|
-
const resolvedPath =
|
|
118679
|
-
const resolvedDir =
|
|
118680
|
-
if (!resolvedPath.startsWith(resolvedDir +
|
|
119314
|
+
const evidencePath = path142.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
|
|
119315
|
+
const expectedDir = path142.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
|
|
119316
|
+
const resolvedPath = path142.resolve(evidencePath);
|
|
119317
|
+
const resolvedDir = path142.resolve(expectedDir);
|
|
119318
|
+
if (!resolvedPath.startsWith(resolvedDir + path142.sep) && resolvedPath !== resolvedDir) {
|
|
118681
119319
|
return {
|
|
118682
119320
|
ok: false,
|
|
118683
119321
|
reason: `Lane ID causes path traversal: ${lane.laneId}`,
|
|
@@ -118717,7 +119355,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
|
|
|
118717
119355
|
}
|
|
118718
119356
|
let filesTouched = [];
|
|
118719
119357
|
try {
|
|
118720
|
-
const planPath =
|
|
119358
|
+
const planPath = path142.join(directory, ".swarm", "plan.json");
|
|
118721
119359
|
const planRaw = fs107.readFileSync(planPath, "utf-8");
|
|
118722
119360
|
const plan = JSON.parse(planRaw);
|
|
118723
119361
|
for (const planPhase of plan.phases ?? []) {
|
|
@@ -118801,7 +119439,7 @@ var TIER_3_PATTERNS2 = [
|
|
|
118801
119439
|
];
|
|
118802
119440
|
function matchesTier3Pattern2(files) {
|
|
118803
119441
|
for (const file3 of files) {
|
|
118804
|
-
const fileName =
|
|
119442
|
+
const fileName = path143.basename(file3);
|
|
118805
119443
|
for (const pattern of TIER_3_PATTERNS2) {
|
|
118806
119444
|
if (pattern.test(fileName)) {
|
|
118807
119445
|
return true;
|
|
@@ -118840,7 +119478,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
118840
119478
|
if (!skipStandardTurboBypass && hasActiveTurboMode()) {
|
|
118841
119479
|
const resolvedDir2 = workingDirectory;
|
|
118842
119480
|
try {
|
|
118843
|
-
const planPath =
|
|
119481
|
+
const planPath = path143.join(resolvedDir2, ".swarm", "plan.json");
|
|
118844
119482
|
const planRaw = fs108.readFileSync(planPath, "utf-8");
|
|
118845
119483
|
const plan = JSON.parse(planRaw);
|
|
118846
119484
|
for (const planPhase of plan.phases ?? []) {
|
|
@@ -118918,7 +119556,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
118918
119556
|
}
|
|
118919
119557
|
if (resolvedDir) {
|
|
118920
119558
|
try {
|
|
118921
|
-
const planPath =
|
|
119559
|
+
const planPath = path143.join(resolvedDir, ".swarm", "plan.json");
|
|
118922
119560
|
const planRaw = fs108.readFileSync(planPath, "utf-8");
|
|
118923
119561
|
const plan = JSON.parse(planRaw);
|
|
118924
119562
|
for (const planPhase of plan.phases ?? []) {
|
|
@@ -119155,8 +119793,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
119155
119793
|
};
|
|
119156
119794
|
}
|
|
119157
119795
|
}
|
|
119158
|
-
normalizedDir =
|
|
119159
|
-
const pathParts = normalizedDir.split(
|
|
119796
|
+
normalizedDir = path143.normalize(args2.working_directory);
|
|
119797
|
+
const pathParts = normalizedDir.split(path143.sep);
|
|
119160
119798
|
if (pathParts.includes("..")) {
|
|
119161
119799
|
return {
|
|
119162
119800
|
success: false,
|
|
@@ -119166,10 +119804,10 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
119166
119804
|
]
|
|
119167
119805
|
};
|
|
119168
119806
|
}
|
|
119169
|
-
const resolvedDir =
|
|
119807
|
+
const resolvedDir = path143.resolve(normalizedDir);
|
|
119170
119808
|
try {
|
|
119171
119809
|
const realPath = fs108.realpathSync(resolvedDir);
|
|
119172
|
-
const planPath =
|
|
119810
|
+
const planPath = path143.join(realPath, ".swarm", "plan.json");
|
|
119173
119811
|
if (!fs108.existsSync(planPath)) {
|
|
119174
119812
|
return {
|
|
119175
119813
|
success: false,
|
|
@@ -119200,9 +119838,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
119200
119838
|
directory = fallbackDir;
|
|
119201
119839
|
}
|
|
119202
119840
|
if (fallbackDir && directory !== fallbackDir) {
|
|
119203
|
-
const canonicalDir = fs108.realpathSync(
|
|
119204
|
-
const canonicalRoot = fs108.realpathSync(
|
|
119205
|
-
if (canonicalDir.startsWith(canonicalRoot +
|
|
119841
|
+
const canonicalDir = fs108.realpathSync(path143.resolve(directory));
|
|
119842
|
+
const canonicalRoot = fs108.realpathSync(path143.resolve(fallbackDir));
|
|
119843
|
+
if (canonicalDir.startsWith(canonicalRoot + path143.sep)) {
|
|
119206
119844
|
return {
|
|
119207
119845
|
success: false,
|
|
119208
119846
|
message: `Invalid working_directory: "${directory}" is a subdirectory of ` + `the project root "${fallbackDir}". Pass the project root path or ` + `omit working_directory entirely.`,
|
|
@@ -119214,8 +119852,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
119214
119852
|
}
|
|
119215
119853
|
if (args2.status === "in_progress") {
|
|
119216
119854
|
try {
|
|
119217
|
-
const evidencePath =
|
|
119218
|
-
fs108.mkdirSync(
|
|
119855
|
+
const evidencePath = path143.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
119856
|
+
fs108.mkdirSync(path143.dirname(evidencePath), { recursive: true });
|
|
119219
119857
|
const fd = fs108.openSync(evidencePath, "wx");
|
|
119220
119858
|
let writeOk = false;
|
|
119221
119859
|
try {
|
|
@@ -119239,7 +119877,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
|
|
|
119239
119877
|
recoverTaskStateFromDelegations(args2.task_id, directory);
|
|
119240
119878
|
let phaseRequiresReviewer = true;
|
|
119241
119879
|
try {
|
|
119242
|
-
const planPath =
|
|
119880
|
+
const planPath = path143.join(directory, ".swarm", "plan.json");
|
|
119243
119881
|
const planRaw = fs108.readFileSync(planPath, "utf-8");
|
|
119244
119882
|
const plan = JSON.parse(planRaw);
|
|
119245
119883
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
@@ -119551,7 +120189,7 @@ init_ledger();
|
|
|
119551
120189
|
init_manager();
|
|
119552
120190
|
init_create_tool();
|
|
119553
120191
|
import fs109 from "node:fs";
|
|
119554
|
-
import
|
|
120192
|
+
import path144 from "node:path";
|
|
119555
120193
|
function normalizeVerdict(verdict) {
|
|
119556
120194
|
switch (verdict) {
|
|
119557
120195
|
case "APPROVED":
|
|
@@ -119599,7 +120237,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
119599
120237
|
entries: [evidenceEntry]
|
|
119600
120238
|
};
|
|
119601
120239
|
const filename = "drift-verifier.json";
|
|
119602
|
-
const relativePath =
|
|
120240
|
+
const relativePath = path144.join("evidence", String(phase), filename);
|
|
119603
120241
|
let validatedPath;
|
|
119604
120242
|
try {
|
|
119605
120243
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -119610,10 +120248,10 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
119610
120248
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
119611
120249
|
}, null, 2);
|
|
119612
120250
|
}
|
|
119613
|
-
const evidenceDir =
|
|
120251
|
+
const evidenceDir = path144.dirname(validatedPath);
|
|
119614
120252
|
try {
|
|
119615
120253
|
await fs109.promises.mkdir(evidenceDir, { recursive: true });
|
|
119616
|
-
const tempPath =
|
|
120254
|
+
const tempPath = path144.join(evidenceDir, `.${filename}.tmp`);
|
|
119617
120255
|
await fs109.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
119618
120256
|
await fs109.promises.rename(tempPath, validatedPath);
|
|
119619
120257
|
let snapshotInfo;
|
|
@@ -119709,7 +120347,7 @@ var write_drift_evidence = createSwarmTool({
|
|
|
119709
120347
|
init_zod();
|
|
119710
120348
|
init_loader();
|
|
119711
120349
|
import fs110 from "node:fs";
|
|
119712
|
-
import
|
|
120350
|
+
import path145 from "node:path";
|
|
119713
120351
|
init_utils2();
|
|
119714
120352
|
init_manager();
|
|
119715
120353
|
init_create_tool();
|
|
@@ -119797,7 +120435,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
119797
120435
|
timestamp: synthesis.timestamp
|
|
119798
120436
|
};
|
|
119799
120437
|
const filename = "final-council.json";
|
|
119800
|
-
const relativePath =
|
|
120438
|
+
const relativePath = path145.join("evidence", filename);
|
|
119801
120439
|
let validatedPath;
|
|
119802
120440
|
try {
|
|
119803
120441
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -119811,10 +120449,10 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
|
|
|
119811
120449
|
const evidenceContent = {
|
|
119812
120450
|
entries: [evidenceEntry]
|
|
119813
120451
|
};
|
|
119814
|
-
const evidenceDir =
|
|
120452
|
+
const evidenceDir = path145.dirname(validatedPath);
|
|
119815
120453
|
try {
|
|
119816
120454
|
await fs110.promises.mkdir(evidenceDir, { recursive: true });
|
|
119817
|
-
const tempPath =
|
|
120455
|
+
const tempPath = path145.join(evidenceDir, `.${filename}.tmp`);
|
|
119818
120456
|
await fs110.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
119819
120457
|
await fs110.promises.rename(tempPath, validatedPath);
|
|
119820
120458
|
return JSON.stringify({
|
|
@@ -119873,7 +120511,7 @@ init_zod();
|
|
|
119873
120511
|
init_utils2();
|
|
119874
120512
|
init_create_tool();
|
|
119875
120513
|
import fs111 from "node:fs";
|
|
119876
|
-
import
|
|
120514
|
+
import path146 from "node:path";
|
|
119877
120515
|
function normalizeVerdict2(verdict) {
|
|
119878
120516
|
switch (verdict) {
|
|
119879
120517
|
case "APPROVED":
|
|
@@ -119921,7 +120559,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
119921
120559
|
entries: [evidenceEntry]
|
|
119922
120560
|
};
|
|
119923
120561
|
const filename = "hallucination-guard.json";
|
|
119924
|
-
const relativePath =
|
|
120562
|
+
const relativePath = path146.join("evidence", String(phase), filename);
|
|
119925
120563
|
let validatedPath;
|
|
119926
120564
|
try {
|
|
119927
120565
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -119932,10 +120570,10 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
119932
120570
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
119933
120571
|
}, null, 2);
|
|
119934
120572
|
}
|
|
119935
|
-
const evidenceDir =
|
|
120573
|
+
const evidenceDir = path146.dirname(validatedPath);
|
|
119936
120574
|
try {
|
|
119937
120575
|
await fs111.promises.mkdir(evidenceDir, { recursive: true });
|
|
119938
|
-
const tempPath =
|
|
120576
|
+
const tempPath = path146.join(evidenceDir, `.${filename}.tmp`);
|
|
119939
120577
|
await fs111.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
119940
120578
|
await fs111.promises.rename(tempPath, validatedPath);
|
|
119941
120579
|
return JSON.stringify({
|
|
@@ -119984,7 +120622,7 @@ init_zod();
|
|
|
119984
120622
|
init_utils2();
|
|
119985
120623
|
init_create_tool();
|
|
119986
120624
|
import fs112 from "node:fs";
|
|
119987
|
-
import
|
|
120625
|
+
import path147 from "node:path";
|
|
119988
120626
|
function normalizeVerdict3(verdict) {
|
|
119989
120627
|
switch (verdict) {
|
|
119990
120628
|
case "PASS":
|
|
@@ -120058,7 +120696,7 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
120058
120696
|
entries: [evidenceEntry]
|
|
120059
120697
|
};
|
|
120060
120698
|
const filename = "mutation-gate.json";
|
|
120061
|
-
const relativePath =
|
|
120699
|
+
const relativePath = path147.join("evidence", String(phase), filename);
|
|
120062
120700
|
let validatedPath;
|
|
120063
120701
|
try {
|
|
120064
120702
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -120069,10 +120707,10 @@ async function executeWriteMutationEvidence(args2, directory) {
|
|
|
120069
120707
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
120070
120708
|
}, null, 2);
|
|
120071
120709
|
}
|
|
120072
|
-
const evidenceDir =
|
|
120710
|
+
const evidenceDir = path147.dirname(validatedPath);
|
|
120073
120711
|
try {
|
|
120074
120712
|
await fs112.promises.mkdir(evidenceDir, { recursive: true });
|
|
120075
|
-
const tempPath =
|
|
120713
|
+
const tempPath = path147.join(evidenceDir, `.${filename}.tmp`);
|
|
120076
120714
|
await fs112.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
120077
120715
|
await fs112.promises.rename(tempPath, validatedPath);
|
|
120078
120716
|
return JSON.stringify({
|
|
@@ -120422,7 +121060,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
120422
121060
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
120423
121061
|
preflightTriggerManager = new PTM(automationConfig);
|
|
120424
121062
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
120425
|
-
const swarmDir =
|
|
121063
|
+
const swarmDir = path149.resolve(ctx.directory, ".swarm");
|
|
120426
121064
|
statusArtifact = new ASA(swarmDir);
|
|
120427
121065
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
120428
121066
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -120601,30 +121239,29 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
120601
121239
|
swarm_command: createSwarmCommandTool(agentDefinitionMap)
|
|
120602
121240
|
},
|
|
120603
121241
|
config: async (opencodeConfig) => {
|
|
120604
|
-
|
|
120605
|
-
|
|
120606
|
-
|
|
120607
|
-
|
|
120608
|
-
opencodeConfig.agent = { ...agents };
|
|
120609
|
-
} else {
|
|
120610
|
-
Object.assign(opencodeConfig.agent, agents);
|
|
121242
|
+
const isObjectRecord = (value) => typeof value === "object" && value !== null;
|
|
121243
|
+
const pluginConfig = opencodeConfig;
|
|
121244
|
+
if (!isObjectRecord(pluginConfig.agent)) {
|
|
121245
|
+
pluginConfig.agent = {};
|
|
120611
121246
|
}
|
|
121247
|
+
const agentConfig = pluginConfig.agent;
|
|
121248
|
+
Object.assign(agentConfig, agents);
|
|
120612
121249
|
const autoSelect = config3?.auto_select_architect;
|
|
120613
121250
|
if (autoSelect) {
|
|
120614
121251
|
const hasArchitect = Object.keys(agents).some((name2) => stripKnownSwarmPrefix(name2) === "architect");
|
|
120615
121252
|
if (hasArchitect) {
|
|
120616
121253
|
for (const builtin of ["build", "plan"]) {
|
|
120617
|
-
const existing =
|
|
120618
|
-
if (existing &&
|
|
121254
|
+
const existing = agentConfig[builtin];
|
|
121255
|
+
if (isObjectRecord(existing) && existing.disable === true) {
|
|
120619
121256
|
continue;
|
|
120620
121257
|
}
|
|
120621
|
-
|
|
120622
|
-
...existing
|
|
121258
|
+
agentConfig[builtin] = {
|
|
121259
|
+
...isObjectRecord(existing) ? existing : {},
|
|
120623
121260
|
disable: true
|
|
120624
121261
|
};
|
|
120625
121262
|
}
|
|
120626
121263
|
if (autoSelect === true) {
|
|
120627
|
-
const primaryArchitects = Object.entries(agents).filter(([name2, cfg]) => stripKnownSwarmPrefix(name2) === "architect" && cfg.mode === "primary");
|
|
121264
|
+
const primaryArchitects = Object.entries(agents).filter(([name2, cfg]) => stripKnownSwarmPrefix(name2) === "architect" && isObjectRecord(cfg) && cfg.mode === "primary");
|
|
120628
121265
|
if (primaryArchitects.length > 1) {
|
|
120629
121266
|
const names = primaryArchitects.map(([n]) => n).join(", ");
|
|
120630
121267
|
addDeferredWarning(`[swarm] auto_select_architect is true but ${primaryArchitects.length} architect agents are primary (${names}). Consider setting auto_select_architect to a specific agent name.`);
|
|
@@ -120636,22 +121273,19 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
120636
121273
|
if (targetIsArchitect) {
|
|
120637
121274
|
for (const [name2, cfg] of Object.entries(agents)) {
|
|
120638
121275
|
if (stripKnownSwarmPrefix(name2) === "architect" && name2 !== targetName) {
|
|
120639
|
-
|
|
120640
|
-
|
|
120641
|
-
|
|
120642
|
-
|
|
120643
|
-
};
|
|
120644
|
-
}
|
|
121276
|
+
agentConfig[name2] = {
|
|
121277
|
+
...isObjectRecord(cfg) ? cfg : {},
|
|
121278
|
+
mode: "subagent"
|
|
121279
|
+
};
|
|
120645
121280
|
}
|
|
120646
121281
|
}
|
|
120647
|
-
|
|
120648
|
-
|
|
120649
|
-
|
|
120650
|
-
|
|
120651
|
-
|
|
120652
|
-
|
|
120653
|
-
|
|
120654
|
-
}
|
|
121282
|
+
const targetExisting = agentConfig[targetName];
|
|
121283
|
+
const targetAgent = agents[targetName];
|
|
121284
|
+
agentConfig[targetName] = {
|
|
121285
|
+
...isObjectRecord(targetExisting) ? targetExisting : {},
|
|
121286
|
+
...isObjectRecord(targetAgent) ? targetAgent : {},
|
|
121287
|
+
mode: "primary"
|
|
121288
|
+
};
|
|
120655
121289
|
} else {
|
|
120656
121290
|
addDeferredWarning(`[swarm] auto_select_architect is set to "${targetName}" but that is not a known architect agent. No architect demotion applied.`);
|
|
120657
121291
|
}
|
|
@@ -121006,7 +121640,7 @@ ${promptRaw}`;
|
|
|
121006
121640
|
"ci-failure-resolver": "CI/CD failure resolution"
|
|
121007
121641
|
};
|
|
121008
121642
|
const skillPaths = topSkills.map((s) => {
|
|
121009
|
-
const dirName =
|
|
121643
|
+
const dirName = path149.basename(path149.dirname(s.skillPath));
|
|
121010
121644
|
const desc = SKILL_DESCRIPTIONS[dirName] ?? dirName;
|
|
121011
121645
|
return `file:${s.skillPath} (-- ${desc})`;
|
|
121012
121646
|
}).join(", ");
|
|
@@ -121015,7 +121649,7 @@ ${promptRaw}`;
|
|
|
121015
121649
|
|
|
121016
121650
|
${promptRaw}`;
|
|
121017
121651
|
argsRecord.prompt = newPrompt;
|
|
121018
|
-
const skillNames = topSkills.map((s) => `${
|
|
121652
|
+
const skillNames = topSkills.map((s) => `${path149.basename(s.skillPath)} (score: ${s.score.toFixed(2)})`).join(", ");
|
|
121019
121653
|
console.warn(`[skill-propagation-gate] Injected skills: ${skillNames}`);
|
|
121020
121654
|
for (const skill of topSkills) {
|
|
121021
121655
|
try {
|