opencode-swarm 6.74.1 → 6.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/evidence-lock.adversarial.test.d.ts +8 -0
- package/dist/__tests__/evidence-lock.test.d.ts +6 -0
- package/dist/__tests__/gate-evidence.adversarial.test.d.ts +7 -0
- package/dist/cli/index.js +1482 -1127
- package/dist/config/schema.d.ts +11 -0
- package/dist/evidence/lock.d.ts +36 -0
- package/dist/index.js +5385 -5061
- package/dist/parallel/dispatcher/index.d.ts +2 -0
- package/dist/parallel/dispatcher/noop-dispatcher.d.ts +18 -0
- package/dist/parallel/dispatcher/noop-dispatcher.test.d.ts +10 -0
- package/dist/parallel/dispatcher/types.d.ts +33 -0
- package/dist/parallel/index.d.ts +1 -0
- package/dist/plan/manager.cas-backoff.test.d.ts +10 -0
- package/dist/plan/manager.d.ts +17 -0
- package/dist/state/agent-run-context.d.ts +24 -0
- package/dist/state.agent-run-context.test.d.ts +10 -0
- package/dist/state.d.ts +16 -2
- package/dist/telemetry.d.ts +1 -1
- package/dist/tools/test-runner.d.ts +32 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -14063,6 +14063,36 @@ var init_plan_schema = __esm(() => {
|
|
|
14063
14063
|
});
|
|
14064
14064
|
});
|
|
14065
14065
|
|
|
14066
|
+
// src/telemetry.ts
|
|
14067
|
+
import * as os from "os";
|
|
14068
|
+
function emit(event, data) {
|
|
14069
|
+
try {
|
|
14070
|
+
if (_disabled || _writeStream === null) {
|
|
14071
|
+
return;
|
|
14072
|
+
}
|
|
14073
|
+
const line = JSON.stringify({
|
|
14074
|
+
timestamp: new Date().toISOString(),
|
|
14075
|
+
event,
|
|
14076
|
+
...data
|
|
14077
|
+
}) + os.EOL;
|
|
14078
|
+
_writeStream.write(line, (err) => {
|
|
14079
|
+
if (err) {
|
|
14080
|
+
_disabled = true;
|
|
14081
|
+
_writeStream = null;
|
|
14082
|
+
}
|
|
14083
|
+
});
|
|
14084
|
+
for (const listener of _listeners) {
|
|
14085
|
+
try {
|
|
14086
|
+
listener(event, data);
|
|
14087
|
+
} catch {}
|
|
14088
|
+
}
|
|
14089
|
+
} catch {}
|
|
14090
|
+
}
|
|
14091
|
+
var _writeStream = null, _listeners, _disabled = false;
|
|
14092
|
+
var init_telemetry = __esm(() => {
|
|
14093
|
+
_listeners = [];
|
|
14094
|
+
});
|
|
14095
|
+
|
|
14066
14096
|
// src/utils/spec-hash.ts
|
|
14067
14097
|
import { createHash } from "crypto";
|
|
14068
14098
|
import { readFile } from "fs/promises";
|
|
@@ -14275,34 +14305,6 @@ async function appendLedgerEvent(directory, eventInput, options) {
|
|
|
14275
14305
|
fs.renameSync(tempPath, ledgerPath);
|
|
14276
14306
|
return event;
|
|
14277
14307
|
}
|
|
14278
|
-
async function appendLedgerEventWithRetry(directory, eventInput, options) {
|
|
14279
|
-
const maxRetries = options.maxRetries ?? 3;
|
|
14280
|
-
const backoffBase = options.backoffMs ?? 10;
|
|
14281
|
-
let currentExpected = options.expectedHash;
|
|
14282
|
-
let attempt = 0;
|
|
14283
|
-
while (true) {
|
|
14284
|
-
try {
|
|
14285
|
-
return await appendLedgerEvent(directory, eventInput, {
|
|
14286
|
-
expectedHash: currentExpected,
|
|
14287
|
-
planHashAfter: options.planHashAfter
|
|
14288
|
-
});
|
|
14289
|
-
} catch (error49) {
|
|
14290
|
-
if (!(error49 instanceof LedgerStaleWriterError) || attempt >= maxRetries) {
|
|
14291
|
-
throw error49;
|
|
14292
|
-
}
|
|
14293
|
-
attempt++;
|
|
14294
|
-
const delayMs = backoffBase * 2 ** (attempt - 1);
|
|
14295
|
-
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
14296
|
-
if (options.verifyValid) {
|
|
14297
|
-
const stillValid = await options.verifyValid();
|
|
14298
|
-
if (!stillValid) {
|
|
14299
|
-
return null;
|
|
14300
|
-
}
|
|
14301
|
-
}
|
|
14302
|
-
currentExpected = computeCurrentPlanHash(directory);
|
|
14303
|
-
}
|
|
14304
|
-
}
|
|
14305
|
-
}
|
|
14306
14308
|
async function takeSnapshotEvent(directory, plan, options) {
|
|
14307
14309
|
const payloadHash = computePlanHash(plan);
|
|
14308
14310
|
const snapshotPayload = {
|
|
@@ -14481,6 +14483,39 @@ import {
|
|
|
14481
14483
|
} from "fs";
|
|
14482
14484
|
import * as fsPromises from "fs/promises";
|
|
14483
14485
|
import * as path3 from "path";
|
|
14486
|
+
async function retryCasWithBackoff(directory, eventInput, options) {
|
|
14487
|
+
const maxRetries = options.maxRetries ?? CAS_MAX_RETRIES;
|
|
14488
|
+
let currentExpected = options.expectedHash;
|
|
14489
|
+
let attempt = 0;
|
|
14490
|
+
while (true) {
|
|
14491
|
+
try {
|
|
14492
|
+
return await appendLedgerEvent(directory, eventInput, {
|
|
14493
|
+
expectedHash: currentExpected,
|
|
14494
|
+
planHashAfter: options.planHashAfter
|
|
14495
|
+
});
|
|
14496
|
+
} catch (error49) {
|
|
14497
|
+
if (!(error49 instanceof LedgerStaleWriterError) || attempt >= maxRetries) {
|
|
14498
|
+
throw error49;
|
|
14499
|
+
}
|
|
14500
|
+
attempt++;
|
|
14501
|
+
const base = Math.min(CAS_BACKOFF_START_MS * 2 ** (attempt - 1), CAS_BACKOFF_CAP_MS);
|
|
14502
|
+
const jitter = base * CAS_BACKOFF_JITTER * (Math.random() * 2 - 1);
|
|
14503
|
+
const delayMs = Math.max(1, Math.round(base + jitter));
|
|
14504
|
+
emit("plan_ledger_cas_retry", {
|
|
14505
|
+
attempt,
|
|
14506
|
+
expectedHashPrefix: currentExpected.slice(0, 8),
|
|
14507
|
+
delayMs
|
|
14508
|
+
});
|
|
14509
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
14510
|
+
if (options.verifyValid) {
|
|
14511
|
+
const stillValid = await options.verifyValid();
|
|
14512
|
+
if (!stillValid)
|
|
14513
|
+
return null;
|
|
14514
|
+
}
|
|
14515
|
+
currentExpected = computeCurrentPlanHash(directory);
|
|
14516
|
+
}
|
|
14517
|
+
}
|
|
14518
|
+
}
|
|
14484
14519
|
async function loadPlanJsonOnly(directory) {
|
|
14485
14520
|
const planJsonContent = await readSwarmFileAsync(directory, "plan.json");
|
|
14486
14521
|
if (planJsonContent !== null) {
|
|
@@ -14933,10 +14968,9 @@ async function savePlan(directory, plan, options) {
|
|
|
14933
14968
|
};
|
|
14934
14969
|
const capturedFromStatus = oldTask.status;
|
|
14935
14970
|
const capturedTaskId = task.id;
|
|
14936
|
-
await
|
|
14971
|
+
await retryCasWithBackoff(directory, eventInput, {
|
|
14937
14972
|
expectedHash: currentHash,
|
|
14938
14973
|
planHashAfter: hashAfter,
|
|
14939
|
-
maxRetries: 3,
|
|
14940
14974
|
verifyValid: async () => {
|
|
14941
14975
|
const onDisk = await loadPlanJsonOnly(directory);
|
|
14942
14976
|
if (!onDisk)
|
|
@@ -15308,10 +15342,11 @@ function migrateLegacyPlan(planContent, swarmId) {
|
|
|
15308
15342
|
};
|
|
15309
15343
|
return plan;
|
|
15310
15344
|
}
|
|
15311
|
-
var PlanConcurrentModificationError, startupLedgerCheckedWorkspaces, recoveryMutexes;
|
|
15345
|
+
var PlanConcurrentModificationError, startupLedgerCheckedWorkspaces, recoveryMutexes, CAS_BACKOFF_START_MS = 5, CAS_BACKOFF_CAP_MS = 250, CAS_BACKOFF_JITTER = 0.25, CAS_MAX_RETRIES = 3;
|
|
15312
15346
|
var init_manager = __esm(() => {
|
|
15313
15347
|
init_plan_schema();
|
|
15314
15348
|
init_utils2();
|
|
15349
|
+
init_telemetry();
|
|
15315
15350
|
init_utils();
|
|
15316
15351
|
init_spec_hash();
|
|
15317
15352
|
init_ledger();
|
|
@@ -15579,378 +15614,79 @@ var init_evidence_schema = __esm(() => {
|
|
|
15579
15614
|
});
|
|
15580
15615
|
});
|
|
15581
15616
|
|
|
15582
|
-
//
|
|
15583
|
-
|
|
15584
|
-
|
|
15585
|
-
|
|
15586
|
-
|
|
15587
|
-
|
|
15588
|
-
|
|
15589
|
-
|
|
15590
|
-
|
|
15591
|
-
|
|
15592
|
-
return "Invalid task ID: contains control characters";
|
|
15593
|
-
}
|
|
15594
|
-
}
|
|
15595
|
-
if (taskId.includes("..") || taskId.includes("/") || taskId.includes("\\")) {
|
|
15596
|
-
return "Invalid task ID: path traversal detected";
|
|
15597
|
-
}
|
|
15598
|
-
return;
|
|
15599
|
-
}
|
|
15600
|
-
function sanitizeTaskId(taskId) {
|
|
15601
|
-
const unsafeMsg = checkUnsafeChars(taskId);
|
|
15602
|
-
if (unsafeMsg) {
|
|
15603
|
-
throw new Error(unsafeMsg);
|
|
15604
|
-
}
|
|
15605
|
-
if (STRICT_TASK_ID_PATTERN.test(taskId) || RETRO_TASK_ID_REGEX.test(taskId) || INTERNAL_TOOL_ID_REGEX.test(taskId) || GENERAL_TASK_ID_REGEX.test(taskId)) {
|
|
15606
|
-
return taskId;
|
|
15607
|
-
}
|
|
15608
|
-
throw new Error(`Invalid task ID: must be alphanumeric (ASCII) with optional hyphens, underscores, or dots, got "${taskId}"`);
|
|
15609
|
-
}
|
|
15610
|
-
var STRICT_TASK_ID_PATTERN, RETRO_TASK_ID_REGEX, INTERNAL_TOOL_ID_REGEX, GENERAL_TASK_ID_REGEX;
|
|
15611
|
-
var init_task_id = __esm(() => {
|
|
15612
|
-
STRICT_TASK_ID_PATTERN = /^\d+\.\d+(\.\d+)*$/;
|
|
15613
|
-
RETRO_TASK_ID_REGEX = /^retro-\d+$/;
|
|
15614
|
-
INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build|secretscan)$/;
|
|
15615
|
-
GENERAL_TASK_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
15616
|
-
});
|
|
15617
|
-
|
|
15618
|
-
// src/evidence/manager.ts
|
|
15619
|
-
import { mkdirSync as mkdirSync2, readdirSync as readdirSync2, rmSync, statSync as statSync2 } from "fs";
|
|
15620
|
-
import * as fs3 from "fs/promises";
|
|
15621
|
-
import * as path5 from "path";
|
|
15622
|
-
function isValidEvidenceType(type) {
|
|
15623
|
-
return VALID_EVIDENCE_TYPES.includes(type);
|
|
15624
|
-
}
|
|
15625
|
-
async function saveEvidence(directory, taskId, evidence) {
|
|
15626
|
-
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
15627
|
-
const relativePath = path5.join("evidence", sanitizedTaskId, "evidence.json");
|
|
15628
|
-
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
15629
|
-
const evidenceDir = path5.dirname(evidencePath);
|
|
15630
|
-
let bundle;
|
|
15631
|
-
const existingContent = await readSwarmFileAsync(directory, relativePath);
|
|
15632
|
-
if (existingContent !== null) {
|
|
15633
|
-
try {
|
|
15634
|
-
const parsed = JSON.parse(existingContent);
|
|
15635
|
-
bundle = EvidenceBundleSchema.parse(parsed);
|
|
15636
|
-
} catch (error49) {
|
|
15637
|
-
warn(`Existing evidence bundle invalid for task ${sanitizedTaskId}, creating new: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
15638
|
-
const now = new Date().toISOString();
|
|
15639
|
-
bundle = {
|
|
15640
|
-
schema_version: "1.0.0",
|
|
15641
|
-
task_id: sanitizedTaskId,
|
|
15642
|
-
entries: [],
|
|
15643
|
-
created_at: now,
|
|
15644
|
-
updated_at: now
|
|
15645
|
-
};
|
|
15646
|
-
}
|
|
15647
|
-
} else {
|
|
15648
|
-
const now = new Date().toISOString();
|
|
15649
|
-
bundle = {
|
|
15650
|
-
schema_version: "1.0.0",
|
|
15651
|
-
task_id: sanitizedTaskId,
|
|
15652
|
-
entries: [],
|
|
15653
|
-
created_at: now,
|
|
15654
|
-
updated_at: now
|
|
15655
|
-
};
|
|
15656
|
-
}
|
|
15657
|
-
const MAX_BUNDLE_ENTRIES = 100;
|
|
15658
|
-
let entries = [...bundle.entries, evidence];
|
|
15659
|
-
if (entries.length > MAX_BUNDLE_ENTRIES) {
|
|
15660
|
-
entries = entries.slice(entries.length - MAX_BUNDLE_ENTRIES);
|
|
15661
|
-
}
|
|
15662
|
-
const updatedBundle = {
|
|
15663
|
-
...bundle,
|
|
15664
|
-
entries,
|
|
15665
|
-
updated_at: new Date().toISOString()
|
|
15617
|
+
// node_modules/graceful-fs/polyfills.js
|
|
15618
|
+
var require_polyfills = __commonJS((exports, module) => {
|
|
15619
|
+
var constants = __require("constants");
|
|
15620
|
+
var origCwd = process.cwd;
|
|
15621
|
+
var cwd = null;
|
|
15622
|
+
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
15623
|
+
process.cwd = function() {
|
|
15624
|
+
if (!cwd)
|
|
15625
|
+
cwd = origCwd.call(process);
|
|
15626
|
+
return cwd;
|
|
15666
15627
|
};
|
|
15667
|
-
const bundleJson = JSON.stringify(updatedBundle);
|
|
15668
|
-
if (bundleJson.length > EVIDENCE_MAX_JSON_BYTES) {
|
|
15669
|
-
throw new Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);
|
|
15670
|
-
}
|
|
15671
|
-
mkdirSync2(evidenceDir, { recursive: true });
|
|
15672
|
-
const tempPath = path5.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
15673
15628
|
try {
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
}
|
|
15682
|
-
return updatedBundle;
|
|
15683
|
-
}
|
|
15684
|
-
function isFlatRetrospective(parsed) {
|
|
15685
|
-
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && parsed.type === "retrospective" && !parsed.schema_version;
|
|
15686
|
-
}
|
|
15687
|
-
function remapLegacyTaskComplexity(entry) {
|
|
15688
|
-
const taskComplexity = entry.task_complexity;
|
|
15689
|
-
if (typeof taskComplexity === "string" && taskComplexity in LEGACY_TASK_COMPLEXITY_MAP) {
|
|
15690
|
-
return {
|
|
15691
|
-
...entry,
|
|
15692
|
-
task_complexity: LEGACY_TASK_COMPLEXITY_MAP[taskComplexity]
|
|
15629
|
+
process.cwd();
|
|
15630
|
+
} catch (er) {}
|
|
15631
|
+
if (typeof process.chdir === "function") {
|
|
15632
|
+
chdir = process.chdir;
|
|
15633
|
+
process.chdir = function(d) {
|
|
15634
|
+
cwd = null;
|
|
15635
|
+
chdir.call(process, d);
|
|
15693
15636
|
};
|
|
15637
|
+
if (Object.setPrototypeOf)
|
|
15638
|
+
Object.setPrototypeOf(process.chdir, chdir);
|
|
15694
15639
|
}
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
function
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15706
|
-
|
|
15707
|
-
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
const tempPath = path5.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
15729
|
-
try {
|
|
15730
|
-
await Bun.write(tempPath, bundleJson);
|
|
15731
|
-
await fs3.rename(tempPath, evidencePath);
|
|
15732
|
-
} catch (writeError) {
|
|
15733
|
-
try {
|
|
15734
|
-
rmSync(tempPath, { force: true });
|
|
15735
|
-
} catch {}
|
|
15736
|
-
warn(`Failed to persist repaired flat retrospective for task ${sanitizedTaskId}: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
15737
|
-
}
|
|
15738
|
-
return { status: "found", bundle: validated };
|
|
15739
|
-
} catch (error49) {
|
|
15740
|
-
warn(`Wrapped flat retrospective failed validation for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
15741
|
-
const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error49 instanceof Error ? error49.message : String(error49)];
|
|
15742
|
-
return { status: "invalid_schema", errors: errors3 };
|
|
15640
|
+
var chdir;
|
|
15641
|
+
module.exports = patch;
|
|
15642
|
+
function patch(fs3) {
|
|
15643
|
+
if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
15644
|
+
patchLchmod(fs3);
|
|
15645
|
+
}
|
|
15646
|
+
if (!fs3.lutimes) {
|
|
15647
|
+
patchLutimes(fs3);
|
|
15648
|
+
}
|
|
15649
|
+
fs3.chown = chownFix(fs3.chown);
|
|
15650
|
+
fs3.fchown = chownFix(fs3.fchown);
|
|
15651
|
+
fs3.lchown = chownFix(fs3.lchown);
|
|
15652
|
+
fs3.chmod = chmodFix(fs3.chmod);
|
|
15653
|
+
fs3.fchmod = chmodFix(fs3.fchmod);
|
|
15654
|
+
fs3.lchmod = chmodFix(fs3.lchmod);
|
|
15655
|
+
fs3.chownSync = chownFixSync(fs3.chownSync);
|
|
15656
|
+
fs3.fchownSync = chownFixSync(fs3.fchownSync);
|
|
15657
|
+
fs3.lchownSync = chownFixSync(fs3.lchownSync);
|
|
15658
|
+
fs3.chmodSync = chmodFixSync(fs3.chmodSync);
|
|
15659
|
+
fs3.fchmodSync = chmodFixSync(fs3.fchmodSync);
|
|
15660
|
+
fs3.lchmodSync = chmodFixSync(fs3.lchmodSync);
|
|
15661
|
+
fs3.stat = statFix(fs3.stat);
|
|
15662
|
+
fs3.fstat = statFix(fs3.fstat);
|
|
15663
|
+
fs3.lstat = statFix(fs3.lstat);
|
|
15664
|
+
fs3.statSync = statFixSync(fs3.statSync);
|
|
15665
|
+
fs3.fstatSync = statFixSync(fs3.fstatSync);
|
|
15666
|
+
fs3.lstatSync = statFixSync(fs3.lstatSync);
|
|
15667
|
+
if (fs3.chmod && !fs3.lchmod) {
|
|
15668
|
+
fs3.lchmod = function(path5, mode, cb) {
|
|
15669
|
+
if (cb)
|
|
15670
|
+
process.nextTick(cb);
|
|
15671
|
+
};
|
|
15672
|
+
fs3.lchmodSync = function() {};
|
|
15743
15673
|
}
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error49 instanceof Error ? error49.message : String(error49)];
|
|
15751
|
-
return { status: "invalid_schema", errors: errors3 };
|
|
15752
|
-
}
|
|
15753
|
-
}
|
|
15754
|
-
async function listEvidenceTaskIds(directory) {
|
|
15755
|
-
const evidenceBasePath = validateSwarmPath(directory, "evidence");
|
|
15756
|
-
try {
|
|
15757
|
-
statSync2(evidenceBasePath);
|
|
15758
|
-
} catch {
|
|
15759
|
-
return [];
|
|
15760
|
-
}
|
|
15761
|
-
let entries;
|
|
15762
|
-
try {
|
|
15763
|
-
entries = readdirSync2(evidenceBasePath);
|
|
15764
|
-
} catch {
|
|
15765
|
-
return [];
|
|
15766
|
-
}
|
|
15767
|
-
const taskIds = [];
|
|
15768
|
-
for (const entry of entries) {
|
|
15769
|
-
const entryPath = path5.join(evidenceBasePath, entry);
|
|
15770
|
-
try {
|
|
15771
|
-
const stats = statSync2(entryPath);
|
|
15772
|
-
if (!stats.isDirectory()) {
|
|
15773
|
-
continue;
|
|
15774
|
-
}
|
|
15775
|
-
sanitizeTaskId2(entry);
|
|
15776
|
-
taskIds.push(entry);
|
|
15777
|
-
} catch (error49) {
|
|
15778
|
-
if (error49 instanceof Error && !error49.message.startsWith("Invalid task ID")) {
|
|
15779
|
-
warn(`Error reading evidence entry '${entry}': ${error49.message}`);
|
|
15780
|
-
}
|
|
15781
|
-
}
|
|
15782
|
-
}
|
|
15783
|
-
return taskIds.sort();
|
|
15784
|
-
}
|
|
15785
|
-
async function deleteEvidence(directory, taskId) {
|
|
15786
|
-
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
15787
|
-
const relativePath = path5.join("evidence", sanitizedTaskId);
|
|
15788
|
-
const evidenceDir = validateSwarmPath(directory, relativePath);
|
|
15789
|
-
try {
|
|
15790
|
-
statSync2(evidenceDir);
|
|
15791
|
-
} catch {
|
|
15792
|
-
return false;
|
|
15793
|
-
}
|
|
15794
|
-
try {
|
|
15795
|
-
rmSync(evidenceDir, { recursive: true, force: true });
|
|
15796
|
-
return true;
|
|
15797
|
-
} catch (error49) {
|
|
15798
|
-
warn(`Failed to delete evidence for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
15799
|
-
return false;
|
|
15800
|
-
}
|
|
15801
|
-
}
|
|
15802
|
-
async function checkRequirementCoverage(phase, directory) {
|
|
15803
|
-
const relativePath = path5.join("evidence", `req-coverage-phase-${phase}.json`);
|
|
15804
|
-
const absolutePath = path5.resolve(directory, ".swarm", relativePath);
|
|
15805
|
-
try {
|
|
15806
|
-
await fs3.access(absolutePath);
|
|
15807
|
-
return { exists: true, path: absolutePath };
|
|
15808
|
-
} catch {
|
|
15809
|
-
return { exists: false, path: absolutePath };
|
|
15810
|
-
}
|
|
15811
|
-
}
|
|
15812
|
-
async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
15813
|
-
const taskIds = await listEvidenceTaskIds(directory);
|
|
15814
|
-
const cutoffDate = new Date;
|
|
15815
|
-
cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
|
|
15816
|
-
const cutoffIso = cutoffDate.toISOString();
|
|
15817
|
-
const archived = [];
|
|
15818
|
-
const remainingBundles = [];
|
|
15819
|
-
for (const taskId of taskIds) {
|
|
15820
|
-
const result = await loadEvidence(directory, taskId);
|
|
15821
|
-
if (result.status !== "found") {
|
|
15822
|
-
continue;
|
|
15823
|
-
}
|
|
15824
|
-
if (result.bundle.updated_at < cutoffIso) {
|
|
15825
|
-
const deleted = await deleteEvidence(directory, taskId);
|
|
15826
|
-
if (deleted) {
|
|
15827
|
-
archived.push(taskId);
|
|
15828
|
-
}
|
|
15829
|
-
} else {
|
|
15830
|
-
remainingBundles.push({
|
|
15831
|
-
taskId,
|
|
15832
|
-
updatedAt: result.bundle.updated_at
|
|
15833
|
-
});
|
|
15834
|
-
}
|
|
15835
|
-
}
|
|
15836
|
-
if (maxBundles !== undefined && remainingBundles.length > maxBundles) {
|
|
15837
|
-
remainingBundles.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt));
|
|
15838
|
-
const toDelete = remainingBundles.length - maxBundles;
|
|
15839
|
-
for (let i = 0;i < toDelete; i++) {
|
|
15840
|
-
const deleted = await deleteEvidence(directory, remainingBundles[i].taskId);
|
|
15841
|
-
if (deleted) {
|
|
15842
|
-
archived.push(remainingBundles[i].taskId);
|
|
15843
|
-
}
|
|
15844
|
-
}
|
|
15845
|
-
}
|
|
15846
|
-
return archived;
|
|
15847
|
-
}
|
|
15848
|
-
var VALID_EVIDENCE_TYPES, sanitizeTaskId2, LEGACY_TASK_COMPLEXITY_MAP;
|
|
15849
|
-
var init_manager2 = __esm(() => {
|
|
15850
|
-
init_zod();
|
|
15851
|
-
init_evidence_schema();
|
|
15852
|
-
init_utils2();
|
|
15853
|
-
init_utils();
|
|
15854
|
-
init_task_id();
|
|
15855
|
-
VALID_EVIDENCE_TYPES = [
|
|
15856
|
-
"review",
|
|
15857
|
-
"test",
|
|
15858
|
-
"diff",
|
|
15859
|
-
"approval",
|
|
15860
|
-
"note",
|
|
15861
|
-
"retrospective",
|
|
15862
|
-
"syntax",
|
|
15863
|
-
"placeholder",
|
|
15864
|
-
"sast",
|
|
15865
|
-
"sbom",
|
|
15866
|
-
"build",
|
|
15867
|
-
"quality_budget",
|
|
15868
|
-
"secretscan"
|
|
15869
|
-
];
|
|
15870
|
-
sanitizeTaskId2 = sanitizeTaskId;
|
|
15871
|
-
LEGACY_TASK_COMPLEXITY_MAP = {
|
|
15872
|
-
low: "simple",
|
|
15873
|
-
medium: "moderate",
|
|
15874
|
-
high: "complex"
|
|
15875
|
-
};
|
|
15876
|
-
});
|
|
15877
|
-
|
|
15878
|
-
// src/telemetry.ts
|
|
15879
|
-
var init_telemetry = () => {};
|
|
15880
|
-
|
|
15881
|
-
// node_modules/graceful-fs/polyfills.js
|
|
15882
|
-
var require_polyfills = __commonJS((exports, module) => {
|
|
15883
|
-
var constants = __require("constants");
|
|
15884
|
-
var origCwd = process.cwd;
|
|
15885
|
-
var cwd = null;
|
|
15886
|
-
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
15887
|
-
process.cwd = function() {
|
|
15888
|
-
if (!cwd)
|
|
15889
|
-
cwd = origCwd.call(process);
|
|
15890
|
-
return cwd;
|
|
15891
|
-
};
|
|
15892
|
-
try {
|
|
15893
|
-
process.cwd();
|
|
15894
|
-
} catch (er) {}
|
|
15895
|
-
if (typeof process.chdir === "function") {
|
|
15896
|
-
chdir = process.chdir;
|
|
15897
|
-
process.chdir = function(d) {
|
|
15898
|
-
cwd = null;
|
|
15899
|
-
chdir.call(process, d);
|
|
15900
|
-
};
|
|
15901
|
-
if (Object.setPrototypeOf)
|
|
15902
|
-
Object.setPrototypeOf(process.chdir, chdir);
|
|
15903
|
-
}
|
|
15904
|
-
var chdir;
|
|
15905
|
-
module.exports = patch;
|
|
15906
|
-
function patch(fs4) {
|
|
15907
|
-
if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
15908
|
-
patchLchmod(fs4);
|
|
15909
|
-
}
|
|
15910
|
-
if (!fs4.lutimes) {
|
|
15911
|
-
patchLutimes(fs4);
|
|
15912
|
-
}
|
|
15913
|
-
fs4.chown = chownFix(fs4.chown);
|
|
15914
|
-
fs4.fchown = chownFix(fs4.fchown);
|
|
15915
|
-
fs4.lchown = chownFix(fs4.lchown);
|
|
15916
|
-
fs4.chmod = chmodFix(fs4.chmod);
|
|
15917
|
-
fs4.fchmod = chmodFix(fs4.fchmod);
|
|
15918
|
-
fs4.lchmod = chmodFix(fs4.lchmod);
|
|
15919
|
-
fs4.chownSync = chownFixSync(fs4.chownSync);
|
|
15920
|
-
fs4.fchownSync = chownFixSync(fs4.fchownSync);
|
|
15921
|
-
fs4.lchownSync = chownFixSync(fs4.lchownSync);
|
|
15922
|
-
fs4.chmodSync = chmodFixSync(fs4.chmodSync);
|
|
15923
|
-
fs4.fchmodSync = chmodFixSync(fs4.fchmodSync);
|
|
15924
|
-
fs4.lchmodSync = chmodFixSync(fs4.lchmodSync);
|
|
15925
|
-
fs4.stat = statFix(fs4.stat);
|
|
15926
|
-
fs4.fstat = statFix(fs4.fstat);
|
|
15927
|
-
fs4.lstat = statFix(fs4.lstat);
|
|
15928
|
-
fs4.statSync = statFixSync(fs4.statSync);
|
|
15929
|
-
fs4.fstatSync = statFixSync(fs4.fstatSync);
|
|
15930
|
-
fs4.lstatSync = statFixSync(fs4.lstatSync);
|
|
15931
|
-
if (fs4.chmod && !fs4.lchmod) {
|
|
15932
|
-
fs4.lchmod = function(path6, mode, cb) {
|
|
15933
|
-
if (cb)
|
|
15934
|
-
process.nextTick(cb);
|
|
15935
|
-
};
|
|
15936
|
-
fs4.lchmodSync = function() {};
|
|
15937
|
-
}
|
|
15938
|
-
if (fs4.chown && !fs4.lchown) {
|
|
15939
|
-
fs4.lchown = function(path6, uid, gid, cb) {
|
|
15940
|
-
if (cb)
|
|
15941
|
-
process.nextTick(cb);
|
|
15942
|
-
};
|
|
15943
|
-
fs4.lchownSync = function() {};
|
|
15674
|
+
if (fs3.chown && !fs3.lchown) {
|
|
15675
|
+
fs3.lchown = function(path5, uid, gid, cb) {
|
|
15676
|
+
if (cb)
|
|
15677
|
+
process.nextTick(cb);
|
|
15678
|
+
};
|
|
15679
|
+
fs3.lchownSync = function() {};
|
|
15944
15680
|
}
|
|
15945
15681
|
if (platform === "win32") {
|
|
15946
|
-
|
|
15947
|
-
function
|
|
15682
|
+
fs3.rename = typeof fs3.rename !== "function" ? fs3.rename : function(fs$rename) {
|
|
15683
|
+
function rename(from, to, cb) {
|
|
15948
15684
|
var start = Date.now();
|
|
15949
15685
|
var backoff = 0;
|
|
15950
15686
|
fs$rename(from, to, function CB(er) {
|
|
15951
15687
|
if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 60000) {
|
|
15952
15688
|
setTimeout(function() {
|
|
15953
|
-
|
|
15689
|
+
fs3.stat(to, function(stater, st) {
|
|
15954
15690
|
if (stater && stater.code === "ENOENT")
|
|
15955
15691
|
fs$rename(from, to, CB);
|
|
15956
15692
|
else
|
|
@@ -15966,11 +15702,11 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15966
15702
|
});
|
|
15967
15703
|
}
|
|
15968
15704
|
if (Object.setPrototypeOf)
|
|
15969
|
-
Object.setPrototypeOf(
|
|
15970
|
-
return
|
|
15971
|
-
}(
|
|
15705
|
+
Object.setPrototypeOf(rename, fs$rename);
|
|
15706
|
+
return rename;
|
|
15707
|
+
}(fs3.rename);
|
|
15972
15708
|
}
|
|
15973
|
-
|
|
15709
|
+
fs3.read = typeof fs3.read !== "function" ? fs3.read : function(fs$read) {
|
|
15974
15710
|
function read(fd, buffer, offset, length, position, callback_) {
|
|
15975
15711
|
var callback;
|
|
15976
15712
|
if (callback_ && typeof callback_ === "function") {
|
|
@@ -15978,23 +15714,23 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
15978
15714
|
callback = function(er, _, __) {
|
|
15979
15715
|
if (er && er.code === "EAGAIN" && eagCounter < 10) {
|
|
15980
15716
|
eagCounter++;
|
|
15981
|
-
return fs$read.call(
|
|
15717
|
+
return fs$read.call(fs3, fd, buffer, offset, length, position, callback);
|
|
15982
15718
|
}
|
|
15983
15719
|
callback_.apply(this, arguments);
|
|
15984
15720
|
};
|
|
15985
15721
|
}
|
|
15986
|
-
return fs$read.call(
|
|
15722
|
+
return fs$read.call(fs3, fd, buffer, offset, length, position, callback);
|
|
15987
15723
|
}
|
|
15988
15724
|
if (Object.setPrototypeOf)
|
|
15989
15725
|
Object.setPrototypeOf(read, fs$read);
|
|
15990
15726
|
return read;
|
|
15991
|
-
}(
|
|
15992
|
-
|
|
15727
|
+
}(fs3.read);
|
|
15728
|
+
fs3.readSync = typeof fs3.readSync !== "function" ? fs3.readSync : function(fs$readSync) {
|
|
15993
15729
|
return function(fd, buffer, offset, length, position) {
|
|
15994
15730
|
var eagCounter = 0;
|
|
15995
15731
|
while (true) {
|
|
15996
15732
|
try {
|
|
15997
|
-
return fs$readSync.call(
|
|
15733
|
+
return fs$readSync.call(fs3, fd, buffer, offset, length, position);
|
|
15998
15734
|
} catch (er) {
|
|
15999
15735
|
if (er.code === "EAGAIN" && eagCounter < 10) {
|
|
16000
15736
|
eagCounter++;
|
|
@@ -16004,90 +15740,90 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
16004
15740
|
}
|
|
16005
15741
|
}
|
|
16006
15742
|
};
|
|
16007
|
-
}(
|
|
16008
|
-
function patchLchmod(
|
|
16009
|
-
|
|
16010
|
-
|
|
15743
|
+
}(fs3.readSync);
|
|
15744
|
+
function patchLchmod(fs4) {
|
|
15745
|
+
fs4.lchmod = function(path5, mode, callback) {
|
|
15746
|
+
fs4.open(path5, constants.O_WRONLY | constants.O_SYMLINK, mode, function(err, fd) {
|
|
16011
15747
|
if (err) {
|
|
16012
15748
|
if (callback)
|
|
16013
15749
|
callback(err);
|
|
16014
15750
|
return;
|
|
16015
15751
|
}
|
|
16016
|
-
|
|
16017
|
-
|
|
15752
|
+
fs4.fchmod(fd, mode, function(err2) {
|
|
15753
|
+
fs4.close(fd, function(err22) {
|
|
16018
15754
|
if (callback)
|
|
16019
15755
|
callback(err2 || err22);
|
|
16020
15756
|
});
|
|
16021
15757
|
});
|
|
16022
15758
|
});
|
|
16023
15759
|
};
|
|
16024
|
-
|
|
16025
|
-
var fd =
|
|
15760
|
+
fs4.lchmodSync = function(path5, mode) {
|
|
15761
|
+
var fd = fs4.openSync(path5, constants.O_WRONLY | constants.O_SYMLINK, mode);
|
|
16026
15762
|
var threw = true;
|
|
16027
15763
|
var ret;
|
|
16028
15764
|
try {
|
|
16029
|
-
ret =
|
|
15765
|
+
ret = fs4.fchmodSync(fd, mode);
|
|
16030
15766
|
threw = false;
|
|
16031
15767
|
} finally {
|
|
16032
15768
|
if (threw) {
|
|
16033
15769
|
try {
|
|
16034
|
-
|
|
15770
|
+
fs4.closeSync(fd);
|
|
16035
15771
|
} catch (er) {}
|
|
16036
15772
|
} else {
|
|
16037
|
-
|
|
15773
|
+
fs4.closeSync(fd);
|
|
16038
15774
|
}
|
|
16039
15775
|
}
|
|
16040
15776
|
return ret;
|
|
16041
15777
|
};
|
|
16042
15778
|
}
|
|
16043
|
-
function patchLutimes(
|
|
16044
|
-
if (constants.hasOwnProperty("O_SYMLINK") &&
|
|
16045
|
-
|
|
16046
|
-
|
|
15779
|
+
function patchLutimes(fs4) {
|
|
15780
|
+
if (constants.hasOwnProperty("O_SYMLINK") && fs4.futimes) {
|
|
15781
|
+
fs4.lutimes = function(path5, at, mt, cb) {
|
|
15782
|
+
fs4.open(path5, constants.O_SYMLINK, function(er, fd) {
|
|
16047
15783
|
if (er) {
|
|
16048
15784
|
if (cb)
|
|
16049
15785
|
cb(er);
|
|
16050
15786
|
return;
|
|
16051
15787
|
}
|
|
16052
|
-
|
|
16053
|
-
|
|
15788
|
+
fs4.futimes(fd, at, mt, function(er2) {
|
|
15789
|
+
fs4.close(fd, function(er22) {
|
|
16054
15790
|
if (cb)
|
|
16055
15791
|
cb(er2 || er22);
|
|
16056
15792
|
});
|
|
16057
15793
|
});
|
|
16058
15794
|
});
|
|
16059
15795
|
};
|
|
16060
|
-
|
|
16061
|
-
var fd =
|
|
15796
|
+
fs4.lutimesSync = function(path5, at, mt) {
|
|
15797
|
+
var fd = fs4.openSync(path5, constants.O_SYMLINK);
|
|
16062
15798
|
var ret;
|
|
16063
15799
|
var threw = true;
|
|
16064
15800
|
try {
|
|
16065
|
-
ret =
|
|
15801
|
+
ret = fs4.futimesSync(fd, at, mt);
|
|
16066
15802
|
threw = false;
|
|
16067
15803
|
} finally {
|
|
16068
15804
|
if (threw) {
|
|
16069
15805
|
try {
|
|
16070
|
-
|
|
15806
|
+
fs4.closeSync(fd);
|
|
16071
15807
|
} catch (er) {}
|
|
16072
15808
|
} else {
|
|
16073
|
-
|
|
15809
|
+
fs4.closeSync(fd);
|
|
16074
15810
|
}
|
|
16075
15811
|
}
|
|
16076
15812
|
return ret;
|
|
16077
15813
|
};
|
|
16078
|
-
} else if (
|
|
16079
|
-
|
|
15814
|
+
} else if (fs4.futimes) {
|
|
15815
|
+
fs4.lutimes = function(_a2, _b, _c, cb) {
|
|
16080
15816
|
if (cb)
|
|
16081
15817
|
process.nextTick(cb);
|
|
16082
15818
|
};
|
|
16083
|
-
|
|
15819
|
+
fs4.lutimesSync = function() {};
|
|
16084
15820
|
}
|
|
16085
15821
|
}
|
|
16086
15822
|
function chmodFix(orig) {
|
|
16087
15823
|
if (!orig)
|
|
16088
15824
|
return orig;
|
|
16089
15825
|
return function(target, mode, cb) {
|
|
16090
|
-
return orig.call(
|
|
15826
|
+
return orig.call(fs3, target, mode, function(er) {
|
|
16091
15827
|
if (chownErOk(er))
|
|
16092
15828
|
er = null;
|
|
16093
15829
|
if (cb)
|
|
@@ -16100,7 +15836,7 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
16100
15836
|
return orig;
|
|
16101
15837
|
return function(target, mode) {
|
|
16102
15838
|
try {
|
|
16103
|
-
return orig.call(
|
|
15839
|
+
return orig.call(fs3, target, mode);
|
|
16104
15840
|
} catch (er) {
|
|
16105
15841
|
if (!chownErOk(er))
|
|
16106
15842
|
throw er;
|
|
@@ -16111,7 +15847,7 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
16111
15847
|
if (!orig)
|
|
16112
15848
|
return orig;
|
|
16113
15849
|
return function(target, uid, gid, cb) {
|
|
16114
|
-
return orig.call(
|
|
15850
|
+
return orig.call(fs3, target, uid, gid, function(er) {
|
|
16115
15851
|
if (chownErOk(er))
|
|
16116
15852
|
er = null;
|
|
16117
15853
|
if (cb)
|
|
@@ -16124,7 +15860,7 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
16124
15860
|
return orig;
|
|
16125
15861
|
return function(target, uid, gid) {
|
|
16126
15862
|
try {
|
|
16127
|
-
return orig.call(
|
|
15863
|
+
return orig.call(fs3, target, uid, gid);
|
|
16128
15864
|
} catch (er) {
|
|
16129
15865
|
if (!chownErOk(er))
|
|
16130
15866
|
throw er;
|
|
@@ -16149,14 +15885,14 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
16149
15885
|
if (cb)
|
|
16150
15886
|
cb.apply(this, arguments);
|
|
16151
15887
|
}
|
|
16152
|
-
return options ? orig.call(
|
|
15888
|
+
return options ? orig.call(fs3, target, options, callback) : orig.call(fs3, target, callback);
|
|
16153
15889
|
};
|
|
16154
15890
|
}
|
|
16155
15891
|
function statFixSync(orig) {
|
|
16156
15892
|
if (!orig)
|
|
16157
15893
|
return orig;
|
|
16158
15894
|
return function(target, options) {
|
|
16159
|
-
var stats = options ? orig.call(
|
|
15895
|
+
var stats = options ? orig.call(fs3, target, options) : orig.call(fs3, target);
|
|
16160
15896
|
if (stats) {
|
|
16161
15897
|
if (stats.uid < 0)
|
|
16162
15898
|
stats.uid += 4294967296;
|
|
@@ -16185,17 +15921,17 @@ var require_polyfills = __commonJS((exports, module) => {
|
|
|
16185
15921
|
var require_legacy_streams = __commonJS((exports, module) => {
|
|
16186
15922
|
var Stream = __require("stream").Stream;
|
|
16187
15923
|
module.exports = legacy;
|
|
16188
|
-
function legacy(
|
|
15924
|
+
function legacy(fs3) {
|
|
16189
15925
|
return {
|
|
16190
15926
|
ReadStream,
|
|
16191
15927
|
WriteStream
|
|
16192
15928
|
};
|
|
16193
|
-
function ReadStream(
|
|
15929
|
+
function ReadStream(path5, options) {
|
|
16194
15930
|
if (!(this instanceof ReadStream))
|
|
16195
|
-
return new ReadStream(
|
|
15931
|
+
return new ReadStream(path5, options);
|
|
16196
15932
|
Stream.call(this);
|
|
16197
15933
|
var self = this;
|
|
16198
|
-
this.path =
|
|
15934
|
+
this.path = path5;
|
|
16199
15935
|
this.fd = null;
|
|
16200
15936
|
this.readable = true;
|
|
16201
15937
|
this.paused = false;
|
|
@@ -16230,7 +15966,7 @@ var require_legacy_streams = __commonJS((exports, module) => {
|
|
|
16230
15966
|
});
|
|
16231
15967
|
return;
|
|
16232
15968
|
}
|
|
16233
|
-
|
|
15969
|
+
fs3.open(this.path, this.flags, this.mode, function(err, fd) {
|
|
16234
15970
|
if (err) {
|
|
16235
15971
|
self.emit("error", err);
|
|
16236
15972
|
self.readable = false;
|
|
@@ -16241,11 +15977,11 @@ var require_legacy_streams = __commonJS((exports, module) => {
|
|
|
16241
15977
|
self._read();
|
|
16242
15978
|
});
|
|
16243
15979
|
}
|
|
16244
|
-
function WriteStream(
|
|
15980
|
+
function WriteStream(path5, options) {
|
|
16245
15981
|
if (!(this instanceof WriteStream))
|
|
16246
|
-
return new WriteStream(
|
|
15982
|
+
return new WriteStream(path5, options);
|
|
16247
15983
|
Stream.call(this);
|
|
16248
|
-
this.path =
|
|
15984
|
+
this.path = path5;
|
|
16249
15985
|
this.fd = null;
|
|
16250
15986
|
this.writable = true;
|
|
16251
15987
|
this.flags = "w";
|
|
@@ -16270,7 +16006,7 @@ var require_legacy_streams = __commonJS((exports, module) => {
|
|
|
16270
16006
|
this.busy = false;
|
|
16271
16007
|
this._queue = [];
|
|
16272
16008
|
if (this.fd === null) {
|
|
16273
|
-
this._open =
|
|
16009
|
+
this._open = fs3.open;
|
|
16274
16010
|
this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
|
|
16275
16011
|
this.flush();
|
|
16276
16012
|
}
|
|
@@ -16300,7 +16036,7 @@ var require_clone = __commonJS((exports, module) => {
|
|
|
16300
16036
|
|
|
16301
16037
|
// node_modules/graceful-fs/graceful-fs.js
|
|
16302
16038
|
var require_graceful_fs = __commonJS((exports, module) => {
|
|
16303
|
-
var
|
|
16039
|
+
var fs3 = __require("fs");
|
|
16304
16040
|
var polyfills = require_polyfills();
|
|
16305
16041
|
var legacy = require_legacy_streams();
|
|
16306
16042
|
var clone2 = require_clone();
|
|
@@ -16332,12 +16068,12 @@ var require_graceful_fs = __commonJS((exports, module) => {
|
|
|
16332
16068
|
GFS4: `);
|
|
16333
16069
|
console.error(m);
|
|
16334
16070
|
};
|
|
16335
|
-
if (!
|
|
16071
|
+
if (!fs3[gracefulQueue]) {
|
|
16336
16072
|
queue = global[gracefulQueue] || [];
|
|
16337
|
-
publishQueue(
|
|
16338
|
-
|
|
16073
|
+
publishQueue(fs3, queue);
|
|
16074
|
+
fs3.close = function(fs$close) {
|
|
16339
16075
|
function close(fd, cb) {
|
|
16340
|
-
return fs$close.call(
|
|
16076
|
+
return fs$close.call(fs3, fd, function(err) {
|
|
16341
16077
|
if (!err) {
|
|
16342
16078
|
resetQueue();
|
|
16343
16079
|
}
|
|
@@ -16349,48 +16085,48 @@ GFS4: `);
|
|
|
16349
16085
|
value: fs$close
|
|
16350
16086
|
});
|
|
16351
16087
|
return close;
|
|
16352
|
-
}(
|
|
16353
|
-
|
|
16088
|
+
}(fs3.close);
|
|
16089
|
+
fs3.closeSync = function(fs$closeSync) {
|
|
16354
16090
|
function closeSync(fd) {
|
|
16355
|
-
fs$closeSync.apply(
|
|
16091
|
+
fs$closeSync.apply(fs3, arguments);
|
|
16356
16092
|
resetQueue();
|
|
16357
16093
|
}
|
|
16358
16094
|
Object.defineProperty(closeSync, previousSymbol, {
|
|
16359
16095
|
value: fs$closeSync
|
|
16360
16096
|
});
|
|
16361
16097
|
return closeSync;
|
|
16362
|
-
}(
|
|
16098
|
+
}(fs3.closeSync);
|
|
16363
16099
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
16364
16100
|
process.on("exit", function() {
|
|
16365
|
-
debug(
|
|
16366
|
-
__require("assert").equal(
|
|
16101
|
+
debug(fs3[gracefulQueue]);
|
|
16102
|
+
__require("assert").equal(fs3[gracefulQueue].length, 0);
|
|
16367
16103
|
});
|
|
16368
16104
|
}
|
|
16369
16105
|
}
|
|
16370
16106
|
var queue;
|
|
16371
16107
|
if (!global[gracefulQueue]) {
|
|
16372
|
-
publishQueue(global,
|
|
16373
|
-
}
|
|
16374
|
-
module.exports = patch(clone2(
|
|
16375
|
-
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !
|
|
16376
|
-
module.exports = patch(
|
|
16377
|
-
|
|
16378
|
-
}
|
|
16379
|
-
function patch(
|
|
16380
|
-
polyfills(
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
var fs$readFile =
|
|
16385
|
-
|
|
16386
|
-
function readFile2(
|
|
16108
|
+
publishQueue(global, fs3[gracefulQueue]);
|
|
16109
|
+
}
|
|
16110
|
+
module.exports = patch(clone2(fs3));
|
|
16111
|
+
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs3.__patched) {
|
|
16112
|
+
module.exports = patch(fs3);
|
|
16113
|
+
fs3.__patched = true;
|
|
16114
|
+
}
|
|
16115
|
+
function patch(fs4) {
|
|
16116
|
+
polyfills(fs4);
|
|
16117
|
+
fs4.gracefulify = patch;
|
|
16118
|
+
fs4.createReadStream = createReadStream;
|
|
16119
|
+
fs4.createWriteStream = createWriteStream;
|
|
16120
|
+
var fs$readFile = fs4.readFile;
|
|
16121
|
+
fs4.readFile = readFile2;
|
|
16122
|
+
function readFile2(path5, options, cb) {
|
|
16387
16123
|
if (typeof options === "function")
|
|
16388
16124
|
cb = options, options = null;
|
|
16389
|
-
return go$readFile(
|
|
16390
|
-
function go$readFile(
|
|
16391
|
-
return fs$readFile(
|
|
16125
|
+
return go$readFile(path5, options, cb);
|
|
16126
|
+
function go$readFile(path6, options2, cb2, startTime) {
|
|
16127
|
+
return fs$readFile(path6, options2, function(err) {
|
|
16392
16128
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16393
|
-
enqueue([go$readFile, [
|
|
16129
|
+
enqueue([go$readFile, [path6, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16394
16130
|
else {
|
|
16395
16131
|
if (typeof cb2 === "function")
|
|
16396
16132
|
cb2.apply(this, arguments);
|
|
@@ -16398,16 +16134,16 @@ GFS4: `);
|
|
|
16398
16134
|
});
|
|
16399
16135
|
}
|
|
16400
16136
|
}
|
|
16401
|
-
var fs$writeFile =
|
|
16402
|
-
|
|
16403
|
-
function writeFile2(
|
|
16137
|
+
var fs$writeFile = fs4.writeFile;
|
|
16138
|
+
fs4.writeFile = writeFile2;
|
|
16139
|
+
function writeFile2(path5, data, options, cb) {
|
|
16404
16140
|
if (typeof options === "function")
|
|
16405
16141
|
cb = options, options = null;
|
|
16406
|
-
return go$writeFile(
|
|
16407
|
-
function go$writeFile(
|
|
16408
|
-
return fs$writeFile(
|
|
16142
|
+
return go$writeFile(path5, data, options, cb);
|
|
16143
|
+
function go$writeFile(path6, data2, options2, cb2, startTime) {
|
|
16144
|
+
return fs$writeFile(path6, data2, options2, function(err) {
|
|
16409
16145
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16410
|
-
enqueue([go$writeFile, [
|
|
16146
|
+
enqueue([go$writeFile, [path6, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16411
16147
|
else {
|
|
16412
16148
|
if (typeof cb2 === "function")
|
|
16413
16149
|
cb2.apply(this, arguments);
|
|
@@ -16415,17 +16151,17 @@ GFS4: `);
|
|
|
16415
16151
|
});
|
|
16416
16152
|
}
|
|
16417
16153
|
}
|
|
16418
|
-
var fs$appendFile =
|
|
16154
|
+
var fs$appendFile = fs4.appendFile;
|
|
16419
16155
|
if (fs$appendFile)
|
|
16420
|
-
|
|
16421
|
-
function appendFile2(
|
|
16156
|
+
fs4.appendFile = appendFile2;
|
|
16157
|
+
function appendFile2(path5, data, options, cb) {
|
|
16422
16158
|
if (typeof options === "function")
|
|
16423
16159
|
cb = options, options = null;
|
|
16424
|
-
return go$appendFile(
|
|
16425
|
-
function go$appendFile(
|
|
16426
|
-
return fs$appendFile(
|
|
16160
|
+
return go$appendFile(path5, data, options, cb);
|
|
16161
|
+
function go$appendFile(path6, data2, options2, cb2, startTime) {
|
|
16162
|
+
return fs$appendFile(path6, data2, options2, function(err) {
|
|
16427
16163
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16428
|
-
enqueue([go$appendFile, [
|
|
16164
|
+
enqueue([go$appendFile, [path6, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16429
16165
|
else {
|
|
16430
16166
|
if (typeof cb2 === "function")
|
|
16431
16167
|
cb2.apply(this, arguments);
|
|
@@ -16433,9 +16169,9 @@ GFS4: `);
|
|
|
16433
16169
|
});
|
|
16434
16170
|
}
|
|
16435
16171
|
}
|
|
16436
|
-
var fs$copyFile =
|
|
16172
|
+
var fs$copyFile = fs4.copyFile;
|
|
16437
16173
|
if (fs$copyFile)
|
|
16438
|
-
|
|
16174
|
+
fs4.copyFile = copyFile;
|
|
16439
16175
|
function copyFile(src, dest, flags, cb) {
|
|
16440
16176
|
if (typeof flags === "function") {
|
|
16441
16177
|
cb = flags;
|
|
@@ -16453,24 +16189,24 @@ GFS4: `);
|
|
|
16453
16189
|
});
|
|
16454
16190
|
}
|
|
16455
16191
|
}
|
|
16456
|
-
var fs$readdir =
|
|
16457
|
-
|
|
16192
|
+
var fs$readdir = fs4.readdir;
|
|
16193
|
+
fs4.readdir = readdir;
|
|
16458
16194
|
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
16459
|
-
function readdir(
|
|
16195
|
+
function readdir(path5, options, cb) {
|
|
16460
16196
|
if (typeof options === "function")
|
|
16461
16197
|
cb = options, options = null;
|
|
16462
|
-
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(
|
|
16463
|
-
return fs$readdir(
|
|
16464
|
-
} : function go$readdir2(
|
|
16465
|
-
return fs$readdir(
|
|
16198
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path6, options2, cb2, startTime) {
|
|
16199
|
+
return fs$readdir(path6, fs$readdirCallback(path6, options2, cb2, startTime));
|
|
16200
|
+
} : function go$readdir2(path6, options2, cb2, startTime) {
|
|
16201
|
+
return fs$readdir(path6, options2, fs$readdirCallback(path6, options2, cb2, startTime));
|
|
16466
16202
|
};
|
|
16467
|
-
return go$readdir(
|
|
16468
|
-
function fs$readdirCallback(
|
|
16203
|
+
return go$readdir(path5, options, cb);
|
|
16204
|
+
function fs$readdirCallback(path6, options2, cb2, startTime) {
|
|
16469
16205
|
return function(err, files) {
|
|
16470
16206
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16471
16207
|
enqueue([
|
|
16472
16208
|
go$readdir,
|
|
16473
|
-
[
|
|
16209
|
+
[path6, options2, cb2],
|
|
16474
16210
|
err,
|
|
16475
16211
|
startTime || Date.now(),
|
|
16476
16212
|
Date.now()
|
|
@@ -16485,21 +16221,21 @@ GFS4: `);
|
|
|
16485
16221
|
}
|
|
16486
16222
|
}
|
|
16487
16223
|
if (process.version.substr(0, 4) === "v0.8") {
|
|
16488
|
-
var legStreams = legacy(
|
|
16224
|
+
var legStreams = legacy(fs4);
|
|
16489
16225
|
ReadStream = legStreams.ReadStream;
|
|
16490
16226
|
WriteStream = legStreams.WriteStream;
|
|
16491
16227
|
}
|
|
16492
|
-
var fs$ReadStream =
|
|
16228
|
+
var fs$ReadStream = fs4.ReadStream;
|
|
16493
16229
|
if (fs$ReadStream) {
|
|
16494
16230
|
ReadStream.prototype = Object.create(fs$ReadStream.prototype);
|
|
16495
16231
|
ReadStream.prototype.open = ReadStream$open;
|
|
16496
16232
|
}
|
|
16497
|
-
var fs$WriteStream =
|
|
16233
|
+
var fs$WriteStream = fs4.WriteStream;
|
|
16498
16234
|
if (fs$WriteStream) {
|
|
16499
16235
|
WriteStream.prototype = Object.create(fs$WriteStream.prototype);
|
|
16500
16236
|
WriteStream.prototype.open = WriteStream$open;
|
|
16501
16237
|
}
|
|
16502
|
-
Object.defineProperty(
|
|
16238
|
+
Object.defineProperty(fs4, "ReadStream", {
|
|
16503
16239
|
get: function() {
|
|
16504
16240
|
return ReadStream;
|
|
16505
16241
|
},
|
|
@@ -16509,7 +16245,7 @@ GFS4: `);
|
|
|
16509
16245
|
enumerable: true,
|
|
16510
16246
|
configurable: true
|
|
16511
16247
|
});
|
|
16512
|
-
Object.defineProperty(
|
|
16248
|
+
Object.defineProperty(fs4, "WriteStream", {
|
|
16513
16249
|
get: function() {
|
|
16514
16250
|
return WriteStream;
|
|
16515
16251
|
},
|
|
@@ -16520,7 +16256,7 @@ GFS4: `);
|
|
|
16520
16256
|
configurable: true
|
|
16521
16257
|
});
|
|
16522
16258
|
var FileReadStream = ReadStream;
|
|
16523
|
-
Object.defineProperty(
|
|
16259
|
+
Object.defineProperty(fs4, "FileReadStream", {
|
|
16524
16260
|
get: function() {
|
|
16525
16261
|
return FileReadStream;
|
|
16526
16262
|
},
|
|
@@ -16531,7 +16267,7 @@ GFS4: `);
|
|
|
16531
16267
|
configurable: true
|
|
16532
16268
|
});
|
|
16533
16269
|
var FileWriteStream = WriteStream;
|
|
16534
|
-
Object.defineProperty(
|
|
16270
|
+
Object.defineProperty(fs4, "FileWriteStream", {
|
|
16535
16271
|
get: function() {
|
|
16536
16272
|
return FileWriteStream;
|
|
16537
16273
|
},
|
|
@@ -16541,7 +16277,7 @@ GFS4: `);
|
|
|
16541
16277
|
enumerable: true,
|
|
16542
16278
|
configurable: true
|
|
16543
16279
|
});
|
|
16544
|
-
function ReadStream(
|
|
16280
|
+
function ReadStream(path5, options) {
|
|
16545
16281
|
if (this instanceof ReadStream)
|
|
16546
16282
|
return fs$ReadStream.apply(this, arguments), this;
|
|
16547
16283
|
else
|
|
@@ -16561,7 +16297,7 @@ GFS4: `);
|
|
|
16561
16297
|
}
|
|
16562
16298
|
});
|
|
16563
16299
|
}
|
|
16564
|
-
function WriteStream(
|
|
16300
|
+
function WriteStream(path5, options) {
|
|
16565
16301
|
if (this instanceof WriteStream)
|
|
16566
16302
|
return fs$WriteStream.apply(this, arguments), this;
|
|
16567
16303
|
else
|
|
@@ -16579,22 +16315,22 @@ GFS4: `);
|
|
|
16579
16315
|
}
|
|
16580
16316
|
});
|
|
16581
16317
|
}
|
|
16582
|
-
function createReadStream(
|
|
16583
|
-
return new
|
|
16318
|
+
function createReadStream(path5, options) {
|
|
16319
|
+
return new fs4.ReadStream(path5, options);
|
|
16584
16320
|
}
|
|
16585
|
-
function createWriteStream(
|
|
16586
|
-
return new
|
|
16321
|
+
function createWriteStream(path5, options) {
|
|
16322
|
+
return new fs4.WriteStream(path5, options);
|
|
16587
16323
|
}
|
|
16588
|
-
var fs$open =
|
|
16589
|
-
|
|
16590
|
-
function open(
|
|
16324
|
+
var fs$open = fs4.open;
|
|
16325
|
+
fs4.open = open;
|
|
16326
|
+
function open(path5, flags, mode, cb) {
|
|
16591
16327
|
if (typeof mode === "function")
|
|
16592
16328
|
cb = mode, mode = null;
|
|
16593
|
-
return go$open(
|
|
16594
|
-
function go$open(
|
|
16595
|
-
return fs$open(
|
|
16329
|
+
return go$open(path5, flags, mode, cb);
|
|
16330
|
+
function go$open(path6, flags2, mode2, cb2, startTime) {
|
|
16331
|
+
return fs$open(path6, flags2, mode2, function(err, fd) {
|
|
16596
16332
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
16597
|
-
enqueue([go$open, [
|
|
16333
|
+
enqueue([go$open, [path6, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
16598
16334
|
else {
|
|
16599
16335
|
if (typeof cb2 === "function")
|
|
16600
16336
|
cb2.apply(this, arguments);
|
|
@@ -16602,20 +16338,20 @@ GFS4: `);
|
|
|
16602
16338
|
});
|
|
16603
16339
|
}
|
|
16604
16340
|
}
|
|
16605
|
-
return
|
|
16341
|
+
return fs4;
|
|
16606
16342
|
}
|
|
16607
16343
|
function enqueue(elem) {
|
|
16608
16344
|
debug("ENQUEUE", elem[0].name, elem[1]);
|
|
16609
|
-
|
|
16345
|
+
fs3[gracefulQueue].push(elem);
|
|
16610
16346
|
retry();
|
|
16611
16347
|
}
|
|
16612
16348
|
var retryTimer;
|
|
16613
16349
|
function resetQueue() {
|
|
16614
16350
|
var now = Date.now();
|
|
16615
|
-
for (var i = 0;i <
|
|
16616
|
-
if (
|
|
16617
|
-
|
|
16618
|
-
|
|
16351
|
+
for (var i = 0;i < fs3[gracefulQueue].length; ++i) {
|
|
16352
|
+
if (fs3[gracefulQueue][i].length > 2) {
|
|
16353
|
+
fs3[gracefulQueue][i][3] = now;
|
|
16354
|
+
fs3[gracefulQueue][i][4] = now;
|
|
16619
16355
|
}
|
|
16620
16356
|
}
|
|
16621
16357
|
retry();
|
|
@@ -16623,9 +16359,9 @@ GFS4: `);
|
|
|
16623
16359
|
function retry() {
|
|
16624
16360
|
clearTimeout(retryTimer);
|
|
16625
16361
|
retryTimer = undefined;
|
|
16626
|
-
if (
|
|
16362
|
+
if (fs3[gracefulQueue].length === 0)
|
|
16627
16363
|
return;
|
|
16628
|
-
var elem =
|
|
16364
|
+
var elem = fs3[gracefulQueue].shift();
|
|
16629
16365
|
var fn = elem[0];
|
|
16630
16366
|
var args = elem[1];
|
|
16631
16367
|
var err = elem[2];
|
|
@@ -16647,7 +16383,7 @@ GFS4: `);
|
|
|
16647
16383
|
debug("RETRY", fn.name, args);
|
|
16648
16384
|
fn.apply(null, args.concat([startTime]));
|
|
16649
16385
|
} else {
|
|
16650
|
-
|
|
16386
|
+
fs3[gracefulQueue].push(elem);
|
|
16651
16387
|
}
|
|
16652
16388
|
}
|
|
16653
16389
|
if (retryTimer === undefined) {
|
|
@@ -16951,7 +16687,7 @@ var require_signal_exit = __commonJS((exports, module) => {
|
|
|
16951
16687
|
emitter.count -= 1;
|
|
16952
16688
|
};
|
|
16953
16689
|
module.exports.unload = unload;
|
|
16954
|
-
|
|
16690
|
+
emit2 = function emit3(event, code, signal) {
|
|
16955
16691
|
if (emitter.emitted[event]) {
|
|
16956
16692
|
return;
|
|
16957
16693
|
}
|
|
@@ -16967,8 +16703,8 @@ var require_signal_exit = __commonJS((exports, module) => {
|
|
|
16967
16703
|
var listeners = process3.listeners(sig);
|
|
16968
16704
|
if (listeners.length === emitter.count) {
|
|
16969
16705
|
unload();
|
|
16970
|
-
|
|
16971
|
-
|
|
16706
|
+
emit2("exit", null, sig);
|
|
16707
|
+
emit2("afterexit", null, sig);
|
|
16972
16708
|
if (isWin && sig === "SIGHUP") {
|
|
16973
16709
|
sig = "SIGINT";
|
|
16974
16710
|
}
|
|
@@ -17004,8 +16740,8 @@ var require_signal_exit = __commonJS((exports, module) => {
|
|
|
17004
16740
|
return;
|
|
17005
16741
|
}
|
|
17006
16742
|
process3.exitCode = code || 0;
|
|
17007
|
-
|
|
17008
|
-
|
|
16743
|
+
emit2("exit", process3.exitCode, null);
|
|
16744
|
+
emit2("afterexit", process3.exitCode, null);
|
|
17009
16745
|
originalProcessReallyExit.call(process3, process3.exitCode);
|
|
17010
16746
|
};
|
|
17011
16747
|
originalProcessEmit = process3.emit;
|
|
@@ -17015,8 +16751,8 @@ var require_signal_exit = __commonJS((exports, module) => {
|
|
|
17015
16751
|
process3.exitCode = arg;
|
|
17016
16752
|
}
|
|
17017
16753
|
var ret = originalProcessEmit.apply(this, arguments);
|
|
17018
|
-
|
|
17019
|
-
|
|
16754
|
+
emit2("exit", process3.exitCode, null);
|
|
16755
|
+
emit2("afterexit", process3.exitCode, null);
|
|
17020
16756
|
return ret;
|
|
17021
16757
|
} else {
|
|
17022
16758
|
return originalProcessEmit.apply(this, arguments);
|
|
@@ -17029,7 +16765,7 @@ var require_signal_exit = __commonJS((exports, module) => {
|
|
|
17029
16765
|
var EE;
|
|
17030
16766
|
var emitter;
|
|
17031
16767
|
var unload;
|
|
17032
|
-
var
|
|
16768
|
+
var emit2;
|
|
17033
16769
|
var sigListeners;
|
|
17034
16770
|
var loaded;
|
|
17035
16771
|
var load;
|
|
@@ -17042,10 +16778,10 @@ var require_signal_exit = __commonJS((exports, module) => {
|
|
|
17042
16778
|
// node_modules/proper-lockfile/lib/mtime-precision.js
|
|
17043
16779
|
var require_mtime_precision = __commonJS((exports, module) => {
|
|
17044
16780
|
var cacheSymbol = Symbol();
|
|
17045
|
-
function probe(file2,
|
|
17046
|
-
const cachedPrecision =
|
|
16781
|
+
function probe(file2, fs3, callback) {
|
|
16782
|
+
const cachedPrecision = fs3[cacheSymbol];
|
|
17047
16783
|
if (cachedPrecision) {
|
|
17048
|
-
return
|
|
16784
|
+
return fs3.stat(file2, (err, stat) => {
|
|
17049
16785
|
if (err) {
|
|
17050
16786
|
return callback(err);
|
|
17051
16787
|
}
|
|
@@ -17053,16 +16789,16 @@ var require_mtime_precision = __commonJS((exports, module) => {
|
|
|
17053
16789
|
});
|
|
17054
16790
|
}
|
|
17055
16791
|
const mtime = new Date(Math.ceil(Date.now() / 1000) * 1000 + 5);
|
|
17056
|
-
|
|
16792
|
+
fs3.utimes(file2, mtime, mtime, (err) => {
|
|
17057
16793
|
if (err) {
|
|
17058
16794
|
return callback(err);
|
|
17059
16795
|
}
|
|
17060
|
-
|
|
16796
|
+
fs3.stat(file2, (err2, stat) => {
|
|
17061
16797
|
if (err2) {
|
|
17062
16798
|
return callback(err2);
|
|
17063
16799
|
}
|
|
17064
16800
|
const precision = stat.mtime.getTime() % 1000 === 0 ? "s" : "ms";
|
|
17065
|
-
Object.defineProperty(
|
|
16801
|
+
Object.defineProperty(fs3, cacheSymbol, { value: precision });
|
|
17066
16802
|
callback(null, stat.mtime, precision);
|
|
17067
16803
|
});
|
|
17068
16804
|
});
|
|
@@ -17080,8 +16816,8 @@ var require_mtime_precision = __commonJS((exports, module) => {
|
|
|
17080
16816
|
|
|
17081
16817
|
// node_modules/proper-lockfile/lib/lockfile.js
|
|
17082
16818
|
var require_lockfile = __commonJS((exports, module) => {
|
|
17083
|
-
var
|
|
17084
|
-
var
|
|
16819
|
+
var path5 = __require("path");
|
|
16820
|
+
var fs3 = require_graceful_fs();
|
|
17085
16821
|
var retry = require_retry();
|
|
17086
16822
|
var onExit = require_signal_exit();
|
|
17087
16823
|
var mtimePrecision = require_mtime_precision();
|
|
@@ -17091,7 +16827,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
17091
16827
|
}
|
|
17092
16828
|
function resolveCanonicalPath(file2, options, callback) {
|
|
17093
16829
|
if (!options.realpath) {
|
|
17094
|
-
return callback(null,
|
|
16830
|
+
return callback(null, path5.resolve(file2));
|
|
17095
16831
|
}
|
|
17096
16832
|
options.fs.realpath(file2, callback);
|
|
17097
16833
|
}
|
|
@@ -17204,7 +16940,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
17204
16940
|
update: null,
|
|
17205
16941
|
realpath: true,
|
|
17206
16942
|
retries: 0,
|
|
17207
|
-
fs:
|
|
16943
|
+
fs: fs3,
|
|
17208
16944
|
onCompromised: (err) => {
|
|
17209
16945
|
throw err;
|
|
17210
16946
|
},
|
|
@@ -17248,7 +16984,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
17248
16984
|
}
|
|
17249
16985
|
function unlock(file2, options, callback) {
|
|
17250
16986
|
options = {
|
|
17251
|
-
fs:
|
|
16987
|
+
fs: fs3,
|
|
17252
16988
|
realpath: true,
|
|
17253
16989
|
...options
|
|
17254
16990
|
};
|
|
@@ -17270,7 +17006,7 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
17270
17006
|
options = {
|
|
17271
17007
|
stale: 1e4,
|
|
17272
17008
|
realpath: true,
|
|
17273
|
-
fs:
|
|
17009
|
+
fs: fs3,
|
|
17274
17010
|
...options
|
|
17275
17011
|
};
|
|
17276
17012
|
options.stale = Math.max(options.stale || 0, 2000);
|
|
@@ -17305,16 +17041,16 @@ var require_lockfile = __commonJS((exports, module) => {
|
|
|
17305
17041
|
|
|
17306
17042
|
// node_modules/proper-lockfile/lib/adapter.js
|
|
17307
17043
|
var require_adapter = __commonJS((exports, module) => {
|
|
17308
|
-
var
|
|
17309
|
-
function createSyncFs(
|
|
17044
|
+
var fs3 = require_graceful_fs();
|
|
17045
|
+
function createSyncFs(fs4) {
|
|
17310
17046
|
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
|
|
17311
|
-
const newFs = { ...
|
|
17047
|
+
const newFs = { ...fs4 };
|
|
17312
17048
|
methods.forEach((method) => {
|
|
17313
17049
|
newFs[method] = (...args) => {
|
|
17314
17050
|
const callback = args.pop();
|
|
17315
17051
|
let ret;
|
|
17316
17052
|
try {
|
|
17317
|
-
ret =
|
|
17053
|
+
ret = fs4[`${method}Sync`](...args);
|
|
17318
17054
|
} catch (err) {
|
|
17319
17055
|
return callback(err);
|
|
17320
17056
|
}
|
|
@@ -17324,12 +17060,12 @@ var require_adapter = __commonJS((exports, module) => {
|
|
|
17324
17060
|
return newFs;
|
|
17325
17061
|
}
|
|
17326
17062
|
function toPromise(method) {
|
|
17327
|
-
return (...args) => new Promise((
|
|
17063
|
+
return (...args) => new Promise((resolve3, reject) => {
|
|
17328
17064
|
args.push((err, result) => {
|
|
17329
17065
|
if (err) {
|
|
17330
17066
|
reject(err);
|
|
17331
17067
|
} else {
|
|
17332
|
-
|
|
17068
|
+
resolve3(result);
|
|
17333
17069
|
}
|
|
17334
17070
|
});
|
|
17335
17071
|
method(...args);
|
|
@@ -17352,7 +17088,7 @@ var require_adapter = __commonJS((exports, module) => {
|
|
|
17352
17088
|
}
|
|
17353
17089
|
function toSyncOptions(options) {
|
|
17354
17090
|
options = { ...options };
|
|
17355
|
-
options.fs = createSyncFs(options.fs ||
|
|
17091
|
+
options.fs = createSyncFs(options.fs || fs3);
|
|
17356
17092
|
if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
|
|
17357
17093
|
throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
|
|
17358
17094
|
}
|
|
@@ -17377,25 +17113,459 @@ var require_proper_lockfile = __commonJS((exports, module) => {
|
|
|
17377
17113
|
const release = toSync(lockfile.lock)(file2, toSyncOptions(options));
|
|
17378
17114
|
return toSync(release);
|
|
17379
17115
|
}
|
|
17380
|
-
function unlock(file2, options) {
|
|
17381
|
-
return toPromise(lockfile.unlock)(file2, options);
|
|
17116
|
+
function unlock(file2, options) {
|
|
17117
|
+
return toPromise(lockfile.unlock)(file2, options);
|
|
17118
|
+
}
|
|
17119
|
+
function unlockSync(file2, options) {
|
|
17120
|
+
return toSync(lockfile.unlock)(file2, toSyncOptions(options));
|
|
17121
|
+
}
|
|
17122
|
+
function check2(file2, options) {
|
|
17123
|
+
return toPromise(lockfile.check)(file2, options);
|
|
17124
|
+
}
|
|
17125
|
+
function checkSync(file2, options) {
|
|
17126
|
+
return toSync(lockfile.check)(file2, toSyncOptions(options));
|
|
17127
|
+
}
|
|
17128
|
+
module.exports = lock;
|
|
17129
|
+
module.exports.lock = lock;
|
|
17130
|
+
module.exports.unlock = unlock;
|
|
17131
|
+
module.exports.lockSync = lockSync;
|
|
17132
|
+
module.exports.unlockSync = unlockSync;
|
|
17133
|
+
module.exports.check = check2;
|
|
17134
|
+
module.exports.checkSync = checkSync;
|
|
17135
|
+
});
|
|
17136
|
+
|
|
17137
|
+
// src/parallel/file-locks.ts
|
|
17138
|
+
import * as fs3 from "fs";
|
|
17139
|
+
import * as path5 from "path";
|
|
17140
|
+
function getLockFilePath(directory, filePath) {
|
|
17141
|
+
const normalized = path5.resolve(directory, filePath);
|
|
17142
|
+
const baseDir = path5.resolve(directory) + path5.sep;
|
|
17143
|
+
const pathOk = process.platform === "win32" ? normalized.toLowerCase().startsWith(baseDir.toLowerCase()) : normalized.startsWith(baseDir);
|
|
17144
|
+
if (!pathOk) {
|
|
17145
|
+
throw new Error("Invalid file path: path traversal not allowed");
|
|
17146
|
+
}
|
|
17147
|
+
const hash2 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
17148
|
+
return path5.join(directory, LOCKS_DIR, `${hash2}.lock`);
|
|
17149
|
+
}
|
|
17150
|
+
async function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
17151
|
+
const lockPath = getLockFilePath(directory, filePath);
|
|
17152
|
+
const locksDir = path5.dirname(lockPath);
|
|
17153
|
+
if (!fs3.existsSync(locksDir)) {
|
|
17154
|
+
fs3.mkdirSync(locksDir, { recursive: true });
|
|
17155
|
+
}
|
|
17156
|
+
if (!fs3.existsSync(lockPath)) {
|
|
17157
|
+
fs3.writeFileSync(lockPath, "", "utf-8");
|
|
17158
|
+
}
|
|
17159
|
+
let release;
|
|
17160
|
+
try {
|
|
17161
|
+
release = await import_proper_lockfile.default.lock(lockPath, {
|
|
17162
|
+
stale: LOCK_TIMEOUT_MS,
|
|
17163
|
+
retries: { retries: 0 },
|
|
17164
|
+
realpath: false
|
|
17165
|
+
});
|
|
17166
|
+
} catch (err) {
|
|
17167
|
+
const code = err.code;
|
|
17168
|
+
if (code === "ELOCKED" || code === "EEXIST") {
|
|
17169
|
+
return { acquired: false };
|
|
17170
|
+
}
|
|
17171
|
+
throw err;
|
|
17172
|
+
}
|
|
17173
|
+
const lock = {
|
|
17174
|
+
filePath,
|
|
17175
|
+
agent,
|
|
17176
|
+
taskId,
|
|
17177
|
+
timestamp: new Date().toISOString(),
|
|
17178
|
+
expiresAt: Date.now() + LOCK_TIMEOUT_MS,
|
|
17179
|
+
_release: release
|
|
17180
|
+
};
|
|
17181
|
+
return { acquired: true, lock };
|
|
17182
|
+
}
|
|
17183
|
+
var import_proper_lockfile, LOCKS_DIR = ".swarm/locks", LOCK_TIMEOUT_MS;
|
|
17184
|
+
var init_file_locks = __esm(() => {
|
|
17185
|
+
import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
17186
|
+
LOCK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
17187
|
+
});
|
|
17188
|
+
|
|
17189
|
+
// src/evidence/lock.ts
|
|
17190
|
+
function backoffMs(attempt) {
|
|
17191
|
+
const base = Math.min(BACKOFF_START_MS * 2 ** attempt, BACKOFF_MAX_MS);
|
|
17192
|
+
const jitter = base * BACKOFF_JITTER_RATIO * (Math.random() * 2 - 1);
|
|
17193
|
+
return Math.max(1, Math.round(base + jitter));
|
|
17194
|
+
}
|
|
17195
|
+
async function withEvidenceLock(directory, evidencePath, agent, taskId, fn, timeoutMs = 60000) {
|
|
17196
|
+
const deadline = Date.now() + timeoutMs;
|
|
17197
|
+
let attempt = 0;
|
|
17198
|
+
while (true) {
|
|
17199
|
+
const result = await tryAcquireLock(directory, evidencePath, agent, taskId);
|
|
17200
|
+
if (result.acquired) {
|
|
17201
|
+
const lock = result.lock;
|
|
17202
|
+
if (attempt > 0) {
|
|
17203
|
+
emit("evidence_lock_stale_recovered", {
|
|
17204
|
+
directory,
|
|
17205
|
+
evidencePath,
|
|
17206
|
+
agent,
|
|
17207
|
+
taskId,
|
|
17208
|
+
attempt
|
|
17209
|
+
});
|
|
17210
|
+
}
|
|
17211
|
+
emit("evidence_lock_acquired", {
|
|
17212
|
+
directory,
|
|
17213
|
+
evidencePath,
|
|
17214
|
+
agent,
|
|
17215
|
+
taskId,
|
|
17216
|
+
attempt
|
|
17217
|
+
});
|
|
17218
|
+
try {
|
|
17219
|
+
return await fn();
|
|
17220
|
+
} finally {
|
|
17221
|
+
if (lock._release) {
|
|
17222
|
+
try {
|
|
17223
|
+
await lock._release();
|
|
17224
|
+
} catch {}
|
|
17225
|
+
}
|
|
17226
|
+
}
|
|
17227
|
+
}
|
|
17228
|
+
if (Date.now() >= deadline) {
|
|
17229
|
+
throw new EvidenceLockTimeoutError(directory, evidencePath, agent, taskId, timeoutMs);
|
|
17230
|
+
}
|
|
17231
|
+
emit("evidence_lock_contended", {
|
|
17232
|
+
directory,
|
|
17233
|
+
evidencePath,
|
|
17234
|
+
agent,
|
|
17235
|
+
taskId,
|
|
17236
|
+
attempt
|
|
17237
|
+
});
|
|
17238
|
+
const delay = Math.min(backoffMs(attempt), deadline - Date.now());
|
|
17239
|
+
if (delay > 0) {
|
|
17240
|
+
await new Promise((resolve4) => setTimeout(resolve4, delay));
|
|
17241
|
+
}
|
|
17242
|
+
attempt++;
|
|
17243
|
+
}
|
|
17244
|
+
}
|
|
17245
|
+
var EvidenceLockTimeoutError, BACKOFF_START_MS = 50, BACKOFF_MAX_MS = 2000, BACKOFF_JITTER_RATIO = 0.25;
|
|
17246
|
+
var init_lock = __esm(() => {
|
|
17247
|
+
init_file_locks();
|
|
17248
|
+
init_telemetry();
|
|
17249
|
+
EvidenceLockTimeoutError = class EvidenceLockTimeoutError extends Error {
|
|
17250
|
+
directory;
|
|
17251
|
+
evidencePath;
|
|
17252
|
+
agent;
|
|
17253
|
+
taskId;
|
|
17254
|
+
constructor(directory, evidencePath, agent, taskId, timeoutMs) {
|
|
17255
|
+
super(`Evidence lock timeout after ${timeoutMs}ms for ${evidencePath} (agent=${agent}, task=${taskId})`);
|
|
17256
|
+
this.name = "EvidenceLockTimeoutError";
|
|
17257
|
+
this.directory = directory;
|
|
17258
|
+
this.evidencePath = evidencePath;
|
|
17259
|
+
this.agent = agent;
|
|
17260
|
+
this.taskId = taskId;
|
|
17261
|
+
}
|
|
17262
|
+
};
|
|
17263
|
+
});
|
|
17264
|
+
|
|
17265
|
+
// src/validation/task-id.ts
|
|
17266
|
+
function checkUnsafeChars(taskId) {
|
|
17267
|
+
if (!taskId || taskId.length === 0) {
|
|
17268
|
+
return "Invalid task ID: empty string";
|
|
17269
|
+
}
|
|
17270
|
+
if (/\0/.test(taskId)) {
|
|
17271
|
+
return "Invalid task ID: contains null bytes";
|
|
17272
|
+
}
|
|
17273
|
+
for (let i = 0;i < taskId.length; i++) {
|
|
17274
|
+
if (taskId.charCodeAt(i) < 32) {
|
|
17275
|
+
return "Invalid task ID: contains control characters";
|
|
17276
|
+
}
|
|
17277
|
+
}
|
|
17278
|
+
if (taskId.includes("..") || taskId.includes("/") || taskId.includes("\\")) {
|
|
17279
|
+
return "Invalid task ID: path traversal detected";
|
|
17280
|
+
}
|
|
17281
|
+
return;
|
|
17282
|
+
}
|
|
17283
|
+
function sanitizeTaskId(taskId) {
|
|
17284
|
+
const unsafeMsg = checkUnsafeChars(taskId);
|
|
17285
|
+
if (unsafeMsg) {
|
|
17286
|
+
throw new Error(unsafeMsg);
|
|
17287
|
+
}
|
|
17288
|
+
if (STRICT_TASK_ID_PATTERN.test(taskId) || RETRO_TASK_ID_REGEX.test(taskId) || INTERNAL_TOOL_ID_REGEX.test(taskId) || GENERAL_TASK_ID_REGEX.test(taskId)) {
|
|
17289
|
+
return taskId;
|
|
17290
|
+
}
|
|
17291
|
+
throw new Error(`Invalid task ID: must be alphanumeric (ASCII) with optional hyphens, underscores, or dots, got "${taskId}"`);
|
|
17292
|
+
}
|
|
17293
|
+
var STRICT_TASK_ID_PATTERN, RETRO_TASK_ID_REGEX, INTERNAL_TOOL_ID_REGEX, GENERAL_TASK_ID_REGEX;
|
|
17294
|
+
var init_task_id = __esm(() => {
|
|
17295
|
+
STRICT_TASK_ID_PATTERN = /^\d+\.\d+(\.\d+)*$/;
|
|
17296
|
+
RETRO_TASK_ID_REGEX = /^retro-\d+$/;
|
|
17297
|
+
INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build|secretscan)$/;
|
|
17298
|
+
GENERAL_TASK_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
17299
|
+
});
|
|
17300
|
+
|
|
17301
|
+
// src/evidence/manager.ts
|
|
17302
|
+
import { mkdirSync as mkdirSync3, readdirSync as readdirSync3, rmSync, statSync as statSync3 } from "fs";
|
|
17303
|
+
import * as fs4 from "fs/promises";
|
|
17304
|
+
import * as path6 from "path";
|
|
17305
|
+
function isValidEvidenceType(type) {
|
|
17306
|
+
return VALID_EVIDENCE_TYPES.includes(type);
|
|
17307
|
+
}
|
|
17308
|
+
async function saveEvidence(directory, taskId, evidence) {
|
|
17309
|
+
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
17310
|
+
const relativePath = path6.join("evidence", sanitizedTaskId, "evidence.json");
|
|
17311
|
+
validateSwarmPath(directory, relativePath);
|
|
17312
|
+
return withEvidenceLock(directory, relativePath, "evidence-manager", sanitizedTaskId, async () => {
|
|
17313
|
+
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
17314
|
+
const evidenceDir = path6.dirname(evidencePath);
|
|
17315
|
+
let bundle;
|
|
17316
|
+
const existingContent = await readSwarmFileAsync(directory, relativePath);
|
|
17317
|
+
if (existingContent !== null) {
|
|
17318
|
+
try {
|
|
17319
|
+
const parsed = JSON.parse(existingContent);
|
|
17320
|
+
bundle = EvidenceBundleSchema.parse(parsed);
|
|
17321
|
+
} catch (error49) {
|
|
17322
|
+
warn(`Existing evidence bundle invalid for task ${sanitizedTaskId}, creating new: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
17323
|
+
const now = new Date().toISOString();
|
|
17324
|
+
bundle = {
|
|
17325
|
+
schema_version: "1.0.0",
|
|
17326
|
+
task_id: sanitizedTaskId,
|
|
17327
|
+
entries: [],
|
|
17328
|
+
created_at: now,
|
|
17329
|
+
updated_at: now
|
|
17330
|
+
};
|
|
17331
|
+
}
|
|
17332
|
+
} else {
|
|
17333
|
+
const now = new Date().toISOString();
|
|
17334
|
+
bundle = {
|
|
17335
|
+
schema_version: "1.0.0",
|
|
17336
|
+
task_id: sanitizedTaskId,
|
|
17337
|
+
entries: [],
|
|
17338
|
+
created_at: now,
|
|
17339
|
+
updated_at: now
|
|
17340
|
+
};
|
|
17341
|
+
}
|
|
17342
|
+
const MAX_BUNDLE_ENTRIES = 100;
|
|
17343
|
+
let entries = [...bundle.entries, evidence];
|
|
17344
|
+
if (entries.length > MAX_BUNDLE_ENTRIES) {
|
|
17345
|
+
entries = entries.slice(entries.length - MAX_BUNDLE_ENTRIES);
|
|
17346
|
+
}
|
|
17347
|
+
const updatedBundle = {
|
|
17348
|
+
...bundle,
|
|
17349
|
+
entries,
|
|
17350
|
+
updated_at: new Date().toISOString()
|
|
17351
|
+
};
|
|
17352
|
+
const bundleJson = JSON.stringify(updatedBundle);
|
|
17353
|
+
if (bundleJson.length > EVIDENCE_MAX_JSON_BYTES) {
|
|
17354
|
+
throw new Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);
|
|
17355
|
+
}
|
|
17356
|
+
mkdirSync3(evidenceDir, { recursive: true });
|
|
17357
|
+
const tempPath = path6.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
17358
|
+
try {
|
|
17359
|
+
await Bun.write(tempPath, bundleJson);
|
|
17360
|
+
await fs4.rename(tempPath, evidencePath);
|
|
17361
|
+
} catch (error49) {
|
|
17362
|
+
try {
|
|
17363
|
+
rmSync(tempPath, { force: true });
|
|
17364
|
+
} catch {}
|
|
17365
|
+
throw error49;
|
|
17366
|
+
}
|
|
17367
|
+
return updatedBundle;
|
|
17368
|
+
});
|
|
17369
|
+
}
|
|
17370
|
+
function isFlatRetrospective(parsed) {
|
|
17371
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && parsed.type === "retrospective" && !parsed.schema_version;
|
|
17372
|
+
}
|
|
17373
|
+
function remapLegacyTaskComplexity(entry) {
|
|
17374
|
+
const taskComplexity = entry.task_complexity;
|
|
17375
|
+
if (typeof taskComplexity === "string" && taskComplexity in LEGACY_TASK_COMPLEXITY_MAP) {
|
|
17376
|
+
return {
|
|
17377
|
+
...entry,
|
|
17378
|
+
task_complexity: LEGACY_TASK_COMPLEXITY_MAP[taskComplexity]
|
|
17379
|
+
};
|
|
17380
|
+
}
|
|
17381
|
+
return entry;
|
|
17382
|
+
}
|
|
17383
|
+
function wrapFlatRetrospective(flatEntry, taskId) {
|
|
17384
|
+
const now = new Date().toISOString();
|
|
17385
|
+
const remappedEntry = remapLegacyTaskComplexity(flatEntry);
|
|
17386
|
+
return {
|
|
17387
|
+
schema_version: "1.0.0",
|
|
17388
|
+
task_id: remappedEntry.task_id ?? taskId,
|
|
17389
|
+
created_at: remappedEntry.timestamp ?? now,
|
|
17390
|
+
updated_at: remappedEntry.timestamp ?? now,
|
|
17391
|
+
entries: [remappedEntry]
|
|
17392
|
+
};
|
|
17393
|
+
}
|
|
17394
|
+
async function loadEvidence(directory, taskId) {
|
|
17395
|
+
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
17396
|
+
const relativePath = path6.join("evidence", sanitizedTaskId, "evidence.json");
|
|
17397
|
+
const evidencePath = validateSwarmPath(directory, relativePath);
|
|
17398
|
+
const content = await readSwarmFileAsync(directory, relativePath);
|
|
17399
|
+
if (content === null) {
|
|
17400
|
+
return { status: "not_found" };
|
|
17401
|
+
}
|
|
17402
|
+
let parsed;
|
|
17403
|
+
try {
|
|
17404
|
+
parsed = JSON.parse(content);
|
|
17405
|
+
} catch {
|
|
17406
|
+
return { status: "invalid_schema", errors: ["Invalid JSON"] };
|
|
17407
|
+
}
|
|
17408
|
+
if (isFlatRetrospective(parsed)) {
|
|
17409
|
+
const wrappedBundle = wrapFlatRetrospective(parsed, sanitizedTaskId);
|
|
17410
|
+
try {
|
|
17411
|
+
const validated = EvidenceBundleSchema.parse(wrappedBundle);
|
|
17412
|
+
try {
|
|
17413
|
+
await withEvidenceLock(directory, relativePath, "evidence-loader", sanitizedTaskId, async () => {
|
|
17414
|
+
const evidenceDir = path6.dirname(evidencePath);
|
|
17415
|
+
const bundleJson = JSON.stringify(validated);
|
|
17416
|
+
const tempPath = path6.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
|
|
17417
|
+
try {
|
|
17418
|
+
await Bun.write(tempPath, bundleJson);
|
|
17419
|
+
await fs4.rename(tempPath, evidencePath);
|
|
17420
|
+
} catch (writeError) {
|
|
17421
|
+
try {
|
|
17422
|
+
rmSync(tempPath, { force: true });
|
|
17423
|
+
} catch {}
|
|
17424
|
+
warn(`Failed to persist repaired flat retrospective for task ${sanitizedTaskId}: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
17425
|
+
}
|
|
17426
|
+
});
|
|
17427
|
+
} catch (lockErr) {
|
|
17428
|
+
warn(`Evidence lock failed during flat-retrospective write-back for task ${sanitizedTaskId}: ${lockErr instanceof Error ? lockErr.message : String(lockErr)}`);
|
|
17429
|
+
}
|
|
17430
|
+
return { status: "found", bundle: validated };
|
|
17431
|
+
} catch (error49) {
|
|
17432
|
+
warn(`Wrapped flat retrospective failed validation for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
17433
|
+
const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error49 instanceof Error ? error49.message : String(error49)];
|
|
17434
|
+
return { status: "invalid_schema", errors: errors3 };
|
|
17435
|
+
}
|
|
17436
|
+
}
|
|
17437
|
+
try {
|
|
17438
|
+
const validated = EvidenceBundleSchema.parse(parsed);
|
|
17439
|
+
return { status: "found", bundle: validated };
|
|
17440
|
+
} catch (error49) {
|
|
17441
|
+
warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
17442
|
+
const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error49 instanceof Error ? error49.message : String(error49)];
|
|
17443
|
+
return { status: "invalid_schema", errors: errors3 };
|
|
17444
|
+
}
|
|
17445
|
+
}
|
|
17446
|
+
async function listEvidenceTaskIds(directory) {
|
|
17447
|
+
const evidenceBasePath = validateSwarmPath(directory, "evidence");
|
|
17448
|
+
try {
|
|
17449
|
+
statSync3(evidenceBasePath);
|
|
17450
|
+
} catch {
|
|
17451
|
+
return [];
|
|
17452
|
+
}
|
|
17453
|
+
let entries;
|
|
17454
|
+
try {
|
|
17455
|
+
entries = readdirSync3(evidenceBasePath);
|
|
17456
|
+
} catch {
|
|
17457
|
+
return [];
|
|
17458
|
+
}
|
|
17459
|
+
const taskIds = [];
|
|
17460
|
+
for (const entry of entries) {
|
|
17461
|
+
const entryPath = path6.join(evidenceBasePath, entry);
|
|
17462
|
+
try {
|
|
17463
|
+
const stats = statSync3(entryPath);
|
|
17464
|
+
if (!stats.isDirectory()) {
|
|
17465
|
+
continue;
|
|
17466
|
+
}
|
|
17467
|
+
sanitizeTaskId2(entry);
|
|
17468
|
+
taskIds.push(entry);
|
|
17469
|
+
} catch (error49) {
|
|
17470
|
+
if (error49 instanceof Error && !error49.message.startsWith("Invalid task ID")) {
|
|
17471
|
+
warn(`Error reading evidence entry '${entry}': ${error49.message}`);
|
|
17472
|
+
}
|
|
17473
|
+
}
|
|
17474
|
+
}
|
|
17475
|
+
return taskIds.sort();
|
|
17476
|
+
}
|
|
17477
|
+
async function deleteEvidence(directory, taskId) {
|
|
17478
|
+
const sanitizedTaskId = sanitizeTaskId2(taskId);
|
|
17479
|
+
const relativePath = path6.join("evidence", sanitizedTaskId);
|
|
17480
|
+
const evidenceDir = validateSwarmPath(directory, relativePath);
|
|
17481
|
+
try {
|
|
17482
|
+
statSync3(evidenceDir);
|
|
17483
|
+
} catch {
|
|
17484
|
+
return false;
|
|
17485
|
+
}
|
|
17486
|
+
try {
|
|
17487
|
+
rmSync(evidenceDir, { recursive: true, force: true });
|
|
17488
|
+
return true;
|
|
17489
|
+
} catch (error49) {
|
|
17490
|
+
warn(`Failed to delete evidence for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
17491
|
+
return false;
|
|
17382
17492
|
}
|
|
17383
|
-
|
|
17384
|
-
|
|
17493
|
+
}
|
|
17494
|
+
async function checkRequirementCoverage(phase, directory) {
|
|
17495
|
+
const relativePath = path6.join("evidence", `req-coverage-phase-${phase}.json`);
|
|
17496
|
+
const absolutePath = path6.resolve(directory, ".swarm", relativePath);
|
|
17497
|
+
try {
|
|
17498
|
+
await fs4.access(absolutePath);
|
|
17499
|
+
return { exists: true, path: absolutePath };
|
|
17500
|
+
} catch {
|
|
17501
|
+
return { exists: false, path: absolutePath };
|
|
17385
17502
|
}
|
|
17386
|
-
|
|
17387
|
-
|
|
17503
|
+
}
|
|
17504
|
+
async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
17505
|
+
const taskIds = await listEvidenceTaskIds(directory);
|
|
17506
|
+
const cutoffDate = new Date;
|
|
17507
|
+
cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
|
|
17508
|
+
const cutoffIso = cutoffDate.toISOString();
|
|
17509
|
+
const archived = [];
|
|
17510
|
+
const remainingBundles = [];
|
|
17511
|
+
for (const taskId of taskIds) {
|
|
17512
|
+
const result = await loadEvidence(directory, taskId);
|
|
17513
|
+
if (result.status !== "found") {
|
|
17514
|
+
continue;
|
|
17515
|
+
}
|
|
17516
|
+
if (result.bundle.updated_at < cutoffIso) {
|
|
17517
|
+
const deleted = await deleteEvidence(directory, taskId);
|
|
17518
|
+
if (deleted) {
|
|
17519
|
+
archived.push(taskId);
|
|
17520
|
+
}
|
|
17521
|
+
} else {
|
|
17522
|
+
remainingBundles.push({
|
|
17523
|
+
taskId,
|
|
17524
|
+
updatedAt: result.bundle.updated_at
|
|
17525
|
+
});
|
|
17526
|
+
}
|
|
17388
17527
|
}
|
|
17389
|
-
|
|
17390
|
-
|
|
17528
|
+
if (maxBundles !== undefined && remainingBundles.length > maxBundles) {
|
|
17529
|
+
remainingBundles.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt));
|
|
17530
|
+
const toDelete = remainingBundles.length - maxBundles;
|
|
17531
|
+
for (let i = 0;i < toDelete; i++) {
|
|
17532
|
+
const deleted = await deleteEvidence(directory, remainingBundles[i].taskId);
|
|
17533
|
+
if (deleted) {
|
|
17534
|
+
archived.push(remainingBundles[i].taskId);
|
|
17535
|
+
}
|
|
17536
|
+
}
|
|
17391
17537
|
}
|
|
17392
|
-
|
|
17393
|
-
|
|
17394
|
-
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
17398
|
-
|
|
17538
|
+
return archived;
|
|
17539
|
+
}
|
|
17540
|
+
var VALID_EVIDENCE_TYPES, sanitizeTaskId2, LEGACY_TASK_COMPLEXITY_MAP;
|
|
17541
|
+
var init_manager2 = __esm(() => {
|
|
17542
|
+
init_zod();
|
|
17543
|
+
init_evidence_schema();
|
|
17544
|
+
init_utils2();
|
|
17545
|
+
init_utils();
|
|
17546
|
+
init_lock();
|
|
17547
|
+
init_task_id();
|
|
17548
|
+
VALID_EVIDENCE_TYPES = [
|
|
17549
|
+
"review",
|
|
17550
|
+
"test",
|
|
17551
|
+
"diff",
|
|
17552
|
+
"approval",
|
|
17553
|
+
"note",
|
|
17554
|
+
"retrospective",
|
|
17555
|
+
"syntax",
|
|
17556
|
+
"placeholder",
|
|
17557
|
+
"sast",
|
|
17558
|
+
"sbom",
|
|
17559
|
+
"build",
|
|
17560
|
+
"quality_budget",
|
|
17561
|
+
"secretscan"
|
|
17562
|
+
];
|
|
17563
|
+
sanitizeTaskId2 = sanitizeTaskId;
|
|
17564
|
+
LEGACY_TASK_COMPLEXITY_MAP = {
|
|
17565
|
+
low: "simple",
|
|
17566
|
+
medium: "moderate",
|
|
17567
|
+
high: "complex"
|
|
17568
|
+
};
|
|
17399
17569
|
});
|
|
17400
17570
|
|
|
17401
17571
|
// src/services/config-doctor.ts
|
|
@@ -17412,15 +17582,15 @@ __export(exports_config_doctor, {
|
|
|
17412
17582
|
applySafeAutoFixes: () => applySafeAutoFixes
|
|
17413
17583
|
});
|
|
17414
17584
|
import * as crypto3 from "crypto";
|
|
17415
|
-
import * as
|
|
17416
|
-
import * as
|
|
17417
|
-
import * as
|
|
17585
|
+
import * as fs9 from "fs";
|
|
17586
|
+
import * as os5 from "os";
|
|
17587
|
+
import * as path18 from "path";
|
|
17418
17588
|
function getUserConfigDir3() {
|
|
17419
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
17589
|
+
return process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config");
|
|
17420
17590
|
}
|
|
17421
17591
|
function getConfigPaths(directory) {
|
|
17422
|
-
const userConfigPath =
|
|
17423
|
-
const projectConfigPath =
|
|
17592
|
+
const userConfigPath = path18.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
17593
|
+
const projectConfigPath = path18.join(directory, ".opencode", "opencode-swarm.json");
|
|
17424
17594
|
return { userConfigPath, projectConfigPath };
|
|
17425
17595
|
}
|
|
17426
17596
|
function computeHash(content) {
|
|
@@ -17445,9 +17615,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
17445
17615
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
17446
17616
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
17447
17617
|
try {
|
|
17448
|
-
const resolvedConfig =
|
|
17449
|
-
const resolvedUser =
|
|
17450
|
-
const resolvedProject =
|
|
17618
|
+
const resolvedConfig = path18.resolve(configPath);
|
|
17619
|
+
const resolvedUser = path18.resolve(normalizedUser);
|
|
17620
|
+
const resolvedProject = path18.resolve(normalizedProject);
|
|
17451
17621
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
17452
17622
|
} catch {
|
|
17453
17623
|
return false;
|
|
@@ -17457,19 +17627,19 @@ function createConfigBackup(directory) {
|
|
|
17457
17627
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17458
17628
|
let configPath = projectConfigPath;
|
|
17459
17629
|
let content = null;
|
|
17460
|
-
if (
|
|
17630
|
+
if (fs9.existsSync(projectConfigPath)) {
|
|
17461
17631
|
try {
|
|
17462
|
-
content =
|
|
17632
|
+
content = fs9.readFileSync(projectConfigPath, "utf-8");
|
|
17463
17633
|
} catch (error93) {
|
|
17464
17634
|
log("[ConfigDoctor] project config read failed", {
|
|
17465
17635
|
error: error93 instanceof Error ? error93.message : String(error93)
|
|
17466
17636
|
});
|
|
17467
17637
|
}
|
|
17468
17638
|
}
|
|
17469
|
-
if (content === null &&
|
|
17639
|
+
if (content === null && fs9.existsSync(userConfigPath)) {
|
|
17470
17640
|
configPath = userConfigPath;
|
|
17471
17641
|
try {
|
|
17472
|
-
content =
|
|
17642
|
+
content = fs9.readFileSync(userConfigPath, "utf-8");
|
|
17473
17643
|
} catch (error93) {
|
|
17474
17644
|
log("[ConfigDoctor] user config read failed", {
|
|
17475
17645
|
error: error93 instanceof Error ? error93.message : String(error93)
|
|
@@ -17487,12 +17657,12 @@ function createConfigBackup(directory) {
|
|
|
17487
17657
|
};
|
|
17488
17658
|
}
|
|
17489
17659
|
function writeBackupArtifact(directory, backup) {
|
|
17490
|
-
const swarmDir =
|
|
17491
|
-
if (!
|
|
17492
|
-
|
|
17660
|
+
const swarmDir = path18.join(directory, ".swarm");
|
|
17661
|
+
if (!fs9.existsSync(swarmDir)) {
|
|
17662
|
+
fs9.mkdirSync(swarmDir, { recursive: true });
|
|
17493
17663
|
}
|
|
17494
17664
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
17495
|
-
const backupPath =
|
|
17665
|
+
const backupPath = path18.join(swarmDir, backupFilename);
|
|
17496
17666
|
const artifact = {
|
|
17497
17667
|
createdAt: backup.createdAt,
|
|
17498
17668
|
configPath: backup.configPath,
|
|
@@ -17500,15 +17670,15 @@ function writeBackupArtifact(directory, backup) {
|
|
|
17500
17670
|
content: backup.content,
|
|
17501
17671
|
preview: backup.content.substring(0, 500) + (backup.content.length > 500 ? "..." : "")
|
|
17502
17672
|
};
|
|
17503
|
-
|
|
17673
|
+
fs9.writeFileSync(backupPath, JSON.stringify(artifact, null, 2), "utf-8");
|
|
17504
17674
|
return backupPath;
|
|
17505
17675
|
}
|
|
17506
17676
|
function restoreFromBackup(backupPath, directory) {
|
|
17507
|
-
if (!
|
|
17677
|
+
if (!fs9.existsSync(backupPath)) {
|
|
17508
17678
|
return null;
|
|
17509
17679
|
}
|
|
17510
17680
|
try {
|
|
17511
|
-
const artifact = JSON.parse(
|
|
17681
|
+
const artifact = JSON.parse(fs9.readFileSync(backupPath, "utf-8"));
|
|
17512
17682
|
if (!artifact.content || !artifact.configPath || !artifact.contentHash) {
|
|
17513
17683
|
return null;
|
|
17514
17684
|
}
|
|
@@ -17522,11 +17692,11 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
17522
17692
|
return null;
|
|
17523
17693
|
}
|
|
17524
17694
|
const targetPath = artifact.configPath;
|
|
17525
|
-
const targetDir =
|
|
17526
|
-
if (!
|
|
17527
|
-
|
|
17695
|
+
const targetDir = path18.dirname(targetPath);
|
|
17696
|
+
if (!fs9.existsSync(targetDir)) {
|
|
17697
|
+
fs9.mkdirSync(targetDir, { recursive: true });
|
|
17528
17698
|
}
|
|
17529
|
-
|
|
17699
|
+
fs9.writeFileSync(targetPath, artifact.content, "utf-8");
|
|
17530
17700
|
return targetPath;
|
|
17531
17701
|
} catch {
|
|
17532
17702
|
return null;
|
|
@@ -17536,12 +17706,12 @@ function readConfigFromFile(directory) {
|
|
|
17536
17706
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17537
17707
|
let configPath = projectConfigPath;
|
|
17538
17708
|
let configContent = null;
|
|
17539
|
-
if (
|
|
17709
|
+
if (fs9.existsSync(projectConfigPath)) {
|
|
17540
17710
|
configPath = projectConfigPath;
|
|
17541
|
-
configContent =
|
|
17542
|
-
} else if (
|
|
17711
|
+
configContent = fs9.readFileSync(projectConfigPath, "utf-8");
|
|
17712
|
+
} else if (fs9.existsSync(userConfigPath)) {
|
|
17543
17713
|
configPath = userConfigPath;
|
|
17544
|
-
configContent =
|
|
17714
|
+
configContent = fs9.readFileSync(userConfigPath, "utf-8");
|
|
17545
17715
|
}
|
|
17546
17716
|
if (configContent === null) {
|
|
17547
17717
|
return null;
|
|
@@ -17553,9 +17723,9 @@ function readConfigFromFile(directory) {
|
|
|
17553
17723
|
return null;
|
|
17554
17724
|
}
|
|
17555
17725
|
}
|
|
17556
|
-
function validateConfigKey(
|
|
17726
|
+
function validateConfigKey(path19, value, _config) {
|
|
17557
17727
|
const findings = [];
|
|
17558
|
-
switch (
|
|
17728
|
+
switch (path19) {
|
|
17559
17729
|
case "agents": {
|
|
17560
17730
|
if (value !== undefined) {
|
|
17561
17731
|
findings.push({
|
|
@@ -17802,27 +17972,27 @@ function validateConfigKey(path18, value, _config) {
|
|
|
17802
17972
|
}
|
|
17803
17973
|
return findings;
|
|
17804
17974
|
}
|
|
17805
|
-
function walkConfigAndValidate(obj,
|
|
17975
|
+
function walkConfigAndValidate(obj, path19, config3, findings) {
|
|
17806
17976
|
if (obj === null || obj === undefined) {
|
|
17807
17977
|
return;
|
|
17808
17978
|
}
|
|
17809
|
-
if (
|
|
17810
|
-
const keyFindings = validateConfigKey(
|
|
17979
|
+
if (path19 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
17980
|
+
const keyFindings = validateConfigKey(path19, obj, config3);
|
|
17811
17981
|
findings.push(...keyFindings);
|
|
17812
17982
|
}
|
|
17813
17983
|
if (typeof obj !== "object") {
|
|
17814
|
-
const keyFindings = validateConfigKey(
|
|
17984
|
+
const keyFindings = validateConfigKey(path19, obj, config3);
|
|
17815
17985
|
findings.push(...keyFindings);
|
|
17816
17986
|
return;
|
|
17817
17987
|
}
|
|
17818
17988
|
if (Array.isArray(obj)) {
|
|
17819
17989
|
obj.forEach((item, index) => {
|
|
17820
|
-
walkConfigAndValidate(item, `${
|
|
17990
|
+
walkConfigAndValidate(item, `${path19}[${index}]`, config3, findings);
|
|
17821
17991
|
});
|
|
17822
17992
|
return;
|
|
17823
17993
|
}
|
|
17824
17994
|
for (const [key, value] of Object.entries(obj)) {
|
|
17825
|
-
const newPath =
|
|
17995
|
+
const newPath = path19 ? `${path19}.${key}` : key;
|
|
17826
17996
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
17827
17997
|
}
|
|
17828
17998
|
}
|
|
@@ -17837,9 +18007,9 @@ function runConfigDoctor(config3, directory) {
|
|
|
17837
18007
|
const hasAutoFixableIssues = findings.some((f) => f.autoFixable && f.proposedFix?.risk === "low");
|
|
17838
18008
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17839
18009
|
let configSource = "defaults";
|
|
17840
|
-
if (
|
|
18010
|
+
if (fs9.existsSync(projectConfigPath)) {
|
|
17841
18011
|
configSource = projectConfigPath;
|
|
17842
|
-
} else if (
|
|
18012
|
+
} else if (fs9.existsSync(userConfigPath)) {
|
|
17843
18013
|
configSource = userConfigPath;
|
|
17844
18014
|
}
|
|
17845
18015
|
return {
|
|
@@ -17868,12 +18038,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
17868
18038
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17869
18039
|
let configPath = projectConfigPath;
|
|
17870
18040
|
let configContent;
|
|
17871
|
-
if (
|
|
18041
|
+
if (fs9.existsSync(projectConfigPath)) {
|
|
17872
18042
|
configPath = projectConfigPath;
|
|
17873
|
-
configContent =
|
|
17874
|
-
} else if (
|
|
18043
|
+
configContent = fs9.readFileSync(projectConfigPath, "utf-8");
|
|
18044
|
+
} else if (fs9.existsSync(userConfigPath)) {
|
|
17875
18045
|
configPath = userConfigPath;
|
|
17876
|
-
configContent =
|
|
18046
|
+
configContent = fs9.readFileSync(userConfigPath, "utf-8");
|
|
17877
18047
|
} else {
|
|
17878
18048
|
return { appliedFixes, updatedConfigPath: null };
|
|
17879
18049
|
}
|
|
@@ -17942,22 +18112,22 @@ function applySafeAutoFixes(directory, result) {
|
|
|
17942
18112
|
}
|
|
17943
18113
|
}
|
|
17944
18114
|
if (appliedFixes.length > 0) {
|
|
17945
|
-
const configDir =
|
|
17946
|
-
if (!
|
|
17947
|
-
|
|
18115
|
+
const configDir = path18.dirname(configPath);
|
|
18116
|
+
if (!fs9.existsSync(configDir)) {
|
|
18117
|
+
fs9.mkdirSync(configDir, { recursive: true });
|
|
17948
18118
|
}
|
|
17949
|
-
|
|
18119
|
+
fs9.writeFileSync(configPath, JSON.stringify(config3, null, 2), "utf-8");
|
|
17950
18120
|
updatedConfigPath = configPath;
|
|
17951
18121
|
}
|
|
17952
18122
|
return { appliedFixes, updatedConfigPath };
|
|
17953
18123
|
}
|
|
17954
18124
|
function writeDoctorArtifact(directory, result) {
|
|
17955
|
-
const swarmDir =
|
|
17956
|
-
if (!
|
|
17957
|
-
|
|
18125
|
+
const swarmDir = path18.join(directory, ".swarm");
|
|
18126
|
+
if (!fs9.existsSync(swarmDir)) {
|
|
18127
|
+
fs9.mkdirSync(swarmDir, { recursive: true });
|
|
17958
18128
|
}
|
|
17959
18129
|
const artifactFilename = "config-doctor.json";
|
|
17960
|
-
const artifactPath =
|
|
18130
|
+
const artifactPath = path18.join(swarmDir, artifactFilename);
|
|
17961
18131
|
const guiOutput = {
|
|
17962
18132
|
timestamp: result.timestamp,
|
|
17963
18133
|
summary: result.summary,
|
|
@@ -17978,7 +18148,7 @@ function writeDoctorArtifact(directory, result) {
|
|
|
17978
18148
|
} : null
|
|
17979
18149
|
}))
|
|
17980
18150
|
};
|
|
17981
|
-
|
|
18151
|
+
fs9.writeFileSync(artifactPath, JSON.stringify(guiOutput, null, 2), "utf-8");
|
|
17982
18152
|
return artifactPath;
|
|
17983
18153
|
}
|
|
17984
18154
|
function shouldRunOnStartup(automationConfig) {
|
|
@@ -18318,9 +18488,9 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
18318
18488
|
});
|
|
18319
18489
|
|
|
18320
18490
|
// src/cli/index.ts
|
|
18321
|
-
import * as
|
|
18322
|
-
import * as
|
|
18323
|
-
import * as
|
|
18491
|
+
import * as fs23 from "fs";
|
|
18492
|
+
import * as os7 from "os";
|
|
18493
|
+
import * as path33 from "path";
|
|
18324
18494
|
|
|
18325
18495
|
// src/commands/acknowledge-spec-drift.ts
|
|
18326
18496
|
init_utils2();
|
|
@@ -18456,7 +18626,7 @@ async function handleAnalyzeCommand(_directory, args) {
|
|
|
18456
18626
|
|
|
18457
18627
|
// src/config/loader.ts
|
|
18458
18628
|
import * as fs2 from "fs";
|
|
18459
|
-
import * as
|
|
18629
|
+
import * as os2 from "os";
|
|
18460
18630
|
import * as path4 from "path";
|
|
18461
18631
|
|
|
18462
18632
|
// src/config/schema.ts
|
|
@@ -19241,6 +19411,11 @@ var CouncilConfigSchema = exports_external.object({
|
|
|
19241
19411
|
requireAllMembers: exports_external.boolean().default(false).describe("When true, convene_council rejects if fewer than 5 member verdicts are provided."),
|
|
19242
19412
|
escalateOnMaxRounds: exports_external.string().optional().describe("Optional webhook URL or handler name invoked when maxRounds is reached without APPROVE. Declared for forward compatibility; no behavior is implemented yet.")
|
|
19243
19413
|
}).strict();
|
|
19414
|
+
var ParallelizationConfigSchema = exports_external.object({
|
|
19415
|
+
enabled: exports_external.boolean().default(false),
|
|
19416
|
+
maxConcurrentTasks: exports_external.number().int().min(1).max(64).default(1),
|
|
19417
|
+
evidenceLockTimeoutMs: exports_external.number().int().min(1000).max(300000).default(60000)
|
|
19418
|
+
});
|
|
19244
19419
|
var PluginConfigSchema = exports_external.object({
|
|
19245
19420
|
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
19246
19421
|
swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
|
|
@@ -19289,6 +19464,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19289
19464
|
incremental_verify: IncrementalVerifyConfigSchema.optional(),
|
|
19290
19465
|
compaction_service: CompactionConfigSchema.optional(),
|
|
19291
19466
|
council: CouncilConfigSchema.optional(),
|
|
19467
|
+
parallelization: ParallelizationConfigSchema.optional(),
|
|
19292
19468
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
19293
19469
|
full_auto: exports_external.object({
|
|
19294
19470
|
enabled: exports_external.boolean().default(false),
|
|
@@ -19308,7 +19484,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19308
19484
|
var CONFIG_FILENAME = "opencode-swarm.json";
|
|
19309
19485
|
var MAX_CONFIG_FILE_BYTES = 102400;
|
|
19310
19486
|
function getUserConfigDir() {
|
|
19311
|
-
return process.env.XDG_CONFIG_HOME || path4.join(
|
|
19487
|
+
return process.env.XDG_CONFIG_HOME || path4.join(os2.homedir(), ".config");
|
|
19312
19488
|
}
|
|
19313
19489
|
function loadRawConfigFromPath(configPath) {
|
|
19314
19490
|
try {
|
|
@@ -19496,8 +19672,8 @@ import { createHash as createHash3 } from "crypto";
|
|
|
19496
19672
|
|
|
19497
19673
|
// src/db/project-db.ts
|
|
19498
19674
|
import { Database } from "bun:sqlite";
|
|
19499
|
-
import { existsSync as
|
|
19500
|
-
import { join as
|
|
19675
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
|
|
19676
|
+
import { join as join7, resolve as resolve5 } from "path";
|
|
19501
19677
|
var MIGRATIONS = [
|
|
19502
19678
|
{
|
|
19503
19679
|
version: 1,
|
|
@@ -19556,19 +19732,19 @@ function runProjectMigrations(db) {
|
|
|
19556
19732
|
}
|
|
19557
19733
|
}
|
|
19558
19734
|
function projectDbPath(directory) {
|
|
19559
|
-
return
|
|
19735
|
+
return join7(resolve5(directory), ".swarm", "swarm.db");
|
|
19560
19736
|
}
|
|
19561
19737
|
function projectDbExists(directory) {
|
|
19562
|
-
return
|
|
19738
|
+
return existsSync5(projectDbPath(directory));
|
|
19563
19739
|
}
|
|
19564
19740
|
function getProjectDb(directory) {
|
|
19565
|
-
const key =
|
|
19741
|
+
const key = resolve5(directory);
|
|
19566
19742
|
const existing = _projectDbs.get(key);
|
|
19567
19743
|
if (existing)
|
|
19568
19744
|
return existing;
|
|
19569
|
-
const swarmDir =
|
|
19570
|
-
|
|
19571
|
-
const db = new Database(
|
|
19745
|
+
const swarmDir = join7(key, ".swarm");
|
|
19746
|
+
mkdirSync4(swarmDir, { recursive: true });
|
|
19747
|
+
const db = new Database(join7(swarmDir, "swarm.db"));
|
|
19572
19748
|
db.run("PRAGMA journal_mode = WAL;");
|
|
19573
19749
|
db.run("PRAGMA synchronous = NORMAL;");
|
|
19574
19750
|
db.run("PRAGMA busy_timeout = 5000;");
|
|
@@ -20002,9 +20178,9 @@ var warnedAgents = new Set;
|
|
|
20002
20178
|
init_manager();
|
|
20003
20179
|
|
|
20004
20180
|
// src/scope/scope-persistence.ts
|
|
20005
|
-
var
|
|
20006
|
-
import * as
|
|
20007
|
-
import * as
|
|
20181
|
+
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
20182
|
+
import * as fs5 from "fs";
|
|
20183
|
+
import * as path7 from "path";
|
|
20008
20184
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
20009
20185
|
var LOCK_STALE_MS = 30 * 1000;
|
|
20010
20186
|
var SCOPES_DIR = ".swarm/scopes";
|
|
@@ -20035,11 +20211,11 @@ var WINDOWS_RESERVED = new Set([
|
|
|
20035
20211
|
"LPT9"
|
|
20036
20212
|
]);
|
|
20037
20213
|
function getScopesDir(directory) {
|
|
20038
|
-
return
|
|
20214
|
+
return path7.join(directory, SCOPES_DIR);
|
|
20039
20215
|
}
|
|
20040
20216
|
function clearAllScopes(directory) {
|
|
20041
20217
|
try {
|
|
20042
|
-
|
|
20218
|
+
fs5.rmSync(getScopesDir(directory), { recursive: true, force: true });
|
|
20043
20219
|
} catch {}
|
|
20044
20220
|
}
|
|
20045
20221
|
|
|
@@ -20138,23 +20314,48 @@ function clearPendingCoderScope() {
|
|
|
20138
20314
|
|
|
20139
20315
|
// src/state.ts
|
|
20140
20316
|
init_manager();
|
|
20317
|
+
|
|
20318
|
+
// src/state/agent-run-context.ts
|
|
20319
|
+
class AgentRunContext {
|
|
20320
|
+
runId;
|
|
20321
|
+
activeToolCalls;
|
|
20322
|
+
activeAgent;
|
|
20323
|
+
delegationChains;
|
|
20324
|
+
agentSessions;
|
|
20325
|
+
environmentProfiles;
|
|
20326
|
+
toolAggregates;
|
|
20327
|
+
constructor(runId, toolAggregates) {
|
|
20328
|
+
this.runId = runId;
|
|
20329
|
+
this.activeToolCalls = new Map;
|
|
20330
|
+
this.activeAgent = new Map;
|
|
20331
|
+
this.delegationChains = new Map;
|
|
20332
|
+
this.agentSessions = new Map;
|
|
20333
|
+
this.environmentProfiles = new Map;
|
|
20334
|
+
this.toolAggregates = toolAggregates;
|
|
20335
|
+
}
|
|
20336
|
+
}
|
|
20337
|
+
|
|
20338
|
+
// src/state.ts
|
|
20141
20339
|
init_telemetry();
|
|
20142
20340
|
var _rehydrationCache = null;
|
|
20143
20341
|
var _councilDisagreementWarned = new Set;
|
|
20342
|
+
var _toolAggregates = new Map;
|
|
20343
|
+
var defaultRunContext = new AgentRunContext("default", _toolAggregates);
|
|
20344
|
+
var _runContexts = new Map;
|
|
20144
20345
|
var swarmState = {
|
|
20145
|
-
activeToolCalls:
|
|
20146
|
-
toolAggregates:
|
|
20147
|
-
activeAgent:
|
|
20148
|
-
delegationChains:
|
|
20346
|
+
activeToolCalls: defaultRunContext.activeToolCalls,
|
|
20347
|
+
toolAggregates: defaultRunContext.toolAggregates,
|
|
20348
|
+
activeAgent: defaultRunContext.activeAgent,
|
|
20349
|
+
delegationChains: defaultRunContext.delegationChains,
|
|
20149
20350
|
pendingEvents: 0,
|
|
20150
20351
|
opencodeClient: null,
|
|
20151
20352
|
curatorInitAgentNames: [],
|
|
20152
20353
|
curatorPhaseAgentNames: [],
|
|
20153
20354
|
lastBudgetPct: 0,
|
|
20154
|
-
agentSessions:
|
|
20355
|
+
agentSessions: defaultRunContext.agentSessions,
|
|
20155
20356
|
pendingRehydrations: new Set,
|
|
20156
20357
|
fullAutoEnabledInConfig: false,
|
|
20157
|
-
environmentProfiles:
|
|
20358
|
+
environmentProfiles: defaultRunContext.environmentProfiles
|
|
20158
20359
|
};
|
|
20159
20360
|
function resetSwarmState() {
|
|
20160
20361
|
swarmState.activeToolCalls.clear();
|
|
@@ -20532,8 +20733,8 @@ init_zod();
|
|
|
20532
20733
|
|
|
20533
20734
|
// src/tools/checkpoint.ts
|
|
20534
20735
|
import * as child_process from "child_process";
|
|
20535
|
-
import * as
|
|
20536
|
-
import * as
|
|
20736
|
+
import * as fs6 from "fs";
|
|
20737
|
+
import * as path8 from "path";
|
|
20537
20738
|
|
|
20538
20739
|
// node_modules/@opencode-ai/plugin/node_modules/zod/v4/classic/external.js
|
|
20539
20740
|
var exports_external2 = {};
|
|
@@ -21264,10 +21465,10 @@ function mergeDefs2(...defs) {
|
|
|
21264
21465
|
function cloneDef2(schema) {
|
|
21265
21466
|
return mergeDefs2(schema._zod.def);
|
|
21266
21467
|
}
|
|
21267
|
-
function getElementAtPath2(obj,
|
|
21268
|
-
if (!
|
|
21468
|
+
function getElementAtPath2(obj, path8) {
|
|
21469
|
+
if (!path8)
|
|
21269
21470
|
return obj;
|
|
21270
|
-
return
|
|
21471
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
21271
21472
|
}
|
|
21272
21473
|
function promiseAllObject2(promisesObj) {
|
|
21273
21474
|
const keys = Object.keys(promisesObj);
|
|
@@ -21626,11 +21827,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
21626
21827
|
}
|
|
21627
21828
|
return false;
|
|
21628
21829
|
}
|
|
21629
|
-
function prefixIssues2(
|
|
21830
|
+
function prefixIssues2(path8, issues) {
|
|
21630
21831
|
return issues.map((iss) => {
|
|
21631
21832
|
var _a2;
|
|
21632
21833
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
21633
|
-
iss.path.unshift(
|
|
21834
|
+
iss.path.unshift(path8);
|
|
21634
21835
|
return iss;
|
|
21635
21836
|
});
|
|
21636
21837
|
}
|
|
@@ -21798,7 +21999,7 @@ function treeifyError2(error49, _mapper) {
|
|
|
21798
21999
|
return issue3.message;
|
|
21799
22000
|
};
|
|
21800
22001
|
const result = { errors: [] };
|
|
21801
|
-
const processError = (error50,
|
|
22002
|
+
const processError = (error50, path8 = []) => {
|
|
21802
22003
|
var _a2, _b;
|
|
21803
22004
|
for (const issue3 of error50.issues) {
|
|
21804
22005
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -21808,7 +22009,7 @@ function treeifyError2(error49, _mapper) {
|
|
|
21808
22009
|
} else if (issue3.code === "invalid_element") {
|
|
21809
22010
|
processError({ issues: issue3.issues }, issue3.path);
|
|
21810
22011
|
} else {
|
|
21811
|
-
const fullpath = [...
|
|
22012
|
+
const fullpath = [...path8, ...issue3.path];
|
|
21812
22013
|
if (fullpath.length === 0) {
|
|
21813
22014
|
result.errors.push(mapper(issue3));
|
|
21814
22015
|
continue;
|
|
@@ -21840,8 +22041,8 @@ function treeifyError2(error49, _mapper) {
|
|
|
21840
22041
|
}
|
|
21841
22042
|
function toDotPath2(_path) {
|
|
21842
22043
|
const segs = [];
|
|
21843
|
-
const
|
|
21844
|
-
for (const seg of
|
|
22044
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
22045
|
+
for (const seg of path8) {
|
|
21845
22046
|
if (typeof seg === "number")
|
|
21846
22047
|
segs.push(`[${seg}]`);
|
|
21847
22048
|
else if (typeof seg === "symbol")
|
|
@@ -32938,13 +33139,13 @@ function validateLabel(label) {
|
|
|
32938
33139
|
return null;
|
|
32939
33140
|
}
|
|
32940
33141
|
function getCheckpointLogPath(directory) {
|
|
32941
|
-
return
|
|
33142
|
+
return path8.join(directory, CHECKPOINT_LOG_PATH);
|
|
32942
33143
|
}
|
|
32943
33144
|
function readCheckpointLog(directory) {
|
|
32944
33145
|
const logPath = getCheckpointLogPath(directory);
|
|
32945
33146
|
try {
|
|
32946
|
-
if (
|
|
32947
|
-
const content =
|
|
33147
|
+
if (fs6.existsSync(logPath)) {
|
|
33148
|
+
const content = fs6.readFileSync(logPath, "utf-8");
|
|
32948
33149
|
const parsed = JSON.parse(content);
|
|
32949
33150
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
32950
33151
|
return { version: 1, checkpoints: [] };
|
|
@@ -32956,13 +33157,13 @@ function readCheckpointLog(directory) {
|
|
|
32956
33157
|
}
|
|
32957
33158
|
function writeCheckpointLog(log2, directory) {
|
|
32958
33159
|
const logPath = getCheckpointLogPath(directory);
|
|
32959
|
-
const dir =
|
|
32960
|
-
if (!
|
|
32961
|
-
|
|
33160
|
+
const dir = path8.dirname(logPath);
|
|
33161
|
+
if (!fs6.existsSync(dir)) {
|
|
33162
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
32962
33163
|
}
|
|
32963
33164
|
const tempPath = `${logPath}.tmp`;
|
|
32964
|
-
|
|
32965
|
-
|
|
33165
|
+
fs6.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
33166
|
+
fs6.renameSync(tempPath, logPath);
|
|
32966
33167
|
}
|
|
32967
33168
|
function gitExec(args) {
|
|
32968
33169
|
const result = child_process.spawnSync("git", args, {
|
|
@@ -33296,8 +33497,8 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
33296
33497
|
|
|
33297
33498
|
// src/commands/close.ts
|
|
33298
33499
|
import { execFileSync } from "child_process";
|
|
33299
|
-
import { promises as
|
|
33300
|
-
import
|
|
33500
|
+
import { promises as fs8 } from "fs";
|
|
33501
|
+
import path13 from "path";
|
|
33301
33502
|
init_manager2();
|
|
33302
33503
|
|
|
33303
33504
|
// src/git/branch.ts
|
|
@@ -33347,36 +33548,36 @@ function hasUncommittedChanges(cwd) {
|
|
|
33347
33548
|
}
|
|
33348
33549
|
|
|
33349
33550
|
// src/hooks/knowledge-store.ts
|
|
33350
|
-
var
|
|
33351
|
-
import { existsSync as
|
|
33551
|
+
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
33552
|
+
import { existsSync as existsSync7 } from "fs";
|
|
33352
33553
|
import { appendFile as appendFile2, mkdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
33353
|
-
import * as
|
|
33354
|
-
import * as
|
|
33554
|
+
import * as os3 from "os";
|
|
33555
|
+
import * as path9 from "path";
|
|
33355
33556
|
function resolveSwarmKnowledgePath(directory) {
|
|
33356
|
-
return
|
|
33557
|
+
return path9.join(directory, ".swarm", "knowledge.jsonl");
|
|
33357
33558
|
}
|
|
33358
33559
|
function resolveSwarmRejectedPath(directory) {
|
|
33359
|
-
return
|
|
33560
|
+
return path9.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
33360
33561
|
}
|
|
33361
33562
|
function resolveHiveKnowledgePath() {
|
|
33362
33563
|
const platform = process.platform;
|
|
33363
|
-
const home =
|
|
33564
|
+
const home = os3.homedir();
|
|
33364
33565
|
let dataDir;
|
|
33365
33566
|
if (platform === "win32") {
|
|
33366
|
-
dataDir =
|
|
33567
|
+
dataDir = path9.join(process.env.LOCALAPPDATA || path9.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
33367
33568
|
} else if (platform === "darwin") {
|
|
33368
|
-
dataDir =
|
|
33569
|
+
dataDir = path9.join(home, "Library", "Application Support", "opencode-swarm");
|
|
33369
33570
|
} else {
|
|
33370
|
-
dataDir =
|
|
33571
|
+
dataDir = path9.join(process.env.XDG_DATA_HOME || path9.join(home, ".local", "share"), "opencode-swarm");
|
|
33371
33572
|
}
|
|
33372
|
-
return
|
|
33573
|
+
return path9.join(dataDir, "shared-learnings.jsonl");
|
|
33373
33574
|
}
|
|
33374
33575
|
function resolveHiveRejectedPath() {
|
|
33375
33576
|
const hivePath = resolveHiveKnowledgePath();
|
|
33376
|
-
return
|
|
33577
|
+
return path9.join(path9.dirname(hivePath), "shared-learnings-rejected.jsonl");
|
|
33377
33578
|
}
|
|
33378
33579
|
async function readKnowledge(filePath) {
|
|
33379
|
-
if (!
|
|
33580
|
+
if (!existsSync7(filePath))
|
|
33380
33581
|
return [];
|
|
33381
33582
|
const content = await readFile2(filePath, "utf-8");
|
|
33382
33583
|
const results = [];
|
|
@@ -33397,16 +33598,16 @@ async function readRejectedLessons(directory) {
|
|
|
33397
33598
|
return readKnowledge(resolveSwarmRejectedPath(directory));
|
|
33398
33599
|
}
|
|
33399
33600
|
async function appendKnowledge(filePath, entry) {
|
|
33400
|
-
await mkdir(
|
|
33601
|
+
await mkdir(path9.dirname(filePath), { recursive: true });
|
|
33401
33602
|
await appendFile2(filePath, `${JSON.stringify(entry)}
|
|
33402
33603
|
`, "utf-8");
|
|
33403
33604
|
}
|
|
33404
33605
|
async function rewriteKnowledge(filePath, entries) {
|
|
33405
|
-
const dir =
|
|
33606
|
+
const dir = path9.dirname(filePath);
|
|
33406
33607
|
await mkdir(dir, { recursive: true });
|
|
33407
33608
|
let release = null;
|
|
33408
33609
|
try {
|
|
33409
|
-
release = await
|
|
33610
|
+
release = await import_proper_lockfile3.default.lock(dir, {
|
|
33410
33611
|
retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
|
|
33411
33612
|
stale: 5000
|
|
33412
33613
|
});
|
|
@@ -33511,9 +33712,9 @@ function inferTags(lesson) {
|
|
|
33511
33712
|
}
|
|
33512
33713
|
|
|
33513
33714
|
// src/hooks/knowledge-validator.ts
|
|
33514
|
-
var
|
|
33715
|
+
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
33515
33716
|
import { appendFile as appendFile3, mkdir as mkdir2, writeFile as writeFile3 } from "fs/promises";
|
|
33516
|
-
import * as
|
|
33717
|
+
import * as path10 from "path";
|
|
33517
33718
|
var DANGEROUS_COMMAND_PATTERNS = [
|
|
33518
33719
|
/\brm\s+-rf\b/,
|
|
33519
33720
|
/\bsudo\s+rm\b/,
|
|
@@ -33768,14 +33969,14 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
|
|
|
33768
33969
|
return;
|
|
33769
33970
|
}
|
|
33770
33971
|
const sanitizedReason = reason.slice(0, 500).replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/g, "");
|
|
33771
|
-
const knowledgePath =
|
|
33772
|
-
const quarantinePath =
|
|
33773
|
-
const rejectedPath =
|
|
33774
|
-
const swarmDir =
|
|
33972
|
+
const knowledgePath = path10.join(directory, ".swarm", "knowledge.jsonl");
|
|
33973
|
+
const quarantinePath = path10.join(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
33974
|
+
const rejectedPath = path10.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
33975
|
+
const swarmDir = path10.join(directory, ".swarm");
|
|
33775
33976
|
await mkdir2(swarmDir, { recursive: true });
|
|
33776
33977
|
let release;
|
|
33777
33978
|
try {
|
|
33778
|
-
release = await
|
|
33979
|
+
release = await import_proper_lockfile4.default.lock(swarmDir, {
|
|
33779
33980
|
retries: { retries: 3, minTimeout: 100 }
|
|
33780
33981
|
});
|
|
33781
33982
|
const entries = await readKnowledge(knowledgePath);
|
|
@@ -33828,14 +34029,14 @@ async function restoreEntry(directory, entryId) {
|
|
|
33828
34029
|
console.warn("[knowledge-validator] restoreEntry: invalid entryId rejected");
|
|
33829
34030
|
return;
|
|
33830
34031
|
}
|
|
33831
|
-
const knowledgePath =
|
|
33832
|
-
const quarantinePath =
|
|
33833
|
-
const rejectedPath =
|
|
33834
|
-
const swarmDir =
|
|
34032
|
+
const knowledgePath = path10.join(directory, ".swarm", "knowledge.jsonl");
|
|
34033
|
+
const quarantinePath = path10.join(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
34034
|
+
const rejectedPath = path10.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
34035
|
+
const swarmDir = path10.join(directory, ".swarm");
|
|
33835
34036
|
await mkdir2(swarmDir, { recursive: true });
|
|
33836
34037
|
let release;
|
|
33837
34038
|
try {
|
|
33838
|
-
release = await
|
|
34039
|
+
release = await import_proper_lockfile4.default.lock(swarmDir, {
|
|
33839
34040
|
retries: { retries: 3, minTimeout: 100 }
|
|
33840
34041
|
});
|
|
33841
34042
|
const quarantinedEntries = await readKnowledge(quarantinePath);
|
|
@@ -33990,18 +34191,18 @@ init_utils2();
|
|
|
33990
34191
|
init_plan_schema();
|
|
33991
34192
|
init_ledger();
|
|
33992
34193
|
init_manager();
|
|
33993
|
-
import * as
|
|
33994
|
-
import * as
|
|
34194
|
+
import * as fs7 from "fs";
|
|
34195
|
+
import * as path11 from "path";
|
|
33995
34196
|
async function writeCheckpoint(directory) {
|
|
33996
34197
|
try {
|
|
33997
34198
|
const plan = await loadPlan(directory);
|
|
33998
34199
|
if (!plan)
|
|
33999
34200
|
return;
|
|
34000
|
-
const jsonPath =
|
|
34001
|
-
const mdPath =
|
|
34002
|
-
|
|
34201
|
+
const jsonPath = path11.join(directory, "SWARM_PLAN.json");
|
|
34202
|
+
const mdPath = path11.join(directory, "SWARM_PLAN.md");
|
|
34203
|
+
fs7.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
34003
34204
|
const md = derivePlanMarkdown(plan);
|
|
34004
|
-
|
|
34205
|
+
fs7.writeFileSync(mdPath, md, "utf8");
|
|
34005
34206
|
} catch (error93) {
|
|
34006
34207
|
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
34007
34208
|
}
|
|
@@ -34009,8 +34210,8 @@ async function writeCheckpoint(directory) {
|
|
|
34009
34210
|
|
|
34010
34211
|
// src/session/snapshot-writer.ts
|
|
34011
34212
|
init_utils2();
|
|
34012
|
-
import { mkdirSync as
|
|
34013
|
-
import * as
|
|
34213
|
+
import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
|
|
34214
|
+
import * as path12 from "path";
|
|
34014
34215
|
init_utils();
|
|
34015
34216
|
var _writeInFlight = Promise.resolve();
|
|
34016
34217
|
function serializeAgentSession(s) {
|
|
@@ -34101,8 +34302,8 @@ async function writeSnapshot(directory, state) {
|
|
|
34101
34302
|
}
|
|
34102
34303
|
const content = JSON.stringify(snapshot, null, 2);
|
|
34103
34304
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
34104
|
-
const dir =
|
|
34105
|
-
|
|
34305
|
+
const dir = path12.dirname(resolvedPath);
|
|
34306
|
+
mkdirSync7(dir, { recursive: true });
|
|
34106
34307
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
34107
34308
|
await Bun.write(tempPath, content);
|
|
34108
34309
|
renameSync5(tempPath, resolvedPath);
|
|
@@ -34493,21 +34694,21 @@ var ACTIVE_STATE_TO_CLEAN = [
|
|
|
34493
34694
|
];
|
|
34494
34695
|
async function handleCloseCommand(directory, args) {
|
|
34495
34696
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
34496
|
-
const swarmDir =
|
|
34697
|
+
const swarmDir = path13.join(directory, ".swarm");
|
|
34497
34698
|
let planExists = false;
|
|
34498
34699
|
let planData = {
|
|
34499
|
-
title:
|
|
34700
|
+
title: path13.basename(directory) || "Ad-hoc session",
|
|
34500
34701
|
phases: []
|
|
34501
34702
|
};
|
|
34502
34703
|
try {
|
|
34503
|
-
const content = await
|
|
34704
|
+
const content = await fs8.readFile(planPath, "utf-8");
|
|
34504
34705
|
planData = JSON.parse(content);
|
|
34505
34706
|
planExists = true;
|
|
34506
34707
|
} catch (error93) {
|
|
34507
34708
|
if (error93?.code !== "ENOENT") {
|
|
34508
34709
|
return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
34509
34710
|
}
|
|
34510
|
-
const swarmDirExists = await
|
|
34711
|
+
const swarmDirExists = await fs8.access(swarmDir).then(() => true).catch(() => false);
|
|
34511
34712
|
if (!swarmDirExists) {
|
|
34512
34713
|
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
34513
34714
|
}
|
|
@@ -34601,10 +34802,10 @@ async function handleCloseCommand(directory, args) {
|
|
|
34601
34802
|
warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
34602
34803
|
}
|
|
34603
34804
|
}
|
|
34604
|
-
const lessonsFilePath =
|
|
34805
|
+
const lessonsFilePath = path13.join(swarmDir, "close-lessons.md");
|
|
34605
34806
|
let explicitLessons = [];
|
|
34606
34807
|
try {
|
|
34607
|
-
const lessonsText = await
|
|
34808
|
+
const lessonsText = await fs8.readFile(lessonsFilePath, "utf-8");
|
|
34608
34809
|
explicitLessons = lessonsText.split(`
|
|
34609
34810
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
34610
34811
|
} catch {}
|
|
@@ -34618,7 +34819,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34618
34819
|
console.warn("[close-command] curateAndStoreSwarm error:", error93);
|
|
34619
34820
|
}
|
|
34620
34821
|
if (curationSucceeded && explicitLessons.length > 0) {
|
|
34621
|
-
await
|
|
34822
|
+
await fs8.unlink(lessonsFilePath).catch(() => {});
|
|
34622
34823
|
}
|
|
34623
34824
|
if (planExists && !planAlreadyDone) {
|
|
34624
34825
|
for (const phase of phases) {
|
|
@@ -34638,7 +34839,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34638
34839
|
}
|
|
34639
34840
|
}
|
|
34640
34841
|
try {
|
|
34641
|
-
await
|
|
34842
|
+
await fs8.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
|
|
34642
34843
|
} catch (error93) {
|
|
34643
34844
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
34644
34845
|
warnings.push(`Failed to persist terminal plan.json state: ${msg}`);
|
|
@@ -34647,53 +34848,53 @@ async function handleCloseCommand(directory, args) {
|
|
|
34647
34848
|
}
|
|
34648
34849
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
34649
34850
|
const suffix = Math.random().toString(36).slice(2, 8);
|
|
34650
|
-
const archiveDir =
|
|
34851
|
+
const archiveDir = path13.join(swarmDir, "archive", `swarm-${timestamp}-${suffix}`);
|
|
34651
34852
|
let archiveResult = "";
|
|
34652
34853
|
let archivedFileCount = 0;
|
|
34653
34854
|
const archivedActiveStateFiles = new Set;
|
|
34654
34855
|
try {
|
|
34655
|
-
await
|
|
34856
|
+
await fs8.mkdir(archiveDir, { recursive: true });
|
|
34656
34857
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
34657
|
-
const srcPath =
|
|
34658
|
-
const destPath =
|
|
34858
|
+
const srcPath = path13.join(swarmDir, artifact);
|
|
34859
|
+
const destPath = path13.join(archiveDir, artifact);
|
|
34659
34860
|
try {
|
|
34660
|
-
await
|
|
34861
|
+
await fs8.copyFile(srcPath, destPath);
|
|
34661
34862
|
archivedFileCount++;
|
|
34662
34863
|
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
34663
34864
|
archivedActiveStateFiles.add(artifact);
|
|
34664
34865
|
}
|
|
34665
34866
|
} catch {}
|
|
34666
34867
|
}
|
|
34667
|
-
const evidenceDir =
|
|
34668
|
-
const archiveEvidenceDir =
|
|
34868
|
+
const evidenceDir = path13.join(swarmDir, "evidence");
|
|
34869
|
+
const archiveEvidenceDir = path13.join(archiveDir, "evidence");
|
|
34669
34870
|
try {
|
|
34670
|
-
const evidenceEntries = await
|
|
34871
|
+
const evidenceEntries = await fs8.readdir(evidenceDir);
|
|
34671
34872
|
if (evidenceEntries.length > 0) {
|
|
34672
|
-
await
|
|
34873
|
+
await fs8.mkdir(archiveEvidenceDir, { recursive: true });
|
|
34673
34874
|
for (const entry of evidenceEntries) {
|
|
34674
|
-
const srcEntry =
|
|
34675
|
-
const destEntry =
|
|
34875
|
+
const srcEntry = path13.join(evidenceDir, entry);
|
|
34876
|
+
const destEntry = path13.join(archiveEvidenceDir, entry);
|
|
34676
34877
|
try {
|
|
34677
|
-
const stat = await
|
|
34878
|
+
const stat = await fs8.stat(srcEntry);
|
|
34678
34879
|
if (stat.isDirectory()) {
|
|
34679
|
-
await
|
|
34680
|
-
const subEntries = await
|
|
34880
|
+
await fs8.mkdir(destEntry, { recursive: true });
|
|
34881
|
+
const subEntries = await fs8.readdir(srcEntry);
|
|
34681
34882
|
for (const sub of subEntries) {
|
|
34682
|
-
await
|
|
34883
|
+
await fs8.copyFile(path13.join(srcEntry, sub), path13.join(destEntry, sub)).catch(() => {});
|
|
34683
34884
|
}
|
|
34684
34885
|
} else {
|
|
34685
|
-
await
|
|
34886
|
+
await fs8.copyFile(srcEntry, destEntry);
|
|
34686
34887
|
}
|
|
34687
34888
|
archivedFileCount++;
|
|
34688
34889
|
} catch {}
|
|
34689
34890
|
}
|
|
34690
34891
|
}
|
|
34691
34892
|
} catch {}
|
|
34692
|
-
const sessionStatePath =
|
|
34893
|
+
const sessionStatePath = path13.join(swarmDir, "session", "state.json");
|
|
34693
34894
|
try {
|
|
34694
|
-
const archiveSessionDir =
|
|
34695
|
-
await
|
|
34696
|
-
await
|
|
34895
|
+
const archiveSessionDir = path13.join(archiveDir, "session");
|
|
34896
|
+
await fs8.mkdir(archiveSessionDir, { recursive: true });
|
|
34897
|
+
await fs8.copyFile(sessionStatePath, path13.join(archiveSessionDir, "state.json"));
|
|
34697
34898
|
archivedFileCount++;
|
|
34698
34899
|
} catch {}
|
|
34699
34900
|
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
@@ -34716,9 +34917,9 @@ async function handleCloseCommand(directory, args) {
|
|
|
34716
34917
|
warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
|
|
34717
34918
|
continue;
|
|
34718
34919
|
}
|
|
34719
|
-
const filePath =
|
|
34920
|
+
const filePath = path13.join(swarmDir, artifact);
|
|
34720
34921
|
try {
|
|
34721
|
-
await
|
|
34922
|
+
await fs8.unlink(filePath);
|
|
34722
34923
|
cleanedFiles.push(artifact);
|
|
34723
34924
|
} catch {}
|
|
34724
34925
|
}
|
|
@@ -34726,23 +34927,23 @@ async function handleCloseCommand(directory, args) {
|
|
|
34726
34927
|
warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
|
|
34727
34928
|
}
|
|
34728
34929
|
try {
|
|
34729
|
-
const swarmFiles = await
|
|
34930
|
+
const swarmFiles = await fs8.readdir(swarmDir);
|
|
34730
34931
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
34731
34932
|
for (const backup of configBackups) {
|
|
34732
34933
|
try {
|
|
34733
|
-
await
|
|
34934
|
+
await fs8.unlink(path13.join(swarmDir, backup));
|
|
34734
34935
|
configBackupsRemoved++;
|
|
34735
34936
|
} catch {}
|
|
34736
34937
|
}
|
|
34737
34938
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
34738
34939
|
for (const sibling of ledgerSiblings) {
|
|
34739
34940
|
try {
|
|
34740
|
-
await
|
|
34941
|
+
await fs8.unlink(path13.join(swarmDir, sibling));
|
|
34741
34942
|
} catch {}
|
|
34742
34943
|
}
|
|
34743
34944
|
} catch {}
|
|
34744
34945
|
clearAllScopes(directory);
|
|
34745
|
-
const contextPath =
|
|
34946
|
+
const contextPath = path13.join(swarmDir, "context.md");
|
|
34746
34947
|
const contextContent = [
|
|
34747
34948
|
"# Context",
|
|
34748
34949
|
"",
|
|
@@ -34755,7 +34956,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34755
34956
|
].join(`
|
|
34756
34957
|
`);
|
|
34757
34958
|
try {
|
|
34758
|
-
await
|
|
34959
|
+
await fs8.writeFile(contextPath, contextContent, "utf-8");
|
|
34759
34960
|
} catch (error93) {
|
|
34760
34961
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
34761
34962
|
warnings.push(`Failed to reset context.md: ${msg}`);
|
|
@@ -34886,7 +35087,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34886
35087
|
].join(`
|
|
34887
35088
|
`);
|
|
34888
35089
|
try {
|
|
34889
|
-
await
|
|
35090
|
+
await fs8.writeFile(closeSummaryPath, summaryContent, "utf-8");
|
|
34890
35091
|
} catch (error93) {
|
|
34891
35092
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
34892
35093
|
warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
@@ -34942,15 +35143,15 @@ ${otherWarnings.map((w) => `- ${w}`).join(`
|
|
|
34942
35143
|
}
|
|
34943
35144
|
|
|
34944
35145
|
// src/commands/config.ts
|
|
34945
|
-
import * as
|
|
34946
|
-
import * as
|
|
35146
|
+
import * as os4 from "os";
|
|
35147
|
+
import * as path14 from "path";
|
|
34947
35148
|
function getUserConfigDir2() {
|
|
34948
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
35149
|
+
return process.env.XDG_CONFIG_HOME || path14.join(os4.homedir(), ".config");
|
|
34949
35150
|
}
|
|
34950
35151
|
async function handleConfigCommand(directory, _args) {
|
|
34951
35152
|
const config3 = loadPluginConfig(directory);
|
|
34952
|
-
const userConfigPath =
|
|
34953
|
-
const projectConfigPath =
|
|
35153
|
+
const userConfigPath = path14.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
35154
|
+
const projectConfigPath = path14.join(directory, ".opencode", "opencode-swarm.json");
|
|
34954
35155
|
const lines = [
|
|
34955
35156
|
"## Swarm Configuration",
|
|
34956
35157
|
"",
|
|
@@ -35218,13 +35419,13 @@ function formatCurationSummary(summary) {
|
|
|
35218
35419
|
}
|
|
35219
35420
|
|
|
35220
35421
|
// src/commands/dark-matter.ts
|
|
35221
|
-
import
|
|
35422
|
+
import path16 from "path";
|
|
35222
35423
|
|
|
35223
35424
|
// src/tools/co-change-analyzer.ts
|
|
35224
35425
|
import * as child_process3 from "child_process";
|
|
35225
35426
|
import { randomUUID } from "crypto";
|
|
35226
35427
|
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
35227
|
-
import * as
|
|
35428
|
+
import * as path15 from "path";
|
|
35228
35429
|
import { promisify } from "util";
|
|
35229
35430
|
function getExecFileAsync() {
|
|
35230
35431
|
return promisify(child_process3.execFile);
|
|
@@ -35326,7 +35527,7 @@ async function scanSourceFiles(dir) {
|
|
|
35326
35527
|
try {
|
|
35327
35528
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
35328
35529
|
for (const entry of entries) {
|
|
35329
|
-
const fullPath =
|
|
35530
|
+
const fullPath = path15.join(dir, entry.name);
|
|
35330
35531
|
if (entry.isDirectory()) {
|
|
35331
35532
|
if (skipDirs.has(entry.name)) {
|
|
35332
35533
|
continue;
|
|
@@ -35334,7 +35535,7 @@ async function scanSourceFiles(dir) {
|
|
|
35334
35535
|
const subFiles = await scanSourceFiles(fullPath);
|
|
35335
35536
|
results.push(...subFiles);
|
|
35336
35537
|
} else if (entry.isFile()) {
|
|
35337
|
-
const ext =
|
|
35538
|
+
const ext = path15.extname(entry.name);
|
|
35338
35539
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
35339
35540
|
results.push(fullPath);
|
|
35340
35541
|
}
|
|
@@ -35356,8 +35557,8 @@ async function getStaticEdges(directory) {
|
|
|
35356
35557
|
continue;
|
|
35357
35558
|
}
|
|
35358
35559
|
try {
|
|
35359
|
-
const sourceDir =
|
|
35360
|
-
const resolvedPath =
|
|
35560
|
+
const sourceDir = path15.dirname(sourceFile);
|
|
35561
|
+
const resolvedPath = path15.resolve(sourceDir, importPath);
|
|
35361
35562
|
const extensions = [
|
|
35362
35563
|
"",
|
|
35363
35564
|
".ts",
|
|
@@ -35382,8 +35583,8 @@ async function getStaticEdges(directory) {
|
|
|
35382
35583
|
if (!targetFile) {
|
|
35383
35584
|
continue;
|
|
35384
35585
|
}
|
|
35385
|
-
const relSource =
|
|
35386
|
-
const relTarget =
|
|
35586
|
+
const relSource = path15.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
35587
|
+
const relTarget = path15.relative(directory, targetFile).replace(/\\/g, "/");
|
|
35387
35588
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
35388
35589
|
edges.add(key);
|
|
35389
35590
|
} catch {}
|
|
@@ -35395,7 +35596,7 @@ async function getStaticEdges(directory) {
|
|
|
35395
35596
|
function isTestImplementationPair(fileA, fileB) {
|
|
35396
35597
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
35397
35598
|
const getBaseName = (filePath) => {
|
|
35398
|
-
const base =
|
|
35599
|
+
const base = path15.basename(filePath);
|
|
35399
35600
|
for (const pattern of testPatterns) {
|
|
35400
35601
|
if (base.endsWith(pattern)) {
|
|
35401
35602
|
return base.slice(0, -pattern.length);
|
|
@@ -35405,16 +35606,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
35405
35606
|
};
|
|
35406
35607
|
const baseA = getBaseName(fileA);
|
|
35407
35608
|
const baseB = getBaseName(fileB);
|
|
35408
|
-
return baseA === baseB && baseA !==
|
|
35609
|
+
return baseA === baseB && baseA !== path15.basename(fileA) && baseA !== path15.basename(fileB);
|
|
35409
35610
|
}
|
|
35410
35611
|
function hasSharedPrefix(fileA, fileB) {
|
|
35411
|
-
const dirA =
|
|
35412
|
-
const dirB =
|
|
35612
|
+
const dirA = path15.dirname(fileA);
|
|
35613
|
+
const dirB = path15.dirname(fileB);
|
|
35413
35614
|
if (dirA !== dirB) {
|
|
35414
35615
|
return false;
|
|
35415
35616
|
}
|
|
35416
|
-
const baseA =
|
|
35417
|
-
const baseB =
|
|
35617
|
+
const baseA = path15.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
35618
|
+
const baseB = path15.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
35418
35619
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
35419
35620
|
return true;
|
|
35420
35621
|
}
|
|
@@ -35468,8 +35669,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
35468
35669
|
const entries = [];
|
|
35469
35670
|
const now = new Date().toISOString();
|
|
35470
35671
|
for (const pair of pairs.slice(0, 10)) {
|
|
35471
|
-
const baseA =
|
|
35472
|
-
const baseB =
|
|
35672
|
+
const baseA = path15.basename(pair.fileA);
|
|
35673
|
+
const baseB = path15.basename(pair.fileB);
|
|
35473
35674
|
let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
35474
35675
|
if (lesson.length > 280) {
|
|
35475
35676
|
lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
@@ -35579,7 +35780,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
35579
35780
|
const output = formatDarkMatterOutput(pairs);
|
|
35580
35781
|
if (pairs.length > 0) {
|
|
35581
35782
|
try {
|
|
35582
|
-
const projectName =
|
|
35783
|
+
const projectName = path16.basename(path16.resolve(directory));
|
|
35583
35784
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
35584
35785
|
if (entries.length > 0) {
|
|
35585
35786
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -35600,8 +35801,8 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
35600
35801
|
|
|
35601
35802
|
// src/services/diagnose-service.ts
|
|
35602
35803
|
import * as child_process4 from "child_process";
|
|
35603
|
-
import { existsSync as
|
|
35604
|
-
import
|
|
35804
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
35805
|
+
import path17 from "path";
|
|
35605
35806
|
import { fileURLToPath } from "url";
|
|
35606
35807
|
init_manager2();
|
|
35607
35808
|
init_utils2();
|
|
@@ -35806,7 +36007,7 @@ async function checkPlanSync(directory, plan) {
|
|
|
35806
36007
|
}
|
|
35807
36008
|
async function checkConfigBackups(directory) {
|
|
35808
36009
|
try {
|
|
35809
|
-
const files =
|
|
36010
|
+
const files = readdirSync4(directory);
|
|
35810
36011
|
const backupCount = files.filter((f) => /\.opencode-swarm\.yaml\.bak/.test(f)).length;
|
|
35811
36012
|
if (backupCount <= 5) {
|
|
35812
36013
|
return {
|
|
@@ -35837,7 +36038,7 @@ async function checkConfigBackups(directory) {
|
|
|
35837
36038
|
}
|
|
35838
36039
|
async function checkGitRepository(directory) {
|
|
35839
36040
|
try {
|
|
35840
|
-
if (!
|
|
36041
|
+
if (!existsSync8(directory) || !statSync5(directory).isDirectory()) {
|
|
35841
36042
|
return {
|
|
35842
36043
|
name: "Git Repository",
|
|
35843
36044
|
status: "\u274C",
|
|
@@ -35901,8 +36102,8 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
35901
36102
|
};
|
|
35902
36103
|
}
|
|
35903
36104
|
async function checkConfigParseability(directory) {
|
|
35904
|
-
const configPath =
|
|
35905
|
-
if (!
|
|
36105
|
+
const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
|
|
36106
|
+
if (!existsSync8(configPath)) {
|
|
35906
36107
|
return {
|
|
35907
36108
|
name: "Config Parseability",
|
|
35908
36109
|
status: "\u2705",
|
|
@@ -35948,15 +36149,15 @@ async function checkGrammarWasmFiles() {
|
|
|
35948
36149
|
"tree-sitter-ini.wasm",
|
|
35949
36150
|
"tree-sitter-regex.wasm"
|
|
35950
36151
|
];
|
|
35951
|
-
const thisDir =
|
|
36152
|
+
const thisDir = path17.dirname(fileURLToPath(import.meta.url));
|
|
35952
36153
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
|
|
35953
|
-
const grammarDir = isSource ?
|
|
36154
|
+
const grammarDir = isSource ? path17.join(thisDir, "..", "lang", "grammars") : path17.join(thisDir, "lang", "grammars");
|
|
35954
36155
|
const missing = [];
|
|
35955
|
-
if (!
|
|
36156
|
+
if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
|
|
35956
36157
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
35957
36158
|
}
|
|
35958
36159
|
for (const file3 of grammarFiles) {
|
|
35959
|
-
if (!
|
|
36160
|
+
if (!existsSync8(path17.join(grammarDir, file3))) {
|
|
35960
36161
|
missing.push(file3);
|
|
35961
36162
|
}
|
|
35962
36163
|
}
|
|
@@ -35974,8 +36175,8 @@ async function checkGrammarWasmFiles() {
|
|
|
35974
36175
|
};
|
|
35975
36176
|
}
|
|
35976
36177
|
async function checkCheckpointManifest(directory) {
|
|
35977
|
-
const manifestPath =
|
|
35978
|
-
if (!
|
|
36178
|
+
const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
|
|
36179
|
+
if (!existsSync8(manifestPath)) {
|
|
35979
36180
|
return {
|
|
35980
36181
|
name: "Checkpoint Manifest",
|
|
35981
36182
|
status: "\u2705",
|
|
@@ -36026,8 +36227,8 @@ async function checkCheckpointManifest(directory) {
|
|
|
36026
36227
|
}
|
|
36027
36228
|
}
|
|
36028
36229
|
async function checkEventStreamIntegrity(directory) {
|
|
36029
|
-
const eventsPath =
|
|
36030
|
-
if (!
|
|
36230
|
+
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36231
|
+
if (!existsSync8(eventsPath)) {
|
|
36031
36232
|
return {
|
|
36032
36233
|
name: "Event Stream",
|
|
36033
36234
|
status: "\u2705",
|
|
@@ -36067,8 +36268,8 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36067
36268
|
}
|
|
36068
36269
|
}
|
|
36069
36270
|
async function checkSteeringDirectives(directory) {
|
|
36070
|
-
const eventsPath =
|
|
36071
|
-
if (!
|
|
36271
|
+
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36272
|
+
if (!existsSync8(eventsPath)) {
|
|
36072
36273
|
return {
|
|
36073
36274
|
name: "Steering Directives",
|
|
36074
36275
|
status: "\u2705",
|
|
@@ -36123,8 +36324,8 @@ async function checkCurator(directory) {
|
|
|
36123
36324
|
detail: "Disabled (enable via curator.enabled)"
|
|
36124
36325
|
};
|
|
36125
36326
|
}
|
|
36126
|
-
const summaryPath =
|
|
36127
|
-
if (!
|
|
36327
|
+
const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
|
|
36328
|
+
if (!existsSync8(summaryPath)) {
|
|
36128
36329
|
return {
|
|
36129
36330
|
name: "Curator",
|
|
36130
36331
|
status: "\u2705",
|
|
@@ -36271,8 +36472,8 @@ async function getDiagnoseData(directory) {
|
|
|
36271
36472
|
checks5.push(await checkSteeringDirectives(directory));
|
|
36272
36473
|
checks5.push(await checkCurator(directory));
|
|
36273
36474
|
try {
|
|
36274
|
-
const evidenceDir =
|
|
36275
|
-
const snapshotFiles =
|
|
36475
|
+
const evidenceDir = path17.join(directory, ".swarm", "evidence");
|
|
36476
|
+
const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
36276
36477
|
if (snapshotFiles.length > 0) {
|
|
36277
36478
|
const latest = snapshotFiles.sort().pop();
|
|
36278
36479
|
checks5.push({
|
|
@@ -36323,16 +36524,16 @@ async function handleDiagnoseCommand(directory, _args) {
|
|
|
36323
36524
|
init_config_doctor();
|
|
36324
36525
|
|
|
36325
36526
|
// src/services/tool-doctor.ts
|
|
36326
|
-
import * as
|
|
36327
|
-
import * as
|
|
36527
|
+
import * as fs11 from "fs";
|
|
36528
|
+
import * as path20 from "path";
|
|
36328
36529
|
|
|
36329
36530
|
// src/build/discovery.ts
|
|
36330
|
-
import * as
|
|
36331
|
-
import * as
|
|
36531
|
+
import * as fs10 from "fs";
|
|
36532
|
+
import * as path19 from "path";
|
|
36332
36533
|
|
|
36333
36534
|
// src/lang/detector.ts
|
|
36334
36535
|
import { access as access2, readdir as readdir2 } from "fs/promises";
|
|
36335
|
-
import { extname as extname2, join as
|
|
36536
|
+
import { extname as extname2, join as join16 } from "path";
|
|
36336
36537
|
|
|
36337
36538
|
// src/lang/profiles.ts
|
|
36338
36539
|
class LanguageRegistry {
|
|
@@ -37312,7 +37513,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37312
37513
|
if (detectFile.includes("*") || detectFile.includes("?"))
|
|
37313
37514
|
continue;
|
|
37314
37515
|
try {
|
|
37315
|
-
await access2(
|
|
37516
|
+
await access2(join16(dir, detectFile));
|
|
37316
37517
|
detected.add(profile.id);
|
|
37317
37518
|
break;
|
|
37318
37519
|
} catch {}
|
|
@@ -37333,7 +37534,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37333
37534
|
const topEntries = await readdir2(projectDir, { withFileTypes: true });
|
|
37334
37535
|
for (const entry of topEntries) {
|
|
37335
37536
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
37336
|
-
await scanDir(
|
|
37537
|
+
await scanDir(join16(projectDir, entry.name));
|
|
37337
37538
|
}
|
|
37338
37539
|
}
|
|
37339
37540
|
} catch {}
|
|
@@ -37488,16 +37689,16 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
37488
37689
|
if (pattern.includes("*")) {
|
|
37489
37690
|
const dir = workingDir;
|
|
37490
37691
|
try {
|
|
37491
|
-
const files =
|
|
37692
|
+
const files = fs10.readdirSync(dir);
|
|
37492
37693
|
const regex = simpleGlobToRegex(pattern);
|
|
37493
37694
|
const matches = files.filter((f) => regex.test(f));
|
|
37494
37695
|
if (matches.length > 0) {
|
|
37495
|
-
return
|
|
37696
|
+
return path19.join(dir, matches[0]);
|
|
37496
37697
|
}
|
|
37497
37698
|
} catch {}
|
|
37498
37699
|
} else {
|
|
37499
|
-
const filePath =
|
|
37500
|
-
if (
|
|
37700
|
+
const filePath = path19.join(workingDir, pattern);
|
|
37701
|
+
if (fs10.existsSync(filePath)) {
|
|
37501
37702
|
return filePath;
|
|
37502
37703
|
}
|
|
37503
37704
|
}
|
|
@@ -37505,12 +37706,12 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
37505
37706
|
return null;
|
|
37506
37707
|
}
|
|
37507
37708
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
37508
|
-
const packageJsonPath =
|
|
37509
|
-
if (!
|
|
37709
|
+
const packageJsonPath = path19.join(workingDir, "package.json");
|
|
37710
|
+
if (!fs10.existsSync(packageJsonPath)) {
|
|
37510
37711
|
return [];
|
|
37511
37712
|
}
|
|
37512
37713
|
try {
|
|
37513
|
-
const content =
|
|
37714
|
+
const content = fs10.readFileSync(packageJsonPath, "utf-8");
|
|
37514
37715
|
const pkg = JSON.parse(content);
|
|
37515
37716
|
if (!pkg.scripts || typeof pkg.scripts !== "object") {
|
|
37516
37717
|
return [];
|
|
@@ -37546,8 +37747,8 @@ function findAllBuildFiles(workingDir) {
|
|
|
37546
37747
|
const regex = simpleGlobToRegex(pattern);
|
|
37547
37748
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
37548
37749
|
} else {
|
|
37549
|
-
const filePath =
|
|
37550
|
-
if (
|
|
37750
|
+
const filePath = path19.join(workingDir, pattern);
|
|
37751
|
+
if (fs10.existsSync(filePath)) {
|
|
37551
37752
|
allBuildFiles.add(filePath);
|
|
37552
37753
|
}
|
|
37553
37754
|
}
|
|
@@ -37557,9 +37758,9 @@ function findAllBuildFiles(workingDir) {
|
|
|
37557
37758
|
}
|
|
37558
37759
|
function findFilesRecursive(dir, regex, results) {
|
|
37559
37760
|
try {
|
|
37560
|
-
const entries =
|
|
37761
|
+
const entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
37561
37762
|
for (const entry of entries) {
|
|
37562
|
-
const fullPath =
|
|
37763
|
+
const fullPath = path19.join(dir, entry.name);
|
|
37563
37764
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
37564
37765
|
findFilesRecursive(fullPath, regex, results);
|
|
37565
37766
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -37582,8 +37783,8 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
37582
37783
|
let foundCommand = false;
|
|
37583
37784
|
for (const cmd of sortedCommands) {
|
|
37584
37785
|
if (cmd.detectFile) {
|
|
37585
|
-
const detectFilePath =
|
|
37586
|
-
if (!
|
|
37786
|
+
const detectFilePath = path19.join(workingDir, cmd.detectFile);
|
|
37787
|
+
if (!fs10.existsSync(detectFilePath)) {
|
|
37587
37788
|
continue;
|
|
37588
37789
|
}
|
|
37589
37790
|
}
|
|
@@ -37706,7 +37907,7 @@ var BINARY_CHECKLIST = [
|
|
|
37706
37907
|
function extractRegisteredToolKeys(indexPath) {
|
|
37707
37908
|
const registeredKeys = new Set;
|
|
37708
37909
|
try {
|
|
37709
|
-
const content =
|
|
37910
|
+
const content = fs11.readFileSync(indexPath, "utf-8");
|
|
37710
37911
|
const toolBlockMatch = content.match(/tool:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s);
|
|
37711
37912
|
if (!toolBlockMatch) {
|
|
37712
37913
|
return registeredKeys;
|
|
@@ -37757,9 +37958,9 @@ function checkBinaryReadiness() {
|
|
|
37757
37958
|
}
|
|
37758
37959
|
function runToolDoctor(_directory, pluginRoot) {
|
|
37759
37960
|
const findings = [];
|
|
37760
|
-
const resolvedPluginRoot = pluginRoot ??
|
|
37761
|
-
const indexPath =
|
|
37762
|
-
if (!
|
|
37961
|
+
const resolvedPluginRoot = pluginRoot ?? path20.resolve(import.meta.dir, "..", "..");
|
|
37962
|
+
const indexPath = path20.join(resolvedPluginRoot, "src", "index.ts");
|
|
37963
|
+
if (!fs11.existsSync(indexPath)) {
|
|
37763
37964
|
return {
|
|
37764
37965
|
findings: [
|
|
37765
37966
|
{
|
|
@@ -38669,14 +38870,14 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
38669
38870
|
}
|
|
38670
38871
|
// src/hooks/knowledge-migrator.ts
|
|
38671
38872
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
38672
|
-
import { existsSync as
|
|
38873
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
38673
38874
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
38674
|
-
import * as
|
|
38875
|
+
import * as path21 from "path";
|
|
38675
38876
|
async function migrateContextToKnowledge(directory, config3) {
|
|
38676
|
-
const sentinelPath =
|
|
38677
|
-
const contextPath =
|
|
38877
|
+
const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
|
|
38878
|
+
const contextPath = path21.join(directory, ".swarm", "context.md");
|
|
38678
38879
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
38679
|
-
if (
|
|
38880
|
+
if (existsSync12(sentinelPath)) {
|
|
38680
38881
|
return {
|
|
38681
38882
|
migrated: false,
|
|
38682
38883
|
entriesMigrated: 0,
|
|
@@ -38685,7 +38886,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
38685
38886
|
skippedReason: "sentinel-exists"
|
|
38686
38887
|
};
|
|
38687
38888
|
}
|
|
38688
|
-
if (!
|
|
38889
|
+
if (!existsSync12(contextPath)) {
|
|
38689
38890
|
return {
|
|
38690
38891
|
migrated: false,
|
|
38691
38892
|
entriesMigrated: 0,
|
|
@@ -38870,8 +39071,8 @@ function truncateLesson(text) {
|
|
|
38870
39071
|
return `${text.slice(0, 277)}...`;
|
|
38871
39072
|
}
|
|
38872
39073
|
function inferProjectName(directory) {
|
|
38873
|
-
const packageJsonPath =
|
|
38874
|
-
if (
|
|
39074
|
+
const packageJsonPath = path21.join(directory, "package.json");
|
|
39075
|
+
if (existsSync12(packageJsonPath)) {
|
|
38875
39076
|
try {
|
|
38876
39077
|
const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
38877
39078
|
if (pkg.name && typeof pkg.name === "string") {
|
|
@@ -38879,7 +39080,7 @@ function inferProjectName(directory) {
|
|
|
38879
39080
|
}
|
|
38880
39081
|
} catch {}
|
|
38881
39082
|
}
|
|
38882
|
-
return
|
|
39083
|
+
return path21.basename(directory);
|
|
38883
39084
|
}
|
|
38884
39085
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
38885
39086
|
const sentinel = {
|
|
@@ -38891,7 +39092,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
38891
39092
|
schema_version: 1,
|
|
38892
39093
|
migration_tool: "knowledge-migrator.ts"
|
|
38893
39094
|
};
|
|
38894
|
-
await mkdir3(
|
|
39095
|
+
await mkdir3(path21.dirname(sentinelPath), { recursive: true });
|
|
38895
39096
|
await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
38896
39097
|
}
|
|
38897
39098
|
|
|
@@ -39127,12 +39328,12 @@ async function handlePlanCommand(directory, args) {
|
|
|
39127
39328
|
// src/services/preflight-service.ts
|
|
39128
39329
|
init_manager2();
|
|
39129
39330
|
init_manager();
|
|
39130
|
-
import * as
|
|
39131
|
-
import * as
|
|
39331
|
+
import * as fs18 from "fs";
|
|
39332
|
+
import * as path28 from "path";
|
|
39132
39333
|
|
|
39133
39334
|
// src/tools/lint.ts
|
|
39134
|
-
import * as
|
|
39135
|
-
import * as
|
|
39335
|
+
import * as fs12 from "fs";
|
|
39336
|
+
import * as path22 from "path";
|
|
39136
39337
|
init_utils();
|
|
39137
39338
|
|
|
39138
39339
|
// src/utils/path-security.ts
|
|
@@ -39178,9 +39379,9 @@ function validateArgs(args) {
|
|
|
39178
39379
|
}
|
|
39179
39380
|
function getLinterCommand(linter, mode, projectDir) {
|
|
39180
39381
|
const isWindows = process.platform === "win32";
|
|
39181
|
-
const binDir =
|
|
39182
|
-
const biomeBin = isWindows ?
|
|
39183
|
-
const eslintBin = isWindows ?
|
|
39382
|
+
const binDir = path22.join(projectDir, "node_modules", ".bin");
|
|
39383
|
+
const biomeBin = isWindows ? path22.join(binDir, "biome.EXE") : path22.join(binDir, "biome");
|
|
39384
|
+
const eslintBin = isWindows ? path22.join(binDir, "eslint.cmd") : path22.join(binDir, "eslint");
|
|
39184
39385
|
switch (linter) {
|
|
39185
39386
|
case "biome":
|
|
39186
39387
|
if (mode === "fix") {
|
|
@@ -39196,7 +39397,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
39196
39397
|
}
|
|
39197
39398
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
39198
39399
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
39199
|
-
const gradlew =
|
|
39400
|
+
const gradlew = fs12.existsSync(path22.join(cwd, gradlewName)) ? path22.join(cwd, gradlewName) : null;
|
|
39200
39401
|
switch (linter) {
|
|
39201
39402
|
case "ruff":
|
|
39202
39403
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -39230,12 +39431,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
39230
39431
|
}
|
|
39231
39432
|
}
|
|
39232
39433
|
function detectRuff(cwd) {
|
|
39233
|
-
if (
|
|
39434
|
+
if (fs12.existsSync(path22.join(cwd, "ruff.toml")))
|
|
39234
39435
|
return isCommandAvailable("ruff");
|
|
39235
39436
|
try {
|
|
39236
|
-
const pyproject =
|
|
39237
|
-
if (
|
|
39238
|
-
const content =
|
|
39437
|
+
const pyproject = path22.join(cwd, "pyproject.toml");
|
|
39438
|
+
if (fs12.existsSync(pyproject)) {
|
|
39439
|
+
const content = fs12.readFileSync(pyproject, "utf-8");
|
|
39239
39440
|
if (content.includes("[tool.ruff]"))
|
|
39240
39441
|
return isCommandAvailable("ruff");
|
|
39241
39442
|
}
|
|
@@ -39243,21 +39444,21 @@ function detectRuff(cwd) {
|
|
|
39243
39444
|
return false;
|
|
39244
39445
|
}
|
|
39245
39446
|
function detectClippy(cwd) {
|
|
39246
|
-
return
|
|
39447
|
+
return fs12.existsSync(path22.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
39247
39448
|
}
|
|
39248
39449
|
function detectGolangciLint(cwd) {
|
|
39249
|
-
return
|
|
39450
|
+
return fs12.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
39250
39451
|
}
|
|
39251
39452
|
function detectCheckstyle(cwd) {
|
|
39252
|
-
const hasMaven =
|
|
39253
|
-
const hasGradle =
|
|
39254
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
39453
|
+
const hasMaven = fs12.existsSync(path22.join(cwd, "pom.xml"));
|
|
39454
|
+
const hasGradle = fs12.existsSync(path22.join(cwd, "build.gradle")) || fs12.existsSync(path22.join(cwd, "build.gradle.kts"));
|
|
39455
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path22.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
39255
39456
|
return (hasMaven || hasGradle) && hasBinary;
|
|
39256
39457
|
}
|
|
39257
39458
|
function detectKtlint(cwd) {
|
|
39258
|
-
const hasKotlin =
|
|
39459
|
+
const hasKotlin = fs12.existsSync(path22.join(cwd, "build.gradle.kts")) || fs12.existsSync(path22.join(cwd, "build.gradle")) || (() => {
|
|
39259
39460
|
try {
|
|
39260
|
-
return
|
|
39461
|
+
return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
39261
39462
|
} catch {
|
|
39262
39463
|
return false;
|
|
39263
39464
|
}
|
|
@@ -39266,7 +39467,7 @@ function detectKtlint(cwd) {
|
|
|
39266
39467
|
}
|
|
39267
39468
|
function detectDotnetFormat(cwd) {
|
|
39268
39469
|
try {
|
|
39269
|
-
const files =
|
|
39470
|
+
const files = fs12.readdirSync(cwd);
|
|
39270
39471
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
39271
39472
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
39272
39473
|
} catch {
|
|
@@ -39274,14 +39475,14 @@ function detectDotnetFormat(cwd) {
|
|
|
39274
39475
|
}
|
|
39275
39476
|
}
|
|
39276
39477
|
function detectCppcheck(cwd) {
|
|
39277
|
-
if (
|
|
39478
|
+
if (fs12.existsSync(path22.join(cwd, "CMakeLists.txt"))) {
|
|
39278
39479
|
return isCommandAvailable("cppcheck");
|
|
39279
39480
|
}
|
|
39280
39481
|
try {
|
|
39281
|
-
const dirsToCheck = [cwd,
|
|
39482
|
+
const dirsToCheck = [cwd, path22.join(cwd, "src")];
|
|
39282
39483
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
39283
39484
|
try {
|
|
39284
|
-
return
|
|
39485
|
+
return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
39285
39486
|
} catch {
|
|
39286
39487
|
return false;
|
|
39287
39488
|
}
|
|
@@ -39292,13 +39493,13 @@ function detectCppcheck(cwd) {
|
|
|
39292
39493
|
}
|
|
39293
39494
|
}
|
|
39294
39495
|
function detectSwiftlint(cwd) {
|
|
39295
|
-
return
|
|
39496
|
+
return fs12.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
39296
39497
|
}
|
|
39297
39498
|
function detectDartAnalyze(cwd) {
|
|
39298
|
-
return
|
|
39499
|
+
return fs12.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
39299
39500
|
}
|
|
39300
39501
|
function detectRubocop(cwd) {
|
|
39301
|
-
return (
|
|
39502
|
+
return (fs12.existsSync(path22.join(cwd, "Gemfile")) || fs12.existsSync(path22.join(cwd, "gems.rb")) || fs12.existsSync(path22.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
39302
39503
|
}
|
|
39303
39504
|
function detectAdditionalLinter(cwd) {
|
|
39304
39505
|
if (detectRuff(cwd))
|
|
@@ -39326,10 +39527,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
39326
39527
|
function findBinInAncestors(startDir, binName) {
|
|
39327
39528
|
let dir = startDir;
|
|
39328
39529
|
while (true) {
|
|
39329
|
-
const candidate =
|
|
39330
|
-
if (
|
|
39530
|
+
const candidate = path22.join(dir, "node_modules", ".bin", binName);
|
|
39531
|
+
if (fs12.existsSync(candidate))
|
|
39331
39532
|
return candidate;
|
|
39332
|
-
const parent =
|
|
39533
|
+
const parent = path22.dirname(dir);
|
|
39333
39534
|
if (parent === dir)
|
|
39334
39535
|
break;
|
|
39335
39536
|
dir = parent;
|
|
@@ -39338,11 +39539,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
39338
39539
|
}
|
|
39339
39540
|
function findBinInEnvPath(binName) {
|
|
39340
39541
|
const searchPath = process.env.PATH ?? "";
|
|
39341
|
-
for (const dir of searchPath.split(
|
|
39542
|
+
for (const dir of searchPath.split(path22.delimiter)) {
|
|
39342
39543
|
if (!dir)
|
|
39343
39544
|
continue;
|
|
39344
|
-
const candidate =
|
|
39345
|
-
if (
|
|
39545
|
+
const candidate = path22.join(dir, binName);
|
|
39546
|
+
if (fs12.existsSync(candidate))
|
|
39346
39547
|
return candidate;
|
|
39347
39548
|
}
|
|
39348
39549
|
return null;
|
|
@@ -39350,17 +39551,17 @@ function findBinInEnvPath(binName) {
|
|
|
39350
39551
|
async function detectAvailableLinter(directory) {
|
|
39351
39552
|
if (!directory)
|
|
39352
39553
|
return null;
|
|
39353
|
-
if (!
|
|
39554
|
+
if (!fs12.existsSync(directory))
|
|
39354
39555
|
return null;
|
|
39355
39556
|
const projectDir = directory;
|
|
39356
39557
|
const isWindows = process.platform === "win32";
|
|
39357
|
-
const biomeBin = isWindows ?
|
|
39358
|
-
const eslintBin = isWindows ?
|
|
39558
|
+
const biomeBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "biome.EXE") : path22.join(projectDir, "node_modules", ".bin", "biome");
|
|
39559
|
+
const eslintBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path22.join(projectDir, "node_modules", ".bin", "eslint");
|
|
39359
39560
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
39360
39561
|
if (localResult)
|
|
39361
39562
|
return localResult;
|
|
39362
|
-
const biomeAncestor = findBinInAncestors(
|
|
39363
|
-
const eslintAncestor = findBinInAncestors(
|
|
39563
|
+
const biomeAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
39564
|
+
const eslintAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
39364
39565
|
if (biomeAncestor || eslintAncestor) {
|
|
39365
39566
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
39366
39567
|
}
|
|
@@ -39379,11 +39580,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
39379
39580
|
stderr: "pipe"
|
|
39380
39581
|
});
|
|
39381
39582
|
const biomeExit = biomeProc.exited;
|
|
39382
|
-
const timeout = new Promise((
|
|
39583
|
+
const timeout = new Promise((resolve9) => setTimeout(() => resolve9("timeout"), DETECT_TIMEOUT));
|
|
39383
39584
|
const result = await Promise.race([biomeExit, timeout]);
|
|
39384
39585
|
if (result === "timeout") {
|
|
39385
39586
|
biomeProc.kill();
|
|
39386
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
39587
|
+
} else if (biomeProc.exitCode === 0 && fs12.existsSync(biomeBin)) {
|
|
39387
39588
|
return "biome";
|
|
39388
39589
|
}
|
|
39389
39590
|
} catch {}
|
|
@@ -39393,11 +39594,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
39393
39594
|
stderr: "pipe"
|
|
39394
39595
|
});
|
|
39395
39596
|
const eslintExit = eslintProc.exited;
|
|
39396
|
-
const timeout = new Promise((
|
|
39597
|
+
const timeout = new Promise((resolve9) => setTimeout(() => resolve9("timeout"), DETECT_TIMEOUT));
|
|
39397
39598
|
const result = await Promise.race([eslintExit, timeout]);
|
|
39398
39599
|
if (result === "timeout") {
|
|
39399
39600
|
eslintProc.kill();
|
|
39400
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
39601
|
+
} else if (eslintProc.exitCode === 0 && fs12.existsSync(eslintBin)) {
|
|
39401
39602
|
return "eslint";
|
|
39402
39603
|
}
|
|
39403
39604
|
} catch {}
|
|
@@ -39567,8 +39768,8 @@ For Rust: rustup component add clippy`
|
|
|
39567
39768
|
});
|
|
39568
39769
|
|
|
39569
39770
|
// src/tools/secretscan.ts
|
|
39570
|
-
import * as
|
|
39571
|
-
import * as
|
|
39771
|
+
import * as fs13 from "fs";
|
|
39772
|
+
import * as path23 from "path";
|
|
39572
39773
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
39573
39774
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
39574
39775
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -39795,11 +39996,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
39795
39996
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
39796
39997
|
}
|
|
39797
39998
|
function loadSecretScanIgnore(scanDir) {
|
|
39798
|
-
const ignorePath =
|
|
39999
|
+
const ignorePath = path23.join(scanDir, ".secretscanignore");
|
|
39799
40000
|
try {
|
|
39800
|
-
if (!
|
|
40001
|
+
if (!fs13.existsSync(ignorePath))
|
|
39801
40002
|
return [];
|
|
39802
|
-
const content =
|
|
40003
|
+
const content = fs13.readFileSync(ignorePath, "utf8");
|
|
39803
40004
|
const patterns = [];
|
|
39804
40005
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
39805
40006
|
const line = rawLine.trim();
|
|
@@ -39818,7 +40019,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
39818
40019
|
if (exactNames.has(entry))
|
|
39819
40020
|
return true;
|
|
39820
40021
|
for (const pattern of globPatterns) {
|
|
39821
|
-
if (
|
|
40022
|
+
if (path23.matchesGlob(relPath, pattern))
|
|
39822
40023
|
return true;
|
|
39823
40024
|
}
|
|
39824
40025
|
return false;
|
|
@@ -39839,7 +40040,7 @@ function validateDirectoryInput(dir) {
|
|
|
39839
40040
|
return null;
|
|
39840
40041
|
}
|
|
39841
40042
|
function isBinaryFile(filePath, buffer) {
|
|
39842
|
-
const ext =
|
|
40043
|
+
const ext = path23.extname(filePath).toLowerCase();
|
|
39843
40044
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
39844
40045
|
return true;
|
|
39845
40046
|
}
|
|
@@ -39914,11 +40115,11 @@ function createRedactedContext(line, findings) {
|
|
|
39914
40115
|
result += line.slice(lastEnd);
|
|
39915
40116
|
return result;
|
|
39916
40117
|
}
|
|
39917
|
-
var O_NOFOLLOW = process.platform !== "win32" ?
|
|
40118
|
+
var O_NOFOLLOW = process.platform !== "win32" ? fs13.constants.O_NOFOLLOW : undefined;
|
|
39918
40119
|
function scanFileForSecrets(filePath) {
|
|
39919
40120
|
const findings = [];
|
|
39920
40121
|
try {
|
|
39921
|
-
const lstat =
|
|
40122
|
+
const lstat = fs13.lstatSync(filePath);
|
|
39922
40123
|
if (lstat.isSymbolicLink()) {
|
|
39923
40124
|
return findings;
|
|
39924
40125
|
}
|
|
@@ -39927,14 +40128,14 @@ function scanFileForSecrets(filePath) {
|
|
|
39927
40128
|
}
|
|
39928
40129
|
let buffer;
|
|
39929
40130
|
if (O_NOFOLLOW !== undefined) {
|
|
39930
|
-
const fd =
|
|
40131
|
+
const fd = fs13.openSync(filePath, "r", O_NOFOLLOW);
|
|
39931
40132
|
try {
|
|
39932
|
-
buffer =
|
|
40133
|
+
buffer = fs13.readFileSync(fd);
|
|
39933
40134
|
} finally {
|
|
39934
|
-
|
|
40135
|
+
fs13.closeSync(fd);
|
|
39935
40136
|
}
|
|
39936
40137
|
} else {
|
|
39937
|
-
buffer =
|
|
40138
|
+
buffer = fs13.readFileSync(filePath);
|
|
39938
40139
|
}
|
|
39939
40140
|
if (isBinaryFile(filePath, buffer)) {
|
|
39940
40141
|
return findings;
|
|
@@ -39976,9 +40177,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
39976
40177
|
return false;
|
|
39977
40178
|
}
|
|
39978
40179
|
function isPathWithinScope(realPath, scanDir) {
|
|
39979
|
-
const resolvedScanDir =
|
|
39980
|
-
const resolvedRealPath =
|
|
39981
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
40180
|
+
const resolvedScanDir = path23.resolve(scanDir);
|
|
40181
|
+
const resolvedRealPath = path23.resolve(realPath);
|
|
40182
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path23.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
39982
40183
|
}
|
|
39983
40184
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
39984
40185
|
skippedDirs: 0,
|
|
@@ -39989,7 +40190,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
39989
40190
|
const files = [];
|
|
39990
40191
|
let entries;
|
|
39991
40192
|
try {
|
|
39992
|
-
entries =
|
|
40193
|
+
entries = fs13.readdirSync(dir);
|
|
39993
40194
|
} catch {
|
|
39994
40195
|
stats.fileErrors++;
|
|
39995
40196
|
return files;
|
|
@@ -40004,15 +40205,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40004
40205
|
return a.localeCompare(b);
|
|
40005
40206
|
});
|
|
40006
40207
|
for (const entry of entries) {
|
|
40007
|
-
const fullPath =
|
|
40008
|
-
const relPath =
|
|
40208
|
+
const fullPath = path23.join(dir, entry);
|
|
40209
|
+
const relPath = path23.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
40009
40210
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
40010
40211
|
stats.skippedDirs++;
|
|
40011
40212
|
continue;
|
|
40012
40213
|
}
|
|
40013
40214
|
let lstat;
|
|
40014
40215
|
try {
|
|
40015
|
-
lstat =
|
|
40216
|
+
lstat = fs13.lstatSync(fullPath);
|
|
40016
40217
|
} catch {
|
|
40017
40218
|
stats.fileErrors++;
|
|
40018
40219
|
continue;
|
|
@@ -40024,7 +40225,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40024
40225
|
if (lstat.isDirectory()) {
|
|
40025
40226
|
let realPath;
|
|
40026
40227
|
try {
|
|
40027
|
-
realPath =
|
|
40228
|
+
realPath = fs13.realpathSync(fullPath);
|
|
40028
40229
|
} catch {
|
|
40029
40230
|
stats.fileErrors++;
|
|
40030
40231
|
continue;
|
|
@@ -40040,7 +40241,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40040
40241
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
40041
40242
|
files.push(...subFiles);
|
|
40042
40243
|
} else if (lstat.isFile()) {
|
|
40043
|
-
const ext =
|
|
40244
|
+
const ext = path23.extname(fullPath).toLowerCase();
|
|
40044
40245
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
40045
40246
|
files.push(fullPath);
|
|
40046
40247
|
} else {
|
|
@@ -40106,15 +40307,15 @@ var secretscan = createSwarmTool({
|
|
|
40106
40307
|
}
|
|
40107
40308
|
}
|
|
40108
40309
|
try {
|
|
40109
|
-
const _scanDirRaw =
|
|
40310
|
+
const _scanDirRaw = path23.resolve(directory);
|
|
40110
40311
|
const scanDir = (() => {
|
|
40111
40312
|
try {
|
|
40112
|
-
return
|
|
40313
|
+
return fs13.realpathSync(_scanDirRaw);
|
|
40113
40314
|
} catch {
|
|
40114
40315
|
return _scanDirRaw;
|
|
40115
40316
|
}
|
|
40116
40317
|
})();
|
|
40117
|
-
if (!
|
|
40318
|
+
if (!fs13.existsSync(scanDir)) {
|
|
40118
40319
|
const errorResult = {
|
|
40119
40320
|
error: "directory not found",
|
|
40120
40321
|
scan_dir: directory,
|
|
@@ -40125,7 +40326,7 @@ var secretscan = createSwarmTool({
|
|
|
40125
40326
|
};
|
|
40126
40327
|
return JSON.stringify(errorResult, null, 2);
|
|
40127
40328
|
}
|
|
40128
|
-
const dirStat =
|
|
40329
|
+
const dirStat = fs13.statSync(scanDir);
|
|
40129
40330
|
if (!dirStat.isDirectory()) {
|
|
40130
40331
|
const errorResult = {
|
|
40131
40332
|
error: "target must be a directory, not a file",
|
|
@@ -40176,7 +40377,7 @@ var secretscan = createSwarmTool({
|
|
|
40176
40377
|
break;
|
|
40177
40378
|
const fileFindings = scanFileForSecrets(filePath);
|
|
40178
40379
|
try {
|
|
40179
|
-
const stat2 =
|
|
40380
|
+
const stat2 = fs13.statSync(filePath);
|
|
40180
40381
|
if (stat2.size > MAX_FILE_SIZE_BYTES) {
|
|
40181
40382
|
skippedFiles++;
|
|
40182
40383
|
continue;
|
|
@@ -40263,12 +40464,12 @@ async function runSecretscan(directory) {
|
|
|
40263
40464
|
}
|
|
40264
40465
|
|
|
40265
40466
|
// src/tools/test-runner.ts
|
|
40266
|
-
import * as
|
|
40267
|
-
import * as
|
|
40467
|
+
import * as fs17 from "fs";
|
|
40468
|
+
import * as path27 from "path";
|
|
40268
40469
|
|
|
40269
40470
|
// src/test-impact/analyzer.ts
|
|
40270
|
-
import
|
|
40271
|
-
import
|
|
40471
|
+
import fs14 from "fs";
|
|
40472
|
+
import path24 from "path";
|
|
40272
40473
|
var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
40273
40474
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
40274
40475
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -40279,7 +40480,7 @@ function normalizePath(p) {
|
|
|
40279
40480
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
40280
40481
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
40281
40482
|
try {
|
|
40282
|
-
const stat2 =
|
|
40483
|
+
const stat2 = fs14.statSync(sourcePath);
|
|
40283
40484
|
if (stat2.mtimeMs > generatedAtMs) {
|
|
40284
40485
|
return true;
|
|
40285
40486
|
}
|
|
@@ -40293,15 +40494,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
40293
40494
|
if (!importPath.startsWith(".")) {
|
|
40294
40495
|
return null;
|
|
40295
40496
|
}
|
|
40296
|
-
const resolved =
|
|
40297
|
-
if (
|
|
40298
|
-
if (
|
|
40497
|
+
const resolved = path24.resolve(fromDir, importPath);
|
|
40498
|
+
if (path24.extname(resolved)) {
|
|
40499
|
+
if (fs14.existsSync(resolved) && fs14.statSync(resolved).isFile()) {
|
|
40299
40500
|
return normalizePath(resolved);
|
|
40300
40501
|
}
|
|
40301
40502
|
} else {
|
|
40302
40503
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
40303
40504
|
const withExt = resolved + ext;
|
|
40304
|
-
if (
|
|
40505
|
+
if (fs14.existsSync(withExt) && fs14.statSync(withExt).isFile()) {
|
|
40305
40506
|
return normalizePath(withExt);
|
|
40306
40507
|
}
|
|
40307
40508
|
}
|
|
@@ -40320,13 +40521,13 @@ function findTestFilesSync(cwd) {
|
|
|
40320
40521
|
function walk(dir, visitedInodes) {
|
|
40321
40522
|
let entries;
|
|
40322
40523
|
try {
|
|
40323
|
-
entries =
|
|
40524
|
+
entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
40324
40525
|
} catch {
|
|
40325
40526
|
return;
|
|
40326
40527
|
}
|
|
40327
40528
|
let dirInode;
|
|
40328
40529
|
try {
|
|
40329
|
-
dirInode =
|
|
40530
|
+
dirInode = fs14.statSync(dir).ino;
|
|
40330
40531
|
} catch {
|
|
40331
40532
|
return;
|
|
40332
40533
|
}
|
|
@@ -40339,12 +40540,12 @@ function findTestFilesSync(cwd) {
|
|
|
40339
40540
|
for (const entry of entries) {
|
|
40340
40541
|
if (entry.isDirectory()) {
|
|
40341
40542
|
if (!skipDirs.has(entry.name)) {
|
|
40342
|
-
walk(
|
|
40543
|
+
walk(path24.join(dir, entry.name), visitedInodes);
|
|
40343
40544
|
}
|
|
40344
40545
|
} else if (entry.isFile()) {
|
|
40345
40546
|
const name = entry.name;
|
|
40346
40547
|
if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
|
|
40347
|
-
testFiles.push(normalizePath(
|
|
40548
|
+
testFiles.push(normalizePath(path24.join(dir, entry.name)));
|
|
40348
40549
|
}
|
|
40349
40550
|
}
|
|
40350
40551
|
}
|
|
@@ -40374,7 +40575,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
40374
40575
|
for (const testFile of testFiles) {
|
|
40375
40576
|
let content;
|
|
40376
40577
|
try {
|
|
40377
|
-
content =
|
|
40578
|
+
content = fs14.readFileSync(testFile, "utf-8");
|
|
40378
40579
|
} catch {
|
|
40379
40580
|
continue;
|
|
40380
40581
|
}
|
|
@@ -40382,7 +40583,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
40382
40583
|
continue;
|
|
40383
40584
|
}
|
|
40384
40585
|
const imports = extractImports(content);
|
|
40385
|
-
const testDir =
|
|
40586
|
+
const testDir = path24.dirname(testFile);
|
|
40386
40587
|
for (const importPath of imports) {
|
|
40387
40588
|
const resolvedSource = resolveRelativeImport(testDir, importPath);
|
|
40388
40589
|
if (resolvedSource === null) {
|
|
@@ -40404,10 +40605,10 @@ async function buildImpactMap(cwd) {
|
|
|
40404
40605
|
return impactMap;
|
|
40405
40606
|
}
|
|
40406
40607
|
async function loadImpactMap(cwd) {
|
|
40407
|
-
const cachePath =
|
|
40408
|
-
if (
|
|
40608
|
+
const cachePath = path24.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
40609
|
+
if (fs14.existsSync(cachePath)) {
|
|
40409
40610
|
try {
|
|
40410
|
-
const content =
|
|
40611
|
+
const content = fs14.readFileSync(cachePath, "utf-8");
|
|
40411
40612
|
const data = JSON.parse(content);
|
|
40412
40613
|
const map3 = data.map;
|
|
40413
40614
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
@@ -40419,17 +40620,17 @@ async function loadImpactMap(cwd) {
|
|
|
40419
40620
|
return buildImpactMap(cwd);
|
|
40420
40621
|
}
|
|
40421
40622
|
async function saveImpactMap(cwd, impactMap) {
|
|
40422
|
-
const cacheDir =
|
|
40423
|
-
const cachePath =
|
|
40424
|
-
if (!
|
|
40425
|
-
|
|
40623
|
+
const cacheDir = path24.join(cwd, ".swarm", "cache");
|
|
40624
|
+
const cachePath = path24.join(cacheDir, "impact-map.json");
|
|
40625
|
+
if (!fs14.existsSync(cacheDir)) {
|
|
40626
|
+
fs14.mkdirSync(cacheDir, { recursive: true });
|
|
40426
40627
|
}
|
|
40427
40628
|
const data = {
|
|
40428
40629
|
generatedAt: new Date().toISOString(),
|
|
40429
40630
|
fileCount: Object.keys(impactMap).length,
|
|
40430
40631
|
map: impactMap
|
|
40431
40632
|
};
|
|
40432
|
-
|
|
40633
|
+
fs14.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
40433
40634
|
}
|
|
40434
40635
|
async function analyzeImpact(changedFiles, cwd) {
|
|
40435
40636
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -40446,7 +40647,7 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
40446
40647
|
const impactedTestsSet = new Set;
|
|
40447
40648
|
const untestedFiles = [];
|
|
40448
40649
|
for (const changedFile of validFiles) {
|
|
40449
|
-
const normalizedChanged = normalizePath(
|
|
40650
|
+
const normalizedChanged = normalizePath(path24.resolve(changedFile));
|
|
40450
40651
|
const tests = impactMap[normalizedChanged];
|
|
40451
40652
|
if (tests && tests.length > 0) {
|
|
40452
40653
|
for (const test of tests) {
|
|
@@ -40692,14 +40893,14 @@ function detectFlakyTests(allHistory) {
|
|
|
40692
40893
|
}
|
|
40693
40894
|
|
|
40694
40895
|
// src/test-impact/history-store.ts
|
|
40695
|
-
import
|
|
40696
|
-
import
|
|
40896
|
+
import fs15 from "fs";
|
|
40897
|
+
import path25 from "path";
|
|
40697
40898
|
var MAX_HISTORY_PER_TEST = 20;
|
|
40698
40899
|
var MAX_ERROR_LENGTH = 500;
|
|
40699
40900
|
var MAX_STACK_LENGTH = 200;
|
|
40700
40901
|
var MAX_CHANGED_FILES = 50;
|
|
40701
40902
|
function getHistoryPath(workingDir) {
|
|
40702
|
-
return
|
|
40903
|
+
return path25.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
|
|
40703
40904
|
}
|
|
40704
40905
|
function sanitizeErrorMessage(errorMessage) {
|
|
40705
40906
|
if (errorMessage === undefined) {
|
|
@@ -40759,9 +40960,9 @@ function appendTestRun(record3, workingDir) {
|
|
|
40759
40960
|
changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
|
|
40760
40961
|
};
|
|
40761
40962
|
const historyPath = getHistoryPath(workingDir);
|
|
40762
|
-
const historyDir =
|
|
40763
|
-
if (!
|
|
40764
|
-
|
|
40963
|
+
const historyDir = path25.dirname(historyPath);
|
|
40964
|
+
if (!fs15.existsSync(historyDir)) {
|
|
40965
|
+
fs15.mkdirSync(historyDir, { recursive: true });
|
|
40765
40966
|
}
|
|
40766
40967
|
const existingRecords = readAllRecords(historyPath);
|
|
40767
40968
|
existingRecords.push(sanitizedRecord);
|
|
@@ -40786,24 +40987,24 @@ function appendTestRun(record3, workingDir) {
|
|
|
40786
40987
|
`)}
|
|
40787
40988
|
`;
|
|
40788
40989
|
const tempPath = `${historyPath}.tmp`;
|
|
40789
|
-
|
|
40790
|
-
|
|
40990
|
+
fs15.writeFileSync(tempPath, content, "utf-8");
|
|
40991
|
+
fs15.renameSync(tempPath, historyPath);
|
|
40791
40992
|
} catch (err) {
|
|
40792
40993
|
try {
|
|
40793
40994
|
const tempPath = `${historyPath}.tmp`;
|
|
40794
|
-
if (
|
|
40795
|
-
|
|
40995
|
+
if (fs15.existsSync(tempPath)) {
|
|
40996
|
+
fs15.unlinkSync(tempPath);
|
|
40796
40997
|
}
|
|
40797
40998
|
} catch {}
|
|
40798
40999
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
40799
41000
|
}
|
|
40800
41001
|
}
|
|
40801
41002
|
function readAllRecords(historyPath) {
|
|
40802
|
-
if (!
|
|
41003
|
+
if (!fs15.existsSync(historyPath)) {
|
|
40803
41004
|
return [];
|
|
40804
41005
|
}
|
|
40805
41006
|
try {
|
|
40806
|
-
const content =
|
|
41007
|
+
const content = fs15.readFileSync(historyPath, "utf-8");
|
|
40807
41008
|
const lines = content.split(`
|
|
40808
41009
|
`);
|
|
40809
41010
|
const records = [];
|
|
@@ -40832,8 +41033,8 @@ function getAllHistory(workingDir) {
|
|
|
40832
41033
|
}
|
|
40833
41034
|
|
|
40834
41035
|
// src/tools/resolve-working-directory.ts
|
|
40835
|
-
import * as
|
|
40836
|
-
import * as
|
|
41036
|
+
import * as fs16 from "fs";
|
|
41037
|
+
import * as path26 from "path";
|
|
40837
41038
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
40838
41039
|
if (workingDirectory == null || workingDirectory === "") {
|
|
40839
41040
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -40853,17 +41054,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
40853
41054
|
};
|
|
40854
41055
|
}
|
|
40855
41056
|
}
|
|
40856
|
-
const normalizedDir =
|
|
40857
|
-
const pathParts = normalizedDir.split(
|
|
41057
|
+
const normalizedDir = path26.normalize(workingDirectory);
|
|
41058
|
+
const pathParts = normalizedDir.split(path26.sep);
|
|
40858
41059
|
if (pathParts.includes("..")) {
|
|
40859
41060
|
return {
|
|
40860
41061
|
success: false,
|
|
40861
41062
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
40862
41063
|
};
|
|
40863
41064
|
}
|
|
40864
|
-
const resolvedDir =
|
|
41065
|
+
const resolvedDir = path26.resolve(normalizedDir);
|
|
40865
41066
|
try {
|
|
40866
|
-
const realPath =
|
|
41067
|
+
const realPath = fs16.realpathSync(resolvedDir);
|
|
40867
41068
|
return { success: true, directory: realPath };
|
|
40868
41069
|
} catch {
|
|
40869
41070
|
return {
|
|
@@ -40944,19 +41145,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
40944
41145
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
40945
41146
|
}
|
|
40946
41147
|
function detectGoTest(cwd) {
|
|
40947
|
-
return
|
|
41148
|
+
return fs17.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
40948
41149
|
}
|
|
40949
41150
|
function detectJavaMaven(cwd) {
|
|
40950
|
-
return
|
|
41151
|
+
return fs17.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
40951
41152
|
}
|
|
40952
41153
|
function detectGradle(cwd) {
|
|
40953
|
-
const hasBuildFile =
|
|
40954
|
-
const hasGradlew =
|
|
41154
|
+
const hasBuildFile = fs17.existsSync(path27.join(cwd, "build.gradle")) || fs17.existsSync(path27.join(cwd, "build.gradle.kts"));
|
|
41155
|
+
const hasGradlew = fs17.existsSync(path27.join(cwd, "gradlew")) || fs17.existsSync(path27.join(cwd, "gradlew.bat"));
|
|
40955
41156
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
40956
41157
|
}
|
|
40957
41158
|
function detectDotnetTest(cwd) {
|
|
40958
41159
|
try {
|
|
40959
|
-
const files =
|
|
41160
|
+
const files = fs17.readdirSync(cwd);
|
|
40960
41161
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
40961
41162
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
40962
41163
|
} catch {
|
|
@@ -40964,32 +41165,32 @@ function detectDotnetTest(cwd) {
|
|
|
40964
41165
|
}
|
|
40965
41166
|
}
|
|
40966
41167
|
function detectCTest(cwd) {
|
|
40967
|
-
const hasSource =
|
|
40968
|
-
const hasBuildCache =
|
|
41168
|
+
const hasSource = fs17.existsSync(path27.join(cwd, "CMakeLists.txt"));
|
|
41169
|
+
const hasBuildCache = fs17.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
|
|
40969
41170
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
40970
41171
|
}
|
|
40971
41172
|
function detectSwiftTest(cwd) {
|
|
40972
|
-
return
|
|
41173
|
+
return fs17.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
40973
41174
|
}
|
|
40974
41175
|
function detectDartTest(cwd) {
|
|
40975
|
-
return
|
|
41176
|
+
return fs17.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
40976
41177
|
}
|
|
40977
41178
|
function detectRSpec(cwd) {
|
|
40978
|
-
const hasRSpecFile =
|
|
40979
|
-
const hasGemfile =
|
|
40980
|
-
const hasSpecDir =
|
|
41179
|
+
const hasRSpecFile = fs17.existsSync(path27.join(cwd, ".rspec"));
|
|
41180
|
+
const hasGemfile = fs17.existsSync(path27.join(cwd, "Gemfile"));
|
|
41181
|
+
const hasSpecDir = fs17.existsSync(path27.join(cwd, "spec"));
|
|
40981
41182
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
40982
41183
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
40983
41184
|
}
|
|
40984
41185
|
function detectMinitest(cwd) {
|
|
40985
|
-
return
|
|
41186
|
+
return fs17.existsSync(path27.join(cwd, "test")) && (fs17.existsSync(path27.join(cwd, "Gemfile")) || fs17.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
40986
41187
|
}
|
|
40987
41188
|
async function detectTestFramework(cwd) {
|
|
40988
41189
|
const baseDir = cwd;
|
|
40989
41190
|
try {
|
|
40990
|
-
const packageJsonPath =
|
|
40991
|
-
if (
|
|
40992
|
-
const content =
|
|
41191
|
+
const packageJsonPath = path27.join(baseDir, "package.json");
|
|
41192
|
+
if (fs17.existsSync(packageJsonPath)) {
|
|
41193
|
+
const content = fs17.readFileSync(packageJsonPath, "utf-8");
|
|
40993
41194
|
const pkg = JSON.parse(content);
|
|
40994
41195
|
const _deps = pkg.dependencies || {};
|
|
40995
41196
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -41008,38 +41209,38 @@ async function detectTestFramework(cwd) {
|
|
|
41008
41209
|
return "jest";
|
|
41009
41210
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
41010
41211
|
return "mocha";
|
|
41011
|
-
if (
|
|
41212
|
+
if (fs17.existsSync(path27.join(baseDir, "bun.lockb")) || fs17.existsSync(path27.join(baseDir, "bun.lock"))) {
|
|
41012
41213
|
if (scripts.test?.includes("bun"))
|
|
41013
41214
|
return "bun";
|
|
41014
41215
|
}
|
|
41015
41216
|
}
|
|
41016
41217
|
} catch {}
|
|
41017
41218
|
try {
|
|
41018
|
-
const pyprojectTomlPath =
|
|
41019
|
-
const setupCfgPath =
|
|
41020
|
-
const requirementsTxtPath =
|
|
41021
|
-
if (
|
|
41022
|
-
const content =
|
|
41219
|
+
const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
|
|
41220
|
+
const setupCfgPath = path27.join(baseDir, "setup.cfg");
|
|
41221
|
+
const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
|
|
41222
|
+
if (fs17.existsSync(pyprojectTomlPath)) {
|
|
41223
|
+
const content = fs17.readFileSync(pyprojectTomlPath, "utf-8");
|
|
41023
41224
|
if (content.includes("[tool.pytest"))
|
|
41024
41225
|
return "pytest";
|
|
41025
41226
|
if (content.includes("pytest"))
|
|
41026
41227
|
return "pytest";
|
|
41027
41228
|
}
|
|
41028
|
-
if (
|
|
41029
|
-
const content =
|
|
41229
|
+
if (fs17.existsSync(setupCfgPath)) {
|
|
41230
|
+
const content = fs17.readFileSync(setupCfgPath, "utf-8");
|
|
41030
41231
|
if (content.includes("[pytest]"))
|
|
41031
41232
|
return "pytest";
|
|
41032
41233
|
}
|
|
41033
|
-
if (
|
|
41034
|
-
const content =
|
|
41234
|
+
if (fs17.existsSync(requirementsTxtPath)) {
|
|
41235
|
+
const content = fs17.readFileSync(requirementsTxtPath, "utf-8");
|
|
41035
41236
|
if (content.includes("pytest"))
|
|
41036
41237
|
return "pytest";
|
|
41037
41238
|
}
|
|
41038
41239
|
} catch {}
|
|
41039
41240
|
try {
|
|
41040
|
-
const cargoTomlPath =
|
|
41041
|
-
if (
|
|
41042
|
-
const content =
|
|
41241
|
+
const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
|
|
41242
|
+
if (fs17.existsSync(cargoTomlPath)) {
|
|
41243
|
+
const content = fs17.readFileSync(cargoTomlPath, "utf-8");
|
|
41043
41244
|
if (content.includes("[dev-dependencies]")) {
|
|
41044
41245
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
41045
41246
|
return "cargo";
|
|
@@ -41048,10 +41249,10 @@ async function detectTestFramework(cwd) {
|
|
|
41048
41249
|
}
|
|
41049
41250
|
} catch {}
|
|
41050
41251
|
try {
|
|
41051
|
-
const pesterConfigPath =
|
|
41052
|
-
const pesterConfigJsonPath =
|
|
41053
|
-
const pesterPs1Path =
|
|
41054
|
-
if (
|
|
41252
|
+
const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
|
|
41253
|
+
const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
|
|
41254
|
+
const pesterPs1Path = path27.join(baseDir, "tests.ps1");
|
|
41255
|
+
if (fs17.existsSync(pesterConfigPath) || fs17.existsSync(pesterConfigJsonPath) || fs17.existsSync(pesterPs1Path)) {
|
|
41055
41256
|
return "pester";
|
|
41056
41257
|
}
|
|
41057
41258
|
} catch {}
|
|
@@ -41075,18 +41276,12 @@ async function detectTestFramework(cwd) {
|
|
|
41075
41276
|
return "minitest";
|
|
41076
41277
|
return "none";
|
|
41077
41278
|
}
|
|
41078
|
-
var TEST_PATTERNS = [
|
|
41079
|
-
{ test: ".spec.", source: "." },
|
|
41080
|
-
{ test: ".test.", source: "." },
|
|
41081
|
-
{ test: "/__tests__/", source: "/" },
|
|
41082
|
-
{ test: "/tests/", source: "/" },
|
|
41083
|
-
{ test: "/test/", source: "/" }
|
|
41084
|
-
];
|
|
41085
41279
|
var COMPOUND_TEST_EXTENSIONS = [
|
|
41086
41280
|
".test.ts",
|
|
41087
41281
|
".test.tsx",
|
|
41088
41282
|
".test.js",
|
|
41089
41283
|
".test.jsx",
|
|
41284
|
+
".tests.ps1",
|
|
41090
41285
|
".spec.ts",
|
|
41091
41286
|
".spec.tsx",
|
|
41092
41287
|
".spec.js",
|
|
@@ -41094,51 +41289,149 @@ var COMPOUND_TEST_EXTENSIONS = [
|
|
|
41094
41289
|
".test.ps1",
|
|
41095
41290
|
".spec.ps1"
|
|
41096
41291
|
];
|
|
41292
|
+
var TEST_DIRECTORY_NAMES = ["__tests__", "tests", "test", "spec"];
|
|
41293
|
+
function isTestDirectoryPath(normalizedPath) {
|
|
41294
|
+
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
41295
|
+
}
|
|
41296
|
+
function resolveWorkspacePath(file3, workingDir) {
|
|
41297
|
+
return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
|
|
41298
|
+
}
|
|
41299
|
+
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
41300
|
+
if (!preferRelative)
|
|
41301
|
+
return absolutePath;
|
|
41302
|
+
return path27.relative(workingDir, absolutePath);
|
|
41303
|
+
}
|
|
41304
|
+
function dedupePush(target, value) {
|
|
41305
|
+
if (!target.includes(value)) {
|
|
41306
|
+
target.push(value);
|
|
41307
|
+
}
|
|
41308
|
+
}
|
|
41309
|
+
function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
41310
|
+
switch (ext) {
|
|
41311
|
+
case ".go":
|
|
41312
|
+
return [`${nameWithoutExt}_test.go`];
|
|
41313
|
+
case ".py":
|
|
41314
|
+
return [`test_${nameWithoutExt}.py`, `${nameWithoutExt}_test.py`];
|
|
41315
|
+
case ".rb":
|
|
41316
|
+
return [`${nameWithoutExt}_spec.rb`];
|
|
41317
|
+
case ".java":
|
|
41318
|
+
return [
|
|
41319
|
+
`${nameWithoutExt}Test.java`,
|
|
41320
|
+
`${nameWithoutExt}Tests.java`,
|
|
41321
|
+
`Test${nameWithoutExt}.java`,
|
|
41322
|
+
`${nameWithoutExt}IT.java`
|
|
41323
|
+
];
|
|
41324
|
+
case ".cs":
|
|
41325
|
+
return [`${nameWithoutExt}Test.cs`, `${nameWithoutExt}Tests.cs`];
|
|
41326
|
+
case ".kt":
|
|
41327
|
+
return [
|
|
41328
|
+
`${nameWithoutExt}Test.kt`,
|
|
41329
|
+
`${nameWithoutExt}Tests.kt`,
|
|
41330
|
+
`Test${nameWithoutExt}.kt`
|
|
41331
|
+
];
|
|
41332
|
+
case ".ps1":
|
|
41333
|
+
return [`${nameWithoutExt}.Tests.ps1`, `${nameWithoutExt}.tests.ps1`];
|
|
41334
|
+
default:
|
|
41335
|
+
return [];
|
|
41336
|
+
}
|
|
41337
|
+
}
|
|
41338
|
+
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
41339
|
+
const relativeDir = path27.dirname(relativePath);
|
|
41340
|
+
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
41341
|
+
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
41342
|
+
const rootDir = path27.join(workingDir, dirName);
|
|
41343
|
+
return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
41344
|
+
});
|
|
41345
|
+
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
41346
|
+
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
41347
|
+
directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
41348
|
+
}
|
|
41349
|
+
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
41350
|
+
directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
41351
|
+
}
|
|
41352
|
+
return [...new Set(directories)];
|
|
41353
|
+
}
|
|
41097
41354
|
function hasCompoundTestExtension(filename) {
|
|
41098
41355
|
const lower = filename.toLowerCase();
|
|
41099
41356
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
41100
41357
|
}
|
|
41101
|
-
function
|
|
41358
|
+
function isLanguageSpecificTestFile(basename4) {
|
|
41359
|
+
const lower = basename4.toLowerCase();
|
|
41360
|
+
if (lower.endsWith("_test.go"))
|
|
41361
|
+
return true;
|
|
41362
|
+
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
41363
|
+
return true;
|
|
41364
|
+
if (lower.endsWith("_spec.rb"))
|
|
41365
|
+
return true;
|
|
41366
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename4) || basename4.endsWith("Test.java") || basename4.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
41367
|
+
return true;
|
|
41368
|
+
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
41369
|
+
return true;
|
|
41370
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename4) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
41371
|
+
return true;
|
|
41372
|
+
if (lower.endsWith(".tests.ps1"))
|
|
41373
|
+
return true;
|
|
41374
|
+
return false;
|
|
41375
|
+
}
|
|
41376
|
+
function isConventionTestFilePath(filePath) {
|
|
41377
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
41378
|
+
const basename4 = path27.basename(filePath);
|
|
41379
|
+
return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
|
|
41380
|
+
}
|
|
41381
|
+
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
41102
41382
|
const testFiles = [];
|
|
41103
41383
|
for (const file3 of sourceFiles) {
|
|
41104
|
-
const
|
|
41105
|
-
const
|
|
41106
|
-
const
|
|
41107
|
-
|
|
41108
|
-
|
|
41109
|
-
|
|
41110
|
-
|
|
41384
|
+
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
41385
|
+
const relativeFile = path27.relative(workingDir, absoluteFile);
|
|
41386
|
+
const basename4 = path27.basename(absoluteFile);
|
|
41387
|
+
const dirname11 = path27.dirname(absoluteFile);
|
|
41388
|
+
const preferRelativeOutput = !path27.isAbsolute(file3);
|
|
41389
|
+
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
41390
|
+
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
41111
41391
|
continue;
|
|
41112
41392
|
}
|
|
41113
|
-
|
|
41114
|
-
|
|
41115
|
-
|
|
41116
|
-
|
|
41117
|
-
|
|
41118
|
-
|
|
41119
|
-
|
|
41120
|
-
|
|
41121
|
-
|
|
41122
|
-
|
|
41123
|
-
|
|
41124
|
-
|
|
41125
|
-
|
|
41126
|
-
|
|
41393
|
+
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
41394
|
+
const ext = path27.extname(basename4);
|
|
41395
|
+
const genericTestNames = [
|
|
41396
|
+
`${nameWithoutExt}.spec${ext}`,
|
|
41397
|
+
`${nameWithoutExt}.test${ext}`
|
|
41398
|
+
];
|
|
41399
|
+
const languageSpecificTestNames = buildLanguageSpecificTestNames(nameWithoutExt, ext);
|
|
41400
|
+
const colocatedCandidates = [
|
|
41401
|
+
...genericTestNames,
|
|
41402
|
+
...languageSpecificTestNames
|
|
41403
|
+
].map((candidateName) => path27.join(dirname11, candidateName));
|
|
41404
|
+
const testDirectoryNames = [
|
|
41405
|
+
basename4,
|
|
41406
|
+
...genericTestNames,
|
|
41407
|
+
...languageSpecificTestNames
|
|
41408
|
+
];
|
|
41409
|
+
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
41410
|
+
const possibleTestFiles = [
|
|
41411
|
+
...colocatedCandidates,
|
|
41412
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
|
|
41413
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
|
|
41414
|
+
];
|
|
41415
|
+
for (const testFile of possibleTestFiles) {
|
|
41416
|
+
if (fs17.existsSync(testFile)) {
|
|
41417
|
+
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
41127
41418
|
}
|
|
41128
41419
|
}
|
|
41129
41420
|
}
|
|
41130
41421
|
return testFiles;
|
|
41131
41422
|
}
|
|
41132
|
-
async function getTestFilesFromGraph(sourceFiles) {
|
|
41423
|
+
async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
41133
41424
|
const testFiles = [];
|
|
41134
|
-
const
|
|
41425
|
+
const absoluteSourceFiles = sourceFiles.map((sourceFile) => resolveWorkspacePath(sourceFile, workingDir));
|
|
41426
|
+
const candidateTestFiles = getTestFilesFromConvention(sourceFiles, workingDir);
|
|
41135
41427
|
if (sourceFiles.length === 0) {
|
|
41136
41428
|
return testFiles;
|
|
41137
41429
|
}
|
|
41138
41430
|
for (const testFile of candidateTestFiles) {
|
|
41139
41431
|
try {
|
|
41140
|
-
const
|
|
41141
|
-
const
|
|
41432
|
+
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
41433
|
+
const content = fs17.readFileSync(absoluteTestFile, "utf-8");
|
|
41434
|
+
const testDir = path27.dirname(absoluteTestFile);
|
|
41142
41435
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
41143
41436
|
let match;
|
|
41144
41437
|
match = importRegex.exec(content);
|
|
@@ -41146,8 +41439,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
41146
41439
|
const importPath = match[1];
|
|
41147
41440
|
let resolvedImport;
|
|
41148
41441
|
if (importPath.startsWith(".")) {
|
|
41149
|
-
resolvedImport =
|
|
41150
|
-
const existingExt =
|
|
41442
|
+
resolvedImport = path27.resolve(testDir, importPath);
|
|
41443
|
+
const existingExt = path27.extname(resolvedImport);
|
|
41151
41444
|
if (!existingExt) {
|
|
41152
41445
|
for (const extToTry of [
|
|
41153
41446
|
".ts",
|
|
@@ -41158,7 +41451,7 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
41158
41451
|
".cjs"
|
|
41159
41452
|
]) {
|
|
41160
41453
|
const withExt = resolvedImport + extToTry;
|
|
41161
|
-
if (
|
|
41454
|
+
if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
|
|
41162
41455
|
resolvedImport = withExt;
|
|
41163
41456
|
break;
|
|
41164
41457
|
}
|
|
@@ -41167,16 +41460,14 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
41167
41460
|
} else {
|
|
41168
41461
|
continue;
|
|
41169
41462
|
}
|
|
41170
|
-
const importBasename =
|
|
41171
|
-
const importDir =
|
|
41172
|
-
for (const sourceFile of
|
|
41173
|
-
const sourceDir =
|
|
41174
|
-
const sourceBasename =
|
|
41175
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
41463
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
41464
|
+
const importDir = path27.dirname(resolvedImport);
|
|
41465
|
+
for (const sourceFile of absoluteSourceFiles) {
|
|
41466
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
41467
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
41468
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
|
|
41176
41469
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
41177
|
-
|
|
41178
|
-
testFiles.push(testFile);
|
|
41179
|
-
}
|
|
41470
|
+
dedupePush(testFiles, testFile);
|
|
41180
41471
|
break;
|
|
41181
41472
|
}
|
|
41182
41473
|
}
|
|
@@ -41187,8 +41478,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
41187
41478
|
while (match !== null) {
|
|
41188
41479
|
const importPath = match[1];
|
|
41189
41480
|
if (importPath.startsWith(".")) {
|
|
41190
|
-
let resolvedImport =
|
|
41191
|
-
const existingExt =
|
|
41481
|
+
let resolvedImport = path27.resolve(testDir, importPath);
|
|
41482
|
+
const existingExt = path27.extname(resolvedImport);
|
|
41192
41483
|
if (!existingExt) {
|
|
41193
41484
|
for (const extToTry of [
|
|
41194
41485
|
".ts",
|
|
@@ -41199,22 +41490,20 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
41199
41490
|
".cjs"
|
|
41200
41491
|
]) {
|
|
41201
41492
|
const withExt = resolvedImport + extToTry;
|
|
41202
|
-
if (
|
|
41493
|
+
if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
|
|
41203
41494
|
resolvedImport = withExt;
|
|
41204
41495
|
break;
|
|
41205
41496
|
}
|
|
41206
41497
|
}
|
|
41207
41498
|
}
|
|
41208
|
-
const importDir =
|
|
41209
|
-
const importBasename =
|
|
41210
|
-
for (const sourceFile of
|
|
41211
|
-
const sourceDir =
|
|
41212
|
-
const sourceBasename =
|
|
41213
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
41499
|
+
const importDir = path27.dirname(resolvedImport);
|
|
41500
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
41501
|
+
for (const sourceFile of absoluteSourceFiles) {
|
|
41502
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
41503
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
41504
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
|
|
41214
41505
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
41215
|
-
|
|
41216
|
-
testFiles.push(testFile);
|
|
41217
|
-
}
|
|
41506
|
+
dedupePush(testFiles, testFile);
|
|
41218
41507
|
break;
|
|
41219
41508
|
}
|
|
41220
41509
|
}
|
|
@@ -41225,6 +41514,26 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
41225
41514
|
}
|
|
41226
41515
|
return testFiles;
|
|
41227
41516
|
}
|
|
41517
|
+
function getTargetedExecutionUnsupportedReason(framework) {
|
|
41518
|
+
switch (framework) {
|
|
41519
|
+
case "go-test":
|
|
41520
|
+
return "go test targets packages, not individual test files";
|
|
41521
|
+
case "cargo":
|
|
41522
|
+
return "cargo test targets crates, targets, or test names rather than file paths";
|
|
41523
|
+
case "maven":
|
|
41524
|
+
return "maven test selection is class-based, not file-path based";
|
|
41525
|
+
case "gradle":
|
|
41526
|
+
return "gradle test selection is class-based, not file-path based";
|
|
41527
|
+
case "dotnet-test":
|
|
41528
|
+
return "dotnet test filters by fully qualified names, not file paths";
|
|
41529
|
+
case "ctest":
|
|
41530
|
+
return "ctest filters named tests from the build tree, not source test files";
|
|
41531
|
+
case "swift-test":
|
|
41532
|
+
return "swift test filters test names, not file paths";
|
|
41533
|
+
default:
|
|
41534
|
+
return null;
|
|
41535
|
+
}
|
|
41536
|
+
}
|
|
41228
41537
|
function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
41229
41538
|
switch (framework) {
|
|
41230
41539
|
case "bun": {
|
|
@@ -41295,8 +41604,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
41295
41604
|
return ["mvn", "test"];
|
|
41296
41605
|
case "gradle": {
|
|
41297
41606
|
const isWindows = process.platform === "win32";
|
|
41298
|
-
const hasGradlewBat =
|
|
41299
|
-
const hasGradlew =
|
|
41607
|
+
const hasGradlewBat = fs17.existsSync(path27.join(baseDir, "gradlew.bat"));
|
|
41608
|
+
const hasGradlew = fs17.existsSync(path27.join(baseDir, "gradlew"));
|
|
41300
41609
|
if (hasGradlewBat && isWindows)
|
|
41301
41610
|
return ["gradlew.bat", "test"];
|
|
41302
41611
|
if (hasGradlew)
|
|
@@ -41313,16 +41622,25 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
41313
41622
|
"cmake-build-release",
|
|
41314
41623
|
"out"
|
|
41315
41624
|
];
|
|
41316
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
41625
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
41317
41626
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
41318
41627
|
}
|
|
41319
41628
|
case "swift-test":
|
|
41320
41629
|
return ["swift", "test"];
|
|
41321
41630
|
case "dart-test":
|
|
41322
|
-
return isCommandAvailable("flutter") ? ["flutter", "test"] : ["dart", "test"];
|
|
41323
|
-
case "rspec":
|
|
41324
|
-
|
|
41631
|
+
return isCommandAvailable("flutter") ? ["flutter", "test", ...files] : ["dart", "test", ...files];
|
|
41632
|
+
case "rspec": {
|
|
41633
|
+
const args = isCommandAvailable("bundle") ? ["bundle", "exec", "rspec"] : ["rspec"];
|
|
41634
|
+
if (scope !== "all" && files.length > 0) {
|
|
41635
|
+
args.push(...files);
|
|
41636
|
+
}
|
|
41637
|
+
return args;
|
|
41638
|
+
}
|
|
41325
41639
|
case "minitest":
|
|
41640
|
+
if (scope !== "all" && files.length > 0) {
|
|
41641
|
+
const requires = files.map((f) => `require_relative '${f.replace(/\\/g, "/").replace(/'/g, "\\'")}'`).join("; ");
|
|
41642
|
+
return ["ruby", "-Itest", "-e", requires];
|
|
41643
|
+
}
|
|
41326
41644
|
return [
|
|
41327
41645
|
"ruby",
|
|
41328
41646
|
"-Itest",
|
|
@@ -41583,6 +41901,19 @@ async function readBoundedStream(stream, maxBytes) {
|
|
|
41583
41901
|
return { text: decoder.decode(combined), truncated };
|
|
41584
41902
|
}
|
|
41585
41903
|
async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
41904
|
+
if (scope !== "all" && files.length > 0) {
|
|
41905
|
+
const unsupportedReason = getTargetedExecutionUnsupportedReason(framework);
|
|
41906
|
+
if (unsupportedReason) {
|
|
41907
|
+
return {
|
|
41908
|
+
success: false,
|
|
41909
|
+
framework,
|
|
41910
|
+
scope,
|
|
41911
|
+
error: `Framework "${framework}" does not support targeted test-file execution`,
|
|
41912
|
+
message: `The resolved test selection cannot be run safely because ${unsupportedReason}. Use a framework-native selector manually or let the architect handle the broader sweep.`,
|
|
41913
|
+
outcome: "error"
|
|
41914
|
+
};
|
|
41915
|
+
}
|
|
41916
|
+
}
|
|
41586
41917
|
const command = buildTestCommand(framework, scope, files, coverage, cwd);
|
|
41587
41918
|
if (!command) {
|
|
41588
41919
|
return {
|
|
@@ -41612,9 +41943,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
41612
41943
|
stderr: "pipe",
|
|
41613
41944
|
cwd
|
|
41614
41945
|
});
|
|
41615
|
-
const timeoutPromise = new Promise((
|
|
41946
|
+
const timeoutPromise = new Promise((resolve12) => setTimeout(() => {
|
|
41616
41947
|
proc.kill();
|
|
41617
|
-
|
|
41948
|
+
resolve12(-1);
|
|
41618
41949
|
}, timeout_ms));
|
|
41619
41950
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
41620
41951
|
Promise.race([proc.exited, timeoutPromise]),
|
|
@@ -41787,10 +42118,10 @@ function analyzeFailures(workingDir) {
|
|
|
41787
42118
|
return report;
|
|
41788
42119
|
}
|
|
41789
42120
|
var test_runner = createSwarmTool({
|
|
41790
|
-
description: 'Run project tests with framework detection. Supports bun, vitest, jest, mocha, pytest, cargo, pester, go-test, maven, gradle, dotnet-test, ctest, swift-test, dart-test, rspec, and minitest. Returns deterministic normalized JSON with framework, scope, command, totals, coverage, duration, success status, and failures. Use scope "all" for full suite, "convention" to map source files to test files, "graph" to find related tests via imports, or "impact" to find tests covering changed files using test-impact analysis.',
|
|
42121
|
+
description: 'Run project tests with framework detection. Supports bun, vitest, jest, mocha, pytest, cargo, pester, go-test, maven, gradle, dotnet-test, ctest, swift-test, dart-test, rspec, and minitest. Returns deterministic normalized JSON with framework, scope, command, totals, coverage, duration, success status, and failures. Use scope "all" for full suite, "convention" to accept direct test files or map source files to test files, "graph" to find related tests via imports from source files, or "impact" to find tests covering changed source files using test-impact analysis.',
|
|
41791
42122
|
args: {
|
|
41792
|
-
scope: tool.schema.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" maps source files to
|
|
41793
|
-
files: tool.schema.array(tool.schema.string()).optional().describe(
|
|
42123
|
+
scope: tool.schema.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" accepts direct test files or maps source files to tests by naming, "graph" finds related tests via imports from source files, "impact" finds tests covering changed source files via test-impact analysis'),
|
|
42124
|
+
files: tool.schema.array(tool.schema.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
|
|
41794
42125
|
coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
|
|
41795
42126
|
timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
|
|
41796
42127
|
allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
|
|
@@ -41915,25 +42246,46 @@ var test_runner = createSwarmTool({
|
|
|
41915
42246
|
let graphFallbackReason;
|
|
41916
42247
|
let effectiveScope = scope;
|
|
41917
42248
|
if (scope === "all") {} else if (scope === "convention") {
|
|
41918
|
-
const
|
|
41919
|
-
|
|
42249
|
+
const directTestFiles = args.files.filter((file3) => isConventionTestFilePath(file3));
|
|
42250
|
+
const sourceFiles = args.files.filter((file3) => {
|
|
42251
|
+
if (directTestFiles.includes(file3))
|
|
42252
|
+
return false;
|
|
42253
|
+
const ext = path27.extname(file3).toLowerCase();
|
|
41920
42254
|
return SOURCE_EXTENSIONS.has(ext);
|
|
41921
42255
|
});
|
|
41922
|
-
|
|
42256
|
+
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
42257
|
+
if (directTestFiles.length === 0 && sourceFiles.length === 0) {
|
|
41923
42258
|
const errorResult = {
|
|
41924
42259
|
success: false,
|
|
41925
42260
|
framework,
|
|
41926
42261
|
scope,
|
|
41927
|
-
error: "Provided files contain no source files
|
|
41928
|
-
message: "The files array must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.)
|
|
42262
|
+
error: "Provided files contain no recognized source files or direct test files",
|
|
42263
|
+
message: "The files array must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.) or a direct test file in a supported test location/naming convention.",
|
|
42264
|
+
outcome: "error"
|
|
42265
|
+
};
|
|
42266
|
+
return JSON.stringify(errorResult, null, 2);
|
|
42267
|
+
}
|
|
42268
|
+
if (invalidFiles.length > 0) {
|
|
42269
|
+
const errorResult = {
|
|
42270
|
+
success: false,
|
|
42271
|
+
framework,
|
|
42272
|
+
scope,
|
|
42273
|
+
error: "Provided files include entries that are neither recognized source files nor direct test files",
|
|
42274
|
+
message: `These files are not valid for targeted test discovery: ${invalidFiles.join(", ")}`,
|
|
41929
42275
|
outcome: "error"
|
|
41930
42276
|
};
|
|
41931
42277
|
return JSON.stringify(errorResult, null, 2);
|
|
41932
42278
|
}
|
|
41933
|
-
testFiles =
|
|
42279
|
+
testFiles = [
|
|
42280
|
+
...directTestFiles,
|
|
42281
|
+
...getTestFilesFromConvention(sourceFiles, workingDir)
|
|
42282
|
+
].filter((file3, index, items) => items.indexOf(file3) === index);
|
|
41934
42283
|
} else if (scope === "graph") {
|
|
41935
42284
|
const sourceFiles = args.files.filter((f) => {
|
|
41936
|
-
|
|
42285
|
+
if (isConventionTestFilePath(f)) {
|
|
42286
|
+
return false;
|
|
42287
|
+
}
|
|
42288
|
+
const ext = path27.extname(f).toLowerCase();
|
|
41937
42289
|
return SOURCE_EXTENSIONS.has(ext);
|
|
41938
42290
|
});
|
|
41939
42291
|
if (sourceFiles.length === 0) {
|
|
@@ -41942,22 +42294,25 @@ var test_runner = createSwarmTool({
|
|
|
41942
42294
|
framework,
|
|
41943
42295
|
scope,
|
|
41944
42296
|
error: "Provided files contain no source files with recognized extensions",
|
|
41945
|
-
message:
|
|
42297
|
+
message: 'The files array for scope "graph" must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.). Direct test files belong in scope "convention".',
|
|
41946
42298
|
outcome: "error"
|
|
41947
42299
|
};
|
|
41948
42300
|
return JSON.stringify(errorResult, null, 2);
|
|
41949
42301
|
}
|
|
41950
|
-
const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
|
|
42302
|
+
const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
|
|
41951
42303
|
if (graphTestFiles.length > 0) {
|
|
41952
42304
|
testFiles = graphTestFiles;
|
|
41953
42305
|
} else {
|
|
41954
42306
|
graphFallbackReason = "imports resolution returned no results, falling back to convention";
|
|
41955
42307
|
effectiveScope = "convention";
|
|
41956
|
-
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
42308
|
+
testFiles = getTestFilesFromConvention(sourceFiles, workingDir);
|
|
41957
42309
|
}
|
|
41958
42310
|
} else if (scope === "impact") {
|
|
41959
42311
|
const sourceFiles = args.files.filter((f) => {
|
|
41960
|
-
|
|
42312
|
+
if (isConventionTestFilePath(f)) {
|
|
42313
|
+
return false;
|
|
42314
|
+
}
|
|
42315
|
+
const ext = path27.extname(f).toLowerCase();
|
|
41961
42316
|
return SOURCE_EXTENSIONS.has(ext);
|
|
41962
42317
|
});
|
|
41963
42318
|
if (sourceFiles.length === 0) {
|
|
@@ -41966,7 +42321,7 @@ var test_runner = createSwarmTool({
|
|
|
41966
42321
|
framework,
|
|
41967
42322
|
scope,
|
|
41968
42323
|
error: "Provided files contain no source files with recognized extensions",
|
|
41969
|
-
message:
|
|
42324
|
+
message: 'The files array for scope "impact" must contain at least one source file with a recognized extension (.ts, .tsx, .js, .jsx, .py, .rs, .ps1, etc.). Direct test files belong in scope "convention".',
|
|
41970
42325
|
outcome: "error"
|
|
41971
42326
|
};
|
|
41972
42327
|
return JSON.stringify(errorResult, null, 2);
|
|
@@ -41975,36 +42330,36 @@ var test_runner = createSwarmTool({
|
|
|
41975
42330
|
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
41976
42331
|
if (impactResult.impactedTests.length > 0) {
|
|
41977
42332
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
41978
|
-
const relativePath =
|
|
41979
|
-
return
|
|
42333
|
+
const relativePath = path27.relative(workingDir, absPath);
|
|
42334
|
+
return path27.isAbsolute(relativePath) ? absPath : relativePath;
|
|
41980
42335
|
});
|
|
41981
42336
|
} else {
|
|
41982
42337
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
41983
42338
|
effectiveScope = "graph";
|
|
41984
|
-
const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
|
|
42339
|
+
const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
|
|
41985
42340
|
if (graphTestFiles.length > 0) {
|
|
41986
42341
|
testFiles = graphTestFiles;
|
|
41987
42342
|
} else {
|
|
41988
42343
|
graphFallbackReason = "imports resolution returned no results, falling back to convention";
|
|
41989
42344
|
effectiveScope = "convention";
|
|
41990
|
-
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
42345
|
+
testFiles = getTestFilesFromConvention(sourceFiles, workingDir);
|
|
41991
42346
|
}
|
|
41992
42347
|
}
|
|
41993
42348
|
} catch {
|
|
41994
42349
|
graphFallbackReason = "impact analysis failed, falling back to graph";
|
|
41995
42350
|
effectiveScope = "graph";
|
|
41996
|
-
const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
|
|
42351
|
+
const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
|
|
41997
42352
|
if (graphTestFiles.length > 0) {
|
|
41998
42353
|
testFiles = graphTestFiles;
|
|
41999
42354
|
} else {
|
|
42000
42355
|
graphFallbackReason = "imports resolution returned no results, falling back to convention";
|
|
42001
42356
|
effectiveScope = "convention";
|
|
42002
|
-
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
42357
|
+
testFiles = getTestFilesFromConvention(sourceFiles, workingDir);
|
|
42003
42358
|
}
|
|
42004
42359
|
}
|
|
42005
42360
|
}
|
|
42006
42361
|
if (scope !== "all" && testFiles.length === 0) {
|
|
42007
|
-
const baseMessage = "No matching test files found for the provided source files. Check that test files exist with matching naming conventions (.spec.*, .test.*, __tests__/, tests/, test/).";
|
|
42362
|
+
const baseMessage = "No matching test files found for the provided source files. Check that test files exist with matching naming conventions (.spec.*, .test.*, .Tests.ps1, __tests__/, tests/, test/, spec/).";
|
|
42008
42363
|
const errorResult = {
|
|
42009
42364
|
success: false,
|
|
42010
42365
|
framework,
|
|
@@ -42069,8 +42424,8 @@ function validateDirectoryPath(dir) {
|
|
|
42069
42424
|
if (dir.includes("..")) {
|
|
42070
42425
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
42071
42426
|
}
|
|
42072
|
-
const normalized =
|
|
42073
|
-
const absolutePath =
|
|
42427
|
+
const normalized = path28.normalize(dir);
|
|
42428
|
+
const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
|
|
42074
42429
|
return absolutePath;
|
|
42075
42430
|
}
|
|
42076
42431
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -42093,9 +42448,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
42093
42448
|
}
|
|
42094
42449
|
function getPackageVersion(dir) {
|
|
42095
42450
|
try {
|
|
42096
|
-
const packagePath =
|
|
42097
|
-
if (
|
|
42098
|
-
const content =
|
|
42451
|
+
const packagePath = path28.join(dir, "package.json");
|
|
42452
|
+
if (fs18.existsSync(packagePath)) {
|
|
42453
|
+
const content = fs18.readFileSync(packagePath, "utf-8");
|
|
42099
42454
|
const pkg = JSON.parse(content);
|
|
42100
42455
|
return pkg.version ?? null;
|
|
42101
42456
|
}
|
|
@@ -42104,9 +42459,9 @@ function getPackageVersion(dir) {
|
|
|
42104
42459
|
}
|
|
42105
42460
|
function getChangelogVersion(dir) {
|
|
42106
42461
|
try {
|
|
42107
|
-
const changelogPath =
|
|
42108
|
-
if (
|
|
42109
|
-
const content =
|
|
42462
|
+
const changelogPath = path28.join(dir, "CHANGELOG.md");
|
|
42463
|
+
if (fs18.existsSync(changelogPath)) {
|
|
42464
|
+
const content = fs18.readFileSync(changelogPath, "utf-8");
|
|
42110
42465
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
42111
42466
|
if (match) {
|
|
42112
42467
|
return match[1];
|
|
@@ -42118,10 +42473,10 @@ function getChangelogVersion(dir) {
|
|
|
42118
42473
|
function getVersionFileVersion(dir) {
|
|
42119
42474
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
42120
42475
|
for (const file3 of possibleFiles) {
|
|
42121
|
-
const filePath =
|
|
42122
|
-
if (
|
|
42476
|
+
const filePath = path28.join(dir, file3);
|
|
42477
|
+
if (fs18.existsSync(filePath)) {
|
|
42123
42478
|
try {
|
|
42124
|
-
const content =
|
|
42479
|
+
const content = fs18.readFileSync(filePath, "utf-8").trim();
|
|
42125
42480
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
42126
42481
|
if (match) {
|
|
42127
42482
|
return match[1];
|
|
@@ -42445,8 +42800,8 @@ async function runEvidenceCheck(dir) {
|
|
|
42445
42800
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
42446
42801
|
const startTime = Date.now();
|
|
42447
42802
|
try {
|
|
42448
|
-
const specPath =
|
|
42449
|
-
if (!
|
|
42803
|
+
const specPath = path28.join(dir, ".swarm", "spec.md");
|
|
42804
|
+
if (!fs18.existsSync(specPath)) {
|
|
42450
42805
|
return {
|
|
42451
42806
|
type: "req_coverage",
|
|
42452
42807
|
status: "skip",
|
|
@@ -42659,9 +43014,9 @@ async function handlePreflightCommand(directory, _args) {
|
|
|
42659
43014
|
return formatPreflightMarkdown(report);
|
|
42660
43015
|
}
|
|
42661
43016
|
// src/knowledge/hive-promoter.ts
|
|
42662
|
-
import * as
|
|
42663
|
-
import * as
|
|
42664
|
-
import * as
|
|
43017
|
+
import * as fs19 from "fs";
|
|
43018
|
+
import * as os6 from "os";
|
|
43019
|
+
import * as path29 from "path";
|
|
42665
43020
|
var DANGEROUS_PATTERNS = [
|
|
42666
43021
|
[/rm\s+-rf/, "rm\\s+-rf"],
|
|
42667
43022
|
[/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
|
|
@@ -42704,16 +43059,16 @@ function validateLesson2(text) {
|
|
|
42704
43059
|
}
|
|
42705
43060
|
function getHiveFilePath() {
|
|
42706
43061
|
const platform = process.platform;
|
|
42707
|
-
const home =
|
|
43062
|
+
const home = os6.homedir();
|
|
42708
43063
|
let dataDir;
|
|
42709
43064
|
if (platform === "win32") {
|
|
42710
|
-
dataDir =
|
|
43065
|
+
dataDir = path29.join(process.env.LOCALAPPDATA || path29.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
42711
43066
|
} else if (platform === "darwin") {
|
|
42712
|
-
dataDir =
|
|
43067
|
+
dataDir = path29.join(home, "Library", "Application Support", "opencode-swarm");
|
|
42713
43068
|
} else {
|
|
42714
|
-
dataDir =
|
|
43069
|
+
dataDir = path29.join(process.env.XDG_DATA_HOME || path29.join(home, ".local", "share"), "opencode-swarm");
|
|
42715
43070
|
}
|
|
42716
|
-
return
|
|
43071
|
+
return path29.join(dataDir, "hive-knowledge.jsonl");
|
|
42717
43072
|
}
|
|
42718
43073
|
async function promoteToHive(_directory, lesson, category) {
|
|
42719
43074
|
const trimmed = (lesson ?? "").trim();
|
|
@@ -42725,9 +43080,9 @@ async function promoteToHive(_directory, lesson, category) {
|
|
|
42725
43080
|
throw new Error(`Lesson rejected by validator: ${validation.reason}`);
|
|
42726
43081
|
}
|
|
42727
43082
|
const hivePath = getHiveFilePath();
|
|
42728
|
-
const hiveDir =
|
|
42729
|
-
if (!
|
|
42730
|
-
|
|
43083
|
+
const hiveDir = path29.dirname(hivePath);
|
|
43084
|
+
if (!fs19.existsSync(hiveDir)) {
|
|
43085
|
+
fs19.mkdirSync(hiveDir, { recursive: true });
|
|
42731
43086
|
}
|
|
42732
43087
|
const now = new Date;
|
|
42733
43088
|
const entry = {
|
|
@@ -42741,16 +43096,16 @@ async function promoteToHive(_directory, lesson, category) {
|
|
|
42741
43096
|
promotedAt: now.toISOString(),
|
|
42742
43097
|
retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
|
|
42743
43098
|
};
|
|
42744
|
-
|
|
43099
|
+
fs19.appendFileSync(hivePath, `${JSON.stringify(entry)}
|
|
42745
43100
|
`, "utf-8");
|
|
42746
43101
|
const preview = `${trimmed.slice(0, 50)}${trimmed.length > 50 ? "..." : ""}`;
|
|
42747
43102
|
return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
|
|
42748
43103
|
}
|
|
42749
43104
|
async function promoteFromSwarm(directory, lessonId) {
|
|
42750
|
-
const knowledgePath =
|
|
43105
|
+
const knowledgePath = path29.join(directory, ".swarm", "knowledge.jsonl");
|
|
42751
43106
|
const entries = [];
|
|
42752
|
-
if (
|
|
42753
|
-
const content =
|
|
43107
|
+
if (fs19.existsSync(knowledgePath)) {
|
|
43108
|
+
const content = fs19.readFileSync(knowledgePath, "utf-8");
|
|
42754
43109
|
for (const line of content.split(`
|
|
42755
43110
|
`)) {
|
|
42756
43111
|
const t = line.trim();
|
|
@@ -42774,9 +43129,9 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
42774
43129
|
throw new Error(`Lesson rejected by validator: ${validation.reason}`);
|
|
42775
43130
|
}
|
|
42776
43131
|
const hivePath = getHiveFilePath();
|
|
42777
|
-
const hiveDir =
|
|
42778
|
-
if (!
|
|
42779
|
-
|
|
43132
|
+
const hiveDir = path29.dirname(hivePath);
|
|
43133
|
+
if (!fs19.existsSync(hiveDir)) {
|
|
43134
|
+
fs19.mkdirSync(hiveDir, { recursive: true });
|
|
42780
43135
|
}
|
|
42781
43136
|
const now = new Date;
|
|
42782
43137
|
const hiveEntry = {
|
|
@@ -42790,7 +43145,7 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
42790
43145
|
promotedAt: now.toISOString(),
|
|
42791
43146
|
retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
|
|
42792
43147
|
};
|
|
42793
|
-
|
|
43148
|
+
fs19.appendFileSync(hivePath, `${JSON.stringify(hiveEntry)}
|
|
42794
43149
|
`, "utf-8");
|
|
42795
43150
|
const preview = `${lessonText.slice(0, 50)}${lessonText.length > 50 ? "..." : ""}`;
|
|
42796
43151
|
return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
|
|
@@ -42969,7 +43324,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
42969
43324
|
}
|
|
42970
43325
|
|
|
42971
43326
|
// src/commands/reset.ts
|
|
42972
|
-
import * as
|
|
43327
|
+
import * as fs20 from "fs";
|
|
42973
43328
|
|
|
42974
43329
|
// src/background/manager.ts
|
|
42975
43330
|
init_utils();
|
|
@@ -43024,13 +43379,13 @@ class CircuitBreaker {
|
|
|
43024
43379
|
if (this.config.callTimeoutMs <= 0) {
|
|
43025
43380
|
return fn();
|
|
43026
43381
|
}
|
|
43027
|
-
return new Promise((
|
|
43382
|
+
return new Promise((resolve13, reject) => {
|
|
43028
43383
|
const timeout = setTimeout(() => {
|
|
43029
43384
|
reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
|
|
43030
43385
|
}, this.config.callTimeoutMs);
|
|
43031
43386
|
fn().then((result) => {
|
|
43032
43387
|
clearTimeout(timeout);
|
|
43033
|
-
|
|
43388
|
+
resolve13(result);
|
|
43034
43389
|
}).catch((error93) => {
|
|
43035
43390
|
clearTimeout(timeout);
|
|
43036
43391
|
reject(error93);
|
|
@@ -43314,7 +43669,7 @@ class AutomationQueue {
|
|
|
43314
43669
|
|
|
43315
43670
|
// src/background/worker.ts
|
|
43316
43671
|
function sleep(ms) {
|
|
43317
|
-
return new Promise((
|
|
43672
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
43318
43673
|
}
|
|
43319
43674
|
|
|
43320
43675
|
class WorkerManager {
|
|
@@ -43670,8 +44025,8 @@ async function handleResetCommand(directory, args) {
|
|
|
43670
44025
|
for (const filename of filesToReset) {
|
|
43671
44026
|
try {
|
|
43672
44027
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
43673
|
-
if (
|
|
43674
|
-
|
|
44028
|
+
if (fs20.existsSync(resolvedPath)) {
|
|
44029
|
+
fs20.unlinkSync(resolvedPath);
|
|
43675
44030
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
43676
44031
|
} else {
|
|
43677
44032
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -43688,8 +44043,8 @@ async function handleResetCommand(directory, args) {
|
|
|
43688
44043
|
}
|
|
43689
44044
|
try {
|
|
43690
44045
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
43691
|
-
if (
|
|
43692
|
-
|
|
44046
|
+
if (fs20.existsSync(summariesPath)) {
|
|
44047
|
+
fs20.rmSync(summariesPath, { recursive: true, force: true });
|
|
43693
44048
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
43694
44049
|
} else {
|
|
43695
44050
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -43709,14 +44064,14 @@ async function handleResetCommand(directory, args) {
|
|
|
43709
44064
|
|
|
43710
44065
|
// src/commands/reset-session.ts
|
|
43711
44066
|
init_utils2();
|
|
43712
|
-
import * as
|
|
43713
|
-
import * as
|
|
44067
|
+
import * as fs21 from "fs";
|
|
44068
|
+
import * as path30 from "path";
|
|
43714
44069
|
async function handleResetSessionCommand(directory, _args) {
|
|
43715
44070
|
const results = [];
|
|
43716
44071
|
try {
|
|
43717
44072
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
43718
|
-
if (
|
|
43719
|
-
|
|
44073
|
+
if (fs21.existsSync(statePath)) {
|
|
44074
|
+
fs21.unlinkSync(statePath);
|
|
43720
44075
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
43721
44076
|
} else {
|
|
43722
44077
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -43725,15 +44080,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
43725
44080
|
results.push("\u274C Failed to delete state.json");
|
|
43726
44081
|
}
|
|
43727
44082
|
try {
|
|
43728
|
-
const sessionDir =
|
|
43729
|
-
if (
|
|
43730
|
-
const files =
|
|
44083
|
+
const sessionDir = path30.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
44084
|
+
if (fs21.existsSync(sessionDir)) {
|
|
44085
|
+
const files = fs21.readdirSync(sessionDir);
|
|
43731
44086
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
43732
44087
|
let deletedCount = 0;
|
|
43733
44088
|
for (const file3 of otherFiles) {
|
|
43734
|
-
const filePath =
|
|
43735
|
-
if (
|
|
43736
|
-
|
|
44089
|
+
const filePath = path30.join(sessionDir, file3);
|
|
44090
|
+
if (fs21.lstatSync(filePath).isFile()) {
|
|
44091
|
+
fs21.unlinkSync(filePath);
|
|
43737
44092
|
deletedCount++;
|
|
43738
44093
|
}
|
|
43739
44094
|
}
|
|
@@ -43761,7 +44116,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
43761
44116
|
// src/summaries/manager.ts
|
|
43762
44117
|
init_utils2();
|
|
43763
44118
|
init_utils();
|
|
43764
|
-
import * as
|
|
44119
|
+
import * as path31 from "path";
|
|
43765
44120
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
43766
44121
|
function sanitizeSummaryId(id) {
|
|
43767
44122
|
if (!id || id.length === 0) {
|
|
@@ -43785,7 +44140,7 @@ function sanitizeSummaryId(id) {
|
|
|
43785
44140
|
}
|
|
43786
44141
|
async function loadFullOutput(directory, id) {
|
|
43787
44142
|
const sanitizedId = sanitizeSummaryId(id);
|
|
43788
|
-
const relativePath =
|
|
44143
|
+
const relativePath = path31.join("summaries", `${sanitizedId}.json`);
|
|
43789
44144
|
validateSwarmPath(directory, relativePath);
|
|
43790
44145
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
43791
44146
|
if (content === null) {
|
|
@@ -43838,18 +44193,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
43838
44193
|
|
|
43839
44194
|
// src/commands/rollback.ts
|
|
43840
44195
|
init_utils2();
|
|
43841
|
-
import * as
|
|
43842
|
-
import * as
|
|
44196
|
+
import * as fs22 from "fs";
|
|
44197
|
+
import * as path32 from "path";
|
|
43843
44198
|
async function handleRollbackCommand(directory, args) {
|
|
43844
44199
|
const phaseArg = args[0];
|
|
43845
44200
|
if (!phaseArg) {
|
|
43846
44201
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
43847
|
-
if (!
|
|
44202
|
+
if (!fs22.existsSync(manifestPath2)) {
|
|
43848
44203
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
43849
44204
|
}
|
|
43850
44205
|
let manifest2;
|
|
43851
44206
|
try {
|
|
43852
|
-
manifest2 = JSON.parse(
|
|
44207
|
+
manifest2 = JSON.parse(fs22.readFileSync(manifestPath2, "utf-8"));
|
|
43853
44208
|
} catch {
|
|
43854
44209
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
43855
44210
|
}
|
|
@@ -43871,12 +44226,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
43871
44226
|
return "Error: Phase number must be a positive integer.";
|
|
43872
44227
|
}
|
|
43873
44228
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
43874
|
-
if (!
|
|
44229
|
+
if (!fs22.existsSync(manifestPath)) {
|
|
43875
44230
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
43876
44231
|
}
|
|
43877
44232
|
let manifest;
|
|
43878
44233
|
try {
|
|
43879
|
-
manifest = JSON.parse(
|
|
44234
|
+
manifest = JSON.parse(fs22.readFileSync(manifestPath, "utf-8"));
|
|
43880
44235
|
} catch {
|
|
43881
44236
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
43882
44237
|
}
|
|
@@ -43886,10 +44241,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
43886
44241
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
43887
44242
|
}
|
|
43888
44243
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
43889
|
-
if (!
|
|
44244
|
+
if (!fs22.existsSync(checkpointDir)) {
|
|
43890
44245
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
43891
44246
|
}
|
|
43892
|
-
const checkpointFiles =
|
|
44247
|
+
const checkpointFiles = fs22.readdirSync(checkpointDir);
|
|
43893
44248
|
if (checkpointFiles.length === 0) {
|
|
43894
44249
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
43895
44250
|
}
|
|
@@ -43897,10 +44252,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
43897
44252
|
const successes = [];
|
|
43898
44253
|
const failures = [];
|
|
43899
44254
|
for (const file3 of checkpointFiles) {
|
|
43900
|
-
const src =
|
|
43901
|
-
const dest =
|
|
44255
|
+
const src = path32.join(checkpointDir, file3);
|
|
44256
|
+
const dest = path32.join(swarmDir, file3);
|
|
43902
44257
|
try {
|
|
43903
|
-
|
|
44258
|
+
fs22.cpSync(src, dest, { recursive: true, force: true });
|
|
43904
44259
|
successes.push(file3);
|
|
43905
44260
|
} catch (error93) {
|
|
43906
44261
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -43917,7 +44272,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
43917
44272
|
timestamp: new Date().toISOString()
|
|
43918
44273
|
};
|
|
43919
44274
|
try {
|
|
43920
|
-
|
|
44275
|
+
fs22.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
43921
44276
|
`);
|
|
43922
44277
|
} catch (error93) {
|
|
43923
44278
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -43960,11 +44315,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
43960
44315
|
];
|
|
43961
44316
|
const report = reportLines.filter(Boolean).join(`
|
|
43962
44317
|
`);
|
|
43963
|
-
const
|
|
43964
|
-
const
|
|
43965
|
-
const reportPath =
|
|
43966
|
-
await
|
|
43967
|
-
await
|
|
44318
|
+
const fs23 = await import("fs/promises");
|
|
44319
|
+
const path33 = await import("path");
|
|
44320
|
+
const reportPath = path33.join(directory, ".swarm", "simulate-report.md");
|
|
44321
|
+
await fs23.mkdir(path33.dirname(reportPath), { recursive: true });
|
|
44322
|
+
await fs23.writeFile(reportPath, report, "utf-8");
|
|
43968
44323
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
43969
44324
|
}
|
|
43970
44325
|
|
|
@@ -44487,18 +44842,18 @@ function resolveCommand(tokens) {
|
|
|
44487
44842
|
}
|
|
44488
44843
|
|
|
44489
44844
|
// src/cli/index.ts
|
|
44490
|
-
var CONFIG_DIR =
|
|
44491
|
-
var OPENCODE_CONFIG_PATH =
|
|
44492
|
-
var PLUGIN_CONFIG_PATH =
|
|
44493
|
-
var PROMPTS_DIR =
|
|
44845
|
+
var CONFIG_DIR = path33.join(process.env.XDG_CONFIG_HOME || path33.join(os7.homedir(), ".config"), "opencode");
|
|
44846
|
+
var OPENCODE_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode.json");
|
|
44847
|
+
var PLUGIN_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode-swarm.json");
|
|
44848
|
+
var PROMPTS_DIR = path33.join(CONFIG_DIR, "opencode-swarm");
|
|
44494
44849
|
function ensureDir(dir) {
|
|
44495
|
-
if (!
|
|
44496
|
-
|
|
44850
|
+
if (!fs23.existsSync(dir)) {
|
|
44851
|
+
fs23.mkdirSync(dir, { recursive: true });
|
|
44497
44852
|
}
|
|
44498
44853
|
}
|
|
44499
44854
|
function loadJson(filepath) {
|
|
44500
44855
|
try {
|
|
44501
|
-
const content =
|
|
44856
|
+
const content = fs23.readFileSync(filepath, "utf-8");
|
|
44502
44857
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
44503
44858
|
return JSON.parse(stripped);
|
|
44504
44859
|
} catch {
|
|
@@ -44506,7 +44861,7 @@ function loadJson(filepath) {
|
|
|
44506
44861
|
}
|
|
44507
44862
|
}
|
|
44508
44863
|
function saveJson(filepath, data) {
|
|
44509
|
-
|
|
44864
|
+
fs23.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
44510
44865
|
`, "utf-8");
|
|
44511
44866
|
}
|
|
44512
44867
|
async function install() {
|
|
@@ -44514,7 +44869,7 @@ async function install() {
|
|
|
44514
44869
|
`);
|
|
44515
44870
|
ensureDir(CONFIG_DIR);
|
|
44516
44871
|
ensureDir(PROMPTS_DIR);
|
|
44517
|
-
const LEGACY_CONFIG_PATH =
|
|
44872
|
+
const LEGACY_CONFIG_PATH = path33.join(CONFIG_DIR, "config.json");
|
|
44518
44873
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
44519
44874
|
if (!opencodeConfig) {
|
|
44520
44875
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -44539,7 +44894,7 @@ async function install() {
|
|
|
44539
44894
|
saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
|
|
44540
44895
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
44541
44896
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
44542
|
-
if (!
|
|
44897
|
+
if (!fs23.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
44543
44898
|
const defaultConfig = {
|
|
44544
44899
|
agents: {
|
|
44545
44900
|
coder: { model: "opencode/minimax-m2.5-free" },
|
|
@@ -44582,7 +44937,7 @@ async function uninstall() {
|
|
|
44582
44937
|
`);
|
|
44583
44938
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
44584
44939
|
if (!opencodeConfig) {
|
|
44585
|
-
if (
|
|
44940
|
+
if (fs23.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
44586
44941
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
44587
44942
|
return 1;
|
|
44588
44943
|
} else {
|
|
@@ -44614,13 +44969,13 @@ async function uninstall() {
|
|
|
44614
44969
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
44615
44970
|
if (process.argv.includes("--clean")) {
|
|
44616
44971
|
let cleaned = false;
|
|
44617
|
-
if (
|
|
44618
|
-
|
|
44972
|
+
if (fs23.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
44973
|
+
fs23.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
44619
44974
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
44620
44975
|
cleaned = true;
|
|
44621
44976
|
}
|
|
44622
|
-
if (
|
|
44623
|
-
|
|
44977
|
+
if (fs23.existsSync(PROMPTS_DIR)) {
|
|
44978
|
+
fs23.rmSync(PROMPTS_DIR, { recursive: true });
|
|
44624
44979
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
44625
44980
|
cleaned = true;
|
|
44626
44981
|
}
|