opencode-swarm 6.19.7 → 6.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -0
- package/dist/cli/index.js +707 -3377
- package/dist/commands/checkpoint.d.ts +5 -0
- package/dist/commands/handoff.d.ts +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/context/role-filter.d.ts +27 -0
- package/dist/context/zone-classifier.d.ts +17 -0
- package/dist/diff/ast-diff.d.ts +20 -0
- package/dist/git/branch.d.ts +50 -0
- package/dist/git/index.d.ts +22 -0
- package/dist/git/pr.d.ts +28 -0
- package/dist/hooks/delegation-gate.d.ts +7 -0
- package/dist/hooks/knowledge-store.d.ts +1 -0
- package/dist/index.js +1068 -348
- package/dist/knowledge/identity.d.ts +25 -0
- package/dist/knowledge/index.d.ts +2 -0
- package/dist/output/agent-writer.d.ts +27 -0
- package/dist/output/index.d.ts +1 -0
- package/dist/parallel/dependency-graph.d.ts +34 -0
- package/dist/parallel/file-locks.d.ts +33 -0
- package/dist/parallel/index.d.ts +4 -0
- package/dist/parallel/meta-indexer.d.ts +32 -0
- package/dist/parallel/review-router.d.ts +29 -0
- package/dist/services/context-budget-service.d.ts +101 -0
- package/dist/services/handoff-service.d.ts +61 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/run-memory.d.ts +66 -0
- package/dist/skills/index.d.ts +30 -0
- package/dist/types/delegation.d.ts +24 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31892,7 +31892,7 @@ var init_detector = __esm(() => {
|
|
|
31892
31892
|
|
|
31893
31893
|
// src/build/discovery.ts
|
|
31894
31894
|
import * as fs6 from "fs";
|
|
31895
|
-
import * as
|
|
31895
|
+
import * as path17 from "path";
|
|
31896
31896
|
function isCommandAvailable(command) {
|
|
31897
31897
|
if (toolchainCache.has(command)) {
|
|
31898
31898
|
return toolchainCache.get(command);
|
|
@@ -31927,11 +31927,11 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
31927
31927
|
return regex.test(f);
|
|
31928
31928
|
});
|
|
31929
31929
|
if (matches.length > 0) {
|
|
31930
|
-
return
|
|
31930
|
+
return path17.join(dir, matches[0]);
|
|
31931
31931
|
}
|
|
31932
31932
|
} catch {}
|
|
31933
31933
|
} else {
|
|
31934
|
-
const filePath =
|
|
31934
|
+
const filePath = path17.join(workingDir, pattern);
|
|
31935
31935
|
if (fs6.existsSync(filePath)) {
|
|
31936
31936
|
return filePath;
|
|
31937
31937
|
}
|
|
@@ -31940,7 +31940,7 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
31940
31940
|
return null;
|
|
31941
31941
|
}
|
|
31942
31942
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
31943
|
-
const packageJsonPath =
|
|
31943
|
+
const packageJsonPath = path17.join(workingDir, "package.json");
|
|
31944
31944
|
if (!fs6.existsSync(packageJsonPath)) {
|
|
31945
31945
|
return [];
|
|
31946
31946
|
}
|
|
@@ -31981,7 +31981,7 @@ function findAllBuildFiles(workingDir) {
|
|
|
31981
31981
|
const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
|
|
31982
31982
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
31983
31983
|
} else {
|
|
31984
|
-
const filePath =
|
|
31984
|
+
const filePath = path17.join(workingDir, pattern);
|
|
31985
31985
|
if (fs6.existsSync(filePath)) {
|
|
31986
31986
|
allBuildFiles.add(filePath);
|
|
31987
31987
|
}
|
|
@@ -31994,7 +31994,7 @@ function findFilesRecursive(dir, regex, results) {
|
|
|
31994
31994
|
try {
|
|
31995
31995
|
const entries = fs6.readdirSync(dir, { withFileTypes: true });
|
|
31996
31996
|
for (const entry of entries) {
|
|
31997
|
-
const fullPath =
|
|
31997
|
+
const fullPath = path17.join(dir, entry.name);
|
|
31998
31998
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
31999
31999
|
findFilesRecursive(fullPath, regex, results);
|
|
32000
32000
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -32017,7 +32017,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
32017
32017
|
let foundCommand = false;
|
|
32018
32018
|
for (const cmd of sortedCommands) {
|
|
32019
32019
|
if (cmd.detectFile) {
|
|
32020
|
-
const detectFilePath =
|
|
32020
|
+
const detectFilePath = path17.join(workingDir, cmd.detectFile);
|
|
32021
32021
|
if (!fs6.existsSync(detectFilePath)) {
|
|
32022
32022
|
continue;
|
|
32023
32023
|
}
|
|
@@ -32227,7 +32227,7 @@ var init_discovery = __esm(() => {
|
|
|
32227
32227
|
|
|
32228
32228
|
// src/tools/lint.ts
|
|
32229
32229
|
import * as fs7 from "fs";
|
|
32230
|
-
import * as
|
|
32230
|
+
import * as path18 from "path";
|
|
32231
32231
|
function validateArgs(args2) {
|
|
32232
32232
|
if (typeof args2 !== "object" || args2 === null)
|
|
32233
32233
|
return false;
|
|
@@ -32238,9 +32238,9 @@ function validateArgs(args2) {
|
|
|
32238
32238
|
}
|
|
32239
32239
|
function getLinterCommand(linter, mode) {
|
|
32240
32240
|
const isWindows = process.platform === "win32";
|
|
32241
|
-
const binDir =
|
|
32242
|
-
const biomeBin = isWindows ?
|
|
32243
|
-
const eslintBin = isWindows ?
|
|
32241
|
+
const binDir = path18.join(process.cwd(), "node_modules", ".bin");
|
|
32242
|
+
const biomeBin = isWindows ? path18.join(binDir, "biome.EXE") : path18.join(binDir, "biome");
|
|
32243
|
+
const eslintBin = isWindows ? path18.join(binDir, "eslint.cmd") : path18.join(binDir, "eslint");
|
|
32244
32244
|
switch (linter) {
|
|
32245
32245
|
case "biome":
|
|
32246
32246
|
if (mode === "fix") {
|
|
@@ -32256,7 +32256,7 @@ function getLinterCommand(linter, mode) {
|
|
|
32256
32256
|
}
|
|
32257
32257
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
32258
32258
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
32259
|
-
const gradlew = fs7.existsSync(
|
|
32259
|
+
const gradlew = fs7.existsSync(path18.join(cwd, gradlewName)) ? path18.join(cwd, gradlewName) : null;
|
|
32260
32260
|
switch (linter) {
|
|
32261
32261
|
case "ruff":
|
|
32262
32262
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -32290,10 +32290,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
32290
32290
|
}
|
|
32291
32291
|
}
|
|
32292
32292
|
function detectRuff(cwd) {
|
|
32293
|
-
if (fs7.existsSync(
|
|
32293
|
+
if (fs7.existsSync(path18.join(cwd, "ruff.toml")))
|
|
32294
32294
|
return isCommandAvailable("ruff");
|
|
32295
32295
|
try {
|
|
32296
|
-
const pyproject =
|
|
32296
|
+
const pyproject = path18.join(cwd, "pyproject.toml");
|
|
32297
32297
|
if (fs7.existsSync(pyproject)) {
|
|
32298
32298
|
const content = fs7.readFileSync(pyproject, "utf-8");
|
|
32299
32299
|
if (content.includes("[tool.ruff]"))
|
|
@@ -32303,19 +32303,19 @@ function detectRuff(cwd) {
|
|
|
32303
32303
|
return false;
|
|
32304
32304
|
}
|
|
32305
32305
|
function detectClippy(cwd) {
|
|
32306
|
-
return fs7.existsSync(
|
|
32306
|
+
return fs7.existsSync(path18.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
32307
32307
|
}
|
|
32308
32308
|
function detectGolangciLint(cwd) {
|
|
32309
|
-
return fs7.existsSync(
|
|
32309
|
+
return fs7.existsSync(path18.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
32310
32310
|
}
|
|
32311
32311
|
function detectCheckstyle(cwd) {
|
|
32312
|
-
const hasMaven = fs7.existsSync(
|
|
32313
|
-
const hasGradle = fs7.existsSync(
|
|
32314
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs7.existsSync(
|
|
32312
|
+
const hasMaven = fs7.existsSync(path18.join(cwd, "pom.xml"));
|
|
32313
|
+
const hasGradle = fs7.existsSync(path18.join(cwd, "build.gradle")) || fs7.existsSync(path18.join(cwd, "build.gradle.kts"));
|
|
32314
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs7.existsSync(path18.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
32315
32315
|
return (hasMaven || hasGradle) && hasBinary;
|
|
32316
32316
|
}
|
|
32317
32317
|
function detectKtlint(cwd) {
|
|
32318
|
-
const hasKotlin = fs7.existsSync(
|
|
32318
|
+
const hasKotlin = fs7.existsSync(path18.join(cwd, "build.gradle.kts")) || fs7.existsSync(path18.join(cwd, "build.gradle")) || (() => {
|
|
32319
32319
|
try {
|
|
32320
32320
|
return fs7.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
32321
32321
|
} catch {
|
|
@@ -32334,11 +32334,11 @@ function detectDotnetFormat(cwd) {
|
|
|
32334
32334
|
}
|
|
32335
32335
|
}
|
|
32336
32336
|
function detectCppcheck(cwd) {
|
|
32337
|
-
if (fs7.existsSync(
|
|
32337
|
+
if (fs7.existsSync(path18.join(cwd, "CMakeLists.txt"))) {
|
|
32338
32338
|
return isCommandAvailable("cppcheck");
|
|
32339
32339
|
}
|
|
32340
32340
|
try {
|
|
32341
|
-
const dirsToCheck = [cwd,
|
|
32341
|
+
const dirsToCheck = [cwd, path18.join(cwd, "src")];
|
|
32342
32342
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
32343
32343
|
try {
|
|
32344
32344
|
return fs7.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -32352,13 +32352,13 @@ function detectCppcheck(cwd) {
|
|
|
32352
32352
|
}
|
|
32353
32353
|
}
|
|
32354
32354
|
function detectSwiftlint(cwd) {
|
|
32355
|
-
return fs7.existsSync(
|
|
32355
|
+
return fs7.existsSync(path18.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
32356
32356
|
}
|
|
32357
32357
|
function detectDartAnalyze(cwd) {
|
|
32358
|
-
return fs7.existsSync(
|
|
32358
|
+
return fs7.existsSync(path18.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
32359
32359
|
}
|
|
32360
32360
|
function detectRubocop(cwd) {
|
|
32361
|
-
return (fs7.existsSync(
|
|
32361
|
+
return (fs7.existsSync(path18.join(cwd, "Gemfile")) || fs7.existsSync(path18.join(cwd, "gems.rb")) || fs7.existsSync(path18.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
32362
32362
|
}
|
|
32363
32363
|
function detectAdditionalLinter(cwd) {
|
|
32364
32364
|
if (detectRuff(cwd))
|
|
@@ -32578,7 +32578,7 @@ For Rust: rustup component add clippy`
|
|
|
32578
32578
|
|
|
32579
32579
|
// src/tools/secretscan.ts
|
|
32580
32580
|
import * as fs8 from "fs";
|
|
32581
|
-
import * as
|
|
32581
|
+
import * as path19 from "path";
|
|
32582
32582
|
function calculateShannonEntropy(str) {
|
|
32583
32583
|
if (str.length === 0)
|
|
32584
32584
|
return 0;
|
|
@@ -32605,7 +32605,7 @@ function isHighEntropyString(str) {
|
|
|
32605
32605
|
function containsPathTraversal(str) {
|
|
32606
32606
|
if (/\.\.[/\\]/.test(str))
|
|
32607
32607
|
return true;
|
|
32608
|
-
const normalized =
|
|
32608
|
+
const normalized = path19.normalize(str);
|
|
32609
32609
|
if (/\.\.[/\\]/.test(normalized))
|
|
32610
32610
|
return true;
|
|
32611
32611
|
if (str.includes("%2e%2e") || str.includes("%2E%2E"))
|
|
@@ -32633,7 +32633,7 @@ function validateDirectoryInput(dir) {
|
|
|
32633
32633
|
return null;
|
|
32634
32634
|
}
|
|
32635
32635
|
function isBinaryFile(filePath, buffer) {
|
|
32636
|
-
const ext =
|
|
32636
|
+
const ext = path19.extname(filePath).toLowerCase();
|
|
32637
32637
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
32638
32638
|
return true;
|
|
32639
32639
|
}
|
|
@@ -32769,9 +32769,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
32769
32769
|
return false;
|
|
32770
32770
|
}
|
|
32771
32771
|
function isPathWithinScope(realPath, scanDir) {
|
|
32772
|
-
const resolvedScanDir =
|
|
32773
|
-
const resolvedRealPath =
|
|
32774
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
32772
|
+
const resolvedScanDir = path19.resolve(scanDir);
|
|
32773
|
+
const resolvedRealPath = path19.resolve(realPath);
|
|
32774
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path19.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
32775
32775
|
}
|
|
32776
32776
|
function findScannableFiles(dir, excludeDirs, scanDir, visited, stats = {
|
|
32777
32777
|
skippedDirs: 0,
|
|
@@ -32801,7 +32801,7 @@ function findScannableFiles(dir, excludeDirs, scanDir, visited, stats = {
|
|
|
32801
32801
|
stats.skippedDirs++;
|
|
32802
32802
|
continue;
|
|
32803
32803
|
}
|
|
32804
|
-
const fullPath =
|
|
32804
|
+
const fullPath = path19.join(dir, entry);
|
|
32805
32805
|
let lstat;
|
|
32806
32806
|
try {
|
|
32807
32807
|
lstat = fs8.lstatSync(fullPath);
|
|
@@ -32832,7 +32832,7 @@ function findScannableFiles(dir, excludeDirs, scanDir, visited, stats = {
|
|
|
32832
32832
|
const subFiles = findScannableFiles(fullPath, excludeDirs, scanDir, visited, stats);
|
|
32833
32833
|
files.push(...subFiles);
|
|
32834
32834
|
} else if (lstat.isFile()) {
|
|
32835
|
-
const ext =
|
|
32835
|
+
const ext = path19.extname(fullPath).toLowerCase();
|
|
32836
32836
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
32837
32837
|
files.push(fullPath);
|
|
32838
32838
|
} else {
|
|
@@ -33098,7 +33098,7 @@ var init_secretscan = __esm(() => {
|
|
|
33098
33098
|
}
|
|
33099
33099
|
}
|
|
33100
33100
|
try {
|
|
33101
|
-
const scanDir =
|
|
33101
|
+
const scanDir = path19.resolve(directory);
|
|
33102
33102
|
if (!fs8.existsSync(scanDir)) {
|
|
33103
33103
|
const errorResult = {
|
|
33104
33104
|
error: "directory not found",
|
|
@@ -33227,7 +33227,7 @@ var init_secretscan = __esm(() => {
|
|
|
33227
33227
|
|
|
33228
33228
|
// src/tools/test-runner.ts
|
|
33229
33229
|
import * as fs9 from "fs";
|
|
33230
|
-
import * as
|
|
33230
|
+
import * as path20 from "path";
|
|
33231
33231
|
function containsPathTraversal2(str) {
|
|
33232
33232
|
if (/\.\.[/\\]/.test(str))
|
|
33233
33233
|
return true;
|
|
@@ -33320,14 +33320,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
33320
33320
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
33321
33321
|
}
|
|
33322
33322
|
function detectGoTest(cwd) {
|
|
33323
|
-
return fs9.existsSync(
|
|
33323
|
+
return fs9.existsSync(path20.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
33324
33324
|
}
|
|
33325
33325
|
function detectJavaMaven(cwd) {
|
|
33326
|
-
return fs9.existsSync(
|
|
33326
|
+
return fs9.existsSync(path20.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
33327
33327
|
}
|
|
33328
33328
|
function detectGradle(cwd) {
|
|
33329
|
-
const hasBuildFile = fs9.existsSync(
|
|
33330
|
-
const hasGradlew = fs9.existsSync(
|
|
33329
|
+
const hasBuildFile = fs9.existsSync(path20.join(cwd, "build.gradle")) || fs9.existsSync(path20.join(cwd, "build.gradle.kts"));
|
|
33330
|
+
const hasGradlew = fs9.existsSync(path20.join(cwd, "gradlew")) || fs9.existsSync(path20.join(cwd, "gradlew.bat"));
|
|
33331
33331
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
33332
33332
|
}
|
|
33333
33333
|
function detectDotnetTest(cwd) {
|
|
@@ -33340,30 +33340,30 @@ function detectDotnetTest(cwd) {
|
|
|
33340
33340
|
}
|
|
33341
33341
|
}
|
|
33342
33342
|
function detectCTest(cwd) {
|
|
33343
|
-
const hasSource = fs9.existsSync(
|
|
33344
|
-
const hasBuildCache = fs9.existsSync(
|
|
33343
|
+
const hasSource = fs9.existsSync(path20.join(cwd, "CMakeLists.txt"));
|
|
33344
|
+
const hasBuildCache = fs9.existsSync(path20.join(cwd, "CMakeCache.txt")) || fs9.existsSync(path20.join(cwd, "build", "CMakeCache.txt"));
|
|
33345
33345
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
33346
33346
|
}
|
|
33347
33347
|
function detectSwiftTest(cwd) {
|
|
33348
|
-
return fs9.existsSync(
|
|
33348
|
+
return fs9.existsSync(path20.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
33349
33349
|
}
|
|
33350
33350
|
function detectDartTest(cwd) {
|
|
33351
|
-
return fs9.existsSync(
|
|
33351
|
+
return fs9.existsSync(path20.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
33352
33352
|
}
|
|
33353
33353
|
function detectRSpec(cwd) {
|
|
33354
|
-
const hasRSpecFile = fs9.existsSync(
|
|
33355
|
-
const hasGemfile = fs9.existsSync(
|
|
33356
|
-
const hasSpecDir = fs9.existsSync(
|
|
33354
|
+
const hasRSpecFile = fs9.existsSync(path20.join(cwd, ".rspec"));
|
|
33355
|
+
const hasGemfile = fs9.existsSync(path20.join(cwd, "Gemfile"));
|
|
33356
|
+
const hasSpecDir = fs9.existsSync(path20.join(cwd, "spec"));
|
|
33357
33357
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
33358
33358
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
33359
33359
|
}
|
|
33360
33360
|
function detectMinitest(cwd) {
|
|
33361
|
-
return fs9.existsSync(
|
|
33361
|
+
return fs9.existsSync(path20.join(cwd, "test")) && (fs9.existsSync(path20.join(cwd, "Gemfile")) || fs9.existsSync(path20.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
33362
33362
|
}
|
|
33363
33363
|
async function detectTestFramework(cwd) {
|
|
33364
33364
|
const baseDir = cwd || process.cwd();
|
|
33365
33365
|
try {
|
|
33366
|
-
const packageJsonPath =
|
|
33366
|
+
const packageJsonPath = path20.join(baseDir, "package.json");
|
|
33367
33367
|
if (fs9.existsSync(packageJsonPath)) {
|
|
33368
33368
|
const content = fs9.readFileSync(packageJsonPath, "utf-8");
|
|
33369
33369
|
const pkg = JSON.parse(content);
|
|
@@ -33384,16 +33384,16 @@ async function detectTestFramework(cwd) {
|
|
|
33384
33384
|
return "jest";
|
|
33385
33385
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
33386
33386
|
return "mocha";
|
|
33387
|
-
if (fs9.existsSync(
|
|
33387
|
+
if (fs9.existsSync(path20.join(baseDir, "bun.lockb")) || fs9.existsSync(path20.join(baseDir, "bun.lock"))) {
|
|
33388
33388
|
if (scripts.test?.includes("bun"))
|
|
33389
33389
|
return "bun";
|
|
33390
33390
|
}
|
|
33391
33391
|
}
|
|
33392
33392
|
} catch {}
|
|
33393
33393
|
try {
|
|
33394
|
-
const pyprojectTomlPath =
|
|
33395
|
-
const setupCfgPath =
|
|
33396
|
-
const requirementsTxtPath =
|
|
33394
|
+
const pyprojectTomlPath = path20.join(baseDir, "pyproject.toml");
|
|
33395
|
+
const setupCfgPath = path20.join(baseDir, "setup.cfg");
|
|
33396
|
+
const requirementsTxtPath = path20.join(baseDir, "requirements.txt");
|
|
33397
33397
|
if (fs9.existsSync(pyprojectTomlPath)) {
|
|
33398
33398
|
const content = fs9.readFileSync(pyprojectTomlPath, "utf-8");
|
|
33399
33399
|
if (content.includes("[tool.pytest"))
|
|
@@ -33413,7 +33413,7 @@ async function detectTestFramework(cwd) {
|
|
|
33413
33413
|
}
|
|
33414
33414
|
} catch {}
|
|
33415
33415
|
try {
|
|
33416
|
-
const cargoTomlPath =
|
|
33416
|
+
const cargoTomlPath = path20.join(baseDir, "Cargo.toml");
|
|
33417
33417
|
if (fs9.existsSync(cargoTomlPath)) {
|
|
33418
33418
|
const content = fs9.readFileSync(cargoTomlPath, "utf-8");
|
|
33419
33419
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -33424,9 +33424,9 @@ async function detectTestFramework(cwd) {
|
|
|
33424
33424
|
}
|
|
33425
33425
|
} catch {}
|
|
33426
33426
|
try {
|
|
33427
|
-
const pesterConfigPath =
|
|
33428
|
-
const pesterConfigJsonPath =
|
|
33429
|
-
const pesterPs1Path =
|
|
33427
|
+
const pesterConfigPath = path20.join(baseDir, "pester.config.ps1");
|
|
33428
|
+
const pesterConfigJsonPath = path20.join(baseDir, "pester.config.ps1.json");
|
|
33429
|
+
const pesterPs1Path = path20.join(baseDir, "tests.ps1");
|
|
33430
33430
|
if (fs9.existsSync(pesterConfigPath) || fs9.existsSync(pesterConfigJsonPath) || fs9.existsSync(pesterPs1Path)) {
|
|
33431
33431
|
return "pester";
|
|
33432
33432
|
}
|
|
@@ -33459,8 +33459,8 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
33459
33459
|
const testFiles = [];
|
|
33460
33460
|
for (const file3 of sourceFiles) {
|
|
33461
33461
|
const normalizedPath = file3.replace(/\\/g, "/");
|
|
33462
|
-
const basename4 =
|
|
33463
|
-
const
|
|
33462
|
+
const basename4 = path20.basename(file3);
|
|
33463
|
+
const dirname8 = path20.dirname(file3);
|
|
33464
33464
|
if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
33465
33465
|
if (!testFiles.includes(file3)) {
|
|
33466
33466
|
testFiles.push(file3);
|
|
@@ -33469,13 +33469,13 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
33469
33469
|
}
|
|
33470
33470
|
for (const _pattern of TEST_PATTERNS) {
|
|
33471
33471
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
33472
|
-
const ext =
|
|
33472
|
+
const ext = path20.extname(basename4);
|
|
33473
33473
|
const possibleTestFiles = [
|
|
33474
|
-
|
|
33475
|
-
|
|
33476
|
-
|
|
33477
|
-
|
|
33478
|
-
|
|
33474
|
+
path20.join(dirname8, `${nameWithoutExt}.spec${ext}`),
|
|
33475
|
+
path20.join(dirname8, `${nameWithoutExt}.test${ext}`),
|
|
33476
|
+
path20.join(dirname8, "__tests__", `${nameWithoutExt}${ext}`),
|
|
33477
|
+
path20.join(dirname8, "tests", `${nameWithoutExt}${ext}`),
|
|
33478
|
+
path20.join(dirname8, "test", `${nameWithoutExt}${ext}`)
|
|
33479
33479
|
];
|
|
33480
33480
|
for (const testFile of possibleTestFiles) {
|
|
33481
33481
|
if (fs9.existsSync(testFile) && !testFiles.includes(testFile)) {
|
|
@@ -33495,7 +33495,7 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
33495
33495
|
for (const testFile of candidateTestFiles) {
|
|
33496
33496
|
try {
|
|
33497
33497
|
const content = fs9.readFileSync(testFile, "utf-8");
|
|
33498
|
-
const testDir =
|
|
33498
|
+
const testDir = path20.dirname(testFile);
|
|
33499
33499
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
33500
33500
|
let match;
|
|
33501
33501
|
match = importRegex.exec(content);
|
|
@@ -33503,8 +33503,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
33503
33503
|
const importPath = match[1];
|
|
33504
33504
|
let resolvedImport;
|
|
33505
33505
|
if (importPath.startsWith(".")) {
|
|
33506
|
-
resolvedImport =
|
|
33507
|
-
const existingExt =
|
|
33506
|
+
resolvedImport = path20.resolve(testDir, importPath);
|
|
33507
|
+
const existingExt = path20.extname(resolvedImport);
|
|
33508
33508
|
if (!existingExt) {
|
|
33509
33509
|
for (const extToTry of [
|
|
33510
33510
|
".ts",
|
|
@@ -33524,12 +33524,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
33524
33524
|
} else {
|
|
33525
33525
|
continue;
|
|
33526
33526
|
}
|
|
33527
|
-
const importBasename =
|
|
33528
|
-
const importDir =
|
|
33527
|
+
const importBasename = path20.basename(resolvedImport, path20.extname(resolvedImport));
|
|
33528
|
+
const importDir = path20.dirname(resolvedImport);
|
|
33529
33529
|
for (const sourceFile of sourceFiles) {
|
|
33530
|
-
const sourceDir =
|
|
33531
|
-
const sourceBasename =
|
|
33532
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
33530
|
+
const sourceDir = path20.dirname(sourceFile);
|
|
33531
|
+
const sourceBasename = path20.basename(sourceFile, path20.extname(sourceFile));
|
|
33532
|
+
const isRelatedDir = importDir === sourceDir || importDir === path20.join(sourceDir, "__tests__") || importDir === path20.join(sourceDir, "tests") || importDir === path20.join(sourceDir, "test");
|
|
33533
33533
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
33534
33534
|
if (!testFiles.includes(testFile)) {
|
|
33535
33535
|
testFiles.push(testFile);
|
|
@@ -33544,8 +33544,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
33544
33544
|
while (match !== null) {
|
|
33545
33545
|
const importPath = match[1];
|
|
33546
33546
|
if (importPath.startsWith(".")) {
|
|
33547
|
-
let resolvedImport =
|
|
33548
|
-
const existingExt =
|
|
33547
|
+
let resolvedImport = path20.resolve(testDir, importPath);
|
|
33548
|
+
const existingExt = path20.extname(resolvedImport);
|
|
33549
33549
|
if (!existingExt) {
|
|
33550
33550
|
for (const extToTry of [
|
|
33551
33551
|
".ts",
|
|
@@ -33562,12 +33562,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
33562
33562
|
}
|
|
33563
33563
|
}
|
|
33564
33564
|
}
|
|
33565
|
-
const importDir =
|
|
33566
|
-
const importBasename =
|
|
33565
|
+
const importDir = path20.dirname(resolvedImport);
|
|
33566
|
+
const importBasename = path20.basename(resolvedImport, path20.extname(resolvedImport));
|
|
33567
33567
|
for (const sourceFile of sourceFiles) {
|
|
33568
|
-
const sourceDir =
|
|
33569
|
-
const sourceBasename =
|
|
33570
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
33568
|
+
const sourceDir = path20.dirname(sourceFile);
|
|
33569
|
+
const sourceBasename = path20.basename(sourceFile, path20.extname(sourceFile));
|
|
33570
|
+
const isRelatedDir = importDir === sourceDir || importDir === path20.join(sourceDir, "__tests__") || importDir === path20.join(sourceDir, "tests") || importDir === path20.join(sourceDir, "test");
|
|
33571
33571
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
33572
33572
|
if (!testFiles.includes(testFile)) {
|
|
33573
33573
|
testFiles.push(testFile);
|
|
@@ -33652,8 +33652,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
33652
33652
|
return ["mvn", "test"];
|
|
33653
33653
|
case "gradle": {
|
|
33654
33654
|
const isWindows = process.platform === "win32";
|
|
33655
|
-
const hasGradlewBat = fs9.existsSync(
|
|
33656
|
-
const hasGradlew = fs9.existsSync(
|
|
33655
|
+
const hasGradlewBat = fs9.existsSync(path20.join(baseDir, "gradlew.bat"));
|
|
33656
|
+
const hasGradlew = fs9.existsSync(path20.join(baseDir, "gradlew"));
|
|
33657
33657
|
if (hasGradlewBat && isWindows)
|
|
33658
33658
|
return ["gradlew.bat", "test"];
|
|
33659
33659
|
if (hasGradlew)
|
|
@@ -33670,7 +33670,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
33670
33670
|
"cmake-build-release",
|
|
33671
33671
|
"out"
|
|
33672
33672
|
];
|
|
33673
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs9.existsSync(
|
|
33673
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs9.existsSync(path20.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
33674
33674
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
33675
33675
|
}
|
|
33676
33676
|
case "swift-test":
|
|
@@ -34023,7 +34023,7 @@ function findSourceFiles(dir, files = []) {
|
|
|
34023
34023
|
for (const entry of entries) {
|
|
34024
34024
|
if (SKIP_DIRECTORIES.has(entry))
|
|
34025
34025
|
continue;
|
|
34026
|
-
const fullPath =
|
|
34026
|
+
const fullPath = path20.join(dir, entry);
|
|
34027
34027
|
let stat2;
|
|
34028
34028
|
try {
|
|
34029
34029
|
stat2 = fs9.statSync(fullPath);
|
|
@@ -34033,7 +34033,7 @@ function findSourceFiles(dir, files = []) {
|
|
|
34033
34033
|
if (stat2.isDirectory()) {
|
|
34034
34034
|
findSourceFiles(fullPath, files);
|
|
34035
34035
|
} else if (stat2.isFile()) {
|
|
34036
|
-
const ext =
|
|
34036
|
+
const ext = path20.extname(fullPath).toLowerCase();
|
|
34037
34037
|
if (SOURCE_EXTENSIONS.has(ext)) {
|
|
34038
34038
|
files.push(fullPath);
|
|
34039
34039
|
}
|
|
@@ -34202,13 +34202,13 @@ var init_test_runner = __esm(() => {
|
|
|
34202
34202
|
testFiles = [];
|
|
34203
34203
|
} else if (scope === "convention") {
|
|
34204
34204
|
const sourceFiles = args2.files && args2.files.length > 0 ? args2.files.filter((f) => {
|
|
34205
|
-
const ext =
|
|
34205
|
+
const ext = path20.extname(f).toLowerCase();
|
|
34206
34206
|
return SOURCE_EXTENSIONS.has(ext);
|
|
34207
34207
|
}) : findSourceFiles(workingDir);
|
|
34208
34208
|
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
34209
34209
|
} else if (scope === "graph") {
|
|
34210
34210
|
const sourceFiles = args2.files && args2.files.length > 0 ? args2.files.filter((f) => {
|
|
34211
|
-
const ext =
|
|
34211
|
+
const ext = path20.extname(f).toLowerCase();
|
|
34212
34212
|
return SOURCE_EXTENSIONS.has(ext);
|
|
34213
34213
|
}) : findSourceFiles(workingDir);
|
|
34214
34214
|
const graphTestFiles = await getTestFilesFromGraph(sourceFiles);
|
|
@@ -34231,7 +34231,7 @@ var init_test_runner = __esm(() => {
|
|
|
34231
34231
|
|
|
34232
34232
|
// src/services/preflight-service.ts
|
|
34233
34233
|
import * as fs10 from "fs";
|
|
34234
|
-
import * as
|
|
34234
|
+
import * as path21 from "path";
|
|
34235
34235
|
function validateDirectoryPath(dir) {
|
|
34236
34236
|
if (!dir || typeof dir !== "string") {
|
|
34237
34237
|
throw new Error("Directory path is required");
|
|
@@ -34239,8 +34239,8 @@ function validateDirectoryPath(dir) {
|
|
|
34239
34239
|
if (dir.includes("..")) {
|
|
34240
34240
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
34241
34241
|
}
|
|
34242
|
-
const normalized =
|
|
34243
|
-
const absolutePath =
|
|
34242
|
+
const normalized = path21.normalize(dir);
|
|
34243
|
+
const absolutePath = path21.isAbsolute(normalized) ? normalized : path21.resolve(normalized);
|
|
34244
34244
|
return absolutePath;
|
|
34245
34245
|
}
|
|
34246
34246
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -34263,7 +34263,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
34263
34263
|
}
|
|
34264
34264
|
function getPackageVersion(dir) {
|
|
34265
34265
|
try {
|
|
34266
|
-
const packagePath =
|
|
34266
|
+
const packagePath = path21.join(dir, "package.json");
|
|
34267
34267
|
if (fs10.existsSync(packagePath)) {
|
|
34268
34268
|
const content = fs10.readFileSync(packagePath, "utf-8");
|
|
34269
34269
|
const pkg = JSON.parse(content);
|
|
@@ -34274,7 +34274,7 @@ function getPackageVersion(dir) {
|
|
|
34274
34274
|
}
|
|
34275
34275
|
function getChangelogVersion(dir) {
|
|
34276
34276
|
try {
|
|
34277
|
-
const changelogPath =
|
|
34277
|
+
const changelogPath = path21.join(dir, "CHANGELOG.md");
|
|
34278
34278
|
if (fs10.existsSync(changelogPath)) {
|
|
34279
34279
|
const content = fs10.readFileSync(changelogPath, "utf-8");
|
|
34280
34280
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -34288,7 +34288,7 @@ function getChangelogVersion(dir) {
|
|
|
34288
34288
|
function getVersionFileVersion(dir) {
|
|
34289
34289
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
34290
34290
|
for (const file3 of possibleFiles) {
|
|
34291
|
-
const filePath =
|
|
34291
|
+
const filePath = path21.join(dir, file3);
|
|
34292
34292
|
if (fs10.existsSync(filePath)) {
|
|
34293
34293
|
try {
|
|
34294
34294
|
const content = fs10.readFileSync(filePath, "utf-8").trim();
|
|
@@ -36274,8 +36274,8 @@ var init_tree_sitter = __esm(() => {
|
|
|
36274
36274
|
bytes = Promise.resolve(input);
|
|
36275
36275
|
} else {
|
|
36276
36276
|
if (globalThis.process?.versions.node) {
|
|
36277
|
-
const
|
|
36278
|
-
bytes =
|
|
36277
|
+
const fs24 = await import("fs/promises");
|
|
36278
|
+
bytes = fs24.readFile(input);
|
|
36279
36279
|
} else {
|
|
36280
36280
|
bytes = fetch(input).then((response) => response.arrayBuffer().then((buffer) => {
|
|
36281
36281
|
if (response.ok) {
|
|
@@ -43807,6 +43807,416 @@ async function handleExportCommand(directory, _args) {
|
|
|
43807
43807
|
const exportData = await getExportData(directory);
|
|
43808
43808
|
return formatExportMarkdown(exportData);
|
|
43809
43809
|
}
|
|
43810
|
+
// src/commands/handoff.ts
|
|
43811
|
+
init_utils2();
|
|
43812
|
+
import { renameSync as renameSync4 } from "fs";
|
|
43813
|
+
|
|
43814
|
+
// src/services/handoff-service.ts
|
|
43815
|
+
init_utils2();
|
|
43816
|
+
init_manager2();
|
|
43817
|
+
var RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
|
|
43818
|
+
var MAX_TASK_ID_LENGTH = 100;
|
|
43819
|
+
var MAX_DECISION_LENGTH = 500;
|
|
43820
|
+
var MAX_INCOMPLETE_TASKS = 20;
|
|
43821
|
+
function escapeHtml(str) {
|
|
43822
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
43823
|
+
}
|
|
43824
|
+
function sanitizeString(str, maxLength) {
|
|
43825
|
+
if (!str)
|
|
43826
|
+
return "";
|
|
43827
|
+
const sanitized = String(str).replace(RTL_OVERRIDE_PATTERN, "");
|
|
43828
|
+
if (sanitized.length > maxLength) {
|
|
43829
|
+
return sanitized.substring(0, maxLength - 3) + "...";
|
|
43830
|
+
}
|
|
43831
|
+
return sanitized;
|
|
43832
|
+
}
|
|
43833
|
+
function validatePlanPhases(plan) {
|
|
43834
|
+
if (!plan || typeof plan !== "object")
|
|
43835
|
+
return false;
|
|
43836
|
+
const p = plan;
|
|
43837
|
+
if (!Array.isArray(p.phases))
|
|
43838
|
+
return false;
|
|
43839
|
+
for (const phase of p.phases) {
|
|
43840
|
+
if (!phase || typeof phase !== "object")
|
|
43841
|
+
return false;
|
|
43842
|
+
const phaseObj = phase;
|
|
43843
|
+
if (!Array.isArray(phaseObj.tasks))
|
|
43844
|
+
return false;
|
|
43845
|
+
}
|
|
43846
|
+
return true;
|
|
43847
|
+
}
|
|
43848
|
+
function extractCurrentPhaseFromPlan(plan) {
|
|
43849
|
+
if (!plan) {
|
|
43850
|
+
return { currentPhase: null, currentTask: null, incompleteTasks: [] };
|
|
43851
|
+
}
|
|
43852
|
+
if (!validatePlanPhases(plan)) {
|
|
43853
|
+
return { currentPhase: null, currentTask: null, incompleteTasks: [] };
|
|
43854
|
+
}
|
|
43855
|
+
let currentPhase = null;
|
|
43856
|
+
const currentPhaseNum = plan.current_phase;
|
|
43857
|
+
if (currentPhaseNum) {
|
|
43858
|
+
const phase = plan.phases.find((p) => p.id === currentPhaseNum);
|
|
43859
|
+
currentPhase = phase ? `Phase ${phase.id}: ${phase.name}` : null;
|
|
43860
|
+
} else {
|
|
43861
|
+
const inProgressPhase = plan.phases.find((p) => p.status === "in_progress");
|
|
43862
|
+
if (inProgressPhase) {
|
|
43863
|
+
currentPhase = `Phase ${inProgressPhase.id}: ${inProgressPhase.name}`;
|
|
43864
|
+
} else if (plan.phases.length > 0) {
|
|
43865
|
+
currentPhase = `Phase ${plan.phases[0].id}: ${plan.phases[0].name}`;
|
|
43866
|
+
}
|
|
43867
|
+
}
|
|
43868
|
+
let currentTask = null;
|
|
43869
|
+
const incompleteTasks = [];
|
|
43870
|
+
for (const phase of plan.phases) {
|
|
43871
|
+
for (const task of phase.tasks) {
|
|
43872
|
+
if (task.status === "in_progress") {
|
|
43873
|
+
currentTask = sanitizeString(task.id, MAX_TASK_ID_LENGTH);
|
|
43874
|
+
}
|
|
43875
|
+
if (task.status !== "completed") {
|
|
43876
|
+
if (incompleteTasks.length < MAX_INCOMPLETE_TASKS) {
|
|
43877
|
+
incompleteTasks.push(sanitizeString(task.id, MAX_TASK_ID_LENGTH));
|
|
43878
|
+
}
|
|
43879
|
+
}
|
|
43880
|
+
}
|
|
43881
|
+
}
|
|
43882
|
+
if (!currentTask && incompleteTasks.length > 0) {
|
|
43883
|
+
currentTask = incompleteTasks[0];
|
|
43884
|
+
}
|
|
43885
|
+
return { currentPhase, currentTask, incompleteTasks };
|
|
43886
|
+
}
|
|
43887
|
+
function parseSessionState(content) {
|
|
43888
|
+
if (!content)
|
|
43889
|
+
return null;
|
|
43890
|
+
try {
|
|
43891
|
+
const state = JSON.parse(content);
|
|
43892
|
+
let activeAgent = null;
|
|
43893
|
+
if (state.activeAgent && typeof state.activeAgent === "object") {
|
|
43894
|
+
const entries = Object.entries(state.activeAgent);
|
|
43895
|
+
if (entries.length > 0) {
|
|
43896
|
+
activeAgent = sanitizeString(entries[entries.length - 1][1], MAX_TASK_ID_LENGTH);
|
|
43897
|
+
}
|
|
43898
|
+
}
|
|
43899
|
+
let delegationState = null;
|
|
43900
|
+
if (state.delegationChains && typeof state.delegationChains === "object") {
|
|
43901
|
+
const chains = Object.entries(state.delegationChains);
|
|
43902
|
+
const activeChains = [];
|
|
43903
|
+
let maxDepth = 0;
|
|
43904
|
+
for (const [, chain] of chains) {
|
|
43905
|
+
if (Array.isArray(chain) && chain.length > 0) {
|
|
43906
|
+
const sanitizedChain = chain.map((e) => `${sanitizeString(e.from, MAX_TASK_ID_LENGTH)}->${sanitizeString(e.to, MAX_TASK_ID_LENGTH)}`).join(" | ");
|
|
43907
|
+
activeChains.push(sanitizedChain);
|
|
43908
|
+
maxDepth = Math.max(maxDepth, chain.length);
|
|
43909
|
+
}
|
|
43910
|
+
}
|
|
43911
|
+
if (activeChains.length > 0) {
|
|
43912
|
+
delegationState = {
|
|
43913
|
+
activeChains,
|
|
43914
|
+
delegationDepth: maxDepth,
|
|
43915
|
+
pendingHandoffs: []
|
|
43916
|
+
};
|
|
43917
|
+
}
|
|
43918
|
+
}
|
|
43919
|
+
let pendingQA = null;
|
|
43920
|
+
if (state.agentSessions && typeof state.agentSessions === "object") {
|
|
43921
|
+
for (const [, session] of Object.entries(state.agentSessions)) {
|
|
43922
|
+
const sess = session;
|
|
43923
|
+
if (sess.lastGateFailure && sess.currentTaskId) {
|
|
43924
|
+
pendingQA = {
|
|
43925
|
+
taskId: sanitizeString(sess.lastGateFailure.taskId, MAX_TASK_ID_LENGTH),
|
|
43926
|
+
lastFailure: sanitizeString(sess.lastGateFailure.tool, MAX_TASK_ID_LENGTH)
|
|
43927
|
+
};
|
|
43928
|
+
break;
|
|
43929
|
+
}
|
|
43930
|
+
}
|
|
43931
|
+
}
|
|
43932
|
+
return { activeAgent, delegationState, pendingQA };
|
|
43933
|
+
} catch {
|
|
43934
|
+
return null;
|
|
43935
|
+
}
|
|
43936
|
+
}
|
|
43937
|
+
function extractDecisions(content) {
|
|
43938
|
+
if (!content)
|
|
43939
|
+
return [];
|
|
43940
|
+
const decisions = [];
|
|
43941
|
+
const lines = content.split(`
|
|
43942
|
+
`);
|
|
43943
|
+
let inDecisionsSection = false;
|
|
43944
|
+
for (const line of lines) {
|
|
43945
|
+
if (line.trim() === "## Decisions") {
|
|
43946
|
+
inDecisionsSection = true;
|
|
43947
|
+
continue;
|
|
43948
|
+
}
|
|
43949
|
+
if (inDecisionsSection && line.startsWith("## ") && line.trim() !== "## Decisions") {
|
|
43950
|
+
break;
|
|
43951
|
+
}
|
|
43952
|
+
if (inDecisionsSection && line.trim().startsWith("- ")) {
|
|
43953
|
+
const text = line.trim().substring(2);
|
|
43954
|
+
const cleaned = text.replace(/\s*\[.*?\]\s*/g, "").replace(/\u2705/g, "").replace(/\[confirmed\]/g, "").trim();
|
|
43955
|
+
if (cleaned) {
|
|
43956
|
+
const sanitized = sanitizeString(cleaned, MAX_DECISION_LENGTH);
|
|
43957
|
+
if (sanitized) {
|
|
43958
|
+
decisions.push(sanitized);
|
|
43959
|
+
}
|
|
43960
|
+
}
|
|
43961
|
+
}
|
|
43962
|
+
}
|
|
43963
|
+
return decisions.slice(-5);
|
|
43964
|
+
}
|
|
43965
|
+
function extractPhaseMetrics(content) {
|
|
43966
|
+
if (!content)
|
|
43967
|
+
return "";
|
|
43968
|
+
const lines = content.split(`
|
|
43969
|
+
`);
|
|
43970
|
+
let inPhaseMetrics = false;
|
|
43971
|
+
const metricsLines = [];
|
|
43972
|
+
for (const line of lines) {
|
|
43973
|
+
if (line.trim() === "## Phase Metrics") {
|
|
43974
|
+
inPhaseMetrics = true;
|
|
43975
|
+
continue;
|
|
43976
|
+
}
|
|
43977
|
+
if (inPhaseMetrics && line.startsWith("## ")) {
|
|
43978
|
+
break;
|
|
43979
|
+
}
|
|
43980
|
+
if (inPhaseMetrics) {
|
|
43981
|
+
metricsLines.push(line);
|
|
43982
|
+
}
|
|
43983
|
+
}
|
|
43984
|
+
const lastFive = metricsLines.slice(-5);
|
|
43985
|
+
return lastFive.join(`
|
|
43986
|
+
`).trim();
|
|
43987
|
+
}
|
|
43988
|
+
async function getHandoffData(directory) {
|
|
43989
|
+
const now = new Date().toISOString();
|
|
43990
|
+
const sessionContent = await readSwarmFileAsync(directory, "session/state.json");
|
|
43991
|
+
const sessionState = parseSessionState(sessionContent);
|
|
43992
|
+
const plan = await loadPlanJsonOnly(directory);
|
|
43993
|
+
const planInfo = extractCurrentPhaseFromPlan(plan);
|
|
43994
|
+
if (!plan) {
|
|
43995
|
+
const planMdContent = await readSwarmFileAsync(directory, "plan.md");
|
|
43996
|
+
if (planMdContent) {
|
|
43997
|
+
const phaseMatch = planMdContent.match(/^## Phase (\d+):?\s*(.+)?$/m);
|
|
43998
|
+
const taskMatch = planMdContent.match(/^- \[ \] (\d+\.\d+)/g);
|
|
43999
|
+
if (phaseMatch) {
|
|
44000
|
+
planInfo.currentPhase = sanitizeString(`Phase ${phaseMatch[1]}${phaseMatch[2] ? ": " + phaseMatch[2] : ""}`, MAX_TASK_ID_LENGTH);
|
|
44001
|
+
}
|
|
44002
|
+
if (taskMatch) {
|
|
44003
|
+
const rawTasks = taskMatch.map((t) => t.replace("- [ ] ", ""));
|
|
44004
|
+
planInfo.incompleteTasks = rawTasks.map((t) => sanitizeString(t, MAX_TASK_ID_LENGTH)).slice(0, MAX_INCOMPLETE_TASKS);
|
|
44005
|
+
if (!planInfo.currentTask && planInfo.incompleteTasks.length > 0) {
|
|
44006
|
+
planInfo.currentTask = planInfo.incompleteTasks[0];
|
|
44007
|
+
}
|
|
44008
|
+
}
|
|
44009
|
+
}
|
|
44010
|
+
}
|
|
44011
|
+
const contextContent = await readSwarmFileAsync(directory, "context.md");
|
|
44012
|
+
const recentDecisions = extractDecisions(contextContent);
|
|
44013
|
+
const rawPhaseMetrics = extractPhaseMetrics(contextContent);
|
|
44014
|
+
const phaseMetrics = sanitizeString(rawPhaseMetrics, 1000);
|
|
44015
|
+
let delegationState = null;
|
|
44016
|
+
if (sessionState?.delegationState) {
|
|
44017
|
+
delegationState = {
|
|
44018
|
+
...sessionState.delegationState,
|
|
44019
|
+
pendingHandoffs: phaseMetrics ? [phaseMetrics] : []
|
|
44020
|
+
};
|
|
44021
|
+
}
|
|
44022
|
+
let pendingQA = null;
|
|
44023
|
+
if (sessionState?.pendingQA) {
|
|
44024
|
+
pendingQA = {
|
|
44025
|
+
taskId: escapeHtml(sessionState.pendingQA.taskId),
|
|
44026
|
+
lastFailure: sessionState.pendingQA.lastFailure ? escapeHtml(sessionState.pendingQA.lastFailure) : null
|
|
44027
|
+
};
|
|
44028
|
+
}
|
|
44029
|
+
const escapedDecisions = recentDecisions.map((d) => escapeHtml(d));
|
|
44030
|
+
let escapedDelegationState = null;
|
|
44031
|
+
if (delegationState) {
|
|
44032
|
+
escapedDelegationState = {
|
|
44033
|
+
...delegationState,
|
|
44034
|
+
activeChains: delegationState.activeChains.map((c) => escapeHtml(c)),
|
|
44035
|
+
pendingHandoffs: delegationState.pendingHandoffs.map((p) => escapeHtml(p))
|
|
44036
|
+
};
|
|
44037
|
+
}
|
|
44038
|
+
const escapedIncompleteTasks = planInfo.incompleteTasks.map((t) => escapeHtml(t));
|
|
44039
|
+
return {
|
|
44040
|
+
generated: now,
|
|
44041
|
+
currentPhase: planInfo.currentPhase ? escapeHtml(planInfo.currentPhase) : null,
|
|
44042
|
+
currentTask: planInfo.currentTask ? escapeHtml(planInfo.currentTask) : null,
|
|
44043
|
+
incompleteTasks: escapedIncompleteTasks,
|
|
44044
|
+
pendingQA,
|
|
44045
|
+
activeAgent: sessionState?.activeAgent ? escapeHtml(sessionState.activeAgent) : null,
|
|
44046
|
+
recentDecisions: escapedDecisions,
|
|
44047
|
+
delegationState: escapedDelegationState
|
|
44048
|
+
};
|
|
44049
|
+
}
|
|
44050
|
+
function formatHandoffMarkdown(data) {
|
|
44051
|
+
const lines = [];
|
|
44052
|
+
lines.push("## Swarm Handoff");
|
|
44053
|
+
lines.push("");
|
|
44054
|
+
lines.push(`**Generated**: ${data.generated}`);
|
|
44055
|
+
lines.push("");
|
|
44056
|
+
lines.push("### Current State");
|
|
44057
|
+
if (data.currentPhase) {
|
|
44058
|
+
lines.push(`- **Phase**: ${data.currentPhase}`);
|
|
44059
|
+
}
|
|
44060
|
+
if (data.currentTask) {
|
|
44061
|
+
lines.push(`- **Task**: ${data.currentTask}`);
|
|
44062
|
+
}
|
|
44063
|
+
if (data.activeAgent) {
|
|
44064
|
+
lines.push(`- **Active Agent**: ${data.activeAgent}`);
|
|
44065
|
+
}
|
|
44066
|
+
lines.push("");
|
|
44067
|
+
if (data.incompleteTasks.length > 0) {
|
|
44068
|
+
lines.push("### Incomplete Tasks");
|
|
44069
|
+
const displayTasks = data.incompleteTasks.slice(0, 10);
|
|
44070
|
+
for (const taskId of displayTasks) {
|
|
44071
|
+
lines.push(`- ${taskId}`);
|
|
44072
|
+
}
|
|
44073
|
+
if (data.incompleteTasks.length > 10) {
|
|
44074
|
+
lines.push(`- ... and ${data.incompleteTasks.length - 10} more`);
|
|
44075
|
+
}
|
|
44076
|
+
lines.push("");
|
|
44077
|
+
}
|
|
44078
|
+
if (data.pendingQA) {
|
|
44079
|
+
lines.push("### Pending QA");
|
|
44080
|
+
lines.push(`- **Task**: ${data.pendingQA.taskId}`);
|
|
44081
|
+
if (data.pendingQA.lastFailure) {
|
|
44082
|
+
lines.push(`- **Last Failure**: ${data.pendingQA.lastFailure}`);
|
|
44083
|
+
}
|
|
44084
|
+
lines.push("");
|
|
44085
|
+
}
|
|
44086
|
+
if (data.delegationState && data.delegationState.activeChains.length > 0) {
|
|
44087
|
+
lines.push("### Delegation");
|
|
44088
|
+
lines.push(`- **Depth**: ${data.delegationState.delegationDepth}`);
|
|
44089
|
+
for (const chain of data.delegationState.activeChains.slice(0, 3)) {
|
|
44090
|
+
lines.push(`- ${chain}`);
|
|
44091
|
+
}
|
|
44092
|
+
lines.push("");
|
|
44093
|
+
}
|
|
44094
|
+
if (data.recentDecisions.length > 0) {
|
|
44095
|
+
lines.push("### Recent Decisions");
|
|
44096
|
+
for (const decision of data.recentDecisions.slice(0, 5)) {
|
|
44097
|
+
lines.push(`- ${decision}`);
|
|
44098
|
+
}
|
|
44099
|
+
lines.push("");
|
|
44100
|
+
}
|
|
44101
|
+
if (data.delegationState?.pendingHandoffs && data.delegationState.pendingHandoffs.length > 0) {
|
|
44102
|
+
lines.push("### Phase Metrics");
|
|
44103
|
+
lines.push("```");
|
|
44104
|
+
lines.push(data.delegationState.pendingHandoffs[0]);
|
|
44105
|
+
lines.push("```");
|
|
44106
|
+
}
|
|
44107
|
+
return lines.join(`
|
|
44108
|
+
`);
|
|
44109
|
+
}
|
|
44110
|
+
|
|
44111
|
+
// src/session/snapshot-writer.ts
|
|
44112
|
+
init_utils2();
|
|
44113
|
+
import { mkdirSync as mkdirSync5, renameSync as renameSync3 } from "fs";
|
|
44114
|
+
import * as path14 from "path";
|
|
44115
|
+
function serializeAgentSession(s) {
|
|
44116
|
+
const gateLog = {};
|
|
44117
|
+
const rawGateLog = s.gateLog ?? new Map;
|
|
44118
|
+
for (const [taskId, gates] of rawGateLog) {
|
|
44119
|
+
gateLog[taskId] = Array.from(gates ?? []);
|
|
44120
|
+
}
|
|
44121
|
+
const reviewerCallCount = {};
|
|
44122
|
+
const rawReviewerCallCount = s.reviewerCallCount ?? new Map;
|
|
44123
|
+
for (const [phase, count] of rawReviewerCallCount) {
|
|
44124
|
+
reviewerCallCount[String(phase)] = count;
|
|
44125
|
+
}
|
|
44126
|
+
const partialGateWarningsIssuedForTask = Array.from(s.partialGateWarningsIssuedForTask ?? new Set);
|
|
44127
|
+
const catastrophicPhaseWarnings = Array.from(s.catastrophicPhaseWarnings ?? new Set);
|
|
44128
|
+
const phaseAgentsDispatched = Array.from(s.phaseAgentsDispatched ?? new Set);
|
|
44129
|
+
const windows = {};
|
|
44130
|
+
const rawWindows = s.windows ?? {};
|
|
44131
|
+
for (const [key, win] of Object.entries(rawWindows)) {
|
|
44132
|
+
windows[key] = {
|
|
44133
|
+
id: win.id,
|
|
44134
|
+
agentName: win.agentName,
|
|
44135
|
+
startedAtMs: win.startedAtMs,
|
|
44136
|
+
toolCalls: win.toolCalls,
|
|
44137
|
+
consecutiveErrors: win.consecutiveErrors,
|
|
44138
|
+
hardLimitHit: win.hardLimitHit,
|
|
44139
|
+
lastSuccessTimeMs: win.lastSuccessTimeMs,
|
|
44140
|
+
recentToolCalls: win.recentToolCalls,
|
|
44141
|
+
warningIssued: win.warningIssued,
|
|
44142
|
+
warningReason: win.warningReason
|
|
44143
|
+
};
|
|
44144
|
+
}
|
|
44145
|
+
return {
|
|
44146
|
+
agentName: s.agentName,
|
|
44147
|
+
lastToolCallTime: s.lastToolCallTime,
|
|
44148
|
+
lastAgentEventTime: s.lastAgentEventTime,
|
|
44149
|
+
delegationActive: s.delegationActive,
|
|
44150
|
+
activeInvocationId: s.activeInvocationId,
|
|
44151
|
+
lastInvocationIdByAgent: s.lastInvocationIdByAgent ?? {},
|
|
44152
|
+
windows,
|
|
44153
|
+
lastCompactionHint: s.lastCompactionHint ?? 0,
|
|
44154
|
+
architectWriteCount: s.architectWriteCount ?? 0,
|
|
44155
|
+
lastCoderDelegationTaskId: s.lastCoderDelegationTaskId ?? null,
|
|
44156
|
+
currentTaskId: s.currentTaskId ?? null,
|
|
44157
|
+
gateLog,
|
|
44158
|
+
reviewerCallCount,
|
|
44159
|
+
lastGateFailure: s.lastGateFailure ?? null,
|
|
44160
|
+
partialGateWarningsIssuedForTask,
|
|
44161
|
+
selfFixAttempted: s.selfFixAttempted ?? false,
|
|
44162
|
+
catastrophicPhaseWarnings,
|
|
44163
|
+
lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
|
|
44164
|
+
lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
|
|
44165
|
+
phaseAgentsDispatched,
|
|
44166
|
+
qaSkipCount: s.qaSkipCount ?? 0,
|
|
44167
|
+
qaSkipTaskIds: s.qaSkipTaskIds ?? []
|
|
44168
|
+
};
|
|
44169
|
+
}
|
|
44170
|
+
async function writeSnapshot(directory, state) {
|
|
44171
|
+
try {
|
|
44172
|
+
const snapshot = {
|
|
44173
|
+
version: 1,
|
|
44174
|
+
writtenAt: Date.now(),
|
|
44175
|
+
toolAggregates: Object.fromEntries(state.toolAggregates),
|
|
44176
|
+
activeAgent: Object.fromEntries(state.activeAgent),
|
|
44177
|
+
delegationChains: Object.fromEntries(state.delegationChains),
|
|
44178
|
+
agentSessions: {}
|
|
44179
|
+
};
|
|
44180
|
+
for (const [sessionId, sessionState] of state.agentSessions) {
|
|
44181
|
+
snapshot.agentSessions[sessionId] = serializeAgentSession(sessionState);
|
|
44182
|
+
}
|
|
44183
|
+
const content = JSON.stringify(snapshot, null, 2);
|
|
44184
|
+
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
44185
|
+
const dir = path14.dirname(resolvedPath);
|
|
44186
|
+
mkdirSync5(dir, { recursive: true });
|
|
44187
|
+
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
44188
|
+
await Bun.write(tempPath, content);
|
|
44189
|
+
renameSync3(tempPath, resolvedPath);
|
|
44190
|
+
} catch {}
|
|
44191
|
+
}
|
|
44192
|
+
function createSnapshotWriterHook(directory) {
|
|
44193
|
+
return async (_input, _output) => {
|
|
44194
|
+
try {
|
|
44195
|
+
await writeSnapshot(directory, swarmState);
|
|
44196
|
+
} catch {}
|
|
44197
|
+
};
|
|
44198
|
+
}
|
|
44199
|
+
|
|
44200
|
+
// src/commands/handoff.ts
|
|
44201
|
+
async function handleHandoffCommand(directory, _args) {
|
|
44202
|
+
const handoffData = await getHandoffData(directory);
|
|
44203
|
+
const markdown = formatHandoffMarkdown(handoffData);
|
|
44204
|
+
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
44205
|
+
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
44206
|
+
await Bun.write(tempPath, markdown);
|
|
44207
|
+
renameSync4(tempPath, resolvedPath);
|
|
44208
|
+
await writeSnapshot(directory, swarmState);
|
|
44209
|
+
return `## Handoff Brief Written
|
|
44210
|
+
|
|
44211
|
+
Brief written to \`.swarm/handoff.md\`.
|
|
44212
|
+
|
|
44213
|
+
${markdown}
|
|
44214
|
+
|
|
44215
|
+
---
|
|
44216
|
+
|
|
44217
|
+
**Next Step:** Start a new OpenCode session, switch to your target model, and send: \`continue the previous work\``;
|
|
44218
|
+
}
|
|
44219
|
+
|
|
43810
44220
|
// src/services/history-service.ts
|
|
43811
44221
|
init_utils2();
|
|
43812
44222
|
init_manager2();
|
|
@@ -43936,12 +44346,12 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
43936
44346
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
43937
44347
|
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
43938
44348
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
43939
|
-
import * as
|
|
44349
|
+
import * as path16 from "path";
|
|
43940
44350
|
|
|
43941
44351
|
// src/hooks/knowledge-validator.ts
|
|
43942
44352
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
43943
44353
|
import { appendFile as appendFile2, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
43944
|
-
import * as
|
|
44354
|
+
import * as path15 from "path";
|
|
43945
44355
|
var DANGEROUS_COMMAND_PATTERNS = [
|
|
43946
44356
|
/\brm\s+-rf\b/,
|
|
43947
44357
|
/\bsudo\s+rm\b/,
|
|
@@ -44193,10 +44603,10 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
|
|
|
44193
44603
|
return;
|
|
44194
44604
|
}
|
|
44195
44605
|
const sanitizedReason = reason.slice(0, 500).replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/g, "");
|
|
44196
|
-
const knowledgePath =
|
|
44197
|
-
const quarantinePath =
|
|
44198
|
-
const rejectedPath =
|
|
44199
|
-
const swarmDir =
|
|
44606
|
+
const knowledgePath = path15.join(directory, ".swarm", "knowledge.jsonl");
|
|
44607
|
+
const quarantinePath = path15.join(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
44608
|
+
const rejectedPath = path15.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
44609
|
+
const swarmDir = path15.join(directory, ".swarm");
|
|
44200
44610
|
await mkdir2(swarmDir, { recursive: true });
|
|
44201
44611
|
let release;
|
|
44202
44612
|
try {
|
|
@@ -44253,10 +44663,10 @@ async function restoreEntry(directory, entryId) {
|
|
|
44253
44663
|
console.warn("[knowledge-validator] restoreEntry: invalid entryId rejected");
|
|
44254
44664
|
return;
|
|
44255
44665
|
}
|
|
44256
|
-
const knowledgePath =
|
|
44257
|
-
const quarantinePath =
|
|
44258
|
-
const rejectedPath =
|
|
44259
|
-
const swarmDir =
|
|
44666
|
+
const knowledgePath = path15.join(directory, ".swarm", "knowledge.jsonl");
|
|
44667
|
+
const quarantinePath = path15.join(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
44668
|
+
const rejectedPath = path15.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
44669
|
+
const swarmDir = path15.join(directory, ".swarm");
|
|
44260
44670
|
await mkdir2(swarmDir, { recursive: true });
|
|
44261
44671
|
let release;
|
|
44262
44672
|
try {
|
|
@@ -44291,8 +44701,8 @@ async function restoreEntry(directory, entryId) {
|
|
|
44291
44701
|
|
|
44292
44702
|
// src/hooks/knowledge-migrator.ts
|
|
44293
44703
|
async function migrateContextToKnowledge(directory, config3) {
|
|
44294
|
-
const sentinelPath =
|
|
44295
|
-
const contextPath =
|
|
44704
|
+
const sentinelPath = path16.join(directory, ".swarm", ".knowledge-migrated");
|
|
44705
|
+
const contextPath = path16.join(directory, ".swarm", "context.md");
|
|
44296
44706
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
44297
44707
|
if (existsSync8(sentinelPath)) {
|
|
44298
44708
|
return {
|
|
@@ -44488,7 +44898,7 @@ function truncateLesson(text) {
|
|
|
44488
44898
|
return `${text.slice(0, 277)}...`;
|
|
44489
44899
|
}
|
|
44490
44900
|
function inferProjectName(directory) {
|
|
44491
|
-
const packageJsonPath =
|
|
44901
|
+
const packageJsonPath = path16.join(directory, "package.json");
|
|
44492
44902
|
if (existsSync8(packageJsonPath)) {
|
|
44493
44903
|
try {
|
|
44494
44904
|
const pkg = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
|
|
@@ -44497,7 +44907,7 @@ function inferProjectName(directory) {
|
|
|
44497
44907
|
}
|
|
44498
44908
|
} catch {}
|
|
44499
44909
|
}
|
|
44500
|
-
return
|
|
44910
|
+
return path16.basename(directory);
|
|
44501
44911
|
}
|
|
44502
44912
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
44503
44913
|
const sentinel = {
|
|
@@ -44509,7 +44919,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
44509
44919
|
schema_version: 1,
|
|
44510
44920
|
migration_tool: "knowledge-migrator.ts"
|
|
44511
44921
|
};
|
|
44512
|
-
await mkdir3(
|
|
44922
|
+
await mkdir3(path16.dirname(sentinelPath), { recursive: true });
|
|
44513
44923
|
await writeFile3(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
44514
44924
|
}
|
|
44515
44925
|
|
|
@@ -44746,7 +45156,7 @@ async function handlePlanCommand(directory, args2) {
|
|
|
44746
45156
|
init_preflight_service();
|
|
44747
45157
|
|
|
44748
45158
|
// src/hooks/hive-promoter.ts
|
|
44749
|
-
import
|
|
45159
|
+
import path22 from "path";
|
|
44750
45160
|
init_utils2();
|
|
44751
45161
|
function isAlreadyInHive(entry, hiveEntries, threshold) {
|
|
44752
45162
|
return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
|
|
@@ -44904,7 +45314,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
44904
45314
|
schema_version: 1,
|
|
44905
45315
|
created_at: new Date().toISOString(),
|
|
44906
45316
|
updated_at: new Date().toISOString(),
|
|
44907
|
-
source_project:
|
|
45317
|
+
source_project: path22.basename(directory) || "unknown"
|
|
44908
45318
|
};
|
|
44909
45319
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
44910
45320
|
return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
|
|
@@ -45064,8 +45474,8 @@ async function handleResetCommand(directory, args2) {
|
|
|
45064
45474
|
// src/summaries/manager.ts
|
|
45065
45475
|
init_utils2();
|
|
45066
45476
|
init_utils();
|
|
45067
|
-
import { mkdirSync as
|
|
45068
|
-
import * as
|
|
45477
|
+
import { mkdirSync as mkdirSync6, readdirSync as readdirSync7, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync7 } from "fs";
|
|
45478
|
+
import * as path23 from "path";
|
|
45069
45479
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
45070
45480
|
function sanitizeSummaryId(id) {
|
|
45071
45481
|
if (!id || id.length === 0) {
|
|
@@ -45093,9 +45503,9 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
45093
45503
|
if (outputBytes > maxStoredBytes) {
|
|
45094
45504
|
throw new Error(`Summary fullOutput size (${outputBytes} bytes) exceeds maximum (${maxStoredBytes} bytes)`);
|
|
45095
45505
|
}
|
|
45096
|
-
const relativePath =
|
|
45506
|
+
const relativePath = path23.join("summaries", `${sanitizedId}.json`);
|
|
45097
45507
|
const summaryPath = validateSwarmPath(directory, relativePath);
|
|
45098
|
-
const summaryDir =
|
|
45508
|
+
const summaryDir = path23.dirname(summaryPath);
|
|
45099
45509
|
const entry = {
|
|
45100
45510
|
id: sanitizedId,
|
|
45101
45511
|
summaryText,
|
|
@@ -45104,11 +45514,11 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
45104
45514
|
originalBytes: outputBytes
|
|
45105
45515
|
};
|
|
45106
45516
|
const entryJson = JSON.stringify(entry);
|
|
45107
|
-
|
|
45108
|
-
const tempPath =
|
|
45517
|
+
mkdirSync6(summaryDir, { recursive: true });
|
|
45518
|
+
const tempPath = path23.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
|
|
45109
45519
|
try {
|
|
45110
45520
|
await Bun.write(tempPath, entryJson);
|
|
45111
|
-
|
|
45521
|
+
renameSync5(tempPath, summaryPath);
|
|
45112
45522
|
} catch (error93) {
|
|
45113
45523
|
try {
|
|
45114
45524
|
rmSync3(tempPath, { force: true });
|
|
@@ -45118,7 +45528,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
|
|
|
45118
45528
|
}
|
|
45119
45529
|
async function loadFullOutput(directory, id) {
|
|
45120
45530
|
const sanitizedId = sanitizeSummaryId(id);
|
|
45121
|
-
const relativePath =
|
|
45531
|
+
const relativePath = path23.join("summaries", `${sanitizedId}.json`);
|
|
45122
45532
|
validateSwarmPath(directory, relativePath);
|
|
45123
45533
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
45124
45534
|
if (content === null) {
|
|
@@ -45172,7 +45582,7 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
45172
45582
|
// src/commands/rollback.ts
|
|
45173
45583
|
init_utils2();
|
|
45174
45584
|
import * as fs12 from "fs";
|
|
45175
|
-
import * as
|
|
45585
|
+
import * as path24 from "path";
|
|
45176
45586
|
async function handleRollbackCommand(directory, args2) {
|
|
45177
45587
|
const phaseArg = args2[0];
|
|
45178
45588
|
if (!phaseArg) {
|
|
@@ -45220,8 +45630,8 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
45220
45630
|
const successes = [];
|
|
45221
45631
|
const failures = [];
|
|
45222
45632
|
for (const file3 of checkpointFiles) {
|
|
45223
|
-
const src =
|
|
45224
|
-
const dest =
|
|
45633
|
+
const src = path24.join(checkpointDir, file3);
|
|
45634
|
+
const dest = path24.join(swarmDir, file3);
|
|
45225
45635
|
try {
|
|
45226
45636
|
fs12.cpSync(src, dest, { recursive: true, force: true });
|
|
45227
45637
|
successes.push(file3);
|
|
@@ -45284,9 +45694,9 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
45284
45694
|
const report = reportLines.filter(Boolean).join(`
|
|
45285
45695
|
`);
|
|
45286
45696
|
const fs13 = await import("fs/promises");
|
|
45287
|
-
const
|
|
45288
|
-
const reportPath =
|
|
45289
|
-
await fs13.mkdir(
|
|
45697
|
+
const path25 = await import("path");
|
|
45698
|
+
const reportPath = path25.join(directory, ".swarm", "simulate-report.md");
|
|
45699
|
+
await fs13.mkdir(path25.dirname(reportPath), { recursive: true });
|
|
45290
45700
|
await fs13.writeFile(reportPath, report, "utf-8");
|
|
45291
45701
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
45292
45702
|
}
|
|
@@ -45349,7 +45759,7 @@ function extractCurrentTask(planContent) {
|
|
|
45349
45759
|
}
|
|
45350
45760
|
return null;
|
|
45351
45761
|
}
|
|
45352
|
-
function
|
|
45762
|
+
function extractDecisions2(contextContent, maxChars = 500) {
|
|
45353
45763
|
if (!contextContent) {
|
|
45354
45764
|
return null;
|
|
45355
45765
|
}
|
|
@@ -45445,7 +45855,7 @@ function extractPatterns(contextContent, maxChars = 500) {
|
|
|
45445
45855
|
}
|
|
45446
45856
|
return `${trimmed.slice(0, maxChars)}...`;
|
|
45447
45857
|
}
|
|
45448
|
-
function
|
|
45858
|
+
function extractCurrentPhaseFromPlan2(plan) {
|
|
45449
45859
|
const phase = plan.phases.find((p) => p.id === plan.current_phase);
|
|
45450
45860
|
if (!phase)
|
|
45451
45861
|
return null;
|
|
@@ -45645,7 +46055,7 @@ init_manager2();
|
|
|
45645
46055
|
async function getStatusData(directory, agents) {
|
|
45646
46056
|
const plan = await loadPlan(directory);
|
|
45647
46057
|
if (plan && plan.migration_status !== "migration_failed") {
|
|
45648
|
-
const currentPhase2 =
|
|
46058
|
+
const currentPhase2 = extractCurrentPhaseFromPlan2(plan) || "Unknown";
|
|
45649
46059
|
let completedTasks2 = 0;
|
|
45650
46060
|
let totalTasks2 = 0;
|
|
45651
46061
|
for (const phase of plan.phases) {
|
|
@@ -45945,6 +46355,7 @@ var HELP_TEXT = [
|
|
|
45945
46355
|
"- `/swarm knowledge restore <id>` \u2014 Restore a quarantined knowledge entry",
|
|
45946
46356
|
"- `/swarm knowledge migrate` \u2014 Migrate knowledge entries to the current format",
|
|
45947
46357
|
'- `/swarm promote "<lesson>" | --category <cat> | --from-swarm <id> \u2014 Manually promote lesson to hive knowledge',
|
|
46358
|
+
"- `/swarm handoff` \u2014 Prepare state for clean model switch (new session)",
|
|
45948
46359
|
"- `/swarm write-retro <json>` \u2014 Write a retrospective evidence bundle for a completed phase"
|
|
45949
46360
|
].join(`
|
|
45950
46361
|
`);
|
|
@@ -46046,6 +46457,9 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
46046
46457
|
case "diagnose":
|
|
46047
46458
|
text = await handleDiagnoseCommand(directory, args2);
|
|
46048
46459
|
break;
|
|
46460
|
+
case "handoff":
|
|
46461
|
+
text = await handleHandoffCommand(directory, args2);
|
|
46462
|
+
break;
|
|
46049
46463
|
default:
|
|
46050
46464
|
text = HELP_TEXT;
|
|
46051
46465
|
break;
|
|
@@ -46057,7 +46471,7 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
46057
46471
|
}
|
|
46058
46472
|
|
|
46059
46473
|
// src/hooks/agent-activity.ts
|
|
46060
|
-
import { renameSync as
|
|
46474
|
+
import { renameSync as renameSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
46061
46475
|
init_utils();
|
|
46062
46476
|
init_utils2();
|
|
46063
46477
|
function createAgentActivityHooks(config3, directory) {
|
|
@@ -46127,11 +46541,11 @@ async function doFlush(directory) {
|
|
|
46127
46541
|
const activitySection = renderActivitySection();
|
|
46128
46542
|
const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
|
|
46129
46543
|
const flushedCount = swarmState.pendingEvents;
|
|
46130
|
-
const
|
|
46131
|
-
const tempPath = `${
|
|
46544
|
+
const path25 = `${directory}/.swarm/context.md`;
|
|
46545
|
+
const tempPath = `${path25}.tmp`;
|
|
46132
46546
|
try {
|
|
46133
46547
|
await Bun.write(tempPath, updated);
|
|
46134
|
-
|
|
46548
|
+
renameSync6(tempPath, path25);
|
|
46135
46549
|
} catch (writeError) {
|
|
46136
46550
|
try {
|
|
46137
46551
|
unlinkSync3(tempPath);
|
|
@@ -46191,7 +46605,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
46191
46605
|
const contextContent = await readSwarmFileAsync(directory, "context.md");
|
|
46192
46606
|
const plan = await loadPlan(directory);
|
|
46193
46607
|
if (plan && plan.migration_status !== "migration_failed") {
|
|
46194
|
-
const currentPhase =
|
|
46608
|
+
const currentPhase = extractCurrentPhaseFromPlan2(plan);
|
|
46195
46609
|
if (currentPhase) {
|
|
46196
46610
|
output.context.push(`[SWARM PLAN] ${currentPhase}`);
|
|
46197
46611
|
}
|
|
@@ -46213,7 +46627,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
46213
46627
|
}
|
|
46214
46628
|
}
|
|
46215
46629
|
if (contextContent) {
|
|
46216
|
-
const decisionsSummary =
|
|
46630
|
+
const decisionsSummary = extractDecisions2(contextContent);
|
|
46217
46631
|
if (decisionsSummary) {
|
|
46218
46632
|
output.context.push(`[SWARM DECISIONS] ${decisionsSummary}`);
|
|
46219
46633
|
}
|
|
@@ -46971,7 +47385,7 @@ function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
|
|
|
46971
47385
|
};
|
|
46972
47386
|
}
|
|
46973
47387
|
// src/hooks/guardrails.ts
|
|
46974
|
-
import * as
|
|
47388
|
+
import * as path25 from "path";
|
|
46975
47389
|
init_manager2();
|
|
46976
47390
|
init_utils();
|
|
46977
47391
|
function extractPhaseNumber(phaseString) {
|
|
@@ -47013,10 +47427,10 @@ function isArchitect(sessionId) {
|
|
|
47013
47427
|
function isOutsideSwarmDir(filePath, directory) {
|
|
47014
47428
|
if (!filePath)
|
|
47015
47429
|
return false;
|
|
47016
|
-
const swarmDir =
|
|
47017
|
-
const resolved =
|
|
47018
|
-
const relative3 =
|
|
47019
|
-
return relative3.startsWith("..") ||
|
|
47430
|
+
const swarmDir = path25.resolve(directory, ".swarm");
|
|
47431
|
+
const resolved = path25.resolve(directory, filePath);
|
|
47432
|
+
const relative3 = path25.relative(swarmDir, resolved);
|
|
47433
|
+
return relative3.startsWith("..") || path25.isAbsolute(relative3);
|
|
47020
47434
|
}
|
|
47021
47435
|
function isSourceCodePath(filePath) {
|
|
47022
47436
|
if (!filePath)
|
|
@@ -47307,7 +47721,7 @@ function createGuardrailsHooks(directory, config3) {
|
|
|
47307
47721
|
try {
|
|
47308
47722
|
const plan = await loadPlan(directory);
|
|
47309
47723
|
if (plan) {
|
|
47310
|
-
const phaseString =
|
|
47724
|
+
const phaseString = extractCurrentPhaseFromPlan2(plan);
|
|
47311
47725
|
currentPhase = extractPhaseNumber(phaseString);
|
|
47312
47726
|
}
|
|
47313
47727
|
} catch {}
|
|
@@ -47391,7 +47805,7 @@ function createGuardrailsHooks(directory, config3) {
|
|
|
47391
47805
|
try {
|
|
47392
47806
|
const plan = await loadPlan(directory);
|
|
47393
47807
|
if (plan) {
|
|
47394
|
-
const phaseString =
|
|
47808
|
+
const phaseString = extractCurrentPhaseFromPlan2(plan);
|
|
47395
47809
|
currentPhaseForCheck = extractPhaseNumber(phaseString);
|
|
47396
47810
|
}
|
|
47397
47811
|
} catch {}
|
|
@@ -47629,7 +48043,7 @@ function createPipelineTrackerHook(config3) {
|
|
|
47629
48043
|
try {
|
|
47630
48044
|
const plan = await loadPlan(process.cwd());
|
|
47631
48045
|
if (plan) {
|
|
47632
|
-
const phaseString =
|
|
48046
|
+
const phaseString = extractCurrentPhaseFromPlan2(plan);
|
|
47633
48047
|
phaseNumber = parsePhaseNumber(phaseString);
|
|
47634
48048
|
}
|
|
47635
48049
|
} catch {
|
|
@@ -47646,6 +48060,7 @@ ${originalText}`;
|
|
|
47646
48060
|
};
|
|
47647
48061
|
}
|
|
47648
48062
|
// src/hooks/system-enhancer.ts
|
|
48063
|
+
import * as fs15 from "fs";
|
|
47649
48064
|
init_manager();
|
|
47650
48065
|
init_detector();
|
|
47651
48066
|
init_manager2();
|
|
@@ -47654,7 +48069,7 @@ init_manager2();
|
|
|
47654
48069
|
init_utils2();
|
|
47655
48070
|
init_manager2();
|
|
47656
48071
|
import * as fs14 from "fs";
|
|
47657
|
-
import * as
|
|
48072
|
+
import * as path26 from "path";
|
|
47658
48073
|
var DEFAULT_DRIFT_CONFIG = {
|
|
47659
48074
|
staleThresholdPhases: 1,
|
|
47660
48075
|
detectContradictions: true,
|
|
@@ -47808,7 +48223,7 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
|
|
|
47808
48223
|
currentPhase = legacyPhase;
|
|
47809
48224
|
}
|
|
47810
48225
|
}
|
|
47811
|
-
const contextPath =
|
|
48226
|
+
const contextPath = path26.join(directory, ".swarm", "context.md");
|
|
47812
48227
|
let contextContent = "";
|
|
47813
48228
|
try {
|
|
47814
48229
|
if (fs14.existsSync(contextPath)) {
|
|
@@ -47920,6 +48335,165 @@ function formatDriftForContext(result) {
|
|
|
47920
48335
|
|
|
47921
48336
|
// src/services/index.ts
|
|
47922
48337
|
init_config_doctor();
|
|
48338
|
+
|
|
48339
|
+
// src/services/context-budget-service.ts
|
|
48340
|
+
init_utils2();
|
|
48341
|
+
function validateDirectory(directory) {
|
|
48342
|
+
if (!directory || directory.trim() === "") {
|
|
48343
|
+
throw new Error("Invalid directory: empty");
|
|
48344
|
+
}
|
|
48345
|
+
if (/\.\.[/\\]/.test(directory)) {
|
|
48346
|
+
throw new Error("Invalid directory: path traversal detected");
|
|
48347
|
+
}
|
|
48348
|
+
if (directory.startsWith("/") || directory.startsWith("\\")) {
|
|
48349
|
+
throw new Error("Invalid directory: absolute path");
|
|
48350
|
+
}
|
|
48351
|
+
if (/^[A-Za-z]:[\\/]/.test(directory)) {
|
|
48352
|
+
throw new Error("Invalid directory: Windows absolute path");
|
|
48353
|
+
}
|
|
48354
|
+
}
|
|
48355
|
+
var COST_PER_1K_TOKENS = 0.003;
|
|
48356
|
+
function estimateTokens2(text) {
|
|
48357
|
+
if (!text || typeof text !== "string") {
|
|
48358
|
+
return 0;
|
|
48359
|
+
}
|
|
48360
|
+
return Math.ceil(text.length / 3.5);
|
|
48361
|
+
}
|
|
48362
|
+
async function readBudgetState(directory) {
|
|
48363
|
+
const content = await readSwarmFileAsync(directory, "session/budget-state.json");
|
|
48364
|
+
if (!content) {
|
|
48365
|
+
return null;
|
|
48366
|
+
}
|
|
48367
|
+
try {
|
|
48368
|
+
return JSON.parse(content);
|
|
48369
|
+
} catch {
|
|
48370
|
+
return null;
|
|
48371
|
+
}
|
|
48372
|
+
}
|
|
48373
|
+
async function writeBudgetState(directory, state) {
|
|
48374
|
+
const resolvedPath = validateSwarmPath(directory, "session/budget-state.json");
|
|
48375
|
+
const content = JSON.stringify(state, null, 2);
|
|
48376
|
+
await Bun.write(resolvedPath, content);
|
|
48377
|
+
}
|
|
48378
|
+
async function countEvents(directory) {
|
|
48379
|
+
const content = await readSwarmFileAsync(directory, "events.jsonl");
|
|
48380
|
+
if (!content) {
|
|
48381
|
+
return 0;
|
|
48382
|
+
}
|
|
48383
|
+
const lines = content.split(`
|
|
48384
|
+
`).filter((line) => line.trim().length > 0);
|
|
48385
|
+
return lines.length;
|
|
48386
|
+
}
|
|
48387
|
+
async function getPlanCursorContent(directory) {
|
|
48388
|
+
const planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
48389
|
+
if (!planContent) {
|
|
48390
|
+
return "";
|
|
48391
|
+
}
|
|
48392
|
+
const lines = planContent.split(`
|
|
48393
|
+
`);
|
|
48394
|
+
const cursorLines = [];
|
|
48395
|
+
let inCurrentSection = false;
|
|
48396
|
+
for (const line of lines) {
|
|
48397
|
+
if (line.includes("in_progress") || line.includes("**Current**")) {
|
|
48398
|
+
inCurrentSection = true;
|
|
48399
|
+
}
|
|
48400
|
+
if (inCurrentSection) {
|
|
48401
|
+
cursorLines.push(line);
|
|
48402
|
+
if (cursorLines.length > 30) {
|
|
48403
|
+
break;
|
|
48404
|
+
}
|
|
48405
|
+
}
|
|
48406
|
+
}
|
|
48407
|
+
return cursorLines.join(`
|
|
48408
|
+
`) || planContent.substring(0, 1000);
|
|
48409
|
+
}
|
|
48410
|
+
async function getContextBudgetReport(directory, assembledSystemPrompt, config3) {
|
|
48411
|
+
validateDirectory(directory);
|
|
48412
|
+
const timestamp = new Date().toISOString();
|
|
48413
|
+
const systemPromptTokens = estimateTokens2(assembledSystemPrompt);
|
|
48414
|
+
const planCursorContent = await getPlanCursorContent(directory);
|
|
48415
|
+
const planCursorTokens = estimateTokens2(planCursorContent);
|
|
48416
|
+
const knowledgeContent = await readSwarmFileAsync(directory, "knowledge.jsonl");
|
|
48417
|
+
const knowledgeTokens = estimateTokens2(knowledgeContent || "");
|
|
48418
|
+
const runMemoryContent = await readSwarmFileAsync(directory, "run-memory.jsonl");
|
|
48419
|
+
const runMemoryTokens = estimateTokens2(runMemoryContent || "");
|
|
48420
|
+
const handoffContent = await readSwarmFileAsync(directory, "handoff.md");
|
|
48421
|
+
const handoffTokens = estimateTokens2(handoffContent || "");
|
|
48422
|
+
const contextMdContent = await readSwarmFileAsync(directory, "context.md");
|
|
48423
|
+
const contextMdTokens = estimateTokens2(contextMdContent || "");
|
|
48424
|
+
const swarmTotalTokens = systemPromptTokens + planCursorTokens + knowledgeTokens + runMemoryTokens + handoffTokens + contextMdTokens;
|
|
48425
|
+
const estimatedTurnCount = await countEvents(directory);
|
|
48426
|
+
const budgetPct = swarmTotalTokens / config3.budgetTokens * 100;
|
|
48427
|
+
let status;
|
|
48428
|
+
let recommendation = null;
|
|
48429
|
+
if (budgetPct < config3.warningPct) {
|
|
48430
|
+
status = "ok";
|
|
48431
|
+
} else if (budgetPct < config3.criticalPct) {
|
|
48432
|
+
status = "warning";
|
|
48433
|
+
recommendation = "Consider wrapping up current phase and running /swarm handoff before starting new work.";
|
|
48434
|
+
} else {
|
|
48435
|
+
status = "critical";
|
|
48436
|
+
recommendation = "Run /swarm handoff and start a new session to avoid cost escalation.";
|
|
48437
|
+
}
|
|
48438
|
+
const estimatedSessionTokens = swarmTotalTokens * Math.max(1, estimatedTurnCount);
|
|
48439
|
+
return {
|
|
48440
|
+
timestamp,
|
|
48441
|
+
systemPromptTokens,
|
|
48442
|
+
planCursorTokens,
|
|
48443
|
+
knowledgeTokens,
|
|
48444
|
+
runMemoryTokens,
|
|
48445
|
+
handoffTokens,
|
|
48446
|
+
contextMdTokens,
|
|
48447
|
+
swarmTotalTokens,
|
|
48448
|
+
estimatedTurnCount,
|
|
48449
|
+
estimatedSessionTokens,
|
|
48450
|
+
budgetPct,
|
|
48451
|
+
status,
|
|
48452
|
+
recommendation
|
|
48453
|
+
};
|
|
48454
|
+
}
|
|
48455
|
+
async function formatBudgetWarning(report, directory, config3) {
|
|
48456
|
+
validateDirectory(directory);
|
|
48457
|
+
if (report.status === "ok") {
|
|
48458
|
+
return null;
|
|
48459
|
+
}
|
|
48460
|
+
if (!directory || directory.trim() === "") {
|
|
48461
|
+
return formatWarningMessage(report);
|
|
48462
|
+
}
|
|
48463
|
+
const budgetState = await readBudgetState(directory);
|
|
48464
|
+
const state = budgetState || {
|
|
48465
|
+
warningFiredAtTurn: null,
|
|
48466
|
+
criticalFiredAtTurn: null,
|
|
48467
|
+
lastInjectedAtTurn: null
|
|
48468
|
+
};
|
|
48469
|
+
const currentTurn = report.estimatedTurnCount;
|
|
48470
|
+
if (report.status === "warning") {
|
|
48471
|
+
if (config3.warningMode === "once" && state.warningFiredAtTurn !== null) {
|
|
48472
|
+
return null;
|
|
48473
|
+
}
|
|
48474
|
+
if (config3.warningMode === "interval" && state.warningFiredAtTurn !== null && currentTurn - state.warningFiredAtTurn < config3.warningIntervalTurns) {
|
|
48475
|
+
return null;
|
|
48476
|
+
}
|
|
48477
|
+
state.warningFiredAtTurn = currentTurn;
|
|
48478
|
+
state.lastInjectedAtTurn = currentTurn;
|
|
48479
|
+
await writeBudgetState(directory, state);
|
|
48480
|
+
} else if (report.status === "critical") {
|
|
48481
|
+
state.criticalFiredAtTurn = currentTurn;
|
|
48482
|
+
state.lastInjectedAtTurn = currentTurn;
|
|
48483
|
+
}
|
|
48484
|
+
return formatWarningMessage(report);
|
|
48485
|
+
}
|
|
48486
|
+
function formatWarningMessage(report) {
|
|
48487
|
+
const budgetPctStr = report.budgetPct.toFixed(1);
|
|
48488
|
+
const tokensPerTurn = report.swarmTotalTokens.toLocaleString();
|
|
48489
|
+
if (report.status === "warning") {
|
|
48490
|
+
return `[CONTEXT BUDGET: ${budgetPctStr}% \u2014 swarm injecting ~${tokensPerTurn} tokens/turn. Consider wrapping current phase and running /swarm handoff before starting new work.]`;
|
|
48491
|
+
}
|
|
48492
|
+
const costPerTurn = (report.swarmTotalTokens / 1000 * COST_PER_1K_TOKENS).toFixed(3);
|
|
48493
|
+
return `[CONTEXT BUDGET: ${budgetPctStr}% CRITICAL \u2014 swarm injecting ~${tokensPerTurn} tokens/turn. Run /swarm handoff and start a new session to avoid cost escalation. Estimated session cost scaling: ~$${costPerTurn}/turn at current context size.]`;
|
|
48494
|
+
}
|
|
48495
|
+
|
|
48496
|
+
// src/services/index.ts
|
|
47923
48497
|
init_evidence_summary_service();
|
|
47924
48498
|
init_preflight_integration();
|
|
47925
48499
|
init_preflight_service();
|
|
@@ -48277,7 +48851,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
48277
48851
|
let planContent = null;
|
|
48278
48852
|
let phaseHeader = "";
|
|
48279
48853
|
if (plan2 && plan2.migration_status !== "migration_failed") {
|
|
48280
|
-
phaseHeader =
|
|
48854
|
+
phaseHeader = extractCurrentPhaseFromPlan2(plan2) || "";
|
|
48281
48855
|
planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
48282
48856
|
} else {
|
|
48283
48857
|
planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
@@ -48290,8 +48864,32 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
48290
48864
|
const planCursor = extractPlanCursor(planContent);
|
|
48291
48865
|
tryInject(planCursor);
|
|
48292
48866
|
}
|
|
48867
|
+
if (mode !== "DISCOVER") {
|
|
48868
|
+
try {
|
|
48869
|
+
const handoffContent = await readSwarmFileAsync(directory, "handoff.md");
|
|
48870
|
+
if (handoffContent) {
|
|
48871
|
+
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
48872
|
+
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
48873
|
+
if (fs15.existsSync(consumedPath)) {
|
|
48874
|
+
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
48875
|
+
fs15.unlinkSync(consumedPath);
|
|
48876
|
+
}
|
|
48877
|
+
fs15.renameSync(handoffPath, consumedPath);
|
|
48878
|
+
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
48879
|
+
The previous model's session ended. Here is your starting context:
|
|
48880
|
+
|
|
48881
|
+
${handoffContent}`;
|
|
48882
|
+
tryInject(`[HANDOFF BRIEF]
|
|
48883
|
+
${handoffBlock}`);
|
|
48884
|
+
}
|
|
48885
|
+
} catch (error93) {
|
|
48886
|
+
if (error93?.code !== "ENOENT") {
|
|
48887
|
+
warn("Handoff injection failed:", error93);
|
|
48888
|
+
}
|
|
48889
|
+
}
|
|
48890
|
+
}
|
|
48293
48891
|
if (mode !== "DISCOVER" && contextContent) {
|
|
48294
|
-
const decisions =
|
|
48892
|
+
const decisions = extractDecisions2(contextContent, 200);
|
|
48295
48893
|
if (decisions) {
|
|
48296
48894
|
tryInject(`[SWARM CONTEXT] Key decisions: ${decisions}`);
|
|
48297
48895
|
}
|
|
@@ -48449,6 +49047,37 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
48449
49047
|
}
|
|
48450
49048
|
}
|
|
48451
49049
|
}
|
|
49050
|
+
const userConfig = config3.context_budget;
|
|
49051
|
+
const defaultConfig = {
|
|
49052
|
+
enabled: true,
|
|
49053
|
+
budgetTokens: 40000,
|
|
49054
|
+
warningPct: 70,
|
|
49055
|
+
criticalPct: 90,
|
|
49056
|
+
warningMode: "once",
|
|
49057
|
+
warningIntervalTurns: 20
|
|
49058
|
+
};
|
|
49059
|
+
const contextBudgetConfig = userConfig ? {
|
|
49060
|
+
...defaultConfig,
|
|
49061
|
+
...userConfig,
|
|
49062
|
+
warningPct: userConfig.warn_threshold ? userConfig.warn_threshold * 100 : defaultConfig.warningPct,
|
|
49063
|
+
criticalPct: userConfig.critical_threshold ? userConfig.critical_threshold * 100 : defaultConfig.criticalPct,
|
|
49064
|
+
budgetTokens: userConfig.model_limits?.default ?? defaultConfig.budgetTokens
|
|
49065
|
+
} : defaultConfig;
|
|
49066
|
+
if (contextBudgetConfig.enabled !== false) {
|
|
49067
|
+
const assembledSystemPrompt = output.system.join(`
|
|
49068
|
+
`);
|
|
49069
|
+
const budgetReport = await getContextBudgetReport(directory, assembledSystemPrompt, contextBudgetConfig);
|
|
49070
|
+
const budgetWarning = await formatBudgetWarning(budgetReport, directory, contextBudgetConfig);
|
|
49071
|
+
if (budgetWarning) {
|
|
49072
|
+
const sessionId_cb = _input.sessionID;
|
|
49073
|
+
const activeAgent_cb = sessionId_cb ? swarmState.activeAgent.get(sessionId_cb) : null;
|
|
49074
|
+
const isArchitect_cb = !activeAgent_cb || stripKnownSwarmPrefix(activeAgent_cb) === "architect";
|
|
49075
|
+
if (isArchitect_cb) {
|
|
49076
|
+
output.system.push(`[FOR: architect]
|
|
49077
|
+
${budgetWarning}`);
|
|
49078
|
+
}
|
|
49079
|
+
}
|
|
49080
|
+
}
|
|
48452
49081
|
return;
|
|
48453
49082
|
}
|
|
48454
49083
|
const mode_b = await detectArchitectMode(directory);
|
|
@@ -48470,7 +49099,7 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
48470
49099
|
let currentPhase = null;
|
|
48471
49100
|
let currentTask = null;
|
|
48472
49101
|
if (plan && plan.migration_status !== "migration_failed") {
|
|
48473
|
-
currentPhase =
|
|
49102
|
+
currentPhase = extractCurrentPhaseFromPlan2(plan);
|
|
48474
49103
|
currentTask = extractCurrentTaskFromPlan(plan);
|
|
48475
49104
|
} else {
|
|
48476
49105
|
planContentForCursor = await readSwarmFileAsync(directory, "plan.md");
|
|
@@ -48515,8 +49144,40 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
48515
49144
|
metadata: { contentType: "markdown" }
|
|
48516
49145
|
});
|
|
48517
49146
|
}
|
|
49147
|
+
if (mode_b !== "DISCOVER") {
|
|
49148
|
+
try {
|
|
49149
|
+
const handoffContent = await readSwarmFileAsync(directory, "handoff.md");
|
|
49150
|
+
if (handoffContent) {
|
|
49151
|
+
const handoffPath = validateSwarmPath(directory, "handoff.md");
|
|
49152
|
+
const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
|
|
49153
|
+
if (fs15.existsSync(consumedPath)) {
|
|
49154
|
+
warn("Duplicate handoff detected: handoff-consumed.md already exists");
|
|
49155
|
+
fs15.unlinkSync(consumedPath);
|
|
49156
|
+
}
|
|
49157
|
+
fs15.renameSync(handoffPath, consumedPath);
|
|
49158
|
+
const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
|
|
49159
|
+
The previous model's session ended. Here is your starting context:
|
|
49160
|
+
|
|
49161
|
+
${handoffContent}`;
|
|
49162
|
+
const handoffText = `[HANDOFF BRIEF]
|
|
49163
|
+
${handoffBlock}`;
|
|
49164
|
+
candidates.push({
|
|
49165
|
+
id: `candidate-${idCounter++}`,
|
|
49166
|
+
kind: "phase",
|
|
49167
|
+
text: handoffText,
|
|
49168
|
+
tokens: estimateTokens(handoffText),
|
|
49169
|
+
priority: 1,
|
|
49170
|
+
metadata: { contentType: "markdown" }
|
|
49171
|
+
});
|
|
49172
|
+
}
|
|
49173
|
+
} catch (error93) {
|
|
49174
|
+
if (error93?.code !== "ENOENT") {
|
|
49175
|
+
warn("Handoff injection failed:", error93);
|
|
49176
|
+
}
|
|
49177
|
+
}
|
|
49178
|
+
}
|
|
48518
49179
|
if (contextContent) {
|
|
48519
|
-
const decisions =
|
|
49180
|
+
const decisions = extractDecisions2(contextContent, 200);
|
|
48520
49181
|
if (decisions) {
|
|
48521
49182
|
const text = `[SWARM CONTEXT] Key decisions: ${decisions}`;
|
|
48522
49183
|
candidates.push({
|
|
@@ -48786,6 +49447,37 @@ function createSystemEnhancerHook(config3, directory) {
|
|
|
48786
49447
|
output.system.push(candidate.text);
|
|
48787
49448
|
injectedTokens += candidate.tokens;
|
|
48788
49449
|
}
|
|
49450
|
+
const userConfig_b = config3.context_budget;
|
|
49451
|
+
const defaultConfig_b = {
|
|
49452
|
+
enabled: true,
|
|
49453
|
+
budgetTokens: 40000,
|
|
49454
|
+
warningPct: 70,
|
|
49455
|
+
criticalPct: 90,
|
|
49456
|
+
warningMode: "once",
|
|
49457
|
+
warningIntervalTurns: 20
|
|
49458
|
+
};
|
|
49459
|
+
const contextBudgetConfig_b = userConfig_b ? {
|
|
49460
|
+
...defaultConfig_b,
|
|
49461
|
+
...userConfig_b,
|
|
49462
|
+
warningPct: userConfig_b.warn_threshold ? userConfig_b.warn_threshold * 100 : defaultConfig_b.warningPct,
|
|
49463
|
+
criticalPct: userConfig_b.critical_threshold ? userConfig_b.critical_threshold * 100 : defaultConfig_b.criticalPct,
|
|
49464
|
+
budgetTokens: userConfig_b.model_limits?.default ?? defaultConfig_b.budgetTokens
|
|
49465
|
+
} : defaultConfig_b;
|
|
49466
|
+
if (contextBudgetConfig_b.enabled !== false) {
|
|
49467
|
+
const assembledSystemPrompt_b = output.system.join(`
|
|
49468
|
+
`);
|
|
49469
|
+
const budgetReport_b = await getContextBudgetReport(directory, assembledSystemPrompt_b, contextBudgetConfig_b);
|
|
49470
|
+
const budgetWarning_b = await formatBudgetWarning(budgetReport_b, directory, contextBudgetConfig_b);
|
|
49471
|
+
if (budgetWarning_b) {
|
|
49472
|
+
const sessionId_cb_b = _input.sessionID;
|
|
49473
|
+
const activeAgent_cb_b = sessionId_cb_b ? swarmState.activeAgent.get(sessionId_cb_b) : null;
|
|
49474
|
+
const isArchitect_cb_b = !activeAgent_cb_b || stripKnownSwarmPrefix(activeAgent_cb_b) === "architect";
|
|
49475
|
+
if (isArchitect_cb_b) {
|
|
49476
|
+
output.system.push(`[FOR: architect]
|
|
49477
|
+
${budgetWarning_b}`);
|
|
49478
|
+
}
|
|
49479
|
+
}
|
|
49480
|
+
}
|
|
48789
49481
|
} catch (error93) {
|
|
48790
49482
|
warn("System enhancer failed:", error93);
|
|
48791
49483
|
}
|
|
@@ -49134,9 +49826,9 @@ function createDarkMatterDetectorHook(directory) {
|
|
|
49134
49826
|
}
|
|
49135
49827
|
|
|
49136
49828
|
// src/hooks/knowledge-reader.ts
|
|
49137
|
-
import { existsSync as
|
|
49829
|
+
import { existsSync as existsSync18 } from "fs";
|
|
49138
49830
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
49139
|
-
import * as
|
|
49831
|
+
import * as path27 from "path";
|
|
49140
49832
|
var JACCARD_THRESHOLD = 0.6;
|
|
49141
49833
|
var HIVE_TIER_BOOST = 0.05;
|
|
49142
49834
|
var SAME_PROJECT_PENALTY = -0.05;
|
|
@@ -49184,15 +49876,15 @@ function inferCategoriesFromPhase(phaseDescription) {
|
|
|
49184
49876
|
return ["process", "tooling"];
|
|
49185
49877
|
}
|
|
49186
49878
|
async function recordLessonsShown(directory, lessonIds, currentPhase) {
|
|
49187
|
-
const shownFile =
|
|
49879
|
+
const shownFile = path27.join(directory, ".swarm", ".knowledge-shown.json");
|
|
49188
49880
|
try {
|
|
49189
49881
|
let shownData = {};
|
|
49190
|
-
if (
|
|
49882
|
+
if (existsSync18(shownFile)) {
|
|
49191
49883
|
const content = await readFile4(shownFile, "utf-8");
|
|
49192
49884
|
shownData = JSON.parse(content);
|
|
49193
49885
|
}
|
|
49194
49886
|
shownData[currentPhase] = lessonIds;
|
|
49195
|
-
await mkdir4(
|
|
49887
|
+
await mkdir4(path27.dirname(shownFile), { recursive: true });
|
|
49196
49888
|
await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
49197
49889
|
} catch {
|
|
49198
49890
|
console.warn("[swarm] Knowledge: failed to record shown lessons");
|
|
@@ -49287,9 +49979,9 @@ async function readMergedKnowledge(directory, config3, context) {
|
|
|
49287
49979
|
return topN;
|
|
49288
49980
|
}
|
|
49289
49981
|
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
49290
|
-
const shownFile =
|
|
49982
|
+
const shownFile = path27.join(directory, ".swarm", ".knowledge-shown.json");
|
|
49291
49983
|
try {
|
|
49292
|
-
if (!
|
|
49984
|
+
if (!existsSync18(shownFile)) {
|
|
49293
49985
|
return;
|
|
49294
49986
|
}
|
|
49295
49987
|
const content = await readFile4(shownFile, "utf-8");
|
|
@@ -49651,6 +50343,111 @@ function createKnowledgeCuratorHook(directory, config3) {
|
|
|
49651
50343
|
|
|
49652
50344
|
// src/hooks/knowledge-injector.ts
|
|
49653
50345
|
init_manager2();
|
|
50346
|
+
|
|
50347
|
+
// src/services/run-memory.ts
|
|
50348
|
+
init_utils2();
|
|
50349
|
+
function validateDirectory2(directory) {
|
|
50350
|
+
if (!directory || directory.trim() === "") {
|
|
50351
|
+
throw new Error("Invalid directory: empty");
|
|
50352
|
+
}
|
|
50353
|
+
if (/\.\.[/\\]/.test(directory)) {
|
|
50354
|
+
throw new Error("Invalid directory: path traversal detected");
|
|
50355
|
+
}
|
|
50356
|
+
if (directory.startsWith("/") || directory.startsWith("\\")) {
|
|
50357
|
+
throw new Error("Invalid directory: absolute path");
|
|
50358
|
+
}
|
|
50359
|
+
if (/^[A-Za-z]:[\\/]/.test(directory)) {
|
|
50360
|
+
throw new Error("Invalid directory: Windows absolute path");
|
|
50361
|
+
}
|
|
50362
|
+
}
|
|
50363
|
+
var RUN_MEMORY_FILENAME = "run-memory.jsonl";
|
|
50364
|
+
var MAX_SUMMARY_TOKENS = 500;
|
|
50365
|
+
function groupByTaskId(entries) {
|
|
50366
|
+
const groups = new Map;
|
|
50367
|
+
for (const entry of entries) {
|
|
50368
|
+
const existing = groups.get(entry.taskId) || [];
|
|
50369
|
+
existing.push(entry);
|
|
50370
|
+
groups.set(entry.taskId, existing);
|
|
50371
|
+
}
|
|
50372
|
+
return groups;
|
|
50373
|
+
}
|
|
50374
|
+
function summarizeTask(taskId, entries) {
|
|
50375
|
+
const failures = entries.filter((e) => e.outcome === "fail" || e.outcome === "retry");
|
|
50376
|
+
const passes = entries.filter((e) => e.outcome === "pass");
|
|
50377
|
+
if (failures.length === 0) {
|
|
50378
|
+
return null;
|
|
50379
|
+
}
|
|
50380
|
+
failures.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
50381
|
+
const lastFailure = failures[0];
|
|
50382
|
+
passes.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
50383
|
+
const lastPass = passes[0];
|
|
50384
|
+
const failCount = failures.length;
|
|
50385
|
+
if (lastPass) {
|
|
50386
|
+
const passAttempt = lastPass.attemptNumber;
|
|
50387
|
+
const failAttempt = lastFailure.attemptNumber;
|
|
50388
|
+
return `Task ${taskId}: FAILED attempt ${failAttempt} \u2014 ${lastFailure.failureReason || "unknown"}. Passed on attempt ${passAttempt}.`;
|
|
50389
|
+
} else {
|
|
50390
|
+
return `Task ${taskId}: FAILED ${failCount} times \u2014 last: ${lastFailure.failureReason || "unknown"}. Still failing.`;
|
|
50391
|
+
}
|
|
50392
|
+
}
|
|
50393
|
+
async function getRunMemorySummary(directory) {
|
|
50394
|
+
validateDirectory2(directory);
|
|
50395
|
+
const content = await readSwarmFileAsync(directory, RUN_MEMORY_FILENAME);
|
|
50396
|
+
if (!content) {
|
|
50397
|
+
return null;
|
|
50398
|
+
}
|
|
50399
|
+
const entries = [];
|
|
50400
|
+
const lines = content.split(`
|
|
50401
|
+
`);
|
|
50402
|
+
for (const line of lines) {
|
|
50403
|
+
if (!line.trim())
|
|
50404
|
+
continue;
|
|
50405
|
+
try {
|
|
50406
|
+
const entry = JSON.parse(line);
|
|
50407
|
+
entries.push(entry);
|
|
50408
|
+
} catch {}
|
|
50409
|
+
}
|
|
50410
|
+
if (entries.length === 0) {
|
|
50411
|
+
return null;
|
|
50412
|
+
}
|
|
50413
|
+
const groups = groupByTaskId(entries);
|
|
50414
|
+
const summaries = [];
|
|
50415
|
+
for (const [taskId, taskEntries] of groups) {
|
|
50416
|
+
const summary = summarizeTask(taskId, taskEntries);
|
|
50417
|
+
if (summary) {
|
|
50418
|
+
summaries.push(summary);
|
|
50419
|
+
}
|
|
50420
|
+
}
|
|
50421
|
+
if (summaries.length === 0) {
|
|
50422
|
+
return null;
|
|
50423
|
+
}
|
|
50424
|
+
const prefix = `[FOR: architect, coder]
|
|
50425
|
+
## RUN MEMORY \u2014 Previous Task Outcomes
|
|
50426
|
+
`;
|
|
50427
|
+
const suffix = `
|
|
50428
|
+
Use this data to avoid repeating known failure patterns.`;
|
|
50429
|
+
let summaryText = summaries.join(`
|
|
50430
|
+
`);
|
|
50431
|
+
const estimateTokens3 = (text) => {
|
|
50432
|
+
return Math.ceil(text.length * 0.33);
|
|
50433
|
+
};
|
|
50434
|
+
const totalText = prefix + summaryText + suffix;
|
|
50435
|
+
const estimatedTokens = estimateTokens3(totalText);
|
|
50436
|
+
if (estimatedTokens > MAX_SUMMARY_TOKENS) {
|
|
50437
|
+
const prefixTokens = estimateTokens3(prefix);
|
|
50438
|
+
const suffixTokens = estimateTokens3(suffix);
|
|
50439
|
+
const availableContentTokens = MAX_SUMMARY_TOKENS - prefixTokens - suffixTokens;
|
|
50440
|
+
if (availableContentTokens > 0) {
|
|
50441
|
+
const maxContentChars = Math.floor(availableContentTokens / 0.33);
|
|
50442
|
+
summaryText = summaryText.slice(-maxContentChars);
|
|
50443
|
+
} else {
|
|
50444
|
+
summaryText = "";
|
|
50445
|
+
}
|
|
50446
|
+
}
|
|
50447
|
+
return prefix + summaryText + suffix;
|
|
50448
|
+
}
|
|
50449
|
+
|
|
50450
|
+
// src/hooks/knowledge-injector.ts
|
|
49654
50451
|
init_utils2();
|
|
49655
50452
|
function formatStars(confidence) {
|
|
49656
50453
|
if (confidence >= 0.9)
|
|
@@ -49724,7 +50521,7 @@ function createKnowledgeInjectorHook(directory, config3) {
|
|
|
49724
50521
|
lastSeenPhase = currentPhase;
|
|
49725
50522
|
cachedInjectionText = null;
|
|
49726
50523
|
}
|
|
49727
|
-
const phaseDescription =
|
|
50524
|
+
const phaseDescription = extractCurrentPhaseFromPlan2(plan) ?? `Phase ${currentPhase}`;
|
|
49728
50525
|
const context = {
|
|
49729
50526
|
projectName: plan.title,
|
|
49730
50527
|
currentPhase: phaseDescription
|
|
@@ -49732,6 +50529,7 @@ function createKnowledgeInjectorHook(directory, config3) {
|
|
|
49732
50529
|
const entries = await readMergedKnowledge(directory, config3, context);
|
|
49733
50530
|
if (entries.length === 0)
|
|
49734
50531
|
return;
|
|
50532
|
+
const runMemory = await getRunMemorySummary(directory);
|
|
49735
50533
|
const lines = entries.map((entry) => {
|
|
49736
50534
|
const stars = formatStars(entry.confidence);
|
|
49737
50535
|
const tierLabel = entry.tier === "hive" ? "[HIVE]" : "[SWARM]";
|
|
@@ -49741,7 +50539,7 @@ function createKnowledgeInjectorHook(directory, config3) {
|
|
|
49741
50539
|
const source = rawSource !== null ? ` \u2014 Source: ${sanitizeLessonForContext(rawSource)}` : "";
|
|
49742
50540
|
return `${stars} ${tierLabel} ${sanitizeLessonForContext(entry.lesson)}${source}${confirmText}`;
|
|
49743
50541
|
});
|
|
49744
|
-
|
|
50542
|
+
const knowledgeSection = [
|
|
49745
50543
|
`\uD83D\uDCDA Knowledge (${entries.length} relevant lesson${entries.length > 1 ? "s" : ""}):`,
|
|
49746
50544
|
"",
|
|
49747
50545
|
...lines,
|
|
@@ -49749,6 +50547,13 @@ function createKnowledgeInjectorHook(directory, config3) {
|
|
|
49749
50547
|
"These are lessons learned from this project and past projects. Consider them as context but use your judgment \u2014 they may not all apply."
|
|
49750
50548
|
].join(`
|
|
49751
50549
|
`);
|
|
50550
|
+
if (runMemory) {
|
|
50551
|
+
cachedInjectionText = runMemory + `
|
|
50552
|
+
|
|
50553
|
+
` + knowledgeSection;
|
|
50554
|
+
} else {
|
|
50555
|
+
cachedInjectionText = knowledgeSection;
|
|
50556
|
+
}
|
|
49752
50557
|
const rejected = await readRejectedLessons(directory);
|
|
49753
50558
|
if (rejected.length > 0) {
|
|
49754
50559
|
const recentRejected = rejected.slice(-3);
|
|
@@ -49765,7 +50570,7 @@ function createKnowledgeInjectorHook(directory, config3) {
|
|
|
49765
50570
|
|
|
49766
50571
|
// src/hooks/steering-consumed.ts
|
|
49767
50572
|
init_utils2();
|
|
49768
|
-
import * as
|
|
50573
|
+
import * as fs16 from "fs";
|
|
49769
50574
|
function recordSteeringConsumed(directory, directiveId) {
|
|
49770
50575
|
try {
|
|
49771
50576
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
@@ -49774,7 +50579,7 @@ function recordSteeringConsumed(directory, directiveId) {
|
|
|
49774
50579
|
directiveId,
|
|
49775
50580
|
timestamp: new Date().toISOString()
|
|
49776
50581
|
};
|
|
49777
|
-
|
|
50582
|
+
fs16.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
49778
50583
|
`, "utf-8");
|
|
49779
50584
|
} catch {}
|
|
49780
50585
|
}
|
|
@@ -49919,95 +50724,6 @@ async function loadSnapshot(directory) {
|
|
|
49919
50724
|
} catch {}
|
|
49920
50725
|
}
|
|
49921
50726
|
|
|
49922
|
-
// src/session/snapshot-writer.ts
|
|
49923
|
-
init_utils2();
|
|
49924
|
-
import { mkdirSync as mkdirSync6, renameSync as renameSync5 } from "fs";
|
|
49925
|
-
import * as path27 from "path";
|
|
49926
|
-
function serializeAgentSession(s) {
|
|
49927
|
-
const gateLog = {};
|
|
49928
|
-
const rawGateLog = s.gateLog ?? new Map;
|
|
49929
|
-
for (const [taskId, gates] of rawGateLog) {
|
|
49930
|
-
gateLog[taskId] = Array.from(gates ?? []);
|
|
49931
|
-
}
|
|
49932
|
-
const reviewerCallCount = {};
|
|
49933
|
-
const rawReviewerCallCount = s.reviewerCallCount ?? new Map;
|
|
49934
|
-
for (const [phase, count] of rawReviewerCallCount) {
|
|
49935
|
-
reviewerCallCount[String(phase)] = count;
|
|
49936
|
-
}
|
|
49937
|
-
const partialGateWarningsIssuedForTask = Array.from(s.partialGateWarningsIssuedForTask ?? new Set);
|
|
49938
|
-
const catastrophicPhaseWarnings = Array.from(s.catastrophicPhaseWarnings ?? new Set);
|
|
49939
|
-
const phaseAgentsDispatched = Array.from(s.phaseAgentsDispatched ?? new Set);
|
|
49940
|
-
const windows = {};
|
|
49941
|
-
const rawWindows = s.windows ?? {};
|
|
49942
|
-
for (const [key, win] of Object.entries(rawWindows)) {
|
|
49943
|
-
windows[key] = {
|
|
49944
|
-
id: win.id,
|
|
49945
|
-
agentName: win.agentName,
|
|
49946
|
-
startedAtMs: win.startedAtMs,
|
|
49947
|
-
toolCalls: win.toolCalls,
|
|
49948
|
-
consecutiveErrors: win.consecutiveErrors,
|
|
49949
|
-
hardLimitHit: win.hardLimitHit,
|
|
49950
|
-
lastSuccessTimeMs: win.lastSuccessTimeMs,
|
|
49951
|
-
recentToolCalls: win.recentToolCalls,
|
|
49952
|
-
warningIssued: win.warningIssued,
|
|
49953
|
-
warningReason: win.warningReason
|
|
49954
|
-
};
|
|
49955
|
-
}
|
|
49956
|
-
return {
|
|
49957
|
-
agentName: s.agentName,
|
|
49958
|
-
lastToolCallTime: s.lastToolCallTime,
|
|
49959
|
-
lastAgentEventTime: s.lastAgentEventTime,
|
|
49960
|
-
delegationActive: s.delegationActive,
|
|
49961
|
-
activeInvocationId: s.activeInvocationId,
|
|
49962
|
-
lastInvocationIdByAgent: s.lastInvocationIdByAgent ?? {},
|
|
49963
|
-
windows,
|
|
49964
|
-
lastCompactionHint: s.lastCompactionHint ?? 0,
|
|
49965
|
-
architectWriteCount: s.architectWriteCount ?? 0,
|
|
49966
|
-
lastCoderDelegationTaskId: s.lastCoderDelegationTaskId ?? null,
|
|
49967
|
-
currentTaskId: s.currentTaskId ?? null,
|
|
49968
|
-
gateLog,
|
|
49969
|
-
reviewerCallCount,
|
|
49970
|
-
lastGateFailure: s.lastGateFailure ?? null,
|
|
49971
|
-
partialGateWarningsIssuedForTask,
|
|
49972
|
-
selfFixAttempted: s.selfFixAttempted ?? false,
|
|
49973
|
-
catastrophicPhaseWarnings,
|
|
49974
|
-
lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
|
|
49975
|
-
lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
|
|
49976
|
-
phaseAgentsDispatched,
|
|
49977
|
-
qaSkipCount: s.qaSkipCount ?? 0,
|
|
49978
|
-
qaSkipTaskIds: s.qaSkipTaskIds ?? []
|
|
49979
|
-
};
|
|
49980
|
-
}
|
|
49981
|
-
async function writeSnapshot(directory, state) {
|
|
49982
|
-
try {
|
|
49983
|
-
const snapshot = {
|
|
49984
|
-
version: 1,
|
|
49985
|
-
writtenAt: Date.now(),
|
|
49986
|
-
toolAggregates: Object.fromEntries(state.toolAggregates),
|
|
49987
|
-
activeAgent: Object.fromEntries(state.activeAgent),
|
|
49988
|
-
delegationChains: Object.fromEntries(state.delegationChains),
|
|
49989
|
-
agentSessions: {}
|
|
49990
|
-
};
|
|
49991
|
-
for (const [sessionId, sessionState] of state.agentSessions) {
|
|
49992
|
-
snapshot.agentSessions[sessionId] = serializeAgentSession(sessionState);
|
|
49993
|
-
}
|
|
49994
|
-
const content = JSON.stringify(snapshot, null, 2);
|
|
49995
|
-
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
49996
|
-
const dir = path27.dirname(resolvedPath);
|
|
49997
|
-
mkdirSync6(dir, { recursive: true });
|
|
49998
|
-
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
49999
|
-
await Bun.write(tempPath, content);
|
|
50000
|
-
renameSync5(tempPath, resolvedPath);
|
|
50001
|
-
} catch {}
|
|
50002
|
-
}
|
|
50003
|
-
function createSnapshotWriterHook(directory) {
|
|
50004
|
-
return async (_input, _output) => {
|
|
50005
|
-
try {
|
|
50006
|
-
await writeSnapshot(directory, swarmState);
|
|
50007
|
-
} catch {}
|
|
50008
|
-
};
|
|
50009
|
-
}
|
|
50010
|
-
|
|
50011
50727
|
// src/tools/build-check.ts
|
|
50012
50728
|
init_dist();
|
|
50013
50729
|
init_discovery();
|
|
@@ -50183,7 +50899,7 @@ var build_check = createSwarmTool({
|
|
|
50183
50899
|
init_tool();
|
|
50184
50900
|
init_create_tool();
|
|
50185
50901
|
import { spawnSync } from "child_process";
|
|
50186
|
-
import * as
|
|
50902
|
+
import * as fs17 from "fs";
|
|
50187
50903
|
import * as path28 from "path";
|
|
50188
50904
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
50189
50905
|
var MAX_LABEL_LENGTH = 100;
|
|
@@ -50240,8 +50956,8 @@ function getCheckpointLogPath(directory) {
|
|
|
50240
50956
|
function readCheckpointLog(directory) {
|
|
50241
50957
|
const logPath = getCheckpointLogPath(directory);
|
|
50242
50958
|
try {
|
|
50243
|
-
if (
|
|
50244
|
-
const content =
|
|
50959
|
+
if (fs17.existsSync(logPath)) {
|
|
50960
|
+
const content = fs17.readFileSync(logPath, "utf-8");
|
|
50245
50961
|
const parsed = JSON.parse(content);
|
|
50246
50962
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
50247
50963
|
return { version: 1, checkpoints: [] };
|
|
@@ -50254,12 +50970,12 @@ function readCheckpointLog(directory) {
|
|
|
50254
50970
|
function writeCheckpointLog(log2, directory) {
|
|
50255
50971
|
const logPath = getCheckpointLogPath(directory);
|
|
50256
50972
|
const dir = path28.dirname(logPath);
|
|
50257
|
-
if (!
|
|
50258
|
-
|
|
50973
|
+
if (!fs17.existsSync(dir)) {
|
|
50974
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
50259
50975
|
}
|
|
50260
50976
|
const tempPath = `${logPath}.tmp`;
|
|
50261
|
-
|
|
50262
|
-
|
|
50977
|
+
fs17.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
50978
|
+
fs17.renameSync(tempPath, logPath);
|
|
50263
50979
|
}
|
|
50264
50980
|
function gitExec(args2) {
|
|
50265
50981
|
const result = spawnSync("git", args2, {
|
|
@@ -50460,7 +51176,7 @@ var checkpoint = createSwarmTool({
|
|
|
50460
51176
|
// src/tools/complexity-hotspots.ts
|
|
50461
51177
|
init_dist();
|
|
50462
51178
|
init_create_tool();
|
|
50463
|
-
import * as
|
|
51179
|
+
import * as fs18 from "fs";
|
|
50464
51180
|
import * as path29 from "path";
|
|
50465
51181
|
var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
|
|
50466
51182
|
var DEFAULT_DAYS = 90;
|
|
@@ -50589,11 +51305,11 @@ function estimateComplexity(content) {
|
|
|
50589
51305
|
}
|
|
50590
51306
|
function getComplexityForFile(filePath) {
|
|
50591
51307
|
try {
|
|
50592
|
-
const stat2 =
|
|
51308
|
+
const stat2 = fs18.statSync(filePath);
|
|
50593
51309
|
if (stat2.size > MAX_FILE_SIZE_BYTES2) {
|
|
50594
51310
|
return null;
|
|
50595
51311
|
}
|
|
50596
|
-
const content =
|
|
51312
|
+
const content = fs18.readFileSync(filePath, "utf-8");
|
|
50597
51313
|
return estimateComplexity(content);
|
|
50598
51314
|
} catch {
|
|
50599
51315
|
return null;
|
|
@@ -50614,7 +51330,7 @@ async function analyzeHotspots(days, topN, extensions) {
|
|
|
50614
51330
|
let analyzedFiles = 0;
|
|
50615
51331
|
for (const [file3, churnCount] of filteredChurn) {
|
|
50616
51332
|
let fullPath = file3;
|
|
50617
|
-
if (!
|
|
51333
|
+
if (!fs18.existsSync(fullPath)) {
|
|
50618
51334
|
fullPath = path29.join(cwd, file3);
|
|
50619
51335
|
}
|
|
50620
51336
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -51086,7 +51802,7 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
51086
51802
|
// src/tools/evidence-check.ts
|
|
51087
51803
|
init_dist();
|
|
51088
51804
|
init_create_tool();
|
|
51089
|
-
import * as
|
|
51805
|
+
import * as fs19 from "fs";
|
|
51090
51806
|
import * as path30 from "path";
|
|
51091
51807
|
var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
|
|
51092
51808
|
var MAX_EVIDENCE_FILES = 1000;
|
|
@@ -51128,12 +51844,12 @@ function parseCompletedTasks(planContent) {
|
|
|
51128
51844
|
}
|
|
51129
51845
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
51130
51846
|
const evidence = [];
|
|
51131
|
-
if (!
|
|
51847
|
+
if (!fs19.existsSync(evidenceDir) || !fs19.statSync(evidenceDir).isDirectory()) {
|
|
51132
51848
|
return evidence;
|
|
51133
51849
|
}
|
|
51134
51850
|
let files;
|
|
51135
51851
|
try {
|
|
51136
|
-
files =
|
|
51852
|
+
files = fs19.readdirSync(evidenceDir);
|
|
51137
51853
|
} catch {
|
|
51138
51854
|
return evidence;
|
|
51139
51855
|
}
|
|
@@ -51149,7 +51865,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
51149
51865
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
51150
51866
|
continue;
|
|
51151
51867
|
}
|
|
51152
|
-
const stat2 =
|
|
51868
|
+
const stat2 = fs19.lstatSync(filePath);
|
|
51153
51869
|
if (!stat2.isFile()) {
|
|
51154
51870
|
continue;
|
|
51155
51871
|
}
|
|
@@ -51158,7 +51874,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
51158
51874
|
}
|
|
51159
51875
|
let fileStat;
|
|
51160
51876
|
try {
|
|
51161
|
-
fileStat =
|
|
51877
|
+
fileStat = fs19.statSync(filePath);
|
|
51162
51878
|
if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
|
|
51163
51879
|
continue;
|
|
51164
51880
|
}
|
|
@@ -51167,7 +51883,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
51167
51883
|
}
|
|
51168
51884
|
let content;
|
|
51169
51885
|
try {
|
|
51170
|
-
content =
|
|
51886
|
+
content = fs19.readFileSync(filePath, "utf-8");
|
|
51171
51887
|
} catch {
|
|
51172
51888
|
continue;
|
|
51173
51889
|
}
|
|
@@ -51266,7 +51982,7 @@ var evidence_check = createSwarmTool({
|
|
|
51266
51982
|
}
|
|
51267
51983
|
let planContent;
|
|
51268
51984
|
try {
|
|
51269
|
-
planContent =
|
|
51985
|
+
planContent = fs19.readFileSync(planPath, "utf-8");
|
|
51270
51986
|
} catch {
|
|
51271
51987
|
const result2 = {
|
|
51272
51988
|
message: "No completed tasks found in plan.",
|
|
@@ -51301,7 +52017,7 @@ var evidence_check = createSwarmTool({
|
|
|
51301
52017
|
// src/tools/file-extractor.ts
|
|
51302
52018
|
init_tool();
|
|
51303
52019
|
init_create_tool();
|
|
51304
|
-
import * as
|
|
52020
|
+
import * as fs20 from "fs";
|
|
51305
52021
|
import * as path31 from "path";
|
|
51306
52022
|
var EXT_MAP = {
|
|
51307
52023
|
python: ".py",
|
|
@@ -51364,8 +52080,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
51364
52080
|
execute: async (args2, directory) => {
|
|
51365
52081
|
const { content, output_dir, prefix } = args2;
|
|
51366
52082
|
const targetDir = output_dir || directory;
|
|
51367
|
-
if (!
|
|
51368
|
-
|
|
52083
|
+
if (!fs20.existsSync(targetDir)) {
|
|
52084
|
+
fs20.mkdirSync(targetDir, { recursive: true });
|
|
51369
52085
|
}
|
|
51370
52086
|
if (!content) {
|
|
51371
52087
|
return "Error: content is required";
|
|
@@ -51387,12 +52103,12 @@ var extract_code_blocks = createSwarmTool({
|
|
|
51387
52103
|
const base = path31.basename(filepath, path31.extname(filepath));
|
|
51388
52104
|
const ext = path31.extname(filepath);
|
|
51389
52105
|
let counter = 1;
|
|
51390
|
-
while (
|
|
52106
|
+
while (fs20.existsSync(filepath)) {
|
|
51391
52107
|
filepath = path31.join(targetDir, `${base}_${counter}${ext}`);
|
|
51392
52108
|
counter++;
|
|
51393
52109
|
}
|
|
51394
52110
|
try {
|
|
51395
|
-
|
|
52111
|
+
fs20.writeFileSync(filepath, code.trim(), "utf-8");
|
|
51396
52112
|
savedFiles.push(filepath);
|
|
51397
52113
|
} catch (error93) {
|
|
51398
52114
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -51500,7 +52216,7 @@ var gitingest = tool({
|
|
|
51500
52216
|
});
|
|
51501
52217
|
// src/tools/imports.ts
|
|
51502
52218
|
init_dist();
|
|
51503
|
-
import * as
|
|
52219
|
+
import * as fs21 from "fs";
|
|
51504
52220
|
import * as path32 from "path";
|
|
51505
52221
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
51506
52222
|
var MAX_SYMBOL_LENGTH = 256;
|
|
@@ -51669,7 +52385,7 @@ var SKIP_DIRECTORIES2 = new Set([
|
|
|
51669
52385
|
function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
51670
52386
|
let entries;
|
|
51671
52387
|
try {
|
|
51672
|
-
entries =
|
|
52388
|
+
entries = fs21.readdirSync(dir);
|
|
51673
52389
|
} catch (e) {
|
|
51674
52390
|
stats.fileErrors.push({
|
|
51675
52391
|
path: dir,
|
|
@@ -51686,7 +52402,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
51686
52402
|
const fullPath = path32.join(dir, entry);
|
|
51687
52403
|
let stat2;
|
|
51688
52404
|
try {
|
|
51689
|
-
stat2 =
|
|
52405
|
+
stat2 = fs21.statSync(fullPath);
|
|
51690
52406
|
} catch (e) {
|
|
51691
52407
|
stats.fileErrors.push({
|
|
51692
52408
|
path: fullPath,
|
|
@@ -51754,7 +52470,7 @@ var imports = tool({
|
|
|
51754
52470
|
}
|
|
51755
52471
|
try {
|
|
51756
52472
|
const targetFile = path32.resolve(file3);
|
|
51757
|
-
if (!
|
|
52473
|
+
if (!fs21.existsSync(targetFile)) {
|
|
51758
52474
|
const errorResult = {
|
|
51759
52475
|
error: `target file not found: ${file3}`,
|
|
51760
52476
|
target: file3,
|
|
@@ -51764,7 +52480,7 @@ var imports = tool({
|
|
|
51764
52480
|
};
|
|
51765
52481
|
return JSON.stringify(errorResult, null, 2);
|
|
51766
52482
|
}
|
|
51767
|
-
const targetStat =
|
|
52483
|
+
const targetStat = fs21.statSync(targetFile);
|
|
51768
52484
|
if (!targetStat.isFile()) {
|
|
51769
52485
|
const errorResult = {
|
|
51770
52486
|
error: "target must be a file, not a directory",
|
|
@@ -51790,12 +52506,12 @@ var imports = tool({
|
|
|
51790
52506
|
if (consumers.length >= MAX_CONSUMERS)
|
|
51791
52507
|
break;
|
|
51792
52508
|
try {
|
|
51793
|
-
const stat2 =
|
|
52509
|
+
const stat2 = fs21.statSync(filePath);
|
|
51794
52510
|
if (stat2.size > MAX_FILE_SIZE_BYTES4) {
|
|
51795
52511
|
skippedFileCount++;
|
|
51796
52512
|
continue;
|
|
51797
52513
|
}
|
|
51798
|
-
const buffer =
|
|
52514
|
+
const buffer = fs21.readFileSync(filePath);
|
|
51799
52515
|
if (isBinaryFile2(filePath, buffer)) {
|
|
51800
52516
|
skippedFileCount++;
|
|
51801
52517
|
continue;
|
|
@@ -51864,7 +52580,7 @@ init_lint();
|
|
|
51864
52580
|
|
|
51865
52581
|
// src/tools/phase-complete.ts
|
|
51866
52582
|
init_dist();
|
|
51867
|
-
import * as
|
|
52583
|
+
import * as fs22 from "fs";
|
|
51868
52584
|
import * as path33 from "path";
|
|
51869
52585
|
init_manager();
|
|
51870
52586
|
init_utils2();
|
|
@@ -52116,7 +52832,7 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
52116
52832
|
};
|
|
52117
52833
|
try {
|
|
52118
52834
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
52119
|
-
|
|
52835
|
+
fs22.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
52120
52836
|
`, "utf-8");
|
|
52121
52837
|
} catch (writeError) {
|
|
52122
52838
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -52174,7 +52890,7 @@ init_dist();
|
|
|
52174
52890
|
init_discovery();
|
|
52175
52891
|
init_utils();
|
|
52176
52892
|
init_create_tool();
|
|
52177
|
-
import * as
|
|
52893
|
+
import * as fs23 from "fs";
|
|
52178
52894
|
import * as path34 from "path";
|
|
52179
52895
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
52180
52896
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
@@ -52193,28 +52909,28 @@ function validateArgs3(args2) {
|
|
|
52193
52909
|
function detectEcosystems() {
|
|
52194
52910
|
const ecosystems = [];
|
|
52195
52911
|
const cwd = process.cwd();
|
|
52196
|
-
if (
|
|
52912
|
+
if (fs23.existsSync(path34.join(cwd, "package.json"))) {
|
|
52197
52913
|
ecosystems.push("npm");
|
|
52198
52914
|
}
|
|
52199
|
-
if (
|
|
52915
|
+
if (fs23.existsSync(path34.join(cwd, "pyproject.toml")) || fs23.existsSync(path34.join(cwd, "requirements.txt"))) {
|
|
52200
52916
|
ecosystems.push("pip");
|
|
52201
52917
|
}
|
|
52202
|
-
if (
|
|
52918
|
+
if (fs23.existsSync(path34.join(cwd, "Cargo.toml"))) {
|
|
52203
52919
|
ecosystems.push("cargo");
|
|
52204
52920
|
}
|
|
52205
|
-
if (
|
|
52921
|
+
if (fs23.existsSync(path34.join(cwd, "go.mod"))) {
|
|
52206
52922
|
ecosystems.push("go");
|
|
52207
52923
|
}
|
|
52208
52924
|
try {
|
|
52209
|
-
const files =
|
|
52925
|
+
const files = fs23.readdirSync(cwd);
|
|
52210
52926
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
52211
52927
|
ecosystems.push("dotnet");
|
|
52212
52928
|
}
|
|
52213
52929
|
} catch {}
|
|
52214
|
-
if (
|
|
52930
|
+
if (fs23.existsSync(path34.join(cwd, "Gemfile")) || fs23.existsSync(path34.join(cwd, "Gemfile.lock"))) {
|
|
52215
52931
|
ecosystems.push("ruby");
|
|
52216
52932
|
}
|
|
52217
|
-
if (
|
|
52933
|
+
if (fs23.existsSync(path34.join(cwd, "pubspec.yaml"))) {
|
|
52218
52934
|
ecosystems.push("dart");
|
|
52219
52935
|
}
|
|
52220
52936
|
return ecosystems;
|
|
@@ -53269,7 +53985,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
|
|
|
53269
53985
|
]);
|
|
53270
53986
|
// src/tools/pre-check-batch.ts
|
|
53271
53987
|
init_dist();
|
|
53272
|
-
import * as
|
|
53988
|
+
import * as fs26 from "fs";
|
|
53273
53989
|
import * as path37 from "path";
|
|
53274
53990
|
|
|
53275
53991
|
// node_modules/yocto-queue/index.js
|
|
@@ -53437,7 +54153,7 @@ init_lint();
|
|
|
53437
54153
|
init_manager();
|
|
53438
54154
|
|
|
53439
54155
|
// src/quality/metrics.ts
|
|
53440
|
-
import * as
|
|
54156
|
+
import * as fs24 from "fs";
|
|
53441
54157
|
import * as path35 from "path";
|
|
53442
54158
|
var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
|
|
53443
54159
|
var MIN_DUPLICATION_LINES = 10;
|
|
@@ -53476,11 +54192,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
53476
54192
|
}
|
|
53477
54193
|
function getComplexityForFile2(filePath) {
|
|
53478
54194
|
try {
|
|
53479
|
-
const stat2 =
|
|
54195
|
+
const stat2 = fs24.statSync(filePath);
|
|
53480
54196
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
53481
54197
|
return null;
|
|
53482
54198
|
}
|
|
53483
|
-
const content =
|
|
54199
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
53484
54200
|
return estimateCyclomaticComplexity(content);
|
|
53485
54201
|
} catch {
|
|
53486
54202
|
return null;
|
|
@@ -53491,7 +54207,7 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
53491
54207
|
const analyzedFiles = [];
|
|
53492
54208
|
for (const file3 of files) {
|
|
53493
54209
|
const fullPath = path35.isAbsolute(file3) ? file3 : path35.join(workingDir, file3);
|
|
53494
|
-
if (!
|
|
54210
|
+
if (!fs24.existsSync(fullPath)) {
|
|
53495
54211
|
continue;
|
|
53496
54212
|
}
|
|
53497
54213
|
const complexity = getComplexityForFile2(fullPath);
|
|
@@ -53612,7 +54328,7 @@ function countGoExports(content) {
|
|
|
53612
54328
|
}
|
|
53613
54329
|
function getExportCountForFile(filePath) {
|
|
53614
54330
|
try {
|
|
53615
|
-
const content =
|
|
54331
|
+
const content = fs24.readFileSync(filePath, "utf-8");
|
|
53616
54332
|
const ext = path35.extname(filePath).toLowerCase();
|
|
53617
54333
|
switch (ext) {
|
|
53618
54334
|
case ".ts":
|
|
@@ -53640,7 +54356,7 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
53640
54356
|
const analyzedFiles = [];
|
|
53641
54357
|
for (const file3 of files) {
|
|
53642
54358
|
const fullPath = path35.isAbsolute(file3) ? file3 : path35.join(workingDir, file3);
|
|
53643
|
-
if (!
|
|
54359
|
+
if (!fs24.existsSync(fullPath)) {
|
|
53644
54360
|
continue;
|
|
53645
54361
|
}
|
|
53646
54362
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -53674,15 +54390,15 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
53674
54390
|
const analyzedFiles = [];
|
|
53675
54391
|
for (const file3 of files) {
|
|
53676
54392
|
const fullPath = path35.isAbsolute(file3) ? file3 : path35.join(workingDir, file3);
|
|
53677
|
-
if (!
|
|
54393
|
+
if (!fs24.existsSync(fullPath)) {
|
|
53678
54394
|
continue;
|
|
53679
54395
|
}
|
|
53680
54396
|
try {
|
|
53681
|
-
const stat2 =
|
|
54397
|
+
const stat2 = fs24.statSync(fullPath);
|
|
53682
54398
|
if (stat2.size > MAX_FILE_SIZE_BYTES5) {
|
|
53683
54399
|
continue;
|
|
53684
54400
|
}
|
|
53685
|
-
const content =
|
|
54401
|
+
const content = fs24.readFileSync(fullPath, "utf-8");
|
|
53686
54402
|
const lines = content.split(`
|
|
53687
54403
|
`).filter((line) => line.trim().length > 0);
|
|
53688
54404
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -53858,7 +54574,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
53858
54574
|
let testLines = 0;
|
|
53859
54575
|
let codeLines = 0;
|
|
53860
54576
|
const srcDir = path35.join(workingDir, "src");
|
|
53861
|
-
if (
|
|
54577
|
+
if (fs24.existsSync(srcDir)) {
|
|
53862
54578
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
53863
54579
|
codeLines += lines;
|
|
53864
54580
|
});
|
|
@@ -53866,14 +54582,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
53866
54582
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
53867
54583
|
for (const dir of possibleSrcDirs) {
|
|
53868
54584
|
const dirPath = path35.join(workingDir, dir);
|
|
53869
|
-
if (
|
|
54585
|
+
if (fs24.existsSync(dirPath)) {
|
|
53870
54586
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
53871
54587
|
codeLines += lines;
|
|
53872
54588
|
});
|
|
53873
54589
|
}
|
|
53874
54590
|
}
|
|
53875
54591
|
const testsDir = path35.join(workingDir, "tests");
|
|
53876
|
-
if (
|
|
54592
|
+
if (fs24.existsSync(testsDir)) {
|
|
53877
54593
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
53878
54594
|
testLines += lines;
|
|
53879
54595
|
});
|
|
@@ -53881,7 +54597,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
53881
54597
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
53882
54598
|
for (const dir of possibleTestDirs) {
|
|
53883
54599
|
const dirPath = path35.join(workingDir, dir);
|
|
53884
|
-
if (
|
|
54600
|
+
if (fs24.existsSync(dirPath) && dirPath !== testsDir) {
|
|
53885
54601
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
53886
54602
|
testLines += lines;
|
|
53887
54603
|
});
|
|
@@ -53893,7 +54609,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
53893
54609
|
}
|
|
53894
54610
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
53895
54611
|
try {
|
|
53896
|
-
const entries =
|
|
54612
|
+
const entries = fs24.readdirSync(dirPath, { withFileTypes: true });
|
|
53897
54613
|
for (const entry of entries) {
|
|
53898
54614
|
const fullPath = path35.join(dirPath, entry.name);
|
|
53899
54615
|
if (entry.isDirectory()) {
|
|
@@ -53939,7 +54655,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
53939
54655
|
continue;
|
|
53940
54656
|
}
|
|
53941
54657
|
try {
|
|
53942
|
-
const content =
|
|
54658
|
+
const content = fs24.readFileSync(fullPath, "utf-8");
|
|
53943
54659
|
const lines = countCodeLines(content);
|
|
53944
54660
|
callback(lines);
|
|
53945
54661
|
} catch {}
|
|
@@ -54153,7 +54869,7 @@ async function qualityBudget(input, directory) {
|
|
|
54153
54869
|
init_dist();
|
|
54154
54870
|
init_manager();
|
|
54155
54871
|
init_detector();
|
|
54156
|
-
import * as
|
|
54872
|
+
import * as fs25 from "fs";
|
|
54157
54873
|
import * as path36 from "path";
|
|
54158
54874
|
import { extname as extname9 } from "path";
|
|
54159
54875
|
|
|
@@ -55021,17 +55737,17 @@ var SEVERITY_ORDER = {
|
|
|
55021
55737
|
};
|
|
55022
55738
|
function shouldSkipFile(filePath) {
|
|
55023
55739
|
try {
|
|
55024
|
-
const stats =
|
|
55740
|
+
const stats = fs25.statSync(filePath);
|
|
55025
55741
|
if (stats.size > MAX_FILE_SIZE_BYTES6) {
|
|
55026
55742
|
return { skip: true, reason: "file too large" };
|
|
55027
55743
|
}
|
|
55028
55744
|
if (stats.size === 0) {
|
|
55029
55745
|
return { skip: true, reason: "empty file" };
|
|
55030
55746
|
}
|
|
55031
|
-
const fd =
|
|
55747
|
+
const fd = fs25.openSync(filePath, "r");
|
|
55032
55748
|
const buffer = Buffer.alloc(8192);
|
|
55033
|
-
const bytesRead =
|
|
55034
|
-
|
|
55749
|
+
const bytesRead = fs25.readSync(fd, buffer, 0, 8192, 0);
|
|
55750
|
+
fs25.closeSync(fd);
|
|
55035
55751
|
if (bytesRead > 0) {
|
|
55036
55752
|
let nullCount = 0;
|
|
55037
55753
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -55070,7 +55786,7 @@ function countBySeverity(findings) {
|
|
|
55070
55786
|
}
|
|
55071
55787
|
function scanFileWithTierA(filePath, language) {
|
|
55072
55788
|
try {
|
|
55073
|
-
const content =
|
|
55789
|
+
const content = fs25.readFileSync(filePath, "utf-8");
|
|
55074
55790
|
const findings = executeRulesSync(filePath, content, language);
|
|
55075
55791
|
return findings.map((f) => ({
|
|
55076
55792
|
rule_id: f.rule_id,
|
|
@@ -55118,7 +55834,7 @@ async function sastScan(input, directory, config3) {
|
|
|
55118
55834
|
continue;
|
|
55119
55835
|
}
|
|
55120
55836
|
const resolvedPath = path36.isAbsolute(filePath) ? filePath : path36.resolve(directory, filePath);
|
|
55121
|
-
if (!
|
|
55837
|
+
if (!fs25.existsSync(resolvedPath)) {
|
|
55122
55838
|
_filesSkipped++;
|
|
55123
55839
|
continue;
|
|
55124
55840
|
}
|
|
@@ -55334,7 +56050,7 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
55334
56050
|
}
|
|
55335
56051
|
return null;
|
|
55336
56052
|
}
|
|
55337
|
-
function
|
|
56053
|
+
function validateDirectory3(dir, workspaceDir) {
|
|
55338
56054
|
if (!dir || dir.length === 0) {
|
|
55339
56055
|
return "directory is required";
|
|
55340
56056
|
}
|
|
@@ -55576,7 +56292,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
55576
56292
|
}
|
|
55577
56293
|
let stat2;
|
|
55578
56294
|
try {
|
|
55579
|
-
stat2 =
|
|
56295
|
+
stat2 = fs26.statSync(file3);
|
|
55580
56296
|
} catch {
|
|
55581
56297
|
skippedFiles++;
|
|
55582
56298
|
continue;
|
|
@@ -55587,7 +56303,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
55587
56303
|
}
|
|
55588
56304
|
let content;
|
|
55589
56305
|
try {
|
|
55590
|
-
const buffer =
|
|
56306
|
+
const buffer = fs26.readFileSync(file3);
|
|
55591
56307
|
if (buffer.includes(0)) {
|
|
55592
56308
|
skippedFiles++;
|
|
55593
56309
|
continue;
|
|
@@ -55690,7 +56406,7 @@ async function runQualityBudgetWrapped(changedFiles, directory, _config) {
|
|
|
55690
56406
|
async function runPreCheckBatch(input, workspaceDir) {
|
|
55691
56407
|
const effectiveWorkspaceDir = workspaceDir || input.directory || process.cwd();
|
|
55692
56408
|
const { files, directory, sast_threshold = "medium", config: config3 } = input;
|
|
55693
|
-
const dirError =
|
|
56409
|
+
const dirError = validateDirectory3(directory, effectiveWorkspaceDir);
|
|
55694
56410
|
if (dirError) {
|
|
55695
56411
|
warn(`pre_check_batch: Invalid directory: ${dirError}`);
|
|
55696
56412
|
return {
|
|
@@ -55854,7 +56570,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
55854
56570
|
}
|
|
55855
56571
|
const resolvedDirectory = path37.resolve(typedArgs.directory);
|
|
55856
56572
|
const workspaceAnchor = resolvedDirectory;
|
|
55857
|
-
const dirError =
|
|
56573
|
+
const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
|
|
55858
56574
|
if (dirError) {
|
|
55859
56575
|
const errorResult = {
|
|
55860
56576
|
gates_passed: false,
|
|
@@ -56044,7 +56760,7 @@ var save_plan = createSwarmTool({
|
|
|
56044
56760
|
// src/tools/sbom-generate.ts
|
|
56045
56761
|
init_dist();
|
|
56046
56762
|
init_manager();
|
|
56047
|
-
import * as
|
|
56763
|
+
import * as fs27 from "fs";
|
|
56048
56764
|
import * as path39 from "path";
|
|
56049
56765
|
|
|
56050
56766
|
// src/sbom/detectors/dart.ts
|
|
@@ -56891,7 +57607,7 @@ function findManifestFiles(rootDir) {
|
|
|
56891
57607
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
56892
57608
|
function searchDir(dir) {
|
|
56893
57609
|
try {
|
|
56894
|
-
const entries =
|
|
57610
|
+
const entries = fs27.readdirSync(dir, { withFileTypes: true });
|
|
56895
57611
|
for (const entry of entries) {
|
|
56896
57612
|
const fullPath = path39.join(dir, entry.name);
|
|
56897
57613
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
@@ -56920,7 +57636,7 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
56920
57636
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
56921
57637
|
for (const dir of directories) {
|
|
56922
57638
|
try {
|
|
56923
|
-
const entries =
|
|
57639
|
+
const entries = fs27.readdirSync(dir, { withFileTypes: true });
|
|
56924
57640
|
for (const entry of entries) {
|
|
56925
57641
|
const fullPath = path39.join(dir, entry.name);
|
|
56926
57642
|
if (entry.isFile()) {
|
|
@@ -56958,7 +57674,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
56958
57674
|
}
|
|
56959
57675
|
function ensureOutputDir(outputDir) {
|
|
56960
57676
|
try {
|
|
56961
|
-
|
|
57677
|
+
fs27.mkdirSync(outputDir, { recursive: true });
|
|
56962
57678
|
} catch (error93) {
|
|
56963
57679
|
if (!error93 || error93.code !== "EEXIST") {
|
|
56964
57680
|
throw error93;
|
|
@@ -57051,10 +57767,10 @@ var sbom_generate = createSwarmTool({
|
|
|
57051
57767
|
for (const manifestFile of manifestFiles) {
|
|
57052
57768
|
try {
|
|
57053
57769
|
const fullPath = path39.isAbsolute(manifestFile) ? manifestFile : path39.join(workingDir, manifestFile);
|
|
57054
|
-
if (!
|
|
57770
|
+
if (!fs27.existsSync(fullPath)) {
|
|
57055
57771
|
continue;
|
|
57056
57772
|
}
|
|
57057
|
-
const content =
|
|
57773
|
+
const content = fs27.readFileSync(fullPath, "utf-8");
|
|
57058
57774
|
const components = detectComponents(manifestFile, content);
|
|
57059
57775
|
processedFiles.push(manifestFile);
|
|
57060
57776
|
if (components.length > 0) {
|
|
@@ -57068,7 +57784,7 @@ var sbom_generate = createSwarmTool({
|
|
|
57068
57784
|
const bomJson = serializeCycloneDX(bom);
|
|
57069
57785
|
const filename = generateSbomFilename();
|
|
57070
57786
|
const outputPath = path39.join(outputDir, filename);
|
|
57071
|
-
|
|
57787
|
+
fs27.writeFileSync(outputPath, bomJson, "utf-8");
|
|
57072
57788
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
57073
57789
|
try {
|
|
57074
57790
|
const timestamp = new Date().toISOString();
|
|
@@ -57110,7 +57826,7 @@ var sbom_generate = createSwarmTool({
|
|
|
57110
57826
|
// src/tools/schema-drift.ts
|
|
57111
57827
|
init_dist();
|
|
57112
57828
|
init_create_tool();
|
|
57113
|
-
import * as
|
|
57829
|
+
import * as fs28 from "fs";
|
|
57114
57830
|
import * as path40 from "path";
|
|
57115
57831
|
var SPEC_CANDIDATES = [
|
|
57116
57832
|
"openapi.json",
|
|
@@ -57152,19 +57868,19 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
57152
57868
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
57153
57869
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
57154
57870
|
}
|
|
57155
|
-
const stats =
|
|
57871
|
+
const stats = fs28.statSync(resolvedPath);
|
|
57156
57872
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
57157
57873
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
57158
57874
|
}
|
|
57159
|
-
if (!
|
|
57875
|
+
if (!fs28.existsSync(resolvedPath)) {
|
|
57160
57876
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
57161
57877
|
}
|
|
57162
57878
|
return resolvedPath;
|
|
57163
57879
|
}
|
|
57164
57880
|
for (const candidate of SPEC_CANDIDATES) {
|
|
57165
57881
|
const candidatePath = path40.resolve(cwd, candidate);
|
|
57166
|
-
if (
|
|
57167
|
-
const stats =
|
|
57882
|
+
if (fs28.existsSync(candidatePath)) {
|
|
57883
|
+
const stats = fs28.statSync(candidatePath);
|
|
57168
57884
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
57169
57885
|
return candidatePath;
|
|
57170
57886
|
}
|
|
@@ -57173,7 +57889,7 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
57173
57889
|
return null;
|
|
57174
57890
|
}
|
|
57175
57891
|
function parseSpec(specFile) {
|
|
57176
|
-
const content =
|
|
57892
|
+
const content = fs28.readFileSync(specFile, "utf-8");
|
|
57177
57893
|
const ext = path40.extname(specFile).toLowerCase();
|
|
57178
57894
|
if (ext === ".json") {
|
|
57179
57895
|
return parseJsonSpec(content);
|
|
@@ -57240,7 +57956,7 @@ function extractRoutes(cwd) {
|
|
|
57240
57956
|
function walkDir(dir) {
|
|
57241
57957
|
let entries;
|
|
57242
57958
|
try {
|
|
57243
|
-
entries =
|
|
57959
|
+
entries = fs28.readdirSync(dir, { withFileTypes: true });
|
|
57244
57960
|
} catch {
|
|
57245
57961
|
return;
|
|
57246
57962
|
}
|
|
@@ -57273,7 +57989,7 @@ function extractRoutes(cwd) {
|
|
|
57273
57989
|
}
|
|
57274
57990
|
function extractRoutesFromFile(filePath) {
|
|
57275
57991
|
const routes = [];
|
|
57276
|
-
const content =
|
|
57992
|
+
const content = fs28.readFileSync(filePath, "utf-8");
|
|
57277
57993
|
const lines = content.split(/\r?\n/);
|
|
57278
57994
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
57279
57995
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -57424,7 +58140,7 @@ init_secretscan();
|
|
|
57424
58140
|
// src/tools/symbols.ts
|
|
57425
58141
|
init_tool();
|
|
57426
58142
|
init_create_tool();
|
|
57427
|
-
import * as
|
|
58143
|
+
import * as fs29 from "fs";
|
|
57428
58144
|
import * as path41 from "path";
|
|
57429
58145
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
57430
58146
|
var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
@@ -57455,8 +58171,8 @@ function containsWindowsAttacks(str) {
|
|
|
57455
58171
|
function isPathInWorkspace(filePath, workspace) {
|
|
57456
58172
|
try {
|
|
57457
58173
|
const resolvedPath = path41.resolve(workspace, filePath);
|
|
57458
|
-
const realWorkspace =
|
|
57459
|
-
const realResolvedPath =
|
|
58174
|
+
const realWorkspace = fs29.realpathSync(workspace);
|
|
58175
|
+
const realResolvedPath = fs29.realpathSync(resolvedPath);
|
|
57460
58176
|
const relativePath = path41.relative(realWorkspace, realResolvedPath);
|
|
57461
58177
|
if (relativePath.startsWith("..") || path41.isAbsolute(relativePath)) {
|
|
57462
58178
|
return false;
|
|
@@ -57476,11 +58192,11 @@ function extractTSSymbols(filePath, cwd) {
|
|
|
57476
58192
|
}
|
|
57477
58193
|
let content;
|
|
57478
58194
|
try {
|
|
57479
|
-
const stats =
|
|
58195
|
+
const stats = fs29.statSync(fullPath);
|
|
57480
58196
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
57481
58197
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
57482
58198
|
}
|
|
57483
|
-
content =
|
|
58199
|
+
content = fs29.readFileSync(fullPath, "utf-8");
|
|
57484
58200
|
} catch {
|
|
57485
58201
|
return [];
|
|
57486
58202
|
}
|
|
@@ -57628,11 +58344,11 @@ function extractPythonSymbols(filePath, cwd) {
|
|
|
57628
58344
|
}
|
|
57629
58345
|
let content;
|
|
57630
58346
|
try {
|
|
57631
|
-
const stats =
|
|
58347
|
+
const stats = fs29.statSync(fullPath);
|
|
57632
58348
|
if (stats.size > MAX_FILE_SIZE_BYTES7) {
|
|
57633
58349
|
throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
|
|
57634
58350
|
}
|
|
57635
|
-
content =
|
|
58351
|
+
content = fs29.readFileSync(fullPath, "utf-8");
|
|
57636
58352
|
} catch {
|
|
57637
58353
|
return [];
|
|
57638
58354
|
}
|
|
@@ -57776,7 +58492,7 @@ init_test_runner();
|
|
|
57776
58492
|
init_tool();
|
|
57777
58493
|
init_manager2();
|
|
57778
58494
|
init_create_tool();
|
|
57779
|
-
import * as
|
|
58495
|
+
import * as fs30 from "fs";
|
|
57780
58496
|
import * as path42 from "path";
|
|
57781
58497
|
var VALID_STATUSES = [
|
|
57782
58498
|
"pending",
|
|
@@ -57844,9 +58560,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
57844
58560
|
}
|
|
57845
58561
|
const resolvedDir = path42.resolve(normalizedDir);
|
|
57846
58562
|
try {
|
|
57847
|
-
const realPath =
|
|
58563
|
+
const realPath = fs30.realpathSync(resolvedDir);
|
|
57848
58564
|
const planPath = path42.join(realPath, ".swarm", "plan.json");
|
|
57849
|
-
if (!
|
|
58565
|
+
if (!fs30.existsSync(planPath)) {
|
|
57850
58566
|
return {
|
|
57851
58567
|
success: false,
|
|
57852
58568
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -57897,7 +58613,7 @@ var update_task_status = createSwarmTool({
|
|
|
57897
58613
|
// src/tools/todo-extract.ts
|
|
57898
58614
|
init_dist();
|
|
57899
58615
|
init_create_tool();
|
|
57900
|
-
import * as
|
|
58616
|
+
import * as fs31 from "fs";
|
|
57901
58617
|
import * as path43 from "path";
|
|
57902
58618
|
var MAX_TEXT_LENGTH = 200;
|
|
57903
58619
|
var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
|
|
@@ -57993,7 +58709,7 @@ function isSupportedExtension(filePath) {
|
|
|
57993
58709
|
function findSourceFiles3(dir, files = []) {
|
|
57994
58710
|
let entries;
|
|
57995
58711
|
try {
|
|
57996
|
-
entries =
|
|
58712
|
+
entries = fs31.readdirSync(dir);
|
|
57997
58713
|
} catch {
|
|
57998
58714
|
return files;
|
|
57999
58715
|
}
|
|
@@ -58005,7 +58721,7 @@ function findSourceFiles3(dir, files = []) {
|
|
|
58005
58721
|
const fullPath = path43.join(dir, entry);
|
|
58006
58722
|
let stat2;
|
|
58007
58723
|
try {
|
|
58008
|
-
stat2 =
|
|
58724
|
+
stat2 = fs31.statSync(fullPath);
|
|
58009
58725
|
} catch {
|
|
58010
58726
|
continue;
|
|
58011
58727
|
}
|
|
@@ -58098,7 +58814,7 @@ var todo_extract = createSwarmTool({
|
|
|
58098
58814
|
return JSON.stringify(errorResult, null, 2);
|
|
58099
58815
|
}
|
|
58100
58816
|
const scanPath = resolvedPath;
|
|
58101
|
-
if (!
|
|
58817
|
+
if (!fs31.existsSync(scanPath)) {
|
|
58102
58818
|
const errorResult = {
|
|
58103
58819
|
error: `path not found: ${pathsInput}`,
|
|
58104
58820
|
total: 0,
|
|
@@ -58108,7 +58824,7 @@ var todo_extract = createSwarmTool({
|
|
|
58108
58824
|
return JSON.stringify(errorResult, null, 2);
|
|
58109
58825
|
}
|
|
58110
58826
|
const filesToScan = [];
|
|
58111
|
-
const stat2 =
|
|
58827
|
+
const stat2 = fs31.statSync(scanPath);
|
|
58112
58828
|
if (stat2.isFile()) {
|
|
58113
58829
|
if (isSupportedExtension(scanPath)) {
|
|
58114
58830
|
filesToScan.push(scanPath);
|
|
@@ -58127,11 +58843,11 @@ var todo_extract = createSwarmTool({
|
|
|
58127
58843
|
const allEntries = [];
|
|
58128
58844
|
for (const filePath of filesToScan) {
|
|
58129
58845
|
try {
|
|
58130
|
-
const fileStat =
|
|
58846
|
+
const fileStat = fs31.statSync(filePath);
|
|
58131
58847
|
if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
|
|
58132
58848
|
continue;
|
|
58133
58849
|
}
|
|
58134
|
-
const content =
|
|
58850
|
+
const content = fs31.readFileSync(filePath, "utf-8");
|
|
58135
58851
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
58136
58852
|
allEntries.push(...entries);
|
|
58137
58853
|
} catch {}
|
|
@@ -58391,6 +59107,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
58391
59107
|
template: "/swarm evidence $ARGUMENTS",
|
|
58392
59108
|
description: "View evidence bundles and summaries"
|
|
58393
59109
|
},
|
|
59110
|
+
"swarm-handoff": {
|
|
59111
|
+
template: "/swarm handoff",
|
|
59112
|
+
description: "Prepare handoff brief for switching models mid-task"
|
|
59113
|
+
},
|
|
58394
59114
|
"swarm-archive": {
|
|
58395
59115
|
template: "/swarm archive",
|
|
58396
59116
|
description: "Archive old evidence bundles"
|