opencode-swarm 7.106.0 → 7.107.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/.opencode/skills/critic-gate/SKILL.md +19 -5
- package/.opencode/skills/plan/SKILL.md +18 -3
- package/.opencode/skills/resume/SKILL.md +4 -1
- package/.opencode/skills/writing-tests/SKILL.md +31 -0
- package/dist/agents/critic.d.ts +1 -1
- package/dist/cli/{evidence-summary-service-v9kmv783.js → evidence-summary-service-zhw4rkjb.js} +1 -1
- package/dist/cli/{guardrail-explain-fvjc90wa.js → guardrail-explain-6xt0pb56.js} +3 -3
- package/dist/cli/{index-k2rmw9sz.js → index-25pev4e7.js} +165 -31
- package/dist/cli/{index-f4yjypa4.js → index-fhw0jm5c.js} +753 -633
- package/dist/cli/{index-z4t3w4xf.js → index-v90bnn0f.js} +3 -3
- package/dist/cli/{index-7dtekwvd.js → index-wa6at603.js} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/commands/reset-session.d.ts +10 -0
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +3 -1
- package/dist/hooks/guardrails/index.d.ts +3 -1
- package/dist/hooks/system-enhancer.d.ts +4 -0
- package/dist/index.js +331 -295
- package/dist/plan/manager.d.ts +15 -1
- package/dist/tools/update-task-status.d.ts +1 -0
- package/dist/utils/spec-hash.d.ts +36 -0
- package/package.json +1 -1
|
@@ -117,7 +117,7 @@ import {
|
|
|
117
117
|
validateProjectRoot,
|
|
118
118
|
validateSpeckit,
|
|
119
119
|
writeProjectedSpecSync
|
|
120
|
-
} from "./index-
|
|
120
|
+
} from "./index-25pev4e7.js";
|
|
121
121
|
import {
|
|
122
122
|
_internals as _internals2,
|
|
123
123
|
_internals1 as _internals3,
|
|
@@ -316,7 +316,7 @@ var init_bubblewrap = __esm(() => {
|
|
|
316
316
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
317
317
|
import { mkdtempSync, writeFileSync } from "fs";
|
|
318
318
|
import * as os5 from "os";
|
|
319
|
-
import * as
|
|
319
|
+
import * as path11 from "path";
|
|
320
320
|
function probeSandboxExec() {
|
|
321
321
|
try {
|
|
322
322
|
const result = spawnSync2("sandbox-exec", ["--version"], {
|
|
@@ -344,8 +344,8 @@ function probeSandboxExec() {
|
|
|
344
344
|
function shellEscape2(s) {
|
|
345
345
|
return s.replace(/'/g, "'\\''");
|
|
346
346
|
}
|
|
347
|
-
function sbplEscapePath(
|
|
348
|
-
const withoutControlChars =
|
|
347
|
+
function sbplEscapePath(path12) {
|
|
348
|
+
const withoutControlChars = path12.split("").filter((ch) => {
|
|
349
349
|
const cp = ch.codePointAt(0);
|
|
350
350
|
return cp >= 32 && cp !== 127;
|
|
351
351
|
}).join("");
|
|
@@ -421,8 +421,8 @@ class MacOSSandboxExecutor {
|
|
|
421
421
|
const profile = buildSandboxProfile(allScopes, temp);
|
|
422
422
|
let profilePath;
|
|
423
423
|
try {
|
|
424
|
-
const profileDir = mkdtempSync(
|
|
425
|
-
profilePath =
|
|
424
|
+
const profileDir = mkdtempSync(path11.join(os5.tmpdir(), "sandbox-"));
|
|
425
|
+
profilePath = path11.join(profileDir, `profile-${process.pid}-${Date.now()}.sb`);
|
|
426
426
|
writeFileSync(profilePath, profile, { mode: 384 });
|
|
427
427
|
} catch (err) {
|
|
428
428
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -529,7 +529,7 @@ var init_edge_cases = () => {};
|
|
|
529
529
|
// src/sandbox/win32/restricted-environment-executor.ts
|
|
530
530
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
531
531
|
import * as os6 from "os";
|
|
532
|
-
import * as
|
|
532
|
+
import * as path12 from "path";
|
|
533
533
|
function probeWindowsSandbox() {
|
|
534
534
|
try {
|
|
535
535
|
const result = spawnSync3("cmd", ["/c", "echo", "ok"], {
|
|
@@ -576,7 +576,7 @@ function isPathInScopes(command, scopes) {
|
|
|
576
576
|
const paths = command.match(pathPattern) || [];
|
|
577
577
|
if (paths.length === 0)
|
|
578
578
|
return true;
|
|
579
|
-
const normalizedPaths = paths.map((p) =>
|
|
579
|
+
const normalizedPaths = paths.map((p) => path12.win32.resolve(p));
|
|
580
580
|
const normalizedScopes = scopes.map((s) => s.toLowerCase().replace(/\\+$/, ""));
|
|
581
581
|
return normalizedPaths.every((p) => {
|
|
582
582
|
const lower = p.toLowerCase();
|
|
@@ -713,7 +713,7 @@ var init_restricted_environment_executor = __esm(() => {
|
|
|
713
713
|
import * as crypto2 from "crypto";
|
|
714
714
|
import * as fs3 from "fs";
|
|
715
715
|
import * as os7 from "os";
|
|
716
|
-
import * as
|
|
716
|
+
import * as path13 from "path";
|
|
717
717
|
|
|
718
718
|
class NativeWindowsSandboxExecutor {
|
|
719
719
|
mechanism;
|
|
@@ -775,11 +775,11 @@ class NativeWindowsSandboxExecutor {
|
|
|
775
775
|
policy.workspace_roots = scopePaths.length > 0 ? scopePaths : [workspaceRoot];
|
|
776
776
|
policy.writable_roots = policy.workspace_roots;
|
|
777
777
|
const policyJson = JSON.stringify(policy);
|
|
778
|
-
const policyDir =
|
|
778
|
+
const policyDir = path13.join(os7.tmpdir(), "swarm-sandbox-policies");
|
|
779
779
|
try {
|
|
780
780
|
fs3.mkdirSync(policyDir, { recursive: true });
|
|
781
781
|
} catch {}
|
|
782
|
-
const policyFile =
|
|
782
|
+
const policyFile = path13.join(policyDir, `${runId}.json`);
|
|
783
783
|
fs3.writeFileSync(policyFile, policyJson, "utf-8");
|
|
784
784
|
const mode = this._probeResult.mode === "none" ? "auto" : this._probeResult.mode;
|
|
785
785
|
const escapedBinary = binary.includes(" ") ? `"${binary}"` : binary;
|
|
@@ -912,7 +912,7 @@ var init_executor = __esm(() => {
|
|
|
912
912
|
// package.json
|
|
913
913
|
var package_default = {
|
|
914
914
|
name: "opencode-swarm",
|
|
915
|
-
version: "7.
|
|
915
|
+
version: "7.107.0",
|
|
916
916
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
917
917
|
main: "dist/index.js",
|
|
918
918
|
types: "dist/index.d.ts",
|
|
@@ -1020,6 +1020,7 @@ var package_default = {
|
|
|
1020
1020
|
|
|
1021
1021
|
// src/commands/acknowledge-spec-drift.ts
|
|
1022
1022
|
import { promises as fsPromises } from "fs";
|
|
1023
|
+
import * as path from "path";
|
|
1023
1024
|
async function handleAcknowledgeSpecDriftCommand(directory, _args, acknowledgedBy = "unknown") {
|
|
1024
1025
|
const specStalenessPath = validateSwarmPath(directory, "spec-staleness.json");
|
|
1025
1026
|
let stalenessContent;
|
|
@@ -1053,6 +1054,13 @@ Please re-run the relevant phase to detect current drift status.`;
|
|
|
1053
1054
|
currentHash = await computeSpecHash(directory);
|
|
1054
1055
|
plan.specHash = currentHash ?? undefined;
|
|
1055
1056
|
await savePlan(directory, plan);
|
|
1057
|
+
try {
|
|
1058
|
+
const currentSpec = readEffectiveSpecSync(directory);
|
|
1059
|
+
if (currentSpec) {
|
|
1060
|
+
const snapshotPath = path.join(directory, ".swarm", "spec-snapshot.md");
|
|
1061
|
+
await fsPromises.writeFile(snapshotPath, currentSpec.content, "utf-8");
|
|
1062
|
+
}
|
|
1063
|
+
} catch {}
|
|
1056
1064
|
}
|
|
1057
1065
|
} catch (planError) {
|
|
1058
1066
|
console.error("[acknowledge-spec-drift] Failed to update plan specHash:", planError instanceof Error ? planError.message : String(planError));
|
|
@@ -1169,11 +1177,11 @@ async function handleAnalyzeCommand(_directory, args) {
|
|
|
1169
1177
|
// src/config/loader.ts
|
|
1170
1178
|
import * as fs from "fs";
|
|
1171
1179
|
import * as os from "os";
|
|
1172
|
-
import * as
|
|
1180
|
+
import * as path2 from "path";
|
|
1173
1181
|
var CONFIG_FILENAME = "opencode-swarm.json";
|
|
1174
1182
|
var MAX_CONFIG_FILE_BYTES = 102400;
|
|
1175
1183
|
function getUserConfigDir() {
|
|
1176
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
1184
|
+
return process.env.XDG_CONFIG_HOME || path2.join(os.homedir(), ".config");
|
|
1177
1185
|
}
|
|
1178
1186
|
function loadRawConfigFromPath(configPath) {
|
|
1179
1187
|
try {
|
|
@@ -1259,8 +1267,8 @@ function rawFullAutoLocked(raw) {
|
|
|
1259
1267
|
return fullAuto.locked === true;
|
|
1260
1268
|
}
|
|
1261
1269
|
function loadPluginConfig(directory) {
|
|
1262
|
-
const userConfigPath =
|
|
1263
|
-
const projectConfigPath =
|
|
1270
|
+
const userConfigPath = path2.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
1271
|
+
const projectConfigPath = path2.join(directory, ".opencode", CONFIG_FILENAME);
|
|
1264
1272
|
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
1265
1273
|
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
1266
1274
|
const rawUserConfig = userResult.config;
|
|
@@ -1305,8 +1313,8 @@ function loadPluginConfig(directory) {
|
|
|
1305
1313
|
return result.data;
|
|
1306
1314
|
}
|
|
1307
1315
|
function loadPluginConfigWithMeta(directory) {
|
|
1308
|
-
const userConfigPath =
|
|
1309
|
-
const projectConfigPath =
|
|
1316
|
+
const userConfigPath = path2.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
1317
|
+
const projectConfigPath = path2.join(directory, ".opencode", CONFIG_FILENAME);
|
|
1310
1318
|
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
1311
1319
|
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
1312
1320
|
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
@@ -1394,7 +1402,7 @@ async function handleArchiveCommand(directory, args) {
|
|
|
1394
1402
|
// src/config/bundled-skills.ts
|
|
1395
1403
|
import * as fs2 from "fs";
|
|
1396
1404
|
import * as fsp from "fs/promises";
|
|
1397
|
-
import * as
|
|
1405
|
+
import * as path3 from "path";
|
|
1398
1406
|
var BUNDLED_PROJECT_SKILLS = [
|
|
1399
1407
|
"brainstorm",
|
|
1400
1408
|
"specify",
|
|
@@ -1427,7 +1435,7 @@ var MAX_SKILL_FILES = 64;
|
|
|
1427
1435
|
var MAX_SKILL_BYTES = 512000;
|
|
1428
1436
|
var syncedProjectSkillTargets = new Set;
|
|
1429
1437
|
function getSyncCacheKey(projectDirectory, packageRoot) {
|
|
1430
|
-
return `${
|
|
1438
|
+
return `${path3.resolve(projectDirectory)}\x00${path3.resolve(packageRoot)}`;
|
|
1431
1439
|
}
|
|
1432
1440
|
function warnBundledSkillSyncFailure(err) {
|
|
1433
1441
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -1457,12 +1465,12 @@ async function pathExistsAsync(p) {
|
|
|
1457
1465
|
}
|
|
1458
1466
|
}
|
|
1459
1467
|
async function collectBundledSkillFilesBoundedAsync(sourceDir, state, relativeDir = "") {
|
|
1460
|
-
const currentSource =
|
|
1468
|
+
const currentSource = path3.join(sourceDir, relativeDir);
|
|
1461
1469
|
const entries = await fsp.readdir(currentSource, { withFileTypes: true });
|
|
1462
1470
|
const files = [];
|
|
1463
1471
|
for (const entry of entries) {
|
|
1464
|
-
const relativeEntry =
|
|
1465
|
-
const sourcePath =
|
|
1472
|
+
const relativeEntry = path3.join(relativeDir, entry.name);
|
|
1473
|
+
const sourcePath = path3.join(sourceDir, relativeEntry);
|
|
1466
1474
|
if (entry.isSymbolicLink() || await isSymbolicLinkAsync(sourcePath))
|
|
1467
1475
|
continue;
|
|
1468
1476
|
if (entry.isDirectory()) {
|
|
@@ -1484,21 +1492,21 @@ async function collectBundledSkillFilesBoundedAsync(sourceDir, state, relativeDi
|
|
|
1484
1492
|
return files;
|
|
1485
1493
|
}
|
|
1486
1494
|
async function rollbackCopiedFilesAsync(copiedFiles, destDir) {
|
|
1487
|
-
const safeDestDir =
|
|
1495
|
+
const safeDestDir = path3.resolve(destDir);
|
|
1488
1496
|
const dirs = new Set;
|
|
1489
1497
|
for (const copiedFile of copiedFiles) {
|
|
1490
|
-
const resolvedFile =
|
|
1491
|
-
const relative2 =
|
|
1492
|
-
if (relative2.startsWith("..") ||
|
|
1498
|
+
const resolvedFile = path3.resolve(copiedFile);
|
|
1499
|
+
const relative2 = path3.relative(safeDestDir, resolvedFile);
|
|
1500
|
+
if (relative2.startsWith("..") || path3.isAbsolute(relative2))
|
|
1493
1501
|
continue;
|
|
1494
1502
|
try {
|
|
1495
1503
|
await fsp.rm(resolvedFile, { force: true });
|
|
1496
1504
|
} catch {}
|
|
1497
|
-
dirs.add(
|
|
1505
|
+
dirs.add(path3.dirname(resolvedFile));
|
|
1498
1506
|
}
|
|
1499
1507
|
for (const dir of [...dirs].sort((a, b) => b.length - a.length)) {
|
|
1500
|
-
const relative2 =
|
|
1501
|
-
if (relative2.startsWith("..") ||
|
|
1508
|
+
const relative2 = path3.relative(safeDestDir, path3.resolve(dir));
|
|
1509
|
+
if (relative2.startsWith("..") || path3.isAbsolute(relative2))
|
|
1502
1510
|
continue;
|
|
1503
1511
|
try {
|
|
1504
1512
|
await fsp.rmdir(dir);
|
|
@@ -1513,9 +1521,9 @@ async function copyBundledDirectoryBoundedAsync(sourceDir, destDir) {
|
|
|
1513
1521
|
const copiedFiles = [];
|
|
1514
1522
|
try {
|
|
1515
1523
|
for (const file of files) {
|
|
1516
|
-
const sourcePath =
|
|
1517
|
-
const destPath =
|
|
1518
|
-
await fsp.mkdir(
|
|
1524
|
+
const sourcePath = path3.join(sourceDir, file.relativePath);
|
|
1525
|
+
const destPath = path3.join(destDir, file.relativePath);
|
|
1526
|
+
await fsp.mkdir(path3.dirname(destPath), { recursive: true });
|
|
1519
1527
|
try {
|
|
1520
1528
|
await fsp.copyFile(sourcePath, destPath, fs2.constants.COPYFILE_EXCL);
|
|
1521
1529
|
copiedFiles.push(destPath);
|
|
@@ -1534,19 +1542,19 @@ async function syncBundledProjectSkillsIfMissingAsync(projectDirectory, packageR
|
|
|
1534
1542
|
const cacheKey = getSyncCacheKey(projectDirectory, packageRoot);
|
|
1535
1543
|
if (syncedProjectSkillTargets.has(cacheKey))
|
|
1536
1544
|
return;
|
|
1537
|
-
const sourceRoot =
|
|
1538
|
-
const opencodeDir =
|
|
1539
|
-
const skillsDir =
|
|
1545
|
+
const sourceRoot = path3.join(packageRoot, ".opencode", "skills");
|
|
1546
|
+
const opencodeDir = path3.join(projectDirectory, ".opencode");
|
|
1547
|
+
const skillsDir = path3.join(opencodeDir, "skills");
|
|
1540
1548
|
let sawBundledSource = false;
|
|
1541
1549
|
if (!await ensureNotSymlinkedDirectoryAsync(opencodeDir))
|
|
1542
1550
|
return;
|
|
1543
1551
|
if (!await ensureNotSymlinkedDirectoryAsync(skillsDir))
|
|
1544
1552
|
return;
|
|
1545
1553
|
for (const slug of BUNDLED_PROJECT_SKILLS) {
|
|
1546
|
-
const sourceDir =
|
|
1547
|
-
const sourceSkill =
|
|
1548
|
-
const destDir =
|
|
1549
|
-
const destSkill =
|
|
1554
|
+
const sourceDir = path3.join(sourceRoot, slug);
|
|
1555
|
+
const sourceSkill = path3.join(sourceDir, "SKILL.md");
|
|
1556
|
+
const destDir = path3.join(skillsDir, slug);
|
|
1557
|
+
const destSkill = path3.join(destDir, "SKILL.md");
|
|
1550
1558
|
if (!await pathExistsAsync(sourceSkill))
|
|
1551
1559
|
continue;
|
|
1552
1560
|
sawBundledSource = true;
|
|
@@ -1572,7 +1580,7 @@ init_logger();
|
|
|
1572
1580
|
|
|
1573
1581
|
// src/state.ts
|
|
1574
1582
|
import * as fs6 from "fs/promises";
|
|
1575
|
-
import * as
|
|
1583
|
+
import * as path18 from "path";
|
|
1576
1584
|
|
|
1577
1585
|
// src/db/qa-gate-profile.ts
|
|
1578
1586
|
import { createHash } from "crypto";
|
|
@@ -1580,7 +1588,7 @@ import { createHash } from "crypto";
|
|
|
1580
1588
|
// src/db/project-db.ts
|
|
1581
1589
|
import { existsSync as existsSync2, mkdirSync } from "fs";
|
|
1582
1590
|
import { createRequire } from "module";
|
|
1583
|
-
import { join as
|
|
1591
|
+
import { join as join4, resolve as resolve2 } from "path";
|
|
1584
1592
|
var _DatabaseCtor = null;
|
|
1585
1593
|
function loadDatabaseCtor() {
|
|
1586
1594
|
if (_DatabaseCtor)
|
|
@@ -1647,7 +1655,7 @@ function runProjectMigrations(db) {
|
|
|
1647
1655
|
}
|
|
1648
1656
|
}
|
|
1649
1657
|
function projectDbPath(directory) {
|
|
1650
|
-
return
|
|
1658
|
+
return join4(resolve2(directory), ".swarm", "swarm.db");
|
|
1651
1659
|
}
|
|
1652
1660
|
function projectDbExists(directory) {
|
|
1653
1661
|
return existsSync2(projectDbPath(directory));
|
|
@@ -1657,10 +1665,10 @@ function getProjectDb(directory) {
|
|
|
1657
1665
|
const existing = _projectDbs.get(key);
|
|
1658
1666
|
if (existing)
|
|
1659
1667
|
return existing;
|
|
1660
|
-
const swarmDir =
|
|
1668
|
+
const swarmDir = join4(key, ".swarm");
|
|
1661
1669
|
mkdirSync(swarmDir, { recursive: true });
|
|
1662
1670
|
const Db = loadDatabaseCtor();
|
|
1663
|
-
const db = new Db(
|
|
1671
|
+
const db = new Db(join4(swarmDir, "swarm.db"));
|
|
1664
1672
|
db.run("PRAGMA journal_mode = WAL;");
|
|
1665
1673
|
db.run("PRAGMA synchronous = NORMAL;");
|
|
1666
1674
|
db.run("PRAGMA busy_timeout = 5000;");
|
|
@@ -1863,6 +1871,76 @@ var _internals6 = {
|
|
|
1863
1871
|
platform: process.platform,
|
|
1864
1872
|
sleep: (ms) => new Promise((resolve3) => setTimeout(resolve3, ms))
|
|
1865
1873
|
};
|
|
1874
|
+
var MERGE_TIMEOUT_MS = 30000;
|
|
1875
|
+
async function runGit2(args, cwd, timeoutMs = MERGE_TIMEOUT_MS) {
|
|
1876
|
+
const proc = _internals6.bunSpawn(["git", ...args], {
|
|
1877
|
+
cwd,
|
|
1878
|
+
timeout: timeoutMs,
|
|
1879
|
+
stdin: "ignore",
|
|
1880
|
+
stdout: "pipe",
|
|
1881
|
+
stderr: "pipe",
|
|
1882
|
+
env: { ...process.env, LC_ALL: "C" }
|
|
1883
|
+
});
|
|
1884
|
+
try {
|
|
1885
|
+
const exitCode = await proc.exited;
|
|
1886
|
+
const stdout = await proc.stdout.text();
|
|
1887
|
+
const stderr = await proc.stderr.text();
|
|
1888
|
+
return { exitCode, stdout, stderr };
|
|
1889
|
+
} finally {
|
|
1890
|
+
try {
|
|
1891
|
+
proc.kill();
|
|
1892
|
+
} catch {}
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
function extractSessionId(branchName) {
|
|
1896
|
+
const segments = branchName.trim().split("/");
|
|
1897
|
+
if (segments.length >= 3 && segments[0] === "swarm-lane") {
|
|
1898
|
+
return segments[1];
|
|
1899
|
+
}
|
|
1900
|
+
if (segments.length >= 4 && segments[0] === "swarm" && segments[1] === "lane") {
|
|
1901
|
+
return segments[2];
|
|
1902
|
+
}
|
|
1903
|
+
return null;
|
|
1904
|
+
}
|
|
1905
|
+
async function listLaneBranches(directory) {
|
|
1906
|
+
const branches = new Set;
|
|
1907
|
+
for (const pattern of ["swarm-lane/*", "swarm/lane/*"]) {
|
|
1908
|
+
const result = await runGit2(["branch", "--format=%(refname:short)", "--list", pattern], directory);
|
|
1909
|
+
if (result.exitCode !== 0)
|
|
1910
|
+
continue;
|
|
1911
|
+
for (const line of result.stdout.split(`
|
|
1912
|
+
`)) {
|
|
1913
|
+
const branch = line.trim();
|
|
1914
|
+
if (branch.length > 0)
|
|
1915
|
+
branches.add(branch);
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
return [...branches];
|
|
1919
|
+
}
|
|
1920
|
+
async function cleanupOrphanedBranches(directory, activeSessionIds = []) {
|
|
1921
|
+
const removed = [];
|
|
1922
|
+
const skipped = [];
|
|
1923
|
+
const errors = [];
|
|
1924
|
+
const branches = await listLaneBranches(directory);
|
|
1925
|
+
for (const branch of branches) {
|
|
1926
|
+
const sessionId = extractSessionId(branch);
|
|
1927
|
+
if (sessionId !== null && activeSessionIds.includes(sessionId)) {
|
|
1928
|
+
skipped.push(branch);
|
|
1929
|
+
continue;
|
|
1930
|
+
}
|
|
1931
|
+
const deleteResult = await runGit2(["branch", "-D", branch], directory);
|
|
1932
|
+
if (deleteResult.exitCode === 0) {
|
|
1933
|
+
removed.push(branch);
|
|
1934
|
+
} else {
|
|
1935
|
+
errors.push({
|
|
1936
|
+
branch,
|
|
1937
|
+
error: deleteResult.stderr.trim() || deleteResult.stdout.trim()
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
await runGit2(["worktree", "prune"], directory);
|
|
1942
|
+
return { removed, skipped, errors };
|
|
1943
|
+
}
|
|
1866
1944
|
// src/hooks/delegation-gate/worktree-isolation.ts
|
|
1867
1945
|
var standardWorktreeByCallID = new Map;
|
|
1868
1946
|
var standardWorktreeSerializationSessions = new Set;
|
|
@@ -2092,7 +2170,7 @@ import {
|
|
|
2092
2170
|
rename,
|
|
2093
2171
|
writeFile
|
|
2094
2172
|
} from "fs/promises";
|
|
2095
|
-
import * as
|
|
2173
|
+
import * as path4 from "path";
|
|
2096
2174
|
|
|
2097
2175
|
// src/memory/schema.ts
|
|
2098
2176
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -3056,7 +3134,7 @@ class LocalJsonlMemoryProvider {
|
|
|
3056
3134
|
pathFor(file) {
|
|
3057
3135
|
const storageDir = this.config.storageDir.replace(/^\.swarm[/\\]?/, "");
|
|
3058
3136
|
const filename = file === "memories" ? "memories.jsonl" : file === "proposals" ? "proposals.jsonl" : file === "audit" ? "audit.jsonl" : "reward-events.jsonl";
|
|
3059
|
-
return validateSwarmPath(this.rootDirectory,
|
|
3137
|
+
return validateSwarmPath(this.rootDirectory, path4.join(storageDir, filename));
|
|
3060
3138
|
}
|
|
3061
3139
|
async initialize() {
|
|
3062
3140
|
if (this.initialized)
|
|
@@ -3488,12 +3566,12 @@ function parseRewardEvent(value) {
|
|
|
3488
3566
|
};
|
|
3489
3567
|
}
|
|
3490
3568
|
async function appendJsonl(filePath, value) {
|
|
3491
|
-
await mkdir2(
|
|
3569
|
+
await mkdir2(path4.dirname(filePath), { recursive: true });
|
|
3492
3570
|
await appendFile(filePath, `${JSON.stringify(value)}
|
|
3493
3571
|
`, "utf-8");
|
|
3494
3572
|
}
|
|
3495
3573
|
async function writeJsonlAtomic(filePath, values) {
|
|
3496
|
-
await mkdir2(
|
|
3574
|
+
await mkdir2(path4.dirname(filePath), { recursive: true });
|
|
3497
3575
|
const tmp = `${filePath}.tmp.${randomUUID()}`;
|
|
3498
3576
|
const content = values.map((value) => JSON.stringify(value)).join(`
|
|
3499
3577
|
`) + (values.length > 0 ? `
|
|
@@ -3504,13 +3582,13 @@ async function writeJsonlAtomic(filePath, values) {
|
|
|
3504
3582
|
|
|
3505
3583
|
// src/memory/provider-pool.ts
|
|
3506
3584
|
import { realpathSync } from "fs";
|
|
3507
|
-
import * as
|
|
3585
|
+
import * as path9 from "path";
|
|
3508
3586
|
|
|
3509
3587
|
// src/memory/sqlite-provider.ts
|
|
3510
3588
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3511
3589
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
3512
3590
|
import { createRequire as createRequire4 } from "module";
|
|
3513
|
-
import * as
|
|
3591
|
+
import * as path8 from "path";
|
|
3514
3592
|
|
|
3515
3593
|
// src/memory/embeddings/cache.ts
|
|
3516
3594
|
var DEFAULT_CACHE_SIZE = 256;
|
|
@@ -3629,7 +3707,7 @@ function minMaxNormalise(candidates) {
|
|
|
3629
3707
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
3630
3708
|
import { createRequire as createRequire2 } from "module";
|
|
3631
3709
|
import * as os3 from "os";
|
|
3632
|
-
import * as
|
|
3710
|
+
import * as path5 from "path";
|
|
3633
3711
|
|
|
3634
3712
|
// src/memory/embeddings/types.ts
|
|
3635
3713
|
class EmbeddingUnavailableError extends Error {
|
|
@@ -3655,16 +3733,16 @@ var _internals7 = {
|
|
|
3655
3733
|
resolveEmbeddingCacheDir() {
|
|
3656
3734
|
let base;
|
|
3657
3735
|
if (process.platform === "win32") {
|
|
3658
|
-
base = process.env.LOCALAPPDATA ||
|
|
3736
|
+
base = process.env.LOCALAPPDATA || path5.join(os3.homedir(), "AppData", "Local");
|
|
3659
3737
|
} else if (process.platform === "darwin") {
|
|
3660
|
-
base =
|
|
3738
|
+
base = path5.join(os3.homedir(), "Library", "Caches");
|
|
3661
3739
|
} else {
|
|
3662
|
-
base = process.env.XDG_CACHE_HOME ||
|
|
3740
|
+
base = process.env.XDG_CACHE_HOME || path5.join(os3.homedir(), ".cache");
|
|
3663
3741
|
}
|
|
3664
|
-
const resolved =
|
|
3665
|
-
const segments = resolved.split(
|
|
3742
|
+
const resolved = path5.join(base, "opencode", "embeddings");
|
|
3743
|
+
const segments = resolved.split(path5.sep);
|
|
3666
3744
|
if (segments.includes(".swarm")) {
|
|
3667
|
-
const safeDefault = process.platform === "win32" ?
|
|
3745
|
+
const safeDefault = process.platform === "win32" ? path5.join(os3.homedir(), "AppData", "Local", "opencode", "embeddings") : process.platform === "darwin" ? path5.join(os3.homedir(), "Library", "Caches", "opencode", "embeddings") : path5.join(os3.homedir(), ".cache", "opencode", "embeddings");
|
|
3668
3746
|
warn("Embedding cache dir resolved under .swarm/ \u2014 falling back to safe default");
|
|
3669
3747
|
return safeDefault;
|
|
3670
3748
|
}
|
|
@@ -3782,7 +3860,7 @@ class LocalEmbeddingProvider {
|
|
|
3782
3860
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
3783
3861
|
import { createRequire as createRequire3 } from "module";
|
|
3784
3862
|
import * as os4 from "os";
|
|
3785
|
-
import * as
|
|
3863
|
+
import * as path6 from "path";
|
|
3786
3864
|
function shouldRerank(previousRecallElapsedMs, latencyBudgetMs) {
|
|
3787
3865
|
return previousRecallElapsedMs <= latencyBudgetMs;
|
|
3788
3866
|
}
|
|
@@ -3850,16 +3928,16 @@ class CrossEncoderReranker {
|
|
|
3850
3928
|
function resolveRerankerCacheDir() {
|
|
3851
3929
|
let base;
|
|
3852
3930
|
if (process.platform === "win32") {
|
|
3853
|
-
base = process.env.LOCALAPPDATA ||
|
|
3931
|
+
base = process.env.LOCALAPPDATA || path6.join(os4.homedir(), "AppData", "Local");
|
|
3854
3932
|
} else if (process.platform === "darwin") {
|
|
3855
|
-
base =
|
|
3933
|
+
base = path6.join(os4.homedir(), "Library", "Caches");
|
|
3856
3934
|
} else {
|
|
3857
|
-
base = process.env.XDG_CACHE_HOME ||
|
|
3935
|
+
base = process.env.XDG_CACHE_HOME || path6.join(os4.homedir(), ".cache");
|
|
3858
3936
|
}
|
|
3859
|
-
const resolved =
|
|
3860
|
-
const segments = resolved.split(
|
|
3937
|
+
const resolved = path6.join(base, "opencode", "embeddings");
|
|
3938
|
+
const segments = resolved.split(path6.sep);
|
|
3861
3939
|
if (segments.includes(".swarm")) {
|
|
3862
|
-
const safeDefault = process.platform === "win32" ?
|
|
3940
|
+
const safeDefault = process.platform === "win32" ? path6.join(os4.homedir(), "AppData", "Local", "opencode", "embeddings") : process.platform === "darwin" ? path6.join(os4.homedir(), "Library", "Caches", "opencode", "embeddings") : path6.join(os4.homedir(), ".cache", "opencode", "embeddings");
|
|
3863
3941
|
warn("Reranker cache dir resolved under .swarm/ \u2014 falling back to safe default");
|
|
3864
3942
|
return safeDefault;
|
|
3865
3943
|
}
|
|
@@ -3869,7 +3947,7 @@ function resolveRerankerCacheDir() {
|
|
|
3869
3947
|
// src/memory/jsonl-migration.ts
|
|
3870
3948
|
import { existsSync as existsSync4, renameSync, unlinkSync } from "fs";
|
|
3871
3949
|
import { copyFile as copyFile2, mkdir as mkdir3, readFile as readFile2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
3872
|
-
import * as
|
|
3950
|
+
import * as path7 from "path";
|
|
3873
3951
|
var LEGACY_JSONL_MIGRATION_VERSION = 2;
|
|
3874
3952
|
var LEGACY_JSONL_MIGRATION_NAME = "legacy_jsonl_import_complete";
|
|
3875
3953
|
function resolveMemoryStorageDir(rootDirectory, config = {}) {
|
|
@@ -3885,8 +3963,8 @@ function resolveSqliteDatabasePath(rootDirectory, config = {}) {
|
|
|
3885
3963
|
async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
3886
3964
|
const resolved = resolveConfig(config);
|
|
3887
3965
|
const storageDir = resolveMemoryStorageDir(rootDirectory, resolved);
|
|
3888
|
-
const memoryLoad = await readMemoryJsonl(
|
|
3889
|
-
const proposalLoad = await readProposalJsonl(
|
|
3966
|
+
const memoryLoad = await readMemoryJsonl(path7.join(storageDir, "memories.jsonl"), resolved);
|
|
3967
|
+
const proposalLoad = await readProposalJsonl(path7.join(storageDir, "proposals.jsonl"), resolved);
|
|
3890
3968
|
return {
|
|
3891
3969
|
memories: memoryLoad.records,
|
|
3892
3970
|
proposals: proposalLoad.records,
|
|
@@ -3896,14 +3974,14 @@ async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
|
3896
3974
|
}
|
|
3897
3975
|
async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
3898
3976
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
3899
|
-
const backupDir =
|
|
3977
|
+
const backupDir = path7.join(storageDir, "backups");
|
|
3900
3978
|
await mkdir3(backupDir, { recursive: true });
|
|
3901
3979
|
const results = [];
|
|
3902
3980
|
for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
|
|
3903
|
-
const source =
|
|
3981
|
+
const source = path7.join(storageDir, filename);
|
|
3904
3982
|
if (!existsSync4(source))
|
|
3905
3983
|
continue;
|
|
3906
|
-
const backup =
|
|
3984
|
+
const backup = path7.join(backupDir, `${filename}.pre-sqlite-migration`);
|
|
3907
3985
|
if (existsSync4(backup)) {
|
|
3908
3986
|
results.push({ source, backup, created: false });
|
|
3909
3987
|
continue;
|
|
@@ -3914,11 +3992,11 @@ async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
|
3914
3992
|
return results;
|
|
3915
3993
|
}
|
|
3916
3994
|
async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
3917
|
-
const exportDir =
|
|
3995
|
+
const exportDir = path7.join(resolveMemoryStorageDir(rootDirectory, config), "export");
|
|
3918
3996
|
await mkdir3(exportDir, { recursive: true });
|
|
3919
|
-
const memoriesPath =
|
|
3920
|
-
const proposalsPath =
|
|
3921
|
-
const memoriesTempPath =
|
|
3997
|
+
const memoriesPath = path7.join(exportDir, "memories.jsonl");
|
|
3998
|
+
const proposalsPath = path7.join(exportDir, "proposals.jsonl");
|
|
3999
|
+
const memoriesTempPath = path7.join(path7.dirname(memoriesPath), `${path7.basename(memoriesPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3922
4000
|
try {
|
|
3923
4001
|
await writeFile2(memoriesTempPath, toJsonl(memories), "utf-8");
|
|
3924
4002
|
renameSync(memoriesTempPath, memoriesPath);
|
|
@@ -3928,7 +4006,7 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
3928
4006
|
} catch {}
|
|
3929
4007
|
throw err;
|
|
3930
4008
|
}
|
|
3931
|
-
const proposalsTempPath =
|
|
4009
|
+
const proposalsTempPath = path7.join(path7.dirname(proposalsPath), `${path7.basename(proposalsPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3932
4010
|
try {
|
|
3933
4011
|
await writeFile2(proposalsTempPath, toJsonl(proposals), "utf-8");
|
|
3934
4012
|
renameSync(proposalsTempPath, proposalsPath);
|
|
@@ -3941,9 +4019,9 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
3941
4019
|
return { directory: exportDir, memoriesPath, proposalsPath };
|
|
3942
4020
|
}
|
|
3943
4021
|
async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
3944
|
-
const reportPath =
|
|
3945
|
-
await mkdir3(
|
|
3946
|
-
const reportTempPath =
|
|
4022
|
+
const reportPath = path7.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
4023
|
+
await mkdir3(path7.dirname(reportPath), { recursive: true });
|
|
4024
|
+
const reportTempPath = path7.join(path7.dirname(reportPath), `${path7.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
3947
4025
|
try {
|
|
3948
4026
|
await writeFile2(reportTempPath, `${JSON.stringify(report, null, 2)}
|
|
3949
4027
|
`, "utf-8");
|
|
@@ -3957,7 +4035,7 @@ async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
|
3957
4035
|
return reportPath;
|
|
3958
4036
|
}
|
|
3959
4037
|
async function readMigrationReport(rootDirectory, config = {}) {
|
|
3960
|
-
const reportPath =
|
|
4038
|
+
const reportPath = path7.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
3961
4039
|
if (!existsSync4(reportPath))
|
|
3962
4040
|
return null;
|
|
3963
4041
|
try {
|
|
@@ -3970,7 +4048,7 @@ async function getLegacyJsonlFileStatus(rootDirectory, config = {}) {
|
|
|
3970
4048
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
3971
4049
|
const statuses = [];
|
|
3972
4050
|
for (const file of ["memories.jsonl", "proposals.jsonl"]) {
|
|
3973
|
-
const filePath =
|
|
4051
|
+
const filePath = path7.join(storageDir, file);
|
|
3974
4052
|
let sizeBytes = 0;
|
|
3975
4053
|
if (existsSync4(filePath)) {
|
|
3976
4054
|
sizeBytes = (await stat2(filePath)).size;
|
|
@@ -4341,7 +4419,7 @@ class SQLiteMemoryProvider {
|
|
|
4341
4419
|
}
|
|
4342
4420
|
async doInitialize() {
|
|
4343
4421
|
const dbPath = this.databasePath();
|
|
4344
|
-
mkdirSync4(
|
|
4422
|
+
mkdirSync4(path8.dirname(dbPath), { recursive: true });
|
|
4345
4423
|
const Db = loadDatabaseCtor2();
|
|
4346
4424
|
this.db = new Db(dbPath);
|
|
4347
4425
|
this.db.run("PRAGMA journal_mode = WAL;");
|
|
@@ -5133,9 +5211,9 @@ class SQLiteMemoryProvider {
|
|
|
5133
5211
|
try {
|
|
5134
5212
|
const dimension = Math.max(1, Math.trunc(this.config.embeddings.dimension ?? 384));
|
|
5135
5213
|
const req = createRequire4(import.meta.url);
|
|
5136
|
-
const pkgDir =
|
|
5214
|
+
const pkgDir = path8.dirname(req.resolve("@sqlite/sqlite-vec/package.json"));
|
|
5137
5215
|
const ext = process.platform === "win32" ? ".dll" : process.platform === "darwin" ? ".dylib" : ".so";
|
|
5138
|
-
const vec0Path =
|
|
5216
|
+
const vec0Path = path8.join(pkgDir, `vec0${ext}`);
|
|
5139
5217
|
db.loadExtension(vec0Path);
|
|
5140
5218
|
db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_items_vec USING vec0(
|
|
5141
5219
|
id TEXT PRIMARY KEY, embedding FLOAT[${dimension}]
|
|
@@ -5808,7 +5886,7 @@ function resolvePoolKey(directory) {
|
|
|
5808
5886
|
try {
|
|
5809
5887
|
return realpathSync(directory);
|
|
5810
5888
|
} catch {
|
|
5811
|
-
return
|
|
5889
|
+
return path9.resolve(directory);
|
|
5812
5890
|
}
|
|
5813
5891
|
}
|
|
5814
5892
|
function evictAndClose(directory) {
|
|
@@ -6259,6 +6337,24 @@ Before reviewing the plan, check whether it was silently mutated since last crit
|
|
|
6259
6337
|
- If \`drift_detected: "unknown"\`: flag as warning and proceed with caution.
|
|
6260
6338
|
3. Report spec-intent divergence: compare the approved baseline intent against what the current plan actually does, not just structural diff. Identify if the plan's purpose or scope has drifted from the original approved intent.
|
|
6261
6339
|
|
|
6340
|
+
## OBLIGATION TRACEABILITY CHECK (mandatory before plan review)
|
|
6341
|
+
|
|
6342
|
+
Before scoring the plan against the quality rubric, verify that every MUST/SHALL
|
|
6343
|
+
SC-### obligation in .swarm/spec.md maps to at least one plan task.
|
|
6344
|
+
|
|
6345
|
+
1. Read .swarm/spec.md. Extract every MUST/SHALL SC-### obligation.
|
|
6346
|
+
2. Read the full plan object (.swarm/plan.json) or .swarm/plan.md. Extract
|
|
6347
|
+
every task ID, description, AND acceptance criteria.
|
|
6348
|
+
3. For each MUST/SHALL SC-###: determine whether any plan task covers it
|
|
6349
|
+
(semantic match, not exact phrase). An SC-### is "mapped" if it is
|
|
6350
|
+
referenced in ANY task's description OR acceptance field.
|
|
6351
|
+
4. If ANY MUST/SHALL SC-### has zero covering tasks: this is a structural
|
|
6352
|
+
completeness failure. Return VERDICT: REJECTED immediately, enumerating
|
|
6353
|
+
each unmapped obligation. Do not proceed to the quality rubric.
|
|
6354
|
+
|
|
6355
|
+
This check mirrors the existing ANALYZE-mode SC-### coverage check
|
|
6356
|
+
(see ANALYZE mode, step 4).
|
|
6357
|
+
|
|
6262
6358
|
## PLAN ASSESSMENT DIMENSIONS
|
|
6263
6359
|
Evaluate ALL seven dimensions. Report any that fail:
|
|
6264
6360
|
1. TASK ATOMICITY: Can each task be completed and QA'd independently?
|
|
@@ -6291,6 +6387,7 @@ RULES:
|
|
|
6291
6387
|
- No code writing
|
|
6292
6388
|
- Don't reject for style/formatting \u2014 focus on substance
|
|
6293
6389
|
- If the plan is fundamentally sound with only minor concerns, APPROVE it
|
|
6390
|
+
- Unmapped MUST/SHALL SC-### obligations: VERDICT must be REJECTED (structural completeness failure, not a style concern)
|
|
6294
6391
|
|
|
6295
6392
|
---
|
|
6296
6393
|
|
|
@@ -7362,7 +7459,7 @@ function extractCurrentPhaseFromPlan(plan) {
|
|
|
7362
7459
|
|
|
7363
7460
|
// src/hooks/guardrails/destructive-command.ts
|
|
7364
7461
|
import * as fsSync from "fs";
|
|
7365
|
-
import * as
|
|
7462
|
+
import * as path10 from "path";
|
|
7366
7463
|
var DC_MAX_UNWRAP_DEPTH = 5;
|
|
7367
7464
|
var DC_SAFE_TARGETS = new Set([
|
|
7368
7465
|
"node_modules",
|
|
@@ -7526,16 +7623,16 @@ function dcIsRemotePath(p) {
|
|
|
7526
7623
|
return DC_REMOTE_PREFIXES.some((pfx) => p.startsWith(pfx));
|
|
7527
7624
|
}
|
|
7528
7625
|
function dcLstatAncestorWalk(targetPath, cwd) {
|
|
7529
|
-
const normalizedTarget =
|
|
7530
|
-
const normalizedCwd =
|
|
7626
|
+
const normalizedTarget = path10.resolve(cwd, targetPath);
|
|
7627
|
+
const normalizedCwd = path10.resolve(cwd);
|
|
7531
7628
|
const ancestors = [];
|
|
7532
7629
|
let current = normalizedTarget;
|
|
7533
7630
|
while (true) {
|
|
7534
7631
|
ancestors.push(current);
|
|
7535
|
-
const parent =
|
|
7632
|
+
const parent = path10.dirname(current);
|
|
7536
7633
|
if (parent === current)
|
|
7537
7634
|
break;
|
|
7538
|
-
const rel =
|
|
7635
|
+
const rel = path10.relative(normalizedCwd, current);
|
|
7539
7636
|
if (rel === "" || rel.startsWith(".."))
|
|
7540
7637
|
break;
|
|
7541
7638
|
current = parent;
|
|
@@ -7574,14 +7671,14 @@ function dcValidateTargets(targets, cwd) {
|
|
|
7574
7671
|
const lstatBlock = dcLstatAncestorWalk(t, cwd);
|
|
7575
7672
|
if (lstatBlock)
|
|
7576
7673
|
return lstatBlock;
|
|
7577
|
-
const basename3 =
|
|
7674
|
+
const basename3 = path10.basename(t);
|
|
7578
7675
|
if (t === basename3 && DC_SAFE_TARGETS.has(t)) {
|
|
7579
7676
|
continue;
|
|
7580
7677
|
}
|
|
7581
7678
|
if (DC_FS_ROOTS.has(t) || DC_FS_ROOTS.has(t.replace(/\//g, "\\"))) {
|
|
7582
7679
|
return `BLOCKED: Destructive command targets filesystem root "${t}"`;
|
|
7583
7680
|
}
|
|
7584
|
-
if (
|
|
7681
|
+
if (path10.isAbsolute(t) || /^[A-Za-z]:/.test(t)) {
|
|
7585
7682
|
for (const blocked of DC_BLOCKED_ABSOLUTE_PREFIXES) {
|
|
7586
7683
|
if (t.startsWith(blocked)) {
|
|
7587
7684
|
return `BLOCKED: Destructive command targets system path "${t}" which is under protected prefix "${blocked}"`;
|
|
@@ -7596,9 +7693,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
7596
7693
|
if (mklinkMatch) {
|
|
7597
7694
|
const target = mklinkMatch[2].trim();
|
|
7598
7695
|
if (!dcHasUnresolvableVars(target)) {
|
|
7599
|
-
const resolved =
|
|
7600
|
-
const rel =
|
|
7601
|
-
if (rel.startsWith("..") ||
|
|
7696
|
+
const resolved = path10.resolve(cwd, target);
|
|
7697
|
+
const rel = path10.relative(cwd, resolved);
|
|
7698
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) {
|
|
7602
7699
|
return `BLOCKED: Junction/symlink creation targeting path outside working directory: mklink target "${target}" resolves to "${resolved}" which is outside "${cwd}". Creating junctions to external paths and then deleting them recursively can destroy data.`;
|
|
7603
7700
|
}
|
|
7604
7701
|
}
|
|
@@ -7610,9 +7707,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
7610
7707
|
if (newItemMatch) {
|
|
7611
7708
|
const target = newItemMatch[1].trim();
|
|
7612
7709
|
if (!dcHasUnresolvableVars(target)) {
|
|
7613
|
-
const resolved =
|
|
7614
|
-
const rel =
|
|
7615
|
-
if (rel.startsWith("..") ||
|
|
7710
|
+
const resolved = path10.resolve(cwd, target);
|
|
7711
|
+
const rel = path10.relative(cwd, resolved);
|
|
7712
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) {
|
|
7616
7713
|
return `BLOCKED: Junction/symlink creation targeting path outside working directory: New-Item target "${target}" resolves to "${resolved}" which is outside "${cwd}". This pattern caused the K2.6 data-loss incident.`;
|
|
7617
7714
|
}
|
|
7618
7715
|
}
|
|
@@ -7622,9 +7719,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
7622
7719
|
if (lnMatch) {
|
|
7623
7720
|
const target = lnMatch[1].trim();
|
|
7624
7721
|
if (!dcHasUnresolvableVars(target)) {
|
|
7625
|
-
const resolved =
|
|
7626
|
-
const rel =
|
|
7627
|
-
if (rel.startsWith("..") ||
|
|
7722
|
+
const resolved = path10.resolve(cwd, target);
|
|
7723
|
+
const rel = path10.relative(cwd, resolved);
|
|
7724
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) {
|
|
7628
7725
|
return `BLOCKED: Symlink creation targeting path outside working directory: ln -s target "${target}" resolves to "${resolved}" which is outside "${cwd}". Symlinks to external paths combined with recursive deletion can destroy data.`;
|
|
7629
7726
|
}
|
|
7630
7727
|
}
|
|
@@ -7915,7 +8012,7 @@ init_executor();
|
|
|
7915
8012
|
// src/scope/scope-persistence.ts
|
|
7916
8013
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
7917
8014
|
import * as fs4 from "fs";
|
|
7918
|
-
import * as
|
|
8015
|
+
import * as path14 from "path";
|
|
7919
8016
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
7920
8017
|
var LOCK_STALE_MS = 30 * 1000;
|
|
7921
8018
|
var SCOPES_DIR = ".swarm/scopes";
|
|
@@ -7946,7 +8043,7 @@ var WINDOWS_RESERVED = new Set([
|
|
|
7946
8043
|
"LPT9"
|
|
7947
8044
|
]);
|
|
7948
8045
|
function getScopesDir(directory) {
|
|
7949
|
-
return
|
|
8046
|
+
return path14.join(directory, SCOPES_DIR);
|
|
7950
8047
|
}
|
|
7951
8048
|
function clearAllScopes(directory) {
|
|
7952
8049
|
try {
|
|
@@ -7955,10 +8052,10 @@ function clearAllScopes(directory) {
|
|
|
7955
8052
|
}
|
|
7956
8053
|
|
|
7957
8054
|
// src/hooks/shell-write-detect.ts
|
|
7958
|
-
import * as
|
|
8055
|
+
import * as path15 from "path";
|
|
7959
8056
|
import parse from "bash-parser";
|
|
7960
|
-
function buildDedupeKey(category, operator,
|
|
7961
|
-
return `${category}|${operator}|${
|
|
8057
|
+
function buildDedupeKey(category, operator, path16) {
|
|
8058
|
+
return `${category}|${operator}|${path16 ?? "null"}`;
|
|
7962
8059
|
}
|
|
7963
8060
|
var REDIRECT_WRITE_TOKENS = new Set([
|
|
7964
8061
|
"GREAT",
|
|
@@ -8018,16 +8115,16 @@ function detectProcessSubstitutionWrites(command) {
|
|
|
8018
8115
|
results.push(builtinResult);
|
|
8019
8116
|
const appendMatch = stage.match(/^\s*(.*?)\s*>>(\s*)(\S+)\s*$/);
|
|
8020
8117
|
if (appendMatch) {
|
|
8021
|
-
const
|
|
8022
|
-
if (
|
|
8023
|
-
results.push({ category: "redirect", operator: ">>", path:
|
|
8118
|
+
const path16 = appendMatch[3];
|
|
8119
|
+
if (path16 && !isNullDevice(path16)) {
|
|
8120
|
+
results.push({ category: "redirect", operator: ">>", path: path16 });
|
|
8024
8121
|
}
|
|
8025
8122
|
} else {
|
|
8026
8123
|
const writeMatch = stage.match(/^\s*(.*?)\s*>(?!>)(\s*)(\S+)\s*$/);
|
|
8027
8124
|
if (writeMatch) {
|
|
8028
|
-
const
|
|
8029
|
-
if (
|
|
8030
|
-
results.push({ category: "redirect", operator: ">", path:
|
|
8125
|
+
const path16 = writeMatch[3];
|
|
8126
|
+
if (path16 && !isNullDevice(path16)) {
|
|
8127
|
+
results.push({ category: "redirect", operator: ">", path: path16 });
|
|
8031
8128
|
}
|
|
8032
8129
|
}
|
|
8033
8130
|
}
|
|
@@ -8201,8 +8298,8 @@ function extractRedirectPath(fileNode) {
|
|
|
8201
8298
|
return null;
|
|
8202
8299
|
return text;
|
|
8203
8300
|
}
|
|
8204
|
-
function isNullDevice(
|
|
8205
|
-
return
|
|
8301
|
+
function isNullDevice(path16) {
|
|
8302
|
+
return path16 === "/dev/null" || path16 === "/dev/zero" || path16 === "/dev/urandom";
|
|
8206
8303
|
}
|
|
8207
8304
|
function isNumeric(s) {
|
|
8208
8305
|
return /^\d+$/.test(s);
|
|
@@ -8222,12 +8319,12 @@ function detectRedirects(cmd) {
|
|
|
8222
8319
|
if (!opType || !REDIRECT_ALL_WRITE_TOKENS.has(opType))
|
|
8223
8320
|
continue;
|
|
8224
8321
|
const fileNode = r.file;
|
|
8225
|
-
const
|
|
8322
|
+
const path16 = extractRedirectPath(fileNode);
|
|
8226
8323
|
const opLabel = operatorLabel(opNode);
|
|
8227
8324
|
if (REDIRECT_WRITE_TOKENS.has(opType)) {
|
|
8228
|
-
results.push({ category: "redirect", operator: opLabel, path:
|
|
8325
|
+
results.push({ category: "redirect", operator: opLabel, path: path16 });
|
|
8229
8326
|
} else if (REDIRECT_HERE_TOKENS.has(opType)) {
|
|
8230
|
-
results.push({ category: "here_doc", operator: opLabel, path:
|
|
8327
|
+
results.push({ category: "here_doc", operator: opLabel, path: path16 });
|
|
8231
8328
|
}
|
|
8232
8329
|
}
|
|
8233
8330
|
return results;
|
|
@@ -8270,9 +8367,9 @@ function detectBuiltinWrites(cmd) {
|
|
|
8270
8367
|
const suffixWords2 = getSuffixWords(cmd);
|
|
8271
8368
|
for (const word of suffixWords2) {
|
|
8272
8369
|
if (word.startsWith("of=")) {
|
|
8273
|
-
const
|
|
8274
|
-
if (
|
|
8275
|
-
results.push({ category: "builtin_write", operator: "dd of=", path:
|
|
8370
|
+
const path16 = word.slice(3);
|
|
8371
|
+
if (path16 && !isNullDevice(path16)) {
|
|
8372
|
+
results.push({ category: "builtin_write", operator: "dd of=", path: path16 });
|
|
8276
8373
|
}
|
|
8277
8374
|
}
|
|
8278
8375
|
}
|
|
@@ -8391,12 +8488,12 @@ function detectNetworkDownloaders(cmd) {
|
|
|
8391
8488
|
for (let i = 0;i < suffixWords.length; i++) {
|
|
8392
8489
|
const word = suffixWords[i];
|
|
8393
8490
|
if (word === "-o" && i + 1 < suffixWords.length) {
|
|
8394
|
-
const
|
|
8395
|
-
if (!
|
|
8491
|
+
const path16 = suffixWords[i + 1];
|
|
8492
|
+
if (!path16.startsWith("-")) {
|
|
8396
8493
|
results.push({
|
|
8397
8494
|
category: "network_download",
|
|
8398
8495
|
operator: "curl -o",
|
|
8399
|
-
path:
|
|
8496
|
+
path: path16
|
|
8400
8497
|
});
|
|
8401
8498
|
}
|
|
8402
8499
|
} else if (word.startsWith("-o") && word.length > 2) {
|
|
@@ -8411,12 +8508,12 @@ function detectNetworkDownloaders(cmd) {
|
|
|
8411
8508
|
for (let i = 0;i < suffixWords.length; i++) {
|
|
8412
8509
|
const word = suffixWords[i];
|
|
8413
8510
|
if (word === "-O" && i + 1 < suffixWords.length) {
|
|
8414
|
-
const
|
|
8415
|
-
if (!
|
|
8511
|
+
const path16 = suffixWords[i + 1];
|
|
8512
|
+
if (!path16.startsWith("-")) {
|
|
8416
8513
|
results.push({
|
|
8417
8514
|
category: "network_download",
|
|
8418
8515
|
operator: "wget -O",
|
|
8419
|
-
path:
|
|
8516
|
+
path: path16
|
|
8420
8517
|
});
|
|
8421
8518
|
}
|
|
8422
8519
|
} else if (word.startsWith("-O") && word.length > 2) {
|
|
@@ -8525,9 +8622,9 @@ function detectGitDestructive(cmd) {
|
|
|
8525
8622
|
if (first === "checkout") {
|
|
8526
8623
|
const dashDashIdx = suffixWords.indexOf("--");
|
|
8527
8624
|
if (dashDashIdx !== -1 && dashDashIdx + 1 < suffixWords.length) {
|
|
8528
|
-
const
|
|
8529
|
-
const op =
|
|
8530
|
-
results.push({ category: "git_destructive", operator: op, path:
|
|
8625
|
+
const path16 = suffixWords[dashDashIdx + 1];
|
|
8626
|
+
const op = path16 === "." ? "git checkout -- ." : "git checkout --";
|
|
8627
|
+
results.push({ category: "git_destructive", operator: op, path: path16 });
|
|
8531
8628
|
}
|
|
8532
8629
|
} else if (first === "restore") {
|
|
8533
8630
|
const hasHard = suffixWords.some((w) => w === "--hard" || w === "-H" || w.startsWith("-") && w.includes("H"));
|
|
@@ -8647,10 +8744,10 @@ function detectPowerShellWrites(command) {
|
|
|
8647
8744
|
if (redirectMatch) {
|
|
8648
8745
|
const beforeRedirect = redirectMatch[1];
|
|
8649
8746
|
const op = redirectMatch[2];
|
|
8650
|
-
const
|
|
8747
|
+
const path16 = redirectMatch[3];
|
|
8651
8748
|
const fdRedirectPattern = /\d>\s*$|\s\d>&$/;
|
|
8652
8749
|
if (!fdRedirectPattern.test(`${beforeRedirect} ${op}`)) {
|
|
8653
|
-
results.push({ category: "redirect", operator: op, path:
|
|
8750
|
+
results.push({ category: "redirect", operator: op, path: path16 });
|
|
8654
8751
|
}
|
|
8655
8752
|
}
|
|
8656
8753
|
const leadingRedirect = innerCommand.match(/^((?:>){1,2})\s+(\S+)$/);
|
|
@@ -8663,12 +8760,12 @@ function detectPowerShellWrites(command) {
|
|
|
8663
8760
|
}
|
|
8664
8761
|
const iwrMatch = trimmed.match(/^(?:Invoke-WebRequest|curl)\s.*?(?:-OutFile\s+(\S+)|-o\s+(\S+))/i);
|
|
8665
8762
|
if (iwrMatch) {
|
|
8666
|
-
const
|
|
8667
|
-
if (
|
|
8763
|
+
const path16 = iwrMatch[1] || iwrMatch[2];
|
|
8764
|
+
if (path16) {
|
|
8668
8765
|
results.push({
|
|
8669
8766
|
category: "network_download",
|
|
8670
8767
|
operator: "Invoke-WebRequest -OutFile",
|
|
8671
|
-
path:
|
|
8768
|
+
path: path16
|
|
8672
8769
|
});
|
|
8673
8770
|
}
|
|
8674
8771
|
}
|
|
@@ -8680,15 +8777,15 @@ function detectPowerShellWrites(command) {
|
|
|
8680
8777
|
const rest = cmd.slice(cmdletMatch[0].length).trim();
|
|
8681
8778
|
const pathFlagMatch = rest.match(/(?:-Path|-FilePath|-LiteralPath)\s+("([^"]+)"|'([^']+)'|(\S+))/i);
|
|
8682
8779
|
if (pathFlagMatch) {
|
|
8683
|
-
const
|
|
8684
|
-
return { category: "redirect", operator: cmdletName, path:
|
|
8780
|
+
const path16 = pathFlagMatch[2] ?? pathFlagMatch[3] ?? pathFlagMatch[4] ?? "";
|
|
8781
|
+
return { category: "redirect", operator: cmdletName, path: path16 };
|
|
8685
8782
|
}
|
|
8686
8783
|
const tokens = rest.match(/(?:[^\s"-]+|"[^"]*"|'[^']*'|-[^\s]+)/g) ?? [];
|
|
8687
8784
|
for (const token of tokens) {
|
|
8688
8785
|
if (token.startsWith("-"))
|
|
8689
8786
|
continue;
|
|
8690
|
-
const
|
|
8691
|
-
return { category: "redirect", operator: cmdletName, path:
|
|
8787
|
+
const path16 = token.replace(/^["']|["']$/g, "");
|
|
8788
|
+
return { category: "redirect", operator: cmdletName, path: path16 };
|
|
8692
8789
|
}
|
|
8693
8790
|
return null;
|
|
8694
8791
|
}
|
|
@@ -8704,9 +8801,9 @@ function detectPowerShellWrites(command) {
|
|
|
8704
8801
|
for (const token of tokens) {
|
|
8705
8802
|
if (token.startsWith("-"))
|
|
8706
8803
|
continue;
|
|
8707
|
-
const
|
|
8708
|
-
if (
|
|
8709
|
-
results.push({ category: "redirect", operator: cmdletName, path:
|
|
8804
|
+
const path16 = token.replace(/^["']|["']$/g, "");
|
|
8805
|
+
if (path16) {
|
|
8806
|
+
results.push({ category: "redirect", operator: cmdletName, path: path16 });
|
|
8710
8807
|
break;
|
|
8711
8808
|
}
|
|
8712
8809
|
}
|
|
@@ -8719,8 +8816,8 @@ function detectPowerShellWrites(command) {
|
|
|
8719
8816
|
const rest = cmd.slice(opMatch[0].length).trim();
|
|
8720
8817
|
const destFlagMatch = rest.match(/-Destination\s+(\S+|"[^"]+"|'[^']+')/i);
|
|
8721
8818
|
if (destFlagMatch) {
|
|
8722
|
-
const
|
|
8723
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
8819
|
+
const path16 = destFlagMatch[1].replace(/^["']|["']$/g, "");
|
|
8820
|
+
return { category: "builtin_write", operator: cmdletName, path: path16 };
|
|
8724
8821
|
}
|
|
8725
8822
|
const tokens = [];
|
|
8726
8823
|
const flagTakingValue = new Set([
|
|
@@ -8759,11 +8856,11 @@ function detectPowerShellWrites(command) {
|
|
|
8759
8856
|
}
|
|
8760
8857
|
}
|
|
8761
8858
|
if (tokens.length >= 2) {
|
|
8762
|
-
const
|
|
8763
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
8859
|
+
const path16 = tokens[tokens.length - 1].replace(/^["']|["']$/g, "");
|
|
8860
|
+
return { category: "builtin_write", operator: cmdletName, path: path16 };
|
|
8764
8861
|
} else if (tokens.length === 1) {
|
|
8765
|
-
const
|
|
8766
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
8862
|
+
const path16 = tokens[0].replace(/^["']|["']$/g, "");
|
|
8863
|
+
return { category: "builtin_write", operator: cmdletName, path: path16 };
|
|
8767
8864
|
}
|
|
8768
8865
|
return null;
|
|
8769
8866
|
}
|
|
@@ -8777,14 +8874,14 @@ function detectPowerShellWrites(command) {
|
|
|
8777
8874
|
const afterCmdlet = pipeFileOpMatch[2].trim();
|
|
8778
8875
|
const destFlagMatch = afterCmdlet.match(/-Destination\s+(\S+|"[^"]+"|'[^']+')/i);
|
|
8779
8876
|
if (destFlagMatch) {
|
|
8780
|
-
const
|
|
8781
|
-
results.push({ category: "builtin_write", operator: cmdletName, path:
|
|
8877
|
+
const path16 = destFlagMatch[1].replace(/^["']|["']$/g, "");
|
|
8878
|
+
results.push({ category: "builtin_write", operator: cmdletName, path: path16 });
|
|
8782
8879
|
} else {
|
|
8783
8880
|
const tokens = afterCmdlet.match(/(?:[^\s"-]+|"[^"]*"|'[^']*'|-[^\s]+)/g) ?? [];
|
|
8784
8881
|
const nonFlagTokens = tokens.filter((t) => !t.startsWith("-") && t.length > 0);
|
|
8785
8882
|
if (nonFlagTokens.length > 0) {
|
|
8786
|
-
const
|
|
8787
|
-
results.push({ category: "builtin_write", operator: cmdletName, path:
|
|
8883
|
+
const path16 = nonFlagTokens[nonFlagTokens.length - 1].replace(/^["']|["']$/g, "");
|
|
8884
|
+
results.push({ category: "builtin_write", operator: cmdletName, path: path16 });
|
|
8788
8885
|
}
|
|
8789
8886
|
}
|
|
8790
8887
|
}
|
|
@@ -8837,10 +8934,10 @@ function detectCmdWrites(command) {
|
|
|
8837
8934
|
if (redirectMatch) {
|
|
8838
8935
|
const beforeRedirect = redirectMatch[1];
|
|
8839
8936
|
const op = redirectMatch[2];
|
|
8840
|
-
const
|
|
8937
|
+
const path16 = redirectMatch[3];
|
|
8841
8938
|
const fdRedirectPattern = /\d>&?$/;
|
|
8842
8939
|
if (!fdRedirectPattern.test(beforeRedirect)) {
|
|
8843
|
-
results.push({ category: "redirect", operator: op, path:
|
|
8940
|
+
results.push({ category: "redirect", operator: op, path: path16 });
|
|
8844
8941
|
}
|
|
8845
8942
|
}
|
|
8846
8943
|
const leadingRedirect = innerCommand.match(/^((?:>){1,2})\s+(\S+)$/);
|
|
@@ -8898,8 +8995,8 @@ function detectCmdWrites(command) {
|
|
|
8898
8995
|
const rawTokens = rest.match(/(\/?[^\s]+|"[^"]*"|'[^']*')/g) ?? [];
|
|
8899
8996
|
const tokens = rawTokens.filter((t) => !t.startsWith("/"));
|
|
8900
8997
|
if (tokens.length > 0) {
|
|
8901
|
-
const
|
|
8902
|
-
return { category: "builtin_write", operator: "del", path:
|
|
8998
|
+
const path16 = tokens[0].replace(/^["']|["']$/g, "");
|
|
8999
|
+
return { category: "builtin_write", operator: "del", path: path16 };
|
|
8903
9000
|
}
|
|
8904
9001
|
return null;
|
|
8905
9002
|
}
|
|
@@ -8909,16 +9006,16 @@ function detectCmdWrites(command) {
|
|
|
8909
9006
|
}
|
|
8910
9007
|
const rdMatch = innerCommand.match(/^rd\s+(?:\/s\s+|\/q\s+)*(\S+)/i);
|
|
8911
9008
|
if (rdMatch) {
|
|
8912
|
-
const
|
|
8913
|
-
if (!
|
|
8914
|
-
results.push({ category: "builtin_write", operator: "rd", path:
|
|
9009
|
+
const path16 = rdMatch[1].replace(/^["']|["']$/g, "");
|
|
9010
|
+
if (!path16.startsWith("/")) {
|
|
9011
|
+
results.push({ category: "builtin_write", operator: "rd", path: path16 });
|
|
8915
9012
|
}
|
|
8916
9013
|
}
|
|
8917
9014
|
const mdMatch = trimmed.match(/^md\s+(\S+)/i);
|
|
8918
9015
|
if (mdMatch) {
|
|
8919
|
-
const
|
|
8920
|
-
if (!
|
|
8921
|
-
results.push({ category: "builtin_write", operator: "md", path:
|
|
9016
|
+
const path16 = mdMatch[1].replace(/^["']|["']$/g, "");
|
|
9017
|
+
if (!path16.startsWith("/")) {
|
|
9018
|
+
results.push({ category: "builtin_write", operator: "md", path: path16 });
|
|
8922
9019
|
}
|
|
8923
9020
|
}
|
|
8924
9021
|
const echoMatch = trimmed.match(/^echo\s+(\S+.*?)\s+((?:>){1,2})\s*(\S+)$/i);
|
|
@@ -9034,9 +9131,9 @@ function resolvePath(pathText, cwd) {
|
|
|
9034
9131
|
return null;
|
|
9035
9132
|
const isWindowsPath = /^[a-zA-Z]:[\\\\/]/.test(cwd) || cwd.includes("\\");
|
|
9036
9133
|
if (isWindowsPath) {
|
|
9037
|
-
return
|
|
9134
|
+
return path15.win32.resolve(cwd, pathText);
|
|
9038
9135
|
}
|
|
9039
|
-
return
|
|
9136
|
+
return path15.posix.resolve(cwd, pathText);
|
|
9040
9137
|
}
|
|
9041
9138
|
function getCdTarget(cmd) {
|
|
9042
9139
|
if (!cmd || typeof cmd !== "object")
|
|
@@ -9103,7 +9200,7 @@ function collectWritesWithNodes(node, out, cwdStack) {
|
|
|
9103
9200
|
for (const cmd of node.commands) {
|
|
9104
9201
|
const cdTarget = getCdTarget(cmd);
|
|
9105
9202
|
if (cdTarget) {
|
|
9106
|
-
currentStack[0] =
|
|
9203
|
+
currentStack[0] = path15.posix.resolve(currentStack[0] ?? "/", cdTarget);
|
|
9107
9204
|
collectWritesWithNodes(cmd, out, currentStack);
|
|
9108
9205
|
} else {
|
|
9109
9206
|
collectWritesWithNodes(cmd, out, currentStack);
|
|
@@ -9149,7 +9246,7 @@ function collectWritesWithNodes(node, out, cwdStack) {
|
|
|
9149
9246
|
const effectiveCwd = cwdStack[0] ?? "/";
|
|
9150
9247
|
const cdTarget = getCdTarget(node);
|
|
9151
9248
|
if (cdTarget) {
|
|
9152
|
-
cwdStack[0] =
|
|
9249
|
+
cwdStack[0] = path15.posix.resolve(cwdStack[0] ?? "/", cdTarget);
|
|
9153
9250
|
return;
|
|
9154
9251
|
}
|
|
9155
9252
|
const writesFromRedirs = getWritesFromCommandRedirs(node, effectiveCwd);
|
|
@@ -9195,12 +9292,12 @@ function getWritesFromRedirectNode(redirect, _context) {
|
|
|
9195
9292
|
if (!opType || !REDIRECT_ALL_WRITE_TOKENS.has(opType))
|
|
9196
9293
|
return [];
|
|
9197
9294
|
const fileNode = r.file;
|
|
9198
|
-
const
|
|
9295
|
+
const path16 = extractRedirectPath(fileNode);
|
|
9199
9296
|
const opLabel = operatorLabel(opNode);
|
|
9200
9297
|
if (REDIRECT_WRITE_TOKENS.has(opType)) {
|
|
9201
|
-
return [{ category: "redirect", operator: opLabel, path:
|
|
9298
|
+
return [{ category: "redirect", operator: opLabel, path: path16 }];
|
|
9202
9299
|
} else if (REDIRECT_HERE_TOKENS.has(opType)) {
|
|
9203
|
-
return [{ category: "here_doc", operator: opLabel, path:
|
|
9300
|
+
return [{ category: "here_doc", operator: opLabel, path: path16 }];
|
|
9204
9301
|
}
|
|
9205
9302
|
return [];
|
|
9206
9303
|
}
|
|
@@ -9333,10 +9430,10 @@ function clearTrajectoryStepCounters(sessionId) {
|
|
|
9333
9430
|
|
|
9334
9431
|
// src/prm/trajectory-store.ts
|
|
9335
9432
|
import * as fs5 from "fs/promises";
|
|
9336
|
-
import * as
|
|
9433
|
+
import * as path16 from "path";
|
|
9337
9434
|
var MAX_TRACKED_TRAJECTORY_SESSIONS = 500;
|
|
9338
9435
|
function getTrajectoryPath(sessionId, directory) {
|
|
9339
|
-
const relativePath =
|
|
9436
|
+
const relativePath = path16.join("trajectories", `${sessionId}.jsonl`);
|
|
9340
9437
|
return validateSwarmPath(directory, relativePath);
|
|
9341
9438
|
}
|
|
9342
9439
|
var _inMemoryTrajectoryCache = new Map;
|
|
@@ -9395,7 +9492,7 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
|
9395
9492
|
for (const entry of entries) {
|
|
9396
9493
|
if (!entry.isFile())
|
|
9397
9494
|
continue;
|
|
9398
|
-
const filePath =
|
|
9495
|
+
const filePath = path16.join(dirPath, entry.name);
|
|
9399
9496
|
try {
|
|
9400
9497
|
const stat4 = await fs5.stat(filePath);
|
|
9401
9498
|
if (now - stat4.mtimeMs > cutoffMs) {
|
|
@@ -9409,13 +9506,13 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
|
9409
9506
|
|
|
9410
9507
|
// src/session/session-start-store.ts
|
|
9411
9508
|
import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
9412
|
-
import * as
|
|
9509
|
+
import * as path17 from "path";
|
|
9413
9510
|
var SESSION_START_FILE = "session-start.jsonl";
|
|
9414
9511
|
function recordSessionStart(directory, startMs) {
|
|
9415
9512
|
try {
|
|
9416
|
-
const swarmDir =
|
|
9417
|
-
const sessionDir =
|
|
9418
|
-
const filePath =
|
|
9513
|
+
const swarmDir = path17.join(directory, ".swarm");
|
|
9514
|
+
const sessionDir = path17.join(swarmDir, "session");
|
|
9515
|
+
const filePath = path17.join(sessionDir, SESSION_START_FILE);
|
|
9419
9516
|
const line = JSON.stringify({ startMs, ts: Date.now() });
|
|
9420
9517
|
mkdirSync7(sessionDir, { recursive: true });
|
|
9421
9518
|
writeFileSync3(filePath, `${line}
|
|
@@ -9424,7 +9521,7 @@ function recordSessionStart(directory, startMs) {
|
|
|
9424
9521
|
}
|
|
9425
9522
|
function readEarliestSessionStart(directory) {
|
|
9426
9523
|
try {
|
|
9427
|
-
const filePath =
|
|
9524
|
+
const filePath = path17.join(directory, ".swarm", "session", SESSION_START_FILE);
|
|
9428
9525
|
if (!existsSync5(filePath))
|
|
9429
9526
|
return null;
|
|
9430
9527
|
const content = readFileSync3(filePath, "utf-8");
|
|
@@ -10071,7 +10168,7 @@ function evidenceToWorkflowState(evidence) {
|
|
|
10071
10168
|
}
|
|
10072
10169
|
async function readPlanFromDisk(directory) {
|
|
10073
10170
|
try {
|
|
10074
|
-
const planPath =
|
|
10171
|
+
const planPath = path18.join(directory, ".swarm", "plan.json");
|
|
10075
10172
|
const content = await fs6.readFile(planPath, "utf-8");
|
|
10076
10173
|
const parsed = JSON.parse(content);
|
|
10077
10174
|
return PlanSchema.parse(parsed);
|
|
@@ -10082,7 +10179,7 @@ async function readPlanFromDisk(directory) {
|
|
|
10082
10179
|
async function readGateEvidenceFromDisk(directory) {
|
|
10083
10180
|
const evidenceMap = new Map;
|
|
10084
10181
|
try {
|
|
10085
|
-
const evidenceDir =
|
|
10182
|
+
const evidenceDir = path18.join(directory, ".swarm", "evidence");
|
|
10086
10183
|
const entries = await fs6.readdir(evidenceDir, { withFileTypes: true });
|
|
10087
10184
|
for (const entry of entries) {
|
|
10088
10185
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
@@ -10093,7 +10190,7 @@ async function readGateEvidenceFromDisk(directory) {
|
|
|
10093
10190
|
continue;
|
|
10094
10191
|
}
|
|
10095
10192
|
try {
|
|
10096
|
-
const filePath =
|
|
10193
|
+
const filePath = path18.join(evidenceDir, entry.name);
|
|
10097
10194
|
const content = await fs6.readFile(filePath, "utf-8");
|
|
10098
10195
|
const parsed = JSON.parse(content);
|
|
10099
10196
|
if (parsed && typeof parsed.taskId === "string" && Array.isArray(parsed.required_gates)) {
|
|
@@ -10315,7 +10412,7 @@ async function handleAutoProceedCommand(_directory, args, sessionID) {
|
|
|
10315
10412
|
// src/services/cost-accounting.ts
|
|
10316
10413
|
import * as fs7 from "fs";
|
|
10317
10414
|
import * as os8 from "os";
|
|
10318
|
-
import * as
|
|
10415
|
+
import * as path19 from "path";
|
|
10319
10416
|
function summarizeTelemetryCosts(directory) {
|
|
10320
10417
|
const summary = createEmptySummary();
|
|
10321
10418
|
for (const event of readTelemetryEvents(directory)) {
|
|
@@ -10326,18 +10423,18 @@ function summarizeTelemetryCosts(directory) {
|
|
|
10326
10423
|
return finalizeSummary(summary);
|
|
10327
10424
|
}
|
|
10328
10425
|
function readTelemetryEvents(directory) {
|
|
10329
|
-
const swarmDir =
|
|
10426
|
+
const swarmDir = path19.join(directory, ".swarm");
|
|
10330
10427
|
const files = [
|
|
10331
|
-
|
|
10332
|
-
|
|
10428
|
+
path19.join(swarmDir, "telemetry.jsonl.1"),
|
|
10429
|
+
path19.join(swarmDir, "telemetry.jsonl")
|
|
10333
10430
|
];
|
|
10334
|
-
const tmpDir = fs7.mkdtempSync(
|
|
10431
|
+
const tmpDir = fs7.mkdtempSync(path19.join(os8.tmpdir(), "telemetry-snapshot-"));
|
|
10335
10432
|
const snapshotFiles = [];
|
|
10336
10433
|
try {
|
|
10337
10434
|
for (const file of files) {
|
|
10338
10435
|
if (!fs7.existsSync(file))
|
|
10339
10436
|
continue;
|
|
10340
|
-
const snap =
|
|
10437
|
+
const snap = path19.join(tmpDir, path19.basename(file));
|
|
10341
10438
|
try {
|
|
10342
10439
|
fs7.copyFileSync(file, snap);
|
|
10343
10440
|
snapshotFiles.push(snap);
|
|
@@ -10894,7 +10991,7 @@ async function handleBrainstormCommand(_directory, args) {
|
|
|
10894
10991
|
// src/tools/checkpoint.ts
|
|
10895
10992
|
import * as child_process from "child_process";
|
|
10896
10993
|
import * as fs8 from "fs";
|
|
10897
|
-
import * as
|
|
10994
|
+
import * as path20 from "path";
|
|
10898
10995
|
|
|
10899
10996
|
// src/tools/create-tool.ts
|
|
10900
10997
|
function classifyToolError(error2) {
|
|
@@ -10981,7 +11078,7 @@ function validateLabel(label) {
|
|
|
10981
11078
|
return null;
|
|
10982
11079
|
}
|
|
10983
11080
|
function getCheckpointLogPath(directory) {
|
|
10984
|
-
return
|
|
11081
|
+
return path20.join(directory, CHECKPOINT_LOG_PATH);
|
|
10985
11082
|
}
|
|
10986
11083
|
function readCheckpointLog(directory) {
|
|
10987
11084
|
const logPath = getCheckpointLogPath(directory);
|
|
@@ -10999,7 +11096,7 @@ function readCheckpointLog(directory) {
|
|
|
10999
11096
|
}
|
|
11000
11097
|
function writeCheckpointLog(log2, directory) {
|
|
11001
11098
|
const logPath = getCheckpointLogPath(directory);
|
|
11002
|
-
const dir =
|
|
11099
|
+
const dir = path20.dirname(logPath);
|
|
11003
11100
|
if (!fs8.existsSync(dir)) {
|
|
11004
11101
|
fs8.mkdirSync(dir, { recursive: true });
|
|
11005
11102
|
}
|
|
@@ -11036,7 +11133,7 @@ function gitExec(args, cwd) {
|
|
|
11036
11133
|
}
|
|
11037
11134
|
function appendRetentionEvent(directory, event) {
|
|
11038
11135
|
try {
|
|
11039
|
-
const eventsPath =
|
|
11136
|
+
const eventsPath = path20.join(directory, ".swarm", "events.jsonl");
|
|
11040
11137
|
const line = `${JSON.stringify({ ...event, timestamp: new Date().toISOString() })}
|
|
11041
11138
|
`;
|
|
11042
11139
|
fs8.appendFileSync(eventsPath, line);
|
|
@@ -11402,7 +11499,7 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
11402
11499
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
11403
11500
|
import * as fsSync2 from "fs";
|
|
11404
11501
|
import { promises as fs13 } from "fs";
|
|
11405
|
-
import
|
|
11502
|
+
import path33 from "path";
|
|
11406
11503
|
|
|
11407
11504
|
// src/hooks/abort-utils.ts
|
|
11408
11505
|
function isAbortError(err) {
|
|
@@ -11532,7 +11629,7 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
|
|
|
11532
11629
|
|
|
11533
11630
|
// src/hooks/curator-postmortem.ts
|
|
11534
11631
|
import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync6 } from "fs";
|
|
11535
|
-
import * as
|
|
11632
|
+
import * as path21 from "path";
|
|
11536
11633
|
var MAX_INPUT_TEXT_CHARS = 500;
|
|
11537
11634
|
var MAX_KNOWLEDGE_ENTRIES = 500;
|
|
11538
11635
|
var MAX_PROPOSALS = 50;
|
|
@@ -11599,13 +11696,13 @@ function readJsonlFile(filePath, maxLines) {
|
|
|
11599
11696
|
}
|
|
11600
11697
|
function collectRetrospectives(directory) {
|
|
11601
11698
|
const results = [];
|
|
11602
|
-
const evidenceDir =
|
|
11699
|
+
const evidenceDir = path21.join(directory, ".swarm", "evidence");
|
|
11603
11700
|
try {
|
|
11604
11701
|
if (!existsSync8(evidenceDir))
|
|
11605
11702
|
return results;
|
|
11606
11703
|
const retroDirs = readdirSync(evidenceDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("retro-")).slice(0, MAX_RETROSPECTIVES);
|
|
11607
11704
|
for (const entry of retroDirs) {
|
|
11608
|
-
const retroPath =
|
|
11705
|
+
const retroPath = path21.join(evidenceDir, entry.name, "evidence.json");
|
|
11609
11706
|
if (existsSync8(retroPath)) {
|
|
11610
11707
|
try {
|
|
11611
11708
|
results.push(readFileSync6(retroPath, "utf-8"));
|
|
@@ -11617,14 +11714,14 @@ function collectRetrospectives(directory) {
|
|
|
11617
11714
|
}
|
|
11618
11715
|
function collectDriftReports(directory) {
|
|
11619
11716
|
const results = [];
|
|
11620
|
-
const swarmDir =
|
|
11717
|
+
const swarmDir = path21.join(directory, ".swarm");
|
|
11621
11718
|
try {
|
|
11622
11719
|
if (!existsSync8(swarmDir))
|
|
11623
11720
|
return results;
|
|
11624
11721
|
const driftFiles = readdirSync(swarmDir).filter((e) => e.startsWith("drift-report-phase-") && e.endsWith(".json")).slice(0, MAX_DRIFT_REPORTS);
|
|
11625
11722
|
for (const entry of driftFiles) {
|
|
11626
11723
|
try {
|
|
11627
|
-
results.push(readFileSync6(
|
|
11724
|
+
results.push(readFileSync6(path21.join(swarmDir, entry), "utf-8"));
|
|
11628
11725
|
} catch {}
|
|
11629
11726
|
}
|
|
11630
11727
|
} catch {}
|
|
@@ -11632,7 +11729,7 @@ function collectDriftReports(directory) {
|
|
|
11632
11729
|
}
|
|
11633
11730
|
function collectPendingProposals(directory) {
|
|
11634
11731
|
const results = [];
|
|
11635
|
-
const insightPath =
|
|
11732
|
+
const insightPath = path21.join(directory, ".swarm", "insight-candidates.jsonl");
|
|
11636
11733
|
if (existsSync8(insightPath)) {
|
|
11637
11734
|
try {
|
|
11638
11735
|
results.push({
|
|
@@ -11641,7 +11738,7 @@ function collectPendingProposals(directory) {
|
|
|
11641
11738
|
});
|
|
11642
11739
|
} catch {}
|
|
11643
11740
|
}
|
|
11644
|
-
const proposalsDir =
|
|
11741
|
+
const proposalsDir = path21.join(directory, ".swarm", "skills", "proposals");
|
|
11645
11742
|
try {
|
|
11646
11743
|
if (existsSync8(proposalsDir)) {
|
|
11647
11744
|
const proposalFiles = readdirSync(proposalsDir).filter((e) => e.endsWith(".md") || e.endsWith(".json")).slice(0, MAX_PROPOSALS);
|
|
@@ -11649,7 +11746,7 @@ function collectPendingProposals(directory) {
|
|
|
11649
11746
|
try {
|
|
11650
11747
|
results.push({
|
|
11651
11748
|
source: `proposals/${entry}`,
|
|
11652
|
-
content: readFileSync6(
|
|
11749
|
+
content: readFileSync6(path21.join(proposalsDir, entry), "utf-8")
|
|
11653
11750
|
});
|
|
11654
11751
|
} catch {}
|
|
11655
11752
|
}
|
|
@@ -11870,7 +11967,7 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
11870
11967
|
warnings.push(`Pending proposals capped at ${MAX_PROPOSALS} (had ${proposals.length}); older entries truncated.`);
|
|
11871
11968
|
proposals = proposals.slice(0, MAX_PROPOSALS);
|
|
11872
11969
|
}
|
|
11873
|
-
const unactionablePath =
|
|
11970
|
+
const unactionablePath = path21.join(resolveKnowledgeStoreDir(directory), "knowledge-unactionable.jsonl");
|
|
11874
11971
|
let unactionable = readJsonlFile(unactionablePath, MAX_UNACTIONABLE);
|
|
11875
11972
|
if (unactionable.length > MAX_UNACTIONABLE) {
|
|
11876
11973
|
warnings.push(`Unactionable entries capped at ${MAX_UNACTIONABLE} (had ${unactionable.length}); older entries truncated.`);
|
|
@@ -11920,7 +12017,7 @@ ${llmOutput}`;
|
|
|
11920
12017
|
}
|
|
11921
12018
|
try {
|
|
11922
12019
|
const { mkdirSync: mkdirSync9 } = await import("fs");
|
|
11923
|
-
mkdirSync9(
|
|
12020
|
+
mkdirSync9(path21.dirname(reportPath), { recursive: true });
|
|
11924
12021
|
await atomicWriteFile(reportPath, reportContent);
|
|
11925
12022
|
} catch (err) {
|
|
11926
12023
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -11968,7 +12065,7 @@ var _internals14 = {
|
|
|
11968
12065
|
};
|
|
11969
12066
|
|
|
11970
12067
|
// src/hooks/hive-promoter.ts
|
|
11971
|
-
import
|
|
12068
|
+
import path24 from "path";
|
|
11972
12069
|
|
|
11973
12070
|
// src/background/event-bus.ts
|
|
11974
12071
|
class AutomationEventBus {
|
|
@@ -12474,7 +12571,7 @@ init_logger();
|
|
|
12474
12571
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
12475
12572
|
import { existsSync as existsSync9 } from "fs";
|
|
12476
12573
|
import { mkdir as mkdir5, readFile as readFile5, rename as rename2, writeFile as writeFile4 } from "fs/promises";
|
|
12477
|
-
import * as
|
|
12574
|
+
import * as path22 from "path";
|
|
12478
12575
|
var LOCK_ACQUIRE_TIMEOUT_MS = 1e4;
|
|
12479
12576
|
var LOCK_RETRY_OPTS = {
|
|
12480
12577
|
retries: {
|
|
@@ -12503,7 +12600,7 @@ async function acquireLock(dir) {
|
|
|
12503
12600
|
}
|
|
12504
12601
|
function resolveQuotaPath(directory, scope = "skill-improver") {
|
|
12505
12602
|
const fileName = scope === "knowledge-enrichment" ? "knowledge-enrichment-quota.json" : "skill-improver-quota.json";
|
|
12506
|
-
return
|
|
12603
|
+
return path22.join(directory, ".swarm", fileName);
|
|
12507
12604
|
}
|
|
12508
12605
|
function todayKey(window, now = new Date) {
|
|
12509
12606
|
if (window === "utc") {
|
|
@@ -12529,7 +12626,7 @@ async function readState(filePath) {
|
|
|
12529
12626
|
}
|
|
12530
12627
|
}
|
|
12531
12628
|
async function writeState(filePath, state) {
|
|
12532
|
-
await mkdir5(
|
|
12629
|
+
await mkdir5(path22.dirname(filePath), { recursive: true });
|
|
12533
12630
|
const tmp = `${filePath}.tmp-${process.pid}`;
|
|
12534
12631
|
await writeFile4(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
12535
12632
|
await rename2(tmp, filePath);
|
|
@@ -12552,10 +12649,10 @@ async function getQuotaState(directory, opts) {
|
|
|
12552
12649
|
}
|
|
12553
12650
|
async function reserveQuota(directory, opts) {
|
|
12554
12651
|
const filePath = resolveQuotaPath(directory, opts.scope);
|
|
12555
|
-
await mkdir5(
|
|
12652
|
+
await mkdir5(path22.dirname(filePath), { recursive: true });
|
|
12556
12653
|
let release = null;
|
|
12557
12654
|
try {
|
|
12558
|
-
release = await acquireLock(
|
|
12655
|
+
release = await acquireLock(path22.dirname(filePath));
|
|
12559
12656
|
const state = await getQuotaState(directory, opts);
|
|
12560
12657
|
if (state.calls_used + opts.nCalls > opts.maxCalls) {
|
|
12561
12658
|
return {
|
|
@@ -12582,10 +12679,10 @@ async function reserveQuota(directory, opts) {
|
|
|
12582
12679
|
}
|
|
12583
12680
|
async function releaseQuota(directory, opts) {
|
|
12584
12681
|
const filePath = resolveQuotaPath(directory, opts.scope);
|
|
12585
|
-
await mkdir5(
|
|
12682
|
+
await mkdir5(path22.dirname(filePath), { recursive: true });
|
|
12586
12683
|
let release = null;
|
|
12587
12684
|
try {
|
|
12588
|
-
release = await acquireLock(
|
|
12685
|
+
release = await acquireLock(path22.dirname(filePath));
|
|
12589
12686
|
const state = await getQuotaState(directory, opts);
|
|
12590
12687
|
const next = {
|
|
12591
12688
|
...state,
|
|
@@ -12609,7 +12706,7 @@ init_logger();
|
|
|
12609
12706
|
// src/hooks/skill-usage-log.ts
|
|
12610
12707
|
import * as crypto3 from "crypto";
|
|
12611
12708
|
import * as fs9 from "fs";
|
|
12612
|
-
import * as
|
|
12709
|
+
import * as path23 from "path";
|
|
12613
12710
|
function resolveLogPath(directory) {
|
|
12614
12711
|
return validateSwarmPath(directory, "skill-usage.jsonl");
|
|
12615
12712
|
}
|
|
@@ -12708,7 +12805,7 @@ function appendFeedbackAppliedMarker(directory, processedEntryIds) {
|
|
|
12708
12805
|
if (processedEntryIds.length === 0)
|
|
12709
12806
|
return;
|
|
12710
12807
|
const resolved = resolveLogPath(directory);
|
|
12711
|
-
const dir =
|
|
12808
|
+
const dir = path23.dirname(resolved);
|
|
12712
12809
|
if (!_internals15.existsSync(dir)) {
|
|
12713
12810
|
_internals15.mkdirSync(dir, { recursive: true });
|
|
12714
12811
|
}
|
|
@@ -12753,7 +12850,7 @@ function appendSkillUsageEntry(directory, entry) {
|
|
|
12753
12850
|
throw new Error("sessionID is required and must be a non-empty string");
|
|
12754
12851
|
}
|
|
12755
12852
|
const resolved = validateSwarmPath(directory, "skill-usage.jsonl");
|
|
12756
|
-
const dir =
|
|
12853
|
+
const dir = path23.dirname(resolved);
|
|
12757
12854
|
if (!_internals15.existsSync(dir)) {
|
|
12758
12855
|
_internals15.mkdirSync(dir, { recursive: true });
|
|
12759
12856
|
}
|
|
@@ -12929,8 +13026,8 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
12929
13026
|
}
|
|
12930
13027
|
if (entries.length === 0) {
|
|
12931
13028
|
if (preservedMarkers.length > 0) {
|
|
12932
|
-
const dir2 =
|
|
12933
|
-
const tmpPath2 =
|
|
13029
|
+
const dir2 = path23.dirname(resolved);
|
|
13030
|
+
const tmpPath2 = path23.join(dir2, `skill-usage-${Date.now()}.tmp`);
|
|
12934
13031
|
const content2 = preservedMarkers.join(`
|
|
12935
13032
|
`).concat(preservedMarkers.length > 0 ? `
|
|
12936
13033
|
` : "");
|
|
@@ -12972,8 +13069,8 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
12972
13069
|
if (pruned === 0) {
|
|
12973
13070
|
return { pruned: 0, remaining: entries.length };
|
|
12974
13071
|
}
|
|
12975
|
-
const dir =
|
|
12976
|
-
const tmpPath =
|
|
13072
|
+
const dir = path23.dirname(resolved);
|
|
13073
|
+
const tmpPath = path23.join(dir, `skill-usage-${Date.now()}.tmp`);
|
|
12977
13074
|
const entryLines = surviving.map((e) => JSON.stringify(e));
|
|
12978
13075
|
const allLines = [...entryLines, ...preservedMarkers];
|
|
12979
13076
|
const content = allLines.join(`
|
|
@@ -13002,9 +13099,9 @@ async function resolveSourceKnowledgeIds(directory, skillPath) {
|
|
|
13002
13099
|
if (/\.\.[/\\]/.test(cleanPath)) {
|
|
13003
13100
|
return [];
|
|
13004
13101
|
}
|
|
13005
|
-
const absolute =
|
|
13006
|
-
const baseDir =
|
|
13007
|
-
const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir +
|
|
13102
|
+
const absolute = path23.normalize(path23.isAbsolute(cleanPath) ? cleanPath : path23.resolve(directory, cleanPath));
|
|
13103
|
+
const baseDir = path23.normalize(path23.resolve(directory));
|
|
13104
|
+
const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir + path23.sep).toLowerCase()) : absolute.startsWith(baseDir + path23.sep);
|
|
13008
13105
|
if (!isContained) {
|
|
13009
13106
|
return [];
|
|
13010
13107
|
}
|
|
@@ -13316,7 +13413,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
13316
13413
|
schema_version: 1,
|
|
13317
13414
|
created_at: new Date().toISOString(),
|
|
13318
13415
|
updated_at: new Date().toISOString(),
|
|
13319
|
-
source_project:
|
|
13416
|
+
source_project: path24.basename(directory) || "unknown",
|
|
13320
13417
|
encounter_score: 1
|
|
13321
13418
|
};
|
|
13322
13419
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
@@ -13370,7 +13467,7 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
13370
13467
|
import { createHash as createHash4 } from "crypto";
|
|
13371
13468
|
import { existsSync as existsSync13 } from "fs";
|
|
13372
13469
|
import { appendFile as appendFile3, mkdir as mkdir7, readFile as readFile8, writeFile as writeFile7 } from "fs/promises";
|
|
13373
|
-
import * as
|
|
13470
|
+
import * as path29 from "path";
|
|
13374
13471
|
|
|
13375
13472
|
// src/services/synonym-map.ts
|
|
13376
13473
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
@@ -13382,7 +13479,7 @@ import {
|
|
|
13382
13479
|
unlink as unlink2,
|
|
13383
13480
|
writeFile as writeFile5
|
|
13384
13481
|
} from "fs/promises";
|
|
13385
|
-
import * as
|
|
13482
|
+
import * as path25 from "path";
|
|
13386
13483
|
var SYNONYM_MAP_FILENAME = "synonym-map.json";
|
|
13387
13484
|
var MAX_TOKEN_LENGTH = 64;
|
|
13388
13485
|
var DEFAULT_MAX_PAIRS = 500;
|
|
@@ -13537,7 +13634,7 @@ async function readSynonymMap(directory, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
|
13537
13634
|
}
|
|
13538
13635
|
}
|
|
13539
13636
|
async function writeSynonymMapAtomic(filePath, map) {
|
|
13540
|
-
await mkdir6(
|
|
13637
|
+
await mkdir6(path25.dirname(filePath), { recursive: true });
|
|
13541
13638
|
const tmp = `${filePath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
13542
13639
|
try {
|
|
13543
13640
|
await writeFile5(tmp, JSON.stringify(map, null, 2), "utf-8");
|
|
@@ -13550,7 +13647,7 @@ async function writeSynonymMapAtomic(filePath, map) {
|
|
|
13550
13647
|
}
|
|
13551
13648
|
async function rebuildSynonymMap(directory, entries, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
13552
13649
|
const filePath = resolveSynonymMapPath(directory);
|
|
13553
|
-
const dir =
|
|
13650
|
+
const dir = path25.dirname(filePath);
|
|
13554
13651
|
await mkdir6(dir, { recursive: true });
|
|
13555
13652
|
let release = null;
|
|
13556
13653
|
try {
|
|
@@ -13615,17 +13712,17 @@ function reinforceSwarmKnowledgeEntry(entry, confirmation) {
|
|
|
13615
13712
|
// src/hooks/micro-reflector.ts
|
|
13616
13713
|
import { existsSync as existsSync12 } from "fs";
|
|
13617
13714
|
import { readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
13618
|
-
import * as
|
|
13715
|
+
import * as path28 from "path";
|
|
13619
13716
|
init_logger();
|
|
13620
13717
|
|
|
13621
13718
|
// src/hooks/skill-propagation-gate.ts
|
|
13622
13719
|
import * as fs11 from "fs";
|
|
13623
|
-
import * as
|
|
13720
|
+
import * as path27 from "path";
|
|
13624
13721
|
init_logger();
|
|
13625
13722
|
|
|
13626
13723
|
// src/hooks/skill-scoring.ts
|
|
13627
13724
|
import * as fs10 from "fs";
|
|
13628
|
-
import * as
|
|
13725
|
+
import * as path26 from "path";
|
|
13629
13726
|
var FREQUENCY_CAP = 10;
|
|
13630
13727
|
var FREQUENCY_WEIGHT = 0.3;
|
|
13631
13728
|
var COMPLIANCE_WEIGHT = 0.3;
|
|
@@ -13653,10 +13750,10 @@ var _internals16 = {
|
|
|
13653
13750
|
computeTriggerMatchBoost: null
|
|
13654
13751
|
};
|
|
13655
13752
|
function extractSkillName(skillPath) {
|
|
13656
|
-
const base =
|
|
13753
|
+
const base = path26.basename(skillPath, path26.extname(skillPath));
|
|
13657
13754
|
if (base !== "SKILL")
|
|
13658
13755
|
return base;
|
|
13659
|
-
const parent =
|
|
13756
|
+
const parent = path26.basename(path26.dirname(skillPath));
|
|
13660
13757
|
return parent;
|
|
13661
13758
|
}
|
|
13662
13759
|
function stripQuotes(value) {
|
|
@@ -13811,12 +13908,12 @@ function readSkillMetadata(skillPath, directory) {
|
|
|
13811
13908
|
const normalizedPath = skillPath.replace(/^file:/, "").replace(/\\/g, "/");
|
|
13812
13909
|
const fallback = parseSkillFrontmatter("", normalizedPath);
|
|
13813
13910
|
try {
|
|
13814
|
-
if (
|
|
13911
|
+
if (path26.isAbsolute(normalizedPath) || normalizedPath.split("/").includes("..")) {
|
|
13815
13912
|
return fallback;
|
|
13816
13913
|
}
|
|
13817
|
-
const root =
|
|
13818
|
-
const absolutePath =
|
|
13819
|
-
if (absolutePath !== root && !absolutePath.startsWith(root +
|
|
13914
|
+
const root = path26.resolve(directory);
|
|
13915
|
+
const absolutePath = path26.resolve(directory, normalizedPath);
|
|
13916
|
+
if (absolutePath !== root && !absolutePath.startsWith(root + path26.sep)) {
|
|
13820
13917
|
return fallback;
|
|
13821
13918
|
}
|
|
13822
13919
|
const content = readFilePrefix(absolutePath);
|
|
@@ -13950,7 +14047,7 @@ function getSkillStats(skillPath, directory) {
|
|
|
13950
14047
|
};
|
|
13951
14048
|
}
|
|
13952
14049
|
function formatSkillIndexWithContext(skills, directory) {
|
|
13953
|
-
const usageLogPath =
|
|
14050
|
+
const usageLogPath = path26.join(directory, ".swarm", "skill-usage.jsonl");
|
|
13954
14051
|
let hasHistory = false;
|
|
13955
14052
|
try {
|
|
13956
14053
|
const stat5 = fs10.statSync(usageLogPath);
|
|
@@ -14084,7 +14181,7 @@ function parseYamlValue(value) {
|
|
|
14084
14181
|
return trimmed;
|
|
14085
14182
|
}
|
|
14086
14183
|
function loadRoutingSkills(directory, targetAgent) {
|
|
14087
|
-
const routingPath =
|
|
14184
|
+
const routingPath = path27.join(directory, ".opencode", "skill-routing.yaml");
|
|
14088
14185
|
if (!_internals17.existsSync(routingPath))
|
|
14089
14186
|
return [];
|
|
14090
14187
|
try {
|
|
@@ -14144,7 +14241,7 @@ var _internals17 = {
|
|
|
14144
14241
|
function discoverAvailableSkills(directory) {
|
|
14145
14242
|
const results = [];
|
|
14146
14243
|
for (const root of SKILL_SEARCH_ROOTS) {
|
|
14147
|
-
const rootPath =
|
|
14244
|
+
const rootPath = path27.join(directory, root);
|
|
14148
14245
|
if (!_internals17.existsSync(rootPath))
|
|
14149
14246
|
continue;
|
|
14150
14247
|
let entries;
|
|
@@ -14156,13 +14253,13 @@ function discoverAvailableSkills(directory) {
|
|
|
14156
14253
|
for (const entry of entries) {
|
|
14157
14254
|
if (entry.startsWith("."))
|
|
14158
14255
|
continue;
|
|
14159
|
-
const skillDir =
|
|
14160
|
-
if (_internals17.existsSync(
|
|
14256
|
+
const skillDir = path27.join(rootPath, entry);
|
|
14257
|
+
if (_internals17.existsSync(path27.join(skillDir, "retired.marker")) || _internals17.existsSync(path27.join(skillDir, "stale.marker")))
|
|
14161
14258
|
continue;
|
|
14162
|
-
const skillFile =
|
|
14259
|
+
const skillFile = path27.join(skillDir, "SKILL.md");
|
|
14163
14260
|
try {
|
|
14164
14261
|
if (_internals17.statSync(skillDir).isDirectory() && _internals17.existsSync(skillFile)) {
|
|
14165
|
-
results.push(
|
|
14262
|
+
results.push(path27.join(root, entry, "SKILL.md").replace(/\\/g, "/"));
|
|
14166
14263
|
}
|
|
14167
14264
|
} catch (err) {
|
|
14168
14265
|
warn(`[skill-propagation-gate] failed to stat skill directory ${entry}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -14231,9 +14328,9 @@ function extractSkillsFieldFromPrompt(prompt) {
|
|
|
14231
14328
|
return "";
|
|
14232
14329
|
}
|
|
14233
14330
|
function writeWarnEvent(directory, record) {
|
|
14234
|
-
const filePath =
|
|
14331
|
+
const filePath = path27.join(directory, ".swarm", "events.jsonl");
|
|
14235
14332
|
try {
|
|
14236
|
-
const dir =
|
|
14333
|
+
const dir = path27.dirname(filePath);
|
|
14237
14334
|
if (!_internals17.existsSync(dir)) {
|
|
14238
14335
|
_internals17.mkdirSync(dir, { recursive: true });
|
|
14239
14336
|
}
|
|
@@ -14362,8 +14459,8 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
14362
14459
|
if (routingPaths.length > 0) {
|
|
14363
14460
|
const existingPaths = new Set(scored.map((s) => s.skillPath));
|
|
14364
14461
|
for (const routingPath of routingPaths) {
|
|
14365
|
-
const routedSkillDir =
|
|
14366
|
-
if (_internals17.existsSync(
|
|
14462
|
+
const routedSkillDir = path27.dirname(path27.join(directory, routingPath));
|
|
14463
|
+
if (_internals17.existsSync(path27.join(routedSkillDir, "retired.marker")) || _internals17.existsSync(path27.join(routedSkillDir, "stale.marker")))
|
|
14367
14464
|
continue;
|
|
14368
14465
|
if (!existingPaths.has(routingPath)) {
|
|
14369
14466
|
scored.push({
|
|
@@ -14382,8 +14479,8 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
14382
14479
|
let skillsForIndex = availableSkills;
|
|
14383
14480
|
if (scoringSkipped) {
|
|
14384
14481
|
skillsForIndex = [...availableSkills].sort((a, b) => {
|
|
14385
|
-
const nameA =
|
|
14386
|
-
const nameB =
|
|
14482
|
+
const nameA = path27.basename(path27.dirname(a));
|
|
14483
|
+
const nameB = path27.basename(path27.dirname(b));
|
|
14387
14484
|
return nameA.localeCompare(nameB);
|
|
14388
14485
|
});
|
|
14389
14486
|
} else if (typeof scored !== "undefined" && scored.length > 0) {
|
|
@@ -14391,7 +14488,7 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
14391
14488
|
}
|
|
14392
14489
|
const formattedIndex = _internals17.formatSkillIndexWithContext(skillsForIndex, directory);
|
|
14393
14490
|
if (formattedIndex.length > 0) {
|
|
14394
|
-
const contextPath =
|
|
14491
|
+
const contextPath = path27.join(directory, ".swarm", "context.md");
|
|
14395
14492
|
let existingContent = "";
|
|
14396
14493
|
if (_internals17.existsSync(contextPath)) {
|
|
14397
14494
|
existingContent = _internals17.readFileSync(contextPath, "utf-8");
|
|
@@ -14413,7 +14510,7 @@ ${newSection}`;
|
|
|
14413
14510
|
updatedContent = existingContent + newSection;
|
|
14414
14511
|
}
|
|
14415
14512
|
}
|
|
14416
|
-
const swarmDir =
|
|
14513
|
+
const swarmDir = path27.dirname(contextPath);
|
|
14417
14514
|
if (!_internals17.existsSync(swarmDir)) {
|
|
14418
14515
|
_internals17.mkdirSync(swarmDir, { recursive: true });
|
|
14419
14516
|
}
|
|
@@ -14639,7 +14736,7 @@ function resolveInsightCandidatesPath(directory) {
|
|
|
14639
14736
|
}
|
|
14640
14737
|
async function readTaskTrajectory(directory, taskId) {
|
|
14641
14738
|
try {
|
|
14642
|
-
const rel =
|
|
14739
|
+
const rel = path28.join("evidence", sanitizeTaskId(taskId), "trajectory.jsonl");
|
|
14643
14740
|
const filePath = validateSwarmPath(directory, rel);
|
|
14644
14741
|
if (!existsSync12(filePath))
|
|
14645
14742
|
return [];
|
|
@@ -15069,8 +15166,8 @@ RETRY: your last output was missing ${result.missing.join("; ")}; produce valid
|
|
|
15069
15166
|
}
|
|
15070
15167
|
async function appendCuratorSkippedEvent(directory, record) {
|
|
15071
15168
|
try {
|
|
15072
|
-
const filePath =
|
|
15073
|
-
await mkdir7(
|
|
15169
|
+
const filePath = path29.join(directory, ".swarm", "events.jsonl");
|
|
15170
|
+
await mkdir7(path29.dirname(filePath), { recursive: true });
|
|
15074
15171
|
await appendFile3(filePath, `${JSON.stringify({
|
|
15075
15172
|
timestamp: new Date().toISOString(),
|
|
15076
15173
|
event: "curator_skipped",
|
|
@@ -15597,7 +15694,7 @@ var _internals19 = {
|
|
|
15597
15694
|
|
|
15598
15695
|
// src/services/session-reflection.ts
|
|
15599
15696
|
import { promises as fs12 } from "fs";
|
|
15600
|
-
import * as
|
|
15697
|
+
import * as path30 from "path";
|
|
15601
15698
|
|
|
15602
15699
|
// src/hooks/skill-improver-llm-factory.ts
|
|
15603
15700
|
function resolveSkillImproverAgentName(sessionId) {
|
|
@@ -15750,11 +15847,11 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
15750
15847
|
const lessons = [];
|
|
15751
15848
|
const taxonomy = {};
|
|
15752
15849
|
try {
|
|
15753
|
-
const evidenceDir =
|
|
15850
|
+
const evidenceDir = path30.join(directory, ".swarm", "evidence");
|
|
15754
15851
|
const entries = await fs12.readdir(evidenceDir);
|
|
15755
15852
|
const retroDirs = entries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
15756
15853
|
for (const retroDir of retroDirs) {
|
|
15757
|
-
const evidencePath =
|
|
15854
|
+
const evidencePath = path30.join(evidenceDir, retroDir, "evidence.json");
|
|
15758
15855
|
try {
|
|
15759
15856
|
const content = await fs12.readFile(evidencePath, "utf-8");
|
|
15760
15857
|
const parsed = JSON.parse(content);
|
|
@@ -15783,12 +15880,12 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
15783
15880
|
async function gatherGateFailures(directory) {
|
|
15784
15881
|
const failures = new Map;
|
|
15785
15882
|
try {
|
|
15786
|
-
const evidenceDir =
|
|
15883
|
+
const evidenceDir = path30.join(directory, ".swarm", "evidence");
|
|
15787
15884
|
const entries = await fs12.readdir(evidenceDir);
|
|
15788
15885
|
for (const entry of entries) {
|
|
15789
15886
|
if (entry.startsWith("retro-"))
|
|
15790
15887
|
continue;
|
|
15791
|
-
const evidencePath =
|
|
15888
|
+
const evidencePath = path30.join(evidenceDir, entry, "evidence.json");
|
|
15792
15889
|
try {
|
|
15793
15890
|
const content = await fs12.readFile(evidencePath, "utf-8");
|
|
15794
15891
|
const parsed = JSON.parse(content);
|
|
@@ -15989,12 +16086,12 @@ async function writeSessionReflection(directory, result) {
|
|
|
15989
16086
|
// src/services/skill-improver.ts
|
|
15990
16087
|
import { existsSync as existsSync15 } from "fs";
|
|
15991
16088
|
import { mkdir as mkdir9, readFile as readFile9, rename as rename4, writeFile as writeFile9 } from "fs/promises";
|
|
15992
|
-
import * as
|
|
16089
|
+
import * as path32 from "path";
|
|
15993
16090
|
init_logger();
|
|
15994
16091
|
|
|
15995
16092
|
// src/services/trajectory-cluster.ts
|
|
15996
16093
|
import { mkdir as mkdir8, writeFile as writeFile8 } from "fs/promises";
|
|
15997
|
-
import * as
|
|
16094
|
+
import * as path31 from "path";
|
|
15998
16095
|
init_logger();
|
|
15999
16096
|
var MACRO_TRAJECTORY_WINDOW = 200;
|
|
16000
16097
|
var MOTIF_MIN_TASKS = 2;
|
|
@@ -16126,11 +16223,11 @@ async function writeMotifProposals(directory, opts = {}) {
|
|
|
16126
16223
|
if (motifs.length === 0)
|
|
16127
16224
|
return result;
|
|
16128
16225
|
const max = opts.maxProposals ?? 10;
|
|
16129
|
-
const proposalsDir = validateSwarmPath(directory,
|
|
16226
|
+
const proposalsDir = validateSwarmPath(directory, path31.join("skills", "proposals"));
|
|
16130
16227
|
await mkdir8(proposalsDir, { recursive: true });
|
|
16131
16228
|
for (const motif of motifs.slice(0, max)) {
|
|
16132
16229
|
const slug = `motif-${slugify(motif.signature)}`;
|
|
16133
|
-
const filePath =
|
|
16230
|
+
const filePath = path31.join(proposalsDir, `${slug}.md`);
|
|
16134
16231
|
await writeFile8(filePath, buildMotifProposal(motif), "utf-8");
|
|
16135
16232
|
result.proposalsWritten.push(filePath);
|
|
16136
16233
|
}
|
|
@@ -16271,11 +16368,11 @@ async function writeSuccessMotifProposals(directory, opts = {}) {
|
|
|
16271
16368
|
if (motifs.length === 0)
|
|
16272
16369
|
return result;
|
|
16273
16370
|
const max = opts.maxProposals ?? 10;
|
|
16274
|
-
const proposalsDir = validateSwarmPath(directory,
|
|
16371
|
+
const proposalsDir = validateSwarmPath(directory, path31.join("skills", "proposals"));
|
|
16275
16372
|
await mkdir8(proposalsDir, { recursive: true });
|
|
16276
16373
|
for (const motif of motifs.slice(0, max)) {
|
|
16277
16374
|
const slug = workflowSlug(motif.signature);
|
|
16278
|
-
const filePath =
|
|
16375
|
+
const filePath = path31.join(proposalsDir, `${slug}.md`);
|
|
16279
16376
|
await writeFile8(filePath, buildWorkflowProposal(motif), "utf-8");
|
|
16280
16377
|
result.proposalsWritten.push(filePath);
|
|
16281
16378
|
}
|
|
@@ -16398,7 +16495,7 @@ function timestampSlug(d) {
|
|
|
16398
16495
|
return d.toISOString().replace(/[:.]/g, "-");
|
|
16399
16496
|
}
|
|
16400
16497
|
async function atomicWrite(p, content) {
|
|
16401
|
-
await mkdir9(
|
|
16498
|
+
await mkdir9(path32.dirname(p), { recursive: true });
|
|
16402
16499
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
16403
16500
|
await writeFile9(tmp, content, "utf-8");
|
|
16404
16501
|
await rename4(tmp, p);
|
|
@@ -16801,8 +16898,8 @@ async function runSkillImprover(req) {
|
|
|
16801
16898
|
}
|
|
16802
16899
|
throw err;
|
|
16803
16900
|
}
|
|
16804
|
-
const proposalDir =
|
|
16805
|
-
const proposalFile =
|
|
16901
|
+
const proposalDir = path32.join(req.directory, ".swarm", "skill-improver", "proposals");
|
|
16902
|
+
const proposalFile = path32.join(proposalDir, `${timestampSlug(now)}.md`);
|
|
16806
16903
|
const finalBody = source === "llm" ? buildLLMProposalFrame({
|
|
16807
16904
|
body,
|
|
16808
16905
|
targets,
|
|
@@ -17288,8 +17385,8 @@ async function copyDirRecursiveWithFailures(src, dest) {
|
|
|
17288
17385
|
const entries = await fs13.readdir(src);
|
|
17289
17386
|
await fs13.mkdir(dest, { recursive: true });
|
|
17290
17387
|
for (const entry of entries) {
|
|
17291
|
-
const srcEntry =
|
|
17292
|
-
const destEntry =
|
|
17388
|
+
const srcEntry = path33.join(src, entry);
|
|
17389
|
+
const destEntry = path33.join(dest, entry);
|
|
17293
17390
|
try {
|
|
17294
17391
|
const stat5 = await fs13.stat(srcEntry);
|
|
17295
17392
|
if (stat5.isDirectory()) {
|
|
@@ -17474,18 +17571,18 @@ async function runFinalizeStage(ctx) {
|
|
|
17474
17571
|
ctx.warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
17475
17572
|
}
|
|
17476
17573
|
}
|
|
17477
|
-
const lessonsFilePath =
|
|
17574
|
+
const lessonsFilePath = path33.join(ctx.swarmDir, "close-lessons.md");
|
|
17478
17575
|
try {
|
|
17479
17576
|
const lessonsText = await fs13.readFile(lessonsFilePath, "utf-8");
|
|
17480
17577
|
ctx.explicitLessons = lessonsText.split(`
|
|
17481
17578
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
17482
17579
|
} catch {}
|
|
17483
17580
|
try {
|
|
17484
|
-
const evidenceDir =
|
|
17581
|
+
const evidenceDir = path33.join(ctx.swarmDir, "evidence");
|
|
17485
17582
|
const evidenceEntries = await fs13.readdir(evidenceDir);
|
|
17486
17583
|
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
17487
17584
|
for (const retroDir of retroDirs) {
|
|
17488
|
-
const evidencePath =
|
|
17585
|
+
const evidencePath = path33.join(evidenceDir, retroDir, "evidence.json");
|
|
17489
17586
|
try {
|
|
17490
17587
|
const content = await fs13.readFile(evidencePath, "utf-8");
|
|
17491
17588
|
const parsed = JSON.parse(content);
|
|
@@ -17667,7 +17764,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
17667
17764
|
let checkpointVerified = false;
|
|
17668
17765
|
try {
|
|
17669
17766
|
const result = spawnSync5("sqlite3", [srcPath, "PRAGMA wal_checkpoint(TRUNCATE);"], {
|
|
17670
|
-
cwd:
|
|
17767
|
+
cwd: path33.dirname(srcPath),
|
|
17671
17768
|
encoding: "utf-8",
|
|
17672
17769
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17673
17770
|
timeout: 1e4,
|
|
@@ -17735,7 +17832,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
17735
17832
|
async function runArchiveStage(ctx) {
|
|
17736
17833
|
ctx.timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
17737
17834
|
ctx.archiveSuffix = Math.random().toString(36).slice(2, 8);
|
|
17738
|
-
ctx.archiveDir =
|
|
17835
|
+
ctx.archiveDir = path33.join(ctx.swarmDir, "archive", `swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);
|
|
17739
17836
|
try {
|
|
17740
17837
|
await fs13.mkdir(ctx.archiveDir, { recursive: true });
|
|
17741
17838
|
const WAL_SIDECAR_FILES = new Set(["swarm.db-shm", "swarm.db-wal"]);
|
|
@@ -17750,8 +17847,8 @@ async function runArchiveStage(ctx) {
|
|
|
17750
17847
|
if (linkedKnowledgeShared && KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact)) {
|
|
17751
17848
|
continue;
|
|
17752
17849
|
}
|
|
17753
|
-
const srcPath =
|
|
17754
|
-
const destPath =
|
|
17850
|
+
const srcPath = path33.join(ctx.swarmDir, artifact);
|
|
17851
|
+
const destPath = path33.join(ctx.archiveDir, artifact);
|
|
17755
17852
|
if (artifact === "swarm.db") {
|
|
17756
17853
|
const result = await copySqliteSafe(srcPath, destPath);
|
|
17757
17854
|
if (result.skipped) {} else if (result.success) {
|
|
@@ -17783,8 +17880,8 @@ async function runArchiveStage(ctx) {
|
|
|
17783
17880
|
}
|
|
17784
17881
|
}
|
|
17785
17882
|
for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
|
|
17786
|
-
const srcDir =
|
|
17787
|
-
const destDir =
|
|
17883
|
+
const srcDir = path33.join(ctx.swarmDir, dirName);
|
|
17884
|
+
const destDir = path33.join(ctx.archiveDir, dirName);
|
|
17788
17885
|
try {
|
|
17789
17886
|
const result = await copyDirRecursiveWithFailures(srcDir, destDir);
|
|
17790
17887
|
ctx.archivedFileCount += result.copied;
|
|
@@ -17861,7 +17958,7 @@ async function runCleanStage(ctx) {
|
|
|
17861
17958
|
ctx.warnings.push(reason ? `Preserved ${artifact} because it was not successfully archived: ${reason}.` : `Preserved ${artifact} because it was not successfully archived.`);
|
|
17862
17959
|
continue;
|
|
17863
17960
|
}
|
|
17864
|
-
const filePath =
|
|
17961
|
+
const filePath = path33.join(ctx.swarmDir, artifact);
|
|
17865
17962
|
try {
|
|
17866
17963
|
await fs13.unlink(filePath);
|
|
17867
17964
|
cleanedFiles.push(artifact);
|
|
@@ -17880,7 +17977,7 @@ async function runCleanStage(ctx) {
|
|
|
17880
17977
|
if (!ctx.archivedActiveStateDirs.has(dirName)) {
|
|
17881
17978
|
continue;
|
|
17882
17979
|
}
|
|
17883
|
-
const dirPath =
|
|
17980
|
+
const dirPath = path33.join(ctx.swarmDir, dirName);
|
|
17884
17981
|
try {
|
|
17885
17982
|
await fs13.rm(dirPath, { recursive: true, force: true });
|
|
17886
17983
|
cleanedFiles.push(`${dirName}/`);
|
|
@@ -17891,7 +17988,7 @@ async function runCleanStage(ctx) {
|
|
|
17891
17988
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
17892
17989
|
for (const backup of configBackups) {
|
|
17893
17990
|
try {
|
|
17894
|
-
await fs13.unlink(
|
|
17991
|
+
await fs13.unlink(path33.join(ctx.swarmDir, backup));
|
|
17895
17992
|
configBackupsRemoved++;
|
|
17896
17993
|
} catch (err) {
|
|
17897
17994
|
const errno = err?.code;
|
|
@@ -17904,7 +18001,7 @@ async function runCleanStage(ctx) {
|
|
|
17904
18001
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
17905
18002
|
for (const sibling of ledgerSiblings) {
|
|
17906
18003
|
try {
|
|
17907
|
-
await fs13.unlink(
|
|
18004
|
+
await fs13.unlink(path33.join(ctx.swarmDir, sibling));
|
|
17908
18005
|
} catch (err) {
|
|
17909
18006
|
const errno = err?.code;
|
|
17910
18007
|
if (errno === "ENOENT") {} else {
|
|
@@ -17922,12 +18019,12 @@ async function runCleanStage(ctx) {
|
|
|
17922
18019
|
}
|
|
17923
18020
|
let swarmPlanFilesRemoved = 0;
|
|
17924
18021
|
const candidates = [
|
|
17925
|
-
|
|
17926
|
-
|
|
17927
|
-
|
|
17928
|
-
|
|
17929
|
-
|
|
17930
|
-
|
|
18022
|
+
path33.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.json"),
|
|
18023
|
+
path33.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.md"),
|
|
18024
|
+
path33.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
18025
|
+
path33.join(ctx.directory, ".swarm", "SWARM_PLAN.md"),
|
|
18026
|
+
path33.join(ctx.directory, "SWARM_PLAN.json"),
|
|
18027
|
+
path33.join(ctx.directory, "SWARM_PLAN.md")
|
|
17931
18028
|
];
|
|
17932
18029
|
for (const candidate of candidates) {
|
|
17933
18030
|
try {
|
|
@@ -17945,7 +18042,7 @@ async function runCleanStage(ctx) {
|
|
|
17945
18042
|
const tmpFiles = swarmFiles.filter((f) => f.startsWith(".tmp."));
|
|
17946
18043
|
for (const tmp of tmpFiles) {
|
|
17947
18044
|
try {
|
|
17948
|
-
await fs13.unlink(
|
|
18045
|
+
await fs13.unlink(path33.join(ctx.swarmDir, tmp));
|
|
17949
18046
|
tmpFilesRemoved++;
|
|
17950
18047
|
} catch (err) {
|
|
17951
18048
|
const errno = err?.code;
|
|
@@ -17967,7 +18064,7 @@ async function runCleanStage(ctx) {
|
|
|
17967
18064
|
}
|
|
17968
18065
|
for (const terminalFile of TERMINAL_STATE_FILES) {
|
|
17969
18066
|
try {
|
|
17970
|
-
await fs13.unlink(
|
|
18067
|
+
await fs13.unlink(path33.join(ctx.swarmDir, terminalFile));
|
|
17971
18068
|
if (!cleanedFiles.includes(terminalFile)) {
|
|
17972
18069
|
cleanedFiles.push(terminalFile);
|
|
17973
18070
|
}
|
|
@@ -17980,7 +18077,7 @@ async function runCleanStage(ctx) {
|
|
|
17980
18077
|
}
|
|
17981
18078
|
}
|
|
17982
18079
|
clearAllScopes(ctx.directory);
|
|
17983
|
-
const contextPath =
|
|
18080
|
+
const contextPath = path33.join(ctx.swarmDir, "context.md");
|
|
17984
18081
|
const contextContent = [
|
|
17985
18082
|
"# Context",
|
|
17986
18083
|
"",
|
|
@@ -17992,7 +18089,7 @@ async function runCleanStage(ctx) {
|
|
|
17992
18089
|
""
|
|
17993
18090
|
].join(`
|
|
17994
18091
|
`);
|
|
17995
|
-
const contextTempPath =
|
|
18092
|
+
const contextTempPath = path33.join(path33.dirname(contextPath), `${path33.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
17996
18093
|
try {
|
|
17997
18094
|
await fs13.writeFile(contextTempPath, contextContent, "utf-8");
|
|
17998
18095
|
fsSync2.renameSync(contextTempPath, contextPath);
|
|
@@ -18056,7 +18153,7 @@ async function runAlignStage(ctx) {
|
|
|
18056
18153
|
return { gitAlignResult, prunedBranches };
|
|
18057
18154
|
}
|
|
18058
18155
|
async function handleCloseCommand(directory, args, options = {}) {
|
|
18059
|
-
const swarmDir =
|
|
18156
|
+
const swarmDir = path33.join(directory, ".swarm");
|
|
18060
18157
|
try {
|
|
18061
18158
|
const stat5 = fsSync2.lstatSync(swarmDir);
|
|
18062
18159
|
if (stat5.isSymbolicLink()) {
|
|
@@ -18070,7 +18167,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
18070
18167
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
18071
18168
|
let planExists = false;
|
|
18072
18169
|
let planData = {
|
|
18073
|
-
title:
|
|
18170
|
+
title: path33.basename(directory) || "Ad-hoc session",
|
|
18074
18171
|
phases: []
|
|
18075
18172
|
};
|
|
18076
18173
|
try {
|
|
@@ -18095,7 +18192,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
18095
18192
|
}
|
|
18096
18193
|
try {
|
|
18097
18194
|
if (!planExists) {
|
|
18098
|
-
const archiveDir =
|
|
18195
|
+
const archiveDir = path33.join(swarmDir, "archive");
|
|
18099
18196
|
try {
|
|
18100
18197
|
const archiveEntries = await fs13.readdir(archiveDir);
|
|
18101
18198
|
const hasArchiveBundle = archiveEntries.some((entry) => entry.startsWith("swarm-"));
|
|
@@ -18103,7 +18200,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
18103
18200
|
const hasActiveState = [
|
|
18104
18201
|
...ACTIVE_STATE_TO_CLEAN,
|
|
18105
18202
|
...ACTIVE_STATE_DIRS_TO_CLEAN
|
|
18106
|
-
].some((entry) => fsSync2.existsSync(
|
|
18203
|
+
].some((entry) => fsSync2.existsSync(path33.join(swarmDir, entry)));
|
|
18107
18204
|
if (!hasActiveState) {
|
|
18108
18205
|
return `\u2705 Already finalized \u2014 nothing to do.
|
|
18109
18206
|
|
|
@@ -18231,7 +18328,7 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
18231
18328
|
...ctx.warnings.length > 0 ? ["## Warnings", ...ctx.warnings.map((w) => `- ${w}`), ""] : []
|
|
18232
18329
|
].join(`
|
|
18233
18330
|
`);
|
|
18234
|
-
const closeSummaryTempPath =
|
|
18331
|
+
const closeSummaryTempPath = path33.join(path33.dirname(closeSummaryPath), `${path33.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
18235
18332
|
try {
|
|
18236
18333
|
await fs13.writeFile(closeSummaryTempPath, summaryContent, "utf-8");
|
|
18237
18334
|
fsSync2.renameSync(closeSummaryTempPath, closeSummaryPath);
|
|
@@ -18575,14 +18672,14 @@ function buildStatusMessage(session, plan) {
|
|
|
18575
18672
|
|
|
18576
18673
|
// src/commands/config.ts
|
|
18577
18674
|
import * as os9 from "os";
|
|
18578
|
-
import * as
|
|
18675
|
+
import * as path34 from "path";
|
|
18579
18676
|
function getUserConfigDir2() {
|
|
18580
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
18677
|
+
return process.env.XDG_CONFIG_HOME || path34.join(os9.homedir(), ".config");
|
|
18581
18678
|
}
|
|
18582
18679
|
async function handleConfigCommand(directory, _args) {
|
|
18583
18680
|
const config = loadPluginConfig(directory);
|
|
18584
|
-
const userConfigPath =
|
|
18585
|
-
const projectConfigPath =
|
|
18681
|
+
const userConfigPath = path34.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
18682
|
+
const projectConfigPath = path34.join(directory, ".opencode", "opencode-swarm.json");
|
|
18586
18683
|
const lines = [
|
|
18587
18684
|
"## Swarm Configuration",
|
|
18588
18685
|
"",
|
|
@@ -18602,7 +18699,7 @@ async function handleConfigCommand(directory, _args) {
|
|
|
18602
18699
|
// src/services/skill-consolidation.ts
|
|
18603
18700
|
import { existsSync as existsSync17 } from "fs";
|
|
18604
18701
|
import { mkdir as mkdir10, readFile as readFile10, rename as rename5, writeFile as writeFile10 } from "fs/promises";
|
|
18605
|
-
import * as
|
|
18702
|
+
import * as path35 from "path";
|
|
18606
18703
|
|
|
18607
18704
|
// src/utils/timeout.ts
|
|
18608
18705
|
async function withTimeout(promise, ms, timeoutError) {
|
|
@@ -18627,7 +18724,7 @@ var DEFAULT_CONSOLIDATION_MAX_CALLS_PER_RUN = 1;
|
|
|
18627
18724
|
var CONSOLIDATION_RUN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
18628
18725
|
var runningByDirectory = new Map;
|
|
18629
18726
|
function consolidationStatePath(directory) {
|
|
18630
|
-
return
|
|
18727
|
+
return path35.join(directory, ".swarm", "skill-improver", "consolidation-state.json");
|
|
18631
18728
|
}
|
|
18632
18729
|
async function readState2(directory) {
|
|
18633
18730
|
const filePath = consolidationStatePath(directory);
|
|
@@ -18643,7 +18740,7 @@ async function readState2(directory) {
|
|
|
18643
18740
|
}
|
|
18644
18741
|
}
|
|
18645
18742
|
async function atomicWrite2(filePath, content) {
|
|
18646
|
-
await mkdir10(
|
|
18743
|
+
await mkdir10(path35.dirname(filePath), { recursive: true });
|
|
18647
18744
|
const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
18648
18745
|
await writeFile10(tmp, content, "utf-8");
|
|
18649
18746
|
await rename5(tmp, filePath);
|
|
@@ -18723,7 +18820,7 @@ async function runSkillConsolidationInner(req) {
|
|
|
18723
18820
|
};
|
|
18724
18821
|
}
|
|
18725
18822
|
async function runSkillConsolidation(req) {
|
|
18726
|
-
const key =
|
|
18823
|
+
const key = path35.resolve(req.directory);
|
|
18727
18824
|
const existing = runningByDirectory.get(key);
|
|
18728
18825
|
if (existing) {
|
|
18729
18826
|
return {
|
|
@@ -18925,7 +19022,7 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
18925
19022
|
// src/commands/coupling.ts
|
|
18926
19023
|
import { randomBytes } from "crypto";
|
|
18927
19024
|
import * as fs14 from "fs";
|
|
18928
|
-
import * as
|
|
19025
|
+
import * as path37 from "path";
|
|
18929
19026
|
|
|
18930
19027
|
// src/turbo/epic/cochange-source.ts
|
|
18931
19028
|
import * as child_process3 from "child_process";
|
|
@@ -18935,7 +19032,7 @@ import { promisify as promisify2 } from "util";
|
|
|
18935
19032
|
import * as child_process2 from "child_process";
|
|
18936
19033
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
18937
19034
|
import { readdir as readdir4, readFile as readFile11, stat as stat5 } from "fs/promises";
|
|
18938
|
-
import * as
|
|
19035
|
+
import * as path36 from "path";
|
|
18939
19036
|
import { promisify } from "util";
|
|
18940
19037
|
function getExecFileAsync() {
|
|
18941
19038
|
return promisify(child_process2.execFile);
|
|
@@ -19039,7 +19136,7 @@ async function scanSourceFiles(dir) {
|
|
|
19039
19136
|
try {
|
|
19040
19137
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
19041
19138
|
for (const entry of entries) {
|
|
19042
|
-
const fullPath =
|
|
19139
|
+
const fullPath = path36.join(dir, entry.name);
|
|
19043
19140
|
if (entry.isDirectory()) {
|
|
19044
19141
|
if (skipDirs.has(entry.name)) {
|
|
19045
19142
|
continue;
|
|
@@ -19047,7 +19144,7 @@ async function scanSourceFiles(dir) {
|
|
|
19047
19144
|
const subFiles = await scanSourceFiles(fullPath);
|
|
19048
19145
|
results.push(...subFiles);
|
|
19049
19146
|
} else if (entry.isFile()) {
|
|
19050
|
-
const ext =
|
|
19147
|
+
const ext = path36.extname(entry.name);
|
|
19051
19148
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
19052
19149
|
results.push(fullPath);
|
|
19053
19150
|
}
|
|
@@ -19069,8 +19166,8 @@ async function getStaticEdges(directory) {
|
|
|
19069
19166
|
continue;
|
|
19070
19167
|
}
|
|
19071
19168
|
try {
|
|
19072
|
-
const sourceDir =
|
|
19073
|
-
const resolvedPath =
|
|
19169
|
+
const sourceDir = path36.dirname(sourceFile);
|
|
19170
|
+
const resolvedPath = path36.resolve(sourceDir, importPath);
|
|
19074
19171
|
const extensions = [
|
|
19075
19172
|
"",
|
|
19076
19173
|
".ts",
|
|
@@ -19095,8 +19192,8 @@ async function getStaticEdges(directory) {
|
|
|
19095
19192
|
if (!targetFile) {
|
|
19096
19193
|
continue;
|
|
19097
19194
|
}
|
|
19098
|
-
const relSource =
|
|
19099
|
-
const relTarget =
|
|
19195
|
+
const relSource = path36.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
19196
|
+
const relTarget = path36.relative(directory, targetFile).replace(/\\/g, "/");
|
|
19100
19197
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
19101
19198
|
edges.add(key);
|
|
19102
19199
|
} catch {}
|
|
@@ -19108,7 +19205,7 @@ async function getStaticEdges(directory) {
|
|
|
19108
19205
|
function isTestImplementationPair(fileA, fileB) {
|
|
19109
19206
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
19110
19207
|
const getBaseName = (filePath) => {
|
|
19111
|
-
const base =
|
|
19208
|
+
const base = path36.basename(filePath);
|
|
19112
19209
|
for (const pattern of testPatterns) {
|
|
19113
19210
|
if (base.endsWith(pattern)) {
|
|
19114
19211
|
return base.slice(0, -pattern.length);
|
|
@@ -19118,16 +19215,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
19118
19215
|
};
|
|
19119
19216
|
const baseA = getBaseName(fileA);
|
|
19120
19217
|
const baseB = getBaseName(fileB);
|
|
19121
|
-
return baseA === baseB && baseA !==
|
|
19218
|
+
return baseA === baseB && baseA !== path36.basename(fileA) && baseA !== path36.basename(fileB);
|
|
19122
19219
|
}
|
|
19123
19220
|
function hasSharedPrefix(fileA, fileB) {
|
|
19124
|
-
const dirA =
|
|
19125
|
-
const dirB =
|
|
19221
|
+
const dirA = path36.dirname(fileA);
|
|
19222
|
+
const dirB = path36.dirname(fileB);
|
|
19126
19223
|
if (dirA !== dirB) {
|
|
19127
19224
|
return false;
|
|
19128
19225
|
}
|
|
19129
|
-
const baseA =
|
|
19130
|
-
const baseB =
|
|
19226
|
+
const baseA = path36.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
19227
|
+
const baseB = path36.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
19131
19228
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
19132
19229
|
return true;
|
|
19133
19230
|
}
|
|
@@ -19182,8 +19279,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
19182
19279
|
const entries = [];
|
|
19183
19280
|
const now = new Date().toISOString();
|
|
19184
19281
|
for (const pair of pairs.slice(0, 10)) {
|
|
19185
|
-
const baseA =
|
|
19186
|
-
const baseB =
|
|
19282
|
+
const baseA = path36.basename(pair.fileA);
|
|
19283
|
+
const baseB = path36.basename(pair.fileB);
|
|
19187
19284
|
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.`;
|
|
19188
19285
|
if (lesson.length > 280) {
|
|
19189
19286
|
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.`;
|
|
@@ -19609,9 +19706,9 @@ function parseArgs3(args) {
|
|
|
19609
19706
|
return parsed;
|
|
19610
19707
|
}
|
|
19611
19708
|
function persistReportJson(directory, report) {
|
|
19612
|
-
const epicDir =
|
|
19709
|
+
const epicDir = path37.join(directory, ".swarm", "epic");
|
|
19613
19710
|
fs14.mkdirSync(epicDir, { recursive: true });
|
|
19614
|
-
const filePath =
|
|
19711
|
+
const filePath = path37.join(epicDir, "coupling-report.json");
|
|
19615
19712
|
const tmpPath = `${filePath}.tmp.${randomBytes(8).toString("hex")}`;
|
|
19616
19713
|
fs14.writeFileSync(tmpPath, `${JSON.stringify(report, null, 2)}
|
|
19617
19714
|
`, "utf-8");
|
|
@@ -19670,7 +19767,7 @@ Usage: /swarm coupling [--phase <n>] [--threshold <-1..1>] [--min-co-changes <n>
|
|
|
19670
19767
|
persistStatus = {
|
|
19671
19768
|
requested: true,
|
|
19672
19769
|
written: true,
|
|
19673
|
-
path:
|
|
19770
|
+
path: path37.relative(directory, writtenAt)
|
|
19674
19771
|
};
|
|
19675
19772
|
} catch (err) {
|
|
19676
19773
|
persistStatus = {
|
|
@@ -19729,7 +19826,7 @@ function formatCurationSummary(summary) {
|
|
|
19729
19826
|
}
|
|
19730
19827
|
|
|
19731
19828
|
// src/commands/dark-matter.ts
|
|
19732
|
-
import
|
|
19829
|
+
import path38 from "path";
|
|
19733
19830
|
async function handleDarkMatterCommand(directory, args) {
|
|
19734
19831
|
const options = {};
|
|
19735
19832
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -19761,7 +19858,7 @@ Ensure this is a git repository with commit history.`;
|
|
|
19761
19858
|
const output = formatDarkMatterOutput(pairs);
|
|
19762
19859
|
if (pairs.length > 0) {
|
|
19763
19860
|
try {
|
|
19764
|
-
const projectName =
|
|
19861
|
+
const projectName = path38.basename(path38.resolve(directory));
|
|
19765
19862
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
19766
19863
|
if (entries.length > 0) {
|
|
19767
19864
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -20128,49 +20225,49 @@ ${USAGE5}`;
|
|
|
20128
20225
|
// src/services/diagnose-service.ts
|
|
20129
20226
|
import * as child_process4 from "child_process";
|
|
20130
20227
|
import { existsSync as existsSync20, readdirSync as readdirSync3, readFileSync as readFileSync10, statSync as statSync6 } from "fs";
|
|
20131
|
-
import
|
|
20228
|
+
import path40 from "path";
|
|
20132
20229
|
import { fileURLToPath } from "url";
|
|
20133
20230
|
|
|
20134
20231
|
// src/config/cache-paths.ts
|
|
20135
20232
|
import * as os10 from "os";
|
|
20136
|
-
import * as
|
|
20233
|
+
import * as path39 from "path";
|
|
20137
20234
|
function getPluginConfigDir() {
|
|
20138
|
-
return
|
|
20235
|
+
return path39.join(process.env.XDG_CONFIG_HOME || path39.join(os10.homedir(), ".config"), "opencode");
|
|
20139
20236
|
}
|
|
20140
20237
|
function getPluginCachePaths() {
|
|
20141
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
20238
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path39.join(os10.homedir(), ".cache");
|
|
20142
20239
|
const configDir = getPluginConfigDir();
|
|
20143
20240
|
const paths = [
|
|
20144
|
-
|
|
20145
|
-
|
|
20146
|
-
|
|
20241
|
+
path39.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
20242
|
+
path39.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
20243
|
+
path39.join(configDir, "node_modules", "opencode-swarm")
|
|
20147
20244
|
];
|
|
20148
20245
|
if (process.platform === "darwin") {
|
|
20149
|
-
const libCaches =
|
|
20150
|
-
paths.push(
|
|
20246
|
+
const libCaches = path39.join(os10.homedir(), "Library", "Caches");
|
|
20247
|
+
paths.push(path39.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path39.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
20151
20248
|
}
|
|
20152
20249
|
if (process.platform === "win32") {
|
|
20153
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
20154
|
-
const appData = process.env.APPDATA ||
|
|
20155
|
-
paths.push(
|
|
20250
|
+
const localAppData = process.env.LOCALAPPDATA || path39.join(os10.homedir(), "AppData", "Local");
|
|
20251
|
+
const appData = process.env.APPDATA || path39.join(os10.homedir(), "AppData", "Roaming");
|
|
20252
|
+
paths.push(path39.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path39.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path39.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
20156
20253
|
}
|
|
20157
20254
|
return paths;
|
|
20158
20255
|
}
|
|
20159
20256
|
function getPluginLockFilePaths() {
|
|
20160
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
20257
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path39.join(os10.homedir(), ".cache");
|
|
20161
20258
|
const configDir = getPluginConfigDir();
|
|
20162
20259
|
const paths = [
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
20260
|
+
path39.join(cacheBase, "opencode", "bun.lock"),
|
|
20261
|
+
path39.join(cacheBase, "opencode", "bun.lockb"),
|
|
20262
|
+
path39.join(configDir, "package-lock.json")
|
|
20166
20263
|
];
|
|
20167
20264
|
if (process.platform === "darwin") {
|
|
20168
|
-
const libCaches =
|
|
20169
|
-
paths.push(
|
|
20265
|
+
const libCaches = path39.join(os10.homedir(), "Library", "Caches");
|
|
20266
|
+
paths.push(path39.join(libCaches, "opencode", "bun.lock"), path39.join(libCaches, "opencode", "bun.lockb"));
|
|
20170
20267
|
}
|
|
20171
20268
|
if (process.platform === "win32") {
|
|
20172
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
20173
|
-
paths.push(
|
|
20269
|
+
const localAppData = process.env.LOCALAPPDATA || path39.join(os10.homedir(), "AppData", "Local");
|
|
20270
|
+
paths.push(path39.join(localAppData, "opencode", "bun.lock"), path39.join(localAppData, "opencode", "bun.lockb"));
|
|
20174
20271
|
}
|
|
20175
20272
|
return paths;
|
|
20176
20273
|
}
|
|
@@ -20186,24 +20283,24 @@ import { readFile as readFile12 } from "fs/promises";
|
|
|
20186
20283
|
// src/services/version-check.ts
|
|
20187
20284
|
import { existsSync as existsSync18, mkdirSync as mkdirSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
|
|
20188
20285
|
import { homedir as homedir6 } from "os";
|
|
20189
|
-
import { join as
|
|
20286
|
+
import { join as join33 } from "path";
|
|
20190
20287
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
20191
20288
|
var SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
20192
20289
|
var MAX_RESPONSE_BYTES = 256 * 1024;
|
|
20193
20290
|
function cacheDir() {
|
|
20194
20291
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
20195
|
-
const base = xdg && xdg.length > 0 ? xdg :
|
|
20196
|
-
return
|
|
20292
|
+
const base = xdg && xdg.length > 0 ? xdg : join33(homedir6(), ".cache");
|
|
20293
|
+
return join33(base, "opencode-swarm");
|
|
20197
20294
|
}
|
|
20198
20295
|
function cacheFile() {
|
|
20199
|
-
return
|
|
20296
|
+
return join33(cacheDir(), "version-check.json");
|
|
20200
20297
|
}
|
|
20201
20298
|
function readVersionCache() {
|
|
20202
20299
|
try {
|
|
20203
|
-
const
|
|
20204
|
-
if (!existsSync18(
|
|
20300
|
+
const path40 = cacheFile();
|
|
20301
|
+
if (!existsSync18(path40))
|
|
20205
20302
|
return null;
|
|
20206
|
-
const raw = readFileSync9(
|
|
20303
|
+
const raw = readFileSync9(path40, "utf-8");
|
|
20207
20304
|
const parsed = JSON.parse(raw);
|
|
20208
20305
|
if (typeof parsed?.checkedAt !== "number")
|
|
20209
20306
|
return null;
|
|
@@ -20458,7 +20555,7 @@ var REQUIRED_CACHE_GRAMMAR_ASSETS = [
|
|
|
20458
20555
|
"tree-sitter-typescript.wasm"
|
|
20459
20556
|
];
|
|
20460
20557
|
function resolveCachePackageRoot(cachePath) {
|
|
20461
|
-
const nestedPackageRoot =
|
|
20558
|
+
const nestedPackageRoot = path40.join(cachePath, "node_modules", "opencode-swarm");
|
|
20462
20559
|
return existsSync20(nestedPackageRoot) ? nestedPackageRoot : cachePath;
|
|
20463
20560
|
}
|
|
20464
20561
|
var _internals26 = {
|
|
@@ -20774,7 +20871,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
20774
20871
|
};
|
|
20775
20872
|
}
|
|
20776
20873
|
async function checkConfigParseability(directory) {
|
|
20777
|
-
const configPath =
|
|
20874
|
+
const configPath = path40.join(directory, ".opencode/opencode-swarm.json");
|
|
20778
20875
|
if (!existsSync20(configPath)) {
|
|
20779
20876
|
return {
|
|
20780
20877
|
name: "Config Parseability",
|
|
@@ -20803,7 +20900,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
20803
20900
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
20804
20901
|
const isSource = normalized.endsWith("/src/services");
|
|
20805
20902
|
const isCliBundle = normalized.endsWith("/cli");
|
|
20806
|
-
return isSource || isCliBundle ?
|
|
20903
|
+
return isSource || isCliBundle ? path40.join(thisDir, "..", "lang", "grammars") : path40.join(thisDir, "lang", "grammars");
|
|
20807
20904
|
}
|
|
20808
20905
|
async function checkGrammarWasmFiles() {
|
|
20809
20906
|
const grammarFiles = [
|
|
@@ -20827,14 +20924,14 @@ async function checkGrammarWasmFiles() {
|
|
|
20827
20924
|
"tree-sitter-ini.wasm",
|
|
20828
20925
|
"tree-sitter-regex.wasm"
|
|
20829
20926
|
];
|
|
20830
|
-
const thisDir =
|
|
20927
|
+
const thisDir = path40.dirname(fileURLToPath(import.meta.url));
|
|
20831
20928
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
20832
20929
|
const missing = [];
|
|
20833
|
-
if (!existsSync20(
|
|
20930
|
+
if (!existsSync20(path40.join(grammarDir, "tree-sitter.wasm"))) {
|
|
20834
20931
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
20835
20932
|
}
|
|
20836
20933
|
for (const file of grammarFiles) {
|
|
20837
|
-
if (!existsSync20(
|
|
20934
|
+
if (!existsSync20(path40.join(grammarDir, file))) {
|
|
20838
20935
|
missing.push(file);
|
|
20839
20936
|
}
|
|
20840
20937
|
}
|
|
@@ -20852,7 +20949,7 @@ async function checkGrammarWasmFiles() {
|
|
|
20852
20949
|
};
|
|
20853
20950
|
}
|
|
20854
20951
|
async function checkCheckpointManifest(directory) {
|
|
20855
|
-
const manifestPath =
|
|
20952
|
+
const manifestPath = path40.join(directory, ".swarm/checkpoints.json");
|
|
20856
20953
|
if (!existsSync20(manifestPath)) {
|
|
20857
20954
|
return {
|
|
20858
20955
|
name: "Checkpoint Manifest",
|
|
@@ -20904,7 +21001,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
20904
21001
|
}
|
|
20905
21002
|
}
|
|
20906
21003
|
async function checkEventStreamIntegrity(directory) {
|
|
20907
|
-
const eventsPath =
|
|
21004
|
+
const eventsPath = path40.join(directory, ".swarm/events.jsonl");
|
|
20908
21005
|
if (!existsSync20(eventsPath)) {
|
|
20909
21006
|
return {
|
|
20910
21007
|
name: "Event Stream",
|
|
@@ -20945,7 +21042,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
20945
21042
|
}
|
|
20946
21043
|
}
|
|
20947
21044
|
async function checkSteeringDirectives(directory) {
|
|
20948
|
-
const eventsPath =
|
|
21045
|
+
const eventsPath = path40.join(directory, ".swarm/events.jsonl");
|
|
20949
21046
|
if (!existsSync20(eventsPath)) {
|
|
20950
21047
|
return {
|
|
20951
21048
|
name: "Steering Directives",
|
|
@@ -21001,7 +21098,7 @@ async function checkCurator(directory) {
|
|
|
21001
21098
|
detail: "Disabled (enable via curator.enabled)"
|
|
21002
21099
|
};
|
|
21003
21100
|
}
|
|
21004
|
-
const summaryPath =
|
|
21101
|
+
const summaryPath = path40.join(directory, ".swarm/curator-summary.json");
|
|
21005
21102
|
if (!existsSync20(summaryPath)) {
|
|
21006
21103
|
return {
|
|
21007
21104
|
name: "Curator",
|
|
@@ -21203,7 +21300,7 @@ async function getDiagnoseData(directory) {
|
|
|
21203
21300
|
checks.push(await checkCurator(directory));
|
|
21204
21301
|
checks.push(await checkKnowledgeHealth(directory));
|
|
21205
21302
|
try {
|
|
21206
|
-
const evidenceDir =
|
|
21303
|
+
const evidenceDir = path40.join(directory, ".swarm", "evidence");
|
|
21207
21304
|
const snapshotFiles = existsSync20(evidenceDir) ? readdirSync3(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
21208
21305
|
if (snapshotFiles.length > 0) {
|
|
21209
21306
|
const latest = snapshotFiles.sort().pop();
|
|
@@ -21243,8 +21340,8 @@ async function getDiagnoseData(directory) {
|
|
|
21243
21340
|
}
|
|
21244
21341
|
const packageRoot = resolveCachePackageRoot(cachePath);
|
|
21245
21342
|
const cacheLabel = packageRoot === cachePath ? cachePath : `${cachePath} -> ${packageRoot}`;
|
|
21246
|
-
const missingGrammarAssets = REQUIRED_CACHE_GRAMMAR_ASSETS.filter((file) => !existsSync20(
|
|
21247
|
-
const pkgJsonPath =
|
|
21343
|
+
const missingGrammarAssets = REQUIRED_CACHE_GRAMMAR_ASSETS.filter((file) => !existsSync20(path40.join(packageRoot, "dist", "lang", "grammars", file)));
|
|
21344
|
+
const pkgJsonPath = path40.join(packageRoot, "package.json");
|
|
21248
21345
|
try {
|
|
21249
21346
|
const raw = readFileSync10(pkgJsonPath, "utf-8");
|
|
21250
21347
|
const parsed = JSON.parse(raw);
|
|
@@ -21620,9 +21717,9 @@ function decideEpicActivation(tasks, cochangePairs, commitsObserved, options) {
|
|
|
21620
21717
|
// src/turbo/epic/calibration.ts
|
|
21621
21718
|
init_logger();
|
|
21622
21719
|
import * as fs15 from "fs";
|
|
21623
|
-
import * as
|
|
21720
|
+
import * as path41 from "path";
|
|
21624
21721
|
var STATE_FILE = "calibration.json";
|
|
21625
|
-
var STATE_REL_DIR =
|
|
21722
|
+
var STATE_REL_DIR = path41.join(".swarm", "epic");
|
|
21626
21723
|
function nowISO() {
|
|
21627
21724
|
return new Date().toISOString();
|
|
21628
21725
|
}
|
|
@@ -21644,7 +21741,7 @@ function markUnreadable(directory, reason) {
|
|
|
21644
21741
|
error(`[epic/calibration] state file unreadable for ${directory}: ${reason} \u2014 failing closed`);
|
|
21645
21742
|
}
|
|
21646
21743
|
function repairCalibrationUnreadable(directory) {
|
|
21647
|
-
const filePath =
|
|
21744
|
+
const filePath = path41.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
21648
21745
|
if (!fs15.existsSync(filePath)) {
|
|
21649
21746
|
stateUnreadableMap.delete(directory);
|
|
21650
21747
|
return;
|
|
@@ -21676,7 +21773,7 @@ function isValidCalibrationShape(candidate) {
|
|
|
21676
21773
|
return true;
|
|
21677
21774
|
}
|
|
21678
21775
|
function ensureSwarmEpicDir(directory) {
|
|
21679
|
-
const dir =
|
|
21776
|
+
const dir = path41.resolve(directory, STATE_REL_DIR);
|
|
21680
21777
|
if (!fs15.existsSync(dir)) {
|
|
21681
21778
|
fs15.mkdirSync(dir, { recursive: true });
|
|
21682
21779
|
}
|
|
@@ -21688,7 +21785,7 @@ function loadCalibrationState(directory) {
|
|
|
21688
21785
|
if (stateUnreadableMap.get(directory))
|
|
21689
21786
|
return null;
|
|
21690
21787
|
}
|
|
21691
|
-
const filePath =
|
|
21788
|
+
const filePath = path41.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
21692
21789
|
try {
|
|
21693
21790
|
if (!fs15.existsSync(filePath)) {
|
|
21694
21791
|
const seed = emptyCalibrationState();
|
|
@@ -21715,12 +21812,12 @@ function loadCalibrationState(directory) {
|
|
|
21715
21812
|
// src/turbo/epic/divergence-recorder.ts
|
|
21716
21813
|
init_logger();
|
|
21717
21814
|
import * as fs16 from "fs";
|
|
21718
|
-
import * as
|
|
21719
|
-
var EVIDENCE_REL_DIR =
|
|
21815
|
+
import * as path42 from "path";
|
|
21816
|
+
var EVIDENCE_REL_DIR = path42.join(".swarm", "epic");
|
|
21720
21817
|
var EVIDENCE_FILE = "divergence.jsonl";
|
|
21721
21818
|
var MAX_TAIL_BYTES2 = 16 * 1024 * 1024;
|
|
21722
21819
|
function readDivergenceHistory(directory, options) {
|
|
21723
|
-
const filePath =
|
|
21820
|
+
const filePath = path42.join(directory, EVIDENCE_REL_DIR, EVIDENCE_FILE);
|
|
21724
21821
|
if (!fs16.existsSync(filePath)) {
|
|
21725
21822
|
return [];
|
|
21726
21823
|
}
|
|
@@ -21769,11 +21866,11 @@ function readDivergenceHistory(directory, options) {
|
|
|
21769
21866
|
|
|
21770
21867
|
// src/turbo/epic/promotion-evidence.ts
|
|
21771
21868
|
import * as fs17 from "fs";
|
|
21772
|
-
import * as
|
|
21773
|
-
var EVIDENCE_REL_DIR2 =
|
|
21869
|
+
import * as path43 from "path";
|
|
21870
|
+
var EVIDENCE_REL_DIR2 = path43.join(".swarm", "evidence");
|
|
21774
21871
|
var EVIDENCE_FILE2 = "epic-promotions.jsonl";
|
|
21775
21872
|
function readPromotionEvidence(directory) {
|
|
21776
|
-
const filePath =
|
|
21873
|
+
const filePath = path43.join(directory, EVIDENCE_REL_DIR2, EVIDENCE_FILE2);
|
|
21777
21874
|
if (!fs17.existsSync(filePath)) {
|
|
21778
21875
|
return [];
|
|
21779
21876
|
}
|
|
@@ -22282,7 +22379,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
22282
22379
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
22283
22380
|
}
|
|
22284
22381
|
async function handleEvidenceSummaryCommand(directory) {
|
|
22285
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
22382
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-zhw4rkjb.js");
|
|
22286
22383
|
const artifact = await buildEvidenceSummary(directory);
|
|
22287
22384
|
if (!artifact) {
|
|
22288
22385
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -22347,7 +22444,7 @@ async function handleExportCommand(directory, _args) {
|
|
|
22347
22444
|
// src/full-auto/state.ts
|
|
22348
22445
|
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
22349
22446
|
import * as fs18 from "fs";
|
|
22350
|
-
import * as
|
|
22447
|
+
import * as path44 from "path";
|
|
22351
22448
|
init_logger();
|
|
22352
22449
|
var lockfile4 = import_proper_lockfile4.default;
|
|
22353
22450
|
var STATE_FILE2 = "full-auto-state.json";
|
|
@@ -22355,7 +22452,7 @@ function nowISO2() {
|
|
|
22355
22452
|
return new Date().toISOString();
|
|
22356
22453
|
}
|
|
22357
22454
|
function ensureSwarmDir(directory) {
|
|
22358
|
-
const swarmDir =
|
|
22455
|
+
const swarmDir = path44.resolve(directory, ".swarm");
|
|
22359
22456
|
if (!fs18.existsSync(swarmDir)) {
|
|
22360
22457
|
fs18.mkdirSync(swarmDir, { recursive: true });
|
|
22361
22458
|
}
|
|
@@ -23167,7 +23264,7 @@ var _internals29 = {
|
|
|
23167
23264
|
|
|
23168
23265
|
// src/session/snapshot-writer.ts
|
|
23169
23266
|
import { closeSync as closeSync6, fsyncSync as fsyncSync2, mkdirSync as mkdirSync17, openSync as openSync6, renameSync as renameSync9 } from "fs";
|
|
23170
|
-
import * as
|
|
23267
|
+
import * as path45 from "path";
|
|
23171
23268
|
var _writeInFlight = Promise.resolve();
|
|
23172
23269
|
function serializeAgentSession(s) {
|
|
23173
23270
|
const gateLog = {};
|
|
@@ -23274,7 +23371,7 @@ async function writeSnapshot(directory, state) {
|
|
|
23274
23371
|
}
|
|
23275
23372
|
const content = JSON.stringify(snapshot, null, 2);
|
|
23276
23373
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
23277
|
-
const dir =
|
|
23374
|
+
const dir = path45.dirname(resolvedPath);
|
|
23278
23375
|
mkdirSync17(dir, { recursive: true });
|
|
23279
23376
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
23280
23377
|
await bunWrite(tempPath, content);
|
|
@@ -23777,7 +23874,7 @@ ${USAGE6}`;
|
|
|
23777
23874
|
}
|
|
23778
23875
|
|
|
23779
23876
|
// src/commands/knowledge.ts
|
|
23780
|
-
import { join as
|
|
23877
|
+
import { join as join38 } from "path";
|
|
23781
23878
|
|
|
23782
23879
|
// src/hooks/knowledge-migrator.ts
|
|
23783
23880
|
init_logger();
|
|
@@ -23785,15 +23882,15 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
23785
23882
|
import { existsSync as existsSync25, readFileSync as readFileSync15 } from "fs";
|
|
23786
23883
|
import { mkdir as mkdir11, readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
|
|
23787
23884
|
import * as os11 from "os";
|
|
23788
|
-
import * as
|
|
23885
|
+
import * as path46 from "path";
|
|
23789
23886
|
|
|
23790
23887
|
// src/hooks/knowledge-types.ts
|
|
23791
23888
|
var KNOWLEDGE_SCHEMA_VERSION = 2;
|
|
23792
23889
|
|
|
23793
23890
|
// src/hooks/knowledge-migrator.ts
|
|
23794
23891
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
23795
|
-
const externalSentinelPath =
|
|
23796
|
-
const contextPath =
|
|
23892
|
+
const externalSentinelPath = path46.join(_directory, ".swarm", ".knowledge-external-migrated");
|
|
23893
|
+
const contextPath = path46.join(_directory, ".swarm", "context.md");
|
|
23797
23894
|
if (_internals32.existsSync(externalSentinelPath)) {
|
|
23798
23895
|
return {
|
|
23799
23896
|
migrated: false,
|
|
@@ -23858,8 +23955,8 @@ var _internals32 = {
|
|
|
23858
23955
|
writeFile: writeFile11
|
|
23859
23956
|
};
|
|
23860
23957
|
async function migrateContextToKnowledge(directory, config) {
|
|
23861
|
-
const sentinelPath =
|
|
23862
|
-
const contextPath =
|
|
23958
|
+
const sentinelPath = path46.join(directory, ".swarm", ".knowledge-migrated");
|
|
23959
|
+
const contextPath = path46.join(directory, ".swarm", "context.md");
|
|
23863
23960
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
23864
23961
|
if (existsSync25(sentinelPath)) {
|
|
23865
23962
|
return {
|
|
@@ -23961,7 +24058,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
23961
24058
|
async function migrateHiveKnowledgeLegacy(config) {
|
|
23962
24059
|
const legacyHivePath = _internals32.resolveLegacyHiveKnowledgePath();
|
|
23963
24060
|
const canonicalHivePath = resolveHiveKnowledgePath();
|
|
23964
|
-
const sentinelPath =
|
|
24061
|
+
const sentinelPath = path46.join(path46.dirname(canonicalHivePath), ".hive-knowledge-migrated");
|
|
23965
24062
|
if (existsSync25(sentinelPath)) {
|
|
23966
24063
|
return {
|
|
23967
24064
|
migrated: false,
|
|
@@ -24172,7 +24269,7 @@ function truncateLesson2(text) {
|
|
|
24172
24269
|
return `${text.slice(0, 277)}...`;
|
|
24173
24270
|
}
|
|
24174
24271
|
function inferProjectName(directory) {
|
|
24175
|
-
const packageJsonPath =
|
|
24272
|
+
const packageJsonPath = path46.join(directory, "package.json");
|
|
24176
24273
|
if (existsSync25(packageJsonPath)) {
|
|
24177
24274
|
try {
|
|
24178
24275
|
const pkg = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
|
|
@@ -24181,7 +24278,7 @@ function inferProjectName(directory) {
|
|
|
24181
24278
|
}
|
|
24182
24279
|
} catch {}
|
|
24183
24280
|
}
|
|
24184
|
-
return
|
|
24281
|
+
return path46.basename(directory);
|
|
24185
24282
|
}
|
|
24186
24283
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
24187
24284
|
const sentinel = {
|
|
@@ -24193,7 +24290,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
24193
24290
|
schema_version: 1,
|
|
24194
24291
|
migration_tool: "knowledge-migrator.ts"
|
|
24195
24292
|
};
|
|
24196
|
-
await _internals32.mkdir(
|
|
24293
|
+
await _internals32.mkdir(path46.dirname(sentinelPath), { recursive: true });
|
|
24197
24294
|
await _internals32.writeFile(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
24198
24295
|
}
|
|
24199
24296
|
function resolveLegacyHiveKnowledgePath() {
|
|
@@ -24201,13 +24298,13 @@ function resolveLegacyHiveKnowledgePath() {
|
|
|
24201
24298
|
const home = process.env.HOME || os11.homedir();
|
|
24202
24299
|
let dataDir;
|
|
24203
24300
|
if (platform === "win32") {
|
|
24204
|
-
dataDir =
|
|
24301
|
+
dataDir = path46.join(process.env.LOCALAPPDATA || path46.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
24205
24302
|
} else if (platform === "darwin") {
|
|
24206
|
-
dataDir =
|
|
24303
|
+
dataDir = path46.join(home, "Library", "Application Support", "opencode-swarm");
|
|
24207
24304
|
} else {
|
|
24208
|
-
dataDir =
|
|
24305
|
+
dataDir = path46.join(process.env.XDG_DATA_HOME || path46.join(home, ".local", "share"), "opencode-swarm");
|
|
24209
24306
|
}
|
|
24210
|
-
return
|
|
24307
|
+
return path46.join(dataDir, "hive-knowledge.jsonl");
|
|
24211
24308
|
}
|
|
24212
24309
|
|
|
24213
24310
|
// src/commands/knowledge.ts
|
|
@@ -24261,7 +24358,7 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
24261
24358
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
24262
24359
|
}
|
|
24263
24360
|
try {
|
|
24264
|
-
const quarantinePath =
|
|
24361
|
+
const quarantinePath = join38(resolveKnowledgeStoreDir(directory), "knowledge-quarantined.jsonl");
|
|
24265
24362
|
const entries = await readKnowledge(quarantinePath);
|
|
24266
24363
|
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
24267
24364
|
if ("error" in resolved) {
|
|
@@ -24513,14 +24610,14 @@ var _internals33 = {
|
|
|
24513
24610
|
|
|
24514
24611
|
// src/commands/link.ts
|
|
24515
24612
|
import { existsSync as existsSync26 } from "fs";
|
|
24516
|
-
import * as
|
|
24613
|
+
import * as path48 from "path";
|
|
24517
24614
|
|
|
24518
24615
|
// src/knowledge/identity.ts
|
|
24519
24616
|
import * as child_process5 from "child_process";
|
|
24520
24617
|
import { createHash as createHash5 } from "crypto";
|
|
24521
|
-
import * as
|
|
24618
|
+
import * as path47 from "path";
|
|
24522
24619
|
function deriveProjectHash(directory) {
|
|
24523
|
-
const absolutePath =
|
|
24620
|
+
const absolutePath = path47.resolve(directory);
|
|
24524
24621
|
let hashInput;
|
|
24525
24622
|
try {
|
|
24526
24623
|
const remoteUrl = child_process5.execSync("git remote get-url origin", {
|
|
@@ -24540,8 +24637,8 @@ function deriveProjectHash(directory) {
|
|
|
24540
24637
|
// src/commands/link.ts
|
|
24541
24638
|
var DEDUP_THRESHOLD = 0.6;
|
|
24542
24639
|
async function mergeLocalKnowledgeIntoLink(localSwarmDir, linkDir) {
|
|
24543
|
-
const localPath =
|
|
24544
|
-
const sharedPath =
|
|
24640
|
+
const localPath = path48.join(localSwarmDir, "knowledge.jsonl");
|
|
24641
|
+
const sharedPath = path48.join(linkDir, "knowledge.jsonl");
|
|
24545
24642
|
if (!existsSync26(localPath))
|
|
24546
24643
|
return { merged: 0, skipped: 0 };
|
|
24547
24644
|
let merged = 0;
|
|
@@ -24639,7 +24736,7 @@ ${formatStatus(directory)}`;
|
|
|
24639
24736
|
const linkDir = resolveLinkDir(linkId);
|
|
24640
24737
|
let merge;
|
|
24641
24738
|
try {
|
|
24642
|
-
merge = await mergeLocalKnowledgeIntoLink(
|
|
24739
|
+
merge = await mergeLocalKnowledgeIntoLink(path48.join(directory, ".swarm"), linkDir);
|
|
24643
24740
|
} catch (error2) {
|
|
24644
24741
|
return `\u274C Failed to merge local knowledge into the link store: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
24645
24742
|
}
|
|
@@ -24836,12 +24933,12 @@ ${USAGE7}`;
|
|
|
24836
24933
|
|
|
24837
24934
|
// src/commands/memory.ts
|
|
24838
24935
|
import { existsSync as existsSync27 } from "fs";
|
|
24839
|
-
import * as
|
|
24936
|
+
import * as path51 from "path";
|
|
24840
24937
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
24841
24938
|
// src/memory/evaluation.ts
|
|
24842
24939
|
import * as fs19 from "fs/promises";
|
|
24843
24940
|
import * as os12 from "os";
|
|
24844
|
-
import * as
|
|
24941
|
+
import * as path49 from "path";
|
|
24845
24942
|
var DEFAULT_PROVIDERS = [
|
|
24846
24943
|
"local-jsonl",
|
|
24847
24944
|
"sqlite"
|
|
@@ -24853,7 +24950,7 @@ var DEFAULT_MODES = [
|
|
|
24853
24950
|
];
|
|
24854
24951
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
24855
24952
|
async function evaluateMemoryRecallFixtures(options) {
|
|
24856
|
-
const fixtureDirectory =
|
|
24953
|
+
const fixtureDirectory = path49.resolve(options.fixtureDirectory);
|
|
24857
24954
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
24858
24955
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
24859
24956
|
const generatedAt = new Date().toISOString();
|
|
@@ -24862,7 +24959,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
24862
24959
|
for (const fixture of fixtures) {
|
|
24863
24960
|
const materialized = materializeFixture(fixture);
|
|
24864
24961
|
for (const providerName of providers) {
|
|
24865
|
-
const tempRoot = await fs19.realpath(await fs19.mkdtemp(
|
|
24962
|
+
const tempRoot = await fs19.realpath(await fs19.mkdtemp(path49.join(os12.tmpdir(), "swarm-memory-eval-")));
|
|
24866
24963
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
24867
24964
|
try {
|
|
24868
24965
|
await provider.initialize?.();
|
|
@@ -24919,7 +25016,7 @@ async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
|
24919
25016
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
24920
25017
|
const fixtures = [];
|
|
24921
25018
|
for (const file of files) {
|
|
24922
|
-
const raw = await fs19.readFile(
|
|
25019
|
+
const raw = await fs19.readFile(path49.join(fixtureDirectory, file), "utf-8");
|
|
24923
25020
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
24924
25021
|
}
|
|
24925
25022
|
return fixtures;
|
|
@@ -25196,8 +25293,8 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
25196
25293
|
}).passthrough();
|
|
25197
25294
|
// src/memory/consolidation-log.ts
|
|
25198
25295
|
import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "fs/promises";
|
|
25199
|
-
import * as
|
|
25200
|
-
var LOG_RELATIVE_PATH =
|
|
25296
|
+
import * as path50 from "path";
|
|
25297
|
+
var LOG_RELATIVE_PATH = path50.join("memory", "consolidation-log.jsonl");
|
|
25201
25298
|
async function readConsolidationLog(directory) {
|
|
25202
25299
|
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
25203
25300
|
let raw;
|
|
@@ -25220,7 +25317,7 @@ async function readConsolidationLog(directory) {
|
|
|
25220
25317
|
}
|
|
25221
25318
|
|
|
25222
25319
|
// src/commands/memory.ts
|
|
25223
|
-
var PACKAGE_ROOT =
|
|
25320
|
+
var PACKAGE_ROOT = path51.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
25224
25321
|
async function handleMemoryCommand(_directory, _args) {
|
|
25225
25322
|
return [
|
|
25226
25323
|
"## Swarm Memory",
|
|
@@ -25577,7 +25674,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
25577
25674
|
}
|
|
25578
25675
|
function parseEvaluateArgs(directory, args) {
|
|
25579
25676
|
let json = false;
|
|
25580
|
-
let fixtureDirectory =
|
|
25677
|
+
let fixtureDirectory = path51.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
25581
25678
|
for (let i = 0;i < args.length; i++) {
|
|
25582
25679
|
const arg = args[i];
|
|
25583
25680
|
if (arg === "--json") {
|
|
@@ -25591,10 +25688,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
25591
25688
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
25592
25689
|
};
|
|
25593
25690
|
}
|
|
25594
|
-
const resolvedFixtures =
|
|
25595
|
-
const canonical =
|
|
25596
|
-
const allowedRootA =
|
|
25597
|
-
const allowedRootB =
|
|
25691
|
+
const resolvedFixtures = path51.resolve(directory, next);
|
|
25692
|
+
const canonical = path51.normalize(resolvedFixtures) + path51.sep;
|
|
25693
|
+
const allowedRootA = path51.normalize(directory) + path51.sep;
|
|
25694
|
+
const allowedRootB = path51.normalize(path51.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path51.sep;
|
|
25598
25695
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
25599
25696
|
return {
|
|
25600
25697
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -25633,15 +25730,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
25633
25730
|
return { limit, confirm };
|
|
25634
25731
|
}
|
|
25635
25732
|
function resolvePackageRootFromModule(modulePath) {
|
|
25636
|
-
const moduleDir =
|
|
25637
|
-
const leaf =
|
|
25733
|
+
const moduleDir = path51.dirname(modulePath);
|
|
25734
|
+
const leaf = path51.basename(moduleDir);
|
|
25638
25735
|
if (leaf === "commands" || leaf === "cli") {
|
|
25639
|
-
return
|
|
25736
|
+
return path51.resolve(moduleDir, "..", "..");
|
|
25640
25737
|
}
|
|
25641
25738
|
if (leaf === "dist") {
|
|
25642
|
-
return
|
|
25739
|
+
return path51.resolve(moduleDir, "..");
|
|
25643
25740
|
}
|
|
25644
|
-
return
|
|
25741
|
+
return path51.resolve(moduleDir, "..");
|
|
25645
25742
|
}
|
|
25646
25743
|
function formatMigrationResult(label, report) {
|
|
25647
25744
|
if (!report) {
|
|
@@ -26340,11 +26437,11 @@ var _internals39 = {
|
|
|
26340
26437
|
|
|
26341
26438
|
// src/services/preflight-service.ts
|
|
26342
26439
|
import * as fs26 from "fs";
|
|
26343
|
-
import * as
|
|
26440
|
+
import * as path58 from "path";
|
|
26344
26441
|
|
|
26345
26442
|
// src/tools/lint.ts
|
|
26346
26443
|
import * as fs20 from "fs";
|
|
26347
|
-
import * as
|
|
26444
|
+
import * as path52 from "path";
|
|
26348
26445
|
|
|
26349
26446
|
// src/utils/path-security.ts
|
|
26350
26447
|
function containsPathTraversal(str) {
|
|
@@ -26400,9 +26497,9 @@ function validateArgs(args) {
|
|
|
26400
26497
|
}
|
|
26401
26498
|
function getLinterCommand(linter, mode, projectDir) {
|
|
26402
26499
|
const isWindows = process.platform === "win32";
|
|
26403
|
-
const binDir =
|
|
26404
|
-
const biomeBin = isWindows ?
|
|
26405
|
-
const eslintBin = isWindows ?
|
|
26500
|
+
const binDir = path52.join(projectDir, "node_modules", ".bin");
|
|
26501
|
+
const biomeBin = isWindows ? path52.join(binDir, "biome.EXE") : path52.join(binDir, "biome");
|
|
26502
|
+
const eslintBin = isWindows ? path52.join(binDir, "eslint.cmd") : path52.join(binDir, "eslint");
|
|
26406
26503
|
switch (linter) {
|
|
26407
26504
|
case "biome":
|
|
26408
26505
|
if (mode === "fix") {
|
|
@@ -26418,7 +26515,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
26418
26515
|
}
|
|
26419
26516
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
26420
26517
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
26421
|
-
const gradlew = fs20.existsSync(
|
|
26518
|
+
const gradlew = fs20.existsSync(path52.join(cwd, gradlewName)) ? path52.join(cwd, gradlewName) : null;
|
|
26422
26519
|
switch (linter) {
|
|
26423
26520
|
case "ruff":
|
|
26424
26521
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -26452,10 +26549,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
26452
26549
|
}
|
|
26453
26550
|
}
|
|
26454
26551
|
function detectRuff(cwd) {
|
|
26455
|
-
if (fs20.existsSync(
|
|
26552
|
+
if (fs20.existsSync(path52.join(cwd, "ruff.toml")))
|
|
26456
26553
|
return isCommandAvailable("ruff");
|
|
26457
26554
|
try {
|
|
26458
|
-
const pyproject =
|
|
26555
|
+
const pyproject = path52.join(cwd, "pyproject.toml");
|
|
26459
26556
|
if (fs20.existsSync(pyproject)) {
|
|
26460
26557
|
const content = fs20.readFileSync(pyproject, "utf-8");
|
|
26461
26558
|
if (content.includes("[tool.ruff]"))
|
|
@@ -26465,19 +26562,19 @@ function detectRuff(cwd) {
|
|
|
26465
26562
|
return false;
|
|
26466
26563
|
}
|
|
26467
26564
|
function detectClippy(cwd) {
|
|
26468
|
-
return fs20.existsSync(
|
|
26565
|
+
return fs20.existsSync(path52.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
26469
26566
|
}
|
|
26470
26567
|
function detectGolangciLint(cwd) {
|
|
26471
|
-
return fs20.existsSync(
|
|
26568
|
+
return fs20.existsSync(path52.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
26472
26569
|
}
|
|
26473
26570
|
function detectCheckstyle(cwd) {
|
|
26474
|
-
const hasMaven = fs20.existsSync(
|
|
26475
|
-
const hasGradle = fs20.existsSync(
|
|
26476
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs20.existsSync(
|
|
26571
|
+
const hasMaven = fs20.existsSync(path52.join(cwd, "pom.xml"));
|
|
26572
|
+
const hasGradle = fs20.existsSync(path52.join(cwd, "build.gradle")) || fs20.existsSync(path52.join(cwd, "build.gradle.kts"));
|
|
26573
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs20.existsSync(path52.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
26477
26574
|
return (hasMaven || hasGradle) && hasBinary;
|
|
26478
26575
|
}
|
|
26479
26576
|
function detectKtlint(cwd) {
|
|
26480
|
-
const hasKotlin = fs20.existsSync(
|
|
26577
|
+
const hasKotlin = fs20.existsSync(path52.join(cwd, "build.gradle.kts")) || fs20.existsSync(path52.join(cwd, "build.gradle")) || (() => {
|
|
26481
26578
|
try {
|
|
26482
26579
|
return fs20.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
26483
26580
|
} catch {
|
|
@@ -26496,11 +26593,11 @@ function detectDotnetFormat(cwd) {
|
|
|
26496
26593
|
}
|
|
26497
26594
|
}
|
|
26498
26595
|
function detectCppcheck(cwd) {
|
|
26499
|
-
if (fs20.existsSync(
|
|
26596
|
+
if (fs20.existsSync(path52.join(cwd, "CMakeLists.txt"))) {
|
|
26500
26597
|
return isCommandAvailable("cppcheck");
|
|
26501
26598
|
}
|
|
26502
26599
|
try {
|
|
26503
|
-
const dirsToCheck = [cwd,
|
|
26600
|
+
const dirsToCheck = [cwd, path52.join(cwd, "src")];
|
|
26504
26601
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
26505
26602
|
try {
|
|
26506
26603
|
return fs20.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -26514,13 +26611,13 @@ function detectCppcheck(cwd) {
|
|
|
26514
26611
|
}
|
|
26515
26612
|
}
|
|
26516
26613
|
function detectSwiftlint(cwd) {
|
|
26517
|
-
return fs20.existsSync(
|
|
26614
|
+
return fs20.existsSync(path52.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
26518
26615
|
}
|
|
26519
26616
|
function detectDartAnalyze(cwd) {
|
|
26520
|
-
return fs20.existsSync(
|
|
26617
|
+
return fs20.existsSync(path52.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
26521
26618
|
}
|
|
26522
26619
|
function detectRubocop(cwd) {
|
|
26523
|
-
return (fs20.existsSync(
|
|
26620
|
+
return (fs20.existsSync(path52.join(cwd, "Gemfile")) || fs20.existsSync(path52.join(cwd, "gems.rb")) || fs20.existsSync(path52.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
26524
26621
|
}
|
|
26525
26622
|
function detectAdditionalLinter(cwd) {
|
|
26526
26623
|
if (detectRuff(cwd))
|
|
@@ -26548,10 +26645,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
26548
26645
|
function findBinInAncestors(startDir, binName) {
|
|
26549
26646
|
let dir = startDir;
|
|
26550
26647
|
while (true) {
|
|
26551
|
-
const candidate =
|
|
26648
|
+
const candidate = path52.join(dir, "node_modules", ".bin", binName);
|
|
26552
26649
|
if (fs20.existsSync(candidate))
|
|
26553
26650
|
return candidate;
|
|
26554
|
-
const parent =
|
|
26651
|
+
const parent = path52.dirname(dir);
|
|
26555
26652
|
if (parent === dir)
|
|
26556
26653
|
break;
|
|
26557
26654
|
dir = parent;
|
|
@@ -26560,10 +26657,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
26560
26657
|
}
|
|
26561
26658
|
function findBinInEnvPath(binName) {
|
|
26562
26659
|
const searchPath = process.env.PATH ?? "";
|
|
26563
|
-
for (const dir of searchPath.split(
|
|
26660
|
+
for (const dir of searchPath.split(path52.delimiter)) {
|
|
26564
26661
|
if (!dir)
|
|
26565
26662
|
continue;
|
|
26566
|
-
const candidate =
|
|
26663
|
+
const candidate = path52.join(dir, binName);
|
|
26567
26664
|
if (fs20.existsSync(candidate))
|
|
26568
26665
|
return candidate;
|
|
26569
26666
|
}
|
|
@@ -26576,13 +26673,13 @@ async function detectAvailableLinter(directory) {
|
|
|
26576
26673
|
return null;
|
|
26577
26674
|
const projectDir = directory;
|
|
26578
26675
|
const isWindows = process.platform === "win32";
|
|
26579
|
-
const biomeBin = isWindows ?
|
|
26580
|
-
const eslintBin = isWindows ?
|
|
26676
|
+
const biomeBin = isWindows ? path52.join(projectDir, "node_modules", ".bin", "biome.EXE") : path52.join(projectDir, "node_modules", ".bin", "biome");
|
|
26677
|
+
const eslintBin = isWindows ? path52.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path52.join(projectDir, "node_modules", ".bin", "eslint");
|
|
26581
26678
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
26582
26679
|
if (localResult)
|
|
26583
26680
|
return localResult;
|
|
26584
|
-
const biomeAncestor = findBinInAncestors(
|
|
26585
|
-
const eslintAncestor = findBinInAncestors(
|
|
26681
|
+
const biomeAncestor = findBinInAncestors(path52.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
26682
|
+
const eslintAncestor = findBinInAncestors(path52.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
26586
26683
|
if (biomeAncestor || eslintAncestor) {
|
|
26587
26684
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
26588
26685
|
}
|
|
@@ -26796,7 +26893,7 @@ var _internals40 = {
|
|
|
26796
26893
|
|
|
26797
26894
|
// src/tools/secretscan.ts
|
|
26798
26895
|
import * as fs21 from "fs";
|
|
26799
|
-
import * as
|
|
26896
|
+
import * as path53 from "path";
|
|
26800
26897
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
26801
26898
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
26802
26899
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -27023,7 +27120,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
27023
27120
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
27024
27121
|
}
|
|
27025
27122
|
function loadSecretScanIgnore(scanDir) {
|
|
27026
|
-
const ignorePath =
|
|
27123
|
+
const ignorePath = path53.join(scanDir, ".secretscanignore");
|
|
27027
27124
|
try {
|
|
27028
27125
|
if (!fs21.existsSync(ignorePath))
|
|
27029
27126
|
return [];
|
|
@@ -27046,7 +27143,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
27046
27143
|
if (exactNames.has(entry))
|
|
27047
27144
|
return true;
|
|
27048
27145
|
for (const pattern of globPatterns) {
|
|
27049
|
-
if (
|
|
27146
|
+
if (path53.matchesGlob(relPath, pattern))
|
|
27050
27147
|
return true;
|
|
27051
27148
|
}
|
|
27052
27149
|
return false;
|
|
@@ -27067,7 +27164,7 @@ function validateDirectoryInput(dir) {
|
|
|
27067
27164
|
return null;
|
|
27068
27165
|
}
|
|
27069
27166
|
function isBinaryFile(filePath, buffer) {
|
|
27070
|
-
const ext =
|
|
27167
|
+
const ext = path53.extname(filePath).toLowerCase();
|
|
27071
27168
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
27072
27169
|
return true;
|
|
27073
27170
|
}
|
|
@@ -27204,9 +27301,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
27204
27301
|
return false;
|
|
27205
27302
|
}
|
|
27206
27303
|
function isPathWithinScope(realPath, scanDir) {
|
|
27207
|
-
const resolvedScanDir =
|
|
27208
|
-
const resolvedRealPath =
|
|
27209
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
27304
|
+
const resolvedScanDir = path53.resolve(scanDir);
|
|
27305
|
+
const resolvedRealPath = path53.resolve(realPath);
|
|
27306
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path53.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
27210
27307
|
}
|
|
27211
27308
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
27212
27309
|
skippedDirs: 0,
|
|
@@ -27232,8 +27329,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
27232
27329
|
return a.localeCompare(b);
|
|
27233
27330
|
});
|
|
27234
27331
|
for (const entry of entries) {
|
|
27235
|
-
const fullPath =
|
|
27236
|
-
const relPath =
|
|
27332
|
+
const fullPath = path53.join(dir, entry);
|
|
27333
|
+
const relPath = path53.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
27237
27334
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
27238
27335
|
stats.skippedDirs++;
|
|
27239
27336
|
continue;
|
|
@@ -27268,7 +27365,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
27268
27365
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
27269
27366
|
files.push(...subFiles);
|
|
27270
27367
|
} else if (lstat2.isFile()) {
|
|
27271
|
-
const ext =
|
|
27368
|
+
const ext = path53.extname(fullPath).toLowerCase();
|
|
27272
27369
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
27273
27370
|
files.push(fullPath);
|
|
27274
27371
|
} else {
|
|
@@ -27334,7 +27431,7 @@ var secretscan = createSwarmTool({
|
|
|
27334
27431
|
}
|
|
27335
27432
|
}
|
|
27336
27433
|
try {
|
|
27337
|
-
const _scanDirRaw =
|
|
27434
|
+
const _scanDirRaw = path53.resolve(directory);
|
|
27338
27435
|
const scanDir = (() => {
|
|
27339
27436
|
try {
|
|
27340
27437
|
return fs21.realpathSync(_scanDirRaw);
|
|
@@ -27497,11 +27594,11 @@ var _internals41 = {
|
|
|
27497
27594
|
|
|
27498
27595
|
// src/tools/test-runner.ts
|
|
27499
27596
|
import * as fs25 from "fs";
|
|
27500
|
-
import * as
|
|
27597
|
+
import * as path57 from "path";
|
|
27501
27598
|
|
|
27502
27599
|
// src/test-impact/analyzer.ts
|
|
27503
27600
|
import fs22 from "fs";
|
|
27504
|
-
import
|
|
27601
|
+
import path54 from "path";
|
|
27505
27602
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
27506
27603
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
27507
27604
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -27542,8 +27639,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
27542
27639
|
if (!importPath.startsWith(".")) {
|
|
27543
27640
|
return null;
|
|
27544
27641
|
}
|
|
27545
|
-
const resolved =
|
|
27546
|
-
if (
|
|
27642
|
+
const resolved = path54.resolve(fromDir, importPath);
|
|
27643
|
+
if (path54.extname(resolved)) {
|
|
27547
27644
|
if (fs22.existsSync(resolved) && fs22.statSync(resolved).isFile()) {
|
|
27548
27645
|
return normalizePath2(resolved);
|
|
27549
27646
|
}
|
|
@@ -27563,20 +27660,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
27563
27660
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
27564
27661
|
let baseDir = fromDir;
|
|
27565
27662
|
for (let i = 1;i < leadingDots; i++) {
|
|
27566
|
-
baseDir =
|
|
27663
|
+
baseDir = path54.dirname(baseDir);
|
|
27567
27664
|
}
|
|
27568
27665
|
const rest = module.slice(leadingDots);
|
|
27569
27666
|
if (rest.length === 0) {
|
|
27570
|
-
const initPath =
|
|
27667
|
+
const initPath = path54.join(baseDir, "__init__.py");
|
|
27571
27668
|
if (fs22.existsSync(initPath) && fs22.statSync(initPath).isFile()) {
|
|
27572
27669
|
return normalizePath2(initPath);
|
|
27573
27670
|
}
|
|
27574
27671
|
return null;
|
|
27575
27672
|
}
|
|
27576
|
-
const subpath = rest.replace(/\./g,
|
|
27673
|
+
const subpath = rest.replace(/\./g, path54.sep);
|
|
27577
27674
|
const candidates = [
|
|
27578
|
-
`${
|
|
27579
|
-
|
|
27675
|
+
`${path54.join(baseDir, subpath)}.py`,
|
|
27676
|
+
path54.join(baseDir, subpath, "__init__.py")
|
|
27580
27677
|
];
|
|
27581
27678
|
for (const c of candidates) {
|
|
27582
27679
|
if (fs22.existsSync(c) && fs22.statSync(c).isFile())
|
|
@@ -27586,7 +27683,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
27586
27683
|
}
|
|
27587
27684
|
var goModuleCache = new Map;
|
|
27588
27685
|
function findGoModule(fromDir) {
|
|
27589
|
-
const resolved =
|
|
27686
|
+
const resolved = path54.resolve(fromDir);
|
|
27590
27687
|
let cur = resolved;
|
|
27591
27688
|
const walked = [];
|
|
27592
27689
|
for (let i = 0;i < 16; i++) {
|
|
@@ -27598,7 +27695,7 @@ function findGoModule(fromDir) {
|
|
|
27598
27695
|
}
|
|
27599
27696
|
walked.push(cur);
|
|
27600
27697
|
try {
|
|
27601
|
-
const goMod =
|
|
27698
|
+
const goMod = path54.join(cur, "go.mod");
|
|
27602
27699
|
const content = fs22.readFileSync(goMod, "utf-8");
|
|
27603
27700
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
27604
27701
|
if (moduleMatch) {
|
|
@@ -27609,10 +27706,10 @@ function findGoModule(fromDir) {
|
|
|
27609
27706
|
}
|
|
27610
27707
|
} catch {}
|
|
27611
27708
|
try {
|
|
27612
|
-
fs22.accessSync(
|
|
27709
|
+
fs22.accessSync(path54.join(cur, ".git"));
|
|
27613
27710
|
break;
|
|
27614
27711
|
} catch {}
|
|
27615
|
-
const parent =
|
|
27712
|
+
const parent = path54.dirname(cur);
|
|
27616
27713
|
if (parent === cur)
|
|
27617
27714
|
break;
|
|
27618
27715
|
cur = parent;
|
|
@@ -27624,12 +27721,12 @@ function findGoModule(fromDir) {
|
|
|
27624
27721
|
function resolveGoImport(fromDir, importPath) {
|
|
27625
27722
|
let dir = null;
|
|
27626
27723
|
if (importPath.startsWith(".")) {
|
|
27627
|
-
dir =
|
|
27724
|
+
dir = path54.resolve(fromDir, importPath);
|
|
27628
27725
|
} else {
|
|
27629
27726
|
const mod = findGoModule(fromDir);
|
|
27630
27727
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
27631
27728
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
27632
|
-
dir =
|
|
27729
|
+
dir = path54.join(mod.moduleRoot, subpath);
|
|
27633
27730
|
}
|
|
27634
27731
|
}
|
|
27635
27732
|
if (dir === null)
|
|
@@ -27637,7 +27734,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
27637
27734
|
if (!fs22.existsSync(dir) || !fs22.statSync(dir).isDirectory())
|
|
27638
27735
|
return [];
|
|
27639
27736
|
try {
|
|
27640
|
-
return fs22.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(
|
|
27737
|
+
return fs22.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path54.join(dir, f)));
|
|
27641
27738
|
} catch {
|
|
27642
27739
|
return [];
|
|
27643
27740
|
}
|
|
@@ -27676,15 +27773,15 @@ function findTestFilesSync(cwd) {
|
|
|
27676
27773
|
for (const entry of entries) {
|
|
27677
27774
|
if (entry.isDirectory()) {
|
|
27678
27775
|
if (!skipDirs.has(entry.name)) {
|
|
27679
|
-
walk(
|
|
27776
|
+
walk(path54.join(dir, entry.name), visitedInodes);
|
|
27680
27777
|
}
|
|
27681
27778
|
} else if (entry.isFile()) {
|
|
27682
27779
|
const name = entry.name;
|
|
27683
27780
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
27684
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
27781
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path54.sep}tests${path54.sep}`) && name.endsWith(".py");
|
|
27685
27782
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
27686
27783
|
if (isTsTest || isPyTest || isGoTest) {
|
|
27687
|
-
testFiles.push(normalizePath2(
|
|
27784
|
+
testFiles.push(normalizePath2(path54.join(dir, entry.name)));
|
|
27688
27785
|
}
|
|
27689
27786
|
}
|
|
27690
27787
|
}
|
|
@@ -27709,8 +27806,8 @@ function extractImports(content) {
|
|
|
27709
27806
|
];
|
|
27710
27807
|
}
|
|
27711
27808
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
27712
|
-
const ext =
|
|
27713
|
-
const testDir =
|
|
27809
|
+
const ext = path54.extname(testFile).toLowerCase();
|
|
27810
|
+
const testDir = path54.dirname(testFile);
|
|
27714
27811
|
function addEdge(source) {
|
|
27715
27812
|
if (!impactMap[source])
|
|
27716
27813
|
impactMap[source] = [];
|
|
@@ -27783,7 +27880,7 @@ async function buildImpactMap(cwd) {
|
|
|
27783
27880
|
return impactMap;
|
|
27784
27881
|
}
|
|
27785
27882
|
async function loadImpactMap(cwd, options) {
|
|
27786
|
-
const cachePath =
|
|
27883
|
+
const cachePath = path54.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
27787
27884
|
if (fs22.existsSync(cachePath)) {
|
|
27788
27885
|
try {
|
|
27789
27886
|
const content = fs22.readFileSync(cachePath, "utf-8");
|
|
@@ -27816,12 +27913,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
27816
27913
|
return _internals42.buildImpactMap(cwd);
|
|
27817
27914
|
}
|
|
27818
27915
|
async function saveImpactMap(cwd, impactMap) {
|
|
27819
|
-
if (!
|
|
27916
|
+
if (!path54.isAbsolute(cwd)) {
|
|
27820
27917
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
27821
27918
|
}
|
|
27822
27919
|
_internals42.validateProjectRoot(cwd);
|
|
27823
|
-
const cacheDir2 =
|
|
27824
|
-
const cachePath =
|
|
27920
|
+
const cacheDir2 = path54.join(cwd, ".swarm", "cache");
|
|
27921
|
+
const cachePath = path54.join(cacheDir2, "impact-map.json");
|
|
27825
27922
|
if (!fs22.existsSync(cacheDir2)) {
|
|
27826
27923
|
fs22.mkdirSync(cacheDir2, { recursive: true });
|
|
27827
27924
|
}
|
|
@@ -27853,7 +27950,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
27853
27950
|
budgetExceeded = true;
|
|
27854
27951
|
break;
|
|
27855
27952
|
}
|
|
27856
|
-
const normalizedChanged = normalizePath2(
|
|
27953
|
+
const normalizedChanged = normalizePath2(path54.resolve(changedFile));
|
|
27857
27954
|
const tests = impactMap[normalizedChanged];
|
|
27858
27955
|
if (tests && tests.length > 0) {
|
|
27859
27956
|
for (const test of tests) {
|
|
@@ -27867,13 +27964,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
27867
27964
|
if (budgetExceeded)
|
|
27868
27965
|
break;
|
|
27869
27966
|
} else {
|
|
27870
|
-
const changedDir = normalizePath2(
|
|
27871
|
-
const changedInputDir = normalizePath2(
|
|
27967
|
+
const changedDir = normalizePath2(path54.dirname(normalizedChanged));
|
|
27968
|
+
const changedInputDir = normalizePath2(path54.dirname(changedFile));
|
|
27872
27969
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
27873
27970
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
27874
27971
|
}).sort(([sourceA], [sourceB]) => {
|
|
27875
|
-
const sourceDirA = normalizePath2(
|
|
27876
|
-
const sourceDirB = normalizePath2(
|
|
27972
|
+
const sourceDirA = normalizePath2(path54.dirname(sourceA));
|
|
27973
|
+
const sourceDirB = normalizePath2(path54.dirname(sourceB));
|
|
27877
27974
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
27878
27975
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
27879
27976
|
if (exactA !== exactB)
|
|
@@ -28200,7 +28297,7 @@ function detectFlakyTests(allHistory) {
|
|
|
28200
28297
|
|
|
28201
28298
|
// src/test-impact/history-store.ts
|
|
28202
28299
|
import fs23 from "fs";
|
|
28203
|
-
import
|
|
28300
|
+
import path55 from "path";
|
|
28204
28301
|
var MAX_HISTORY_PER_TEST = 20;
|
|
28205
28302
|
var MAX_ERROR_LENGTH = 500;
|
|
28206
28303
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -28212,10 +28309,10 @@ function getHistoryPath(workingDir) {
|
|
|
28212
28309
|
if (!workingDir) {
|
|
28213
28310
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
28214
28311
|
}
|
|
28215
|
-
if (!
|
|
28312
|
+
if (!path55.isAbsolute(workingDir)) {
|
|
28216
28313
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
28217
28314
|
}
|
|
28218
|
-
return
|
|
28315
|
+
return path55.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
28219
28316
|
}
|
|
28220
28317
|
function sanitizeErrorMessage(errorMessage) {
|
|
28221
28318
|
if (errorMessage === undefined) {
|
|
@@ -28307,7 +28404,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
28307
28404
|
}
|
|
28308
28405
|
}
|
|
28309
28406
|
const historyPath = getHistoryPath(workingDir);
|
|
28310
|
-
const historyDir =
|
|
28407
|
+
const historyDir = path55.dirname(historyPath);
|
|
28311
28408
|
_internals43.validateProjectRoot(workingDir);
|
|
28312
28409
|
if (!fs23.existsSync(historyDir)) {
|
|
28313
28410
|
fs23.mkdirSync(historyDir, { recursive: true });
|
|
@@ -28437,7 +28534,7 @@ var _internals43 = {
|
|
|
28437
28534
|
|
|
28438
28535
|
// src/tools/resolve-working-directory.ts
|
|
28439
28536
|
import * as fs24 from "fs";
|
|
28440
|
-
import * as
|
|
28537
|
+
import * as path56 from "path";
|
|
28441
28538
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
28442
28539
|
if (workingDirectory == null || workingDirectory === "") {
|
|
28443
28540
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -28476,8 +28573,8 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
28476
28573
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
28477
28574
|
};
|
|
28478
28575
|
}
|
|
28479
|
-
const normalizedDir =
|
|
28480
|
-
const resolvedDir =
|
|
28576
|
+
const normalizedDir = path56.normalize(workingDirectory);
|
|
28577
|
+
const resolvedDir = path56.resolve(normalizedDir);
|
|
28481
28578
|
let statResult;
|
|
28482
28579
|
try {
|
|
28483
28580
|
statResult = fs24.statSync(resolvedDir);
|
|
@@ -28496,7 +28593,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
28496
28593
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
28497
28594
|
return { success: true, directory: resolvedDir };
|
|
28498
28595
|
}
|
|
28499
|
-
const resolvedFallback =
|
|
28596
|
+
const resolvedFallback = path56.resolve(fallbackDirectory);
|
|
28500
28597
|
let fallbackExists = false;
|
|
28501
28598
|
try {
|
|
28502
28599
|
fs24.statSync(resolvedFallback);
|
|
@@ -28505,7 +28602,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
28505
28602
|
fallbackExists = false;
|
|
28506
28603
|
}
|
|
28507
28604
|
if (fallbackExists) {
|
|
28508
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
28605
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path56.sep);
|
|
28509
28606
|
if (isSubdirectory) {
|
|
28510
28607
|
return {
|
|
28511
28608
|
success: false,
|
|
@@ -28528,7 +28625,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
28528
28625
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
28529
28626
|
const uniqueTestFiles = new Set;
|
|
28530
28627
|
for (const sourceFile of sourceFiles) {
|
|
28531
|
-
const resolvedPath =
|
|
28628
|
+
const resolvedPath = path57.resolve(cwd, sourceFile);
|
|
28532
28629
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
28533
28630
|
const testFiles = impactMap[normalizedPath];
|
|
28534
28631
|
if (testFiles) {
|
|
@@ -28613,14 +28710,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
28613
28710
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
28614
28711
|
}
|
|
28615
28712
|
function detectGoTest(cwd) {
|
|
28616
|
-
return fs25.existsSync(
|
|
28713
|
+
return fs25.existsSync(path57.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
28617
28714
|
}
|
|
28618
28715
|
function detectJavaMaven(cwd) {
|
|
28619
|
-
return fs25.existsSync(
|
|
28716
|
+
return fs25.existsSync(path57.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
28620
28717
|
}
|
|
28621
28718
|
function detectGradle(cwd) {
|
|
28622
|
-
const hasBuildFile = fs25.existsSync(
|
|
28623
|
-
const hasGradlew = fs25.existsSync(
|
|
28719
|
+
const hasBuildFile = fs25.existsSync(path57.join(cwd, "build.gradle")) || fs25.existsSync(path57.join(cwd, "build.gradle.kts"));
|
|
28720
|
+
const hasGradlew = fs25.existsSync(path57.join(cwd, "gradlew")) || fs25.existsSync(path57.join(cwd, "gradlew.bat"));
|
|
28624
28721
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
28625
28722
|
}
|
|
28626
28723
|
function detectDotnetTest(cwd) {
|
|
@@ -28633,25 +28730,25 @@ function detectDotnetTest(cwd) {
|
|
|
28633
28730
|
}
|
|
28634
28731
|
}
|
|
28635
28732
|
function detectCTest(cwd) {
|
|
28636
|
-
const hasSource = fs25.existsSync(
|
|
28637
|
-
const hasBuildCache = fs25.existsSync(
|
|
28733
|
+
const hasSource = fs25.existsSync(path57.join(cwd, "CMakeLists.txt"));
|
|
28734
|
+
const hasBuildCache = fs25.existsSync(path57.join(cwd, "CMakeCache.txt")) || fs25.existsSync(path57.join(cwd, "build", "CMakeCache.txt"));
|
|
28638
28735
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
28639
28736
|
}
|
|
28640
28737
|
function detectSwiftTest(cwd) {
|
|
28641
|
-
return fs25.existsSync(
|
|
28738
|
+
return fs25.existsSync(path57.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
28642
28739
|
}
|
|
28643
28740
|
function detectDartTest(cwd) {
|
|
28644
|
-
return fs25.existsSync(
|
|
28741
|
+
return fs25.existsSync(path57.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
28645
28742
|
}
|
|
28646
28743
|
function detectRSpec(cwd) {
|
|
28647
|
-
const hasRSpecFile = fs25.existsSync(
|
|
28648
|
-
const hasGemfile = fs25.existsSync(
|
|
28649
|
-
const hasSpecDir = fs25.existsSync(
|
|
28744
|
+
const hasRSpecFile = fs25.existsSync(path57.join(cwd, ".rspec"));
|
|
28745
|
+
const hasGemfile = fs25.existsSync(path57.join(cwd, "Gemfile"));
|
|
28746
|
+
const hasSpecDir = fs25.existsSync(path57.join(cwd, "spec"));
|
|
28650
28747
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
28651
28748
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
28652
28749
|
}
|
|
28653
28750
|
function detectMinitest(cwd) {
|
|
28654
|
-
return fs25.existsSync(
|
|
28751
|
+
return fs25.existsSync(path57.join(cwd, "test")) && (fs25.existsSync(path57.join(cwd, "Gemfile")) || fs25.existsSync(path57.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
28655
28752
|
}
|
|
28656
28753
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
28657
28754
|
bun: "bun",
|
|
@@ -28736,7 +28833,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
28736
28833
|
async function detectTestFramework(cwd) {
|
|
28737
28834
|
const baseDir = cwd;
|
|
28738
28835
|
try {
|
|
28739
|
-
const packageJsonPath =
|
|
28836
|
+
const packageJsonPath = path57.join(baseDir, "package.json");
|
|
28740
28837
|
if (fs25.existsSync(packageJsonPath)) {
|
|
28741
28838
|
const content = fs25.readFileSync(packageJsonPath, "utf-8");
|
|
28742
28839
|
const pkg = JSON.parse(content);
|
|
@@ -28757,16 +28854,16 @@ async function detectTestFramework(cwd) {
|
|
|
28757
28854
|
return "jest";
|
|
28758
28855
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
28759
28856
|
return "mocha";
|
|
28760
|
-
if (fs25.existsSync(
|
|
28857
|
+
if (fs25.existsSync(path57.join(baseDir, "bun.lockb")) || fs25.existsSync(path57.join(baseDir, "bun.lock"))) {
|
|
28761
28858
|
if (scripts.test?.includes("bun"))
|
|
28762
28859
|
return "bun";
|
|
28763
28860
|
}
|
|
28764
28861
|
}
|
|
28765
28862
|
} catch {}
|
|
28766
28863
|
try {
|
|
28767
|
-
const pyprojectTomlPath =
|
|
28768
|
-
const setupCfgPath =
|
|
28769
|
-
const requirementsTxtPath =
|
|
28864
|
+
const pyprojectTomlPath = path57.join(baseDir, "pyproject.toml");
|
|
28865
|
+
const setupCfgPath = path57.join(baseDir, "setup.cfg");
|
|
28866
|
+
const requirementsTxtPath = path57.join(baseDir, "requirements.txt");
|
|
28770
28867
|
if (fs25.existsSync(pyprojectTomlPath)) {
|
|
28771
28868
|
const content = fs25.readFileSync(pyprojectTomlPath, "utf-8");
|
|
28772
28869
|
if (content.includes("[tool.pytest"))
|
|
@@ -28786,7 +28883,7 @@ async function detectTestFramework(cwd) {
|
|
|
28786
28883
|
}
|
|
28787
28884
|
} catch {}
|
|
28788
28885
|
try {
|
|
28789
|
-
const cargoTomlPath =
|
|
28886
|
+
const cargoTomlPath = path57.join(baseDir, "Cargo.toml");
|
|
28790
28887
|
if (fs25.existsSync(cargoTomlPath)) {
|
|
28791
28888
|
const content = fs25.readFileSync(cargoTomlPath, "utf-8");
|
|
28792
28889
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -28797,9 +28894,9 @@ async function detectTestFramework(cwd) {
|
|
|
28797
28894
|
}
|
|
28798
28895
|
} catch {}
|
|
28799
28896
|
try {
|
|
28800
|
-
const pesterConfigPath =
|
|
28801
|
-
const pesterConfigJsonPath =
|
|
28802
|
-
const pesterPs1Path =
|
|
28897
|
+
const pesterConfigPath = path57.join(baseDir, "pester.config.ps1");
|
|
28898
|
+
const pesterConfigJsonPath = path57.join(baseDir, "pester.config.ps1.json");
|
|
28899
|
+
const pesterPs1Path = path57.join(baseDir, "tests.ps1");
|
|
28803
28900
|
if (fs25.existsSync(pesterConfigPath) || fs25.existsSync(pesterConfigJsonPath) || fs25.existsSync(pesterPs1Path)) {
|
|
28804
28901
|
return "pester";
|
|
28805
28902
|
}
|
|
@@ -28842,12 +28939,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
28842
28939
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
28843
28940
|
}
|
|
28844
28941
|
function resolveWorkspacePath(file, workingDir) {
|
|
28845
|
-
return
|
|
28942
|
+
return path57.isAbsolute(file) ? path57.resolve(file) : path57.resolve(workingDir, file);
|
|
28846
28943
|
}
|
|
28847
28944
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
28848
28945
|
if (!preferRelative)
|
|
28849
28946
|
return absolutePath;
|
|
28850
|
-
return
|
|
28947
|
+
return path57.relative(workingDir, absolutePath);
|
|
28851
28948
|
}
|
|
28852
28949
|
function dedupePush(target, value) {
|
|
28853
28950
|
if (!target.includes(value)) {
|
|
@@ -28884,18 +28981,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
28884
28981
|
}
|
|
28885
28982
|
}
|
|
28886
28983
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
28887
|
-
const relativeDir =
|
|
28984
|
+
const relativeDir = path57.dirname(relativePath);
|
|
28888
28985
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
28889
28986
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
28890
|
-
const rootDir =
|
|
28891
|
-
return nestedRelativeDir ? [rootDir,
|
|
28987
|
+
const rootDir = path57.join(workingDir, dirName);
|
|
28988
|
+
return nestedRelativeDir ? [rootDir, path57.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
28892
28989
|
});
|
|
28893
28990
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
28894
28991
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
28895
|
-
directories.push(
|
|
28992
|
+
directories.push(path57.join(workingDir, "src/test/java", path57.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
28896
28993
|
}
|
|
28897
28994
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
28898
|
-
directories.push(
|
|
28995
|
+
directories.push(path57.join(workingDir, "src/test/kotlin", path57.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
28899
28996
|
}
|
|
28900
28997
|
return [...new Set(directories)];
|
|
28901
28998
|
}
|
|
@@ -28923,23 +29020,23 @@ function isLanguageSpecificTestFile(basename10) {
|
|
|
28923
29020
|
}
|
|
28924
29021
|
function isConventionTestFilePath(filePath) {
|
|
28925
29022
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
28926
|
-
const basename10 =
|
|
29023
|
+
const basename10 = path57.basename(filePath);
|
|
28927
29024
|
return hasCompoundTestExtension(basename10) || basename10.includes(".spec.") || basename10.includes(".test.") || isLanguageSpecificTestFile(basename10) || isTestDirectoryPath(normalizedPath);
|
|
28928
29025
|
}
|
|
28929
29026
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
28930
29027
|
const testFiles = [];
|
|
28931
29028
|
for (const file of sourceFiles) {
|
|
28932
29029
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
28933
|
-
const relativeFile =
|
|
28934
|
-
const basename10 =
|
|
28935
|
-
const dirname25 =
|
|
28936
|
-
const preferRelativeOutput = !
|
|
29030
|
+
const relativeFile = path57.relative(workingDir, absoluteFile);
|
|
29031
|
+
const basename10 = path57.basename(absoluteFile);
|
|
29032
|
+
const dirname25 = path57.dirname(absoluteFile);
|
|
29033
|
+
const preferRelativeOutput = !path57.isAbsolute(file);
|
|
28937
29034
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
28938
29035
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
28939
29036
|
continue;
|
|
28940
29037
|
}
|
|
28941
29038
|
const nameWithoutExt = basename10.replace(/\.[^.]+$/, "");
|
|
28942
|
-
const ext =
|
|
29039
|
+
const ext = path57.extname(basename10);
|
|
28943
29040
|
const genericTestNames = [
|
|
28944
29041
|
`${nameWithoutExt}.spec${ext}`,
|
|
28945
29042
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -28948,7 +29045,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
28948
29045
|
const colocatedCandidates = [
|
|
28949
29046
|
...genericTestNames,
|
|
28950
29047
|
...languageSpecificTestNames
|
|
28951
|
-
].map((candidateName) =>
|
|
29048
|
+
].map((candidateName) => path57.join(dirname25, candidateName));
|
|
28952
29049
|
const testDirectoryNames = [
|
|
28953
29050
|
basename10,
|
|
28954
29051
|
...genericTestNames,
|
|
@@ -28957,8 +29054,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
28957
29054
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
28958
29055
|
const possibleTestFiles = [
|
|
28959
29056
|
...colocatedCandidates,
|
|
28960
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
28961
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
29057
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path57.join(dirname25, dirName, candidateName))),
|
|
29058
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path57.join(candidateDir, candidateName)))
|
|
28962
29059
|
];
|
|
28963
29060
|
for (const testFile of possibleTestFiles) {
|
|
28964
29061
|
if (fs25.existsSync(testFile)) {
|
|
@@ -28979,7 +29076,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
28979
29076
|
try {
|
|
28980
29077
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
28981
29078
|
const content = fs25.readFileSync(absoluteTestFile, "utf-8");
|
|
28982
|
-
const testDir =
|
|
29079
|
+
const testDir = path57.dirname(absoluteTestFile);
|
|
28983
29080
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
28984
29081
|
let match;
|
|
28985
29082
|
match = importRegex.exec(content);
|
|
@@ -28987,8 +29084,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
28987
29084
|
const importPath = match[1];
|
|
28988
29085
|
let resolvedImport;
|
|
28989
29086
|
if (importPath.startsWith(".")) {
|
|
28990
|
-
resolvedImport =
|
|
28991
|
-
const existingExt =
|
|
29087
|
+
resolvedImport = path57.resolve(testDir, importPath);
|
|
29088
|
+
const existingExt = path57.extname(resolvedImport);
|
|
28992
29089
|
if (!existingExt) {
|
|
28993
29090
|
for (const extToTry of [
|
|
28994
29091
|
".ts",
|
|
@@ -29008,12 +29105,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
29008
29105
|
} else {
|
|
29009
29106
|
continue;
|
|
29010
29107
|
}
|
|
29011
|
-
const importBasename =
|
|
29012
|
-
const importDir =
|
|
29108
|
+
const importBasename = path57.basename(resolvedImport, path57.extname(resolvedImport));
|
|
29109
|
+
const importDir = path57.dirname(resolvedImport);
|
|
29013
29110
|
for (const sourceFile of absoluteSourceFiles) {
|
|
29014
|
-
const sourceDir =
|
|
29015
|
-
const sourceBasename =
|
|
29016
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
29111
|
+
const sourceDir = path57.dirname(sourceFile);
|
|
29112
|
+
const sourceBasename = path57.basename(sourceFile, path57.extname(sourceFile));
|
|
29113
|
+
const isRelatedDir = importDir === sourceDir || importDir === path57.join(sourceDir, "__tests__") || importDir === path57.join(sourceDir, "tests") || importDir === path57.join(sourceDir, "test") || importDir === path57.join(sourceDir, "spec");
|
|
29017
29114
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
29018
29115
|
dedupePush(testFiles, testFile);
|
|
29019
29116
|
break;
|
|
@@ -29026,8 +29123,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
29026
29123
|
while (match !== null) {
|
|
29027
29124
|
const importPath = match[1];
|
|
29028
29125
|
if (importPath.startsWith(".")) {
|
|
29029
|
-
let resolvedImport =
|
|
29030
|
-
const existingExt =
|
|
29126
|
+
let resolvedImport = path57.resolve(testDir, importPath);
|
|
29127
|
+
const existingExt = path57.extname(resolvedImport);
|
|
29031
29128
|
if (!existingExt) {
|
|
29032
29129
|
for (const extToTry of [
|
|
29033
29130
|
".ts",
|
|
@@ -29044,12 +29141,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
29044
29141
|
}
|
|
29045
29142
|
}
|
|
29046
29143
|
}
|
|
29047
|
-
const importDir =
|
|
29048
|
-
const importBasename =
|
|
29144
|
+
const importDir = path57.dirname(resolvedImport);
|
|
29145
|
+
const importBasename = path57.basename(resolvedImport, path57.extname(resolvedImport));
|
|
29049
29146
|
for (const sourceFile of absoluteSourceFiles) {
|
|
29050
|
-
const sourceDir =
|
|
29051
|
-
const sourceBasename =
|
|
29052
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
29147
|
+
const sourceDir = path57.dirname(sourceFile);
|
|
29148
|
+
const sourceBasename = path57.basename(sourceFile, path57.extname(sourceFile));
|
|
29149
|
+
const isRelatedDir = importDir === sourceDir || importDir === path57.join(sourceDir, "__tests__") || importDir === path57.join(sourceDir, "tests") || importDir === path57.join(sourceDir, "test") || importDir === path57.join(sourceDir, "spec");
|
|
29053
29150
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
29054
29151
|
dedupePush(testFiles, testFile);
|
|
29055
29152
|
break;
|
|
@@ -29169,8 +29266,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
29169
29266
|
return ["mvn", "test"];
|
|
29170
29267
|
case "gradle": {
|
|
29171
29268
|
const isWindows = process.platform === "win32";
|
|
29172
|
-
const hasGradlewBat = fs25.existsSync(
|
|
29173
|
-
const hasGradlew = fs25.existsSync(
|
|
29269
|
+
const hasGradlewBat = fs25.existsSync(path57.join(baseDir, "gradlew.bat"));
|
|
29270
|
+
const hasGradlew = fs25.existsSync(path57.join(baseDir, "gradlew"));
|
|
29174
29271
|
if (hasGradlewBat && isWindows)
|
|
29175
29272
|
return ["gradlew.bat", "test"];
|
|
29176
29273
|
if (hasGradlew)
|
|
@@ -29187,7 +29284,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
29187
29284
|
"cmake-build-release",
|
|
29188
29285
|
"out"
|
|
29189
29286
|
];
|
|
29190
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs25.existsSync(
|
|
29287
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs25.existsSync(path57.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
29191
29288
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
29192
29289
|
}
|
|
29193
29290
|
case "swift-test":
|
|
@@ -29621,11 +29718,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
29621
29718
|
};
|
|
29622
29719
|
}
|
|
29623
29720
|
const startTime = Date.now();
|
|
29624
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
29721
|
+
const vitestJsonOutputPath = framework === "vitest" ? path57.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
29625
29722
|
try {
|
|
29626
29723
|
if (vitestJsonOutputPath) {
|
|
29627
29724
|
try {
|
|
29628
|
-
fs25.mkdirSync(
|
|
29725
|
+
fs25.mkdirSync(path57.dirname(vitestJsonOutputPath), { recursive: true });
|
|
29629
29726
|
if (fs25.existsSync(vitestJsonOutputPath)) {
|
|
29630
29727
|
fs25.unlinkSync(vitestJsonOutputPath);
|
|
29631
29728
|
}
|
|
@@ -29793,10 +29890,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
29793
29890
|
]);
|
|
29794
29891
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
29795
29892
|
const normalized = testFile.replace(/\\/g, "/");
|
|
29796
|
-
if (!
|
|
29893
|
+
if (!path57.isAbsolute(testFile))
|
|
29797
29894
|
return normalized;
|
|
29798
|
-
const relative8 =
|
|
29799
|
-
if (relative8.startsWith("..") ||
|
|
29895
|
+
const relative8 = path57.relative(workingDir, testFile);
|
|
29896
|
+
if (relative8.startsWith("..") || path57.isAbsolute(relative8)) {
|
|
29800
29897
|
return normalized;
|
|
29801
29898
|
}
|
|
29802
29899
|
return relative8.replace(/\\/g, "/");
|
|
@@ -30035,7 +30132,7 @@ var test_runner = createSwarmTool({
|
|
|
30035
30132
|
const sourceFiles = args.files.filter((file) => {
|
|
30036
30133
|
if (directTestFiles.includes(file))
|
|
30037
30134
|
return false;
|
|
30038
|
-
const ext =
|
|
30135
|
+
const ext = path57.extname(file).toLowerCase();
|
|
30039
30136
|
return SOURCE_EXTENSIONS.has(ext);
|
|
30040
30137
|
});
|
|
30041
30138
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -30081,7 +30178,7 @@ var test_runner = createSwarmTool({
|
|
|
30081
30178
|
if (isConventionTestFilePath(f)) {
|
|
30082
30179
|
return false;
|
|
30083
30180
|
}
|
|
30084
|
-
const ext =
|
|
30181
|
+
const ext = path57.extname(f).toLowerCase();
|
|
30085
30182
|
return SOURCE_EXTENSIONS.has(ext);
|
|
30086
30183
|
});
|
|
30087
30184
|
if (sourceFiles.length === 0) {
|
|
@@ -30131,7 +30228,7 @@ var test_runner = createSwarmTool({
|
|
|
30131
30228
|
if (isConventionTestFilePath(f)) {
|
|
30132
30229
|
return false;
|
|
30133
30230
|
}
|
|
30134
|
-
const ext =
|
|
30231
|
+
const ext = path57.extname(f).toLowerCase();
|
|
30135
30232
|
return SOURCE_EXTENSIONS.has(ext);
|
|
30136
30233
|
});
|
|
30137
30234
|
if (sourceFiles.length === 0) {
|
|
@@ -30183,8 +30280,8 @@ var test_runner = createSwarmTool({
|
|
|
30183
30280
|
}
|
|
30184
30281
|
if (impactResult.impactedTests.length > 0) {
|
|
30185
30282
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
30186
|
-
const relativePath =
|
|
30187
|
-
return
|
|
30283
|
+
const relativePath = path57.relative(workingDir, absPath);
|
|
30284
|
+
return path57.isAbsolute(relativePath) ? absPath : relativePath;
|
|
30188
30285
|
});
|
|
30189
30286
|
} else {
|
|
30190
30287
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -30279,8 +30376,8 @@ function validateDirectoryPath(dir) {
|
|
|
30279
30376
|
if (dir.includes("..")) {
|
|
30280
30377
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
30281
30378
|
}
|
|
30282
|
-
const normalized =
|
|
30283
|
-
const absolutePath =
|
|
30379
|
+
const normalized = path58.normalize(dir);
|
|
30380
|
+
const absolutePath = path58.isAbsolute(normalized) ? normalized : path58.resolve(normalized);
|
|
30284
30381
|
return absolutePath;
|
|
30285
30382
|
}
|
|
30286
30383
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -30303,7 +30400,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
30303
30400
|
}
|
|
30304
30401
|
function getPackageVersion(dir) {
|
|
30305
30402
|
try {
|
|
30306
|
-
const packagePath =
|
|
30403
|
+
const packagePath = path58.join(dir, "package.json");
|
|
30307
30404
|
if (fs26.existsSync(packagePath)) {
|
|
30308
30405
|
const content = fs26.readFileSync(packagePath, "utf-8");
|
|
30309
30406
|
const pkg = JSON.parse(content);
|
|
@@ -30314,7 +30411,7 @@ function getPackageVersion(dir) {
|
|
|
30314
30411
|
}
|
|
30315
30412
|
function getChangelogVersion(dir) {
|
|
30316
30413
|
try {
|
|
30317
|
-
const changelogPath =
|
|
30414
|
+
const changelogPath = path58.join(dir, "CHANGELOG.md");
|
|
30318
30415
|
if (fs26.existsSync(changelogPath)) {
|
|
30319
30416
|
const content = fs26.readFileSync(changelogPath, "utf-8");
|
|
30320
30417
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -30328,7 +30425,7 @@ function getChangelogVersion(dir) {
|
|
|
30328
30425
|
function getVersionFileVersion(dir) {
|
|
30329
30426
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
30330
30427
|
for (const file of possibleFiles) {
|
|
30331
|
-
const filePath =
|
|
30428
|
+
const filePath = path58.join(dir, file);
|
|
30332
30429
|
if (fs26.existsSync(filePath)) {
|
|
30333
30430
|
try {
|
|
30334
30431
|
const content = fs26.readFileSync(filePath, "utf-8").trim();
|
|
@@ -31066,7 +31163,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
31066
31163
|
|
|
31067
31164
|
// src/commands/reset.ts
|
|
31068
31165
|
import * as fs27 from "fs";
|
|
31069
|
-
import * as
|
|
31166
|
+
import * as path59 from "path";
|
|
31070
31167
|
|
|
31071
31168
|
// src/background/circuit-breaker.ts
|
|
31072
31169
|
class CircuitBreaker {
|
|
@@ -31785,7 +31882,7 @@ async function handleResetCommand(directory, args) {
|
|
|
31785
31882
|
}
|
|
31786
31883
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
31787
31884
|
try {
|
|
31788
|
-
const rootPath =
|
|
31885
|
+
const rootPath = path59.join(directory, filename);
|
|
31789
31886
|
if (fs27.existsSync(rootPath)) {
|
|
31790
31887
|
fs27.unlinkSync(rootPath);
|
|
31791
31888
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -31823,7 +31920,7 @@ async function handleResetCommand(directory, args) {
|
|
|
31823
31920
|
|
|
31824
31921
|
// src/commands/reset-session.ts
|
|
31825
31922
|
import * as fs29 from "fs";
|
|
31826
|
-
import * as
|
|
31923
|
+
import * as path61 from "path";
|
|
31827
31924
|
|
|
31828
31925
|
// src/hooks/trajectory-logger.ts
|
|
31829
31926
|
var callStartTimes = new Map;
|
|
@@ -32230,16 +32327,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
32230
32327
|
}
|
|
32231
32328
|
// src/prm/replay.ts
|
|
32232
32329
|
import { promises as fs28 } from "fs";
|
|
32233
|
-
import
|
|
32330
|
+
import path60 from "path";
|
|
32234
32331
|
function isPathSafe(targetPath, basePath) {
|
|
32235
|
-
const resolvedTarget =
|
|
32236
|
-
const resolvedBase =
|
|
32237
|
-
const rel =
|
|
32238
|
-
return !rel.startsWith("..") && !
|
|
32332
|
+
const resolvedTarget = path60.resolve(targetPath);
|
|
32333
|
+
const resolvedBase = path60.resolve(basePath);
|
|
32334
|
+
const rel = path60.relative(resolvedBase, resolvedTarget);
|
|
32335
|
+
return !rel.startsWith("..") && !path60.isAbsolute(rel);
|
|
32239
32336
|
}
|
|
32240
32337
|
function isWithinReplaysDir(targetPath) {
|
|
32241
|
-
const resolved =
|
|
32242
|
-
const parts = resolved.split(
|
|
32338
|
+
const resolved = path60.resolve(targetPath);
|
|
32339
|
+
const parts = resolved.split(path60.sep);
|
|
32243
32340
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
32244
32341
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
32245
32342
|
return true;
|
|
@@ -32252,10 +32349,10 @@ function sanitizeFilename(input) {
|
|
|
32252
32349
|
}
|
|
32253
32350
|
async function startReplayRecording(sessionID, directory) {
|
|
32254
32351
|
try {
|
|
32255
|
-
const replayDir =
|
|
32352
|
+
const replayDir = path60.join(directory, ".swarm", "replays");
|
|
32256
32353
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
32257
32354
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
32258
|
-
const filepath =
|
|
32355
|
+
const filepath = path60.join(replayDir, filename);
|
|
32259
32356
|
if (!isPathSafe(filepath, replayDir)) {
|
|
32260
32357
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
32261
32358
|
return null;
|
|
@@ -32315,6 +32412,9 @@ function resetPrmSessionState(session, sessionId) {
|
|
|
32315
32412
|
}
|
|
32316
32413
|
|
|
32317
32414
|
// src/commands/reset-session.ts
|
|
32415
|
+
var _internals46 = {
|
|
32416
|
+
cleanupOrphanedBranches
|
|
32417
|
+
};
|
|
32318
32418
|
function errorMessage(err) {
|
|
32319
32419
|
if (err instanceof Error)
|
|
32320
32420
|
return err.message;
|
|
@@ -32333,7 +32433,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
32333
32433
|
} catch {
|
|
32334
32434
|
results.push("\u274C Failed to delete state.json");
|
|
32335
32435
|
}
|
|
32336
|
-
const sessionDir =
|
|
32436
|
+
const sessionDir = path61.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
32337
32437
|
let sessionFiles = [];
|
|
32338
32438
|
if (fs29.existsSync(sessionDir)) {
|
|
32339
32439
|
try {
|
|
@@ -32345,7 +32445,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
32345
32445
|
for (const file of sessionFiles) {
|
|
32346
32446
|
if (file === "state.json")
|
|
32347
32447
|
continue;
|
|
32348
|
-
const filePath =
|
|
32448
|
+
const filePath = path61.join(sessionDir, file);
|
|
32349
32449
|
try {
|
|
32350
32450
|
if (!fs29.existsSync(filePath))
|
|
32351
32451
|
continue;
|
|
@@ -32367,6 +32467,26 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
32367
32467
|
const chainCount = swarmState.delegationChains.size;
|
|
32368
32468
|
swarmState.delegationChains.clear();
|
|
32369
32469
|
results.push(`\u2705 Cleared ${chainCount} delegation chain(s)`);
|
|
32470
|
+
const worktreesDir = path61.resolve(path61.dirname(directory), ".swarm-worktrees");
|
|
32471
|
+
try {
|
|
32472
|
+
if (fs29.existsSync(worktreesDir)) {
|
|
32473
|
+
fs29.rmSync(worktreesDir, { recursive: true, force: true });
|
|
32474
|
+
results.push("\u2705 Removed .swarm-worktrees/ directory");
|
|
32475
|
+
}
|
|
32476
|
+
} catch (err) {
|
|
32477
|
+
results.push(`\u26A0\uFE0F Failed to remove .swarm-worktrees/: ${errorMessage(err)}`);
|
|
32478
|
+
}
|
|
32479
|
+
try {
|
|
32480
|
+
const branchResult = await _internals46.cleanupOrphanedBranches(directory, []);
|
|
32481
|
+
if (branchResult.removed.length > 0) {
|
|
32482
|
+
results.push(`\u2705 Removed ${branchResult.removed.length} orphan swarm-lane branch(es)`);
|
|
32483
|
+
}
|
|
32484
|
+
if (branchResult.errors.length > 0) {
|
|
32485
|
+
results.push(`\u26A0\uFE0F Failed to remove ${branchResult.errors.length} branch(es): ${branchResult.errors.map((e) => e.error).join("; ")}`);
|
|
32486
|
+
}
|
|
32487
|
+
} catch (err) {
|
|
32488
|
+
results.push(`\u26A0\uFE0F Failed to cleanup orphan branches: ${errorMessage(err)}`);
|
|
32489
|
+
}
|
|
32370
32490
|
return [
|
|
32371
32491
|
"## Session State Reset",
|
|
32372
32492
|
"",
|
|
@@ -32380,7 +32500,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
32380
32500
|
}
|
|
32381
32501
|
|
|
32382
32502
|
// src/summaries/manager.ts
|
|
32383
|
-
import * as
|
|
32503
|
+
import * as path62 from "path";
|
|
32384
32504
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
32385
32505
|
function sanitizeSummaryId(id) {
|
|
32386
32506
|
if (!id || id.length === 0) {
|
|
@@ -32404,7 +32524,7 @@ function sanitizeSummaryId(id) {
|
|
|
32404
32524
|
}
|
|
32405
32525
|
async function loadFullOutput(directory, id) {
|
|
32406
32526
|
const sanitizedId = sanitizeSummaryId(id);
|
|
32407
|
-
const relativePath =
|
|
32527
|
+
const relativePath = path62.join("summaries", `${sanitizedId}.json`);
|
|
32408
32528
|
validateSwarmPath(directory, relativePath);
|
|
32409
32529
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
32410
32530
|
if (content === null) {
|
|
@@ -32457,7 +32577,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
32457
32577
|
|
|
32458
32578
|
// src/commands/rollback.ts
|
|
32459
32579
|
import * as fs30 from "fs";
|
|
32460
|
-
import * as
|
|
32580
|
+
import * as path63 from "path";
|
|
32461
32581
|
async function handleRollbackCommand(directory, args) {
|
|
32462
32582
|
const phaseArg = args[0];
|
|
32463
32583
|
if (!phaseArg) {
|
|
@@ -32523,8 +32643,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
32523
32643
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
32524
32644
|
continue;
|
|
32525
32645
|
}
|
|
32526
|
-
const src =
|
|
32527
|
-
const dest =
|
|
32646
|
+
const src = path63.join(checkpointDir, file);
|
|
32647
|
+
const dest = path63.join(swarmDir, file);
|
|
32528
32648
|
try {
|
|
32529
32649
|
fs30.cpSync(src, dest, { recursive: true, force: true });
|
|
32530
32650
|
successes.push(file);
|
|
@@ -32543,7 +32663,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
32543
32663
|
].join(`
|
|
32544
32664
|
`);
|
|
32545
32665
|
}
|
|
32546
|
-
const existingLedgerPath =
|
|
32666
|
+
const existingLedgerPath = path63.join(swarmDir, "plan-ledger.jsonl");
|
|
32547
32667
|
let ledgerDeletionFailed = false;
|
|
32548
32668
|
if (fs30.existsSync(existingLedgerPath)) {
|
|
32549
32669
|
try {
|
|
@@ -32556,7 +32676,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
32556
32676
|
}
|
|
32557
32677
|
if (!ledgerDeletionFailed) {
|
|
32558
32678
|
try {
|
|
32559
|
-
const planJsonPath =
|
|
32679
|
+
const planJsonPath = path63.join(swarmDir, "plan.json");
|
|
32560
32680
|
if (fs30.existsSync(planJsonPath)) {
|
|
32561
32681
|
const planRaw = fs30.readFileSync(planJsonPath, "utf-8");
|
|
32562
32682
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -32604,8 +32724,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
32604
32724
|
|
|
32605
32725
|
// src/commands/sdd.ts
|
|
32606
32726
|
import * as fs31 from "fs";
|
|
32607
|
-
import * as
|
|
32608
|
-
var SWARM_SPEC_REL =
|
|
32727
|
+
import * as path64 from "path";
|
|
32728
|
+
var SWARM_SPEC_REL = path64.join(".swarm", "spec.md");
|
|
32609
32729
|
var USAGE9 = `Usage:
|
|
32610
32730
|
/swarm sdd status [--json] [--source <provider>]
|
|
32611
32731
|
/swarm sdd validate [--json] [--change <id>] [--source <provider>] [--feature <id>]
|
|
@@ -32721,7 +32841,7 @@ ${USAGE9}`;
|
|
|
32721
32841
|
}
|
|
32722
32842
|
const speckitDetection = detectSpeckit(directory);
|
|
32723
32843
|
const speckitPresent = speckitDetection.features.length > 0;
|
|
32724
|
-
const nativeSpecExists = fs31.existsSync(
|
|
32844
|
+
const nativeSpecExists = fs31.existsSync(path64.join(directory, SWARM_SPEC_REL));
|
|
32725
32845
|
if (speckitPresent && !parsed.source && !nativeSpecExists) {
|
|
32726
32846
|
const openspecProjection = buildOpenSpecProjectionSync(directory);
|
|
32727
32847
|
if (openspecProjection !== null) {
|
|
@@ -32791,7 +32911,7 @@ ${USAGE9}`;
|
|
|
32791
32911
|
${USAGE9}`;
|
|
32792
32912
|
}
|
|
32793
32913
|
let useSpeckit = false;
|
|
32794
|
-
const nativeSpecExists = fs31.existsSync(
|
|
32914
|
+
const nativeSpecExists = fs31.existsSync(path64.join(directory, SWARM_SPEC_REL));
|
|
32795
32915
|
if (parsed.source === "speckit") {
|
|
32796
32916
|
useSpeckit = true;
|
|
32797
32917
|
} else if (!parsed.source && !nativeSpecExists) {
|
|
@@ -33103,10 +33223,10 @@ Ensure this is a git repository with commit history.`;
|
|
|
33103
33223
|
`);
|
|
33104
33224
|
try {
|
|
33105
33225
|
const fs32 = await import("fs/promises");
|
|
33106
|
-
const
|
|
33107
|
-
const reportPath =
|
|
33108
|
-
await fs32.mkdir(
|
|
33109
|
-
const reportTempPath =
|
|
33226
|
+
const path65 = await import("path");
|
|
33227
|
+
const reportPath = path65.join(directory, ".swarm", "simulate-report.md");
|
|
33228
|
+
await fs32.mkdir(path65.dirname(reportPath), { recursive: true });
|
|
33229
|
+
const reportTempPath = path65.join(path65.dirname(reportPath), `${path65.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
33110
33230
|
try {
|
|
33111
33231
|
await fs32.writeFile(reportTempPath, report, "utf-8");
|
|
33112
33232
|
renameSync11(reportTempPath, reportPath);
|
|
@@ -33135,18 +33255,18 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
33135
33255
|
// src/services/status-service.ts
|
|
33136
33256
|
import * as fsSync3 from "fs";
|
|
33137
33257
|
import { readFile as readFile16 } from "fs/promises";
|
|
33138
|
-
import * as
|
|
33258
|
+
import * as path66 from "path";
|
|
33139
33259
|
|
|
33140
33260
|
// src/turbo/lean/state.ts
|
|
33141
33261
|
init_logger();
|
|
33142
33262
|
import * as fs32 from "fs";
|
|
33143
|
-
import * as
|
|
33263
|
+
import * as path65 from "path";
|
|
33144
33264
|
var STATE_FILE3 = "turbo-state.json";
|
|
33145
33265
|
function nowISO3() {
|
|
33146
33266
|
return new Date().toISOString();
|
|
33147
33267
|
}
|
|
33148
33268
|
function ensureSwarmDir2(directory) {
|
|
33149
|
-
const swarmDir =
|
|
33269
|
+
const swarmDir = path65.resolve(directory, ".swarm");
|
|
33150
33270
|
if (!fs32.existsSync(swarmDir)) {
|
|
33151
33271
|
fs32.mkdirSync(swarmDir, { recursive: true });
|
|
33152
33272
|
}
|
|
@@ -33191,7 +33311,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
33191
33311
|
}
|
|
33192
33312
|
function readPersisted2(directory) {
|
|
33193
33313
|
try {
|
|
33194
|
-
const filePath =
|
|
33314
|
+
const filePath = path65.join(directory, ".swarm", STATE_FILE3);
|
|
33195
33315
|
if (!fs32.existsSync(filePath)) {
|
|
33196
33316
|
const seed = emptyPersisted2();
|
|
33197
33317
|
try {
|
|
@@ -33227,7 +33347,7 @@ function writePersisted2(directory, persisted) {
|
|
|
33227
33347
|
let payload;
|
|
33228
33348
|
try {
|
|
33229
33349
|
ensureSwarmDir2(directory);
|
|
33230
|
-
filePath =
|
|
33350
|
+
filePath = path65.join(directory, ".swarm", STATE_FILE3);
|
|
33231
33351
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
33232
33352
|
persisted.updatedAt = nowISO3();
|
|
33233
33353
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -33338,14 +33458,14 @@ var DEFAULT_CONTEXT_BUDGET_CONFIG = {
|
|
|
33338
33458
|
};
|
|
33339
33459
|
|
|
33340
33460
|
// src/services/status-service.ts
|
|
33341
|
-
var
|
|
33461
|
+
var _internals47 = {
|
|
33342
33462
|
loadLeanTurboRunState,
|
|
33343
33463
|
hasActiveLeanTurbo,
|
|
33344
33464
|
hasActiveFullAuto
|
|
33345
33465
|
};
|
|
33346
33466
|
function readSpecStalenessSnapshot(directory) {
|
|
33347
33467
|
try {
|
|
33348
|
-
const p =
|
|
33468
|
+
const p = path66.join(directory, ".swarm", "spec-staleness.json");
|
|
33349
33469
|
if (!fsSync3.existsSync(p))
|
|
33350
33470
|
return { stale: false };
|
|
33351
33471
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -33443,7 +33563,7 @@ async function getStatusData(directory, agents) {
|
|
|
33443
33563
|
}
|
|
33444
33564
|
function enrichWithLeanTurbo(status, directory) {
|
|
33445
33565
|
const turboMode = hasActiveTurboMode();
|
|
33446
|
-
const leanActive =
|
|
33566
|
+
const leanActive = _internals47.hasActiveLeanTurbo();
|
|
33447
33567
|
let turboStrategy = "off";
|
|
33448
33568
|
if (leanActive) {
|
|
33449
33569
|
turboStrategy = "lean";
|
|
@@ -33462,7 +33582,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
33462
33582
|
}
|
|
33463
33583
|
}
|
|
33464
33584
|
if (leanSessionID) {
|
|
33465
|
-
const runState =
|
|
33585
|
+
const runState = _internals47.loadLeanTurboRunState(directory, leanSessionID);
|
|
33466
33586
|
if (runState) {
|
|
33467
33587
|
status.leanTurboPhase = runState.phase;
|
|
33468
33588
|
status.leanMaxParallelCoders = runState.maxParallelCoders;
|
|
@@ -33494,7 +33614,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
33494
33614
|
}
|
|
33495
33615
|
}
|
|
33496
33616
|
}
|
|
33497
|
-
status.fullAutoActive =
|
|
33617
|
+
status.fullAutoActive = _internals47.hasActiveFullAuto();
|
|
33498
33618
|
return status;
|
|
33499
33619
|
}
|
|
33500
33620
|
function formatStatusMarkdown(status) {
|
|
@@ -33648,7 +33768,7 @@ No active swarm plan found. Nothing to sync.`;
|
|
|
33648
33768
|
|
|
33649
33769
|
// src/commands/turbo.ts
|
|
33650
33770
|
init_logger();
|
|
33651
|
-
var
|
|
33771
|
+
var _internals48 = {
|
|
33652
33772
|
loadPluginConfigWithMeta
|
|
33653
33773
|
};
|
|
33654
33774
|
async function handleTurboCommand(directory, args, sessionID) {
|
|
@@ -33708,7 +33828,7 @@ async function handleTurboCommand(directory, args, sessionID) {
|
|
|
33708
33828
|
if (arg0 === "on") {
|
|
33709
33829
|
let strategy = "standard";
|
|
33710
33830
|
try {
|
|
33711
|
-
const { config } =
|
|
33831
|
+
const { config } = _internals48.loadPluginConfigWithMeta(directory);
|
|
33712
33832
|
if (config.turbo?.strategy === "lean") {
|
|
33713
33833
|
strategy = "lean";
|
|
33714
33834
|
}
|
|
@@ -33805,7 +33925,7 @@ function enableLeanTurbo(session, directory, sessionID) {
|
|
|
33805
33925
|
let maxParallelCoders = 4;
|
|
33806
33926
|
let conflictPolicy = "serialize";
|
|
33807
33927
|
try {
|
|
33808
|
-
const { config } =
|
|
33928
|
+
const { config } = _internals48.loadPluginConfigWithMeta(directory);
|
|
33809
33929
|
const leanConfig = config.turbo?.lean;
|
|
33810
33930
|
if (leanConfig) {
|
|
33811
33931
|
maxParallelCoders = leanConfig.max_parallel_coders ?? 4;
|
|
@@ -33878,11 +33998,11 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
33878
33998
|
|
|
33879
33999
|
// src/commands/unlink.ts
|
|
33880
34000
|
import { existsSync as existsSync38 } from "fs";
|
|
33881
|
-
import * as
|
|
34001
|
+
import * as path67 from "path";
|
|
33882
34002
|
var DEDUP_THRESHOLD2 = 0.6;
|
|
33883
34003
|
async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
|
|
33884
|
-
const sharedPath =
|
|
33885
|
-
const localPath =
|
|
34004
|
+
const sharedPath = path67.join(linkDir, "knowledge.jsonl");
|
|
34005
|
+
const localPath = path67.join(localSwarmDir, "knowledge.jsonl");
|
|
33886
34006
|
if (!existsSync38(sharedPath))
|
|
33887
34007
|
return 0;
|
|
33888
34008
|
const sharedEntries = await readKnowledge(sharedPath);
|
|
@@ -33917,7 +34037,7 @@ async function handleUnlinkCommand(directory, args) {
|
|
|
33917
34037
|
let copied = 0;
|
|
33918
34038
|
if (copyBack) {
|
|
33919
34039
|
try {
|
|
33920
|
-
copied = await copySharedKnowledgeToLocal(linkDir,
|
|
34040
|
+
copied = await copySharedKnowledgeToLocal(linkDir, path67.join(directory, ".swarm"));
|
|
33921
34041
|
} catch (error2) {
|
|
33922
34042
|
return `\u274C Failed to copy shared knowledge back to local: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
33923
34043
|
}
|
|
@@ -34021,7 +34141,7 @@ function findSimilarCommands(query) {
|
|
|
34021
34141
|
}
|
|
34022
34142
|
const scored = VALID_COMMANDS.map((cmd) => {
|
|
34023
34143
|
const cmdLower = cmd.toLowerCase();
|
|
34024
|
-
const fullScore =
|
|
34144
|
+
const fullScore = _internals49.levenshteinDistance(q, cmdLower);
|
|
34025
34145
|
let tokenScore = Infinity;
|
|
34026
34146
|
if (cmd.includes(" ") || cmd.includes("-")) {
|
|
34027
34147
|
const qTokens = q.split(/[\s-]+/);
|
|
@@ -34034,7 +34154,7 @@ function findSimilarCommands(query) {
|
|
|
34034
34154
|
for (const ct of cmdTokens) {
|
|
34035
34155
|
if (ct.length === 0)
|
|
34036
34156
|
continue;
|
|
34037
|
-
const dist =
|
|
34157
|
+
const dist = _internals49.levenshteinDistance(qt, ct);
|
|
34038
34158
|
if (dist < minDist)
|
|
34039
34159
|
minDist = dist;
|
|
34040
34160
|
}
|
|
@@ -34044,7 +34164,7 @@ function findSimilarCommands(query) {
|
|
|
34044
34164
|
}
|
|
34045
34165
|
const dashStrippedQ = q.replace(/-/g, "");
|
|
34046
34166
|
const dashStrippedCmd = cmdLower.replace(/-/g, "");
|
|
34047
|
-
const dashScore =
|
|
34167
|
+
const dashScore = _internals49.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
|
|
34048
34168
|
const score = Math.min(fullScore, tokenScore, dashScore);
|
|
34049
34169
|
return { cmd, score };
|
|
34050
34170
|
});
|
|
@@ -34079,16 +34199,16 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
34079
34199
|
async function handleHelpCommand(ctx) {
|
|
34080
34200
|
const targetCommand = ctx.args.join(" ");
|
|
34081
34201
|
if (!targetCommand) {
|
|
34082
|
-
const { buildHelpText } = await import("./index-
|
|
34202
|
+
const { buildHelpText } = await import("./index-v90bnn0f.js");
|
|
34083
34203
|
return buildHelpText();
|
|
34084
34204
|
}
|
|
34085
34205
|
const tokens = targetCommand.split(/\s+/);
|
|
34086
|
-
const resolved =
|
|
34206
|
+
const resolved = _internals49.resolveCommand(tokens);
|
|
34087
34207
|
if (resolved) {
|
|
34088
|
-
return
|
|
34208
|
+
return _internals49.buildDetailedHelp(resolved.key, resolved.entry);
|
|
34089
34209
|
}
|
|
34090
|
-
const similar =
|
|
34091
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
34210
|
+
const similar = _internals49.findSimilarCommands(targetCommand);
|
|
34211
|
+
const { buildHelpText: fullHelp } = await import("./index-v90bnn0f.js");
|
|
34092
34212
|
if (similar.length > 0) {
|
|
34093
34213
|
return `Command '/swarm ${targetCommand}' not found.
|
|
34094
34214
|
|
|
@@ -34152,7 +34272,7 @@ var COMMAND_REGISTRY = {
|
|
|
34152
34272
|
toolNoArgs: true
|
|
34153
34273
|
},
|
|
34154
34274
|
help: {
|
|
34155
|
-
handler: (ctx) =>
|
|
34275
|
+
handler: (ctx) => _internals49.handleHelpCommand(ctx),
|
|
34156
34276
|
description: "Show help for swarm commands",
|
|
34157
34277
|
category: "core",
|
|
34158
34278
|
args: "[command]",
|
|
@@ -34221,7 +34341,7 @@ var COMMAND_REGISTRY = {
|
|
|
34221
34341
|
},
|
|
34222
34342
|
"guardrail explain": {
|
|
34223
34343
|
handler: async (ctx) => {
|
|
34224
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
34344
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-6xt0pb56.js");
|
|
34225
34345
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
34226
34346
|
},
|
|
34227
34347
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -35002,24 +35122,24 @@ function validateAliases() {
|
|
|
35002
35122
|
continue;
|
|
35003
35123
|
}
|
|
35004
35124
|
const visited = new Set;
|
|
35005
|
-
const
|
|
35125
|
+
const path68 = [];
|
|
35006
35126
|
let current = target;
|
|
35007
35127
|
while (current) {
|
|
35008
35128
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
35009
35129
|
if (!currentEntry)
|
|
35010
35130
|
break;
|
|
35011
35131
|
if (visited.has(current)) {
|
|
35012
|
-
const cycleStart =
|
|
35132
|
+
const cycleStart = path68.indexOf(current);
|
|
35013
35133
|
const fullChain = [
|
|
35014
35134
|
name,
|
|
35015
|
-
...
|
|
35135
|
+
...path68.slice(0, cycleStart > 0 ? cycleStart : path68.length),
|
|
35016
35136
|
current
|
|
35017
35137
|
].join(" \u2192 ");
|
|
35018
35138
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
35019
35139
|
break;
|
|
35020
35140
|
}
|
|
35021
35141
|
visited.add(current);
|
|
35022
|
-
|
|
35142
|
+
path68.push(current);
|
|
35023
35143
|
current = currentEntry.aliasOf || "";
|
|
35024
35144
|
}
|
|
35025
35145
|
}
|
|
@@ -35038,7 +35158,7 @@ function validateToolPolicy() {
|
|
|
35038
35158
|
}
|
|
35039
35159
|
return { valid: warnings.length === 0, warnings };
|
|
35040
35160
|
}
|
|
35041
|
-
var
|
|
35161
|
+
var _internals49 = {
|
|
35042
35162
|
handleHelpCommand,
|
|
35043
35163
|
validateAliases,
|
|
35044
35164
|
validateToolPolicy,
|
|
@@ -35048,16 +35168,16 @@ var _internals48 = {
|
|
|
35048
35168
|
findSimilarCommands,
|
|
35049
35169
|
buildDetailedHelp
|
|
35050
35170
|
};
|
|
35051
|
-
var validation =
|
|
35171
|
+
var validation = _internals49.validateAliases();
|
|
35052
35172
|
if (!validation.valid) {
|
|
35053
35173
|
throw new Error(`COMMAND_REGISTRY alias validation failed:
|
|
35054
35174
|
${validation.errors.join(`
|
|
35055
35175
|
`)}`);
|
|
35056
35176
|
}
|
|
35057
|
-
|
|
35177
|
+
_internals49.emitValidationWarnings("COMMAND_REGISTRY alias warnings", validation.warnings);
|
|
35058
35178
|
try {
|
|
35059
|
-
const toolPolicyValidation =
|
|
35060
|
-
|
|
35179
|
+
const toolPolicyValidation = _internals49.validateToolPolicy();
|
|
35180
|
+
_internals49.emitValidationWarnings("COMMAND_REGISTRY toolPolicy warnings", toolPolicyValidation.warnings);
|
|
35061
35181
|
} catch (e) {
|
|
35062
35182
|
warn(`COMMAND_REGISTRY toolPolicy validation failed (non-fatal): ${e.message}`);
|
|
35063
35183
|
}
|
|
@@ -35116,7 +35236,7 @@ function formatCommandNotFound(tokens) {
|
|
|
35116
35236
|
const attemptedCommand = tokens[0] || "";
|
|
35117
35237
|
const MAX_DISPLAY = 100;
|
|
35118
35238
|
const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
|
|
35119
|
-
const similar =
|
|
35239
|
+
const similar = _internals49.findSimilarCommands(attemptedCommand);
|
|
35120
35240
|
const header = `Command \`/swarm ${displayCommand}\` not found.`;
|
|
35121
35241
|
const suggestions = similar.length > 0 ? `Did you mean:
|
|
35122
35242
|
${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
@@ -35173,4 +35293,4 @@ ${text}`;
|
|
|
35173
35293
|
};
|
|
35174
35294
|
}
|
|
35175
35295
|
|
|
35176
|
-
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryValueLogCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS,
|
|
35296
|
+
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryValueLogCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals49 as _internals, resolveCommand };
|