opencode-swarm 6.19.7 → 6.19.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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 path16 from "path";
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 path16.join(dir, matches[0]);
31930
+ return path17.join(dir, matches[0]);
31931
31931
  }
31932
31932
  } catch {}
31933
31933
  } else {
31934
- const filePath = path16.join(workingDir, pattern);
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 = path16.join(workingDir, "package.json");
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 = path16.join(workingDir, pattern);
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 = path16.join(dir, entry.name);
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 = path16.join(workingDir, cmd.detectFile);
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 path17 from "path";
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 = path17.join(process.cwd(), "node_modules", ".bin");
32242
- const biomeBin = isWindows ? path17.join(binDir, "biome.EXE") : path17.join(binDir, "biome");
32243
- const eslintBin = isWindows ? path17.join(binDir, "eslint.cmd") : path17.join(binDir, "eslint");
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(path17.join(cwd, gradlewName)) ? path17.join(cwd, gradlewName) : null;
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(path17.join(cwd, "ruff.toml")))
32293
+ if (fs7.existsSync(path18.join(cwd, "ruff.toml")))
32294
32294
  return isCommandAvailable("ruff");
32295
32295
  try {
32296
- const pyproject = path17.join(cwd, "pyproject.toml");
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(path17.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
32306
+ return fs7.existsSync(path18.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
32307
32307
  }
32308
32308
  function detectGolangciLint(cwd) {
32309
- return fs7.existsSync(path17.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
32309
+ return fs7.existsSync(path18.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
32310
32310
  }
32311
32311
  function detectCheckstyle(cwd) {
32312
- const hasMaven = fs7.existsSync(path17.join(cwd, "pom.xml"));
32313
- const hasGradle = fs7.existsSync(path17.join(cwd, "build.gradle")) || fs7.existsSync(path17.join(cwd, "build.gradle.kts"));
32314
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs7.existsSync(path17.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
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(path17.join(cwd, "build.gradle.kts")) || fs7.existsSync(path17.join(cwd, "build.gradle")) || (() => {
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(path17.join(cwd, "CMakeLists.txt"))) {
32337
+ if (fs7.existsSync(path18.join(cwd, "CMakeLists.txt"))) {
32338
32338
  return isCommandAvailable("cppcheck");
32339
32339
  }
32340
32340
  try {
32341
- const dirsToCheck = [cwd, path17.join(cwd, "src")];
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(path17.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
32355
+ return fs7.existsSync(path18.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
32356
32356
  }
32357
32357
  function detectDartAnalyze(cwd) {
32358
- return fs7.existsSync(path17.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
32358
+ return fs7.existsSync(path18.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
32359
32359
  }
32360
32360
  function detectRubocop(cwd) {
32361
- return (fs7.existsSync(path17.join(cwd, "Gemfile")) || fs7.existsSync(path17.join(cwd, "gems.rb")) || fs7.existsSync(path17.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
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 path18 from "path";
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 = path18.normalize(str);
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 = path18.extname(filePath).toLowerCase();
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 = path18.resolve(scanDir);
32773
- const resolvedRealPath = path18.resolve(realPath);
32774
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path18.sep) || resolvedRealPath.startsWith(`${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 = path18.join(dir, entry);
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 = path18.extname(fullPath).toLowerCase();
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 = path18.resolve(directory);
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 path19 from "path";
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(path19.join(cwd, "go.mod")) && isCommandAvailable("go");
33323
+ return fs9.existsSync(path20.join(cwd, "go.mod")) && isCommandAvailable("go");
33324
33324
  }
33325
33325
  function detectJavaMaven(cwd) {
33326
- return fs9.existsSync(path19.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
33326
+ return fs9.existsSync(path20.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
33327
33327
  }
33328
33328
  function detectGradle(cwd) {
33329
- const hasBuildFile = fs9.existsSync(path19.join(cwd, "build.gradle")) || fs9.existsSync(path19.join(cwd, "build.gradle.kts"));
33330
- const hasGradlew = fs9.existsSync(path19.join(cwd, "gradlew")) || fs9.existsSync(path19.join(cwd, "gradlew.bat"));
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(path19.join(cwd, "CMakeLists.txt"));
33344
- const hasBuildCache = fs9.existsSync(path19.join(cwd, "CMakeCache.txt")) || fs9.existsSync(path19.join(cwd, "build", "CMakeCache.txt"));
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(path19.join(cwd, "Package.swift")) && isCommandAvailable("swift");
33348
+ return fs9.existsSync(path20.join(cwd, "Package.swift")) && isCommandAvailable("swift");
33349
33349
  }
33350
33350
  function detectDartTest(cwd) {
33351
- return fs9.existsSync(path19.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
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(path19.join(cwd, ".rspec"));
33355
- const hasGemfile = fs9.existsSync(path19.join(cwd, "Gemfile"));
33356
- const hasSpecDir = fs9.existsSync(path19.join(cwd, "spec"));
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(path19.join(cwd, "test")) && (fs9.existsSync(path19.join(cwd, "Gemfile")) || fs9.existsSync(path19.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
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 = path19.join(baseDir, "package.json");
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(path19.join(baseDir, "bun.lockb")) || fs9.existsSync(path19.join(baseDir, "bun.lock"))) {
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 = path19.join(baseDir, "pyproject.toml");
33395
- const setupCfgPath = path19.join(baseDir, "setup.cfg");
33396
- const requirementsTxtPath = path19.join(baseDir, "requirements.txt");
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 = path19.join(baseDir, "Cargo.toml");
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 = path19.join(baseDir, "pester.config.ps1");
33428
- const pesterConfigJsonPath = path19.join(baseDir, "pester.config.ps1.json");
33429
- const pesterPs1Path = path19.join(baseDir, "tests.ps1");
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 = path19.basename(file3);
33463
- const dirname7 = path19.dirname(file3);
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 = path19.extname(basename4);
33472
+ const ext = path20.extname(basename4);
33473
33473
  const possibleTestFiles = [
33474
- path19.join(dirname7, `${nameWithoutExt}.spec${ext}`),
33475
- path19.join(dirname7, `${nameWithoutExt}.test${ext}`),
33476
- path19.join(dirname7, "__tests__", `${nameWithoutExt}${ext}`),
33477
- path19.join(dirname7, "tests", `${nameWithoutExt}${ext}`),
33478
- path19.join(dirname7, "test", `${nameWithoutExt}${ext}`)
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 = path19.dirname(testFile);
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 = path19.resolve(testDir, importPath);
33507
- const existingExt = path19.extname(resolvedImport);
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 = path19.basename(resolvedImport, path19.extname(resolvedImport));
33528
- const importDir = path19.dirname(resolvedImport);
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 = path19.dirname(sourceFile);
33531
- const sourceBasename = path19.basename(sourceFile, path19.extname(sourceFile));
33532
- const isRelatedDir = importDir === sourceDir || importDir === path19.join(sourceDir, "__tests__") || importDir === path19.join(sourceDir, "tests") || importDir === path19.join(sourceDir, "test");
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 = path19.resolve(testDir, importPath);
33548
- const existingExt = path19.extname(resolvedImport);
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 = path19.dirname(resolvedImport);
33566
- const importBasename = path19.basename(resolvedImport, path19.extname(resolvedImport));
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 = path19.dirname(sourceFile);
33569
- const sourceBasename = path19.basename(sourceFile, path19.extname(sourceFile));
33570
- const isRelatedDir = importDir === sourceDir || importDir === path19.join(sourceDir, "__tests__") || importDir === path19.join(sourceDir, "tests") || importDir === path19.join(sourceDir, "test");
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(path19.join(baseDir, "gradlew.bat"));
33656
- const hasGradlew = fs9.existsSync(path19.join(baseDir, "gradlew"));
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(path19.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
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 = path19.join(dir, entry);
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 = path19.extname(fullPath).toLowerCase();
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 = path19.extname(f).toLowerCase();
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 = path19.extname(f).toLowerCase();
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 path20 from "path";
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 = path20.normalize(dir);
34243
- const absolutePath = path20.isAbsolute(normalized) ? normalized : path20.resolve(normalized);
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 = path20.join(dir, "package.json");
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 = path20.join(dir, "CHANGELOG.md");
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 = path20.join(dir, file3);
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 fs23 = await import("fs/promises");
36278
- bytes = fs23.readFile(input);
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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 path15 from "path";
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 path14 from "path";
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 = path14.join(directory, ".swarm", "knowledge.jsonl");
44197
- const quarantinePath = path14.join(directory, ".swarm", "knowledge-quarantined.jsonl");
44198
- const rejectedPath = path14.join(directory, ".swarm", "knowledge-rejected.jsonl");
44199
- const swarmDir = path14.join(directory, ".swarm");
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 = path14.join(directory, ".swarm", "knowledge.jsonl");
44257
- const quarantinePath = path14.join(directory, ".swarm", "knowledge-quarantined.jsonl");
44258
- const rejectedPath = path14.join(directory, ".swarm", "knowledge-rejected.jsonl");
44259
- const swarmDir = path14.join(directory, ".swarm");
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 = path15.join(directory, ".swarm", ".knowledge-migrated");
44295
- const contextPath = path15.join(directory, ".swarm", "context.md");
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 = path15.join(directory, "package.json");
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 path15.basename(directory);
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(path15.dirname(sentinelPath), { recursive: true });
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 path21 from "path";
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: path21.basename(directory) || "unknown"
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 mkdirSync5, readdirSync as readdirSync7, renameSync as renameSync3, rmSync as rmSync3, statSync as statSync7 } from "fs";
45068
- import * as path22 from "path";
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 = path22.join("summaries", `${sanitizedId}.json`);
45506
+ const relativePath = path23.join("summaries", `${sanitizedId}.json`);
45097
45507
  const summaryPath = validateSwarmPath(directory, relativePath);
45098
- const summaryDir = path22.dirname(summaryPath);
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
- mkdirSync5(summaryDir, { recursive: true });
45108
- const tempPath = path22.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
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
- renameSync3(tempPath, summaryPath);
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 = path22.join("summaries", `${sanitizedId}.json`);
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 path23 from "path";
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 = path23.join(checkpointDir, file3);
45224
- const dest = path23.join(swarmDir, file3);
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 path24 = await import("path");
45288
- const reportPath = path24.join(directory, ".swarm", "simulate-report.md");
45289
- await fs13.mkdir(path24.dirname(reportPath), { recursive: true });
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 extractDecisions(contextContent, maxChars = 500) {
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 extractCurrentPhaseFromPlan(plan) {
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 = extractCurrentPhaseFromPlan(plan) || "Unknown";
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 renameSync4, unlinkSync as unlinkSync3 } from "fs";
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 path24 = `${directory}/.swarm/context.md`;
46131
- const tempPath = `${path24}.tmp`;
46544
+ const path25 = `${directory}/.swarm/context.md`;
46545
+ const tempPath = `${path25}.tmp`;
46132
46546
  try {
46133
46547
  await Bun.write(tempPath, updated);
46134
- renameSync4(tempPath, path24);
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 = extractCurrentPhaseFromPlan(plan);
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 = extractDecisions(contextContent);
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 path24 from "path";
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 = path24.resolve(directory, ".swarm");
47017
- const resolved = path24.resolve(directory, filePath);
47018
- const relative3 = path24.relative(swarmDir, resolved);
47019
- return relative3.startsWith("..") || path24.isAbsolute(relative3);
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 = extractCurrentPhaseFromPlan(plan);
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 = extractCurrentPhaseFromPlan(plan);
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 = extractCurrentPhaseFromPlan(plan);
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 path25 from "path";
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 = path25.join(directory, ".swarm", "context.md");
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 = extractCurrentPhaseFromPlan(plan2) || "";
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 = extractDecisions(contextContent, 200);
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 = extractCurrentPhaseFromPlan(plan);
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 = extractDecisions(contextContent, 200);
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 existsSync17 } from "fs";
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 path26 from "path";
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 = path26.join(directory, ".swarm", ".knowledge-shown.json");
49879
+ const shownFile = path27.join(directory, ".swarm", ".knowledge-shown.json");
49188
49880
  try {
49189
49881
  let shownData = {};
49190
- if (existsSync17(shownFile)) {
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(path26.dirname(shownFile), { recursive: true });
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 = path26.join(directory, ".swarm", ".knowledge-shown.json");
49982
+ const shownFile = path27.join(directory, ".swarm", ".knowledge-shown.json");
49291
49983
  try {
49292
- if (!existsSync17(shownFile)) {
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 = extractCurrentPhaseFromPlan(plan) ?? `Phase ${currentPhase}`;
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
- cachedInjectionText = [
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 fs15 from "fs";
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
- fs15.appendFileSync(eventsPath, `${JSON.stringify(event)}
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 fs16 from "fs";
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 (fs16.existsSync(logPath)) {
50244
- const content = fs16.readFileSync(logPath, "utf-8");
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 (!fs16.existsSync(dir)) {
50258
- fs16.mkdirSync(dir, { recursive: true });
50973
+ if (!fs17.existsSync(dir)) {
50974
+ fs17.mkdirSync(dir, { recursive: true });
50259
50975
  }
50260
50976
  const tempPath = `${logPath}.tmp`;
50261
- fs16.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
50262
- fs16.renameSync(tempPath, logPath);
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 fs17 from "fs";
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 = fs17.statSync(filePath);
51308
+ const stat2 = fs18.statSync(filePath);
50593
51309
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
50594
51310
  return null;
50595
51311
  }
50596
- const content = fs17.readFileSync(filePath, "utf-8");
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 (!fs17.existsSync(fullPath)) {
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 fs18 from "fs";
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 (!fs18.existsSync(evidenceDir) || !fs18.statSync(evidenceDir).isDirectory()) {
51847
+ if (!fs19.existsSync(evidenceDir) || !fs19.statSync(evidenceDir).isDirectory()) {
51132
51848
  return evidence;
51133
51849
  }
51134
51850
  let files;
51135
51851
  try {
51136
- files = fs18.readdirSync(evidenceDir);
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 = fs18.lstatSync(filePath);
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 = fs18.statSync(filePath);
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 = fs18.readFileSync(filePath, "utf-8");
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 = fs18.readFileSync(planPath, "utf-8");
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 fs19 from "fs";
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 (!fs19.existsSync(targetDir)) {
51368
- fs19.mkdirSync(targetDir, { recursive: true });
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 (fs19.existsSync(filepath)) {
52106
+ while (fs20.existsSync(filepath)) {
51391
52107
  filepath = path31.join(targetDir, `${base}_${counter}${ext}`);
51392
52108
  counter++;
51393
52109
  }
51394
52110
  try {
51395
- fs19.writeFileSync(filepath, code.trim(), "utf-8");
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 fs20 from "fs";
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 = fs20.readdirSync(dir);
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 = fs20.statSync(fullPath);
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 (!fs20.existsSync(targetFile)) {
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 = fs20.statSync(targetFile);
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 = fs20.statSync(filePath);
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 = fs20.readFileSync(filePath);
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 fs21 from "fs";
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
- fs21.appendFileSync(eventsPath, `${JSON.stringify(event)}
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 fs22 from "fs";
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 (fs22.existsSync(path34.join(cwd, "package.json"))) {
52912
+ if (fs23.existsSync(path34.join(cwd, "package.json"))) {
52197
52913
  ecosystems.push("npm");
52198
52914
  }
52199
- if (fs22.existsSync(path34.join(cwd, "pyproject.toml")) || fs22.existsSync(path34.join(cwd, "requirements.txt"))) {
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 (fs22.existsSync(path34.join(cwd, "Cargo.toml"))) {
52918
+ if (fs23.existsSync(path34.join(cwd, "Cargo.toml"))) {
52203
52919
  ecosystems.push("cargo");
52204
52920
  }
52205
- if (fs22.existsSync(path34.join(cwd, "go.mod"))) {
52921
+ if (fs23.existsSync(path34.join(cwd, "go.mod"))) {
52206
52922
  ecosystems.push("go");
52207
52923
  }
52208
52924
  try {
52209
- const files = fs22.readdirSync(cwd);
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 (fs22.existsSync(path34.join(cwd, "Gemfile")) || fs22.existsSync(path34.join(cwd, "Gemfile.lock"))) {
52930
+ if (fs23.existsSync(path34.join(cwd, "Gemfile")) || fs23.existsSync(path34.join(cwd, "Gemfile.lock"))) {
52215
52931
  ecosystems.push("ruby");
52216
52932
  }
52217
- if (fs22.existsSync(path34.join(cwd, "pubspec.yaml"))) {
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 fs25 from "fs";
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 fs23 from "fs";
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 = fs23.statSync(filePath);
54195
+ const stat2 = fs24.statSync(filePath);
53480
54196
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
53481
54197
  return null;
53482
54198
  }
53483
- const content = fs23.readFileSync(filePath, "utf-8");
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 (!fs23.existsSync(fullPath)) {
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 = fs23.readFileSync(filePath, "utf-8");
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 (!fs23.existsSync(fullPath)) {
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 (!fs23.existsSync(fullPath)) {
54393
+ if (!fs24.existsSync(fullPath)) {
53678
54394
  continue;
53679
54395
  }
53680
54396
  try {
53681
- const stat2 = fs23.statSync(fullPath);
54397
+ const stat2 = fs24.statSync(fullPath);
53682
54398
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
53683
54399
  continue;
53684
54400
  }
53685
- const content = fs23.readFileSync(fullPath, "utf-8");
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 (fs23.existsSync(srcDir)) {
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 (fs23.existsSync(dirPath)) {
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 (fs23.existsSync(testsDir)) {
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 (fs23.existsSync(dirPath) && dirPath !== testsDir) {
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 = fs23.readdirSync(dirPath, { withFileTypes: true });
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 = fs23.readFileSync(fullPath, "utf-8");
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 fs24 from "fs";
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 = fs24.statSync(filePath);
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 = fs24.openSync(filePath, "r");
55747
+ const fd = fs25.openSync(filePath, "r");
55032
55748
  const buffer = Buffer.alloc(8192);
55033
- const bytesRead = fs24.readSync(fd, buffer, 0, 8192, 0);
55034
- fs24.closeSync(fd);
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 = fs24.readFileSync(filePath, "utf-8");
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 (!fs24.existsSync(resolvedPath)) {
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 validateDirectory(dir, workspaceDir) {
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 = fs25.statSync(file3);
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 = fs25.readFileSync(file3);
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 = validateDirectory(directory, effectiveWorkspaceDir);
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 = validateDirectory(resolvedDirectory, workspaceAnchor);
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 fs26 from "fs";
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 = fs26.readdirSync(dir, { withFileTypes: true });
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 = fs26.readdirSync(dir, { withFileTypes: true });
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
- fs26.mkdirSync(outputDir, { recursive: true });
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 (!fs26.existsSync(fullPath)) {
57770
+ if (!fs27.existsSync(fullPath)) {
57055
57771
  continue;
57056
57772
  }
57057
- const content = fs26.readFileSync(fullPath, "utf-8");
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
- fs26.writeFileSync(outputPath, bomJson, "utf-8");
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 fs27 from "fs";
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 = fs27.statSync(resolvedPath);
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 (!fs27.existsSync(resolvedPath)) {
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 (fs27.existsSync(candidatePath)) {
57167
- const stats = fs27.statSync(candidatePath);
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 = fs27.readFileSync(specFile, "utf-8");
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 = fs27.readdirSync(dir, { withFileTypes: true });
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 = fs27.readFileSync(filePath, "utf-8");
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 fs28 from "fs";
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 = fs28.realpathSync(workspace);
57459
- const realResolvedPath = fs28.realpathSync(resolvedPath);
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 = fs28.statSync(fullPath);
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 = fs28.readFileSync(fullPath, "utf-8");
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 = fs28.statSync(fullPath);
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 = fs28.readFileSync(fullPath, "utf-8");
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 fs29 from "fs";
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 = fs29.realpathSync(resolvedDir);
58563
+ const realPath = fs30.realpathSync(resolvedDir);
57848
58564
  const planPath = path42.join(realPath, ".swarm", "plan.json");
57849
- if (!fs29.existsSync(planPath)) {
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 fs30 from "fs";
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 = fs30.readdirSync(dir);
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 = fs30.statSync(fullPath);
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 (!fs30.existsSync(scanPath)) {
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 = fs30.statSync(scanPath);
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 = fs30.statSync(filePath);
58846
+ const fileStat = fs31.statSync(filePath);
58131
58847
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
58132
58848
  continue;
58133
58849
  }
58134
- const content = fs30.readFileSync(filePath, "utf-8");
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"