opencode-swarm 6.41.1 → 6.41.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +247 -160
- package/dist/index.js +783 -622
- package/dist/tools/completion-verify.d.ts +2 -0
- package/dist/tools/resolve-working-directory.d.ts +35 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35466,9 +35466,52 @@ var init_secretscan = __esm(() => {
|
|
|
35466
35466
|
});
|
|
35467
35467
|
});
|
|
35468
35468
|
|
|
35469
|
-
// src/tools/
|
|
35469
|
+
// src/tools/resolve-working-directory.ts
|
|
35470
35470
|
import * as fs15 from "fs";
|
|
35471
35471
|
import * as path26 from "path";
|
|
35472
|
+
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
35473
|
+
if (workingDirectory == null || workingDirectory === "") {
|
|
35474
|
+
return { success: true, directory: fallbackDirectory };
|
|
35475
|
+
}
|
|
35476
|
+
if (workingDirectory.includes("\x00")) {
|
|
35477
|
+
return {
|
|
35478
|
+
success: false,
|
|
35479
|
+
message: "Invalid working_directory: null bytes are not allowed"
|
|
35480
|
+
};
|
|
35481
|
+
}
|
|
35482
|
+
if (process.platform === "win32") {
|
|
35483
|
+
const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
|
|
35484
|
+
if (devicePathPattern.test(workingDirectory)) {
|
|
35485
|
+
return {
|
|
35486
|
+
success: false,
|
|
35487
|
+
message: "Invalid working_directory: Windows device paths are not allowed"
|
|
35488
|
+
};
|
|
35489
|
+
}
|
|
35490
|
+
}
|
|
35491
|
+
const normalizedDir = path26.normalize(workingDirectory);
|
|
35492
|
+
const pathParts = normalizedDir.split(path26.sep);
|
|
35493
|
+
if (pathParts.includes("..")) {
|
|
35494
|
+
return {
|
|
35495
|
+
success: false,
|
|
35496
|
+
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
35497
|
+
};
|
|
35498
|
+
}
|
|
35499
|
+
const resolvedDir = path26.resolve(normalizedDir);
|
|
35500
|
+
try {
|
|
35501
|
+
const realPath = fs15.realpathSync(resolvedDir);
|
|
35502
|
+
return { success: true, directory: realPath };
|
|
35503
|
+
} catch {
|
|
35504
|
+
return {
|
|
35505
|
+
success: false,
|
|
35506
|
+
message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
|
|
35507
|
+
};
|
|
35508
|
+
}
|
|
35509
|
+
}
|
|
35510
|
+
var init_resolve_working_directory = () => {};
|
|
35511
|
+
|
|
35512
|
+
// src/tools/test-runner.ts
|
|
35513
|
+
import * as fs16 from "fs";
|
|
35514
|
+
import * as path27 from "path";
|
|
35472
35515
|
function isAbsolutePath(str) {
|
|
35473
35516
|
if (str.startsWith("/"))
|
|
35474
35517
|
return true;
|
|
@@ -35533,19 +35576,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
35533
35576
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
35534
35577
|
}
|
|
35535
35578
|
function detectGoTest(cwd) {
|
|
35536
|
-
return
|
|
35579
|
+
return fs16.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
35537
35580
|
}
|
|
35538
35581
|
function detectJavaMaven(cwd) {
|
|
35539
|
-
return
|
|
35582
|
+
return fs16.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
35540
35583
|
}
|
|
35541
35584
|
function detectGradle(cwd) {
|
|
35542
|
-
const hasBuildFile =
|
|
35543
|
-
const hasGradlew =
|
|
35585
|
+
const hasBuildFile = fs16.existsSync(path27.join(cwd, "build.gradle")) || fs16.existsSync(path27.join(cwd, "build.gradle.kts"));
|
|
35586
|
+
const hasGradlew = fs16.existsSync(path27.join(cwd, "gradlew")) || fs16.existsSync(path27.join(cwd, "gradlew.bat"));
|
|
35544
35587
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
35545
35588
|
}
|
|
35546
35589
|
function detectDotnetTest(cwd) {
|
|
35547
35590
|
try {
|
|
35548
|
-
const files =
|
|
35591
|
+
const files = fs16.readdirSync(cwd);
|
|
35549
35592
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
35550
35593
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
35551
35594
|
} catch {
|
|
@@ -35553,32 +35596,32 @@ function detectDotnetTest(cwd) {
|
|
|
35553
35596
|
}
|
|
35554
35597
|
}
|
|
35555
35598
|
function detectCTest(cwd) {
|
|
35556
|
-
const hasSource =
|
|
35557
|
-
const hasBuildCache =
|
|
35599
|
+
const hasSource = fs16.existsSync(path27.join(cwd, "CMakeLists.txt"));
|
|
35600
|
+
const hasBuildCache = fs16.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
|
|
35558
35601
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
35559
35602
|
}
|
|
35560
35603
|
function detectSwiftTest(cwd) {
|
|
35561
|
-
return
|
|
35604
|
+
return fs16.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
35562
35605
|
}
|
|
35563
35606
|
function detectDartTest(cwd) {
|
|
35564
|
-
return
|
|
35607
|
+
return fs16.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
35565
35608
|
}
|
|
35566
35609
|
function detectRSpec(cwd) {
|
|
35567
|
-
const hasRSpecFile =
|
|
35568
|
-
const hasGemfile =
|
|
35569
|
-
const hasSpecDir =
|
|
35610
|
+
const hasRSpecFile = fs16.existsSync(path27.join(cwd, ".rspec"));
|
|
35611
|
+
const hasGemfile = fs16.existsSync(path27.join(cwd, "Gemfile"));
|
|
35612
|
+
const hasSpecDir = fs16.existsSync(path27.join(cwd, "spec"));
|
|
35570
35613
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
35571
35614
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
35572
35615
|
}
|
|
35573
35616
|
function detectMinitest(cwd) {
|
|
35574
|
-
return
|
|
35617
|
+
return fs16.existsSync(path27.join(cwd, "test")) && (fs16.existsSync(path27.join(cwd, "Gemfile")) || fs16.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
35575
35618
|
}
|
|
35576
35619
|
async function detectTestFramework(cwd) {
|
|
35577
35620
|
const baseDir = cwd;
|
|
35578
35621
|
try {
|
|
35579
|
-
const packageJsonPath =
|
|
35580
|
-
if (
|
|
35581
|
-
const content =
|
|
35622
|
+
const packageJsonPath = path27.join(baseDir, "package.json");
|
|
35623
|
+
if (fs16.existsSync(packageJsonPath)) {
|
|
35624
|
+
const content = fs16.readFileSync(packageJsonPath, "utf-8");
|
|
35582
35625
|
const pkg = JSON.parse(content);
|
|
35583
35626
|
const _deps = pkg.dependencies || {};
|
|
35584
35627
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -35597,38 +35640,38 @@ async function detectTestFramework(cwd) {
|
|
|
35597
35640
|
return "jest";
|
|
35598
35641
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
35599
35642
|
return "mocha";
|
|
35600
|
-
if (
|
|
35643
|
+
if (fs16.existsSync(path27.join(baseDir, "bun.lockb")) || fs16.existsSync(path27.join(baseDir, "bun.lock"))) {
|
|
35601
35644
|
if (scripts.test?.includes("bun"))
|
|
35602
35645
|
return "bun";
|
|
35603
35646
|
}
|
|
35604
35647
|
}
|
|
35605
35648
|
} catch {}
|
|
35606
35649
|
try {
|
|
35607
|
-
const pyprojectTomlPath =
|
|
35608
|
-
const setupCfgPath =
|
|
35609
|
-
const requirementsTxtPath =
|
|
35610
|
-
if (
|
|
35611
|
-
const content =
|
|
35650
|
+
const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
|
|
35651
|
+
const setupCfgPath = path27.join(baseDir, "setup.cfg");
|
|
35652
|
+
const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
|
|
35653
|
+
if (fs16.existsSync(pyprojectTomlPath)) {
|
|
35654
|
+
const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
|
|
35612
35655
|
if (content.includes("[tool.pytest"))
|
|
35613
35656
|
return "pytest";
|
|
35614
35657
|
if (content.includes("pytest"))
|
|
35615
35658
|
return "pytest";
|
|
35616
35659
|
}
|
|
35617
|
-
if (
|
|
35618
|
-
const content =
|
|
35660
|
+
if (fs16.existsSync(setupCfgPath)) {
|
|
35661
|
+
const content = fs16.readFileSync(setupCfgPath, "utf-8");
|
|
35619
35662
|
if (content.includes("[pytest]"))
|
|
35620
35663
|
return "pytest";
|
|
35621
35664
|
}
|
|
35622
|
-
if (
|
|
35623
|
-
const content =
|
|
35665
|
+
if (fs16.existsSync(requirementsTxtPath)) {
|
|
35666
|
+
const content = fs16.readFileSync(requirementsTxtPath, "utf-8");
|
|
35624
35667
|
if (content.includes("pytest"))
|
|
35625
35668
|
return "pytest";
|
|
35626
35669
|
}
|
|
35627
35670
|
} catch {}
|
|
35628
35671
|
try {
|
|
35629
|
-
const cargoTomlPath =
|
|
35630
|
-
if (
|
|
35631
|
-
const content =
|
|
35672
|
+
const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
|
|
35673
|
+
if (fs16.existsSync(cargoTomlPath)) {
|
|
35674
|
+
const content = fs16.readFileSync(cargoTomlPath, "utf-8");
|
|
35632
35675
|
if (content.includes("[dev-dependencies]")) {
|
|
35633
35676
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
35634
35677
|
return "cargo";
|
|
@@ -35637,10 +35680,10 @@ async function detectTestFramework(cwd) {
|
|
|
35637
35680
|
}
|
|
35638
35681
|
} catch {}
|
|
35639
35682
|
try {
|
|
35640
|
-
const pesterConfigPath =
|
|
35641
|
-
const pesterConfigJsonPath =
|
|
35642
|
-
const pesterPs1Path =
|
|
35643
|
-
if (
|
|
35683
|
+
const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
|
|
35684
|
+
const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
|
|
35685
|
+
const pesterPs1Path = path27.join(baseDir, "tests.ps1");
|
|
35686
|
+
if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
|
|
35644
35687
|
return "pester";
|
|
35645
35688
|
}
|
|
35646
35689
|
} catch {}
|
|
@@ -35672,8 +35715,8 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
35672
35715
|
const testFiles = [];
|
|
35673
35716
|
for (const file3 of sourceFiles) {
|
|
35674
35717
|
const normalizedPath = file3.replace(/\\/g, "/");
|
|
35675
|
-
const basename4 =
|
|
35676
|
-
const dirname11 =
|
|
35718
|
+
const basename4 = path27.basename(file3);
|
|
35719
|
+
const dirname11 = path27.dirname(file3);
|
|
35677
35720
|
if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
35678
35721
|
if (!testFiles.includes(file3)) {
|
|
35679
35722
|
testFiles.push(file3);
|
|
@@ -35682,16 +35725,16 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
35682
35725
|
}
|
|
35683
35726
|
for (const _pattern of TEST_PATTERNS) {
|
|
35684
35727
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
35685
|
-
const ext =
|
|
35728
|
+
const ext = path27.extname(basename4);
|
|
35686
35729
|
const possibleTestFiles = [
|
|
35687
|
-
|
|
35688
|
-
|
|
35689
|
-
|
|
35690
|
-
|
|
35691
|
-
|
|
35730
|
+
path27.join(dirname11, `${nameWithoutExt}.spec${ext}`),
|
|
35731
|
+
path27.join(dirname11, `${nameWithoutExt}.test${ext}`),
|
|
35732
|
+
path27.join(dirname11, "__tests__", `${nameWithoutExt}${ext}`),
|
|
35733
|
+
path27.join(dirname11, "tests", `${nameWithoutExt}${ext}`),
|
|
35734
|
+
path27.join(dirname11, "test", `${nameWithoutExt}${ext}`)
|
|
35692
35735
|
];
|
|
35693
35736
|
for (const testFile of possibleTestFiles) {
|
|
35694
|
-
if (
|
|
35737
|
+
if (fs16.existsSync(testFile) && !testFiles.includes(testFile)) {
|
|
35695
35738
|
testFiles.push(testFile);
|
|
35696
35739
|
}
|
|
35697
35740
|
}
|
|
@@ -35707,8 +35750,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
35707
35750
|
}
|
|
35708
35751
|
for (const testFile of candidateTestFiles) {
|
|
35709
35752
|
try {
|
|
35710
|
-
const content =
|
|
35711
|
-
const testDir =
|
|
35753
|
+
const content = fs16.readFileSync(testFile, "utf-8");
|
|
35754
|
+
const testDir = path27.dirname(testFile);
|
|
35712
35755
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
35713
35756
|
let match;
|
|
35714
35757
|
match = importRegex.exec(content);
|
|
@@ -35716,8 +35759,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
35716
35759
|
const importPath = match[1];
|
|
35717
35760
|
let resolvedImport;
|
|
35718
35761
|
if (importPath.startsWith(".")) {
|
|
35719
|
-
resolvedImport =
|
|
35720
|
-
const existingExt =
|
|
35762
|
+
resolvedImport = path27.resolve(testDir, importPath);
|
|
35763
|
+
const existingExt = path27.extname(resolvedImport);
|
|
35721
35764
|
if (!existingExt) {
|
|
35722
35765
|
for (const extToTry of [
|
|
35723
35766
|
".ts",
|
|
@@ -35728,7 +35771,7 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
35728
35771
|
".cjs"
|
|
35729
35772
|
]) {
|
|
35730
35773
|
const withExt = resolvedImport + extToTry;
|
|
35731
|
-
if (sourceFiles.includes(withExt) ||
|
|
35774
|
+
if (sourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
|
|
35732
35775
|
resolvedImport = withExt;
|
|
35733
35776
|
break;
|
|
35734
35777
|
}
|
|
@@ -35737,12 +35780,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
35737
35780
|
} else {
|
|
35738
35781
|
continue;
|
|
35739
35782
|
}
|
|
35740
|
-
const importBasename =
|
|
35741
|
-
const importDir =
|
|
35783
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
35784
|
+
const importDir = path27.dirname(resolvedImport);
|
|
35742
35785
|
for (const sourceFile of sourceFiles) {
|
|
35743
|
-
const sourceDir =
|
|
35744
|
-
const sourceBasename =
|
|
35745
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
35786
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
35787
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
35788
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test");
|
|
35746
35789
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
35747
35790
|
if (!testFiles.includes(testFile)) {
|
|
35748
35791
|
testFiles.push(testFile);
|
|
@@ -35757,8 +35800,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
35757
35800
|
while (match !== null) {
|
|
35758
35801
|
const importPath = match[1];
|
|
35759
35802
|
if (importPath.startsWith(".")) {
|
|
35760
|
-
let resolvedImport =
|
|
35761
|
-
const existingExt =
|
|
35803
|
+
let resolvedImport = path27.resolve(testDir, importPath);
|
|
35804
|
+
const existingExt = path27.extname(resolvedImport);
|
|
35762
35805
|
if (!existingExt) {
|
|
35763
35806
|
for (const extToTry of [
|
|
35764
35807
|
".ts",
|
|
@@ -35769,18 +35812,18 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
35769
35812
|
".cjs"
|
|
35770
35813
|
]) {
|
|
35771
35814
|
const withExt = resolvedImport + extToTry;
|
|
35772
|
-
if (sourceFiles.includes(withExt) ||
|
|
35815
|
+
if (sourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
|
|
35773
35816
|
resolvedImport = withExt;
|
|
35774
35817
|
break;
|
|
35775
35818
|
}
|
|
35776
35819
|
}
|
|
35777
35820
|
}
|
|
35778
|
-
const importDir =
|
|
35779
|
-
const importBasename =
|
|
35821
|
+
const importDir = path27.dirname(resolvedImport);
|
|
35822
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
35780
35823
|
for (const sourceFile of sourceFiles) {
|
|
35781
|
-
const sourceDir =
|
|
35782
|
-
const sourceBasename =
|
|
35783
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
35824
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
35825
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
35826
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test");
|
|
35784
35827
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
35785
35828
|
if (!testFiles.includes(testFile)) {
|
|
35786
35829
|
testFiles.push(testFile);
|
|
@@ -35865,8 +35908,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
35865
35908
|
return ["mvn", "test"];
|
|
35866
35909
|
case "gradle": {
|
|
35867
35910
|
const isWindows = process.platform === "win32";
|
|
35868
|
-
const hasGradlewBat =
|
|
35869
|
-
const hasGradlew =
|
|
35911
|
+
const hasGradlewBat = fs16.existsSync(path27.join(baseDir, "gradlew.bat"));
|
|
35912
|
+
const hasGradlew = fs16.existsSync(path27.join(baseDir, "gradlew"));
|
|
35870
35913
|
if (hasGradlewBat && isWindows)
|
|
35871
35914
|
return ["gradlew.bat", "test"];
|
|
35872
35915
|
if (hasGradlew)
|
|
@@ -35883,7 +35926,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
35883
35926
|
"cmake-build-release",
|
|
35884
35927
|
"out"
|
|
35885
35928
|
];
|
|
35886
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
35929
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
35887
35930
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
35888
35931
|
}
|
|
35889
35932
|
case "swift-test":
|
|
@@ -36115,6 +36158,43 @@ function parseTestOutput(framework, output) {
|
|
|
36115
36158
|
}
|
|
36116
36159
|
return { totals, coveragePercent };
|
|
36117
36160
|
}
|
|
36161
|
+
async function readBoundedStream(stream, maxBytes) {
|
|
36162
|
+
const reader = stream.getReader();
|
|
36163
|
+
const chunks = [];
|
|
36164
|
+
let totalBytes = 0;
|
|
36165
|
+
let truncated = false;
|
|
36166
|
+
try {
|
|
36167
|
+
while (true) {
|
|
36168
|
+
const { done, value } = await reader.read();
|
|
36169
|
+
if (done)
|
|
36170
|
+
break;
|
|
36171
|
+
if (totalBytes + value.length > maxBytes) {
|
|
36172
|
+
const remaining = maxBytes - totalBytes;
|
|
36173
|
+
if (remaining > 0) {
|
|
36174
|
+
chunks.push(value.slice(0, remaining));
|
|
36175
|
+
}
|
|
36176
|
+
totalBytes = maxBytes;
|
|
36177
|
+
truncated = true;
|
|
36178
|
+
reader.cancel().catch(() => {});
|
|
36179
|
+
break;
|
|
36180
|
+
}
|
|
36181
|
+
chunks.push(value);
|
|
36182
|
+
totalBytes += value.length;
|
|
36183
|
+
}
|
|
36184
|
+
} catch {} finally {
|
|
36185
|
+
try {
|
|
36186
|
+
reader.releaseLock();
|
|
36187
|
+
} catch {}
|
|
36188
|
+
}
|
|
36189
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
36190
|
+
const combined = new Uint8Array(totalBytes);
|
|
36191
|
+
let offset = 0;
|
|
36192
|
+
for (const chunk of chunks) {
|
|
36193
|
+
combined.set(chunk, offset);
|
|
36194
|
+
offset += chunk.length;
|
|
36195
|
+
}
|
|
36196
|
+
return { text: decoder.decode(combined), truncated };
|
|
36197
|
+
}
|
|
36118
36198
|
async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
36119
36199
|
const command = buildTestCommand(framework, scope, files, coverage, cwd);
|
|
36120
36200
|
if (!command) {
|
|
@@ -36143,34 +36223,24 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
36143
36223
|
stderr: "pipe",
|
|
36144
36224
|
cwd
|
|
36145
36225
|
});
|
|
36146
|
-
const
|
|
36147
|
-
const timeoutPromise = new Promise((resolve8) => setTimeout(() => {
|
|
36226
|
+
const timeoutPromise = new Promise((resolve9) => setTimeout(() => {
|
|
36148
36227
|
proc.kill();
|
|
36149
|
-
|
|
36228
|
+
resolve9(-1);
|
|
36150
36229
|
}, timeout_ms));
|
|
36151
|
-
const exitCode = await Promise.
|
|
36152
|
-
|
|
36153
|
-
|
|
36154
|
-
|
|
36155
|
-
new Response(proc.stderr).text()
|
|
36230
|
+
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
36231
|
+
Promise.race([proc.exited, timeoutPromise]),
|
|
36232
|
+
readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
|
|
36233
|
+
readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
|
|
36156
36234
|
]);
|
|
36157
|
-
|
|
36158
|
-
|
|
36235
|
+
const duration_ms = Date.now() - startTime;
|
|
36236
|
+
let output = stdoutResult.text;
|
|
36237
|
+
if (stderrResult.text) {
|
|
36159
36238
|
output += (output ? `
|
|
36160
|
-
` : "") +
|
|
36239
|
+
` : "") + stderrResult.text;
|
|
36161
36240
|
}
|
|
36162
|
-
|
|
36163
|
-
|
|
36164
|
-
|
|
36165
|
-
while (truncIndex > 0) {
|
|
36166
|
-
const truncated = output.slice(0, truncIndex);
|
|
36167
|
-
if (Buffer.byteLength(truncated, "utf-8") <= MAX_OUTPUT_BYTES3) {
|
|
36168
|
-
break;
|
|
36169
|
-
}
|
|
36170
|
-
truncIndex--;
|
|
36171
|
-
}
|
|
36172
|
-
output = `${output.slice(0, truncIndex)}
|
|
36173
|
-
... (output truncated)`;
|
|
36241
|
+
if (stdoutResult.truncated || stderrResult.truncated) {
|
|
36242
|
+
output += `
|
|
36243
|
+
... (output truncated at stream read limit)`;
|
|
36174
36244
|
}
|
|
36175
36245
|
const { totals, coveragePercent } = parseTestOutput(framework, output);
|
|
36176
36246
|
const isTimeout = exitCode === -1;
|
|
@@ -36230,6 +36300,7 @@ var init_test_runner = __esm(() => {
|
|
|
36230
36300
|
init_dist();
|
|
36231
36301
|
init_discovery();
|
|
36232
36302
|
init_create_tool();
|
|
36303
|
+
init_resolve_working_directory();
|
|
36233
36304
|
POWERSHELL_METACHARACTERS = /[|;&`$(){}[\]<>"'#*?\x00-\x1f]/;
|
|
36234
36305
|
TEST_PATTERNS = [
|
|
36235
36306
|
{ test: ".spec.", source: "." },
|
|
@@ -36309,10 +36380,26 @@ var init_test_runner = __esm(() => {
|
|
|
36309
36380
|
files: tool.schema.array(tool.schema.string()).optional().describe("Specific files to test (used with convention or graph scope)"),
|
|
36310
36381
|
coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
|
|
36311
36382
|
timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
|
|
36312
|
-
allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.')
|
|
36383
|
+
allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
|
|
36384
|
+
working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
|
|
36313
36385
|
},
|
|
36314
36386
|
async execute(args2, directory) {
|
|
36315
|
-
|
|
36387
|
+
let workingDirInput;
|
|
36388
|
+
if (args2 && typeof args2 === "object") {
|
|
36389
|
+
const obj = args2;
|
|
36390
|
+
workingDirInput = typeof obj.working_directory === "string" ? obj.working_directory : undefined;
|
|
36391
|
+
}
|
|
36392
|
+
const dirResult = resolveWorkingDirectory(workingDirInput, directory);
|
|
36393
|
+
if (!dirResult.success) {
|
|
36394
|
+
const errorResult = {
|
|
36395
|
+
success: false,
|
|
36396
|
+
framework: "none",
|
|
36397
|
+
scope: "all",
|
|
36398
|
+
error: dirResult.message
|
|
36399
|
+
};
|
|
36400
|
+
return JSON.stringify(errorResult, null, 2);
|
|
36401
|
+
}
|
|
36402
|
+
const workingDir = dirResult.directory;
|
|
36316
36403
|
if (workingDir.length > 4096) {
|
|
36317
36404
|
const errorResult = {
|
|
36318
36405
|
success: false,
|
|
@@ -36366,8 +36453,8 @@ var init_test_runner = __esm(() => {
|
|
|
36366
36453
|
success: false,
|
|
36367
36454
|
framework: "none",
|
|
36368
36455
|
scope: "all",
|
|
36369
|
-
error: '
|
|
36370
|
-
message: '
|
|
36456
|
+
error: 'scope "all" is not allowed without explicit files. Use scope "convention" or "graph" with a files array to run targeted tests.',
|
|
36457
|
+
message: 'Running the full test suite without file targeting is blocked. Provide scope "convention" or "graph" with specific source files in the files array. Example: { scope: "convention", files: ["src/tools/test-runner.ts"] }'
|
|
36371
36458
|
};
|
|
36372
36459
|
return JSON.stringify(errorResult, null, 2);
|
|
36373
36460
|
}
|
|
@@ -36407,7 +36494,7 @@ var init_test_runner = __esm(() => {
|
|
|
36407
36494
|
let effectiveScope = scope;
|
|
36408
36495
|
if (scope === "all") {} else if (scope === "convention") {
|
|
36409
36496
|
const sourceFiles = args2.files.filter((f) => {
|
|
36410
|
-
const ext =
|
|
36497
|
+
const ext = path27.extname(f).toLowerCase();
|
|
36411
36498
|
return SOURCE_EXTENSIONS.has(ext);
|
|
36412
36499
|
});
|
|
36413
36500
|
if (sourceFiles.length === 0) {
|
|
@@ -36423,7 +36510,7 @@ var init_test_runner = __esm(() => {
|
|
|
36423
36510
|
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
36424
36511
|
} else if (scope === "graph") {
|
|
36425
36512
|
const sourceFiles = args2.files.filter((f) => {
|
|
36426
|
-
const ext =
|
|
36513
|
+
const ext = path27.extname(f).toLowerCase();
|
|
36427
36514
|
return SOURCE_EXTENSIONS.has(ext);
|
|
36428
36515
|
});
|
|
36429
36516
|
if (sourceFiles.length === 0) {
|
|
@@ -36476,8 +36563,8 @@ var init_test_runner = __esm(() => {
|
|
|
36476
36563
|
});
|
|
36477
36564
|
|
|
36478
36565
|
// src/services/preflight-service.ts
|
|
36479
|
-
import * as
|
|
36480
|
-
import * as
|
|
36566
|
+
import * as fs17 from "fs";
|
|
36567
|
+
import * as path28 from "path";
|
|
36481
36568
|
function validateDirectoryPath(dir) {
|
|
36482
36569
|
if (!dir || typeof dir !== "string") {
|
|
36483
36570
|
throw new Error("Directory path is required");
|
|
@@ -36485,8 +36572,8 @@ function validateDirectoryPath(dir) {
|
|
|
36485
36572
|
if (dir.includes("..")) {
|
|
36486
36573
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
36487
36574
|
}
|
|
36488
|
-
const normalized =
|
|
36489
|
-
const absolutePath =
|
|
36575
|
+
const normalized = path28.normalize(dir);
|
|
36576
|
+
const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
|
|
36490
36577
|
return absolutePath;
|
|
36491
36578
|
}
|
|
36492
36579
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -36509,9 +36596,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
36509
36596
|
}
|
|
36510
36597
|
function getPackageVersion(dir) {
|
|
36511
36598
|
try {
|
|
36512
|
-
const packagePath =
|
|
36513
|
-
if (
|
|
36514
|
-
const content =
|
|
36599
|
+
const packagePath = path28.join(dir, "package.json");
|
|
36600
|
+
if (fs17.existsSync(packagePath)) {
|
|
36601
|
+
const content = fs17.readFileSync(packagePath, "utf-8");
|
|
36515
36602
|
const pkg = JSON.parse(content);
|
|
36516
36603
|
return pkg.version ?? null;
|
|
36517
36604
|
}
|
|
@@ -36520,9 +36607,9 @@ function getPackageVersion(dir) {
|
|
|
36520
36607
|
}
|
|
36521
36608
|
function getChangelogVersion(dir) {
|
|
36522
36609
|
try {
|
|
36523
|
-
const changelogPath =
|
|
36524
|
-
if (
|
|
36525
|
-
const content =
|
|
36610
|
+
const changelogPath = path28.join(dir, "CHANGELOG.md");
|
|
36611
|
+
if (fs17.existsSync(changelogPath)) {
|
|
36612
|
+
const content = fs17.readFileSync(changelogPath, "utf-8");
|
|
36526
36613
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
36527
36614
|
if (match) {
|
|
36528
36615
|
return match[1];
|
|
@@ -36534,10 +36621,10 @@ function getChangelogVersion(dir) {
|
|
|
36534
36621
|
function getVersionFileVersion(dir) {
|
|
36535
36622
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
36536
36623
|
for (const file3 of possibleFiles) {
|
|
36537
|
-
const filePath =
|
|
36538
|
-
if (
|
|
36624
|
+
const filePath = path28.join(dir, file3);
|
|
36625
|
+
if (fs17.existsSync(filePath)) {
|
|
36539
36626
|
try {
|
|
36540
|
-
const content =
|
|
36627
|
+
const content = fs17.readFileSync(filePath, "utf-8").trim();
|
|
36541
36628
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
36542
36629
|
if (match) {
|
|
36543
36630
|
return match[1];
|
|
@@ -37062,7 +37149,7 @@ __export(exports_gate_evidence, {
|
|
|
37062
37149
|
DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
|
|
37063
37150
|
});
|
|
37064
37151
|
import { mkdirSync as mkdirSync10, readFileSync as readFileSync14, renameSync as renameSync9, unlinkSync as unlinkSync5 } from "fs";
|
|
37065
|
-
import * as
|
|
37152
|
+
import * as path34 from "path";
|
|
37066
37153
|
function isValidTaskId2(taskId) {
|
|
37067
37154
|
if (!taskId)
|
|
37068
37155
|
return false;
|
|
@@ -37109,10 +37196,10 @@ function expandRequiredGates(existingGates, newAgentType) {
|
|
|
37109
37196
|
return combined.sort();
|
|
37110
37197
|
}
|
|
37111
37198
|
function getEvidenceDir(directory) {
|
|
37112
|
-
return
|
|
37199
|
+
return path34.join(directory, ".swarm", "evidence");
|
|
37113
37200
|
}
|
|
37114
37201
|
function getEvidencePath(directory, taskId) {
|
|
37115
|
-
return
|
|
37202
|
+
return path34.join(getEvidenceDir(directory), `${taskId}.json`);
|
|
37116
37203
|
}
|
|
37117
37204
|
function readExisting(evidencePath) {
|
|
37118
37205
|
try {
|
|
@@ -37282,15 +37369,15 @@ __export(exports_doc_scan, {
|
|
|
37282
37369
|
doc_extract: () => doc_extract
|
|
37283
37370
|
});
|
|
37284
37371
|
import * as crypto4 from "crypto";
|
|
37285
|
-
import * as
|
|
37372
|
+
import * as fs27 from "fs";
|
|
37286
37373
|
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
37287
|
-
import * as
|
|
37374
|
+
import * as path39 from "path";
|
|
37288
37375
|
function normalizeSeparators(filePath) {
|
|
37289
37376
|
return filePath.replace(/\\/g, "/");
|
|
37290
37377
|
}
|
|
37291
37378
|
function matchesDocPattern(filePath, patterns) {
|
|
37292
37379
|
const normalizedPath = normalizeSeparators(filePath);
|
|
37293
|
-
const basename5 =
|
|
37380
|
+
const basename5 = path39.basename(filePath);
|
|
37294
37381
|
for (const pattern of patterns) {
|
|
37295
37382
|
if (!pattern.includes("/") && !pattern.includes("\\")) {
|
|
37296
37383
|
if (basename5 === pattern) {
|
|
@@ -37346,7 +37433,7 @@ function stripMarkdown(text) {
|
|
|
37346
37433
|
return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
|
|
37347
37434
|
}
|
|
37348
37435
|
async function scanDocIndex(directory) {
|
|
37349
|
-
const manifestPath =
|
|
37436
|
+
const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
|
|
37350
37437
|
const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
|
|
37351
37438
|
const extraPatterns = [
|
|
37352
37439
|
"ARCHITECTURE.md",
|
|
@@ -37363,8 +37450,8 @@ async function scanDocIndex(directory) {
|
|
|
37363
37450
|
let cacheValid = true;
|
|
37364
37451
|
for (const file3 of existingManifest.files) {
|
|
37365
37452
|
try {
|
|
37366
|
-
const fullPath =
|
|
37367
|
-
const stat2 =
|
|
37453
|
+
const fullPath = path39.join(directory, file3.path);
|
|
37454
|
+
const stat2 = fs27.statSync(fullPath);
|
|
37368
37455
|
if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
|
|
37369
37456
|
cacheValid = false;
|
|
37370
37457
|
break;
|
|
@@ -37382,7 +37469,7 @@ async function scanDocIndex(directory) {
|
|
|
37382
37469
|
const discoveredFiles = [];
|
|
37383
37470
|
let rawEntries;
|
|
37384
37471
|
try {
|
|
37385
|
-
rawEntries =
|
|
37472
|
+
rawEntries = fs27.readdirSync(directory, { recursive: true });
|
|
37386
37473
|
} catch {
|
|
37387
37474
|
const manifest2 = {
|
|
37388
37475
|
schema_version: 1,
|
|
@@ -37393,10 +37480,10 @@ async function scanDocIndex(directory) {
|
|
|
37393
37480
|
}
|
|
37394
37481
|
const entries = rawEntries.filter((e) => typeof e === "string");
|
|
37395
37482
|
for (const entry of entries) {
|
|
37396
|
-
const fullPath =
|
|
37483
|
+
const fullPath = path39.join(directory, entry);
|
|
37397
37484
|
let stat2;
|
|
37398
37485
|
try {
|
|
37399
|
-
stat2 =
|
|
37486
|
+
stat2 = fs27.statSync(fullPath);
|
|
37400
37487
|
} catch {
|
|
37401
37488
|
continue;
|
|
37402
37489
|
}
|
|
@@ -37425,11 +37512,11 @@ async function scanDocIndex(directory) {
|
|
|
37425
37512
|
}
|
|
37426
37513
|
let content;
|
|
37427
37514
|
try {
|
|
37428
|
-
content =
|
|
37515
|
+
content = fs27.readFileSync(fullPath, "utf-8");
|
|
37429
37516
|
} catch {
|
|
37430
37517
|
continue;
|
|
37431
37518
|
}
|
|
37432
|
-
const { title, summary } = extractTitleAndSummary(content,
|
|
37519
|
+
const { title, summary } = extractTitleAndSummary(content, path39.basename(entry));
|
|
37433
37520
|
const lineCount = content.split(`
|
|
37434
37521
|
`).length;
|
|
37435
37522
|
discoveredFiles.push({
|
|
@@ -37455,7 +37542,7 @@ async function scanDocIndex(directory) {
|
|
|
37455
37542
|
files: discoveredFiles
|
|
37456
37543
|
};
|
|
37457
37544
|
try {
|
|
37458
|
-
await mkdir6(
|
|
37545
|
+
await mkdir6(path39.dirname(manifestPath), { recursive: true });
|
|
37459
37546
|
await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
37460
37547
|
} catch {}
|
|
37461
37548
|
return { manifest, cached: false };
|
|
@@ -37494,7 +37581,7 @@ function extractConstraintsFromContent(content) {
|
|
|
37494
37581
|
return constraints;
|
|
37495
37582
|
}
|
|
37496
37583
|
async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
37497
|
-
const manifestPath =
|
|
37584
|
+
const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
|
|
37498
37585
|
let manifest;
|
|
37499
37586
|
try {
|
|
37500
37587
|
const content = await readFile6(manifestPath, "utf-8");
|
|
@@ -37520,7 +37607,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
37520
37607
|
}
|
|
37521
37608
|
let fullContent;
|
|
37522
37609
|
try {
|
|
37523
|
-
fullContent = await readFile6(
|
|
37610
|
+
fullContent = await readFile6(path39.join(directory, docFile.path), "utf-8");
|
|
37524
37611
|
} catch {
|
|
37525
37612
|
skippedCount++;
|
|
37526
37613
|
continue;
|
|
@@ -37543,7 +37630,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
|
|
|
37543
37630
|
tier: "swarm",
|
|
37544
37631
|
lesson: constraint,
|
|
37545
37632
|
category: "architecture",
|
|
37546
|
-
tags: ["doc-scan",
|
|
37633
|
+
tags: ["doc-scan", path39.basename(docFile.path)],
|
|
37547
37634
|
scope: "global",
|
|
37548
37635
|
confidence: 0.5,
|
|
37549
37636
|
status: "candidate",
|
|
@@ -37616,9 +37703,9 @@ var init_doc_scan = __esm(() => {
|
|
|
37616
37703
|
}
|
|
37617
37704
|
} catch {}
|
|
37618
37705
|
if (force) {
|
|
37619
|
-
const manifestPath =
|
|
37706
|
+
const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
|
|
37620
37707
|
try {
|
|
37621
|
-
|
|
37708
|
+
fs27.unlinkSync(manifestPath);
|
|
37622
37709
|
} catch {}
|
|
37623
37710
|
}
|
|
37624
37711
|
const { manifest, cached: cached3 } = await scanDocIndex(directory);
|
|
@@ -37670,11 +37757,11 @@ __export(exports_curator_drift, {
|
|
|
37670
37757
|
readPriorDriftReports: () => readPriorDriftReports,
|
|
37671
37758
|
buildDriftInjectionText: () => buildDriftInjectionText
|
|
37672
37759
|
});
|
|
37673
|
-
import * as
|
|
37674
|
-
import * as
|
|
37760
|
+
import * as fs30 from "fs";
|
|
37761
|
+
import * as path42 from "path";
|
|
37675
37762
|
async function readPriorDriftReports(directory) {
|
|
37676
|
-
const swarmDir =
|
|
37677
|
-
const entries = await
|
|
37763
|
+
const swarmDir = path42.join(directory, ".swarm");
|
|
37764
|
+
const entries = await fs30.promises.readdir(swarmDir).catch(() => null);
|
|
37678
37765
|
if (entries === null)
|
|
37679
37766
|
return [];
|
|
37680
37767
|
const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
|
|
@@ -37700,10 +37787,10 @@ async function readPriorDriftReports(directory) {
|
|
|
37700
37787
|
async function writeDriftReport(directory, report) {
|
|
37701
37788
|
const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
|
|
37702
37789
|
const filePath = validateSwarmPath(directory, filename);
|
|
37703
|
-
const swarmDir =
|
|
37704
|
-
await
|
|
37790
|
+
const swarmDir = path42.dirname(filePath);
|
|
37791
|
+
await fs30.promises.mkdir(swarmDir, { recursive: true });
|
|
37705
37792
|
try {
|
|
37706
|
-
await
|
|
37793
|
+
await fs30.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
|
|
37707
37794
|
} catch (err2) {
|
|
37708
37795
|
throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
|
|
37709
37796
|
}
|
|
@@ -39270,8 +39357,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
39270
39357
|
var moduleRtn;
|
|
39271
39358
|
var Module = moduleArg;
|
|
39272
39359
|
var readyPromiseResolve, readyPromiseReject;
|
|
39273
|
-
var readyPromise = new Promise((
|
|
39274
|
-
readyPromiseResolve =
|
|
39360
|
+
var readyPromise = new Promise((resolve17, reject) => {
|
|
39361
|
+
readyPromiseResolve = resolve17;
|
|
39275
39362
|
readyPromiseReject = reject;
|
|
39276
39363
|
});
|
|
39277
39364
|
var ENVIRONMENT_IS_WEB = typeof window == "object";
|
|
@@ -39293,11 +39380,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
39293
39380
|
throw toThrow;
|
|
39294
39381
|
}, "quit_");
|
|
39295
39382
|
var scriptDirectory = "";
|
|
39296
|
-
function locateFile(
|
|
39383
|
+
function locateFile(path50) {
|
|
39297
39384
|
if (Module["locateFile"]) {
|
|
39298
|
-
return Module["locateFile"](
|
|
39385
|
+
return Module["locateFile"](path50, scriptDirectory);
|
|
39299
39386
|
}
|
|
39300
|
-
return scriptDirectory +
|
|
39387
|
+
return scriptDirectory + path50;
|
|
39301
39388
|
}
|
|
39302
39389
|
__name(locateFile, "locateFile");
|
|
39303
39390
|
var readAsync, readBinary;
|
|
@@ -39351,13 +39438,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
39351
39438
|
}
|
|
39352
39439
|
readAsync = /* @__PURE__ */ __name(async (url3) => {
|
|
39353
39440
|
if (isFileURI(url3)) {
|
|
39354
|
-
return new Promise((
|
|
39441
|
+
return new Promise((resolve17, reject) => {
|
|
39355
39442
|
var xhr = new XMLHttpRequest;
|
|
39356
39443
|
xhr.open("GET", url3, true);
|
|
39357
39444
|
xhr.responseType = "arraybuffer";
|
|
39358
39445
|
xhr.onload = () => {
|
|
39359
39446
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
39360
|
-
|
|
39447
|
+
resolve17(xhr.response);
|
|
39361
39448
|
return;
|
|
39362
39449
|
}
|
|
39363
39450
|
reject(xhr.status);
|
|
@@ -39577,10 +39664,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
39577
39664
|
__name(receiveInstantiationResult, "receiveInstantiationResult");
|
|
39578
39665
|
var info2 = getWasmImports();
|
|
39579
39666
|
if (Module["instantiateWasm"]) {
|
|
39580
|
-
return new Promise((
|
|
39667
|
+
return new Promise((resolve17, reject) => {
|
|
39581
39668
|
Module["instantiateWasm"](info2, (mod, inst) => {
|
|
39582
39669
|
receiveInstance(mod, inst);
|
|
39583
|
-
|
|
39670
|
+
resolve17(mod.exports);
|
|
39584
39671
|
});
|
|
39585
39672
|
});
|
|
39586
39673
|
}
|
|
@@ -41037,13 +41124,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
41037
41124
|
});
|
|
41038
41125
|
|
|
41039
41126
|
// src/lang/runtime.ts
|
|
41040
|
-
import * as
|
|
41127
|
+
import * as path50 from "path";
|
|
41041
41128
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
41042
41129
|
async function initTreeSitter() {
|
|
41043
41130
|
if (treeSitterInitialized) {
|
|
41044
41131
|
return;
|
|
41045
41132
|
}
|
|
41046
|
-
const thisDir =
|
|
41133
|
+
const thisDir = path50.dirname(fileURLToPath2(import.meta.url));
|
|
41047
41134
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
41048
41135
|
if (isSource) {
|
|
41049
41136
|
await Parser.init();
|
|
@@ -41051,7 +41138,7 @@ async function initTreeSitter() {
|
|
|
41051
41138
|
const grammarsDir = getGrammarsDirAbsolute();
|
|
41052
41139
|
await Parser.init({
|
|
41053
41140
|
locateFile(scriptName) {
|
|
41054
|
-
return
|
|
41141
|
+
return path50.join(grammarsDir, scriptName);
|
|
41055
41142
|
}
|
|
41056
41143
|
});
|
|
41057
41144
|
}
|
|
@@ -41072,9 +41159,9 @@ function getWasmFileName(languageId) {
|
|
|
41072
41159
|
return `tree-sitter-${sanitized}.wasm`;
|
|
41073
41160
|
}
|
|
41074
41161
|
function getGrammarsDirAbsolute() {
|
|
41075
|
-
const thisDir =
|
|
41162
|
+
const thisDir = path50.dirname(fileURLToPath2(import.meta.url));
|
|
41076
41163
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
41077
|
-
return isSource ?
|
|
41164
|
+
return isSource ? path50.join(thisDir, "grammars") : path50.join(thisDir, "lang", "grammars");
|
|
41078
41165
|
}
|
|
41079
41166
|
async function loadGrammar(languageId) {
|
|
41080
41167
|
if (typeof languageId !== "string" || languageId.length > 100) {
|
|
@@ -41090,7 +41177,7 @@ async function loadGrammar(languageId) {
|
|
|
41090
41177
|
await initTreeSitter();
|
|
41091
41178
|
const parser = new Parser;
|
|
41092
41179
|
const wasmFileName = getWasmFileName(normalizedId);
|
|
41093
|
-
const wasmPath =
|
|
41180
|
+
const wasmPath = path50.join(getGrammarsDirAbsolute(), wasmFileName);
|
|
41094
41181
|
const { existsSync: existsSync29 } = await import("fs");
|
|
41095
41182
|
if (!existsSync29(wasmPath)) {
|
|
41096
41183
|
throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
|
|
@@ -41137,7 +41224,7 @@ var init_runtime = __esm(() => {
|
|
|
41137
41224
|
});
|
|
41138
41225
|
|
|
41139
41226
|
// src/index.ts
|
|
41140
|
-
import * as
|
|
41227
|
+
import * as path67 from "path";
|
|
41141
41228
|
|
|
41142
41229
|
// src/agents/index.ts
|
|
41143
41230
|
init_config();
|
|
@@ -47074,7 +47161,7 @@ async function executeWriteRetro(args2, directory) {
|
|
|
47074
47161
|
var write_retro = createSwarmTool({
|
|
47075
47162
|
description: "Write a retrospective evidence bundle for a completed phase. " + "Accepts flat retro fields and writes a correctly-wrapped EvidenceBundle to " + ".swarm/evidence/retro-{phase}/evidence.json. " + "Use this instead of manually writing retro JSON to avoid schema validation failures in phase_complete.",
|
|
47076
47163
|
args: {
|
|
47077
|
-
phase: tool.schema.number().int().
|
|
47164
|
+
phase: tool.schema.number().int().min(1).max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),
|
|
47078
47165
|
summary: tool.schema.string().describe("Human-readable summary of the phase"),
|
|
47079
47166
|
task_count: tool.schema.number().int().min(1).max(9999).describe("Count of tasks completed in this phase"),
|
|
47080
47167
|
task_complexity: tool.schema.enum(["trivial", "simple", "moderate", "complex"]).describe("Complexity level of the completed tasks"),
|
|
@@ -50040,7 +50127,7 @@ async function handlePromoteCommand(directory, args2) {
|
|
|
50040
50127
|
}
|
|
50041
50128
|
|
|
50042
50129
|
// src/commands/reset.ts
|
|
50043
|
-
import * as
|
|
50130
|
+
import * as fs18 from "fs";
|
|
50044
50131
|
init_utils2();
|
|
50045
50132
|
async function handleResetCommand(directory, args2) {
|
|
50046
50133
|
const hasConfirm = args2.includes("--confirm");
|
|
@@ -50061,8 +50148,8 @@ async function handleResetCommand(directory, args2) {
|
|
|
50061
50148
|
for (const filename of filesToReset) {
|
|
50062
50149
|
try {
|
|
50063
50150
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
50064
|
-
if (
|
|
50065
|
-
|
|
50151
|
+
if (fs18.existsSync(resolvedPath)) {
|
|
50152
|
+
fs18.unlinkSync(resolvedPath);
|
|
50066
50153
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
50067
50154
|
} else {
|
|
50068
50155
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -50079,8 +50166,8 @@ async function handleResetCommand(directory, args2) {
|
|
|
50079
50166
|
}
|
|
50080
50167
|
try {
|
|
50081
50168
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
50082
|
-
if (
|
|
50083
|
-
|
|
50169
|
+
if (fs18.existsSync(summariesPath)) {
|
|
50170
|
+
fs18.rmSync(summariesPath, { recursive: true, force: true });
|
|
50084
50171
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
50085
50172
|
} else {
|
|
50086
50173
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -50100,14 +50187,14 @@ async function handleResetCommand(directory, args2) {
|
|
|
50100
50187
|
|
|
50101
50188
|
// src/commands/reset-session.ts
|
|
50102
50189
|
init_utils2();
|
|
50103
|
-
import * as
|
|
50104
|
-
import * as
|
|
50190
|
+
import * as fs19 from "fs";
|
|
50191
|
+
import * as path29 from "path";
|
|
50105
50192
|
async function handleResetSessionCommand(directory, _args) {
|
|
50106
50193
|
const results = [];
|
|
50107
50194
|
try {
|
|
50108
50195
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
50109
|
-
if (
|
|
50110
|
-
|
|
50196
|
+
if (fs19.existsSync(statePath)) {
|
|
50197
|
+
fs19.unlinkSync(statePath);
|
|
50111
50198
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
50112
50199
|
} else {
|
|
50113
50200
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -50116,15 +50203,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
50116
50203
|
results.push("\u274C Failed to delete state.json");
|
|
50117
50204
|
}
|
|
50118
50205
|
try {
|
|
50119
|
-
const sessionDir =
|
|
50120
|
-
if (
|
|
50121
|
-
const files =
|
|
50206
|
+
const sessionDir = path29.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
50207
|
+
if (fs19.existsSync(sessionDir)) {
|
|
50208
|
+
const files = fs19.readdirSync(sessionDir);
|
|
50122
50209
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
50123
50210
|
let deletedCount = 0;
|
|
50124
50211
|
for (const file3 of otherFiles) {
|
|
50125
|
-
const filePath =
|
|
50126
|
-
if (
|
|
50127
|
-
|
|
50212
|
+
const filePath = path29.join(sessionDir, file3);
|
|
50213
|
+
if (fs19.lstatSync(filePath).isFile()) {
|
|
50214
|
+
fs19.unlinkSync(filePath);
|
|
50128
50215
|
deletedCount++;
|
|
50129
50216
|
}
|
|
50130
50217
|
}
|
|
@@ -50153,7 +50240,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
50153
50240
|
init_utils2();
|
|
50154
50241
|
init_utils();
|
|
50155
50242
|
import { mkdirSync as mkdirSync9, readdirSync as readdirSync8, renameSync as renameSync7, rmSync as rmSync3, statSync as statSync8 } from "fs";
|
|
50156
|
-
import * as
|
|
50243
|
+
import * as path30 from "path";
|
|
50157
50244
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
50158
50245
|
function sanitizeSummaryId(id) {
|
|
50159
50246
|
if (!id || id.length === 0) {
|
|
@@ -50188,9 +50275,9 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
50188
50275
|
if (serializedSize > maxStoredBytes) {
|
|
50189
50276
|
throw new Error(`Summary entry size (${serializedSize} bytes) exceeds maximum (${maxStoredBytes} bytes)`);
|
|
50190
50277
|
}
|
|
50191
|
-
const relativePath =
|
|
50278
|
+
const relativePath = path30.join("summaries", `${sanitizedId}.json`);
|
|
50192
50279
|
const summaryPath = validateSwarmPath(directory, relativePath);
|
|
50193
|
-
const summaryDir =
|
|
50280
|
+
const summaryDir = path30.dirname(summaryPath);
|
|
50194
50281
|
const entry = {
|
|
50195
50282
|
id: sanitizedId,
|
|
50196
50283
|
summaryText,
|
|
@@ -50200,7 +50287,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
50200
50287
|
};
|
|
50201
50288
|
const entryJson = JSON.stringify(entry);
|
|
50202
50289
|
mkdirSync9(summaryDir, { recursive: true });
|
|
50203
|
-
const tempPath =
|
|
50290
|
+
const tempPath = path30.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
|
|
50204
50291
|
try {
|
|
50205
50292
|
await Bun.write(tempPath, entryJson);
|
|
50206
50293
|
renameSync7(tempPath, summaryPath);
|
|
@@ -50213,7 +50300,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
50213
50300
|
}
|
|
50214
50301
|
async function loadFullOutput(directory, id) {
|
|
50215
50302
|
const sanitizedId = sanitizeSummaryId(id);
|
|
50216
|
-
const relativePath =
|
|
50303
|
+
const relativePath = path30.join("summaries", `${sanitizedId}.json`);
|
|
50217
50304
|
validateSwarmPath(directory, relativePath);
|
|
50218
50305
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
50219
50306
|
if (content === null) {
|
|
@@ -50266,18 +50353,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
50266
50353
|
|
|
50267
50354
|
// src/commands/rollback.ts
|
|
50268
50355
|
init_utils2();
|
|
50269
|
-
import * as
|
|
50270
|
-
import * as
|
|
50356
|
+
import * as fs20 from "fs";
|
|
50357
|
+
import * as path31 from "path";
|
|
50271
50358
|
async function handleRollbackCommand(directory, args2) {
|
|
50272
50359
|
const phaseArg = args2[0];
|
|
50273
50360
|
if (!phaseArg) {
|
|
50274
50361
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
50275
|
-
if (!
|
|
50362
|
+
if (!fs20.existsSync(manifestPath2)) {
|
|
50276
50363
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
50277
50364
|
}
|
|
50278
50365
|
let manifest2;
|
|
50279
50366
|
try {
|
|
50280
|
-
manifest2 = JSON.parse(
|
|
50367
|
+
manifest2 = JSON.parse(fs20.readFileSync(manifestPath2, "utf-8"));
|
|
50281
50368
|
} catch {
|
|
50282
50369
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
50283
50370
|
}
|
|
@@ -50299,12 +50386,12 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
50299
50386
|
return "Error: Phase number must be a positive integer.";
|
|
50300
50387
|
}
|
|
50301
50388
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
50302
|
-
if (!
|
|
50389
|
+
if (!fs20.existsSync(manifestPath)) {
|
|
50303
50390
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
50304
50391
|
}
|
|
50305
50392
|
let manifest;
|
|
50306
50393
|
try {
|
|
50307
|
-
manifest = JSON.parse(
|
|
50394
|
+
manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf-8"));
|
|
50308
50395
|
} catch {
|
|
50309
50396
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
50310
50397
|
}
|
|
@@ -50314,10 +50401,10 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
50314
50401
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
50315
50402
|
}
|
|
50316
50403
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
50317
|
-
if (!
|
|
50404
|
+
if (!fs20.existsSync(checkpointDir)) {
|
|
50318
50405
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
50319
50406
|
}
|
|
50320
|
-
const checkpointFiles =
|
|
50407
|
+
const checkpointFiles = fs20.readdirSync(checkpointDir);
|
|
50321
50408
|
if (checkpointFiles.length === 0) {
|
|
50322
50409
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
50323
50410
|
}
|
|
@@ -50325,10 +50412,10 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
50325
50412
|
const successes = [];
|
|
50326
50413
|
const failures = [];
|
|
50327
50414
|
for (const file3 of checkpointFiles) {
|
|
50328
|
-
const src =
|
|
50329
|
-
const dest =
|
|
50415
|
+
const src = path31.join(checkpointDir, file3);
|
|
50416
|
+
const dest = path31.join(swarmDir, file3);
|
|
50330
50417
|
try {
|
|
50331
|
-
|
|
50418
|
+
fs20.cpSync(src, dest, { recursive: true, force: true });
|
|
50332
50419
|
successes.push(file3);
|
|
50333
50420
|
} catch (error93) {
|
|
50334
50421
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -50345,7 +50432,7 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
50345
50432
|
timestamp: new Date().toISOString()
|
|
50346
50433
|
};
|
|
50347
50434
|
try {
|
|
50348
|
-
|
|
50435
|
+
fs20.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
50349
50436
|
`);
|
|
50350
50437
|
} catch (error93) {
|
|
50351
50438
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -50389,11 +50476,11 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
50389
50476
|
];
|
|
50390
50477
|
const report = reportLines.filter(Boolean).join(`
|
|
50391
50478
|
`);
|
|
50392
|
-
const
|
|
50393
|
-
const
|
|
50394
|
-
const reportPath =
|
|
50395
|
-
await
|
|
50396
|
-
await
|
|
50479
|
+
const fs21 = await import("fs/promises");
|
|
50480
|
+
const path32 = await import("path");
|
|
50481
|
+
const reportPath = path32.join(directory, ".swarm", "simulate-report.md");
|
|
50482
|
+
await fs21.mkdir(path32.dirname(reportPath), { recursive: true });
|
|
50483
|
+
await fs21.writeFile(reportPath, report, "utf-8");
|
|
50397
50484
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
50398
50485
|
}
|
|
50399
50486
|
|
|
@@ -50750,8 +50837,8 @@ init_utils2();
|
|
|
50750
50837
|
init_manager2();
|
|
50751
50838
|
|
|
50752
50839
|
// src/services/compaction-service.ts
|
|
50753
|
-
import * as
|
|
50754
|
-
import * as
|
|
50840
|
+
import * as fs21 from "fs";
|
|
50841
|
+
import * as path32 from "path";
|
|
50755
50842
|
function makeInitialState() {
|
|
50756
50843
|
return {
|
|
50757
50844
|
lastObservationAt: 0,
|
|
@@ -50774,13 +50861,13 @@ function getSessionState(sessionId) {
|
|
|
50774
50861
|
}
|
|
50775
50862
|
function appendSnapshot(directory, tier, budgetPct, message) {
|
|
50776
50863
|
try {
|
|
50777
|
-
const snapshotPath =
|
|
50864
|
+
const snapshotPath = path32.join(directory, ".swarm", "context-snapshot.md");
|
|
50778
50865
|
const timestamp = new Date().toISOString();
|
|
50779
50866
|
const entry = `
|
|
50780
50867
|
## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
|
|
50781
50868
|
${message}
|
|
50782
50869
|
`;
|
|
50783
|
-
|
|
50870
|
+
fs21.appendFileSync(snapshotPath, entry, "utf-8");
|
|
50784
50871
|
} catch {}
|
|
50785
50872
|
}
|
|
50786
50873
|
function buildObservationMessage(budgetPct) {
|
|
@@ -51505,11 +51592,11 @@ async function doFlush(directory) {
|
|
|
51505
51592
|
const activitySection = renderActivitySection();
|
|
51506
51593
|
const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
|
|
51507
51594
|
const flushedCount = swarmState.pendingEvents;
|
|
51508
|
-
const
|
|
51509
|
-
const tempPath = `${
|
|
51595
|
+
const path33 = nodePath2.join(directory, ".swarm", "context.md");
|
|
51596
|
+
const tempPath = `${path33}.tmp`;
|
|
51510
51597
|
try {
|
|
51511
51598
|
await Bun.write(tempPath, updated);
|
|
51512
|
-
renameSync8(tempPath,
|
|
51599
|
+
renameSync8(tempPath, path33);
|
|
51513
51600
|
} catch (writeError) {
|
|
51514
51601
|
try {
|
|
51515
51602
|
unlinkSync4(tempPath);
|
|
@@ -51558,7 +51645,7 @@ ${content.substring(endIndex + 1)}`;
|
|
|
51558
51645
|
}
|
|
51559
51646
|
// src/hooks/compaction-customizer.ts
|
|
51560
51647
|
init_manager2();
|
|
51561
|
-
import * as
|
|
51648
|
+
import * as fs22 from "fs";
|
|
51562
51649
|
import { join as join29 } from "path";
|
|
51563
51650
|
init_utils2();
|
|
51564
51651
|
function createCompactionCustomizerHook(config3, directory) {
|
|
@@ -51606,7 +51693,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
51606
51693
|
}
|
|
51607
51694
|
try {
|
|
51608
51695
|
const summariesDir = join29(directory, ".swarm", "summaries");
|
|
51609
|
-
const files = await
|
|
51696
|
+
const files = await fs22.promises.readdir(summariesDir);
|
|
51610
51697
|
if (files.length > 0) {
|
|
51611
51698
|
const count = files.length;
|
|
51612
51699
|
output.context.push(`[CONTEXT OPTIMIZATION] Tool outputs from earlier in this session have been stored to disk. When compacting, replace any large tool output blocks (bash, test_runner, lint, diff results) with a one-line reference: "[Output stored \u2014 use /swarm retrieve to access full content]". Preserve the tool name, exit status, and any error messages. Discard raw output lines.`);
|
|
@@ -52091,8 +52178,8 @@ function maskToolOutput(msg, _threshold) {
|
|
|
52091
52178
|
}
|
|
52092
52179
|
// src/hooks/delegation-gate.ts
|
|
52093
52180
|
init_schema();
|
|
52094
|
-
import * as
|
|
52095
|
-
import * as
|
|
52181
|
+
import * as fs23 from "fs";
|
|
52182
|
+
import * as path35 from "path";
|
|
52096
52183
|
|
|
52097
52184
|
// src/parallel/review-router.ts
|
|
52098
52185
|
async function computeComplexity(directory, changedFiles) {
|
|
@@ -52104,13 +52191,13 @@ async function computeComplexity(directory, changedFiles) {
|
|
|
52104
52191
|
continue;
|
|
52105
52192
|
}
|
|
52106
52193
|
try {
|
|
52107
|
-
const
|
|
52108
|
-
const
|
|
52109
|
-
const filePath =
|
|
52110
|
-
if (!
|
|
52194
|
+
const fs23 = await import("fs");
|
|
52195
|
+
const path33 = await import("path");
|
|
52196
|
+
const filePath = path33.join(directory, file3);
|
|
52197
|
+
if (!fs23.existsSync(filePath)) {
|
|
52111
52198
|
continue;
|
|
52112
52199
|
}
|
|
52113
|
-
const content =
|
|
52200
|
+
const content = fs23.readFileSync(filePath, "utf-8");
|
|
52114
52201
|
const functionMatches = content.match(/\b(function|def|func|fn)\s+\w+/g);
|
|
52115
52202
|
const fileFunctionCount = functionMatches?.length || 0;
|
|
52116
52203
|
functionCount += fileFunctionCount;
|
|
@@ -52158,7 +52245,7 @@ function shouldParallelizeReview(routing) {
|
|
|
52158
52245
|
init_telemetry();
|
|
52159
52246
|
|
|
52160
52247
|
// src/hooks/guardrails.ts
|
|
52161
|
-
import * as
|
|
52248
|
+
import * as path33 from "path";
|
|
52162
52249
|
init_constants();
|
|
52163
52250
|
init_schema();
|
|
52164
52251
|
|
|
@@ -52320,10 +52407,10 @@ function isArchitect(sessionId) {
|
|
|
52320
52407
|
function isOutsideSwarmDir(filePath, directory) {
|
|
52321
52408
|
if (!filePath)
|
|
52322
52409
|
return false;
|
|
52323
|
-
const swarmDir =
|
|
52324
|
-
const resolved =
|
|
52325
|
-
const relative4 =
|
|
52326
|
-
return relative4.startsWith("..") ||
|
|
52410
|
+
const swarmDir = path33.resolve(directory, ".swarm");
|
|
52411
|
+
const resolved = path33.resolve(directory, filePath);
|
|
52412
|
+
const relative4 = path33.relative(swarmDir, resolved);
|
|
52413
|
+
return relative4.startsWith("..") || path33.isAbsolute(relative4);
|
|
52327
52414
|
}
|
|
52328
52415
|
function isSourceCodePath(filePath) {
|
|
52329
52416
|
if (!filePath)
|
|
@@ -52391,13 +52478,13 @@ function getCurrentTaskId(sessionId) {
|
|
|
52391
52478
|
}
|
|
52392
52479
|
function isInDeclaredScope(filePath, scopeEntries, cwd) {
|
|
52393
52480
|
const dir = cwd ?? process.cwd();
|
|
52394
|
-
const resolvedFile =
|
|
52481
|
+
const resolvedFile = path33.resolve(dir, filePath);
|
|
52395
52482
|
return scopeEntries.some((scope) => {
|
|
52396
|
-
const resolvedScope =
|
|
52483
|
+
const resolvedScope = path33.resolve(dir, scope);
|
|
52397
52484
|
if (resolvedFile === resolvedScope)
|
|
52398
52485
|
return true;
|
|
52399
|
-
const rel =
|
|
52400
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
52486
|
+
const rel = path33.relative(resolvedScope, resolvedFile);
|
|
52487
|
+
return rel.length > 0 && !rel.startsWith("..") && !path33.isAbsolute(rel);
|
|
52401
52488
|
});
|
|
52402
52489
|
}
|
|
52403
52490
|
function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
@@ -52593,9 +52680,9 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
52593
52680
|
const toolArgs = args2;
|
|
52594
52681
|
const targetPath = toolArgs?.filePath ?? toolArgs?.path ?? toolArgs?.file ?? toolArgs?.target;
|
|
52595
52682
|
if (typeof targetPath === "string" && targetPath.length > 0) {
|
|
52596
|
-
const resolvedTarget =
|
|
52597
|
-
const planMdPath =
|
|
52598
|
-
const planJsonPath =
|
|
52683
|
+
const resolvedTarget = path33.resolve(effectiveDirectory, targetPath).toLowerCase();
|
|
52684
|
+
const planMdPath = path33.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
|
|
52685
|
+
const planJsonPath = path33.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
|
|
52599
52686
|
if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
|
|
52600
52687
|
throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
|
|
52601
52688
|
}
|
|
@@ -52644,9 +52731,9 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
52644
52731
|
}
|
|
52645
52732
|
}
|
|
52646
52733
|
for (const p of paths) {
|
|
52647
|
-
const resolvedP =
|
|
52648
|
-
const planMdPath =
|
|
52649
|
-
const planJsonPath =
|
|
52734
|
+
const resolvedP = path33.resolve(effectiveDirectory, p);
|
|
52735
|
+
const planMdPath = path33.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
|
|
52736
|
+
const planJsonPath = path33.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
|
|
52650
52737
|
if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
|
|
52651
52738
|
throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
|
|
52652
52739
|
}
|
|
@@ -52666,7 +52753,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
|
|
|
52666
52753
|
}
|
|
52667
52754
|
}
|
|
52668
52755
|
}
|
|
52669
|
-
if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, effectiveDirectory) && isSourceCodePath(
|
|
52756
|
+
if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, effectiveDirectory) && isSourceCodePath(path33.relative(effectiveDirectory, path33.resolve(effectiveDirectory, targetPath)))) {
|
|
52670
52757
|
const session = swarmState.agentSessions.get(sessionID);
|
|
52671
52758
|
if (session) {
|
|
52672
52759
|
session.architectWriteCount++;
|
|
@@ -53297,8 +53384,8 @@ var AGENT_AUTHORITY_RULES = {
|
|
|
53297
53384
|
function checkFileAuthority(agentName, filePath, cwd) {
|
|
53298
53385
|
const normalizedAgent = agentName.toLowerCase();
|
|
53299
53386
|
const dir = cwd || process.cwd();
|
|
53300
|
-
const resolved =
|
|
53301
|
-
const normalizedPath =
|
|
53387
|
+
const resolved = path33.resolve(dir, filePath);
|
|
53388
|
+
const normalizedPath = path33.relative(dir, resolved).replace(/\\/g, "/");
|
|
53302
53389
|
const rules = AGENT_AUTHORITY_RULES[normalizedAgent];
|
|
53303
53390
|
if (!rules) {
|
|
53304
53391
|
return { allowed: false, reason: `Unknown agent: ${agentName}` };
|
|
@@ -53380,13 +53467,13 @@ async function getEvidenceTaskId(session, directory) {
|
|
|
53380
53467
|
if (typeof directory !== "string" || directory.length === 0) {
|
|
53381
53468
|
return null;
|
|
53382
53469
|
}
|
|
53383
|
-
const resolvedDirectory =
|
|
53384
|
-
const planPath =
|
|
53385
|
-
const resolvedPlanPath =
|
|
53386
|
-
if (!resolvedPlanPath.startsWith(resolvedDirectory +
|
|
53470
|
+
const resolvedDirectory = path35.resolve(directory);
|
|
53471
|
+
const planPath = path35.join(resolvedDirectory, ".swarm", "plan.json");
|
|
53472
|
+
const resolvedPlanPath = path35.resolve(planPath);
|
|
53473
|
+
if (!resolvedPlanPath.startsWith(resolvedDirectory + path35.sep) && resolvedPlanPath !== resolvedDirectory) {
|
|
53387
53474
|
return null;
|
|
53388
53475
|
}
|
|
53389
|
-
const planContent = await
|
|
53476
|
+
const planContent = await fs23.promises.readFile(resolvedPlanPath, "utf-8");
|
|
53390
53477
|
const plan = JSON.parse(planContent);
|
|
53391
53478
|
if (!plan || !Array.isArray(plan.phases)) {
|
|
53392
53479
|
return null;
|
|
@@ -53915,7 +54002,7 @@ ${warningLines.join(`
|
|
|
53915
54002
|
}
|
|
53916
54003
|
// src/hooks/delegation-sanitizer.ts
|
|
53917
54004
|
init_utils2();
|
|
53918
|
-
import * as
|
|
54005
|
+
import * as fs24 from "fs";
|
|
53919
54006
|
var SANITIZATION_PATTERNS = [
|
|
53920
54007
|
/\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
|
|
53921
54008
|
/\b(5th|fifth|final|last)\s+attempt\b/gi,
|
|
@@ -53986,7 +54073,7 @@ function createDelegationSanitizerHook(directory) {
|
|
|
53986
54073
|
stripped_patterns: result.stripped,
|
|
53987
54074
|
timestamp: new Date().toISOString()
|
|
53988
54075
|
};
|
|
53989
|
-
|
|
54076
|
+
fs24.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
53990
54077
|
`, "utf-8");
|
|
53991
54078
|
} catch {}
|
|
53992
54079
|
}
|
|
@@ -54111,7 +54198,7 @@ function consolidateSystemMessages(messages) {
|
|
|
54111
54198
|
// src/hooks/phase-monitor.ts
|
|
54112
54199
|
init_schema();
|
|
54113
54200
|
init_manager2();
|
|
54114
|
-
import * as
|
|
54201
|
+
import * as path36 from "path";
|
|
54115
54202
|
init_utils2();
|
|
54116
54203
|
function createPhaseMonitorHook(directory, preflightManager, curatorRunner = runCuratorInit) {
|
|
54117
54204
|
let lastKnownPhase = null;
|
|
@@ -54129,9 +54216,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner = run
|
|
|
54129
54216
|
if (curatorConfig.enabled && curatorConfig.init_enabled) {
|
|
54130
54217
|
const initResult = await curatorRunner(directory, curatorConfig);
|
|
54131
54218
|
if (initResult.briefing) {
|
|
54132
|
-
const briefingPath =
|
|
54219
|
+
const briefingPath = path36.join(directory, ".swarm", "curator-briefing.md");
|
|
54133
54220
|
const { mkdir: mkdir5, writeFile: writeFile5 } = await import("fs/promises");
|
|
54134
|
-
await mkdir5(
|
|
54221
|
+
await mkdir5(path36.dirname(briefingPath), { recursive: true });
|
|
54135
54222
|
await writeFile5(briefingPath, initResult.briefing, "utf-8");
|
|
54136
54223
|
}
|
|
54137
54224
|
}
|
|
@@ -54243,15 +54330,15 @@ init_schema();
|
|
|
54243
54330
|
init_manager();
|
|
54244
54331
|
init_detector();
|
|
54245
54332
|
init_manager2();
|
|
54246
|
-
import * as
|
|
54247
|
-
import * as
|
|
54333
|
+
import * as fs28 from "fs";
|
|
54334
|
+
import * as path40 from "path";
|
|
54248
54335
|
|
|
54249
54336
|
// src/services/decision-drift-analyzer.ts
|
|
54250
54337
|
init_utils2();
|
|
54251
54338
|
init_manager2();
|
|
54252
54339
|
init_utils();
|
|
54253
|
-
import * as
|
|
54254
|
-
import * as
|
|
54340
|
+
import * as fs25 from "fs";
|
|
54341
|
+
import * as path37 from "path";
|
|
54255
54342
|
var DEFAULT_DRIFT_CONFIG = {
|
|
54256
54343
|
staleThresholdPhases: 1,
|
|
54257
54344
|
detectContradictions: true,
|
|
@@ -54405,11 +54492,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
|
|
|
54405
54492
|
currentPhase = legacyPhase;
|
|
54406
54493
|
}
|
|
54407
54494
|
}
|
|
54408
|
-
const contextPath =
|
|
54495
|
+
const contextPath = path37.join(directory, ".swarm", "context.md");
|
|
54409
54496
|
let contextContent = "";
|
|
54410
54497
|
try {
|
|
54411
|
-
if (
|
|
54412
|
-
contextContent =
|
|
54498
|
+
if (fs25.existsSync(contextPath)) {
|
|
54499
|
+
contextContent = fs25.readFileSync(contextPath, "utf-8");
|
|
54413
54500
|
}
|
|
54414
54501
|
} catch (error93) {
|
|
54415
54502
|
log("[DecisionDriftAnalyzer] context file read failed", {
|
|
@@ -54534,8 +54621,8 @@ init_utils();
|
|
|
54534
54621
|
// src/hooks/adversarial-detector.ts
|
|
54535
54622
|
init_constants();
|
|
54536
54623
|
init_schema();
|
|
54537
|
-
import * as
|
|
54538
|
-
import * as
|
|
54624
|
+
import * as fs26 from "fs/promises";
|
|
54625
|
+
import * as path38 from "path";
|
|
54539
54626
|
function safeGet(obj, key) {
|
|
54540
54627
|
if (!obj || !Object.hasOwn(obj, key))
|
|
54541
54628
|
return;
|
|
@@ -54749,10 +54836,10 @@ async function handleDebuggingSpiral(match, taskId, directory) {
|
|
|
54749
54836
|
let eventLogged = false;
|
|
54750
54837
|
let checkpointCreated = false;
|
|
54751
54838
|
try {
|
|
54752
|
-
const swarmDir =
|
|
54753
|
-
await
|
|
54754
|
-
const eventsPath =
|
|
54755
|
-
await
|
|
54839
|
+
const swarmDir = path38.join(directory, ".swarm");
|
|
54840
|
+
await fs26.mkdir(swarmDir, { recursive: true });
|
|
54841
|
+
const eventsPath = path38.join(swarmDir, "events.jsonl");
|
|
54842
|
+
await fs26.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
|
|
54756
54843
|
`);
|
|
54757
54844
|
eventLogged = true;
|
|
54758
54845
|
} catch {}
|
|
@@ -55133,7 +55220,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
55133
55220
|
} catch {}
|
|
55134
55221
|
try {
|
|
55135
55222
|
const darkMatterPath = validateSwarmPath(directory, "dark-matter.md");
|
|
55136
|
-
if (!
|
|
55223
|
+
if (!fs28.existsSync(darkMatterPath)) {
|
|
55137
55224
|
const {
|
|
55138
55225
|
detectDarkMatter: detectDarkMatter2,
|
|
55139
55226
|
formatDarkMatterOutput: formatDarkMatterOutput2,
|
|
@@ -55146,10 +55233,10 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
55146
55233
|
});
|
|
55147
55234
|
if (darkMatter && darkMatter.length > 0) {
|
|
55148
55235
|
const darkMatterReport = formatDarkMatterOutput2(darkMatter);
|
|
55149
|
-
await
|
|
55236
|
+
await fs28.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
|
|
55150
55237
|
warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
|
|
55151
55238
|
try {
|
|
55152
|
-
const projectName =
|
|
55239
|
+
const projectName = path40.basename(path40.resolve(directory));
|
|
55153
55240
|
const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
|
|
55154
55241
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
55155
55242
|
const existingEntries = await readKnowledge(knowledgePath);
|
|
@@ -55200,11 +55287,11 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
55200
55287
|
if (handoffContent) {
|
|
55201
55288
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
55202
55289
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
55203
|
-
if (
|
|
55290
|
+
if (fs28.existsSync(consumedPath)) {
|
|
55204
55291
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
55205
|
-
|
|
55292
|
+
fs28.unlinkSync(consumedPath);
|
|
55206
55293
|
}
|
|
55207
|
-
|
|
55294
|
+
fs28.renameSync(handoffPath, consumedPath);
|
|
55208
55295
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
55209
55296
|
The previous model's session ended. Here is your starting context:
|
|
55210
55297
|
|
|
@@ -55485,11 +55572,11 @@ ${budgetWarning}`);
|
|
|
55485
55572
|
if (handoffContent) {
|
|
55486
55573
|
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
55487
55574
|
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
55488
|
-
if (
|
|
55575
|
+
if (fs28.existsSync(consumedPath)) {
|
|
55489
55576
|
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
55490
|
-
|
|
55577
|
+
fs28.unlinkSync(consumedPath);
|
|
55491
55578
|
}
|
|
55492
|
-
|
|
55579
|
+
fs28.renameSync(handoffPath, consumedPath);
|
|
55493
55580
|
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
55494
55581
|
The previous model's session ended. Here is your starting context:
|
|
55495
55582
|
|
|
@@ -56259,14 +56346,14 @@ function isReadTool(toolName) {
|
|
|
56259
56346
|
}
|
|
56260
56347
|
|
|
56261
56348
|
// src/hooks/incremental-verify.ts
|
|
56262
|
-
import * as
|
|
56263
|
-
import * as
|
|
56349
|
+
import * as fs29 from "fs";
|
|
56350
|
+
import * as path41 from "path";
|
|
56264
56351
|
|
|
56265
56352
|
// src/hooks/spawn-helper.ts
|
|
56266
56353
|
import { spawn } from "child_process";
|
|
56267
56354
|
var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
|
|
56268
56355
|
function spawnAsync(command, cwd, timeoutMs) {
|
|
56269
|
-
return new Promise((
|
|
56356
|
+
return new Promise((resolve13) => {
|
|
56270
56357
|
try {
|
|
56271
56358
|
const [rawCmd, ...args2] = command;
|
|
56272
56359
|
const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
|
|
@@ -56310,24 +56397,24 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
56310
56397
|
try {
|
|
56311
56398
|
proc.kill();
|
|
56312
56399
|
} catch {}
|
|
56313
|
-
|
|
56400
|
+
resolve13(null);
|
|
56314
56401
|
}, timeoutMs);
|
|
56315
56402
|
proc.on("close", (code) => {
|
|
56316
56403
|
if (done)
|
|
56317
56404
|
return;
|
|
56318
56405
|
done = true;
|
|
56319
56406
|
clearTimeout(timer);
|
|
56320
|
-
|
|
56407
|
+
resolve13({ exitCode: code ?? 1, stdout, stderr });
|
|
56321
56408
|
});
|
|
56322
56409
|
proc.on("error", () => {
|
|
56323
56410
|
if (done)
|
|
56324
56411
|
return;
|
|
56325
56412
|
done = true;
|
|
56326
56413
|
clearTimeout(timer);
|
|
56327
|
-
|
|
56414
|
+
resolve13(null);
|
|
56328
56415
|
});
|
|
56329
56416
|
} catch {
|
|
56330
|
-
|
|
56417
|
+
resolve13(null);
|
|
56331
56418
|
}
|
|
56332
56419
|
});
|
|
56333
56420
|
}
|
|
@@ -56335,21 +56422,21 @@ function spawnAsync(command, cwd, timeoutMs) {
|
|
|
56335
56422
|
// src/hooks/incremental-verify.ts
|
|
56336
56423
|
var emittedSkipAdvisories = new Set;
|
|
56337
56424
|
function detectPackageManager(projectDir) {
|
|
56338
|
-
if (
|
|
56425
|
+
if (fs29.existsSync(path41.join(projectDir, "bun.lockb")))
|
|
56339
56426
|
return "bun";
|
|
56340
|
-
if (
|
|
56427
|
+
if (fs29.existsSync(path41.join(projectDir, "pnpm-lock.yaml")))
|
|
56341
56428
|
return "pnpm";
|
|
56342
|
-
if (
|
|
56429
|
+
if (fs29.existsSync(path41.join(projectDir, "yarn.lock")))
|
|
56343
56430
|
return "yarn";
|
|
56344
|
-
if (
|
|
56431
|
+
if (fs29.existsSync(path41.join(projectDir, "package-lock.json")))
|
|
56345
56432
|
return "npm";
|
|
56346
56433
|
return "bun";
|
|
56347
56434
|
}
|
|
56348
56435
|
function detectTypecheckCommand(projectDir) {
|
|
56349
|
-
const pkgPath =
|
|
56350
|
-
if (
|
|
56436
|
+
const pkgPath = path41.join(projectDir, "package.json");
|
|
56437
|
+
if (fs29.existsSync(pkgPath)) {
|
|
56351
56438
|
try {
|
|
56352
|
-
const pkg = JSON.parse(
|
|
56439
|
+
const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
|
|
56353
56440
|
const scripts = pkg.scripts;
|
|
56354
56441
|
if (scripts?.typecheck) {
|
|
56355
56442
|
const pm = detectPackageManager(projectDir);
|
|
@@ -56363,8 +56450,8 @@ function detectTypecheckCommand(projectDir) {
|
|
|
56363
56450
|
...pkg.dependencies,
|
|
56364
56451
|
...pkg.devDependencies
|
|
56365
56452
|
};
|
|
56366
|
-
if (!deps?.typescript && !
|
|
56367
|
-
const hasTSMarkers = deps?.typescript ||
|
|
56453
|
+
if (!deps?.typescript && !fs29.existsSync(path41.join(projectDir, "tsconfig.json"))) {}
|
|
56454
|
+
const hasTSMarkers = deps?.typescript || fs29.existsSync(path41.join(projectDir, "tsconfig.json"));
|
|
56368
56455
|
if (hasTSMarkers) {
|
|
56369
56456
|
return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
|
|
56370
56457
|
}
|
|
@@ -56372,17 +56459,17 @@ function detectTypecheckCommand(projectDir) {
|
|
|
56372
56459
|
return null;
|
|
56373
56460
|
}
|
|
56374
56461
|
}
|
|
56375
|
-
if (
|
|
56462
|
+
if (fs29.existsSync(path41.join(projectDir, "go.mod"))) {
|
|
56376
56463
|
return { command: ["go", "vet", "./..."], language: "go" };
|
|
56377
56464
|
}
|
|
56378
|
-
if (
|
|
56465
|
+
if (fs29.existsSync(path41.join(projectDir, "Cargo.toml"))) {
|
|
56379
56466
|
return { command: ["cargo", "check"], language: "rust" };
|
|
56380
56467
|
}
|
|
56381
|
-
if (
|
|
56468
|
+
if (fs29.existsSync(path41.join(projectDir, "pyproject.toml")) || fs29.existsSync(path41.join(projectDir, "requirements.txt")) || fs29.existsSync(path41.join(projectDir, "setup.py"))) {
|
|
56382
56469
|
return { command: null, language: "python" };
|
|
56383
56470
|
}
|
|
56384
56471
|
try {
|
|
56385
|
-
const entries =
|
|
56472
|
+
const entries = fs29.readdirSync(projectDir);
|
|
56386
56473
|
if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
56387
56474
|
return {
|
|
56388
56475
|
command: ["dotnet", "build", "--no-restore"],
|
|
@@ -56691,7 +56778,7 @@ ${injectionText}`;
|
|
|
56691
56778
|
// src/hooks/scope-guard.ts
|
|
56692
56779
|
init_constants();
|
|
56693
56780
|
init_schema();
|
|
56694
|
-
import * as
|
|
56781
|
+
import * as path43 from "path";
|
|
56695
56782
|
var WRITE_TOOLS = new Set([
|
|
56696
56783
|
"write",
|
|
56697
56784
|
"edit",
|
|
@@ -56753,13 +56840,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
|
|
|
56753
56840
|
}
|
|
56754
56841
|
function isFileInScope(filePath, scopeEntries, directory) {
|
|
56755
56842
|
const dir = directory ?? process.cwd();
|
|
56756
|
-
const resolvedFile =
|
|
56843
|
+
const resolvedFile = path43.resolve(dir, filePath);
|
|
56757
56844
|
return scopeEntries.some((scope) => {
|
|
56758
|
-
const resolvedScope =
|
|
56845
|
+
const resolvedScope = path43.resolve(dir, scope);
|
|
56759
56846
|
if (resolvedFile === resolvedScope)
|
|
56760
56847
|
return true;
|
|
56761
|
-
const rel =
|
|
56762
|
-
return rel.length > 0 && !rel.startsWith("..") && !
|
|
56848
|
+
const rel = path43.relative(resolvedScope, resolvedFile);
|
|
56849
|
+
return rel.length > 0 && !rel.startsWith("..") && !path43.isAbsolute(rel);
|
|
56763
56850
|
});
|
|
56764
56851
|
}
|
|
56765
56852
|
|
|
@@ -56808,8 +56895,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
|
|
|
56808
56895
|
}
|
|
56809
56896
|
|
|
56810
56897
|
// src/hooks/slop-detector.ts
|
|
56811
|
-
import * as
|
|
56812
|
-
import * as
|
|
56898
|
+
import * as fs31 from "fs";
|
|
56899
|
+
import * as path44 from "path";
|
|
56813
56900
|
var WRITE_EDIT_TOOLS = new Set([
|
|
56814
56901
|
"write",
|
|
56815
56902
|
"edit",
|
|
@@ -56854,12 +56941,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
|
|
|
56854
56941
|
function walkFiles(dir, exts, deadline) {
|
|
56855
56942
|
const results = [];
|
|
56856
56943
|
try {
|
|
56857
|
-
for (const entry of
|
|
56944
|
+
for (const entry of fs31.readdirSync(dir, { withFileTypes: true })) {
|
|
56858
56945
|
if (deadline !== undefined && Date.now() > deadline)
|
|
56859
56946
|
break;
|
|
56860
56947
|
if (entry.isSymbolicLink())
|
|
56861
56948
|
continue;
|
|
56862
|
-
const full =
|
|
56949
|
+
const full = path44.join(dir, entry.name);
|
|
56863
56950
|
if (entry.isDirectory()) {
|
|
56864
56951
|
if (entry.name === "node_modules" || entry.name === ".git")
|
|
56865
56952
|
continue;
|
|
@@ -56874,7 +56961,7 @@ function walkFiles(dir, exts, deadline) {
|
|
|
56874
56961
|
return results;
|
|
56875
56962
|
}
|
|
56876
56963
|
function checkDeadExports(content, projectDir, startTime) {
|
|
56877
|
-
const hasPackageJson =
|
|
56964
|
+
const hasPackageJson = fs31.existsSync(path44.join(projectDir, "package.json"));
|
|
56878
56965
|
if (!hasPackageJson)
|
|
56879
56966
|
return null;
|
|
56880
56967
|
const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
|
|
@@ -56897,7 +56984,7 @@ function checkDeadExports(content, projectDir, startTime) {
|
|
|
56897
56984
|
if (found || Date.now() - startTime > 480)
|
|
56898
56985
|
break;
|
|
56899
56986
|
try {
|
|
56900
|
-
const text =
|
|
56987
|
+
const text = fs31.readFileSync(file3, "utf-8");
|
|
56901
56988
|
if (importPattern.test(text))
|
|
56902
56989
|
found = true;
|
|
56903
56990
|
importPattern.lastIndex = 0;
|
|
@@ -57030,7 +57117,7 @@ Review before proceeding.`;
|
|
|
57030
57117
|
|
|
57031
57118
|
// src/hooks/steering-consumed.ts
|
|
57032
57119
|
init_utils2();
|
|
57033
|
-
import * as
|
|
57120
|
+
import * as fs32 from "fs";
|
|
57034
57121
|
function recordSteeringConsumed(directory, directiveId) {
|
|
57035
57122
|
try {
|
|
57036
57123
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -57039,7 +57126,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
57039
57126
|
directiveId,
|
|
57040
57127
|
timestamp: new Date().toISOString()
|
|
57041
57128
|
};
|
|
57042
|
-
|
|
57129
|
+
fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
57043
57130
|
`, "utf-8");
|
|
57044
57131
|
} catch {}
|
|
57045
57132
|
}
|
|
@@ -57329,21 +57416,24 @@ async function executeCommand(command) {
|
|
|
57329
57416
|
cmd = ["/bin/sh"];
|
|
57330
57417
|
args2 = ["-c", command.command];
|
|
57331
57418
|
}
|
|
57332
|
-
const result =
|
|
57419
|
+
const result = Bun.spawn({
|
|
57333
57420
|
cmd: [...cmd, ...args2],
|
|
57334
57421
|
cwd: command.cwd,
|
|
57335
57422
|
stdout: "pipe",
|
|
57336
57423
|
stderr: "pipe",
|
|
57337
57424
|
timeout: DEFAULT_TIMEOUT_MS2
|
|
57338
57425
|
});
|
|
57426
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
57427
|
+
result.exited,
|
|
57428
|
+
new Response(result.stdout).text(),
|
|
57429
|
+
new Response(result.stderr).text()
|
|
57430
|
+
]);
|
|
57339
57431
|
const duration_ms = Date.now() - startTime;
|
|
57340
|
-
const stdout = await new Response(result.stdout).text();
|
|
57341
|
-
const stderr = await new Response(result.stderr).text();
|
|
57342
57432
|
return {
|
|
57343
57433
|
kind,
|
|
57344
57434
|
command: command.command,
|
|
57345
57435
|
cwd: command.cwd,
|
|
57346
|
-
exit_code:
|
|
57436
|
+
exit_code: exitCode ?? -1,
|
|
57347
57437
|
duration_ms,
|
|
57348
57438
|
stdout_tail: truncateOutput(stdout),
|
|
57349
57439
|
stderr_tail: truncateOutput(stderr)
|
|
@@ -57448,8 +57538,9 @@ var build_check = createSwarmTool({
|
|
|
57448
57538
|
init_dist();
|
|
57449
57539
|
init_manager();
|
|
57450
57540
|
init_create_tool();
|
|
57451
|
-
|
|
57452
|
-
import * as
|
|
57541
|
+
init_resolve_working_directory();
|
|
57542
|
+
import * as fs33 from "fs";
|
|
57543
|
+
import * as path45 from "path";
|
|
57453
57544
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
57454
57545
|
var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
|
|
57455
57546
|
function isValidTaskId3(taskId) {
|
|
@@ -57466,18 +57557,18 @@ function isValidTaskId3(taskId) {
|
|
|
57466
57557
|
return TASK_ID_PATTERN2.test(taskId);
|
|
57467
57558
|
}
|
|
57468
57559
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
57469
|
-
const normalizedWorkspace =
|
|
57470
|
-
const swarmPath =
|
|
57471
|
-
const normalizedPath =
|
|
57560
|
+
const normalizedWorkspace = path45.resolve(workspaceRoot);
|
|
57561
|
+
const swarmPath = path45.join(normalizedWorkspace, ".swarm", "evidence");
|
|
57562
|
+
const normalizedPath = path45.resolve(filePath);
|
|
57472
57563
|
return normalizedPath.startsWith(swarmPath);
|
|
57473
57564
|
}
|
|
57474
57565
|
function readEvidenceFile(evidencePath) {
|
|
57475
|
-
if (!
|
|
57566
|
+
if (!fs33.existsSync(evidencePath)) {
|
|
57476
57567
|
return null;
|
|
57477
57568
|
}
|
|
57478
57569
|
let content;
|
|
57479
57570
|
try {
|
|
57480
|
-
content =
|
|
57571
|
+
content = fs33.readFileSync(evidencePath, "utf-8");
|
|
57481
57572
|
} catch {
|
|
57482
57573
|
return null;
|
|
57483
57574
|
}
|
|
@@ -57495,16 +57586,34 @@ function readEvidenceFile(evidencePath) {
|
|
|
57495
57586
|
var check_gate_status = createSwarmTool({
|
|
57496
57587
|
description: "Read-only tool to check the gate status of a specific task. Reads .swarm/evidence/{taskId}.json and returns structured JSON describing required, passed, and missing gates.",
|
|
57497
57588
|
args: {
|
|
57498
|
-
task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")')
|
|
57589
|
+
task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")'),
|
|
57590
|
+
working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/evidence/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
|
|
57499
57591
|
},
|
|
57500
57592
|
async execute(args2, directory) {
|
|
57501
57593
|
let taskIdInput;
|
|
57594
|
+
let workingDirInput;
|
|
57502
57595
|
try {
|
|
57503
57596
|
if (args2 && typeof args2 === "object") {
|
|
57504
57597
|
const obj = args2;
|
|
57505
57598
|
taskIdInput = typeof obj.task_id === "string" ? obj.task_id : undefined;
|
|
57599
|
+
workingDirInput = typeof obj.working_directory === "string" ? obj.working_directory : undefined;
|
|
57506
57600
|
}
|
|
57507
57601
|
} catch {}
|
|
57602
|
+
const dirResult = resolveWorkingDirectory(workingDirInput, directory);
|
|
57603
|
+
if (!dirResult.success) {
|
|
57604
|
+
const errorResult = {
|
|
57605
|
+
taskId: taskIdInput ?? "",
|
|
57606
|
+
status: "no_evidence",
|
|
57607
|
+
required_gates: [],
|
|
57608
|
+
passed_gates: [],
|
|
57609
|
+
missing_gates: [],
|
|
57610
|
+
gates: {},
|
|
57611
|
+
message: dirResult.message,
|
|
57612
|
+
todo_scan: null
|
|
57613
|
+
};
|
|
57614
|
+
return JSON.stringify(errorResult, null, 2);
|
|
57615
|
+
}
|
|
57616
|
+
directory = dirResult.directory;
|
|
57508
57617
|
if (!taskIdInput) {
|
|
57509
57618
|
const errorResult = {
|
|
57510
57619
|
taskId: "",
|
|
@@ -57531,7 +57640,7 @@ var check_gate_status = createSwarmTool({
|
|
|
57531
57640
|
};
|
|
57532
57641
|
return JSON.stringify(errorResult, null, 2);
|
|
57533
57642
|
}
|
|
57534
|
-
const evidencePath =
|
|
57643
|
+
const evidencePath = path45.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
57535
57644
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
57536
57645
|
const errorResult = {
|
|
57537
57646
|
taskId: taskIdInput,
|
|
@@ -57624,9 +57733,10 @@ init_co_change_analyzer();
|
|
|
57624
57733
|
// src/tools/completion-verify.ts
|
|
57625
57734
|
init_dist();
|
|
57626
57735
|
init_utils2();
|
|
57627
|
-
import * as
|
|
57628
|
-
import * as
|
|
57736
|
+
import * as fs34 from "fs";
|
|
57737
|
+
import * as path46 from "path";
|
|
57629
57738
|
init_create_tool();
|
|
57739
|
+
init_resolve_working_directory();
|
|
57630
57740
|
function extractMatches(regex, text) {
|
|
57631
57741
|
return Array.from(text.matchAll(regex));
|
|
57632
57742
|
}
|
|
@@ -57676,6 +57786,19 @@ function parseFilePaths(description, filesTouched) {
|
|
|
57676
57786
|
}
|
|
57677
57787
|
return filePaths;
|
|
57678
57788
|
}
|
|
57789
|
+
function buildVerifySummary(tasksChecked, tasksSkipped, tasksBlocked) {
|
|
57790
|
+
if (tasksBlocked > 0) {
|
|
57791
|
+
return `Blocked: ${tasksBlocked} task(s) with missing identifiers`;
|
|
57792
|
+
}
|
|
57793
|
+
const verified = tasksChecked - tasksSkipped;
|
|
57794
|
+
if (tasksSkipped === tasksChecked) {
|
|
57795
|
+
return `All ${tasksChecked} completed task(s) skipped \u2014 research/inventory tasks`;
|
|
57796
|
+
}
|
|
57797
|
+
if (tasksSkipped > 0) {
|
|
57798
|
+
return `${verified} task(s) verified, ${tasksSkipped} skipped (research tasks)`;
|
|
57799
|
+
}
|
|
57800
|
+
return `All ${tasksChecked} completed tasks verified successfully`;
|
|
57801
|
+
}
|
|
57679
57802
|
async function executeCompletionVerify(args2, directory) {
|
|
57680
57803
|
const phase = Number(args2.phase);
|
|
57681
57804
|
if (Number.isNaN(phase) || phase < 1 || !Number.isFinite(phase)) {
|
|
@@ -57707,7 +57830,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57707
57830
|
let plan;
|
|
57708
57831
|
try {
|
|
57709
57832
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
57710
|
-
const planRaw =
|
|
57833
|
+
const planRaw = fs34.readFileSync(planPath, "utf-8");
|
|
57711
57834
|
plan = JSON.parse(planRaw);
|
|
57712
57835
|
} catch {
|
|
57713
57836
|
const result2 = {
|
|
@@ -57737,7 +57860,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57737
57860
|
return JSON.stringify(result2, null, 2);
|
|
57738
57861
|
}
|
|
57739
57862
|
let tasksChecked = 0;
|
|
57740
|
-
|
|
57863
|
+
let tasksSkipped = 0;
|
|
57741
57864
|
let tasksBlocked = 0;
|
|
57742
57865
|
const blockedTasks = [];
|
|
57743
57866
|
for (const task of targetPhase.tasks) {
|
|
@@ -57748,13 +57871,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57748
57871
|
const fileTargets = parseFilePaths(task.description, task.files_touched);
|
|
57749
57872
|
const identifiers = parseIdentifiers(task.description);
|
|
57750
57873
|
if (fileTargets.length === 0) {
|
|
57751
|
-
|
|
57752
|
-
task_id: task.id,
|
|
57753
|
-
identifier: "",
|
|
57754
|
-
file_path: "",
|
|
57755
|
-
reason: "No file targets \u2014 cannot verify completion without files_touched"
|
|
57756
|
-
});
|
|
57757
|
-
tasksBlocked++;
|
|
57874
|
+
tasksSkipped++;
|
|
57758
57875
|
continue;
|
|
57759
57876
|
}
|
|
57760
57877
|
if (identifiers.length === 0) {
|
|
@@ -57771,10 +57888,23 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57771
57888
|
let hasFileReadFailure = false;
|
|
57772
57889
|
for (const filePath of fileTargets) {
|
|
57773
57890
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
57774
|
-
const resolvedPath =
|
|
57891
|
+
const resolvedPath = path46.resolve(directory, normalizedPath);
|
|
57892
|
+
const projectRoot = path46.resolve(directory);
|
|
57893
|
+
const relative6 = path46.relative(projectRoot, resolvedPath);
|
|
57894
|
+
const withinProject = relative6 === "" || !relative6.startsWith("..") && !path46.isAbsolute(relative6);
|
|
57895
|
+
if (!withinProject) {
|
|
57896
|
+
blockedTasks.push({
|
|
57897
|
+
task_id: task.id,
|
|
57898
|
+
identifier: "",
|
|
57899
|
+
file_path: filePath,
|
|
57900
|
+
reason: `File path '${filePath}' escapes the project directory \u2014 cannot verify completion`
|
|
57901
|
+
});
|
|
57902
|
+
hasFileReadFailure = true;
|
|
57903
|
+
continue;
|
|
57904
|
+
}
|
|
57775
57905
|
let fileContent;
|
|
57776
57906
|
try {
|
|
57777
|
-
fileContent =
|
|
57907
|
+
fileContent = fs34.readFileSync(resolvedPath, "utf-8");
|
|
57778
57908
|
} catch {
|
|
57779
57909
|
blockedTasks.push({
|
|
57780
57910
|
task_id: task.id,
|
|
@@ -57816,9 +57946,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57816
57946
|
blockedTasks
|
|
57817
57947
|
};
|
|
57818
57948
|
try {
|
|
57819
|
-
const evidenceDir =
|
|
57820
|
-
const evidencePath =
|
|
57821
|
-
|
|
57949
|
+
const evidenceDir = path46.join(directory, ".swarm", "evidence", `${phase}`);
|
|
57950
|
+
const evidencePath = path46.join(evidenceDir, "completion-verify.json");
|
|
57951
|
+
fs34.mkdirSync(evidenceDir, { recursive: true });
|
|
57822
57952
|
const evidenceBundle = {
|
|
57823
57953
|
schema_version: "1.0.0",
|
|
57824
57954
|
task_id: "completion-verify",
|
|
@@ -57830,7 +57960,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57830
57960
|
timestamp: now,
|
|
57831
57961
|
agent: "completion_verify",
|
|
57832
57962
|
verdict: tasksBlocked === 0 ? "pass" : "fail",
|
|
57833
|
-
summary:
|
|
57963
|
+
summary: buildVerifySummary(tasksChecked, tasksSkipped, tasksBlocked),
|
|
57834
57964
|
phase,
|
|
57835
57965
|
tasks_checked: tasksChecked,
|
|
57836
57966
|
tasks_skipped: tasksSkipped,
|
|
@@ -57839,7 +57969,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
57839
57969
|
}
|
|
57840
57970
|
]
|
|
57841
57971
|
};
|
|
57842
|
-
|
|
57972
|
+
fs34.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
57843
57973
|
} catch {}
|
|
57844
57974
|
return JSON.stringify(result, null, 2);
|
|
57845
57975
|
}
|
|
@@ -57847,7 +57977,8 @@ var completion_verify = createSwarmTool({
|
|
|
57847
57977
|
description: "Deterministic pre-check verifying that plan task identifiers exist in their target source files before phase completion. Blocks if obviously incomplete.",
|
|
57848
57978
|
args: {
|
|
57849
57979
|
phase: tool.schema.number().describe("The phase number to check"),
|
|
57850
|
-
sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
|
|
57980
|
+
sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
|
|
57981
|
+
working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
|
|
57851
57982
|
},
|
|
57852
57983
|
execute: async (args2, directory) => {
|
|
57853
57984
|
let parsedArgs;
|
|
@@ -57856,7 +57987,8 @@ var completion_verify = createSwarmTool({
|
|
|
57856
57987
|
const obj = args2;
|
|
57857
57988
|
parsedArgs = {
|
|
57858
57989
|
phase: typeof obj.phase === "number" ? obj.phase : typeof obj.phase === "string" ? Number(obj.phase) : 0,
|
|
57859
|
-
sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined
|
|
57990
|
+
sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined,
|
|
57991
|
+
working_directory: typeof obj.working_directory === "string" ? obj.working_directory : undefined
|
|
57860
57992
|
};
|
|
57861
57993
|
} else {
|
|
57862
57994
|
parsedArgs = { phase: 0 };
|
|
@@ -57873,17 +58005,30 @@ var completion_verify = createSwarmTool({
|
|
|
57873
58005
|
blockedTasks: []
|
|
57874
58006
|
}, null, 2);
|
|
57875
58007
|
}
|
|
57876
|
-
|
|
58008
|
+
const dirResult = resolveWorkingDirectory(parsedArgs.working_directory, directory);
|
|
58009
|
+
if (!dirResult.success) {
|
|
58010
|
+
return JSON.stringify({
|
|
58011
|
+
success: false,
|
|
58012
|
+
phase: parsedArgs.phase,
|
|
58013
|
+
status: "blocked",
|
|
58014
|
+
reason: dirResult.message,
|
|
58015
|
+
tasksChecked: 0,
|
|
58016
|
+
tasksSkipped: 0,
|
|
58017
|
+
tasksBlocked: 0,
|
|
58018
|
+
blockedTasks: []
|
|
58019
|
+
}, null, 2);
|
|
58020
|
+
}
|
|
58021
|
+
return executeCompletionVerify(parsedArgs, dirResult.directory);
|
|
57877
58022
|
}
|
|
57878
58023
|
});
|
|
57879
58024
|
// src/tools/complexity-hotspots.ts
|
|
57880
58025
|
init_dist();
|
|
57881
|
-
import * as
|
|
57882
|
-
import * as
|
|
58026
|
+
import * as fs36 from "fs";
|
|
58027
|
+
import * as path48 from "path";
|
|
57883
58028
|
|
|
57884
58029
|
// src/quality/metrics.ts
|
|
57885
|
-
import * as
|
|
57886
|
-
import * as
|
|
58030
|
+
import * as fs35 from "fs";
|
|
58031
|
+
import * as path47 from "path";
|
|
57887
58032
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
57888
58033
|
var MIN_DUPLICATION_LINES = 10;
|
|
57889
58034
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -57921,11 +58066,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
57921
58066
|
}
|
|
57922
58067
|
function getComplexityForFile(filePath) {
|
|
57923
58068
|
try {
|
|
57924
|
-
const stat2 =
|
|
58069
|
+
const stat2 = fs35.statSync(filePath);
|
|
57925
58070
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
57926
58071
|
return null;
|
|
57927
58072
|
}
|
|
57928
|
-
const content =
|
|
58073
|
+
const content = fs35.readFileSync(filePath, "utf-8");
|
|
57929
58074
|
return estimateCyclomaticComplexity(content);
|
|
57930
58075
|
} catch {
|
|
57931
58076
|
return null;
|
|
@@ -57935,8 +58080,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
57935
58080
|
let totalComplexity = 0;
|
|
57936
58081
|
const analyzedFiles = [];
|
|
57937
58082
|
for (const file3 of files) {
|
|
57938
|
-
const fullPath =
|
|
57939
|
-
if (!
|
|
58083
|
+
const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
|
|
58084
|
+
if (!fs35.existsSync(fullPath)) {
|
|
57940
58085
|
continue;
|
|
57941
58086
|
}
|
|
57942
58087
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -58057,8 +58202,8 @@ function countGoExports(content) {
|
|
|
58057
58202
|
}
|
|
58058
58203
|
function getExportCountForFile(filePath) {
|
|
58059
58204
|
try {
|
|
58060
|
-
const content =
|
|
58061
|
-
const ext =
|
|
58205
|
+
const content = fs35.readFileSync(filePath, "utf-8");
|
|
58206
|
+
const ext = path47.extname(filePath).toLowerCase();
|
|
58062
58207
|
switch (ext) {
|
|
58063
58208
|
case ".ts":
|
|
58064
58209
|
case ".tsx":
|
|
@@ -58084,8 +58229,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
58084
58229
|
let totalExports = 0;
|
|
58085
58230
|
const analyzedFiles = [];
|
|
58086
58231
|
for (const file3 of files) {
|
|
58087
|
-
const fullPath =
|
|
58088
|
-
if (!
|
|
58232
|
+
const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
|
|
58233
|
+
if (!fs35.existsSync(fullPath)) {
|
|
58089
58234
|
continue;
|
|
58090
58235
|
}
|
|
58091
58236
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -58118,16 +58263,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
58118
58263
|
let duplicateLines = 0;
|
|
58119
58264
|
const analyzedFiles = [];
|
|
58120
58265
|
for (const file3 of files) {
|
|
58121
|
-
const fullPath =
|
|
58122
|
-
if (!
|
|
58266
|
+
const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
|
|
58267
|
+
if (!fs35.existsSync(fullPath)) {
|
|
58123
58268
|
continue;
|
|
58124
58269
|
}
|
|
58125
58270
|
try {
|
|
58126
|
-
const stat2 =
|
|
58271
|
+
const stat2 = fs35.statSync(fullPath);
|
|
58127
58272
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
58128
58273
|
continue;
|
|
58129
58274
|
}
|
|
58130
|
-
const content =
|
|
58275
|
+
const content = fs35.readFileSync(fullPath, "utf-8");
|
|
58131
58276
|
const lines = content.split(`
|
|
58132
58277
|
`).filter((line) => line.trim().length > 0);
|
|
58133
58278
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -58151,8 +58296,8 @@ function countCodeLines(content) {
|
|
|
58151
58296
|
return lines.length;
|
|
58152
58297
|
}
|
|
58153
58298
|
function isTestFile(filePath) {
|
|
58154
|
-
const basename7 =
|
|
58155
|
-
const _ext =
|
|
58299
|
+
const basename7 = path47.basename(filePath);
|
|
58300
|
+
const _ext = path47.extname(filePath).toLowerCase();
|
|
58156
58301
|
const testPatterns = [
|
|
58157
58302
|
".test.",
|
|
58158
58303
|
".spec.",
|
|
@@ -58233,8 +58378,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
58233
58378
|
}
|
|
58234
58379
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
58235
58380
|
}
|
|
58236
|
-
function matchesGlobSegment(
|
|
58237
|
-
const normalizedPath =
|
|
58381
|
+
function matchesGlobSegment(path48, glob) {
|
|
58382
|
+
const normalizedPath = path48.replace(/\\/g, "/");
|
|
58238
58383
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
58239
58384
|
if (normalizedPath.includes("//")) {
|
|
58240
58385
|
return false;
|
|
@@ -58265,8 +58410,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
58265
58410
|
function hasGlobstar(glob) {
|
|
58266
58411
|
return glob.includes("**");
|
|
58267
58412
|
}
|
|
58268
|
-
function globMatches(
|
|
58269
|
-
const normalizedPath =
|
|
58413
|
+
function globMatches(path48, glob) {
|
|
58414
|
+
const normalizedPath = path48.replace(/\\/g, "/");
|
|
58270
58415
|
if (!glob || glob === "") {
|
|
58271
58416
|
if (normalizedPath.includes("//")) {
|
|
58272
58417
|
return false;
|
|
@@ -58302,31 +58447,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
58302
58447
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
58303
58448
|
let testLines = 0;
|
|
58304
58449
|
let codeLines = 0;
|
|
58305
|
-
const srcDir =
|
|
58306
|
-
if (
|
|
58450
|
+
const srcDir = path47.join(workingDir, "src");
|
|
58451
|
+
if (fs35.existsSync(srcDir)) {
|
|
58307
58452
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
58308
58453
|
codeLines += lines;
|
|
58309
58454
|
});
|
|
58310
58455
|
}
|
|
58311
58456
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
58312
58457
|
for (const dir of possibleSrcDirs) {
|
|
58313
|
-
const dirPath =
|
|
58314
|
-
if (
|
|
58458
|
+
const dirPath = path47.join(workingDir, dir);
|
|
58459
|
+
if (fs35.existsSync(dirPath)) {
|
|
58315
58460
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
58316
58461
|
codeLines += lines;
|
|
58317
58462
|
});
|
|
58318
58463
|
}
|
|
58319
58464
|
}
|
|
58320
|
-
const testsDir =
|
|
58321
|
-
if (
|
|
58465
|
+
const testsDir = path47.join(workingDir, "tests");
|
|
58466
|
+
if (fs35.existsSync(testsDir)) {
|
|
58322
58467
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
58323
58468
|
testLines += lines;
|
|
58324
58469
|
});
|
|
58325
58470
|
}
|
|
58326
58471
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
58327
58472
|
for (const dir of possibleTestDirs) {
|
|
58328
|
-
const dirPath =
|
|
58329
|
-
if (
|
|
58473
|
+
const dirPath = path47.join(workingDir, dir);
|
|
58474
|
+
if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
|
|
58330
58475
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
58331
58476
|
testLines += lines;
|
|
58332
58477
|
});
|
|
@@ -58338,9 +58483,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
58338
58483
|
}
|
|
58339
58484
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
58340
58485
|
try {
|
|
58341
|
-
const entries =
|
|
58486
|
+
const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
|
|
58342
58487
|
for (const entry of entries) {
|
|
58343
|
-
const fullPath =
|
|
58488
|
+
const fullPath = path47.join(dirPath, entry.name);
|
|
58344
58489
|
if (entry.isDirectory()) {
|
|
58345
58490
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
58346
58491
|
continue;
|
|
@@ -58348,7 +58493,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
58348
58493
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
58349
58494
|
} else if (entry.isFile()) {
|
|
58350
58495
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
58351
|
-
const ext =
|
|
58496
|
+
const ext = path47.extname(entry.name).toLowerCase();
|
|
58352
58497
|
const validExts = [
|
|
58353
58498
|
".ts",
|
|
58354
58499
|
".tsx",
|
|
@@ -58384,7 +58529,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
58384
58529
|
continue;
|
|
58385
58530
|
}
|
|
58386
58531
|
try {
|
|
58387
|
-
const content =
|
|
58532
|
+
const content = fs35.readFileSync(fullPath, "utf-8");
|
|
58388
58533
|
const lines = countCodeLines(content);
|
|
58389
58534
|
callback(lines);
|
|
58390
58535
|
} catch {}
|
|
@@ -58563,8 +58708,10 @@ async function getGitChurn(days, directory) {
|
|
|
58563
58708
|
stderr: "pipe",
|
|
58564
58709
|
cwd: directory
|
|
58565
58710
|
});
|
|
58566
|
-
const stdout = await
|
|
58567
|
-
|
|
58711
|
+
const [stdout] = await Promise.all([
|
|
58712
|
+
new Response(proc.stdout).text(),
|
|
58713
|
+
proc.exited
|
|
58714
|
+
]);
|
|
58568
58715
|
const lines = stdout.split(/\r?\n/);
|
|
58569
58716
|
for (const line of lines) {
|
|
58570
58717
|
const normalizedPath = line.replace(/\\/g, "/");
|
|
@@ -58583,11 +58730,11 @@ async function getGitChurn(days, directory) {
|
|
|
58583
58730
|
}
|
|
58584
58731
|
function getComplexityForFile2(filePath) {
|
|
58585
58732
|
try {
|
|
58586
|
-
const stat2 =
|
|
58733
|
+
const stat2 = fs36.statSync(filePath);
|
|
58587
58734
|
if (stat2.size > MAX_FILE_SIZE_BYTES3) {
|
|
58588
58735
|
return null;
|
|
58589
58736
|
}
|
|
58590
|
-
const content =
|
|
58737
|
+
const content = fs36.readFileSync(filePath, "utf-8");
|
|
58591
58738
|
return estimateCyclomaticComplexity(content);
|
|
58592
58739
|
} catch {
|
|
58593
58740
|
return null;
|
|
@@ -58598,7 +58745,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
58598
58745
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
58599
58746
|
const filteredChurn = new Map;
|
|
58600
58747
|
for (const [file3, count] of churnMap) {
|
|
58601
|
-
const ext =
|
|
58748
|
+
const ext = path48.extname(file3).toLowerCase();
|
|
58602
58749
|
if (extSet.has(ext)) {
|
|
58603
58750
|
filteredChurn.set(file3, count);
|
|
58604
58751
|
}
|
|
@@ -58608,8 +58755,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
58608
58755
|
let analyzedFiles = 0;
|
|
58609
58756
|
for (const [file3, churnCount] of filteredChurn) {
|
|
58610
58757
|
let fullPath = file3;
|
|
58611
|
-
if (!
|
|
58612
|
-
fullPath =
|
|
58758
|
+
if (!fs36.existsSync(fullPath)) {
|
|
58759
|
+
fullPath = path48.join(cwd, file3);
|
|
58613
58760
|
}
|
|
58614
58761
|
const complexity = getComplexityForFile2(fullPath);
|
|
58615
58762
|
if (complexity !== null) {
|
|
@@ -58817,8 +58964,8 @@ var curator_analyze = createSwarmTool({
|
|
|
58817
58964
|
});
|
|
58818
58965
|
// src/tools/declare-scope.ts
|
|
58819
58966
|
init_tool();
|
|
58820
|
-
import * as
|
|
58821
|
-
import * as
|
|
58967
|
+
import * as fs37 from "fs";
|
|
58968
|
+
import * as path49 from "path";
|
|
58822
58969
|
init_create_tool();
|
|
58823
58970
|
function validateTaskIdFormat(taskId) {
|
|
58824
58971
|
const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
|
|
@@ -58897,8 +59044,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
58897
59044
|
};
|
|
58898
59045
|
}
|
|
58899
59046
|
}
|
|
58900
|
-
normalizedDir =
|
|
58901
|
-
const pathParts = normalizedDir.split(
|
|
59047
|
+
normalizedDir = path49.normalize(args2.working_directory);
|
|
59048
|
+
const pathParts = normalizedDir.split(path49.sep);
|
|
58902
59049
|
if (pathParts.includes("..")) {
|
|
58903
59050
|
return {
|
|
58904
59051
|
success: false,
|
|
@@ -58908,11 +59055,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
58908
59055
|
]
|
|
58909
59056
|
};
|
|
58910
59057
|
}
|
|
58911
|
-
const resolvedDir =
|
|
59058
|
+
const resolvedDir = path49.resolve(normalizedDir);
|
|
58912
59059
|
try {
|
|
58913
|
-
const realPath =
|
|
58914
|
-
const planPath2 =
|
|
58915
|
-
if (!
|
|
59060
|
+
const realPath = fs37.realpathSync(resolvedDir);
|
|
59061
|
+
const planPath2 = path49.join(realPath, ".swarm", "plan.json");
|
|
59062
|
+
if (!fs37.existsSync(planPath2)) {
|
|
58916
59063
|
return {
|
|
58917
59064
|
success: false,
|
|
58918
59065
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -58935,8 +59082,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
58935
59082
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
58936
59083
|
}
|
|
58937
59084
|
const directory = normalizedDir || fallbackDir;
|
|
58938
|
-
const planPath =
|
|
58939
|
-
if (!
|
|
59085
|
+
const planPath = path49.resolve(directory, ".swarm", "plan.json");
|
|
59086
|
+
if (!fs37.existsSync(planPath)) {
|
|
58940
59087
|
return {
|
|
58941
59088
|
success: false,
|
|
58942
59089
|
message: "No plan found",
|
|
@@ -58945,7 +59092,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
58945
59092
|
}
|
|
58946
59093
|
let planContent;
|
|
58947
59094
|
try {
|
|
58948
|
-
planContent = JSON.parse(
|
|
59095
|
+
planContent = JSON.parse(fs37.readFileSync(planPath, "utf-8"));
|
|
58949
59096
|
} catch {
|
|
58950
59097
|
return {
|
|
58951
59098
|
success: false,
|
|
@@ -58977,8 +59124,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
58977
59124
|
const normalizeErrors = [];
|
|
58978
59125
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
58979
59126
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
58980
|
-
if (
|
|
58981
|
-
const relativePath =
|
|
59127
|
+
if (path49.isAbsolute(file3)) {
|
|
59128
|
+
const relativePath = path49.relative(dir, file3).replace(/\\/g, "/");
|
|
58982
59129
|
if (relativePath.startsWith("..")) {
|
|
58983
59130
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
58984
59131
|
return file3;
|
|
@@ -59304,20 +59451,20 @@ function validateBase(base) {
|
|
|
59304
59451
|
function validatePaths(paths) {
|
|
59305
59452
|
if (!paths)
|
|
59306
59453
|
return null;
|
|
59307
|
-
for (const
|
|
59308
|
-
if (!
|
|
59454
|
+
for (const path51 of paths) {
|
|
59455
|
+
if (!path51 || path51.length === 0) {
|
|
59309
59456
|
return "empty path not allowed";
|
|
59310
59457
|
}
|
|
59311
|
-
if (
|
|
59458
|
+
if (path51.length > MAX_PATH_LENGTH) {
|
|
59312
59459
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
59313
59460
|
}
|
|
59314
|
-
if (SHELL_METACHARACTERS2.test(
|
|
59461
|
+
if (SHELL_METACHARACTERS2.test(path51)) {
|
|
59315
59462
|
return "path contains shell metacharacters";
|
|
59316
59463
|
}
|
|
59317
|
-
if (
|
|
59464
|
+
if (path51.startsWith("-")) {
|
|
59318
59465
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
59319
59466
|
}
|
|
59320
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
59467
|
+
if (CONTROL_CHAR_PATTERN2.test(path51)) {
|
|
59321
59468
|
return "path contains control characters";
|
|
59322
59469
|
}
|
|
59323
59470
|
}
|
|
@@ -59398,8 +59545,8 @@ var diff = createSwarmTool({
|
|
|
59398
59545
|
if (parts2.length >= 3) {
|
|
59399
59546
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
59400
59547
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
59401
|
-
const
|
|
59402
|
-
files.push({ path:
|
|
59548
|
+
const path51 = parts2[2];
|
|
59549
|
+
files.push({ path: path51, additions, deletions });
|
|
59403
59550
|
}
|
|
59404
59551
|
}
|
|
59405
59552
|
const contractChanges = [];
|
|
@@ -59681,8 +59828,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
59681
59828
|
// src/tools/evidence-check.ts
|
|
59682
59829
|
init_dist();
|
|
59683
59830
|
init_create_tool();
|
|
59684
|
-
import * as
|
|
59685
|
-
import * as
|
|
59831
|
+
import * as fs38 from "fs";
|
|
59832
|
+
import * as path51 from "path";
|
|
59686
59833
|
var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
|
|
59687
59834
|
var MAX_EVIDENCE_FILES = 1000;
|
|
59688
59835
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
@@ -59709,9 +59856,9 @@ function validateRequiredTypes(input) {
|
|
|
59709
59856
|
return null;
|
|
59710
59857
|
}
|
|
59711
59858
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
59712
|
-
const normalizedCwd =
|
|
59713
|
-
const swarmPath =
|
|
59714
|
-
const normalizedPath =
|
|
59859
|
+
const normalizedCwd = path51.resolve(cwd);
|
|
59860
|
+
const swarmPath = path51.join(normalizedCwd, ".swarm");
|
|
59861
|
+
const normalizedPath = path51.resolve(filePath);
|
|
59715
59862
|
return normalizedPath.startsWith(swarmPath);
|
|
59716
59863
|
}
|
|
59717
59864
|
function parseCompletedTasks(planContent) {
|
|
@@ -59727,12 +59874,12 @@ function parseCompletedTasks(planContent) {
|
|
|
59727
59874
|
}
|
|
59728
59875
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
59729
59876
|
const evidence = [];
|
|
59730
|
-
if (!
|
|
59877
|
+
if (!fs38.existsSync(evidenceDir) || !fs38.statSync(evidenceDir).isDirectory()) {
|
|
59731
59878
|
return evidence;
|
|
59732
59879
|
}
|
|
59733
59880
|
let files;
|
|
59734
59881
|
try {
|
|
59735
|
-
files =
|
|
59882
|
+
files = fs38.readdirSync(evidenceDir);
|
|
59736
59883
|
} catch {
|
|
59737
59884
|
return evidence;
|
|
59738
59885
|
}
|
|
@@ -59741,14 +59888,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
59741
59888
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
59742
59889
|
continue;
|
|
59743
59890
|
}
|
|
59744
|
-
const filePath =
|
|
59891
|
+
const filePath = path51.join(evidenceDir, filename);
|
|
59745
59892
|
try {
|
|
59746
|
-
const resolvedPath =
|
|
59747
|
-
const evidenceDirResolved =
|
|
59893
|
+
const resolvedPath = path51.resolve(filePath);
|
|
59894
|
+
const evidenceDirResolved = path51.resolve(evidenceDir);
|
|
59748
59895
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
59749
59896
|
continue;
|
|
59750
59897
|
}
|
|
59751
|
-
const stat2 =
|
|
59898
|
+
const stat2 = fs38.lstatSync(filePath);
|
|
59752
59899
|
if (!stat2.isFile()) {
|
|
59753
59900
|
continue;
|
|
59754
59901
|
}
|
|
@@ -59757,7 +59904,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
59757
59904
|
}
|
|
59758
59905
|
let fileStat;
|
|
59759
59906
|
try {
|
|
59760
|
-
fileStat =
|
|
59907
|
+
fileStat = fs38.statSync(filePath);
|
|
59761
59908
|
if (fileStat.size > MAX_FILE_SIZE_BYTES4) {
|
|
59762
59909
|
continue;
|
|
59763
59910
|
}
|
|
@@ -59766,7 +59913,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
59766
59913
|
}
|
|
59767
59914
|
let content;
|
|
59768
59915
|
try {
|
|
59769
|
-
content =
|
|
59916
|
+
content = fs38.readFileSync(filePath, "utf-8");
|
|
59770
59917
|
} catch {
|
|
59771
59918
|
continue;
|
|
59772
59919
|
}
|
|
@@ -59862,7 +60009,7 @@ var evidence_check = createSwarmTool({
|
|
|
59862
60009
|
return JSON.stringify(errorResult, null, 2);
|
|
59863
60010
|
}
|
|
59864
60011
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
59865
|
-
const planPath =
|
|
60012
|
+
const planPath = path51.join(cwd, PLAN_FILE);
|
|
59866
60013
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
59867
60014
|
const errorResult = {
|
|
59868
60015
|
error: "plan file path validation failed",
|
|
@@ -59876,7 +60023,7 @@ var evidence_check = createSwarmTool({
|
|
|
59876
60023
|
}
|
|
59877
60024
|
let planContent;
|
|
59878
60025
|
try {
|
|
59879
|
-
planContent =
|
|
60026
|
+
planContent = fs38.readFileSync(planPath, "utf-8");
|
|
59880
60027
|
} catch {
|
|
59881
60028
|
const result2 = {
|
|
59882
60029
|
message: "No completed tasks found in plan.",
|
|
@@ -59894,7 +60041,7 @@ var evidence_check = createSwarmTool({
|
|
|
59894
60041
|
};
|
|
59895
60042
|
return JSON.stringify(result2, null, 2);
|
|
59896
60043
|
}
|
|
59897
|
-
const evidenceDir =
|
|
60044
|
+
const evidenceDir = path51.join(cwd, EVIDENCE_DIR2);
|
|
59898
60045
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
59899
60046
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
59900
60047
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -59911,8 +60058,8 @@ var evidence_check = createSwarmTool({
|
|
|
59911
60058
|
// src/tools/file-extractor.ts
|
|
59912
60059
|
init_tool();
|
|
59913
60060
|
init_create_tool();
|
|
59914
|
-
import * as
|
|
59915
|
-
import * as
|
|
60061
|
+
import * as fs39 from "fs";
|
|
60062
|
+
import * as path52 from "path";
|
|
59916
60063
|
var EXT_MAP = {
|
|
59917
60064
|
python: ".py",
|
|
59918
60065
|
py: ".py",
|
|
@@ -59974,8 +60121,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
59974
60121
|
execute: async (args2, directory) => {
|
|
59975
60122
|
const { content, output_dir, prefix } = args2;
|
|
59976
60123
|
const targetDir = output_dir || directory;
|
|
59977
|
-
if (!
|
|
59978
|
-
|
|
60124
|
+
if (!fs39.existsSync(targetDir)) {
|
|
60125
|
+
fs39.mkdirSync(targetDir, { recursive: true });
|
|
59979
60126
|
}
|
|
59980
60127
|
if (!content) {
|
|
59981
60128
|
return "Error: content is required";
|
|
@@ -59993,16 +60140,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
59993
60140
|
if (prefix) {
|
|
59994
60141
|
filename = `${prefix}_${filename}`;
|
|
59995
60142
|
}
|
|
59996
|
-
let filepath =
|
|
59997
|
-
const base =
|
|
59998
|
-
const ext =
|
|
60143
|
+
let filepath = path52.join(targetDir, filename);
|
|
60144
|
+
const base = path52.basename(filepath, path52.extname(filepath));
|
|
60145
|
+
const ext = path52.extname(filepath);
|
|
59999
60146
|
let counter = 1;
|
|
60000
|
-
while (
|
|
60001
|
-
filepath =
|
|
60147
|
+
while (fs39.existsSync(filepath)) {
|
|
60148
|
+
filepath = path52.join(targetDir, `${base}_${counter}${ext}`);
|
|
60002
60149
|
counter++;
|
|
60003
60150
|
}
|
|
60004
60151
|
try {
|
|
60005
|
-
|
|
60152
|
+
fs39.writeFileSync(filepath, code.trim(), "utf-8");
|
|
60006
60153
|
savedFiles.push(filepath);
|
|
60007
60154
|
} catch (error93) {
|
|
60008
60155
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -60032,7 +60179,7 @@ init_create_tool();
|
|
|
60032
60179
|
var GITINGEST_TIMEOUT_MS = 1e4;
|
|
60033
60180
|
var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
|
|
60034
60181
|
var GITINGEST_MAX_RETRIES = 2;
|
|
60035
|
-
var delay = (ms) => new Promise((
|
|
60182
|
+
var delay = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
60036
60183
|
async function fetchGitingest(args2) {
|
|
60037
60184
|
for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
|
|
60038
60185
|
try {
|
|
@@ -60118,8 +60265,8 @@ var gitingest = createSwarmTool({
|
|
|
60118
60265
|
// src/tools/imports.ts
|
|
60119
60266
|
init_dist();
|
|
60120
60267
|
init_create_tool();
|
|
60121
|
-
import * as
|
|
60122
|
-
import * as
|
|
60268
|
+
import * as fs40 from "fs";
|
|
60269
|
+
import * as path53 from "path";
|
|
60123
60270
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
60124
60271
|
var MAX_SYMBOL_LENGTH = 256;
|
|
60125
60272
|
var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
|
|
@@ -60167,7 +60314,7 @@ function validateSymbolInput(symbol3) {
|
|
|
60167
60314
|
return null;
|
|
60168
60315
|
}
|
|
60169
60316
|
function isBinaryFile2(filePath, buffer) {
|
|
60170
|
-
const ext =
|
|
60317
|
+
const ext = path53.extname(filePath).toLowerCase();
|
|
60171
60318
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
60172
60319
|
return false;
|
|
60173
60320
|
}
|
|
@@ -60191,15 +60338,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
60191
60338
|
const imports = [];
|
|
60192
60339
|
let _resolvedTarget;
|
|
60193
60340
|
try {
|
|
60194
|
-
_resolvedTarget =
|
|
60341
|
+
_resolvedTarget = path53.resolve(targetFile);
|
|
60195
60342
|
} catch {
|
|
60196
60343
|
_resolvedTarget = targetFile;
|
|
60197
60344
|
}
|
|
60198
|
-
const targetBasename =
|
|
60345
|
+
const targetBasename = path53.basename(targetFile, path53.extname(targetFile));
|
|
60199
60346
|
const targetWithExt = targetFile;
|
|
60200
60347
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
60201
|
-
const normalizedTargetWithExt =
|
|
60202
|
-
const normalizedTargetWithoutExt =
|
|
60348
|
+
const normalizedTargetWithExt = path53.normalize(targetWithExt).replace(/\\/g, "/");
|
|
60349
|
+
const normalizedTargetWithoutExt = path53.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
60203
60350
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
60204
60351
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
60205
60352
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -60222,9 +60369,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
60222
60369
|
}
|
|
60223
60370
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
60224
60371
|
let isMatch = false;
|
|
60225
|
-
const _targetDir =
|
|
60226
|
-
const targetExt =
|
|
60227
|
-
const targetBasenameNoExt =
|
|
60372
|
+
const _targetDir = path53.dirname(targetFile);
|
|
60373
|
+
const targetExt = path53.extname(targetFile);
|
|
60374
|
+
const targetBasenameNoExt = path53.basename(targetFile, targetExt);
|
|
60228
60375
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
60229
60376
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
60230
60377
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -60281,7 +60428,7 @@ var SKIP_DIRECTORIES3 = new Set([
|
|
|
60281
60428
|
function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
60282
60429
|
let entries;
|
|
60283
60430
|
try {
|
|
60284
|
-
entries =
|
|
60431
|
+
entries = fs40.readdirSync(dir);
|
|
60285
60432
|
} catch (e) {
|
|
60286
60433
|
stats.fileErrors.push({
|
|
60287
60434
|
path: dir,
|
|
@@ -60292,13 +60439,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
60292
60439
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
60293
60440
|
for (const entry of entries) {
|
|
60294
60441
|
if (SKIP_DIRECTORIES3.has(entry)) {
|
|
60295
|
-
stats.skippedDirs.push(
|
|
60442
|
+
stats.skippedDirs.push(path53.join(dir, entry));
|
|
60296
60443
|
continue;
|
|
60297
60444
|
}
|
|
60298
|
-
const fullPath =
|
|
60445
|
+
const fullPath = path53.join(dir, entry);
|
|
60299
60446
|
let stat2;
|
|
60300
60447
|
try {
|
|
60301
|
-
stat2 =
|
|
60448
|
+
stat2 = fs40.statSync(fullPath);
|
|
60302
60449
|
} catch (e) {
|
|
60303
60450
|
stats.fileErrors.push({
|
|
60304
60451
|
path: fullPath,
|
|
@@ -60309,7 +60456,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
|
|
|
60309
60456
|
if (stat2.isDirectory()) {
|
|
60310
60457
|
findSourceFiles(fullPath, files, stats);
|
|
60311
60458
|
} else if (stat2.isFile()) {
|
|
60312
|
-
const ext =
|
|
60459
|
+
const ext = path53.extname(fullPath).toLowerCase();
|
|
60313
60460
|
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
60314
60461
|
files.push(fullPath);
|
|
60315
60462
|
}
|
|
@@ -60366,8 +60513,8 @@ var imports = createSwarmTool({
|
|
|
60366
60513
|
return JSON.stringify(errorResult, null, 2);
|
|
60367
60514
|
}
|
|
60368
60515
|
try {
|
|
60369
|
-
const targetFile =
|
|
60370
|
-
if (!
|
|
60516
|
+
const targetFile = path53.resolve(file3);
|
|
60517
|
+
if (!fs40.existsSync(targetFile)) {
|
|
60371
60518
|
const errorResult = {
|
|
60372
60519
|
error: `target file not found: ${file3}`,
|
|
60373
60520
|
target: file3,
|
|
@@ -60377,7 +60524,7 @@ var imports = createSwarmTool({
|
|
|
60377
60524
|
};
|
|
60378
60525
|
return JSON.stringify(errorResult, null, 2);
|
|
60379
60526
|
}
|
|
60380
|
-
const targetStat =
|
|
60527
|
+
const targetStat = fs40.statSync(targetFile);
|
|
60381
60528
|
if (!targetStat.isFile()) {
|
|
60382
60529
|
const errorResult = {
|
|
60383
60530
|
error: "target must be a file, not a directory",
|
|
@@ -60388,7 +60535,7 @@ var imports = createSwarmTool({
|
|
|
60388
60535
|
};
|
|
60389
60536
|
return JSON.stringify(errorResult, null, 2);
|
|
60390
60537
|
}
|
|
60391
|
-
const baseDir =
|
|
60538
|
+
const baseDir = path53.dirname(targetFile);
|
|
60392
60539
|
const scanStats = {
|
|
60393
60540
|
skippedDirs: [],
|
|
60394
60541
|
skippedFiles: 0,
|
|
@@ -60403,12 +60550,12 @@ var imports = createSwarmTool({
|
|
|
60403
60550
|
if (consumers.length >= MAX_CONSUMERS)
|
|
60404
60551
|
break;
|
|
60405
60552
|
try {
|
|
60406
|
-
const stat2 =
|
|
60553
|
+
const stat2 = fs40.statSync(filePath);
|
|
60407
60554
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
60408
60555
|
skippedFileCount++;
|
|
60409
60556
|
continue;
|
|
60410
60557
|
}
|
|
60411
|
-
const buffer =
|
|
60558
|
+
const buffer = fs40.readFileSync(filePath);
|
|
60412
60559
|
if (isBinaryFile2(filePath, buffer)) {
|
|
60413
60560
|
skippedFileCount++;
|
|
60414
60561
|
continue;
|
|
@@ -60997,11 +61144,12 @@ init_dist();
|
|
|
60997
61144
|
init_config();
|
|
60998
61145
|
init_schema();
|
|
60999
61146
|
init_manager();
|
|
61000
|
-
import * as
|
|
61001
|
-
import * as
|
|
61147
|
+
import * as fs41 from "fs";
|
|
61148
|
+
import * as path54 from "path";
|
|
61002
61149
|
init_utils2();
|
|
61003
61150
|
init_telemetry();
|
|
61004
61151
|
init_create_tool();
|
|
61152
|
+
init_resolve_working_directory();
|
|
61005
61153
|
function safeWarn(message, error93) {
|
|
61006
61154
|
try {
|
|
61007
61155
|
console.warn(message, error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -61218,11 +61366,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61218
61366
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
61219
61367
|
}
|
|
61220
61368
|
try {
|
|
61221
|
-
const driftEvidencePath =
|
|
61369
|
+
const driftEvidencePath = path54.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
61222
61370
|
let driftVerdictFound = false;
|
|
61223
61371
|
let driftVerdictApproved = false;
|
|
61224
61372
|
try {
|
|
61225
|
-
const driftEvidenceContent =
|
|
61373
|
+
const driftEvidenceContent = fs41.readFileSync(driftEvidencePath, "utf-8");
|
|
61226
61374
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
61227
61375
|
const entries = driftEvidence.entries ?? [];
|
|
61228
61376
|
for (const entry of entries) {
|
|
@@ -61252,14 +61400,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61252
61400
|
driftVerdictFound = false;
|
|
61253
61401
|
}
|
|
61254
61402
|
if (!driftVerdictFound) {
|
|
61255
|
-
const specPath =
|
|
61256
|
-
const specExists =
|
|
61403
|
+
const specPath = path54.join(dir, ".swarm", "spec.md");
|
|
61404
|
+
const specExists = fs41.existsSync(specPath);
|
|
61257
61405
|
if (!specExists) {
|
|
61258
61406
|
let incompleteTaskCount = 0;
|
|
61259
61407
|
let planPhaseFound = false;
|
|
61260
61408
|
try {
|
|
61261
61409
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
61262
|
-
const planRaw =
|
|
61410
|
+
const planRaw = fs41.readFileSync(planPath, "utf-8");
|
|
61263
61411
|
const plan = JSON.parse(planRaw);
|
|
61264
61412
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
61265
61413
|
if (targetPhase) {
|
|
@@ -61326,7 +61474,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61326
61474
|
};
|
|
61327
61475
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
61328
61476
|
try {
|
|
61329
|
-
const projectName =
|
|
61477
|
+
const projectName = path54.basename(dir);
|
|
61330
61478
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
61331
61479
|
if (curationResult) {
|
|
61332
61480
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -61371,7 +61519,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61371
61519
|
let phaseRequiredAgents;
|
|
61372
61520
|
try {
|
|
61373
61521
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
61374
|
-
const planRaw =
|
|
61522
|
+
const planRaw = fs41.readFileSync(planPath, "utf-8");
|
|
61375
61523
|
const plan = JSON.parse(planRaw);
|
|
61376
61524
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
61377
61525
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -61386,7 +61534,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61386
61534
|
if (agentsMissing.length > 0) {
|
|
61387
61535
|
try {
|
|
61388
61536
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
61389
|
-
const planRaw =
|
|
61537
|
+
const planRaw = fs41.readFileSync(planPath, "utf-8");
|
|
61390
61538
|
const plan = JSON.parse(planRaw);
|
|
61391
61539
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
61392
61540
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -61417,7 +61565,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61417
61565
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
61418
61566
|
try {
|
|
61419
61567
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
61420
|
-
const planRaw =
|
|
61568
|
+
const planRaw = fs41.readFileSync(planPath, "utf-8");
|
|
61421
61569
|
const plan = JSON.parse(planRaw);
|
|
61422
61570
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
61423
61571
|
if (targetPhase) {
|
|
@@ -61455,7 +61603,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61455
61603
|
};
|
|
61456
61604
|
try {
|
|
61457
61605
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
61458
|
-
|
|
61606
|
+
fs41.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
61459
61607
|
`, "utf-8");
|
|
61460
61608
|
} catch (writeError) {
|
|
61461
61609
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -61479,12 +61627,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61479
61627
|
}
|
|
61480
61628
|
try {
|
|
61481
61629
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
61482
|
-
const planJson =
|
|
61630
|
+
const planJson = fs41.readFileSync(planPath, "utf-8");
|
|
61483
61631
|
const plan = JSON.parse(planJson);
|
|
61484
61632
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
61485
61633
|
if (phaseObj) {
|
|
61486
61634
|
phaseObj.status = "completed";
|
|
61487
|
-
|
|
61635
|
+
fs41.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
|
|
61488
61636
|
`, "utf-8");
|
|
61489
61637
|
}
|
|
61490
61638
|
} catch (error93) {
|
|
@@ -61509,18 +61657,21 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
61509
61657
|
var phase_complete = createSwarmTool({
|
|
61510
61658
|
description: "Mark a phase as complete and track which agents were dispatched. Used for phase completion gating and tracking. Accepts phase number and optional summary. Returns list of agents that were dispatched.",
|
|
61511
61659
|
args: {
|
|
61512
|
-
phase: tool.schema.number().describe("The phase number being completed (e.g., 1, 2, 3)"),
|
|
61660
|
+
phase: tool.schema.number().int().min(1).describe("The phase number being completed \u2014 a positive integer (e.g., 1, 2, 3)"),
|
|
61513
61661
|
summary: tool.schema.string().optional().describe("Optional summary of what was accomplished in this phase"),
|
|
61514
|
-
sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
|
|
61662
|
+
sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
|
|
61663
|
+
working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
|
|
61515
61664
|
},
|
|
61516
61665
|
execute: async (args2, directory, ctx) => {
|
|
61517
61666
|
let phaseCompleteArgs;
|
|
61667
|
+
let workingDirInput;
|
|
61518
61668
|
try {
|
|
61519
61669
|
phaseCompleteArgs = {
|
|
61520
61670
|
phase: Number(args2.phase),
|
|
61521
61671
|
summary: args2.summary !== undefined ? String(args2.summary) : undefined,
|
|
61522
61672
|
sessionID: ctx?.sessionID ?? (args2.sessionID !== undefined ? String(args2.sessionID) : undefined)
|
|
61523
61673
|
};
|
|
61674
|
+
workingDirInput = args2.working_directory !== undefined ? String(args2.working_directory) : undefined;
|
|
61524
61675
|
} catch {
|
|
61525
61676
|
return JSON.stringify({
|
|
61526
61677
|
success: false,
|
|
@@ -61530,7 +61681,17 @@ var phase_complete = createSwarmTool({
|
|
|
61530
61681
|
warnings: ["Failed to parse arguments"]
|
|
61531
61682
|
}, null, 2);
|
|
61532
61683
|
}
|
|
61533
|
-
|
|
61684
|
+
const dirResult = resolveWorkingDirectory(workingDirInput, directory);
|
|
61685
|
+
if (!dirResult.success) {
|
|
61686
|
+
return JSON.stringify({
|
|
61687
|
+
success: false,
|
|
61688
|
+
phase: phaseCompleteArgs.phase,
|
|
61689
|
+
message: dirResult.message,
|
|
61690
|
+
agentsDispatched: [],
|
|
61691
|
+
warnings: [dirResult.message]
|
|
61692
|
+
}, null, 2);
|
|
61693
|
+
}
|
|
61694
|
+
return executePhaseComplete(phaseCompleteArgs, dirResult.directory, dirResult.directory);
|
|
61534
61695
|
}
|
|
61535
61696
|
});
|
|
61536
61697
|
// src/tools/pkg-audit.ts
|
|
@@ -61538,8 +61699,8 @@ init_dist();
|
|
|
61538
61699
|
init_discovery();
|
|
61539
61700
|
init_utils();
|
|
61540
61701
|
init_create_tool();
|
|
61541
|
-
import * as
|
|
61542
|
-
import * as
|
|
61702
|
+
import * as fs42 from "fs";
|
|
61703
|
+
import * as path55 from "path";
|
|
61543
61704
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
61544
61705
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
61545
61706
|
function isValidEcosystem(value) {
|
|
@@ -61557,28 +61718,28 @@ function validateArgs3(args2) {
|
|
|
61557
61718
|
function detectEcosystems(directory) {
|
|
61558
61719
|
const ecosystems = [];
|
|
61559
61720
|
const cwd = directory;
|
|
61560
|
-
if (
|
|
61721
|
+
if (fs42.existsSync(path55.join(cwd, "package.json"))) {
|
|
61561
61722
|
ecosystems.push("npm");
|
|
61562
61723
|
}
|
|
61563
|
-
if (
|
|
61724
|
+
if (fs42.existsSync(path55.join(cwd, "pyproject.toml")) || fs42.existsSync(path55.join(cwd, "requirements.txt"))) {
|
|
61564
61725
|
ecosystems.push("pip");
|
|
61565
61726
|
}
|
|
61566
|
-
if (
|
|
61727
|
+
if (fs42.existsSync(path55.join(cwd, "Cargo.toml"))) {
|
|
61567
61728
|
ecosystems.push("cargo");
|
|
61568
61729
|
}
|
|
61569
|
-
if (
|
|
61730
|
+
if (fs42.existsSync(path55.join(cwd, "go.mod"))) {
|
|
61570
61731
|
ecosystems.push("go");
|
|
61571
61732
|
}
|
|
61572
61733
|
try {
|
|
61573
|
-
const files =
|
|
61734
|
+
const files = fs42.readdirSync(cwd);
|
|
61574
61735
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
61575
61736
|
ecosystems.push("dotnet");
|
|
61576
61737
|
}
|
|
61577
61738
|
} catch {}
|
|
61578
|
-
if (
|
|
61739
|
+
if (fs42.existsSync(path55.join(cwd, "Gemfile")) || fs42.existsSync(path55.join(cwd, "Gemfile.lock"))) {
|
|
61579
61740
|
ecosystems.push("ruby");
|
|
61580
61741
|
}
|
|
61581
|
-
if (
|
|
61742
|
+
if (fs42.existsSync(path55.join(cwd, "pubspec.yaml"))) {
|
|
61582
61743
|
ecosystems.push("dart");
|
|
61583
61744
|
}
|
|
61584
61745
|
return ecosystems;
|
|
@@ -61591,7 +61752,7 @@ async function runNpmAudit(directory) {
|
|
|
61591
61752
|
stderr: "pipe",
|
|
61592
61753
|
cwd: directory
|
|
61593
61754
|
});
|
|
61594
|
-
const timeoutPromise = new Promise((
|
|
61755
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
61595
61756
|
const result = await Promise.race([
|
|
61596
61757
|
Promise.all([
|
|
61597
61758
|
new Response(proc.stdout).text(),
|
|
@@ -61714,7 +61875,7 @@ async function runPipAudit(directory) {
|
|
|
61714
61875
|
stderr: "pipe",
|
|
61715
61876
|
cwd: directory
|
|
61716
61877
|
});
|
|
61717
|
-
const timeoutPromise = new Promise((
|
|
61878
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
61718
61879
|
const result = await Promise.race([
|
|
61719
61880
|
Promise.all([
|
|
61720
61881
|
new Response(proc.stdout).text(),
|
|
@@ -61845,7 +62006,7 @@ async function runCargoAudit(directory) {
|
|
|
61845
62006
|
stderr: "pipe",
|
|
61846
62007
|
cwd: directory
|
|
61847
62008
|
});
|
|
61848
|
-
const timeoutPromise = new Promise((
|
|
62009
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
61849
62010
|
const result = await Promise.race([
|
|
61850
62011
|
Promise.all([
|
|
61851
62012
|
new Response(proc.stdout).text(),
|
|
@@ -61972,7 +62133,7 @@ async function runGoAudit(directory) {
|
|
|
61972
62133
|
stderr: "pipe",
|
|
61973
62134
|
cwd: directory
|
|
61974
62135
|
});
|
|
61975
|
-
const timeoutPromise = new Promise((
|
|
62136
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
61976
62137
|
const result = await Promise.race([
|
|
61977
62138
|
Promise.all([
|
|
61978
62139
|
new Response(proc.stdout).text(),
|
|
@@ -62108,7 +62269,7 @@ async function runDotnetAudit(directory) {
|
|
|
62108
62269
|
stderr: "pipe",
|
|
62109
62270
|
cwd: directory
|
|
62110
62271
|
});
|
|
62111
|
-
const timeoutPromise = new Promise((
|
|
62272
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
62112
62273
|
const result = await Promise.race([
|
|
62113
62274
|
Promise.all([
|
|
62114
62275
|
new Response(proc.stdout).text(),
|
|
@@ -62227,7 +62388,7 @@ async function runBundleAudit(directory) {
|
|
|
62227
62388
|
stderr: "pipe",
|
|
62228
62389
|
cwd: directory
|
|
62229
62390
|
});
|
|
62230
|
-
const timeoutPromise = new Promise((
|
|
62391
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
62231
62392
|
const result = await Promise.race([
|
|
62232
62393
|
Promise.all([
|
|
62233
62394
|
new Response(proc.stdout).text(),
|
|
@@ -62374,7 +62535,7 @@ async function runDartAudit(directory) {
|
|
|
62374
62535
|
stderr: "pipe",
|
|
62375
62536
|
cwd: directory
|
|
62376
62537
|
});
|
|
62377
|
-
const timeoutPromise = new Promise((
|
|
62538
|
+
const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
|
|
62378
62539
|
const result = await Promise.race([
|
|
62379
62540
|
Promise.all([
|
|
62380
62541
|
new Response(proc.stdout).text(),
|
|
@@ -62599,8 +62760,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
62599
62760
|
]);
|
|
62600
62761
|
// src/tools/pre-check-batch.ts
|
|
62601
62762
|
init_dist();
|
|
62602
|
-
import * as
|
|
62603
|
-
import * as
|
|
62763
|
+
import * as fs44 from "fs";
|
|
62764
|
+
import * as path57 from "path";
|
|
62604
62765
|
|
|
62605
62766
|
// node_modules/yocto-queue/index.js
|
|
62606
62767
|
class Node2 {
|
|
@@ -62691,26 +62852,26 @@ function pLimit(concurrency) {
|
|
|
62691
62852
|
activeCount--;
|
|
62692
62853
|
resumeNext();
|
|
62693
62854
|
};
|
|
62694
|
-
const run2 = async (function_,
|
|
62855
|
+
const run2 = async (function_, resolve19, arguments_2) => {
|
|
62695
62856
|
const result = (async () => function_(...arguments_2))();
|
|
62696
|
-
|
|
62857
|
+
resolve19(result);
|
|
62697
62858
|
try {
|
|
62698
62859
|
await result;
|
|
62699
62860
|
} catch {}
|
|
62700
62861
|
next();
|
|
62701
62862
|
};
|
|
62702
|
-
const enqueue = (function_,
|
|
62863
|
+
const enqueue = (function_, resolve19, reject, arguments_2) => {
|
|
62703
62864
|
const queueItem = { reject };
|
|
62704
62865
|
new Promise((internalResolve) => {
|
|
62705
62866
|
queueItem.run = internalResolve;
|
|
62706
62867
|
queue.enqueue(queueItem);
|
|
62707
|
-
}).then(run2.bind(undefined, function_,
|
|
62868
|
+
}).then(run2.bind(undefined, function_, resolve19, arguments_2));
|
|
62708
62869
|
if (activeCount < concurrency) {
|
|
62709
62870
|
resumeNext();
|
|
62710
62871
|
}
|
|
62711
62872
|
};
|
|
62712
|
-
const generator = (function_, ...arguments_2) => new Promise((
|
|
62713
|
-
enqueue(function_,
|
|
62873
|
+
const generator = (function_, ...arguments_2) => new Promise((resolve19, reject) => {
|
|
62874
|
+
enqueue(function_, resolve19, reject, arguments_2);
|
|
62714
62875
|
});
|
|
62715
62876
|
Object.defineProperties(generator, {
|
|
62716
62877
|
activeCount: {
|
|
@@ -62874,8 +63035,8 @@ async function qualityBudget(input, directory) {
|
|
|
62874
63035
|
init_dist();
|
|
62875
63036
|
init_manager();
|
|
62876
63037
|
init_detector();
|
|
62877
|
-
import * as
|
|
62878
|
-
import * as
|
|
63038
|
+
import * as fs43 from "fs";
|
|
63039
|
+
import * as path56 from "path";
|
|
62879
63040
|
import { extname as extname10 } from "path";
|
|
62880
63041
|
|
|
62881
63042
|
// src/sast/rules/c.ts
|
|
@@ -63626,7 +63787,7 @@ function mapSemgrepSeverity(severity) {
|
|
|
63626
63787
|
}
|
|
63627
63788
|
}
|
|
63628
63789
|
async function executeWithTimeout(command, args2, options) {
|
|
63629
|
-
return new Promise((
|
|
63790
|
+
return new Promise((resolve19) => {
|
|
63630
63791
|
const child = spawn2(command, args2, {
|
|
63631
63792
|
shell: false,
|
|
63632
63793
|
cwd: options.cwd
|
|
@@ -63635,7 +63796,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
63635
63796
|
let stderr = "";
|
|
63636
63797
|
const timeout = setTimeout(() => {
|
|
63637
63798
|
child.kill("SIGTERM");
|
|
63638
|
-
|
|
63799
|
+
resolve19({
|
|
63639
63800
|
stdout,
|
|
63640
63801
|
stderr: "Process timed out",
|
|
63641
63802
|
exitCode: 124
|
|
@@ -63649,7 +63810,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
63649
63810
|
});
|
|
63650
63811
|
child.on("close", (code) => {
|
|
63651
63812
|
clearTimeout(timeout);
|
|
63652
|
-
|
|
63813
|
+
resolve19({
|
|
63653
63814
|
stdout,
|
|
63654
63815
|
stderr,
|
|
63655
63816
|
exitCode: code ?? 0
|
|
@@ -63657,7 +63818,7 @@ async function executeWithTimeout(command, args2, options) {
|
|
|
63657
63818
|
});
|
|
63658
63819
|
child.on("error", (err2) => {
|
|
63659
63820
|
clearTimeout(timeout);
|
|
63660
|
-
|
|
63821
|
+
resolve19({
|
|
63661
63822
|
stdout,
|
|
63662
63823
|
stderr: err2.message,
|
|
63663
63824
|
exitCode: 1
|
|
@@ -63745,17 +63906,17 @@ var SEVERITY_ORDER = {
|
|
|
63745
63906
|
};
|
|
63746
63907
|
function shouldSkipFile(filePath) {
|
|
63747
63908
|
try {
|
|
63748
|
-
const stats =
|
|
63909
|
+
const stats = fs43.statSync(filePath);
|
|
63749
63910
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
63750
63911
|
return { skip: true, reason: "file too large" };
|
|
63751
63912
|
}
|
|
63752
63913
|
if (stats.size === 0) {
|
|
63753
63914
|
return { skip: true, reason: "empty file" };
|
|
63754
63915
|
}
|
|
63755
|
-
const fd =
|
|
63916
|
+
const fd = fs43.openSync(filePath, "r");
|
|
63756
63917
|
const buffer = Buffer.alloc(8192);
|
|
63757
|
-
const bytesRead =
|
|
63758
|
-
|
|
63918
|
+
const bytesRead = fs43.readSync(fd, buffer, 0, 8192, 0);
|
|
63919
|
+
fs43.closeSync(fd);
|
|
63759
63920
|
if (bytesRead > 0) {
|
|
63760
63921
|
let nullCount = 0;
|
|
63761
63922
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -63794,7 +63955,7 @@ function countBySeverity(findings) {
|
|
|
63794
63955
|
}
|
|
63795
63956
|
function scanFileWithTierA(filePath, language) {
|
|
63796
63957
|
try {
|
|
63797
|
-
const content =
|
|
63958
|
+
const content = fs43.readFileSync(filePath, "utf-8");
|
|
63798
63959
|
const findings = executeRulesSync(filePath, content, language);
|
|
63799
63960
|
return findings.map((f) => ({
|
|
63800
63961
|
rule_id: f.rule_id,
|
|
@@ -63841,8 +64002,8 @@ async function sastScan(input, directory, config3) {
|
|
|
63841
64002
|
_filesSkipped++;
|
|
63842
64003
|
continue;
|
|
63843
64004
|
}
|
|
63844
|
-
const resolvedPath =
|
|
63845
|
-
if (!
|
|
64005
|
+
const resolvedPath = path56.isAbsolute(filePath) ? filePath : path56.resolve(directory, filePath);
|
|
64006
|
+
if (!fs43.existsSync(resolvedPath)) {
|
|
63846
64007
|
_filesSkipped++;
|
|
63847
64008
|
continue;
|
|
63848
64009
|
}
|
|
@@ -64040,20 +64201,20 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
64040
64201
|
let resolved;
|
|
64041
64202
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
64042
64203
|
if (isWinAbs) {
|
|
64043
|
-
resolved =
|
|
64044
|
-
} else if (
|
|
64045
|
-
resolved =
|
|
64204
|
+
resolved = path57.win32.resolve(inputPath);
|
|
64205
|
+
} else if (path57.isAbsolute(inputPath)) {
|
|
64206
|
+
resolved = path57.resolve(inputPath);
|
|
64046
64207
|
} else {
|
|
64047
|
-
resolved =
|
|
64208
|
+
resolved = path57.resolve(baseDir, inputPath);
|
|
64048
64209
|
}
|
|
64049
|
-
const workspaceResolved =
|
|
64050
|
-
let
|
|
64210
|
+
const workspaceResolved = path57.resolve(workspaceDir);
|
|
64211
|
+
let relative8;
|
|
64051
64212
|
if (isWinAbs) {
|
|
64052
|
-
|
|
64213
|
+
relative8 = path57.win32.relative(workspaceResolved, resolved);
|
|
64053
64214
|
} else {
|
|
64054
|
-
|
|
64215
|
+
relative8 = path57.relative(workspaceResolved, resolved);
|
|
64055
64216
|
}
|
|
64056
|
-
if (
|
|
64217
|
+
if (relative8.startsWith("..")) {
|
|
64057
64218
|
return "path traversal detected";
|
|
64058
64219
|
}
|
|
64059
64220
|
return null;
|
|
@@ -64112,13 +64273,13 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
64112
64273
|
}
|
|
64113
64274
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
64114
64275
|
const isWindows = process.platform === "win32";
|
|
64115
|
-
const binDir =
|
|
64276
|
+
const binDir = path57.join(workspaceDir, "node_modules", ".bin");
|
|
64116
64277
|
const validatedFiles = [];
|
|
64117
64278
|
for (const file3 of files) {
|
|
64118
64279
|
if (typeof file3 !== "string") {
|
|
64119
64280
|
continue;
|
|
64120
64281
|
}
|
|
64121
|
-
const resolvedPath =
|
|
64282
|
+
const resolvedPath = path57.resolve(file3);
|
|
64122
64283
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
64123
64284
|
if (validationError) {
|
|
64124
64285
|
continue;
|
|
@@ -64136,10 +64297,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
64136
64297
|
}
|
|
64137
64298
|
let command;
|
|
64138
64299
|
if (linter === "biome") {
|
|
64139
|
-
const biomeBin = isWindows ?
|
|
64300
|
+
const biomeBin = isWindows ? path57.join(binDir, "biome.EXE") : path57.join(binDir, "biome");
|
|
64140
64301
|
command = [biomeBin, "check", ...validatedFiles];
|
|
64141
64302
|
} else {
|
|
64142
|
-
const eslintBin = isWindows ?
|
|
64303
|
+
const eslintBin = isWindows ? path57.join(binDir, "eslint.cmd") : path57.join(binDir, "eslint");
|
|
64143
64304
|
command = [eslintBin, ...validatedFiles];
|
|
64144
64305
|
}
|
|
64145
64306
|
try {
|
|
@@ -64276,7 +64437,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
64276
64437
|
skippedFiles++;
|
|
64277
64438
|
continue;
|
|
64278
64439
|
}
|
|
64279
|
-
const resolvedPath =
|
|
64440
|
+
const resolvedPath = path57.resolve(file3);
|
|
64280
64441
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
64281
64442
|
if (validationError) {
|
|
64282
64443
|
skippedFiles++;
|
|
@@ -64294,14 +64455,14 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
64294
64455
|
};
|
|
64295
64456
|
}
|
|
64296
64457
|
for (const file3 of validatedFiles) {
|
|
64297
|
-
const ext =
|
|
64458
|
+
const ext = path57.extname(file3).toLowerCase();
|
|
64298
64459
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
64299
64460
|
skippedFiles++;
|
|
64300
64461
|
continue;
|
|
64301
64462
|
}
|
|
64302
64463
|
let stat2;
|
|
64303
64464
|
try {
|
|
64304
|
-
stat2 =
|
|
64465
|
+
stat2 = fs44.statSync(file3);
|
|
64305
64466
|
} catch {
|
|
64306
64467
|
skippedFiles++;
|
|
64307
64468
|
continue;
|
|
@@ -64312,7 +64473,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
64312
64473
|
}
|
|
64313
64474
|
let content;
|
|
64314
64475
|
try {
|
|
64315
|
-
const buffer =
|
|
64476
|
+
const buffer = fs44.readFileSync(file3);
|
|
64316
64477
|
if (buffer.includes(0)) {
|
|
64317
64478
|
skippedFiles++;
|
|
64318
64479
|
continue;
|
|
@@ -64500,7 +64661,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
64500
64661
|
const preexistingFindings = [];
|
|
64501
64662
|
for (const finding of findings) {
|
|
64502
64663
|
const filePath = finding.location.file;
|
|
64503
|
-
const normalised =
|
|
64664
|
+
const normalised = path57.relative(directory, filePath).replace(/\\/g, "/");
|
|
64504
64665
|
const changedLines = changedLineRanges.get(normalised);
|
|
64505
64666
|
if (changedLines && changedLines.has(finding.location.line)) {
|
|
64506
64667
|
newFindings.push(finding);
|
|
@@ -64551,7 +64712,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
64551
64712
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
64552
64713
|
continue;
|
|
64553
64714
|
}
|
|
64554
|
-
changedFiles.push(
|
|
64715
|
+
changedFiles.push(path57.resolve(directory, file3));
|
|
64555
64716
|
}
|
|
64556
64717
|
if (changedFiles.length === 0) {
|
|
64557
64718
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -64739,7 +64900,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
64739
64900
|
};
|
|
64740
64901
|
return JSON.stringify(errorResult, null, 2);
|
|
64741
64902
|
}
|
|
64742
|
-
const resolvedDirectory =
|
|
64903
|
+
const resolvedDirectory = path57.resolve(typedArgs.directory);
|
|
64743
64904
|
const workspaceAnchor = resolvedDirectory;
|
|
64744
64905
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
64745
64906
|
if (dirError) {
|
|
@@ -64845,38 +65006,38 @@ ${paginatedContent}`;
|
|
|
64845
65006
|
});
|
|
64846
65007
|
// src/tools/save-plan.ts
|
|
64847
65008
|
init_tool();
|
|
64848
|
-
import * as
|
|
64849
|
-
import * as
|
|
65009
|
+
import * as fs46 from "fs";
|
|
65010
|
+
import * as path59 from "path";
|
|
64850
65011
|
|
|
64851
65012
|
// src/parallel/file-locks.ts
|
|
64852
|
-
import * as
|
|
64853
|
-
import * as
|
|
65013
|
+
import * as fs45 from "fs";
|
|
65014
|
+
import * as path58 from "path";
|
|
64854
65015
|
var LOCKS_DIR = ".swarm/locks";
|
|
64855
65016
|
var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
64856
65017
|
function getLockFilePath(directory, filePath) {
|
|
64857
|
-
const normalized =
|
|
64858
|
-
if (!normalized.startsWith(
|
|
65018
|
+
const normalized = path58.resolve(directory, filePath);
|
|
65019
|
+
if (!normalized.startsWith(path58.resolve(directory))) {
|
|
64859
65020
|
throw new Error("Invalid file path: path traversal not allowed");
|
|
64860
65021
|
}
|
|
64861
65022
|
const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
64862
|
-
return
|
|
65023
|
+
return path58.join(directory, LOCKS_DIR, `${hash3}.lock`);
|
|
64863
65024
|
}
|
|
64864
65025
|
function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
64865
65026
|
const lockPath = getLockFilePath(directory, filePath);
|
|
64866
|
-
const locksDir =
|
|
64867
|
-
if (!
|
|
64868
|
-
|
|
65027
|
+
const locksDir = path58.dirname(lockPath);
|
|
65028
|
+
if (!fs45.existsSync(locksDir)) {
|
|
65029
|
+
fs45.mkdirSync(locksDir, { recursive: true });
|
|
64869
65030
|
}
|
|
64870
|
-
if (
|
|
65031
|
+
if (fs45.existsSync(lockPath)) {
|
|
64871
65032
|
try {
|
|
64872
|
-
const existingLock = JSON.parse(
|
|
65033
|
+
const existingLock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
|
|
64873
65034
|
if (Date.now() > existingLock.expiresAt) {
|
|
64874
|
-
|
|
65035
|
+
fs45.unlinkSync(lockPath);
|
|
64875
65036
|
} else {
|
|
64876
65037
|
return { acquired: false, existing: existingLock };
|
|
64877
65038
|
}
|
|
64878
65039
|
} catch {
|
|
64879
|
-
|
|
65040
|
+
fs45.unlinkSync(lockPath);
|
|
64880
65041
|
}
|
|
64881
65042
|
}
|
|
64882
65043
|
const lock = {
|
|
@@ -64887,24 +65048,24 @@ function tryAcquireLock(directory, filePath, agent, taskId) {
|
|
|
64887
65048
|
expiresAt: Date.now() + LOCK_TIMEOUT_MS
|
|
64888
65049
|
};
|
|
64889
65050
|
const tempPath = `${lockPath}.tmp`;
|
|
64890
|
-
|
|
64891
|
-
|
|
65051
|
+
fs45.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
|
|
65052
|
+
fs45.renameSync(tempPath, lockPath);
|
|
64892
65053
|
return { acquired: true, lock };
|
|
64893
65054
|
}
|
|
64894
65055
|
function releaseLock(directory, filePath, taskId) {
|
|
64895
65056
|
const lockPath = getLockFilePath(directory, filePath);
|
|
64896
|
-
if (!
|
|
65057
|
+
if (!fs45.existsSync(lockPath)) {
|
|
64897
65058
|
return true;
|
|
64898
65059
|
}
|
|
64899
65060
|
try {
|
|
64900
|
-
const lock = JSON.parse(
|
|
65061
|
+
const lock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
|
|
64901
65062
|
if (lock.taskId === taskId) {
|
|
64902
|
-
|
|
65063
|
+
fs45.unlinkSync(lockPath);
|
|
64903
65064
|
return true;
|
|
64904
65065
|
}
|
|
64905
65066
|
return false;
|
|
64906
65067
|
} catch {
|
|
64907
|
-
|
|
65068
|
+
fs45.unlinkSync(lockPath);
|
|
64908
65069
|
return true;
|
|
64909
65070
|
}
|
|
64910
65071
|
}
|
|
@@ -64962,7 +65123,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
64962
65123
|
success: false,
|
|
64963
65124
|
message: "Plan rejected: invalid phase or task IDs",
|
|
64964
65125
|
errors: validationErrors,
|
|
64965
|
-
recovery_guidance: "
|
|
65126
|
+
recovery_guidance: "Phase IDs must be positive integers: 1, 2, 3 (not 0, -1, or decimals). " + 'Task IDs must use N.M format: "1.1", "2.3", "3.1". ' + "Call save_plan again with corrected ids. " + "Never write .swarm/plan.json or .swarm/plan.md directly."
|
|
64966
65127
|
};
|
|
64967
65128
|
}
|
|
64968
65129
|
const placeholderIssues = detectPlaceholderContent(args2);
|
|
@@ -65029,14 +65190,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
65029
65190
|
try {
|
|
65030
65191
|
await savePlan(dir, plan);
|
|
65031
65192
|
try {
|
|
65032
|
-
const markerPath =
|
|
65193
|
+
const markerPath = path59.join(dir, ".swarm", ".plan-write-marker");
|
|
65033
65194
|
const marker = JSON.stringify({
|
|
65034
65195
|
source: "save_plan",
|
|
65035
65196
|
timestamp: new Date().toISOString(),
|
|
65036
65197
|
phases_count: plan.phases.length,
|
|
65037
65198
|
tasks_count: tasksCount
|
|
65038
65199
|
});
|
|
65039
|
-
await
|
|
65200
|
+
await fs46.promises.writeFile(markerPath, marker, "utf8");
|
|
65040
65201
|
} catch {}
|
|
65041
65202
|
const warnings = [];
|
|
65042
65203
|
let criticReviewFound = false;
|
|
@@ -65052,7 +65213,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
65052
65213
|
return {
|
|
65053
65214
|
success: true,
|
|
65054
65215
|
message: "Plan saved successfully",
|
|
65055
|
-
plan_path:
|
|
65216
|
+
plan_path: path59.join(dir, ".swarm", "plan.json"),
|
|
65056
65217
|
phases_count: plan.phases.length,
|
|
65057
65218
|
tasks_count: tasksCount,
|
|
65058
65219
|
...warnings.length > 0 ? { warnings } : {}
|
|
@@ -65075,7 +65236,7 @@ var save_plan = createSwarmTool({
|
|
|
65075
65236
|
title: tool.schema.string().min(1).describe("Plan title \u2014 the REAL project name from the spec. NOT a placeholder like [Project]."),
|
|
65076
65237
|
swarm_id: tool.schema.string().min(1).describe('Swarm identifier (e.g. "mega")'),
|
|
65077
65238
|
phases: tool.schema.array(tool.schema.object({
|
|
65078
|
-
id: tool.schema.number().int().
|
|
65239
|
+
id: tool.schema.number().int().min(1).describe("Phase number \u2014 a positive integer starting at 1. Use 1, 2, 3, etc."),
|
|
65079
65240
|
name: tool.schema.string().min(1).describe("Descriptive phase name derived from the spec"),
|
|
65080
65241
|
tasks: tool.schema.array(tool.schema.object({
|
|
65081
65242
|
id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M format, e.g. "1.1"').describe('Task ID in N.M format, e.g. "1.1", "2.3"'),
|
|
@@ -65094,8 +65255,8 @@ var save_plan = createSwarmTool({
|
|
|
65094
65255
|
// src/tools/sbom-generate.ts
|
|
65095
65256
|
init_dist();
|
|
65096
65257
|
init_manager();
|
|
65097
|
-
import * as
|
|
65098
|
-
import * as
|
|
65258
|
+
import * as fs47 from "fs";
|
|
65259
|
+
import * as path60 from "path";
|
|
65099
65260
|
|
|
65100
65261
|
// src/sbom/detectors/index.ts
|
|
65101
65262
|
init_utils();
|
|
@@ -65943,9 +66104,9 @@ function findManifestFiles(rootDir) {
|
|
|
65943
66104
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
65944
66105
|
function searchDir(dir) {
|
|
65945
66106
|
try {
|
|
65946
|
-
const entries =
|
|
66107
|
+
const entries = fs47.readdirSync(dir, { withFileTypes: true });
|
|
65947
66108
|
for (const entry of entries) {
|
|
65948
|
-
const fullPath =
|
|
66109
|
+
const fullPath = path60.join(dir, entry.name);
|
|
65949
66110
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
65950
66111
|
continue;
|
|
65951
66112
|
}
|
|
@@ -65954,7 +66115,7 @@ function findManifestFiles(rootDir) {
|
|
|
65954
66115
|
} else if (entry.isFile()) {
|
|
65955
66116
|
for (const pattern of patterns) {
|
|
65956
66117
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
65957
|
-
manifestFiles.push(
|
|
66118
|
+
manifestFiles.push(path60.relative(rootDir, fullPath));
|
|
65958
66119
|
break;
|
|
65959
66120
|
}
|
|
65960
66121
|
}
|
|
@@ -65970,13 +66131,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
65970
66131
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
65971
66132
|
for (const dir of directories) {
|
|
65972
66133
|
try {
|
|
65973
|
-
const entries =
|
|
66134
|
+
const entries = fs47.readdirSync(dir, { withFileTypes: true });
|
|
65974
66135
|
for (const entry of entries) {
|
|
65975
|
-
const fullPath =
|
|
66136
|
+
const fullPath = path60.join(dir, entry.name);
|
|
65976
66137
|
if (entry.isFile()) {
|
|
65977
66138
|
for (const pattern of patterns) {
|
|
65978
66139
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
65979
|
-
found.push(
|
|
66140
|
+
found.push(path60.relative(workingDir, fullPath));
|
|
65980
66141
|
break;
|
|
65981
66142
|
}
|
|
65982
66143
|
}
|
|
@@ -65989,11 +66150,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
65989
66150
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
65990
66151
|
const dirs = new Set;
|
|
65991
66152
|
for (const file3 of changedFiles) {
|
|
65992
|
-
let currentDir =
|
|
66153
|
+
let currentDir = path60.dirname(file3);
|
|
65993
66154
|
while (true) {
|
|
65994
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
65995
|
-
dirs.add(
|
|
65996
|
-
const parent =
|
|
66155
|
+
if (currentDir && currentDir !== "." && currentDir !== path60.sep) {
|
|
66156
|
+
dirs.add(path60.join(workingDir, currentDir));
|
|
66157
|
+
const parent = path60.dirname(currentDir);
|
|
65997
66158
|
if (parent === currentDir)
|
|
65998
66159
|
break;
|
|
65999
66160
|
currentDir = parent;
|
|
@@ -66007,7 +66168,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
66007
66168
|
}
|
|
66008
66169
|
function ensureOutputDir(outputDir) {
|
|
66009
66170
|
try {
|
|
66010
|
-
|
|
66171
|
+
fs47.mkdirSync(outputDir, { recursive: true });
|
|
66011
66172
|
} catch (error93) {
|
|
66012
66173
|
if (!error93 || error93.code !== "EEXIST") {
|
|
66013
66174
|
throw error93;
|
|
@@ -66077,7 +66238,7 @@ var sbom_generate = createSwarmTool({
|
|
|
66077
66238
|
const changedFiles = obj.changed_files;
|
|
66078
66239
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
66079
66240
|
const workingDir = directory;
|
|
66080
|
-
const outputDir =
|
|
66241
|
+
const outputDir = path60.isAbsolute(relativeOutputDir) ? relativeOutputDir : path60.join(workingDir, relativeOutputDir);
|
|
66081
66242
|
let manifestFiles = [];
|
|
66082
66243
|
if (scope === "all") {
|
|
66083
66244
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -66100,11 +66261,11 @@ var sbom_generate = createSwarmTool({
|
|
|
66100
66261
|
const processedFiles = [];
|
|
66101
66262
|
for (const manifestFile of manifestFiles) {
|
|
66102
66263
|
try {
|
|
66103
|
-
const fullPath =
|
|
66104
|
-
if (!
|
|
66264
|
+
const fullPath = path60.isAbsolute(manifestFile) ? manifestFile : path60.join(workingDir, manifestFile);
|
|
66265
|
+
if (!fs47.existsSync(fullPath)) {
|
|
66105
66266
|
continue;
|
|
66106
66267
|
}
|
|
66107
|
-
const content =
|
|
66268
|
+
const content = fs47.readFileSync(fullPath, "utf-8");
|
|
66108
66269
|
const components = detectComponents(manifestFile, content);
|
|
66109
66270
|
processedFiles.push(manifestFile);
|
|
66110
66271
|
if (components.length > 0) {
|
|
@@ -66117,8 +66278,8 @@ var sbom_generate = createSwarmTool({
|
|
|
66117
66278
|
const bom = generateCycloneDX(allComponents);
|
|
66118
66279
|
const bomJson = serializeCycloneDX(bom);
|
|
66119
66280
|
const filename = generateSbomFilename();
|
|
66120
|
-
const outputPath =
|
|
66121
|
-
|
|
66281
|
+
const outputPath = path60.join(outputDir, filename);
|
|
66282
|
+
fs47.writeFileSync(outputPath, bomJson, "utf-8");
|
|
66122
66283
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
66123
66284
|
try {
|
|
66124
66285
|
const timestamp = new Date().toISOString();
|
|
@@ -66160,8 +66321,8 @@ var sbom_generate = createSwarmTool({
|
|
|
66160
66321
|
// src/tools/schema-drift.ts
|
|
66161
66322
|
init_dist();
|
|
66162
66323
|
init_create_tool();
|
|
66163
|
-
import * as
|
|
66164
|
-
import * as
|
|
66324
|
+
import * as fs48 from "fs";
|
|
66325
|
+
import * as path61 from "path";
|
|
66165
66326
|
var SPEC_CANDIDATES = [
|
|
66166
66327
|
"openapi.json",
|
|
66167
66328
|
"openapi.yaml",
|
|
@@ -66193,28 +66354,28 @@ function normalizePath2(p) {
|
|
|
66193
66354
|
}
|
|
66194
66355
|
function discoverSpecFile(cwd, specFileArg) {
|
|
66195
66356
|
if (specFileArg) {
|
|
66196
|
-
const resolvedPath =
|
|
66197
|
-
const normalizedCwd = cwd.endsWith(
|
|
66357
|
+
const resolvedPath = path61.resolve(cwd, specFileArg);
|
|
66358
|
+
const normalizedCwd = cwd.endsWith(path61.sep) ? cwd : cwd + path61.sep;
|
|
66198
66359
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
66199
66360
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
66200
66361
|
}
|
|
66201
|
-
const ext =
|
|
66362
|
+
const ext = path61.extname(resolvedPath).toLowerCase();
|
|
66202
66363
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
66203
66364
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
66204
66365
|
}
|
|
66205
|
-
const stats =
|
|
66366
|
+
const stats = fs48.statSync(resolvedPath);
|
|
66206
66367
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
66207
66368
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
66208
66369
|
}
|
|
66209
|
-
if (!
|
|
66370
|
+
if (!fs48.existsSync(resolvedPath)) {
|
|
66210
66371
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
66211
66372
|
}
|
|
66212
66373
|
return resolvedPath;
|
|
66213
66374
|
}
|
|
66214
66375
|
for (const candidate of SPEC_CANDIDATES) {
|
|
66215
|
-
const candidatePath =
|
|
66216
|
-
if (
|
|
66217
|
-
const stats =
|
|
66376
|
+
const candidatePath = path61.resolve(cwd, candidate);
|
|
66377
|
+
if (fs48.existsSync(candidatePath)) {
|
|
66378
|
+
const stats = fs48.statSync(candidatePath);
|
|
66218
66379
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
66219
66380
|
return candidatePath;
|
|
66220
66381
|
}
|
|
@@ -66223,8 +66384,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
66223
66384
|
return null;
|
|
66224
66385
|
}
|
|
66225
66386
|
function parseSpec(specFile) {
|
|
66226
|
-
const content =
|
|
66227
|
-
const ext =
|
|
66387
|
+
const content = fs48.readFileSync(specFile, "utf-8");
|
|
66388
|
+
const ext = path61.extname(specFile).toLowerCase();
|
|
66228
66389
|
if (ext === ".json") {
|
|
66229
66390
|
return parseJsonSpec(content);
|
|
66230
66391
|
}
|
|
@@ -66295,12 +66456,12 @@ function extractRoutes(cwd) {
|
|
|
66295
66456
|
function walkDir(dir) {
|
|
66296
66457
|
let entries;
|
|
66297
66458
|
try {
|
|
66298
|
-
entries =
|
|
66459
|
+
entries = fs48.readdirSync(dir, { withFileTypes: true });
|
|
66299
66460
|
} catch {
|
|
66300
66461
|
return;
|
|
66301
66462
|
}
|
|
66302
66463
|
for (const entry of entries) {
|
|
66303
|
-
const fullPath =
|
|
66464
|
+
const fullPath = path61.join(dir, entry.name);
|
|
66304
66465
|
if (entry.isSymbolicLink()) {
|
|
66305
66466
|
continue;
|
|
66306
66467
|
}
|
|
@@ -66310,7 +66471,7 @@ function extractRoutes(cwd) {
|
|
|
66310
66471
|
}
|
|
66311
66472
|
walkDir(fullPath);
|
|
66312
66473
|
} else if (entry.isFile()) {
|
|
66313
|
-
const ext =
|
|
66474
|
+
const ext = path61.extname(entry.name).toLowerCase();
|
|
66314
66475
|
const baseName = entry.name.toLowerCase();
|
|
66315
66476
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
66316
66477
|
continue;
|
|
@@ -66328,7 +66489,7 @@ function extractRoutes(cwd) {
|
|
|
66328
66489
|
}
|
|
66329
66490
|
function extractRoutesFromFile(filePath) {
|
|
66330
66491
|
const routes = [];
|
|
66331
|
-
const content =
|
|
66492
|
+
const content = fs48.readFileSync(filePath, "utf-8");
|
|
66332
66493
|
const lines = content.split(/\r?\n/);
|
|
66333
66494
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
66334
66495
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -66479,8 +66640,8 @@ init_secretscan();
|
|
|
66479
66640
|
// src/tools/symbols.ts
|
|
66480
66641
|
init_tool();
|
|
66481
66642
|
init_create_tool();
|
|
66482
|
-
import * as
|
|
66483
|
-
import * as
|
|
66643
|
+
import * as fs49 from "fs";
|
|
66644
|
+
import * as path62 from "path";
|
|
66484
66645
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
66485
66646
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
66486
66647
|
function containsWindowsAttacks(str) {
|
|
@@ -66497,11 +66658,11 @@ function containsWindowsAttacks(str) {
|
|
|
66497
66658
|
}
|
|
66498
66659
|
function isPathInWorkspace(filePath, workspace) {
|
|
66499
66660
|
try {
|
|
66500
|
-
const resolvedPath =
|
|
66501
|
-
const realWorkspace =
|
|
66502
|
-
const realResolvedPath =
|
|
66503
|
-
const relativePath =
|
|
66504
|
-
if (relativePath.startsWith("..") ||
|
|
66661
|
+
const resolvedPath = path62.resolve(workspace, filePath);
|
|
66662
|
+
const realWorkspace = fs49.realpathSync(workspace);
|
|
66663
|
+
const realResolvedPath = fs49.realpathSync(resolvedPath);
|
|
66664
|
+
const relativePath = path62.relative(realWorkspace, realResolvedPath);
|
|
66665
|
+
if (relativePath.startsWith("..") || path62.isAbsolute(relativePath)) {
|
|
66505
66666
|
return false;
|
|
66506
66667
|
}
|
|
66507
66668
|
return true;
|
|
@@ -66513,17 +66674,17 @@ function validatePathForRead(filePath, workspace) {
|
|
|
66513
66674
|
return isPathInWorkspace(filePath, workspace);
|
|
66514
66675
|
}
|
|
66515
66676
|
function extractTSSymbols(filePath, cwd) {
|
|
66516
|
-
const fullPath =
|
|
66677
|
+
const fullPath = path62.join(cwd, filePath);
|
|
66517
66678
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
66518
66679
|
return [];
|
|
66519
66680
|
}
|
|
66520
66681
|
let content;
|
|
66521
66682
|
try {
|
|
66522
|
-
const stats =
|
|
66683
|
+
const stats = fs49.statSync(fullPath);
|
|
66523
66684
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
66524
66685
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
66525
66686
|
}
|
|
66526
|
-
content =
|
|
66687
|
+
content = fs49.readFileSync(fullPath, "utf-8");
|
|
66527
66688
|
} catch {
|
|
66528
66689
|
return [];
|
|
66529
66690
|
}
|
|
@@ -66665,17 +66826,17 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
66665
66826
|
});
|
|
66666
66827
|
}
|
|
66667
66828
|
function extractPythonSymbols(filePath, cwd) {
|
|
66668
|
-
const fullPath =
|
|
66829
|
+
const fullPath = path62.join(cwd, filePath);
|
|
66669
66830
|
if (!validatePathForRead(fullPath, cwd)) {
|
|
66670
66831
|
return [];
|
|
66671
66832
|
}
|
|
66672
66833
|
let content;
|
|
66673
66834
|
try {
|
|
66674
|
-
const stats =
|
|
66835
|
+
const stats = fs49.statSync(fullPath);
|
|
66675
66836
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
66676
66837
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
66677
66838
|
}
|
|
66678
|
-
content =
|
|
66839
|
+
content = fs49.readFileSync(fullPath, "utf-8");
|
|
66679
66840
|
} catch {
|
|
66680
66841
|
return [];
|
|
66681
66842
|
}
|
|
@@ -66748,7 +66909,7 @@ var symbols = createSwarmTool({
|
|
|
66748
66909
|
}, null, 2);
|
|
66749
66910
|
}
|
|
66750
66911
|
const cwd = directory;
|
|
66751
|
-
const ext =
|
|
66912
|
+
const ext = path62.extname(file3);
|
|
66752
66913
|
if (containsControlChars(file3)) {
|
|
66753
66914
|
return JSON.stringify({
|
|
66754
66915
|
file: file3,
|
|
@@ -66819,8 +66980,8 @@ init_test_runner();
|
|
|
66819
66980
|
init_dist();
|
|
66820
66981
|
init_utils();
|
|
66821
66982
|
init_create_tool();
|
|
66822
|
-
import * as
|
|
66823
|
-
import * as
|
|
66983
|
+
import * as fs50 from "fs";
|
|
66984
|
+
import * as path63 from "path";
|
|
66824
66985
|
var MAX_TEXT_LENGTH = 200;
|
|
66825
66986
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
66826
66987
|
var SUPPORTED_EXTENSIONS2 = new Set([
|
|
@@ -66885,9 +67046,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
66885
67046
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
66886
67047
|
}
|
|
66887
67048
|
try {
|
|
66888
|
-
const resolvedPath =
|
|
66889
|
-
const normalizedCwd =
|
|
66890
|
-
const normalizedResolved =
|
|
67049
|
+
const resolvedPath = path63.resolve(paths);
|
|
67050
|
+
const normalizedCwd = path63.resolve(cwd);
|
|
67051
|
+
const normalizedResolved = path63.resolve(resolvedPath);
|
|
66891
67052
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
66892
67053
|
return {
|
|
66893
67054
|
error: "paths must be within the current working directory",
|
|
@@ -66903,13 +67064,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
66903
67064
|
}
|
|
66904
67065
|
}
|
|
66905
67066
|
function isSupportedExtension(filePath) {
|
|
66906
|
-
const ext =
|
|
67067
|
+
const ext = path63.extname(filePath).toLowerCase();
|
|
66907
67068
|
return SUPPORTED_EXTENSIONS2.has(ext);
|
|
66908
67069
|
}
|
|
66909
67070
|
function findSourceFiles2(dir, files = []) {
|
|
66910
67071
|
let entries;
|
|
66911
67072
|
try {
|
|
66912
|
-
entries =
|
|
67073
|
+
entries = fs50.readdirSync(dir);
|
|
66913
67074
|
} catch {
|
|
66914
67075
|
return files;
|
|
66915
67076
|
}
|
|
@@ -66918,10 +67079,10 @@ function findSourceFiles2(dir, files = []) {
|
|
|
66918
67079
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
66919
67080
|
continue;
|
|
66920
67081
|
}
|
|
66921
|
-
const fullPath =
|
|
67082
|
+
const fullPath = path63.join(dir, entry);
|
|
66922
67083
|
let stat2;
|
|
66923
67084
|
try {
|
|
66924
|
-
stat2 =
|
|
67085
|
+
stat2 = fs50.statSync(fullPath);
|
|
66925
67086
|
} catch {
|
|
66926
67087
|
continue;
|
|
66927
67088
|
}
|
|
@@ -67014,7 +67175,7 @@ var todo_extract = createSwarmTool({
|
|
|
67014
67175
|
return JSON.stringify(errorResult, null, 2);
|
|
67015
67176
|
}
|
|
67016
67177
|
const scanPath = resolvedPath;
|
|
67017
|
-
if (!
|
|
67178
|
+
if (!fs50.existsSync(scanPath)) {
|
|
67018
67179
|
const errorResult = {
|
|
67019
67180
|
error: `path not found: ${pathsInput}`,
|
|
67020
67181
|
total: 0,
|
|
@@ -67024,13 +67185,13 @@ var todo_extract = createSwarmTool({
|
|
|
67024
67185
|
return JSON.stringify(errorResult, null, 2);
|
|
67025
67186
|
}
|
|
67026
67187
|
const filesToScan = [];
|
|
67027
|
-
const stat2 =
|
|
67188
|
+
const stat2 = fs50.statSync(scanPath);
|
|
67028
67189
|
if (stat2.isFile()) {
|
|
67029
67190
|
if (isSupportedExtension(scanPath)) {
|
|
67030
67191
|
filesToScan.push(scanPath);
|
|
67031
67192
|
} else {
|
|
67032
67193
|
const errorResult = {
|
|
67033
|
-
error: `unsupported file extension: ${
|
|
67194
|
+
error: `unsupported file extension: ${path63.extname(scanPath)}`,
|
|
67034
67195
|
total: 0,
|
|
67035
67196
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
67036
67197
|
entries: []
|
|
@@ -67043,11 +67204,11 @@ var todo_extract = createSwarmTool({
|
|
|
67043
67204
|
const allEntries = [];
|
|
67044
67205
|
for (const filePath of filesToScan) {
|
|
67045
67206
|
try {
|
|
67046
|
-
const fileStat =
|
|
67207
|
+
const fileStat = fs50.statSync(filePath);
|
|
67047
67208
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
67048
67209
|
continue;
|
|
67049
67210
|
}
|
|
67050
|
-
const content =
|
|
67211
|
+
const content = fs50.readFileSync(filePath, "utf-8");
|
|
67051
67212
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
67052
67213
|
allEntries.push(...entries);
|
|
67053
67214
|
} catch {}
|
|
@@ -67076,18 +67237,18 @@ var todo_extract = createSwarmTool({
|
|
|
67076
67237
|
init_tool();
|
|
67077
67238
|
init_schema();
|
|
67078
67239
|
init_gate_evidence();
|
|
67079
|
-
import * as
|
|
67080
|
-
import * as
|
|
67240
|
+
import * as fs52 from "fs";
|
|
67241
|
+
import * as path65 from "path";
|
|
67081
67242
|
|
|
67082
67243
|
// src/hooks/diff-scope.ts
|
|
67083
|
-
import * as
|
|
67084
|
-
import * as
|
|
67244
|
+
import * as fs51 from "fs";
|
|
67245
|
+
import * as path64 from "path";
|
|
67085
67246
|
function getDeclaredScope(taskId, directory) {
|
|
67086
67247
|
try {
|
|
67087
|
-
const planPath =
|
|
67088
|
-
if (!
|
|
67248
|
+
const planPath = path64.join(directory, ".swarm", "plan.json");
|
|
67249
|
+
if (!fs51.existsSync(planPath))
|
|
67089
67250
|
return null;
|
|
67090
|
-
const raw =
|
|
67251
|
+
const raw = fs51.readFileSync(planPath, "utf-8");
|
|
67091
67252
|
const plan = JSON.parse(raw);
|
|
67092
67253
|
for (const phase of plan.phases ?? []) {
|
|
67093
67254
|
for (const task of phase.tasks ?? []) {
|
|
@@ -67200,7 +67361,7 @@ var TIER_3_PATTERNS = [
|
|
|
67200
67361
|
];
|
|
67201
67362
|
function matchesTier3Pattern(files) {
|
|
67202
67363
|
for (const file3 of files) {
|
|
67203
|
-
const fileName =
|
|
67364
|
+
const fileName = path65.basename(file3);
|
|
67204
67365
|
for (const pattern of TIER_3_PATTERNS) {
|
|
67205
67366
|
if (pattern.test(fileName)) {
|
|
67206
67367
|
return true;
|
|
@@ -67214,8 +67375,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
67214
67375
|
if (hasActiveTurboMode()) {
|
|
67215
67376
|
const resolvedDir2 = workingDirectory;
|
|
67216
67377
|
try {
|
|
67217
|
-
const planPath =
|
|
67218
|
-
const planRaw =
|
|
67378
|
+
const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
|
|
67379
|
+
const planRaw = fs52.readFileSync(planPath, "utf-8");
|
|
67219
67380
|
const plan = JSON.parse(planRaw);
|
|
67220
67381
|
for (const planPhase of plan.phases ?? []) {
|
|
67221
67382
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -67281,8 +67442,8 @@ function checkReviewerGate(taskId, workingDirectory) {
|
|
|
67281
67442
|
}
|
|
67282
67443
|
try {
|
|
67283
67444
|
const resolvedDir2 = workingDirectory;
|
|
67284
|
-
const planPath =
|
|
67285
|
-
const planRaw =
|
|
67445
|
+
const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
|
|
67446
|
+
const planRaw = fs52.readFileSync(planPath, "utf-8");
|
|
67286
67447
|
const plan = JSON.parse(planRaw);
|
|
67287
67448
|
for (const planPhase of plan.phases ?? []) {
|
|
67288
67449
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -67464,8 +67625,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
67464
67625
|
};
|
|
67465
67626
|
}
|
|
67466
67627
|
}
|
|
67467
|
-
normalizedDir =
|
|
67468
|
-
const pathParts = normalizedDir.split(
|
|
67628
|
+
normalizedDir = path65.normalize(args2.working_directory);
|
|
67629
|
+
const pathParts = normalizedDir.split(path65.sep);
|
|
67469
67630
|
if (pathParts.includes("..")) {
|
|
67470
67631
|
return {
|
|
67471
67632
|
success: false,
|
|
@@ -67475,11 +67636,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
67475
67636
|
]
|
|
67476
67637
|
};
|
|
67477
67638
|
}
|
|
67478
|
-
const resolvedDir =
|
|
67639
|
+
const resolvedDir = path65.resolve(normalizedDir);
|
|
67479
67640
|
try {
|
|
67480
|
-
const realPath =
|
|
67481
|
-
const planPath =
|
|
67482
|
-
if (!
|
|
67641
|
+
const realPath = fs52.realpathSync(resolvedDir);
|
|
67642
|
+
const planPath = path65.join(realPath, ".swarm", "plan.json");
|
|
67643
|
+
if (!fs52.existsSync(planPath)) {
|
|
67483
67644
|
return {
|
|
67484
67645
|
success: false,
|
|
67485
67646
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -67512,8 +67673,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
67512
67673
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
67513
67674
|
let phaseRequiresReviewer = true;
|
|
67514
67675
|
try {
|
|
67515
|
-
const planPath =
|
|
67516
|
-
const planRaw =
|
|
67676
|
+
const planPath = path65.join(directory, ".swarm", "plan.json");
|
|
67677
|
+
const planRaw = fs52.readFileSync(planPath, "utf-8");
|
|
67517
67678
|
const plan = JSON.parse(planRaw);
|
|
67518
67679
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
67519
67680
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -67576,8 +67737,8 @@ var update_task_status = createSwarmTool({
|
|
|
67576
67737
|
init_tool();
|
|
67577
67738
|
init_utils2();
|
|
67578
67739
|
init_create_tool();
|
|
67579
|
-
import
|
|
67580
|
-
import
|
|
67740
|
+
import fs53 from "fs";
|
|
67741
|
+
import path66 from "path";
|
|
67581
67742
|
function normalizeVerdict(verdict) {
|
|
67582
67743
|
switch (verdict) {
|
|
67583
67744
|
case "APPROVED":
|
|
@@ -67624,7 +67785,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
67624
67785
|
entries: [evidenceEntry]
|
|
67625
67786
|
};
|
|
67626
67787
|
const filename = "drift-verifier.json";
|
|
67627
|
-
const relativePath =
|
|
67788
|
+
const relativePath = path66.join("evidence", String(phase), filename);
|
|
67628
67789
|
let validatedPath;
|
|
67629
67790
|
try {
|
|
67630
67791
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -67635,12 +67796,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
67635
67796
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
67636
67797
|
}, null, 2);
|
|
67637
67798
|
}
|
|
67638
|
-
const evidenceDir =
|
|
67799
|
+
const evidenceDir = path66.dirname(validatedPath);
|
|
67639
67800
|
try {
|
|
67640
|
-
await
|
|
67641
|
-
const tempPath =
|
|
67642
|
-
await
|
|
67643
|
-
await
|
|
67801
|
+
await fs53.promises.mkdir(evidenceDir, { recursive: true });
|
|
67802
|
+
const tempPath = path66.join(evidenceDir, `.${filename}.tmp`);
|
|
67803
|
+
await fs53.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
67804
|
+
await fs53.promises.rename(tempPath, validatedPath);
|
|
67644
67805
|
return JSON.stringify({
|
|
67645
67806
|
success: true,
|
|
67646
67807
|
phase,
|
|
@@ -67658,7 +67819,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
67658
67819
|
var write_drift_evidence = createSwarmTool({
|
|
67659
67820
|
description: "Write drift verification evidence for a completed phase. " + "Normalizes verdict (APPROVED->approved, NEEDS_REVISION->rejected) and writes " + "a gate-contract formatted EvidenceBundle to .swarm/evidence/{phase}/drift-verifier.json. " + "Use this after critic_drift_verifier delegation to persist the verification result.",
|
|
67660
67821
|
args: {
|
|
67661
|
-
phase: tool.schema.number().int().
|
|
67822
|
+
phase: tool.schema.number().int().min(1).describe("The phase number for the drift verification (e.g., 1, 2, 3)"),
|
|
67662
67823
|
verdict: tool.schema.enum(["APPROVED", "NEEDS_REVISION"]).describe("Verdict of the drift verification: 'APPROVED' or 'NEEDS_REVISION'"),
|
|
67663
67824
|
summary: tool.schema.string().describe("Human-readable summary of the drift verification")
|
|
67664
67825
|
},
|
|
@@ -67828,7 +67989,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
67828
67989
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
67829
67990
|
preflightTriggerManager = new PTM(automationConfig);
|
|
67830
67991
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
67831
|
-
const swarmDir =
|
|
67992
|
+
const swarmDir = path67.resolve(ctx.directory, ".swarm");
|
|
67832
67993
|
statusArtifact = new ASA(swarmDir);
|
|
67833
67994
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
67834
67995
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|