opencode-swarm 6.41.2 → 6.41.4

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
@@ -32342,7 +32342,7 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
32342
32342
  lesson,
32343
32343
  category: "architecture",
32344
32344
  tags: ["hidden-coupling", "co-change", "dark-matter"],
32345
- scope: "project",
32345
+ scope: "global",
32346
32346
  confidence,
32347
32347
  status: "candidate",
32348
32348
  confirmed_by: [],
@@ -35466,9 +35466,52 @@ var init_secretscan = __esm(() => {
35466
35466
  });
35467
35467
  });
35468
35468
 
35469
- // src/tools/test-runner.ts
35469
+ // src/tools/resolve-working-directory.ts
35470
35470
  import * as fs15 from "fs";
35471
35471
  import * as path26 from "path";
35472
+ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
35473
+ if (workingDirectory == null || workingDirectory === "") {
35474
+ return { success: true, directory: fallbackDirectory };
35475
+ }
35476
+ if (workingDirectory.includes("\x00")) {
35477
+ return {
35478
+ success: false,
35479
+ message: "Invalid working_directory: null bytes are not allowed"
35480
+ };
35481
+ }
35482
+ if (process.platform === "win32") {
35483
+ const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
35484
+ if (devicePathPattern.test(workingDirectory)) {
35485
+ return {
35486
+ success: false,
35487
+ message: "Invalid working_directory: Windows device paths are not allowed"
35488
+ };
35489
+ }
35490
+ }
35491
+ const normalizedDir = path26.normalize(workingDirectory);
35492
+ const pathParts = normalizedDir.split(path26.sep);
35493
+ if (pathParts.includes("..")) {
35494
+ return {
35495
+ success: false,
35496
+ message: "Invalid working_directory: path traversal sequences (..) are not allowed"
35497
+ };
35498
+ }
35499
+ const resolvedDir = path26.resolve(normalizedDir);
35500
+ try {
35501
+ const realPath = fs15.realpathSync(resolvedDir);
35502
+ return { success: true, directory: realPath };
35503
+ } catch {
35504
+ return {
35505
+ success: false,
35506
+ message: `Invalid working_directory: path "${resolvedDir}" does not exist or is inaccessible`
35507
+ };
35508
+ }
35509
+ }
35510
+ var init_resolve_working_directory = () => {};
35511
+
35512
+ // src/tools/test-runner.ts
35513
+ import * as fs16 from "fs";
35514
+ import * as path27 from "path";
35472
35515
  function isAbsolutePath(str) {
35473
35516
  if (str.startsWith("/"))
35474
35517
  return true;
@@ -35533,19 +35576,19 @@ function hasDevDependency(devDeps, ...patterns) {
35533
35576
  return hasPackageJsonDependency(devDeps, ...patterns);
35534
35577
  }
35535
35578
  function detectGoTest(cwd) {
35536
- return fs15.existsSync(path26.join(cwd, "go.mod")) && isCommandAvailable("go");
35579
+ return fs16.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
35537
35580
  }
35538
35581
  function detectJavaMaven(cwd) {
35539
- return fs15.existsSync(path26.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
35582
+ return fs16.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
35540
35583
  }
35541
35584
  function detectGradle(cwd) {
35542
- const hasBuildFile = fs15.existsSync(path26.join(cwd, "build.gradle")) || fs15.existsSync(path26.join(cwd, "build.gradle.kts"));
35543
- const hasGradlew = fs15.existsSync(path26.join(cwd, "gradlew")) || fs15.existsSync(path26.join(cwd, "gradlew.bat"));
35585
+ const hasBuildFile = fs16.existsSync(path27.join(cwd, "build.gradle")) || fs16.existsSync(path27.join(cwd, "build.gradle.kts"));
35586
+ const hasGradlew = fs16.existsSync(path27.join(cwd, "gradlew")) || fs16.existsSync(path27.join(cwd, "gradlew.bat"));
35544
35587
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
35545
35588
  }
35546
35589
  function detectDotnetTest(cwd) {
35547
35590
  try {
35548
- const files = fs15.readdirSync(cwd);
35591
+ const files = fs16.readdirSync(cwd);
35549
35592
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
35550
35593
  return hasCsproj && isCommandAvailable("dotnet");
35551
35594
  } catch {
@@ -35553,32 +35596,32 @@ function detectDotnetTest(cwd) {
35553
35596
  }
35554
35597
  }
35555
35598
  function detectCTest(cwd) {
35556
- const hasSource = fs15.existsSync(path26.join(cwd, "CMakeLists.txt"));
35557
- const hasBuildCache = fs15.existsSync(path26.join(cwd, "CMakeCache.txt")) || fs15.existsSync(path26.join(cwd, "build", "CMakeCache.txt"));
35599
+ const hasSource = fs16.existsSync(path27.join(cwd, "CMakeLists.txt"));
35600
+ const hasBuildCache = fs16.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
35558
35601
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
35559
35602
  }
35560
35603
  function detectSwiftTest(cwd) {
35561
- return fs15.existsSync(path26.join(cwd, "Package.swift")) && isCommandAvailable("swift");
35604
+ return fs16.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
35562
35605
  }
35563
35606
  function detectDartTest(cwd) {
35564
- return fs15.existsSync(path26.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
35607
+ return fs16.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
35565
35608
  }
35566
35609
  function detectRSpec(cwd) {
35567
- const hasRSpecFile = fs15.existsSync(path26.join(cwd, ".rspec"));
35568
- const hasGemfile = fs15.existsSync(path26.join(cwd, "Gemfile"));
35569
- const hasSpecDir = fs15.existsSync(path26.join(cwd, "spec"));
35610
+ const hasRSpecFile = fs16.existsSync(path27.join(cwd, ".rspec"));
35611
+ const hasGemfile = fs16.existsSync(path27.join(cwd, "Gemfile"));
35612
+ const hasSpecDir = fs16.existsSync(path27.join(cwd, "spec"));
35570
35613
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
35571
35614
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
35572
35615
  }
35573
35616
  function detectMinitest(cwd) {
35574
- return fs15.existsSync(path26.join(cwd, "test")) && (fs15.existsSync(path26.join(cwd, "Gemfile")) || fs15.existsSync(path26.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
35617
+ return fs16.existsSync(path27.join(cwd, "test")) && (fs16.existsSync(path27.join(cwd, "Gemfile")) || fs16.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
35575
35618
  }
35576
35619
  async function detectTestFramework(cwd) {
35577
35620
  const baseDir = cwd;
35578
35621
  try {
35579
- const packageJsonPath = path26.join(baseDir, "package.json");
35580
- if (fs15.existsSync(packageJsonPath)) {
35581
- const content = fs15.readFileSync(packageJsonPath, "utf-8");
35622
+ const packageJsonPath = path27.join(baseDir, "package.json");
35623
+ if (fs16.existsSync(packageJsonPath)) {
35624
+ const content = fs16.readFileSync(packageJsonPath, "utf-8");
35582
35625
  const pkg = JSON.parse(content);
35583
35626
  const _deps = pkg.dependencies || {};
35584
35627
  const devDeps = pkg.devDependencies || {};
@@ -35597,38 +35640,38 @@ async function detectTestFramework(cwd) {
35597
35640
  return "jest";
35598
35641
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
35599
35642
  return "mocha";
35600
- if (fs15.existsSync(path26.join(baseDir, "bun.lockb")) || fs15.existsSync(path26.join(baseDir, "bun.lock"))) {
35643
+ if (fs16.existsSync(path27.join(baseDir, "bun.lockb")) || fs16.existsSync(path27.join(baseDir, "bun.lock"))) {
35601
35644
  if (scripts.test?.includes("bun"))
35602
35645
  return "bun";
35603
35646
  }
35604
35647
  }
35605
35648
  } catch {}
35606
35649
  try {
35607
- const pyprojectTomlPath = path26.join(baseDir, "pyproject.toml");
35608
- const setupCfgPath = path26.join(baseDir, "setup.cfg");
35609
- const requirementsTxtPath = path26.join(baseDir, "requirements.txt");
35610
- if (fs15.existsSync(pyprojectTomlPath)) {
35611
- const content = fs15.readFileSync(pyprojectTomlPath, "utf-8");
35650
+ const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
35651
+ const setupCfgPath = path27.join(baseDir, "setup.cfg");
35652
+ const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
35653
+ if (fs16.existsSync(pyprojectTomlPath)) {
35654
+ const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
35612
35655
  if (content.includes("[tool.pytest"))
35613
35656
  return "pytest";
35614
35657
  if (content.includes("pytest"))
35615
35658
  return "pytest";
35616
35659
  }
35617
- if (fs15.existsSync(setupCfgPath)) {
35618
- const content = fs15.readFileSync(setupCfgPath, "utf-8");
35660
+ if (fs16.existsSync(setupCfgPath)) {
35661
+ const content = fs16.readFileSync(setupCfgPath, "utf-8");
35619
35662
  if (content.includes("[pytest]"))
35620
35663
  return "pytest";
35621
35664
  }
35622
- if (fs15.existsSync(requirementsTxtPath)) {
35623
- const content = fs15.readFileSync(requirementsTxtPath, "utf-8");
35665
+ if (fs16.existsSync(requirementsTxtPath)) {
35666
+ const content = fs16.readFileSync(requirementsTxtPath, "utf-8");
35624
35667
  if (content.includes("pytest"))
35625
35668
  return "pytest";
35626
35669
  }
35627
35670
  } catch {}
35628
35671
  try {
35629
- const cargoTomlPath = path26.join(baseDir, "Cargo.toml");
35630
- if (fs15.existsSync(cargoTomlPath)) {
35631
- const content = fs15.readFileSync(cargoTomlPath, "utf-8");
35672
+ const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
35673
+ if (fs16.existsSync(cargoTomlPath)) {
35674
+ const content = fs16.readFileSync(cargoTomlPath, "utf-8");
35632
35675
  if (content.includes("[dev-dependencies]")) {
35633
35676
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
35634
35677
  return "cargo";
@@ -35637,10 +35680,10 @@ async function detectTestFramework(cwd) {
35637
35680
  }
35638
35681
  } catch {}
35639
35682
  try {
35640
- const pesterConfigPath = path26.join(baseDir, "pester.config.ps1");
35641
- const pesterConfigJsonPath = path26.join(baseDir, "pester.config.ps1.json");
35642
- const pesterPs1Path = path26.join(baseDir, "tests.ps1");
35643
- if (fs15.existsSync(pesterConfigPath) || fs15.existsSync(pesterConfigJsonPath) || fs15.existsSync(pesterPs1Path)) {
35683
+ const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
35684
+ const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
35685
+ const pesterPs1Path = path27.join(baseDir, "tests.ps1");
35686
+ if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
35644
35687
  return "pester";
35645
35688
  }
35646
35689
  } catch {}
@@ -35672,8 +35715,8 @@ function getTestFilesFromConvention(sourceFiles) {
35672
35715
  const testFiles = [];
35673
35716
  for (const file3 of sourceFiles) {
35674
35717
  const normalizedPath = file3.replace(/\\/g, "/");
35675
- const basename4 = path26.basename(file3);
35676
- const dirname11 = path26.dirname(file3);
35718
+ const basename4 = path27.basename(file3);
35719
+ const dirname11 = path27.dirname(file3);
35677
35720
  if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
35678
35721
  if (!testFiles.includes(file3)) {
35679
35722
  testFiles.push(file3);
@@ -35682,16 +35725,16 @@ function getTestFilesFromConvention(sourceFiles) {
35682
35725
  }
35683
35726
  for (const _pattern of TEST_PATTERNS) {
35684
35727
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
35685
- const ext = path26.extname(basename4);
35728
+ const ext = path27.extname(basename4);
35686
35729
  const possibleTestFiles = [
35687
- path26.join(dirname11, `${nameWithoutExt}.spec${ext}`),
35688
- path26.join(dirname11, `${nameWithoutExt}.test${ext}`),
35689
- path26.join(dirname11, "__tests__", `${nameWithoutExt}${ext}`),
35690
- path26.join(dirname11, "tests", `${nameWithoutExt}${ext}`),
35691
- path26.join(dirname11, "test", `${nameWithoutExt}${ext}`)
35730
+ path27.join(dirname11, `${nameWithoutExt}.spec${ext}`),
35731
+ path27.join(dirname11, `${nameWithoutExt}.test${ext}`),
35732
+ path27.join(dirname11, "__tests__", `${nameWithoutExt}${ext}`),
35733
+ path27.join(dirname11, "tests", `${nameWithoutExt}${ext}`),
35734
+ path27.join(dirname11, "test", `${nameWithoutExt}${ext}`)
35692
35735
  ];
35693
35736
  for (const testFile of possibleTestFiles) {
35694
- if (fs15.existsSync(testFile) && !testFiles.includes(testFile)) {
35737
+ if (fs16.existsSync(testFile) && !testFiles.includes(testFile)) {
35695
35738
  testFiles.push(testFile);
35696
35739
  }
35697
35740
  }
@@ -35707,8 +35750,8 @@ async function getTestFilesFromGraph(sourceFiles) {
35707
35750
  }
35708
35751
  for (const testFile of candidateTestFiles) {
35709
35752
  try {
35710
- const content = fs15.readFileSync(testFile, "utf-8");
35711
- const testDir = path26.dirname(testFile);
35753
+ const content = fs16.readFileSync(testFile, "utf-8");
35754
+ const testDir = path27.dirname(testFile);
35712
35755
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
35713
35756
  let match;
35714
35757
  match = importRegex.exec(content);
@@ -35716,8 +35759,8 @@ async function getTestFilesFromGraph(sourceFiles) {
35716
35759
  const importPath = match[1];
35717
35760
  let resolvedImport;
35718
35761
  if (importPath.startsWith(".")) {
35719
- resolvedImport = path26.resolve(testDir, importPath);
35720
- const existingExt = path26.extname(resolvedImport);
35762
+ resolvedImport = path27.resolve(testDir, importPath);
35763
+ const existingExt = path27.extname(resolvedImport);
35721
35764
  if (!existingExt) {
35722
35765
  for (const extToTry of [
35723
35766
  ".ts",
@@ -35728,7 +35771,7 @@ async function getTestFilesFromGraph(sourceFiles) {
35728
35771
  ".cjs"
35729
35772
  ]) {
35730
35773
  const withExt = resolvedImport + extToTry;
35731
- if (sourceFiles.includes(withExt) || fs15.existsSync(withExt)) {
35774
+ if (sourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
35732
35775
  resolvedImport = withExt;
35733
35776
  break;
35734
35777
  }
@@ -35737,12 +35780,12 @@ async function getTestFilesFromGraph(sourceFiles) {
35737
35780
  } else {
35738
35781
  continue;
35739
35782
  }
35740
- const importBasename = path26.basename(resolvedImport, path26.extname(resolvedImport));
35741
- const importDir = path26.dirname(resolvedImport);
35783
+ const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
35784
+ const importDir = path27.dirname(resolvedImport);
35742
35785
  for (const sourceFile of sourceFiles) {
35743
- const sourceDir = path26.dirname(sourceFile);
35744
- const sourceBasename = path26.basename(sourceFile, path26.extname(sourceFile));
35745
- const isRelatedDir = importDir === sourceDir || importDir === path26.join(sourceDir, "__tests__") || importDir === path26.join(sourceDir, "tests") || importDir === path26.join(sourceDir, "test");
35786
+ const sourceDir = path27.dirname(sourceFile);
35787
+ const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
35788
+ const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test");
35746
35789
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
35747
35790
  if (!testFiles.includes(testFile)) {
35748
35791
  testFiles.push(testFile);
@@ -35757,8 +35800,8 @@ async function getTestFilesFromGraph(sourceFiles) {
35757
35800
  while (match !== null) {
35758
35801
  const importPath = match[1];
35759
35802
  if (importPath.startsWith(".")) {
35760
- let resolvedImport = path26.resolve(testDir, importPath);
35761
- const existingExt = path26.extname(resolvedImport);
35803
+ let resolvedImport = path27.resolve(testDir, importPath);
35804
+ const existingExt = path27.extname(resolvedImport);
35762
35805
  if (!existingExt) {
35763
35806
  for (const extToTry of [
35764
35807
  ".ts",
@@ -35769,18 +35812,18 @@ async function getTestFilesFromGraph(sourceFiles) {
35769
35812
  ".cjs"
35770
35813
  ]) {
35771
35814
  const withExt = resolvedImport + extToTry;
35772
- if (sourceFiles.includes(withExt) || fs15.existsSync(withExt)) {
35815
+ if (sourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
35773
35816
  resolvedImport = withExt;
35774
35817
  break;
35775
35818
  }
35776
35819
  }
35777
35820
  }
35778
- const importDir = path26.dirname(resolvedImport);
35779
- const importBasename = path26.basename(resolvedImport, path26.extname(resolvedImport));
35821
+ const importDir = path27.dirname(resolvedImport);
35822
+ const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
35780
35823
  for (const sourceFile of sourceFiles) {
35781
- const sourceDir = path26.dirname(sourceFile);
35782
- const sourceBasename = path26.basename(sourceFile, path26.extname(sourceFile));
35783
- const isRelatedDir = importDir === sourceDir || importDir === path26.join(sourceDir, "__tests__") || importDir === path26.join(sourceDir, "tests") || importDir === path26.join(sourceDir, "test");
35824
+ const sourceDir = path27.dirname(sourceFile);
35825
+ const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
35826
+ const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test");
35784
35827
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
35785
35828
  if (!testFiles.includes(testFile)) {
35786
35829
  testFiles.push(testFile);
@@ -35865,8 +35908,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
35865
35908
  return ["mvn", "test"];
35866
35909
  case "gradle": {
35867
35910
  const isWindows = process.platform === "win32";
35868
- const hasGradlewBat = fs15.existsSync(path26.join(baseDir, "gradlew.bat"));
35869
- const hasGradlew = fs15.existsSync(path26.join(baseDir, "gradlew"));
35911
+ const hasGradlewBat = fs16.existsSync(path27.join(baseDir, "gradlew.bat"));
35912
+ const hasGradlew = fs16.existsSync(path27.join(baseDir, "gradlew"));
35870
35913
  if (hasGradlewBat && isWindows)
35871
35914
  return ["gradlew.bat", "test"];
35872
35915
  if (hasGradlew)
@@ -35883,7 +35926,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
35883
35926
  "cmake-build-release",
35884
35927
  "out"
35885
35928
  ];
35886
- const actualBuildDir = buildDirCandidates.find((d) => fs15.existsSync(path26.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
35929
+ const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
35887
35930
  return ["ctest", "--test-dir", actualBuildDir];
35888
35931
  }
35889
35932
  case "swift-test":
@@ -36115,6 +36158,43 @@ function parseTestOutput(framework, output) {
36115
36158
  }
36116
36159
  return { totals, coveragePercent };
36117
36160
  }
36161
+ async function readBoundedStream(stream, maxBytes) {
36162
+ const reader = stream.getReader();
36163
+ const chunks = [];
36164
+ let totalBytes = 0;
36165
+ let truncated = false;
36166
+ try {
36167
+ while (true) {
36168
+ const { done, value } = await reader.read();
36169
+ if (done)
36170
+ break;
36171
+ if (totalBytes + value.length > maxBytes) {
36172
+ const remaining = maxBytes - totalBytes;
36173
+ if (remaining > 0) {
36174
+ chunks.push(value.slice(0, remaining));
36175
+ }
36176
+ totalBytes = maxBytes;
36177
+ truncated = true;
36178
+ reader.cancel().catch(() => {});
36179
+ break;
36180
+ }
36181
+ chunks.push(value);
36182
+ totalBytes += value.length;
36183
+ }
36184
+ } catch {} finally {
36185
+ try {
36186
+ reader.releaseLock();
36187
+ } catch {}
36188
+ }
36189
+ const decoder = new TextDecoder("utf-8", { fatal: false });
36190
+ const combined = new Uint8Array(totalBytes);
36191
+ let offset = 0;
36192
+ for (const chunk of chunks) {
36193
+ combined.set(chunk, offset);
36194
+ offset += chunk.length;
36195
+ }
36196
+ return { text: decoder.decode(combined), truncated };
36197
+ }
36118
36198
  async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
36119
36199
  const command = buildTestCommand(framework, scope, files, coverage, cwd);
36120
36200
  if (!command) {
@@ -36143,34 +36223,24 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
36143
36223
  stderr: "pipe",
36144
36224
  cwd
36145
36225
  });
36146
- const exitPromise = proc.exited;
36147
- const timeoutPromise = new Promise((resolve8) => setTimeout(() => {
36226
+ const timeoutPromise = new Promise((resolve9) => setTimeout(() => {
36148
36227
  proc.kill();
36149
- resolve8(-1);
36228
+ resolve9(-1);
36150
36229
  }, timeout_ms));
36151
- const exitCode = await Promise.race([exitPromise, timeoutPromise]);
36152
- const duration_ms = Date.now() - startTime;
36153
- const [stdout, stderr] = await Promise.all([
36154
- new Response(proc.stdout).text(),
36155
- new Response(proc.stderr).text()
36230
+ const [exitCode, stdoutResult, stderrResult] = await Promise.all([
36231
+ Promise.race([proc.exited, timeoutPromise]),
36232
+ readBoundedStream(proc.stdout, MAX_OUTPUT_BYTES3),
36233
+ readBoundedStream(proc.stderr, MAX_OUTPUT_BYTES3)
36156
36234
  ]);
36157
- let output = stdout;
36158
- if (stderr) {
36235
+ const duration_ms = Date.now() - startTime;
36236
+ let output = stdoutResult.text;
36237
+ if (stderrResult.text) {
36159
36238
  output += (output ? `
36160
- ` : "") + stderr;
36239
+ ` : "") + stderrResult.text;
36161
36240
  }
36162
- const outputBytes = Buffer.byteLength(output, "utf-8");
36163
- if (outputBytes > MAX_OUTPUT_BYTES3) {
36164
- let truncIndex = MAX_OUTPUT_BYTES3;
36165
- while (truncIndex > 0) {
36166
- const truncated = output.slice(0, truncIndex);
36167
- if (Buffer.byteLength(truncated, "utf-8") <= MAX_OUTPUT_BYTES3) {
36168
- break;
36169
- }
36170
- truncIndex--;
36171
- }
36172
- output = `${output.slice(0, truncIndex)}
36173
- ... (output truncated)`;
36241
+ if (stdoutResult.truncated || stderrResult.truncated) {
36242
+ output += `
36243
+ ... (output truncated at stream read limit)`;
36174
36244
  }
36175
36245
  const { totals, coveragePercent } = parseTestOutput(framework, output);
36176
36246
  const isTimeout = exitCode === -1;
@@ -36230,6 +36300,7 @@ var init_test_runner = __esm(() => {
36230
36300
  init_dist();
36231
36301
  init_discovery();
36232
36302
  init_create_tool();
36303
+ init_resolve_working_directory();
36233
36304
  POWERSHELL_METACHARACTERS = /[|;&`$(){}[\]<>"'#*?\x00-\x1f]/;
36234
36305
  TEST_PATTERNS = [
36235
36306
  { test: ".spec.", source: "." },
@@ -36309,10 +36380,26 @@ var init_test_runner = __esm(() => {
36309
36380
  files: tool.schema.array(tool.schema.string()).optional().describe("Specific files to test (used with convention or graph scope)"),
36310
36381
  coverage: tool.schema.boolean().optional().describe("Enable coverage reporting if supported"),
36311
36382
  timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
36312
- allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.')
36383
+ allow_full_suite: tool.schema.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
36384
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
36313
36385
  },
36314
36386
  async execute(args2, directory) {
36315
- const workingDir = directory.trim() || directory;
36387
+ let workingDirInput;
36388
+ if (args2 && typeof args2 === "object") {
36389
+ const obj = args2;
36390
+ workingDirInput = typeof obj.working_directory === "string" ? obj.working_directory : undefined;
36391
+ }
36392
+ const dirResult = resolveWorkingDirectory(workingDirInput, directory);
36393
+ if (!dirResult.success) {
36394
+ const errorResult = {
36395
+ success: false,
36396
+ framework: "none",
36397
+ scope: "all",
36398
+ error: dirResult.message
36399
+ };
36400
+ return JSON.stringify(errorResult, null, 2);
36401
+ }
36402
+ const workingDir = dirResult.directory;
36316
36403
  if (workingDir.length > 4096) {
36317
36404
  const errorResult = {
36318
36405
  success: false,
@@ -36366,8 +36453,8 @@ var init_test_runner = __esm(() => {
36366
36453
  success: false,
36367
36454
  framework: "none",
36368
36455
  scope: "all",
36369
- error: 'Full-suite test execution (scope: "all") requires allow_full_suite: true',
36370
- message: 'Set allow_full_suite: true to confirm intentional full-suite execution. Use scope "convention" or "graph" for targeted tests. Full-suite output is large and may destabilize SSE streaming on some opencode versions.'
36456
+ error: 'scope "all" is not allowed without explicit files. Use scope "convention" or "graph" with a files array to run targeted tests.',
36457
+ message: 'Running the full test suite without file targeting is blocked. Provide scope "convention" or "graph" with specific source files in the files array. Example: { scope: "convention", files: ["src/tools/test-runner.ts"] }'
36371
36458
  };
36372
36459
  return JSON.stringify(errorResult, null, 2);
36373
36460
  }
@@ -36407,7 +36494,7 @@ var init_test_runner = __esm(() => {
36407
36494
  let effectiveScope = scope;
36408
36495
  if (scope === "all") {} else if (scope === "convention") {
36409
36496
  const sourceFiles = args2.files.filter((f) => {
36410
- const ext = path26.extname(f).toLowerCase();
36497
+ const ext = path27.extname(f).toLowerCase();
36411
36498
  return SOURCE_EXTENSIONS.has(ext);
36412
36499
  });
36413
36500
  if (sourceFiles.length === 0) {
@@ -36423,7 +36510,7 @@ var init_test_runner = __esm(() => {
36423
36510
  testFiles = getTestFilesFromConvention(sourceFiles);
36424
36511
  } else if (scope === "graph") {
36425
36512
  const sourceFiles = args2.files.filter((f) => {
36426
- const ext = path26.extname(f).toLowerCase();
36513
+ const ext = path27.extname(f).toLowerCase();
36427
36514
  return SOURCE_EXTENSIONS.has(ext);
36428
36515
  });
36429
36516
  if (sourceFiles.length === 0) {
@@ -36476,8 +36563,8 @@ var init_test_runner = __esm(() => {
36476
36563
  });
36477
36564
 
36478
36565
  // src/services/preflight-service.ts
36479
- import * as fs16 from "fs";
36480
- import * as path27 from "path";
36566
+ import * as fs17 from "fs";
36567
+ import * as path28 from "path";
36481
36568
  function validateDirectoryPath(dir) {
36482
36569
  if (!dir || typeof dir !== "string") {
36483
36570
  throw new Error("Directory path is required");
@@ -36485,8 +36572,8 @@ function validateDirectoryPath(dir) {
36485
36572
  if (dir.includes("..")) {
36486
36573
  throw new Error("Directory path must not contain path traversal sequences");
36487
36574
  }
36488
- const normalized = path27.normalize(dir);
36489
- const absolutePath = path27.isAbsolute(normalized) ? normalized : path27.resolve(normalized);
36575
+ const normalized = path28.normalize(dir);
36576
+ const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
36490
36577
  return absolutePath;
36491
36578
  }
36492
36579
  function validateTimeout(timeoutMs, defaultValue) {
@@ -36509,9 +36596,9 @@ function validateTimeout(timeoutMs, defaultValue) {
36509
36596
  }
36510
36597
  function getPackageVersion(dir) {
36511
36598
  try {
36512
- const packagePath = path27.join(dir, "package.json");
36513
- if (fs16.existsSync(packagePath)) {
36514
- const content = fs16.readFileSync(packagePath, "utf-8");
36599
+ const packagePath = path28.join(dir, "package.json");
36600
+ if (fs17.existsSync(packagePath)) {
36601
+ const content = fs17.readFileSync(packagePath, "utf-8");
36515
36602
  const pkg = JSON.parse(content);
36516
36603
  return pkg.version ?? null;
36517
36604
  }
@@ -36520,9 +36607,9 @@ function getPackageVersion(dir) {
36520
36607
  }
36521
36608
  function getChangelogVersion(dir) {
36522
36609
  try {
36523
- const changelogPath = path27.join(dir, "CHANGELOG.md");
36524
- if (fs16.existsSync(changelogPath)) {
36525
- const content = fs16.readFileSync(changelogPath, "utf-8");
36610
+ const changelogPath = path28.join(dir, "CHANGELOG.md");
36611
+ if (fs17.existsSync(changelogPath)) {
36612
+ const content = fs17.readFileSync(changelogPath, "utf-8");
36526
36613
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
36527
36614
  if (match) {
36528
36615
  return match[1];
@@ -36534,10 +36621,10 @@ function getChangelogVersion(dir) {
36534
36621
  function getVersionFileVersion(dir) {
36535
36622
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
36536
36623
  for (const file3 of possibleFiles) {
36537
- const filePath = path27.join(dir, file3);
36538
- if (fs16.existsSync(filePath)) {
36624
+ const filePath = path28.join(dir, file3);
36625
+ if (fs17.existsSync(filePath)) {
36539
36626
  try {
36540
- const content = fs16.readFileSync(filePath, "utf-8").trim();
36627
+ const content = fs17.readFileSync(filePath, "utf-8").trim();
36541
36628
  const match = content.match(/(\d+\.\d+\.\d+)/);
36542
36629
  if (match) {
36543
36630
  return match[1];
@@ -37062,7 +37149,7 @@ __export(exports_gate_evidence, {
37062
37149
  DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
37063
37150
  });
37064
37151
  import { mkdirSync as mkdirSync10, readFileSync as readFileSync14, renameSync as renameSync9, unlinkSync as unlinkSync5 } from "fs";
37065
- import * as path33 from "path";
37152
+ import * as path34 from "path";
37066
37153
  function isValidTaskId2(taskId) {
37067
37154
  if (!taskId)
37068
37155
  return false;
@@ -37109,10 +37196,10 @@ function expandRequiredGates(existingGates, newAgentType) {
37109
37196
  return combined.sort();
37110
37197
  }
37111
37198
  function getEvidenceDir(directory) {
37112
- return path33.join(directory, ".swarm", "evidence");
37199
+ return path34.join(directory, ".swarm", "evidence");
37113
37200
  }
37114
37201
  function getEvidencePath(directory, taskId) {
37115
- return path33.join(getEvidenceDir(directory), `${taskId}.json`);
37202
+ return path34.join(getEvidenceDir(directory), `${taskId}.json`);
37116
37203
  }
37117
37204
  function readExisting(evidencePath) {
37118
37205
  try {
@@ -37282,15 +37369,15 @@ __export(exports_doc_scan, {
37282
37369
  doc_extract: () => doc_extract
37283
37370
  });
37284
37371
  import * as crypto4 from "crypto";
37285
- import * as fs26 from "fs";
37372
+ import * as fs27 from "fs";
37286
37373
  import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
37287
- import * as path38 from "path";
37374
+ import * as path39 from "path";
37288
37375
  function normalizeSeparators(filePath) {
37289
37376
  return filePath.replace(/\\/g, "/");
37290
37377
  }
37291
37378
  function matchesDocPattern(filePath, patterns) {
37292
37379
  const normalizedPath = normalizeSeparators(filePath);
37293
- const basename5 = path38.basename(filePath);
37380
+ const basename5 = path39.basename(filePath);
37294
37381
  for (const pattern of patterns) {
37295
37382
  if (!pattern.includes("/") && !pattern.includes("\\")) {
37296
37383
  if (basename5 === pattern) {
@@ -37346,7 +37433,7 @@ function stripMarkdown(text) {
37346
37433
  return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
37347
37434
  }
37348
37435
  async function scanDocIndex(directory) {
37349
- const manifestPath = path38.join(directory, ".swarm", "doc-manifest.json");
37436
+ const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
37350
37437
  const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
37351
37438
  const extraPatterns = [
37352
37439
  "ARCHITECTURE.md",
@@ -37363,8 +37450,8 @@ async function scanDocIndex(directory) {
37363
37450
  let cacheValid = true;
37364
37451
  for (const file3 of existingManifest.files) {
37365
37452
  try {
37366
- const fullPath = path38.join(directory, file3.path);
37367
- const stat2 = fs26.statSync(fullPath);
37453
+ const fullPath = path39.join(directory, file3.path);
37454
+ const stat2 = fs27.statSync(fullPath);
37368
37455
  if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
37369
37456
  cacheValid = false;
37370
37457
  break;
@@ -37382,7 +37469,7 @@ async function scanDocIndex(directory) {
37382
37469
  const discoveredFiles = [];
37383
37470
  let rawEntries;
37384
37471
  try {
37385
- rawEntries = fs26.readdirSync(directory, { recursive: true });
37472
+ rawEntries = fs27.readdirSync(directory, { recursive: true });
37386
37473
  } catch {
37387
37474
  const manifest2 = {
37388
37475
  schema_version: 1,
@@ -37393,10 +37480,10 @@ async function scanDocIndex(directory) {
37393
37480
  }
37394
37481
  const entries = rawEntries.filter((e) => typeof e === "string");
37395
37482
  for (const entry of entries) {
37396
- const fullPath = path38.join(directory, entry);
37483
+ const fullPath = path39.join(directory, entry);
37397
37484
  let stat2;
37398
37485
  try {
37399
- stat2 = fs26.statSync(fullPath);
37486
+ stat2 = fs27.statSync(fullPath);
37400
37487
  } catch {
37401
37488
  continue;
37402
37489
  }
@@ -37425,11 +37512,11 @@ async function scanDocIndex(directory) {
37425
37512
  }
37426
37513
  let content;
37427
37514
  try {
37428
- content = fs26.readFileSync(fullPath, "utf-8");
37515
+ content = fs27.readFileSync(fullPath, "utf-8");
37429
37516
  } catch {
37430
37517
  continue;
37431
37518
  }
37432
- const { title, summary } = extractTitleAndSummary(content, path38.basename(entry));
37519
+ const { title, summary } = extractTitleAndSummary(content, path39.basename(entry));
37433
37520
  const lineCount = content.split(`
37434
37521
  `).length;
37435
37522
  discoveredFiles.push({
@@ -37455,7 +37542,7 @@ async function scanDocIndex(directory) {
37455
37542
  files: discoveredFiles
37456
37543
  };
37457
37544
  try {
37458
- await mkdir6(path38.dirname(manifestPath), { recursive: true });
37545
+ await mkdir6(path39.dirname(manifestPath), { recursive: true });
37459
37546
  await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
37460
37547
  } catch {}
37461
37548
  return { manifest, cached: false };
@@ -37494,7 +37581,7 @@ function extractConstraintsFromContent(content) {
37494
37581
  return constraints;
37495
37582
  }
37496
37583
  async function extractDocConstraints(directory, taskFiles, taskDescription) {
37497
- const manifestPath = path38.join(directory, ".swarm", "doc-manifest.json");
37584
+ const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
37498
37585
  let manifest;
37499
37586
  try {
37500
37587
  const content = await readFile6(manifestPath, "utf-8");
@@ -37520,7 +37607,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
37520
37607
  }
37521
37608
  let fullContent;
37522
37609
  try {
37523
- fullContent = await readFile6(path38.join(directory, docFile.path), "utf-8");
37610
+ fullContent = await readFile6(path39.join(directory, docFile.path), "utf-8");
37524
37611
  } catch {
37525
37612
  skippedCount++;
37526
37613
  continue;
@@ -37543,7 +37630,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
37543
37630
  tier: "swarm",
37544
37631
  lesson: constraint,
37545
37632
  category: "architecture",
37546
- tags: ["doc-scan", path38.basename(docFile.path)],
37633
+ tags: ["doc-scan", path39.basename(docFile.path)],
37547
37634
  scope: "global",
37548
37635
  confidence: 0.5,
37549
37636
  status: "candidate",
@@ -37616,9 +37703,9 @@ var init_doc_scan = __esm(() => {
37616
37703
  }
37617
37704
  } catch {}
37618
37705
  if (force) {
37619
- const manifestPath = path38.join(directory, ".swarm", "doc-manifest.json");
37706
+ const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
37620
37707
  try {
37621
- fs26.unlinkSync(manifestPath);
37708
+ fs27.unlinkSync(manifestPath);
37622
37709
  } catch {}
37623
37710
  }
37624
37711
  const { manifest, cached: cached3 } = await scanDocIndex(directory);
@@ -37670,11 +37757,11 @@ __export(exports_curator_drift, {
37670
37757
  readPriorDriftReports: () => readPriorDriftReports,
37671
37758
  buildDriftInjectionText: () => buildDriftInjectionText
37672
37759
  });
37673
- import * as fs29 from "fs";
37674
- import * as path41 from "path";
37760
+ import * as fs30 from "fs";
37761
+ import * as path42 from "path";
37675
37762
  async function readPriorDriftReports(directory) {
37676
- const swarmDir = path41.join(directory, ".swarm");
37677
- const entries = await fs29.promises.readdir(swarmDir).catch(() => null);
37763
+ const swarmDir = path42.join(directory, ".swarm");
37764
+ const entries = await fs30.promises.readdir(swarmDir).catch(() => null);
37678
37765
  if (entries === null)
37679
37766
  return [];
37680
37767
  const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
@@ -37700,10 +37787,10 @@ async function readPriorDriftReports(directory) {
37700
37787
  async function writeDriftReport(directory, report) {
37701
37788
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
37702
37789
  const filePath = validateSwarmPath(directory, filename);
37703
- const swarmDir = path41.dirname(filePath);
37704
- await fs29.promises.mkdir(swarmDir, { recursive: true });
37790
+ const swarmDir = path42.dirname(filePath);
37791
+ await fs30.promises.mkdir(swarmDir, { recursive: true });
37705
37792
  try {
37706
- await fs29.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
37793
+ await fs30.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
37707
37794
  } catch (err2) {
37708
37795
  throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
37709
37796
  }
@@ -39270,8 +39357,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
39270
39357
  var moduleRtn;
39271
39358
  var Module = moduleArg;
39272
39359
  var readyPromiseResolve, readyPromiseReject;
39273
- var readyPromise = new Promise((resolve16, reject) => {
39274
- readyPromiseResolve = resolve16;
39360
+ var readyPromise = new Promise((resolve17, reject) => {
39361
+ readyPromiseResolve = resolve17;
39275
39362
  readyPromiseReject = reject;
39276
39363
  });
39277
39364
  var ENVIRONMENT_IS_WEB = typeof window == "object";
@@ -39293,11 +39380,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
39293
39380
  throw toThrow;
39294
39381
  }, "quit_");
39295
39382
  var scriptDirectory = "";
39296
- function locateFile(path49) {
39383
+ function locateFile(path50) {
39297
39384
  if (Module["locateFile"]) {
39298
- return Module["locateFile"](path49, scriptDirectory);
39385
+ return Module["locateFile"](path50, scriptDirectory);
39299
39386
  }
39300
- return scriptDirectory + path49;
39387
+ return scriptDirectory + path50;
39301
39388
  }
39302
39389
  __name(locateFile, "locateFile");
39303
39390
  var readAsync, readBinary;
@@ -39351,13 +39438,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
39351
39438
  }
39352
39439
  readAsync = /* @__PURE__ */ __name(async (url3) => {
39353
39440
  if (isFileURI(url3)) {
39354
- return new Promise((resolve16, reject) => {
39441
+ return new Promise((resolve17, reject) => {
39355
39442
  var xhr = new XMLHttpRequest;
39356
39443
  xhr.open("GET", url3, true);
39357
39444
  xhr.responseType = "arraybuffer";
39358
39445
  xhr.onload = () => {
39359
39446
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
39360
- resolve16(xhr.response);
39447
+ resolve17(xhr.response);
39361
39448
  return;
39362
39449
  }
39363
39450
  reject(xhr.status);
@@ -39577,10 +39664,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
39577
39664
  __name(receiveInstantiationResult, "receiveInstantiationResult");
39578
39665
  var info2 = getWasmImports();
39579
39666
  if (Module["instantiateWasm"]) {
39580
- return new Promise((resolve16, reject) => {
39667
+ return new Promise((resolve17, reject) => {
39581
39668
  Module["instantiateWasm"](info2, (mod, inst) => {
39582
39669
  receiveInstance(mod, inst);
39583
- resolve16(mod.exports);
39670
+ resolve17(mod.exports);
39584
39671
  });
39585
39672
  });
39586
39673
  }
@@ -41037,13 +41124,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
41037
41124
  });
41038
41125
 
41039
41126
  // src/lang/runtime.ts
41040
- import * as path49 from "path";
41127
+ import * as path50 from "path";
41041
41128
  import { fileURLToPath as fileURLToPath2 } from "url";
41042
41129
  async function initTreeSitter() {
41043
41130
  if (treeSitterInitialized) {
41044
41131
  return;
41045
41132
  }
41046
- const thisDir = path49.dirname(fileURLToPath2(import.meta.url));
41133
+ const thisDir = path50.dirname(fileURLToPath2(import.meta.url));
41047
41134
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41048
41135
  if (isSource) {
41049
41136
  await Parser.init();
@@ -41051,7 +41138,7 @@ async function initTreeSitter() {
41051
41138
  const grammarsDir = getGrammarsDirAbsolute();
41052
41139
  await Parser.init({
41053
41140
  locateFile(scriptName) {
41054
- return path49.join(grammarsDir, scriptName);
41141
+ return path50.join(grammarsDir, scriptName);
41055
41142
  }
41056
41143
  });
41057
41144
  }
@@ -41072,9 +41159,9 @@ function getWasmFileName(languageId) {
41072
41159
  return `tree-sitter-${sanitized}.wasm`;
41073
41160
  }
41074
41161
  function getGrammarsDirAbsolute() {
41075
- const thisDir = path49.dirname(fileURLToPath2(import.meta.url));
41162
+ const thisDir = path50.dirname(fileURLToPath2(import.meta.url));
41076
41163
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41077
- return isSource ? path49.join(thisDir, "grammars") : path49.join(thisDir, "lang", "grammars");
41164
+ return isSource ? path50.join(thisDir, "grammars") : path50.join(thisDir, "lang", "grammars");
41078
41165
  }
41079
41166
  async function loadGrammar(languageId) {
41080
41167
  if (typeof languageId !== "string" || languageId.length > 100) {
@@ -41090,7 +41177,7 @@ async function loadGrammar(languageId) {
41090
41177
  await initTreeSitter();
41091
41178
  const parser = new Parser;
41092
41179
  const wasmFileName = getWasmFileName(normalizedId);
41093
- const wasmPath = path49.join(getGrammarsDirAbsolute(), wasmFileName);
41180
+ const wasmPath = path50.join(getGrammarsDirAbsolute(), wasmFileName);
41094
41181
  const { existsSync: existsSync29 } = await import("fs");
41095
41182
  if (!existsSync29(wasmPath)) {
41096
41183
  throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
@@ -41137,7 +41224,7 @@ var init_runtime = __esm(() => {
41137
41224
  });
41138
41225
 
41139
41226
  // src/index.ts
41140
- import * as path66 from "path";
41227
+ import * as path67 from "path";
41141
41228
 
41142
41229
  // src/agents/index.ts
41143
41230
  init_config();
@@ -50040,7 +50127,7 @@ async function handlePromoteCommand(directory, args2) {
50040
50127
  }
50041
50128
 
50042
50129
  // src/commands/reset.ts
50043
- import * as fs17 from "fs";
50130
+ import * as fs18 from "fs";
50044
50131
  init_utils2();
50045
50132
  async function handleResetCommand(directory, args2) {
50046
50133
  const hasConfirm = args2.includes("--confirm");
@@ -50061,8 +50148,8 @@ async function handleResetCommand(directory, args2) {
50061
50148
  for (const filename of filesToReset) {
50062
50149
  try {
50063
50150
  const resolvedPath = validateSwarmPath(directory, filename);
50064
- if (fs17.existsSync(resolvedPath)) {
50065
- fs17.unlinkSync(resolvedPath);
50151
+ if (fs18.existsSync(resolvedPath)) {
50152
+ fs18.unlinkSync(resolvedPath);
50066
50153
  results.push(`- \u2705 Deleted ${filename}`);
50067
50154
  } else {
50068
50155
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -50079,8 +50166,8 @@ async function handleResetCommand(directory, args2) {
50079
50166
  }
50080
50167
  try {
50081
50168
  const summariesPath = validateSwarmPath(directory, "summaries");
50082
- if (fs17.existsSync(summariesPath)) {
50083
- fs17.rmSync(summariesPath, { recursive: true, force: true });
50169
+ if (fs18.existsSync(summariesPath)) {
50170
+ fs18.rmSync(summariesPath, { recursive: true, force: true });
50084
50171
  results.push("- \u2705 Deleted summaries/ directory");
50085
50172
  } else {
50086
50173
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -50100,14 +50187,14 @@ async function handleResetCommand(directory, args2) {
50100
50187
 
50101
50188
  // src/commands/reset-session.ts
50102
50189
  init_utils2();
50103
- import * as fs18 from "fs";
50104
- import * as path28 from "path";
50190
+ import * as fs19 from "fs";
50191
+ import * as path29 from "path";
50105
50192
  async function handleResetSessionCommand(directory, _args) {
50106
50193
  const results = [];
50107
50194
  try {
50108
50195
  const statePath = validateSwarmPath(directory, "session/state.json");
50109
- if (fs18.existsSync(statePath)) {
50110
- fs18.unlinkSync(statePath);
50196
+ if (fs19.existsSync(statePath)) {
50197
+ fs19.unlinkSync(statePath);
50111
50198
  results.push("\u2705 Deleted .swarm/session/state.json");
50112
50199
  } else {
50113
50200
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -50116,15 +50203,15 @@ async function handleResetSessionCommand(directory, _args) {
50116
50203
  results.push("\u274C Failed to delete state.json");
50117
50204
  }
50118
50205
  try {
50119
- const sessionDir = path28.dirname(validateSwarmPath(directory, "session/state.json"));
50120
- if (fs18.existsSync(sessionDir)) {
50121
- const files = fs18.readdirSync(sessionDir);
50206
+ const sessionDir = path29.dirname(validateSwarmPath(directory, "session/state.json"));
50207
+ if (fs19.existsSync(sessionDir)) {
50208
+ const files = fs19.readdirSync(sessionDir);
50122
50209
  const otherFiles = files.filter((f) => f !== "state.json");
50123
50210
  let deletedCount = 0;
50124
50211
  for (const file3 of otherFiles) {
50125
- const filePath = path28.join(sessionDir, file3);
50126
- if (fs18.lstatSync(filePath).isFile()) {
50127
- fs18.unlinkSync(filePath);
50212
+ const filePath = path29.join(sessionDir, file3);
50213
+ if (fs19.lstatSync(filePath).isFile()) {
50214
+ fs19.unlinkSync(filePath);
50128
50215
  deletedCount++;
50129
50216
  }
50130
50217
  }
@@ -50153,7 +50240,7 @@ async function handleResetSessionCommand(directory, _args) {
50153
50240
  init_utils2();
50154
50241
  init_utils();
50155
50242
  import { mkdirSync as mkdirSync9, readdirSync as readdirSync8, renameSync as renameSync7, rmSync as rmSync3, statSync as statSync8 } from "fs";
50156
- import * as path29 from "path";
50243
+ import * as path30 from "path";
50157
50244
  var SUMMARY_ID_REGEX = /^S\d+$/;
50158
50245
  function sanitizeSummaryId(id) {
50159
50246
  if (!id || id.length === 0) {
@@ -50188,9 +50275,9 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
50188
50275
  if (serializedSize > maxStoredBytes) {
50189
50276
  throw new Error(`Summary entry size (${serializedSize} bytes) exceeds maximum (${maxStoredBytes} bytes)`);
50190
50277
  }
50191
- const relativePath = path29.join("summaries", `${sanitizedId}.json`);
50278
+ const relativePath = path30.join("summaries", `${sanitizedId}.json`);
50192
50279
  const summaryPath = validateSwarmPath(directory, relativePath);
50193
- const summaryDir = path29.dirname(summaryPath);
50280
+ const summaryDir = path30.dirname(summaryPath);
50194
50281
  const entry = {
50195
50282
  id: sanitizedId,
50196
50283
  summaryText,
@@ -50200,7 +50287,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
50200
50287
  };
50201
50288
  const entryJson = JSON.stringify(entry);
50202
50289
  mkdirSync9(summaryDir, { recursive: true });
50203
- const tempPath = path29.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
50290
+ const tempPath = path30.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
50204
50291
  try {
50205
50292
  await Bun.write(tempPath, entryJson);
50206
50293
  renameSync7(tempPath, summaryPath);
@@ -50213,7 +50300,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
50213
50300
  }
50214
50301
  async function loadFullOutput(directory, id) {
50215
50302
  const sanitizedId = sanitizeSummaryId(id);
50216
- const relativePath = path29.join("summaries", `${sanitizedId}.json`);
50303
+ const relativePath = path30.join("summaries", `${sanitizedId}.json`);
50217
50304
  validateSwarmPath(directory, relativePath);
50218
50305
  const content = await readSwarmFileAsync(directory, relativePath);
50219
50306
  if (content === null) {
@@ -50266,18 +50353,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
50266
50353
 
50267
50354
  // src/commands/rollback.ts
50268
50355
  init_utils2();
50269
- import * as fs19 from "fs";
50270
- import * as path30 from "path";
50356
+ import * as fs20 from "fs";
50357
+ import * as path31 from "path";
50271
50358
  async function handleRollbackCommand(directory, args2) {
50272
50359
  const phaseArg = args2[0];
50273
50360
  if (!phaseArg) {
50274
50361
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
50275
- if (!fs19.existsSync(manifestPath2)) {
50362
+ if (!fs20.existsSync(manifestPath2)) {
50276
50363
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
50277
50364
  }
50278
50365
  let manifest2;
50279
50366
  try {
50280
- manifest2 = JSON.parse(fs19.readFileSync(manifestPath2, "utf-8"));
50367
+ manifest2 = JSON.parse(fs20.readFileSync(manifestPath2, "utf-8"));
50281
50368
  } catch {
50282
50369
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
50283
50370
  }
@@ -50299,12 +50386,12 @@ async function handleRollbackCommand(directory, args2) {
50299
50386
  return "Error: Phase number must be a positive integer.";
50300
50387
  }
50301
50388
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
50302
- if (!fs19.existsSync(manifestPath)) {
50389
+ if (!fs20.existsSync(manifestPath)) {
50303
50390
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
50304
50391
  }
50305
50392
  let manifest;
50306
50393
  try {
50307
- manifest = JSON.parse(fs19.readFileSync(manifestPath, "utf-8"));
50394
+ manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf-8"));
50308
50395
  } catch {
50309
50396
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
50310
50397
  }
@@ -50314,10 +50401,10 @@ async function handleRollbackCommand(directory, args2) {
50314
50401
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
50315
50402
  }
50316
50403
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
50317
- if (!fs19.existsSync(checkpointDir)) {
50404
+ if (!fs20.existsSync(checkpointDir)) {
50318
50405
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
50319
50406
  }
50320
- const checkpointFiles = fs19.readdirSync(checkpointDir);
50407
+ const checkpointFiles = fs20.readdirSync(checkpointDir);
50321
50408
  if (checkpointFiles.length === 0) {
50322
50409
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
50323
50410
  }
@@ -50325,10 +50412,10 @@ async function handleRollbackCommand(directory, args2) {
50325
50412
  const successes = [];
50326
50413
  const failures = [];
50327
50414
  for (const file3 of checkpointFiles) {
50328
- const src = path30.join(checkpointDir, file3);
50329
- const dest = path30.join(swarmDir, file3);
50415
+ const src = path31.join(checkpointDir, file3);
50416
+ const dest = path31.join(swarmDir, file3);
50330
50417
  try {
50331
- fs19.cpSync(src, dest, { recursive: true, force: true });
50418
+ fs20.cpSync(src, dest, { recursive: true, force: true });
50332
50419
  successes.push(file3);
50333
50420
  } catch (error93) {
50334
50421
  failures.push({ file: file3, error: error93.message });
@@ -50345,7 +50432,7 @@ async function handleRollbackCommand(directory, args2) {
50345
50432
  timestamp: new Date().toISOString()
50346
50433
  };
50347
50434
  try {
50348
- fs19.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
50435
+ fs20.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
50349
50436
  `);
50350
50437
  } catch (error93) {
50351
50438
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -50389,11 +50476,11 @@ async function handleSimulateCommand(directory, args2) {
50389
50476
  ];
50390
50477
  const report = reportLines.filter(Boolean).join(`
50391
50478
  `);
50392
- const fs20 = await import("fs/promises");
50393
- const path31 = await import("path");
50394
- const reportPath = path31.join(directory, ".swarm", "simulate-report.md");
50395
- await fs20.mkdir(path31.dirname(reportPath), { recursive: true });
50396
- await fs20.writeFile(reportPath, report, "utf-8");
50479
+ const fs21 = await import("fs/promises");
50480
+ const path32 = await import("path");
50481
+ const reportPath = path32.join(directory, ".swarm", "simulate-report.md");
50482
+ await fs21.mkdir(path32.dirname(reportPath), { recursive: true });
50483
+ await fs21.writeFile(reportPath, report, "utf-8");
50397
50484
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
50398
50485
  }
50399
50486
 
@@ -50750,8 +50837,8 @@ init_utils2();
50750
50837
  init_manager2();
50751
50838
 
50752
50839
  // src/services/compaction-service.ts
50753
- import * as fs20 from "fs";
50754
- import * as path31 from "path";
50840
+ import * as fs21 from "fs";
50841
+ import * as path32 from "path";
50755
50842
  function makeInitialState() {
50756
50843
  return {
50757
50844
  lastObservationAt: 0,
@@ -50774,13 +50861,13 @@ function getSessionState(sessionId) {
50774
50861
  }
50775
50862
  function appendSnapshot(directory, tier, budgetPct, message) {
50776
50863
  try {
50777
- const snapshotPath = path31.join(directory, ".swarm", "context-snapshot.md");
50864
+ const snapshotPath = path32.join(directory, ".swarm", "context-snapshot.md");
50778
50865
  const timestamp = new Date().toISOString();
50779
50866
  const entry = `
50780
50867
  ## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
50781
50868
  ${message}
50782
50869
  `;
50783
- fs20.appendFileSync(snapshotPath, entry, "utf-8");
50870
+ fs21.appendFileSync(snapshotPath, entry, "utf-8");
50784
50871
  } catch {}
50785
50872
  }
50786
50873
  function buildObservationMessage(budgetPct) {
@@ -51505,11 +51592,11 @@ async function doFlush(directory) {
51505
51592
  const activitySection = renderActivitySection();
51506
51593
  const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
51507
51594
  const flushedCount = swarmState.pendingEvents;
51508
- const path32 = nodePath2.join(directory, ".swarm", "context.md");
51509
- const tempPath = `${path32}.tmp`;
51595
+ const path33 = nodePath2.join(directory, ".swarm", "context.md");
51596
+ const tempPath = `${path33}.tmp`;
51510
51597
  try {
51511
51598
  await Bun.write(tempPath, updated);
51512
- renameSync8(tempPath, path32);
51599
+ renameSync8(tempPath, path33);
51513
51600
  } catch (writeError) {
51514
51601
  try {
51515
51602
  unlinkSync4(tempPath);
@@ -51558,7 +51645,7 @@ ${content.substring(endIndex + 1)}`;
51558
51645
  }
51559
51646
  // src/hooks/compaction-customizer.ts
51560
51647
  init_manager2();
51561
- import * as fs21 from "fs";
51648
+ import * as fs22 from "fs";
51562
51649
  import { join as join29 } from "path";
51563
51650
  init_utils2();
51564
51651
  function createCompactionCustomizerHook(config3, directory) {
@@ -51606,7 +51693,7 @@ function createCompactionCustomizerHook(config3, directory) {
51606
51693
  }
51607
51694
  try {
51608
51695
  const summariesDir = join29(directory, ".swarm", "summaries");
51609
- const files = await fs21.promises.readdir(summariesDir);
51696
+ const files = await fs22.promises.readdir(summariesDir);
51610
51697
  if (files.length > 0) {
51611
51698
  const count = files.length;
51612
51699
  output.context.push(`[CONTEXT OPTIMIZATION] Tool outputs from earlier in this session have been stored to disk. When compacting, replace any large tool output blocks (bash, test_runner, lint, diff results) with a one-line reference: "[Output stored \u2014 use /swarm retrieve to access full content]". Preserve the tool name, exit status, and any error messages. Discard raw output lines.`);
@@ -52091,8 +52178,8 @@ function maskToolOutput(msg, _threshold) {
52091
52178
  }
52092
52179
  // src/hooks/delegation-gate.ts
52093
52180
  init_schema();
52094
- import * as fs22 from "fs";
52095
- import * as path34 from "path";
52181
+ import * as fs23 from "fs";
52182
+ import * as path35 from "path";
52096
52183
 
52097
52184
  // src/parallel/review-router.ts
52098
52185
  async function computeComplexity(directory, changedFiles) {
@@ -52104,13 +52191,13 @@ async function computeComplexity(directory, changedFiles) {
52104
52191
  continue;
52105
52192
  }
52106
52193
  try {
52107
- const fs22 = await import("fs");
52108
- const path32 = await import("path");
52109
- const filePath = path32.join(directory, file3);
52110
- if (!fs22.existsSync(filePath)) {
52194
+ const fs23 = await import("fs");
52195
+ const path33 = await import("path");
52196
+ const filePath = path33.join(directory, file3);
52197
+ if (!fs23.existsSync(filePath)) {
52111
52198
  continue;
52112
52199
  }
52113
- const content = fs22.readFileSync(filePath, "utf-8");
52200
+ const content = fs23.readFileSync(filePath, "utf-8");
52114
52201
  const functionMatches = content.match(/\b(function|def|func|fn)\s+\w+/g);
52115
52202
  const fileFunctionCount = functionMatches?.length || 0;
52116
52203
  functionCount += fileFunctionCount;
@@ -52158,7 +52245,7 @@ function shouldParallelizeReview(routing) {
52158
52245
  init_telemetry();
52159
52246
 
52160
52247
  // src/hooks/guardrails.ts
52161
- import * as path32 from "path";
52248
+ import * as path33 from "path";
52162
52249
  init_constants();
52163
52250
  init_schema();
52164
52251
 
@@ -52320,10 +52407,10 @@ function isArchitect(sessionId) {
52320
52407
  function isOutsideSwarmDir(filePath, directory) {
52321
52408
  if (!filePath)
52322
52409
  return false;
52323
- const swarmDir = path32.resolve(directory, ".swarm");
52324
- const resolved = path32.resolve(directory, filePath);
52325
- const relative4 = path32.relative(swarmDir, resolved);
52326
- return relative4.startsWith("..") || path32.isAbsolute(relative4);
52410
+ const swarmDir = path33.resolve(directory, ".swarm");
52411
+ const resolved = path33.resolve(directory, filePath);
52412
+ const relative4 = path33.relative(swarmDir, resolved);
52413
+ return relative4.startsWith("..") || path33.isAbsolute(relative4);
52327
52414
  }
52328
52415
  function isSourceCodePath(filePath) {
52329
52416
  if (!filePath)
@@ -52391,13 +52478,13 @@ function getCurrentTaskId(sessionId) {
52391
52478
  }
52392
52479
  function isInDeclaredScope(filePath, scopeEntries, cwd) {
52393
52480
  const dir = cwd ?? process.cwd();
52394
- const resolvedFile = path32.resolve(dir, filePath);
52481
+ const resolvedFile = path33.resolve(dir, filePath);
52395
52482
  return scopeEntries.some((scope) => {
52396
- const resolvedScope = path32.resolve(dir, scope);
52483
+ const resolvedScope = path33.resolve(dir, scope);
52397
52484
  if (resolvedFile === resolvedScope)
52398
52485
  return true;
52399
- const rel = path32.relative(resolvedScope, resolvedFile);
52400
- return rel.length > 0 && !rel.startsWith("..") && !path32.isAbsolute(rel);
52486
+ const rel = path33.relative(resolvedScope, resolvedFile);
52487
+ return rel.length > 0 && !rel.startsWith("..") && !path33.isAbsolute(rel);
52401
52488
  });
52402
52489
  }
52403
52490
  function createGuardrailsHooks(directory, directoryOrConfig, config3) {
@@ -52593,9 +52680,9 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
52593
52680
  const toolArgs = args2;
52594
52681
  const targetPath = toolArgs?.filePath ?? toolArgs?.path ?? toolArgs?.file ?? toolArgs?.target;
52595
52682
  if (typeof targetPath === "string" && targetPath.length > 0) {
52596
- const resolvedTarget = path32.resolve(effectiveDirectory, targetPath).toLowerCase();
52597
- const planMdPath = path32.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
52598
- const planJsonPath = path32.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
52683
+ const resolvedTarget = path33.resolve(effectiveDirectory, targetPath).toLowerCase();
52684
+ const planMdPath = path33.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
52685
+ const planJsonPath = path33.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
52599
52686
  if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
52600
52687
  throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
52601
52688
  }
@@ -52644,9 +52731,9 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
52644
52731
  }
52645
52732
  }
52646
52733
  for (const p of paths) {
52647
- const resolvedP = path32.resolve(effectiveDirectory, p);
52648
- const planMdPath = path32.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
52649
- const planJsonPath = path32.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
52734
+ const resolvedP = path33.resolve(effectiveDirectory, p);
52735
+ const planMdPath = path33.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
52736
+ const planJsonPath = path33.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
52650
52737
  if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
52651
52738
  throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
52652
52739
  }
@@ -52666,7 +52753,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
52666
52753
  }
52667
52754
  }
52668
52755
  }
52669
- if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, effectiveDirectory) && isSourceCodePath(path32.relative(effectiveDirectory, path32.resolve(effectiveDirectory, targetPath)))) {
52756
+ if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, effectiveDirectory) && isSourceCodePath(path33.relative(effectiveDirectory, path33.resolve(effectiveDirectory, targetPath)))) {
52670
52757
  const session = swarmState.agentSessions.get(sessionID);
52671
52758
  if (session) {
52672
52759
  session.architectWriteCount++;
@@ -53297,8 +53384,8 @@ var AGENT_AUTHORITY_RULES = {
53297
53384
  function checkFileAuthority(agentName, filePath, cwd) {
53298
53385
  const normalizedAgent = agentName.toLowerCase();
53299
53386
  const dir = cwd || process.cwd();
53300
- const resolved = path32.resolve(dir, filePath);
53301
- const normalizedPath = path32.relative(dir, resolved).replace(/\\/g, "/");
53387
+ const resolved = path33.resolve(dir, filePath);
53388
+ const normalizedPath = path33.relative(dir, resolved).replace(/\\/g, "/");
53302
53389
  const rules = AGENT_AUTHORITY_RULES[normalizedAgent];
53303
53390
  if (!rules) {
53304
53391
  return { allowed: false, reason: `Unknown agent: ${agentName}` };
@@ -53380,13 +53467,13 @@ async function getEvidenceTaskId(session, directory) {
53380
53467
  if (typeof directory !== "string" || directory.length === 0) {
53381
53468
  return null;
53382
53469
  }
53383
- const resolvedDirectory = path34.resolve(directory);
53384
- const planPath = path34.join(resolvedDirectory, ".swarm", "plan.json");
53385
- const resolvedPlanPath = path34.resolve(planPath);
53386
- if (!resolvedPlanPath.startsWith(resolvedDirectory + path34.sep) && resolvedPlanPath !== resolvedDirectory) {
53470
+ const resolvedDirectory = path35.resolve(directory);
53471
+ const planPath = path35.join(resolvedDirectory, ".swarm", "plan.json");
53472
+ const resolvedPlanPath = path35.resolve(planPath);
53473
+ if (!resolvedPlanPath.startsWith(resolvedDirectory + path35.sep) && resolvedPlanPath !== resolvedDirectory) {
53387
53474
  return null;
53388
53475
  }
53389
- const planContent = await fs22.promises.readFile(resolvedPlanPath, "utf-8");
53476
+ const planContent = await fs23.promises.readFile(resolvedPlanPath, "utf-8");
53390
53477
  const plan = JSON.parse(planContent);
53391
53478
  if (!plan || !Array.isArray(plan.phases)) {
53392
53479
  return null;
@@ -53915,7 +54002,7 @@ ${warningLines.join(`
53915
54002
  }
53916
54003
  // src/hooks/delegation-sanitizer.ts
53917
54004
  init_utils2();
53918
- import * as fs23 from "fs";
54005
+ import * as fs24 from "fs";
53919
54006
  var SANITIZATION_PATTERNS = [
53920
54007
  /\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
53921
54008
  /\b(5th|fifth|final|last)\s+attempt\b/gi,
@@ -53986,7 +54073,7 @@ function createDelegationSanitizerHook(directory) {
53986
54073
  stripped_patterns: result.stripped,
53987
54074
  timestamp: new Date().toISOString()
53988
54075
  };
53989
- fs23.appendFileSync(eventsPath, `${JSON.stringify(event)}
54076
+ fs24.appendFileSync(eventsPath, `${JSON.stringify(event)}
53990
54077
  `, "utf-8");
53991
54078
  } catch {}
53992
54079
  }
@@ -54111,7 +54198,7 @@ function consolidateSystemMessages(messages) {
54111
54198
  // src/hooks/phase-monitor.ts
54112
54199
  init_schema();
54113
54200
  init_manager2();
54114
- import * as path35 from "path";
54201
+ import * as path36 from "path";
54115
54202
  init_utils2();
54116
54203
  function createPhaseMonitorHook(directory, preflightManager, curatorRunner = runCuratorInit) {
54117
54204
  let lastKnownPhase = null;
@@ -54129,9 +54216,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner = run
54129
54216
  if (curatorConfig.enabled && curatorConfig.init_enabled) {
54130
54217
  const initResult = await curatorRunner(directory, curatorConfig);
54131
54218
  if (initResult.briefing) {
54132
- const briefingPath = path35.join(directory, ".swarm", "curator-briefing.md");
54219
+ const briefingPath = path36.join(directory, ".swarm", "curator-briefing.md");
54133
54220
  const { mkdir: mkdir5, writeFile: writeFile5 } = await import("fs/promises");
54134
- await mkdir5(path35.dirname(briefingPath), { recursive: true });
54221
+ await mkdir5(path36.dirname(briefingPath), { recursive: true });
54135
54222
  await writeFile5(briefingPath, initResult.briefing, "utf-8");
54136
54223
  }
54137
54224
  }
@@ -54243,15 +54330,15 @@ init_schema();
54243
54330
  init_manager();
54244
54331
  init_detector();
54245
54332
  init_manager2();
54246
- import * as fs27 from "fs";
54247
- import * as path39 from "path";
54333
+ import * as fs28 from "fs";
54334
+ import * as path40 from "path";
54248
54335
 
54249
54336
  // src/services/decision-drift-analyzer.ts
54250
54337
  init_utils2();
54251
54338
  init_manager2();
54252
54339
  init_utils();
54253
- import * as fs24 from "fs";
54254
- import * as path36 from "path";
54340
+ import * as fs25 from "fs";
54341
+ import * as path37 from "path";
54255
54342
  var DEFAULT_DRIFT_CONFIG = {
54256
54343
  staleThresholdPhases: 1,
54257
54344
  detectContradictions: true,
@@ -54405,11 +54492,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
54405
54492
  currentPhase = legacyPhase;
54406
54493
  }
54407
54494
  }
54408
- const contextPath = path36.join(directory, ".swarm", "context.md");
54495
+ const contextPath = path37.join(directory, ".swarm", "context.md");
54409
54496
  let contextContent = "";
54410
54497
  try {
54411
- if (fs24.existsSync(contextPath)) {
54412
- contextContent = fs24.readFileSync(contextPath, "utf-8");
54498
+ if (fs25.existsSync(contextPath)) {
54499
+ contextContent = fs25.readFileSync(contextPath, "utf-8");
54413
54500
  }
54414
54501
  } catch (error93) {
54415
54502
  log("[DecisionDriftAnalyzer] context file read failed", {
@@ -54534,8 +54621,8 @@ init_utils();
54534
54621
  // src/hooks/adversarial-detector.ts
54535
54622
  init_constants();
54536
54623
  init_schema();
54537
- import * as fs25 from "fs/promises";
54538
- import * as path37 from "path";
54624
+ import * as fs26 from "fs/promises";
54625
+ import * as path38 from "path";
54539
54626
  function safeGet(obj, key) {
54540
54627
  if (!obj || !Object.hasOwn(obj, key))
54541
54628
  return;
@@ -54749,10 +54836,10 @@ async function handleDebuggingSpiral(match, taskId, directory) {
54749
54836
  let eventLogged = false;
54750
54837
  let checkpointCreated = false;
54751
54838
  try {
54752
- const swarmDir = path37.join(directory, ".swarm");
54753
- await fs25.mkdir(swarmDir, { recursive: true });
54754
- const eventsPath = path37.join(swarmDir, "events.jsonl");
54755
- await fs25.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
54839
+ const swarmDir = path38.join(directory, ".swarm");
54840
+ await fs26.mkdir(swarmDir, { recursive: true });
54841
+ const eventsPath = path38.join(swarmDir, "events.jsonl");
54842
+ await fs26.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
54756
54843
  `);
54757
54844
  eventLogged = true;
54758
54845
  } catch {}
@@ -55133,7 +55220,7 @@ function createSystemEnhancerHook(config3, directory) {
55133
55220
  } catch {}
55134
55221
  try {
55135
55222
  const darkMatterPath = validateSwarmPath(directory, "dark-matter.md");
55136
- if (!fs27.existsSync(darkMatterPath)) {
55223
+ if (!fs28.existsSync(darkMatterPath)) {
55137
55224
  const {
55138
55225
  detectDarkMatter: detectDarkMatter2,
55139
55226
  formatDarkMatterOutput: formatDarkMatterOutput2,
@@ -55141,15 +55228,14 @@ function createSystemEnhancerHook(config3, directory) {
55141
55228
  } = await Promise.resolve().then(() => (init_co_change_analyzer(), exports_co_change_analyzer));
55142
55229
  const darkMatter = await detectDarkMatter2(directory, {
55143
55230
  minCommits: 20,
55144
- minCoChanges: 3,
55145
- npmiThreshold: 0.3
55231
+ minCoChanges: 3
55146
55232
  });
55147
55233
  if (darkMatter && darkMatter.length > 0) {
55148
55234
  const darkMatterReport = formatDarkMatterOutput2(darkMatter);
55149
- await fs27.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55235
+ await fs28.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55150
55236
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
55151
55237
  try {
55152
- const projectName = path39.basename(path39.resolve(directory));
55238
+ const projectName = path40.basename(path40.resolve(directory));
55153
55239
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
55154
55240
  const knowledgePath = resolveSwarmKnowledgePath(directory);
55155
55241
  const existingEntries = await readKnowledge(knowledgePath);
@@ -55168,6 +55254,19 @@ function createSystemEnhancerHook(config3, directory) {
55168
55254
  }
55169
55255
  }
55170
55256
  }
55257
+ try {
55258
+ const knowledgePath = resolveSwarmKnowledgePath(directory);
55259
+ const allEntries = await readKnowledge(knowledgePath);
55260
+ const stale = allEntries.filter((e) => e.scope === "project" && e.auto_generated === true && Array.isArray(e.tags) && e.tags.includes("dark-matter"));
55261
+ if (stale.length > 0) {
55262
+ for (const e of stale) {
55263
+ e.scope = "global";
55264
+ e.updated_at = new Date().toISOString();
55265
+ }
55266
+ await rewriteKnowledge(knowledgePath, allEntries);
55267
+ warn(`[system-enhancer] Repaired ${stale.length} dark matter knowledge entries (scope: 'project' \u2192 'global')`);
55268
+ }
55269
+ } catch {}
55171
55270
  } catch {}
55172
55271
  const scoringEnabled = config3.context_budget?.scoring?.enabled === true;
55173
55272
  if (!scoringEnabled) {
@@ -55200,11 +55299,11 @@ function createSystemEnhancerHook(config3, directory) {
55200
55299
  if (handoffContent) {
55201
55300
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55202
55301
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55203
- if (fs27.existsSync(consumedPath)) {
55302
+ if (fs28.existsSync(consumedPath)) {
55204
55303
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55205
- fs27.unlinkSync(consumedPath);
55304
+ fs28.unlinkSync(consumedPath);
55206
55305
  }
55207
- fs27.renameSync(handoffPath, consumedPath);
55306
+ fs28.renameSync(handoffPath, consumedPath);
55208
55307
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55209
55308
  The previous model's session ended. Here is your starting context:
55210
55309
 
@@ -55485,11 +55584,11 @@ ${budgetWarning}`);
55485
55584
  if (handoffContent) {
55486
55585
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55487
55586
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55488
- if (fs27.existsSync(consumedPath)) {
55587
+ if (fs28.existsSync(consumedPath)) {
55489
55588
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55490
- fs27.unlinkSync(consumedPath);
55589
+ fs28.unlinkSync(consumedPath);
55491
55590
  }
55492
- fs27.renameSync(handoffPath, consumedPath);
55591
+ fs28.renameSync(handoffPath, consumedPath);
55493
55592
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55494
55593
  The previous model's session ended. Here is your starting context:
55495
55594
 
@@ -56259,14 +56358,14 @@ function isReadTool(toolName) {
56259
56358
  }
56260
56359
 
56261
56360
  // src/hooks/incremental-verify.ts
56262
- import * as fs28 from "fs";
56263
- import * as path40 from "path";
56361
+ import * as fs29 from "fs";
56362
+ import * as path41 from "path";
56264
56363
 
56265
56364
  // src/hooks/spawn-helper.ts
56266
56365
  import { spawn } from "child_process";
56267
56366
  var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
56268
56367
  function spawnAsync(command, cwd, timeoutMs) {
56269
- return new Promise((resolve12) => {
56368
+ return new Promise((resolve13) => {
56270
56369
  try {
56271
56370
  const [rawCmd, ...args2] = command;
56272
56371
  const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
@@ -56310,24 +56409,24 @@ function spawnAsync(command, cwd, timeoutMs) {
56310
56409
  try {
56311
56410
  proc.kill();
56312
56411
  } catch {}
56313
- resolve12(null);
56412
+ resolve13(null);
56314
56413
  }, timeoutMs);
56315
56414
  proc.on("close", (code) => {
56316
56415
  if (done)
56317
56416
  return;
56318
56417
  done = true;
56319
56418
  clearTimeout(timer);
56320
- resolve12({ exitCode: code ?? 1, stdout, stderr });
56419
+ resolve13({ exitCode: code ?? 1, stdout, stderr });
56321
56420
  });
56322
56421
  proc.on("error", () => {
56323
56422
  if (done)
56324
56423
  return;
56325
56424
  done = true;
56326
56425
  clearTimeout(timer);
56327
- resolve12(null);
56426
+ resolve13(null);
56328
56427
  });
56329
56428
  } catch {
56330
- resolve12(null);
56429
+ resolve13(null);
56331
56430
  }
56332
56431
  });
56333
56432
  }
@@ -56335,21 +56434,21 @@ function spawnAsync(command, cwd, timeoutMs) {
56335
56434
  // src/hooks/incremental-verify.ts
56336
56435
  var emittedSkipAdvisories = new Set;
56337
56436
  function detectPackageManager(projectDir) {
56338
- if (fs28.existsSync(path40.join(projectDir, "bun.lockb")))
56437
+ if (fs29.existsSync(path41.join(projectDir, "bun.lockb")))
56339
56438
  return "bun";
56340
- if (fs28.existsSync(path40.join(projectDir, "pnpm-lock.yaml")))
56439
+ if (fs29.existsSync(path41.join(projectDir, "pnpm-lock.yaml")))
56341
56440
  return "pnpm";
56342
- if (fs28.existsSync(path40.join(projectDir, "yarn.lock")))
56441
+ if (fs29.existsSync(path41.join(projectDir, "yarn.lock")))
56343
56442
  return "yarn";
56344
- if (fs28.existsSync(path40.join(projectDir, "package-lock.json")))
56443
+ if (fs29.existsSync(path41.join(projectDir, "package-lock.json")))
56345
56444
  return "npm";
56346
56445
  return "bun";
56347
56446
  }
56348
56447
  function detectTypecheckCommand(projectDir) {
56349
- const pkgPath = path40.join(projectDir, "package.json");
56350
- if (fs28.existsSync(pkgPath)) {
56448
+ const pkgPath = path41.join(projectDir, "package.json");
56449
+ if (fs29.existsSync(pkgPath)) {
56351
56450
  try {
56352
- const pkg = JSON.parse(fs28.readFileSync(pkgPath, "utf8"));
56451
+ const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
56353
56452
  const scripts = pkg.scripts;
56354
56453
  if (scripts?.typecheck) {
56355
56454
  const pm = detectPackageManager(projectDir);
@@ -56363,8 +56462,8 @@ function detectTypecheckCommand(projectDir) {
56363
56462
  ...pkg.dependencies,
56364
56463
  ...pkg.devDependencies
56365
56464
  };
56366
- if (!deps?.typescript && !fs28.existsSync(path40.join(projectDir, "tsconfig.json"))) {}
56367
- const hasTSMarkers = deps?.typescript || fs28.existsSync(path40.join(projectDir, "tsconfig.json"));
56465
+ if (!deps?.typescript && !fs29.existsSync(path41.join(projectDir, "tsconfig.json"))) {}
56466
+ const hasTSMarkers = deps?.typescript || fs29.existsSync(path41.join(projectDir, "tsconfig.json"));
56368
56467
  if (hasTSMarkers) {
56369
56468
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
56370
56469
  }
@@ -56372,17 +56471,17 @@ function detectTypecheckCommand(projectDir) {
56372
56471
  return null;
56373
56472
  }
56374
56473
  }
56375
- if (fs28.existsSync(path40.join(projectDir, "go.mod"))) {
56474
+ if (fs29.existsSync(path41.join(projectDir, "go.mod"))) {
56376
56475
  return { command: ["go", "vet", "./..."], language: "go" };
56377
56476
  }
56378
- if (fs28.existsSync(path40.join(projectDir, "Cargo.toml"))) {
56477
+ if (fs29.existsSync(path41.join(projectDir, "Cargo.toml"))) {
56379
56478
  return { command: ["cargo", "check"], language: "rust" };
56380
56479
  }
56381
- if (fs28.existsSync(path40.join(projectDir, "pyproject.toml")) || fs28.existsSync(path40.join(projectDir, "requirements.txt")) || fs28.existsSync(path40.join(projectDir, "setup.py"))) {
56480
+ if (fs29.existsSync(path41.join(projectDir, "pyproject.toml")) || fs29.existsSync(path41.join(projectDir, "requirements.txt")) || fs29.existsSync(path41.join(projectDir, "setup.py"))) {
56382
56481
  return { command: null, language: "python" };
56383
56482
  }
56384
56483
  try {
56385
- const entries = fs28.readdirSync(projectDir);
56484
+ const entries = fs29.readdirSync(projectDir);
56386
56485
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
56387
56486
  return {
56388
56487
  command: ["dotnet", "build", "--no-restore"],
@@ -56691,7 +56790,7 @@ ${injectionText}`;
56691
56790
  // src/hooks/scope-guard.ts
56692
56791
  init_constants();
56693
56792
  init_schema();
56694
- import * as path42 from "path";
56793
+ import * as path43 from "path";
56695
56794
  var WRITE_TOOLS = new Set([
56696
56795
  "write",
56697
56796
  "edit",
@@ -56753,13 +56852,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
56753
56852
  }
56754
56853
  function isFileInScope(filePath, scopeEntries, directory) {
56755
56854
  const dir = directory ?? process.cwd();
56756
- const resolvedFile = path42.resolve(dir, filePath);
56855
+ const resolvedFile = path43.resolve(dir, filePath);
56757
56856
  return scopeEntries.some((scope) => {
56758
- const resolvedScope = path42.resolve(dir, scope);
56857
+ const resolvedScope = path43.resolve(dir, scope);
56759
56858
  if (resolvedFile === resolvedScope)
56760
56859
  return true;
56761
- const rel = path42.relative(resolvedScope, resolvedFile);
56762
- return rel.length > 0 && !rel.startsWith("..") && !path42.isAbsolute(rel);
56860
+ const rel = path43.relative(resolvedScope, resolvedFile);
56861
+ return rel.length > 0 && !rel.startsWith("..") && !path43.isAbsolute(rel);
56763
56862
  });
56764
56863
  }
56765
56864
 
@@ -56808,8 +56907,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
56808
56907
  }
56809
56908
 
56810
56909
  // src/hooks/slop-detector.ts
56811
- import * as fs30 from "fs";
56812
- import * as path43 from "path";
56910
+ import * as fs31 from "fs";
56911
+ import * as path44 from "path";
56813
56912
  var WRITE_EDIT_TOOLS = new Set([
56814
56913
  "write",
56815
56914
  "edit",
@@ -56854,12 +56953,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
56854
56953
  function walkFiles(dir, exts, deadline) {
56855
56954
  const results = [];
56856
56955
  try {
56857
- for (const entry of fs30.readdirSync(dir, { withFileTypes: true })) {
56956
+ for (const entry of fs31.readdirSync(dir, { withFileTypes: true })) {
56858
56957
  if (deadline !== undefined && Date.now() > deadline)
56859
56958
  break;
56860
56959
  if (entry.isSymbolicLink())
56861
56960
  continue;
56862
- const full = path43.join(dir, entry.name);
56961
+ const full = path44.join(dir, entry.name);
56863
56962
  if (entry.isDirectory()) {
56864
56963
  if (entry.name === "node_modules" || entry.name === ".git")
56865
56964
  continue;
@@ -56874,7 +56973,7 @@ function walkFiles(dir, exts, deadline) {
56874
56973
  return results;
56875
56974
  }
56876
56975
  function checkDeadExports(content, projectDir, startTime) {
56877
- const hasPackageJson = fs30.existsSync(path43.join(projectDir, "package.json"));
56976
+ const hasPackageJson = fs31.existsSync(path44.join(projectDir, "package.json"));
56878
56977
  if (!hasPackageJson)
56879
56978
  return null;
56880
56979
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -56897,7 +56996,7 @@ function checkDeadExports(content, projectDir, startTime) {
56897
56996
  if (found || Date.now() - startTime > 480)
56898
56997
  break;
56899
56998
  try {
56900
- const text = fs30.readFileSync(file3, "utf-8");
56999
+ const text = fs31.readFileSync(file3, "utf-8");
56901
57000
  if (importPattern.test(text))
56902
57001
  found = true;
56903
57002
  importPattern.lastIndex = 0;
@@ -57030,7 +57129,7 @@ Review before proceeding.`;
57030
57129
 
57031
57130
  // src/hooks/steering-consumed.ts
57032
57131
  init_utils2();
57033
- import * as fs31 from "fs";
57132
+ import * as fs32 from "fs";
57034
57133
  function recordSteeringConsumed(directory, directiveId) {
57035
57134
  try {
57036
57135
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -57039,7 +57138,7 @@ function recordSteeringConsumed(directory, directiveId) {
57039
57138
  directiveId,
57040
57139
  timestamp: new Date().toISOString()
57041
57140
  };
57042
- fs31.appendFileSync(eventsPath, `${JSON.stringify(event)}
57141
+ fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
57043
57142
  `, "utf-8");
57044
57143
  } catch {}
57045
57144
  }
@@ -57329,21 +57428,24 @@ async function executeCommand(command) {
57329
57428
  cmd = ["/bin/sh"];
57330
57429
  args2 = ["-c", command.command];
57331
57430
  }
57332
- const result = await Bun.spawn({
57431
+ const result = Bun.spawn({
57333
57432
  cmd: [...cmd, ...args2],
57334
57433
  cwd: command.cwd,
57335
57434
  stdout: "pipe",
57336
57435
  stderr: "pipe",
57337
57436
  timeout: DEFAULT_TIMEOUT_MS2
57338
57437
  });
57438
+ const [exitCode, stdout, stderr] = await Promise.all([
57439
+ result.exited,
57440
+ new Response(result.stdout).text(),
57441
+ new Response(result.stderr).text()
57442
+ ]);
57339
57443
  const duration_ms = Date.now() - startTime;
57340
- const stdout = await new Response(result.stdout).text();
57341
- const stderr = await new Response(result.stderr).text();
57342
57444
  return {
57343
57445
  kind,
57344
57446
  command: command.command,
57345
57447
  cwd: command.cwd,
57346
- exit_code: result.exitCode ?? -1,
57448
+ exit_code: exitCode ?? -1,
57347
57449
  duration_ms,
57348
57450
  stdout_tail: truncateOutput(stdout),
57349
57451
  stderr_tail: truncateOutput(stderr)
@@ -57448,8 +57550,9 @@ var build_check = createSwarmTool({
57448
57550
  init_dist();
57449
57551
  init_manager();
57450
57552
  init_create_tool();
57451
- import * as fs32 from "fs";
57452
- import * as path44 from "path";
57553
+ init_resolve_working_directory();
57554
+ import * as fs33 from "fs";
57555
+ import * as path45 from "path";
57453
57556
  var EVIDENCE_DIR = ".swarm/evidence";
57454
57557
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
57455
57558
  function isValidTaskId3(taskId) {
@@ -57466,18 +57569,18 @@ function isValidTaskId3(taskId) {
57466
57569
  return TASK_ID_PATTERN2.test(taskId);
57467
57570
  }
57468
57571
  function isPathWithinSwarm(filePath, workspaceRoot) {
57469
- const normalizedWorkspace = path44.resolve(workspaceRoot);
57470
- const swarmPath = path44.join(normalizedWorkspace, ".swarm", "evidence");
57471
- const normalizedPath = path44.resolve(filePath);
57572
+ const normalizedWorkspace = path45.resolve(workspaceRoot);
57573
+ const swarmPath = path45.join(normalizedWorkspace, ".swarm", "evidence");
57574
+ const normalizedPath = path45.resolve(filePath);
57472
57575
  return normalizedPath.startsWith(swarmPath);
57473
57576
  }
57474
57577
  function readEvidenceFile(evidencePath) {
57475
- if (!fs32.existsSync(evidencePath)) {
57578
+ if (!fs33.existsSync(evidencePath)) {
57476
57579
  return null;
57477
57580
  }
57478
57581
  let content;
57479
57582
  try {
57480
- content = fs32.readFileSync(evidencePath, "utf-8");
57583
+ content = fs33.readFileSync(evidencePath, "utf-8");
57481
57584
  } catch {
57482
57585
  return null;
57483
57586
  }
@@ -57495,16 +57598,34 @@ function readEvidenceFile(evidencePath) {
57495
57598
  var check_gate_status = createSwarmTool({
57496
57599
  description: "Read-only tool to check the gate status of a specific task. Reads .swarm/evidence/{taskId}.json and returns structured JSON describing required, passed, and missing gates.",
57497
57600
  args: {
57498
- task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")')
57601
+ task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")'),
57602
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/evidence/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
57499
57603
  },
57500
57604
  async execute(args2, directory) {
57501
57605
  let taskIdInput;
57606
+ let workingDirInput;
57502
57607
  try {
57503
57608
  if (args2 && typeof args2 === "object") {
57504
57609
  const obj = args2;
57505
57610
  taskIdInput = typeof obj.task_id === "string" ? obj.task_id : undefined;
57611
+ workingDirInput = typeof obj.working_directory === "string" ? obj.working_directory : undefined;
57506
57612
  }
57507
57613
  } catch {}
57614
+ const dirResult = resolveWorkingDirectory(workingDirInput, directory);
57615
+ if (!dirResult.success) {
57616
+ const errorResult = {
57617
+ taskId: taskIdInput ?? "",
57618
+ status: "no_evidence",
57619
+ required_gates: [],
57620
+ passed_gates: [],
57621
+ missing_gates: [],
57622
+ gates: {},
57623
+ message: dirResult.message,
57624
+ todo_scan: null
57625
+ };
57626
+ return JSON.stringify(errorResult, null, 2);
57627
+ }
57628
+ directory = dirResult.directory;
57508
57629
  if (!taskIdInput) {
57509
57630
  const errorResult = {
57510
57631
  taskId: "",
@@ -57531,7 +57652,7 @@ var check_gate_status = createSwarmTool({
57531
57652
  };
57532
57653
  return JSON.stringify(errorResult, null, 2);
57533
57654
  }
57534
- const evidencePath = path44.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57655
+ const evidencePath = path45.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57535
57656
  if (!isPathWithinSwarm(evidencePath, directory)) {
57536
57657
  const errorResult = {
57537
57658
  taskId: taskIdInput,
@@ -57624,9 +57745,10 @@ init_co_change_analyzer();
57624
57745
  // src/tools/completion-verify.ts
57625
57746
  init_dist();
57626
57747
  init_utils2();
57627
- import * as fs33 from "fs";
57628
- import * as path45 from "path";
57748
+ import * as fs34 from "fs";
57749
+ import * as path46 from "path";
57629
57750
  init_create_tool();
57751
+ init_resolve_working_directory();
57630
57752
  function extractMatches(regex, text) {
57631
57753
  return Array.from(text.matchAll(regex));
57632
57754
  }
@@ -57720,7 +57842,7 @@ async function executeCompletionVerify(args2, directory) {
57720
57842
  let plan;
57721
57843
  try {
57722
57844
  const planPath = validateSwarmPath(directory, "plan.json");
57723
- const planRaw = fs33.readFileSync(planPath, "utf-8");
57845
+ const planRaw = fs34.readFileSync(planPath, "utf-8");
57724
57846
  plan = JSON.parse(planRaw);
57725
57847
  } catch {
57726
57848
  const result2 = {
@@ -57778,10 +57900,10 @@ async function executeCompletionVerify(args2, directory) {
57778
57900
  let hasFileReadFailure = false;
57779
57901
  for (const filePath of fileTargets) {
57780
57902
  const normalizedPath = filePath.replace(/\\/g, "/");
57781
- const resolvedPath = path45.resolve(directory, normalizedPath);
57782
- const projectRoot = path45.resolve(directory);
57783
- const relative6 = path45.relative(projectRoot, resolvedPath);
57784
- const withinProject = relative6 === "" || !relative6.startsWith("..") && !path45.isAbsolute(relative6);
57903
+ const resolvedPath = path46.resolve(directory, normalizedPath);
57904
+ const projectRoot = path46.resolve(directory);
57905
+ const relative6 = path46.relative(projectRoot, resolvedPath);
57906
+ const withinProject = relative6 === "" || !relative6.startsWith("..") && !path46.isAbsolute(relative6);
57785
57907
  if (!withinProject) {
57786
57908
  blockedTasks.push({
57787
57909
  task_id: task.id,
@@ -57794,7 +57916,7 @@ async function executeCompletionVerify(args2, directory) {
57794
57916
  }
57795
57917
  let fileContent;
57796
57918
  try {
57797
- fileContent = fs33.readFileSync(resolvedPath, "utf-8");
57919
+ fileContent = fs34.readFileSync(resolvedPath, "utf-8");
57798
57920
  } catch {
57799
57921
  blockedTasks.push({
57800
57922
  task_id: task.id,
@@ -57836,9 +57958,9 @@ async function executeCompletionVerify(args2, directory) {
57836
57958
  blockedTasks
57837
57959
  };
57838
57960
  try {
57839
- const evidenceDir = path45.join(directory, ".swarm", "evidence", `${phase}`);
57840
- const evidencePath = path45.join(evidenceDir, "completion-verify.json");
57841
- fs33.mkdirSync(evidenceDir, { recursive: true });
57961
+ const evidenceDir = path46.join(directory, ".swarm", "evidence", `${phase}`);
57962
+ const evidencePath = path46.join(evidenceDir, "completion-verify.json");
57963
+ fs34.mkdirSync(evidenceDir, { recursive: true });
57842
57964
  const evidenceBundle = {
57843
57965
  schema_version: "1.0.0",
57844
57966
  task_id: "completion-verify",
@@ -57859,7 +57981,7 @@ async function executeCompletionVerify(args2, directory) {
57859
57981
  }
57860
57982
  ]
57861
57983
  };
57862
- fs33.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57984
+ fs34.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57863
57985
  } catch {}
57864
57986
  return JSON.stringify(result, null, 2);
57865
57987
  }
@@ -57867,7 +57989,8 @@ var completion_verify = createSwarmTool({
57867
57989
  description: "Deterministic pre-check verifying that plan task identifiers exist in their target source files before phase completion. Blocks if obviously incomplete.",
57868
57990
  args: {
57869
57991
  phase: tool.schema.number().describe("The phase number to check"),
57870
- sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
57992
+ sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
57993
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
57871
57994
  },
57872
57995
  execute: async (args2, directory) => {
57873
57996
  let parsedArgs;
@@ -57876,7 +57999,8 @@ var completion_verify = createSwarmTool({
57876
57999
  const obj = args2;
57877
58000
  parsedArgs = {
57878
58001
  phase: typeof obj.phase === "number" ? obj.phase : typeof obj.phase === "string" ? Number(obj.phase) : 0,
57879
- sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined
58002
+ sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined,
58003
+ working_directory: typeof obj.working_directory === "string" ? obj.working_directory : undefined
57880
58004
  };
57881
58005
  } else {
57882
58006
  parsedArgs = { phase: 0 };
@@ -57893,17 +58017,30 @@ var completion_verify = createSwarmTool({
57893
58017
  blockedTasks: []
57894
58018
  }, null, 2);
57895
58019
  }
57896
- return executeCompletionVerify(parsedArgs, directory);
58020
+ const dirResult = resolveWorkingDirectory(parsedArgs.working_directory, directory);
58021
+ if (!dirResult.success) {
58022
+ return JSON.stringify({
58023
+ success: false,
58024
+ phase: parsedArgs.phase,
58025
+ status: "blocked",
58026
+ reason: dirResult.message,
58027
+ tasksChecked: 0,
58028
+ tasksSkipped: 0,
58029
+ tasksBlocked: 0,
58030
+ blockedTasks: []
58031
+ }, null, 2);
58032
+ }
58033
+ return executeCompletionVerify(parsedArgs, dirResult.directory);
57897
58034
  }
57898
58035
  });
57899
58036
  // src/tools/complexity-hotspots.ts
57900
58037
  init_dist();
57901
- import * as fs35 from "fs";
57902
- import * as path47 from "path";
58038
+ import * as fs36 from "fs";
58039
+ import * as path48 from "path";
57903
58040
 
57904
58041
  // src/quality/metrics.ts
57905
- import * as fs34 from "fs";
57906
- import * as path46 from "path";
58042
+ import * as fs35 from "fs";
58043
+ import * as path47 from "path";
57907
58044
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
57908
58045
  var MIN_DUPLICATION_LINES = 10;
57909
58046
  function estimateCyclomaticComplexity(content) {
@@ -57941,11 +58078,11 @@ function estimateCyclomaticComplexity(content) {
57941
58078
  }
57942
58079
  function getComplexityForFile(filePath) {
57943
58080
  try {
57944
- const stat2 = fs34.statSync(filePath);
58081
+ const stat2 = fs35.statSync(filePath);
57945
58082
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
57946
58083
  return null;
57947
58084
  }
57948
- const content = fs34.readFileSync(filePath, "utf-8");
58085
+ const content = fs35.readFileSync(filePath, "utf-8");
57949
58086
  return estimateCyclomaticComplexity(content);
57950
58087
  } catch {
57951
58088
  return null;
@@ -57955,8 +58092,8 @@ async function computeComplexityDelta(files, workingDir) {
57955
58092
  let totalComplexity = 0;
57956
58093
  const analyzedFiles = [];
57957
58094
  for (const file3 of files) {
57958
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
57959
- if (!fs34.existsSync(fullPath)) {
58095
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58096
+ if (!fs35.existsSync(fullPath)) {
57960
58097
  continue;
57961
58098
  }
57962
58099
  const complexity = getComplexityForFile(fullPath);
@@ -58077,8 +58214,8 @@ function countGoExports(content) {
58077
58214
  }
58078
58215
  function getExportCountForFile(filePath) {
58079
58216
  try {
58080
- const content = fs34.readFileSync(filePath, "utf-8");
58081
- const ext = path46.extname(filePath).toLowerCase();
58217
+ const content = fs35.readFileSync(filePath, "utf-8");
58218
+ const ext = path47.extname(filePath).toLowerCase();
58082
58219
  switch (ext) {
58083
58220
  case ".ts":
58084
58221
  case ".tsx":
@@ -58104,8 +58241,8 @@ async function computePublicApiDelta(files, workingDir) {
58104
58241
  let totalExports = 0;
58105
58242
  const analyzedFiles = [];
58106
58243
  for (const file3 of files) {
58107
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
58108
- if (!fs34.existsSync(fullPath)) {
58244
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58245
+ if (!fs35.existsSync(fullPath)) {
58109
58246
  continue;
58110
58247
  }
58111
58248
  const exports = getExportCountForFile(fullPath);
@@ -58138,16 +58275,16 @@ async function computeDuplicationRatio(files, workingDir) {
58138
58275
  let duplicateLines = 0;
58139
58276
  const analyzedFiles = [];
58140
58277
  for (const file3 of files) {
58141
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
58142
- if (!fs34.existsSync(fullPath)) {
58278
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58279
+ if (!fs35.existsSync(fullPath)) {
58143
58280
  continue;
58144
58281
  }
58145
58282
  try {
58146
- const stat2 = fs34.statSync(fullPath);
58283
+ const stat2 = fs35.statSync(fullPath);
58147
58284
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58148
58285
  continue;
58149
58286
  }
58150
- const content = fs34.readFileSync(fullPath, "utf-8");
58287
+ const content = fs35.readFileSync(fullPath, "utf-8");
58151
58288
  const lines = content.split(`
58152
58289
  `).filter((line) => line.trim().length > 0);
58153
58290
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -58171,8 +58308,8 @@ function countCodeLines(content) {
58171
58308
  return lines.length;
58172
58309
  }
58173
58310
  function isTestFile(filePath) {
58174
- const basename7 = path46.basename(filePath);
58175
- const _ext = path46.extname(filePath).toLowerCase();
58311
+ const basename7 = path47.basename(filePath);
58312
+ const _ext = path47.extname(filePath).toLowerCase();
58176
58313
  const testPatterns = [
58177
58314
  ".test.",
58178
58315
  ".spec.",
@@ -58253,8 +58390,8 @@ function matchGlobSegment(globSegments, pathSegments) {
58253
58390
  }
58254
58391
  return gIndex === globSegments.length && pIndex === pathSegments.length;
58255
58392
  }
58256
- function matchesGlobSegment(path47, glob) {
58257
- const normalizedPath = path47.replace(/\\/g, "/");
58393
+ function matchesGlobSegment(path48, glob) {
58394
+ const normalizedPath = path48.replace(/\\/g, "/");
58258
58395
  const normalizedGlob = glob.replace(/\\/g, "/");
58259
58396
  if (normalizedPath.includes("//")) {
58260
58397
  return false;
@@ -58285,8 +58422,8 @@ function simpleGlobToRegex2(glob) {
58285
58422
  function hasGlobstar(glob) {
58286
58423
  return glob.includes("**");
58287
58424
  }
58288
- function globMatches(path47, glob) {
58289
- const normalizedPath = path47.replace(/\\/g, "/");
58425
+ function globMatches(path48, glob) {
58426
+ const normalizedPath = path48.replace(/\\/g, "/");
58290
58427
  if (!glob || glob === "") {
58291
58428
  if (normalizedPath.includes("//")) {
58292
58429
  return false;
@@ -58322,31 +58459,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
58322
58459
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58323
58460
  let testLines = 0;
58324
58461
  let codeLines = 0;
58325
- const srcDir = path46.join(workingDir, "src");
58326
- if (fs34.existsSync(srcDir)) {
58462
+ const srcDir = path47.join(workingDir, "src");
58463
+ if (fs35.existsSync(srcDir)) {
58327
58464
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
58328
58465
  codeLines += lines;
58329
58466
  });
58330
58467
  }
58331
58468
  const possibleSrcDirs = ["lib", "app", "source", "core"];
58332
58469
  for (const dir of possibleSrcDirs) {
58333
- const dirPath = path46.join(workingDir, dir);
58334
- if (fs34.existsSync(dirPath)) {
58470
+ const dirPath = path47.join(workingDir, dir);
58471
+ if (fs35.existsSync(dirPath)) {
58335
58472
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
58336
58473
  codeLines += lines;
58337
58474
  });
58338
58475
  }
58339
58476
  }
58340
- const testsDir = path46.join(workingDir, "tests");
58341
- if (fs34.existsSync(testsDir)) {
58477
+ const testsDir = path47.join(workingDir, "tests");
58478
+ if (fs35.existsSync(testsDir)) {
58342
58479
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
58343
58480
  testLines += lines;
58344
58481
  });
58345
58482
  }
58346
58483
  const possibleTestDirs = ["test", "__tests__", "specs"];
58347
58484
  for (const dir of possibleTestDirs) {
58348
- const dirPath = path46.join(workingDir, dir);
58349
- if (fs34.existsSync(dirPath) && dirPath !== testsDir) {
58485
+ const dirPath = path47.join(workingDir, dir);
58486
+ if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
58350
58487
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
58351
58488
  testLines += lines;
58352
58489
  });
@@ -58358,9 +58495,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58358
58495
  }
58359
58496
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
58360
58497
  try {
58361
- const entries = fs34.readdirSync(dirPath, { withFileTypes: true });
58498
+ const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
58362
58499
  for (const entry of entries) {
58363
- const fullPath = path46.join(dirPath, entry.name);
58500
+ const fullPath = path47.join(dirPath, entry.name);
58364
58501
  if (entry.isDirectory()) {
58365
58502
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
58366
58503
  continue;
@@ -58368,7 +58505,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58368
58505
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
58369
58506
  } else if (entry.isFile()) {
58370
58507
  const relativePath = fullPath.replace(`${dirPath}/`, "");
58371
- const ext = path46.extname(entry.name).toLowerCase();
58508
+ const ext = path47.extname(entry.name).toLowerCase();
58372
58509
  const validExts = [
58373
58510
  ".ts",
58374
58511
  ".tsx",
@@ -58404,7 +58541,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58404
58541
  continue;
58405
58542
  }
58406
58543
  try {
58407
- const content = fs34.readFileSync(fullPath, "utf-8");
58544
+ const content = fs35.readFileSync(fullPath, "utf-8");
58408
58545
  const lines = countCodeLines(content);
58409
58546
  callback(lines);
58410
58547
  } catch {}
@@ -58583,8 +58720,10 @@ async function getGitChurn(days, directory) {
58583
58720
  stderr: "pipe",
58584
58721
  cwd: directory
58585
58722
  });
58586
- const stdout = await new Response(proc.stdout).text();
58587
- await proc.exited;
58723
+ const [stdout] = await Promise.all([
58724
+ new Response(proc.stdout).text(),
58725
+ proc.exited
58726
+ ]);
58588
58727
  const lines = stdout.split(/\r?\n/);
58589
58728
  for (const line of lines) {
58590
58729
  const normalizedPath = line.replace(/\\/g, "/");
@@ -58603,11 +58742,11 @@ async function getGitChurn(days, directory) {
58603
58742
  }
58604
58743
  function getComplexityForFile2(filePath) {
58605
58744
  try {
58606
- const stat2 = fs35.statSync(filePath);
58745
+ const stat2 = fs36.statSync(filePath);
58607
58746
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
58608
58747
  return null;
58609
58748
  }
58610
- const content = fs35.readFileSync(filePath, "utf-8");
58749
+ const content = fs36.readFileSync(filePath, "utf-8");
58611
58750
  return estimateCyclomaticComplexity(content);
58612
58751
  } catch {
58613
58752
  return null;
@@ -58618,7 +58757,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58618
58757
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
58619
58758
  const filteredChurn = new Map;
58620
58759
  for (const [file3, count] of churnMap) {
58621
- const ext = path47.extname(file3).toLowerCase();
58760
+ const ext = path48.extname(file3).toLowerCase();
58622
58761
  if (extSet.has(ext)) {
58623
58762
  filteredChurn.set(file3, count);
58624
58763
  }
@@ -58628,8 +58767,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58628
58767
  let analyzedFiles = 0;
58629
58768
  for (const [file3, churnCount] of filteredChurn) {
58630
58769
  let fullPath = file3;
58631
- if (!fs35.existsSync(fullPath)) {
58632
- fullPath = path47.join(cwd, file3);
58770
+ if (!fs36.existsSync(fullPath)) {
58771
+ fullPath = path48.join(cwd, file3);
58633
58772
  }
58634
58773
  const complexity = getComplexityForFile2(fullPath);
58635
58774
  if (complexity !== null) {
@@ -58837,8 +58976,8 @@ var curator_analyze = createSwarmTool({
58837
58976
  });
58838
58977
  // src/tools/declare-scope.ts
58839
58978
  init_tool();
58840
- import * as fs36 from "fs";
58841
- import * as path48 from "path";
58979
+ import * as fs37 from "fs";
58980
+ import * as path49 from "path";
58842
58981
  init_create_tool();
58843
58982
  function validateTaskIdFormat(taskId) {
58844
58983
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -58917,8 +59056,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58917
59056
  };
58918
59057
  }
58919
59058
  }
58920
- normalizedDir = path48.normalize(args2.working_directory);
58921
- const pathParts = normalizedDir.split(path48.sep);
59059
+ normalizedDir = path49.normalize(args2.working_directory);
59060
+ const pathParts = normalizedDir.split(path49.sep);
58922
59061
  if (pathParts.includes("..")) {
58923
59062
  return {
58924
59063
  success: false,
@@ -58928,11 +59067,11 @@ async function executeDeclareScope(args2, fallbackDir) {
58928
59067
  ]
58929
59068
  };
58930
59069
  }
58931
- const resolvedDir = path48.resolve(normalizedDir);
59070
+ const resolvedDir = path49.resolve(normalizedDir);
58932
59071
  try {
58933
- const realPath = fs36.realpathSync(resolvedDir);
58934
- const planPath2 = path48.join(realPath, ".swarm", "plan.json");
58935
- if (!fs36.existsSync(planPath2)) {
59072
+ const realPath = fs37.realpathSync(resolvedDir);
59073
+ const planPath2 = path49.join(realPath, ".swarm", "plan.json");
59074
+ if (!fs37.existsSync(planPath2)) {
58936
59075
  return {
58937
59076
  success: false,
58938
59077
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -58955,8 +59094,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58955
59094
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
58956
59095
  }
58957
59096
  const directory = normalizedDir || fallbackDir;
58958
- const planPath = path48.resolve(directory, ".swarm", "plan.json");
58959
- if (!fs36.existsSync(planPath)) {
59097
+ const planPath = path49.resolve(directory, ".swarm", "plan.json");
59098
+ if (!fs37.existsSync(planPath)) {
58960
59099
  return {
58961
59100
  success: false,
58962
59101
  message: "No plan found",
@@ -58965,7 +59104,7 @@ async function executeDeclareScope(args2, fallbackDir) {
58965
59104
  }
58966
59105
  let planContent;
58967
59106
  try {
58968
- planContent = JSON.parse(fs36.readFileSync(planPath, "utf-8"));
59107
+ planContent = JSON.parse(fs37.readFileSync(planPath, "utf-8"));
58969
59108
  } catch {
58970
59109
  return {
58971
59110
  success: false,
@@ -58997,8 +59136,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58997
59136
  const normalizeErrors = [];
58998
59137
  const dir = normalizedDir || fallbackDir || process.cwd();
58999
59138
  const mergedFiles = rawMergedFiles.map((file3) => {
59000
- if (path48.isAbsolute(file3)) {
59001
- const relativePath = path48.relative(dir, file3).replace(/\\/g, "/");
59139
+ if (path49.isAbsolute(file3)) {
59140
+ const relativePath = path49.relative(dir, file3).replace(/\\/g, "/");
59002
59141
  if (relativePath.startsWith("..")) {
59003
59142
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
59004
59143
  return file3;
@@ -59324,20 +59463,20 @@ function validateBase(base) {
59324
59463
  function validatePaths(paths) {
59325
59464
  if (!paths)
59326
59465
  return null;
59327
- for (const path50 of paths) {
59328
- if (!path50 || path50.length === 0) {
59466
+ for (const path51 of paths) {
59467
+ if (!path51 || path51.length === 0) {
59329
59468
  return "empty path not allowed";
59330
59469
  }
59331
- if (path50.length > MAX_PATH_LENGTH) {
59470
+ if (path51.length > MAX_PATH_LENGTH) {
59332
59471
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
59333
59472
  }
59334
- if (SHELL_METACHARACTERS2.test(path50)) {
59473
+ if (SHELL_METACHARACTERS2.test(path51)) {
59335
59474
  return "path contains shell metacharacters";
59336
59475
  }
59337
- if (path50.startsWith("-")) {
59476
+ if (path51.startsWith("-")) {
59338
59477
  return 'path cannot start with "-" (option-like arguments not allowed)';
59339
59478
  }
59340
- if (CONTROL_CHAR_PATTERN2.test(path50)) {
59479
+ if (CONTROL_CHAR_PATTERN2.test(path51)) {
59341
59480
  return "path contains control characters";
59342
59481
  }
59343
59482
  }
@@ -59418,8 +59557,8 @@ var diff = createSwarmTool({
59418
59557
  if (parts2.length >= 3) {
59419
59558
  const additions = parseInt(parts2[0], 10) || 0;
59420
59559
  const deletions = parseInt(parts2[1], 10) || 0;
59421
- const path50 = parts2[2];
59422
- files.push({ path: path50, additions, deletions });
59560
+ const path51 = parts2[2];
59561
+ files.push({ path: path51, additions, deletions });
59423
59562
  }
59424
59563
  }
59425
59564
  const contractChanges = [];
@@ -59701,8 +59840,8 @@ Use these as DOMAIN values when delegating to @sme.`;
59701
59840
  // src/tools/evidence-check.ts
59702
59841
  init_dist();
59703
59842
  init_create_tool();
59704
- import * as fs37 from "fs";
59705
- import * as path50 from "path";
59843
+ import * as fs38 from "fs";
59844
+ import * as path51 from "path";
59706
59845
  var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
59707
59846
  var MAX_EVIDENCE_FILES = 1000;
59708
59847
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -59729,9 +59868,9 @@ function validateRequiredTypes(input) {
59729
59868
  return null;
59730
59869
  }
59731
59870
  function isPathWithinSwarm2(filePath, cwd) {
59732
- const normalizedCwd = path50.resolve(cwd);
59733
- const swarmPath = path50.join(normalizedCwd, ".swarm");
59734
- const normalizedPath = path50.resolve(filePath);
59871
+ const normalizedCwd = path51.resolve(cwd);
59872
+ const swarmPath = path51.join(normalizedCwd, ".swarm");
59873
+ const normalizedPath = path51.resolve(filePath);
59735
59874
  return normalizedPath.startsWith(swarmPath);
59736
59875
  }
59737
59876
  function parseCompletedTasks(planContent) {
@@ -59747,12 +59886,12 @@ function parseCompletedTasks(planContent) {
59747
59886
  }
59748
59887
  function readEvidenceFiles(evidenceDir, _cwd) {
59749
59888
  const evidence = [];
59750
- if (!fs37.existsSync(evidenceDir) || !fs37.statSync(evidenceDir).isDirectory()) {
59889
+ if (!fs38.existsSync(evidenceDir) || !fs38.statSync(evidenceDir).isDirectory()) {
59751
59890
  return evidence;
59752
59891
  }
59753
59892
  let files;
59754
59893
  try {
59755
- files = fs37.readdirSync(evidenceDir);
59894
+ files = fs38.readdirSync(evidenceDir);
59756
59895
  } catch {
59757
59896
  return evidence;
59758
59897
  }
@@ -59761,14 +59900,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59761
59900
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
59762
59901
  continue;
59763
59902
  }
59764
- const filePath = path50.join(evidenceDir, filename);
59903
+ const filePath = path51.join(evidenceDir, filename);
59765
59904
  try {
59766
- const resolvedPath = path50.resolve(filePath);
59767
- const evidenceDirResolved = path50.resolve(evidenceDir);
59905
+ const resolvedPath = path51.resolve(filePath);
59906
+ const evidenceDirResolved = path51.resolve(evidenceDir);
59768
59907
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
59769
59908
  continue;
59770
59909
  }
59771
- const stat2 = fs37.lstatSync(filePath);
59910
+ const stat2 = fs38.lstatSync(filePath);
59772
59911
  if (!stat2.isFile()) {
59773
59912
  continue;
59774
59913
  }
@@ -59777,7 +59916,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59777
59916
  }
59778
59917
  let fileStat;
59779
59918
  try {
59780
- fileStat = fs37.statSync(filePath);
59919
+ fileStat = fs38.statSync(filePath);
59781
59920
  if (fileStat.size > MAX_FILE_SIZE_BYTES4) {
59782
59921
  continue;
59783
59922
  }
@@ -59786,7 +59925,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59786
59925
  }
59787
59926
  let content;
59788
59927
  try {
59789
- content = fs37.readFileSync(filePath, "utf-8");
59928
+ content = fs38.readFileSync(filePath, "utf-8");
59790
59929
  } catch {
59791
59930
  continue;
59792
59931
  }
@@ -59882,7 +60021,7 @@ var evidence_check = createSwarmTool({
59882
60021
  return JSON.stringify(errorResult, null, 2);
59883
60022
  }
59884
60023
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
59885
- const planPath = path50.join(cwd, PLAN_FILE);
60024
+ const planPath = path51.join(cwd, PLAN_FILE);
59886
60025
  if (!isPathWithinSwarm2(planPath, cwd)) {
59887
60026
  const errorResult = {
59888
60027
  error: "plan file path validation failed",
@@ -59896,7 +60035,7 @@ var evidence_check = createSwarmTool({
59896
60035
  }
59897
60036
  let planContent;
59898
60037
  try {
59899
- planContent = fs37.readFileSync(planPath, "utf-8");
60038
+ planContent = fs38.readFileSync(planPath, "utf-8");
59900
60039
  } catch {
59901
60040
  const result2 = {
59902
60041
  message: "No completed tasks found in plan.",
@@ -59914,7 +60053,7 @@ var evidence_check = createSwarmTool({
59914
60053
  };
59915
60054
  return JSON.stringify(result2, null, 2);
59916
60055
  }
59917
- const evidenceDir = path50.join(cwd, EVIDENCE_DIR2);
60056
+ const evidenceDir = path51.join(cwd, EVIDENCE_DIR2);
59918
60057
  const evidence = readEvidenceFiles(evidenceDir, cwd);
59919
60058
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
59920
60059
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -59931,8 +60070,8 @@ var evidence_check = createSwarmTool({
59931
60070
  // src/tools/file-extractor.ts
59932
60071
  init_tool();
59933
60072
  init_create_tool();
59934
- import * as fs38 from "fs";
59935
- import * as path51 from "path";
60073
+ import * as fs39 from "fs";
60074
+ import * as path52 from "path";
59936
60075
  var EXT_MAP = {
59937
60076
  python: ".py",
59938
60077
  py: ".py",
@@ -59994,8 +60133,8 @@ var extract_code_blocks = createSwarmTool({
59994
60133
  execute: async (args2, directory) => {
59995
60134
  const { content, output_dir, prefix } = args2;
59996
60135
  const targetDir = output_dir || directory;
59997
- if (!fs38.existsSync(targetDir)) {
59998
- fs38.mkdirSync(targetDir, { recursive: true });
60136
+ if (!fs39.existsSync(targetDir)) {
60137
+ fs39.mkdirSync(targetDir, { recursive: true });
59999
60138
  }
60000
60139
  if (!content) {
60001
60140
  return "Error: content is required";
@@ -60013,16 +60152,16 @@ var extract_code_blocks = createSwarmTool({
60013
60152
  if (prefix) {
60014
60153
  filename = `${prefix}_${filename}`;
60015
60154
  }
60016
- let filepath = path51.join(targetDir, filename);
60017
- const base = path51.basename(filepath, path51.extname(filepath));
60018
- const ext = path51.extname(filepath);
60155
+ let filepath = path52.join(targetDir, filename);
60156
+ const base = path52.basename(filepath, path52.extname(filepath));
60157
+ const ext = path52.extname(filepath);
60019
60158
  let counter = 1;
60020
- while (fs38.existsSync(filepath)) {
60021
- filepath = path51.join(targetDir, `${base}_${counter}${ext}`);
60159
+ while (fs39.existsSync(filepath)) {
60160
+ filepath = path52.join(targetDir, `${base}_${counter}${ext}`);
60022
60161
  counter++;
60023
60162
  }
60024
60163
  try {
60025
- fs38.writeFileSync(filepath, code.trim(), "utf-8");
60164
+ fs39.writeFileSync(filepath, code.trim(), "utf-8");
60026
60165
  savedFiles.push(filepath);
60027
60166
  } catch (error93) {
60028
60167
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -60052,7 +60191,7 @@ init_create_tool();
60052
60191
  var GITINGEST_TIMEOUT_MS = 1e4;
60053
60192
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
60054
60193
  var GITINGEST_MAX_RETRIES = 2;
60055
- var delay = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
60194
+ var delay = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms));
60056
60195
  async function fetchGitingest(args2) {
60057
60196
  for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
60058
60197
  try {
@@ -60138,8 +60277,8 @@ var gitingest = createSwarmTool({
60138
60277
  // src/tools/imports.ts
60139
60278
  init_dist();
60140
60279
  init_create_tool();
60141
- import * as fs39 from "fs";
60142
- import * as path52 from "path";
60280
+ import * as fs40 from "fs";
60281
+ import * as path53 from "path";
60143
60282
  var MAX_FILE_PATH_LENGTH2 = 500;
60144
60283
  var MAX_SYMBOL_LENGTH = 256;
60145
60284
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
@@ -60187,7 +60326,7 @@ function validateSymbolInput(symbol3) {
60187
60326
  return null;
60188
60327
  }
60189
60328
  function isBinaryFile2(filePath, buffer) {
60190
- const ext = path52.extname(filePath).toLowerCase();
60329
+ const ext = path53.extname(filePath).toLowerCase();
60191
60330
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
60192
60331
  return false;
60193
60332
  }
@@ -60211,15 +60350,15 @@ function parseImports(content, targetFile, targetSymbol) {
60211
60350
  const imports = [];
60212
60351
  let _resolvedTarget;
60213
60352
  try {
60214
- _resolvedTarget = path52.resolve(targetFile);
60353
+ _resolvedTarget = path53.resolve(targetFile);
60215
60354
  } catch {
60216
60355
  _resolvedTarget = targetFile;
60217
60356
  }
60218
- const targetBasename = path52.basename(targetFile, path52.extname(targetFile));
60357
+ const targetBasename = path53.basename(targetFile, path53.extname(targetFile));
60219
60358
  const targetWithExt = targetFile;
60220
60359
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
60221
- const normalizedTargetWithExt = path52.normalize(targetWithExt).replace(/\\/g, "/");
60222
- const normalizedTargetWithoutExt = path52.normalize(targetWithoutExt).replace(/\\/g, "/");
60360
+ const normalizedTargetWithExt = path53.normalize(targetWithExt).replace(/\\/g, "/");
60361
+ const normalizedTargetWithoutExt = path53.normalize(targetWithoutExt).replace(/\\/g, "/");
60223
60362
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
60224
60363
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
60225
60364
  const modulePath = match[1] || match[2] || match[3];
@@ -60242,9 +60381,9 @@ function parseImports(content, targetFile, targetSymbol) {
60242
60381
  }
60243
60382
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
60244
60383
  let isMatch = false;
60245
- const _targetDir = path52.dirname(targetFile);
60246
- const targetExt = path52.extname(targetFile);
60247
- const targetBasenameNoExt = path52.basename(targetFile, targetExt);
60384
+ const _targetDir = path53.dirname(targetFile);
60385
+ const targetExt = path53.extname(targetFile);
60386
+ const targetBasenameNoExt = path53.basename(targetFile, targetExt);
60248
60387
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
60249
60388
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
60250
60389
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -60301,7 +60440,7 @@ var SKIP_DIRECTORIES3 = new Set([
60301
60440
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
60302
60441
  let entries;
60303
60442
  try {
60304
- entries = fs39.readdirSync(dir);
60443
+ entries = fs40.readdirSync(dir);
60305
60444
  } catch (e) {
60306
60445
  stats.fileErrors.push({
60307
60446
  path: dir,
@@ -60312,13 +60451,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60312
60451
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
60313
60452
  for (const entry of entries) {
60314
60453
  if (SKIP_DIRECTORIES3.has(entry)) {
60315
- stats.skippedDirs.push(path52.join(dir, entry));
60454
+ stats.skippedDirs.push(path53.join(dir, entry));
60316
60455
  continue;
60317
60456
  }
60318
- const fullPath = path52.join(dir, entry);
60457
+ const fullPath = path53.join(dir, entry);
60319
60458
  let stat2;
60320
60459
  try {
60321
- stat2 = fs39.statSync(fullPath);
60460
+ stat2 = fs40.statSync(fullPath);
60322
60461
  } catch (e) {
60323
60462
  stats.fileErrors.push({
60324
60463
  path: fullPath,
@@ -60329,7 +60468,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60329
60468
  if (stat2.isDirectory()) {
60330
60469
  findSourceFiles(fullPath, files, stats);
60331
60470
  } else if (stat2.isFile()) {
60332
- const ext = path52.extname(fullPath).toLowerCase();
60471
+ const ext = path53.extname(fullPath).toLowerCase();
60333
60472
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
60334
60473
  files.push(fullPath);
60335
60474
  }
@@ -60386,8 +60525,8 @@ var imports = createSwarmTool({
60386
60525
  return JSON.stringify(errorResult, null, 2);
60387
60526
  }
60388
60527
  try {
60389
- const targetFile = path52.resolve(file3);
60390
- if (!fs39.existsSync(targetFile)) {
60528
+ const targetFile = path53.resolve(file3);
60529
+ if (!fs40.existsSync(targetFile)) {
60391
60530
  const errorResult = {
60392
60531
  error: `target file not found: ${file3}`,
60393
60532
  target: file3,
@@ -60397,7 +60536,7 @@ var imports = createSwarmTool({
60397
60536
  };
60398
60537
  return JSON.stringify(errorResult, null, 2);
60399
60538
  }
60400
- const targetStat = fs39.statSync(targetFile);
60539
+ const targetStat = fs40.statSync(targetFile);
60401
60540
  if (!targetStat.isFile()) {
60402
60541
  const errorResult = {
60403
60542
  error: "target must be a file, not a directory",
@@ -60408,7 +60547,7 @@ var imports = createSwarmTool({
60408
60547
  };
60409
60548
  return JSON.stringify(errorResult, null, 2);
60410
60549
  }
60411
- const baseDir = path52.dirname(targetFile);
60550
+ const baseDir = path53.dirname(targetFile);
60412
60551
  const scanStats = {
60413
60552
  skippedDirs: [],
60414
60553
  skippedFiles: 0,
@@ -60423,12 +60562,12 @@ var imports = createSwarmTool({
60423
60562
  if (consumers.length >= MAX_CONSUMERS)
60424
60563
  break;
60425
60564
  try {
60426
- const stat2 = fs39.statSync(filePath);
60565
+ const stat2 = fs40.statSync(filePath);
60427
60566
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
60428
60567
  skippedFileCount++;
60429
60568
  continue;
60430
60569
  }
60431
- const buffer = fs39.readFileSync(filePath);
60570
+ const buffer = fs40.readFileSync(filePath);
60432
60571
  if (isBinaryFile2(filePath, buffer)) {
60433
60572
  skippedFileCount++;
60434
60573
  continue;
@@ -61017,11 +61156,12 @@ init_dist();
61017
61156
  init_config();
61018
61157
  init_schema();
61019
61158
  init_manager();
61020
- import * as fs40 from "fs";
61021
- import * as path53 from "path";
61159
+ import * as fs41 from "fs";
61160
+ import * as path54 from "path";
61022
61161
  init_utils2();
61023
61162
  init_telemetry();
61024
61163
  init_create_tool();
61164
+ init_resolve_working_directory();
61025
61165
  function safeWarn(message, error93) {
61026
61166
  try {
61027
61167
  console.warn(message, error93 instanceof Error ? error93.message : String(error93));
@@ -61238,11 +61378,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61238
61378
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
61239
61379
  }
61240
61380
  try {
61241
- const driftEvidencePath = path53.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61381
+ const driftEvidencePath = path54.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61242
61382
  let driftVerdictFound = false;
61243
61383
  let driftVerdictApproved = false;
61244
61384
  try {
61245
- const driftEvidenceContent = fs40.readFileSync(driftEvidencePath, "utf-8");
61385
+ const driftEvidenceContent = fs41.readFileSync(driftEvidencePath, "utf-8");
61246
61386
  const driftEvidence = JSON.parse(driftEvidenceContent);
61247
61387
  const entries = driftEvidence.entries ?? [];
61248
61388
  for (const entry of entries) {
@@ -61272,14 +61412,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61272
61412
  driftVerdictFound = false;
61273
61413
  }
61274
61414
  if (!driftVerdictFound) {
61275
- const specPath = path53.join(dir, ".swarm", "spec.md");
61276
- const specExists = fs40.existsSync(specPath);
61415
+ const specPath = path54.join(dir, ".swarm", "spec.md");
61416
+ const specExists = fs41.existsSync(specPath);
61277
61417
  if (!specExists) {
61278
61418
  let incompleteTaskCount = 0;
61279
61419
  let planPhaseFound = false;
61280
61420
  try {
61281
61421
  const planPath = validateSwarmPath(dir, "plan.json");
61282
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61422
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61283
61423
  const plan = JSON.parse(planRaw);
61284
61424
  const targetPhase = plan.phases.find((p) => p.id === phase);
61285
61425
  if (targetPhase) {
@@ -61346,7 +61486,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61346
61486
  };
61347
61487
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
61348
61488
  try {
61349
- const projectName = path53.basename(dir);
61489
+ const projectName = path54.basename(dir);
61350
61490
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
61351
61491
  if (curationResult) {
61352
61492
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -61391,7 +61531,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61391
61531
  let phaseRequiredAgents;
61392
61532
  try {
61393
61533
  const planPath = validateSwarmPath(dir, "plan.json");
61394
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61534
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61395
61535
  const plan = JSON.parse(planRaw);
61396
61536
  const phaseObj = plan.phases.find((p) => p.id === phase);
61397
61537
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -61406,7 +61546,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61406
61546
  if (agentsMissing.length > 0) {
61407
61547
  try {
61408
61548
  const planPath = validateSwarmPath(dir, "plan.json");
61409
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61549
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61410
61550
  const plan = JSON.parse(planRaw);
61411
61551
  const targetPhase = plan.phases.find((p) => p.id === phase);
61412
61552
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -61437,7 +61577,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61437
61577
  if (phaseCompleteConfig.regression_sweep?.enforce) {
61438
61578
  try {
61439
61579
  const planPath = validateSwarmPath(dir, "plan.json");
61440
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61580
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61441
61581
  const plan = JSON.parse(planRaw);
61442
61582
  const targetPhase = plan.phases.find((p) => p.id === phase);
61443
61583
  if (targetPhase) {
@@ -61475,7 +61615,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61475
61615
  };
61476
61616
  try {
61477
61617
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
61478
- fs40.appendFileSync(eventsPath, `${JSON.stringify(event)}
61618
+ fs41.appendFileSync(eventsPath, `${JSON.stringify(event)}
61479
61619
  `, "utf-8");
61480
61620
  } catch (writeError) {
61481
61621
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -61499,12 +61639,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61499
61639
  }
61500
61640
  try {
61501
61641
  const planPath = validateSwarmPath(dir, "plan.json");
61502
- const planJson = fs40.readFileSync(planPath, "utf-8");
61642
+ const planJson = fs41.readFileSync(planPath, "utf-8");
61503
61643
  const plan = JSON.parse(planJson);
61504
61644
  const phaseObj = plan.phases.find((p) => p.id === phase);
61505
61645
  if (phaseObj) {
61506
61646
  phaseObj.status = "completed";
61507
- fs40.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61647
+ fs41.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61508
61648
  `, "utf-8");
61509
61649
  }
61510
61650
  } catch (error93) {
@@ -61531,16 +61671,19 @@ var phase_complete = createSwarmTool({
61531
61671
  args: {
61532
61672
  phase: tool.schema.number().int().min(1).describe("The phase number being completed \u2014 a positive integer (e.g., 1, 2, 3)"),
61533
61673
  summary: tool.schema.string().optional().describe("Optional summary of what was accomplished in this phase"),
61534
- sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
61674
+ sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
61675
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
61535
61676
  },
61536
61677
  execute: async (args2, directory, ctx) => {
61537
61678
  let phaseCompleteArgs;
61679
+ let workingDirInput;
61538
61680
  try {
61539
61681
  phaseCompleteArgs = {
61540
61682
  phase: Number(args2.phase),
61541
61683
  summary: args2.summary !== undefined ? String(args2.summary) : undefined,
61542
61684
  sessionID: ctx?.sessionID ?? (args2.sessionID !== undefined ? String(args2.sessionID) : undefined)
61543
61685
  };
61686
+ workingDirInput = args2.working_directory !== undefined ? String(args2.working_directory) : undefined;
61544
61687
  } catch {
61545
61688
  return JSON.stringify({
61546
61689
  success: false,
@@ -61550,7 +61693,17 @@ var phase_complete = createSwarmTool({
61550
61693
  warnings: ["Failed to parse arguments"]
61551
61694
  }, null, 2);
61552
61695
  }
61553
- return executePhaseComplete(phaseCompleteArgs, undefined, directory);
61696
+ const dirResult = resolveWorkingDirectory(workingDirInput, directory);
61697
+ if (!dirResult.success) {
61698
+ return JSON.stringify({
61699
+ success: false,
61700
+ phase: phaseCompleteArgs.phase,
61701
+ message: dirResult.message,
61702
+ agentsDispatched: [],
61703
+ warnings: [dirResult.message]
61704
+ }, null, 2);
61705
+ }
61706
+ return executePhaseComplete(phaseCompleteArgs, dirResult.directory, dirResult.directory);
61554
61707
  }
61555
61708
  });
61556
61709
  // src/tools/pkg-audit.ts
@@ -61558,8 +61711,8 @@ init_dist();
61558
61711
  init_discovery();
61559
61712
  init_utils();
61560
61713
  init_create_tool();
61561
- import * as fs41 from "fs";
61562
- import * as path54 from "path";
61714
+ import * as fs42 from "fs";
61715
+ import * as path55 from "path";
61563
61716
  var MAX_OUTPUT_BYTES5 = 52428800;
61564
61717
  var AUDIT_TIMEOUT_MS = 120000;
61565
61718
  function isValidEcosystem(value) {
@@ -61577,28 +61730,28 @@ function validateArgs3(args2) {
61577
61730
  function detectEcosystems(directory) {
61578
61731
  const ecosystems = [];
61579
61732
  const cwd = directory;
61580
- if (fs41.existsSync(path54.join(cwd, "package.json"))) {
61733
+ if (fs42.existsSync(path55.join(cwd, "package.json"))) {
61581
61734
  ecosystems.push("npm");
61582
61735
  }
61583
- if (fs41.existsSync(path54.join(cwd, "pyproject.toml")) || fs41.existsSync(path54.join(cwd, "requirements.txt"))) {
61736
+ if (fs42.existsSync(path55.join(cwd, "pyproject.toml")) || fs42.existsSync(path55.join(cwd, "requirements.txt"))) {
61584
61737
  ecosystems.push("pip");
61585
61738
  }
61586
- if (fs41.existsSync(path54.join(cwd, "Cargo.toml"))) {
61739
+ if (fs42.existsSync(path55.join(cwd, "Cargo.toml"))) {
61587
61740
  ecosystems.push("cargo");
61588
61741
  }
61589
- if (fs41.existsSync(path54.join(cwd, "go.mod"))) {
61742
+ if (fs42.existsSync(path55.join(cwd, "go.mod"))) {
61590
61743
  ecosystems.push("go");
61591
61744
  }
61592
61745
  try {
61593
- const files = fs41.readdirSync(cwd);
61746
+ const files = fs42.readdirSync(cwd);
61594
61747
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
61595
61748
  ecosystems.push("dotnet");
61596
61749
  }
61597
61750
  } catch {}
61598
- if (fs41.existsSync(path54.join(cwd, "Gemfile")) || fs41.existsSync(path54.join(cwd, "Gemfile.lock"))) {
61751
+ if (fs42.existsSync(path55.join(cwd, "Gemfile")) || fs42.existsSync(path55.join(cwd, "Gemfile.lock"))) {
61599
61752
  ecosystems.push("ruby");
61600
61753
  }
61601
- if (fs41.existsSync(path54.join(cwd, "pubspec.yaml"))) {
61754
+ if (fs42.existsSync(path55.join(cwd, "pubspec.yaml"))) {
61602
61755
  ecosystems.push("dart");
61603
61756
  }
61604
61757
  return ecosystems;
@@ -61611,7 +61764,7 @@ async function runNpmAudit(directory) {
61611
61764
  stderr: "pipe",
61612
61765
  cwd: directory
61613
61766
  });
61614
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
61767
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61615
61768
  const result = await Promise.race([
61616
61769
  Promise.all([
61617
61770
  new Response(proc.stdout).text(),
@@ -61734,7 +61887,7 @@ async function runPipAudit(directory) {
61734
61887
  stderr: "pipe",
61735
61888
  cwd: directory
61736
61889
  });
61737
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
61890
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61738
61891
  const result = await Promise.race([
61739
61892
  Promise.all([
61740
61893
  new Response(proc.stdout).text(),
@@ -61865,7 +62018,7 @@ async function runCargoAudit(directory) {
61865
62018
  stderr: "pipe",
61866
62019
  cwd: directory
61867
62020
  });
61868
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62021
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61869
62022
  const result = await Promise.race([
61870
62023
  Promise.all([
61871
62024
  new Response(proc.stdout).text(),
@@ -61992,7 +62145,7 @@ async function runGoAudit(directory) {
61992
62145
  stderr: "pipe",
61993
62146
  cwd: directory
61994
62147
  });
61995
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62148
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61996
62149
  const result = await Promise.race([
61997
62150
  Promise.all([
61998
62151
  new Response(proc.stdout).text(),
@@ -62128,7 +62281,7 @@ async function runDotnetAudit(directory) {
62128
62281
  stderr: "pipe",
62129
62282
  cwd: directory
62130
62283
  });
62131
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62284
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62132
62285
  const result = await Promise.race([
62133
62286
  Promise.all([
62134
62287
  new Response(proc.stdout).text(),
@@ -62247,7 +62400,7 @@ async function runBundleAudit(directory) {
62247
62400
  stderr: "pipe",
62248
62401
  cwd: directory
62249
62402
  });
62250
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62403
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62251
62404
  const result = await Promise.race([
62252
62405
  Promise.all([
62253
62406
  new Response(proc.stdout).text(),
@@ -62394,7 +62547,7 @@ async function runDartAudit(directory) {
62394
62547
  stderr: "pipe",
62395
62548
  cwd: directory
62396
62549
  });
62397
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62550
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62398
62551
  const result = await Promise.race([
62399
62552
  Promise.all([
62400
62553
  new Response(proc.stdout).text(),
@@ -62619,8 +62772,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
62619
62772
  ]);
62620
62773
  // src/tools/pre-check-batch.ts
62621
62774
  init_dist();
62622
- import * as fs43 from "fs";
62623
- import * as path56 from "path";
62775
+ import * as fs44 from "fs";
62776
+ import * as path57 from "path";
62624
62777
 
62625
62778
  // node_modules/yocto-queue/index.js
62626
62779
  class Node2 {
@@ -62711,26 +62864,26 @@ function pLimit(concurrency) {
62711
62864
  activeCount--;
62712
62865
  resumeNext();
62713
62866
  };
62714
- const run2 = async (function_, resolve18, arguments_2) => {
62867
+ const run2 = async (function_, resolve19, arguments_2) => {
62715
62868
  const result = (async () => function_(...arguments_2))();
62716
- resolve18(result);
62869
+ resolve19(result);
62717
62870
  try {
62718
62871
  await result;
62719
62872
  } catch {}
62720
62873
  next();
62721
62874
  };
62722
- const enqueue = (function_, resolve18, reject, arguments_2) => {
62875
+ const enqueue = (function_, resolve19, reject, arguments_2) => {
62723
62876
  const queueItem = { reject };
62724
62877
  new Promise((internalResolve) => {
62725
62878
  queueItem.run = internalResolve;
62726
62879
  queue.enqueue(queueItem);
62727
- }).then(run2.bind(undefined, function_, resolve18, arguments_2));
62880
+ }).then(run2.bind(undefined, function_, resolve19, arguments_2));
62728
62881
  if (activeCount < concurrency) {
62729
62882
  resumeNext();
62730
62883
  }
62731
62884
  };
62732
- const generator = (function_, ...arguments_2) => new Promise((resolve18, reject) => {
62733
- enqueue(function_, resolve18, reject, arguments_2);
62885
+ const generator = (function_, ...arguments_2) => new Promise((resolve19, reject) => {
62886
+ enqueue(function_, resolve19, reject, arguments_2);
62734
62887
  });
62735
62888
  Object.defineProperties(generator, {
62736
62889
  activeCount: {
@@ -62894,8 +63047,8 @@ async function qualityBudget(input, directory) {
62894
63047
  init_dist();
62895
63048
  init_manager();
62896
63049
  init_detector();
62897
- import * as fs42 from "fs";
62898
- import * as path55 from "path";
63050
+ import * as fs43 from "fs";
63051
+ import * as path56 from "path";
62899
63052
  import { extname as extname10 } from "path";
62900
63053
 
62901
63054
  // src/sast/rules/c.ts
@@ -63646,7 +63799,7 @@ function mapSemgrepSeverity(severity) {
63646
63799
  }
63647
63800
  }
63648
63801
  async function executeWithTimeout(command, args2, options) {
63649
- return new Promise((resolve18) => {
63802
+ return new Promise((resolve19) => {
63650
63803
  const child = spawn2(command, args2, {
63651
63804
  shell: false,
63652
63805
  cwd: options.cwd
@@ -63655,7 +63808,7 @@ async function executeWithTimeout(command, args2, options) {
63655
63808
  let stderr = "";
63656
63809
  const timeout = setTimeout(() => {
63657
63810
  child.kill("SIGTERM");
63658
- resolve18({
63811
+ resolve19({
63659
63812
  stdout,
63660
63813
  stderr: "Process timed out",
63661
63814
  exitCode: 124
@@ -63669,7 +63822,7 @@ async function executeWithTimeout(command, args2, options) {
63669
63822
  });
63670
63823
  child.on("close", (code) => {
63671
63824
  clearTimeout(timeout);
63672
- resolve18({
63825
+ resolve19({
63673
63826
  stdout,
63674
63827
  stderr,
63675
63828
  exitCode: code ?? 0
@@ -63677,7 +63830,7 @@ async function executeWithTimeout(command, args2, options) {
63677
63830
  });
63678
63831
  child.on("error", (err2) => {
63679
63832
  clearTimeout(timeout);
63680
- resolve18({
63833
+ resolve19({
63681
63834
  stdout,
63682
63835
  stderr: err2.message,
63683
63836
  exitCode: 1
@@ -63765,17 +63918,17 @@ var SEVERITY_ORDER = {
63765
63918
  };
63766
63919
  function shouldSkipFile(filePath) {
63767
63920
  try {
63768
- const stats = fs42.statSync(filePath);
63921
+ const stats = fs43.statSync(filePath);
63769
63922
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
63770
63923
  return { skip: true, reason: "file too large" };
63771
63924
  }
63772
63925
  if (stats.size === 0) {
63773
63926
  return { skip: true, reason: "empty file" };
63774
63927
  }
63775
- const fd = fs42.openSync(filePath, "r");
63928
+ const fd = fs43.openSync(filePath, "r");
63776
63929
  const buffer = Buffer.alloc(8192);
63777
- const bytesRead = fs42.readSync(fd, buffer, 0, 8192, 0);
63778
- fs42.closeSync(fd);
63930
+ const bytesRead = fs43.readSync(fd, buffer, 0, 8192, 0);
63931
+ fs43.closeSync(fd);
63779
63932
  if (bytesRead > 0) {
63780
63933
  let nullCount = 0;
63781
63934
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -63814,7 +63967,7 @@ function countBySeverity(findings) {
63814
63967
  }
63815
63968
  function scanFileWithTierA(filePath, language) {
63816
63969
  try {
63817
- const content = fs42.readFileSync(filePath, "utf-8");
63970
+ const content = fs43.readFileSync(filePath, "utf-8");
63818
63971
  const findings = executeRulesSync(filePath, content, language);
63819
63972
  return findings.map((f) => ({
63820
63973
  rule_id: f.rule_id,
@@ -63861,8 +64014,8 @@ async function sastScan(input, directory, config3) {
63861
64014
  _filesSkipped++;
63862
64015
  continue;
63863
64016
  }
63864
- const resolvedPath = path55.isAbsolute(filePath) ? filePath : path55.resolve(directory, filePath);
63865
- if (!fs42.existsSync(resolvedPath)) {
64017
+ const resolvedPath = path56.isAbsolute(filePath) ? filePath : path56.resolve(directory, filePath);
64018
+ if (!fs43.existsSync(resolvedPath)) {
63866
64019
  _filesSkipped++;
63867
64020
  continue;
63868
64021
  }
@@ -64060,18 +64213,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
64060
64213
  let resolved;
64061
64214
  const isWinAbs = isWindowsAbsolutePath(inputPath);
64062
64215
  if (isWinAbs) {
64063
- resolved = path56.win32.resolve(inputPath);
64064
- } else if (path56.isAbsolute(inputPath)) {
64065
- resolved = path56.resolve(inputPath);
64216
+ resolved = path57.win32.resolve(inputPath);
64217
+ } else if (path57.isAbsolute(inputPath)) {
64218
+ resolved = path57.resolve(inputPath);
64066
64219
  } else {
64067
- resolved = path56.resolve(baseDir, inputPath);
64220
+ resolved = path57.resolve(baseDir, inputPath);
64068
64221
  }
64069
- const workspaceResolved = path56.resolve(workspaceDir);
64222
+ const workspaceResolved = path57.resolve(workspaceDir);
64070
64223
  let relative8;
64071
64224
  if (isWinAbs) {
64072
- relative8 = path56.win32.relative(workspaceResolved, resolved);
64225
+ relative8 = path57.win32.relative(workspaceResolved, resolved);
64073
64226
  } else {
64074
- relative8 = path56.relative(workspaceResolved, resolved);
64227
+ relative8 = path57.relative(workspaceResolved, resolved);
64075
64228
  }
64076
64229
  if (relative8.startsWith("..")) {
64077
64230
  return "path traversal detected";
@@ -64132,13 +64285,13 @@ async function runLintWrapped(files, directory, _config) {
64132
64285
  }
64133
64286
  async function runLintOnFiles(linter, files, workspaceDir) {
64134
64287
  const isWindows = process.platform === "win32";
64135
- const binDir = path56.join(workspaceDir, "node_modules", ".bin");
64288
+ const binDir = path57.join(workspaceDir, "node_modules", ".bin");
64136
64289
  const validatedFiles = [];
64137
64290
  for (const file3 of files) {
64138
64291
  if (typeof file3 !== "string") {
64139
64292
  continue;
64140
64293
  }
64141
- const resolvedPath = path56.resolve(file3);
64294
+ const resolvedPath = path57.resolve(file3);
64142
64295
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
64143
64296
  if (validationError) {
64144
64297
  continue;
@@ -64156,10 +64309,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
64156
64309
  }
64157
64310
  let command;
64158
64311
  if (linter === "biome") {
64159
- const biomeBin = isWindows ? path56.join(binDir, "biome.EXE") : path56.join(binDir, "biome");
64312
+ const biomeBin = isWindows ? path57.join(binDir, "biome.EXE") : path57.join(binDir, "biome");
64160
64313
  command = [biomeBin, "check", ...validatedFiles];
64161
64314
  } else {
64162
- const eslintBin = isWindows ? path56.join(binDir, "eslint.cmd") : path56.join(binDir, "eslint");
64315
+ const eslintBin = isWindows ? path57.join(binDir, "eslint.cmd") : path57.join(binDir, "eslint");
64163
64316
  command = [eslintBin, ...validatedFiles];
64164
64317
  }
64165
64318
  try {
@@ -64296,7 +64449,7 @@ async function runSecretscanWithFiles(files, directory) {
64296
64449
  skippedFiles++;
64297
64450
  continue;
64298
64451
  }
64299
- const resolvedPath = path56.resolve(file3);
64452
+ const resolvedPath = path57.resolve(file3);
64300
64453
  const validationError = validatePath(resolvedPath, directory, directory);
64301
64454
  if (validationError) {
64302
64455
  skippedFiles++;
@@ -64314,14 +64467,14 @@ async function runSecretscanWithFiles(files, directory) {
64314
64467
  };
64315
64468
  }
64316
64469
  for (const file3 of validatedFiles) {
64317
- const ext = path56.extname(file3).toLowerCase();
64470
+ const ext = path57.extname(file3).toLowerCase();
64318
64471
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
64319
64472
  skippedFiles++;
64320
64473
  continue;
64321
64474
  }
64322
64475
  let stat2;
64323
64476
  try {
64324
- stat2 = fs43.statSync(file3);
64477
+ stat2 = fs44.statSync(file3);
64325
64478
  } catch {
64326
64479
  skippedFiles++;
64327
64480
  continue;
@@ -64332,7 +64485,7 @@ async function runSecretscanWithFiles(files, directory) {
64332
64485
  }
64333
64486
  let content;
64334
64487
  try {
64335
- const buffer = fs43.readFileSync(file3);
64488
+ const buffer = fs44.readFileSync(file3);
64336
64489
  if (buffer.includes(0)) {
64337
64490
  skippedFiles++;
64338
64491
  continue;
@@ -64520,7 +64673,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
64520
64673
  const preexistingFindings = [];
64521
64674
  for (const finding of findings) {
64522
64675
  const filePath = finding.location.file;
64523
- const normalised = path56.relative(directory, filePath).replace(/\\/g, "/");
64676
+ const normalised = path57.relative(directory, filePath).replace(/\\/g, "/");
64524
64677
  const changedLines = changedLineRanges.get(normalised);
64525
64678
  if (changedLines && changedLines.has(finding.location.line)) {
64526
64679
  newFindings.push(finding);
@@ -64571,7 +64724,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
64571
64724
  warn(`pre_check_batch: Invalid file path: ${file3}`);
64572
64725
  continue;
64573
64726
  }
64574
- changedFiles.push(path56.resolve(directory, file3));
64727
+ changedFiles.push(path57.resolve(directory, file3));
64575
64728
  }
64576
64729
  if (changedFiles.length === 0) {
64577
64730
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -64759,7 +64912,7 @@ var pre_check_batch = createSwarmTool({
64759
64912
  };
64760
64913
  return JSON.stringify(errorResult, null, 2);
64761
64914
  }
64762
- const resolvedDirectory = path56.resolve(typedArgs.directory);
64915
+ const resolvedDirectory = path57.resolve(typedArgs.directory);
64763
64916
  const workspaceAnchor = resolvedDirectory;
64764
64917
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
64765
64918
  if (dirError) {
@@ -64865,38 +65018,38 @@ ${paginatedContent}`;
64865
65018
  });
64866
65019
  // src/tools/save-plan.ts
64867
65020
  init_tool();
64868
- import * as fs45 from "fs";
64869
- import * as path58 from "path";
65021
+ import * as fs46 from "fs";
65022
+ import * as path59 from "path";
64870
65023
 
64871
65024
  // src/parallel/file-locks.ts
64872
- import * as fs44 from "fs";
64873
- import * as path57 from "path";
65025
+ import * as fs45 from "fs";
65026
+ import * as path58 from "path";
64874
65027
  var LOCKS_DIR = ".swarm/locks";
64875
65028
  var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
64876
65029
  function getLockFilePath(directory, filePath) {
64877
- const normalized = path57.resolve(directory, filePath);
64878
- if (!normalized.startsWith(path57.resolve(directory))) {
65030
+ const normalized = path58.resolve(directory, filePath);
65031
+ if (!normalized.startsWith(path58.resolve(directory))) {
64879
65032
  throw new Error("Invalid file path: path traversal not allowed");
64880
65033
  }
64881
65034
  const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
64882
- return path57.join(directory, LOCKS_DIR, `${hash3}.lock`);
65035
+ return path58.join(directory, LOCKS_DIR, `${hash3}.lock`);
64883
65036
  }
64884
65037
  function tryAcquireLock(directory, filePath, agent, taskId) {
64885
65038
  const lockPath = getLockFilePath(directory, filePath);
64886
- const locksDir = path57.dirname(lockPath);
64887
- if (!fs44.existsSync(locksDir)) {
64888
- fs44.mkdirSync(locksDir, { recursive: true });
65039
+ const locksDir = path58.dirname(lockPath);
65040
+ if (!fs45.existsSync(locksDir)) {
65041
+ fs45.mkdirSync(locksDir, { recursive: true });
64889
65042
  }
64890
- if (fs44.existsSync(lockPath)) {
65043
+ if (fs45.existsSync(lockPath)) {
64891
65044
  try {
64892
- const existingLock = JSON.parse(fs44.readFileSync(lockPath, "utf-8"));
65045
+ const existingLock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
64893
65046
  if (Date.now() > existingLock.expiresAt) {
64894
- fs44.unlinkSync(lockPath);
65047
+ fs45.unlinkSync(lockPath);
64895
65048
  } else {
64896
65049
  return { acquired: false, existing: existingLock };
64897
65050
  }
64898
65051
  } catch {
64899
- fs44.unlinkSync(lockPath);
65052
+ fs45.unlinkSync(lockPath);
64900
65053
  }
64901
65054
  }
64902
65055
  const lock = {
@@ -64907,24 +65060,24 @@ function tryAcquireLock(directory, filePath, agent, taskId) {
64907
65060
  expiresAt: Date.now() + LOCK_TIMEOUT_MS
64908
65061
  };
64909
65062
  const tempPath = `${lockPath}.tmp`;
64910
- fs44.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
64911
- fs44.renameSync(tempPath, lockPath);
65063
+ fs45.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65064
+ fs45.renameSync(tempPath, lockPath);
64912
65065
  return { acquired: true, lock };
64913
65066
  }
64914
65067
  function releaseLock(directory, filePath, taskId) {
64915
65068
  const lockPath = getLockFilePath(directory, filePath);
64916
- if (!fs44.existsSync(lockPath)) {
65069
+ if (!fs45.existsSync(lockPath)) {
64917
65070
  return true;
64918
65071
  }
64919
65072
  try {
64920
- const lock = JSON.parse(fs44.readFileSync(lockPath, "utf-8"));
65073
+ const lock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
64921
65074
  if (lock.taskId === taskId) {
64922
- fs44.unlinkSync(lockPath);
65075
+ fs45.unlinkSync(lockPath);
64923
65076
  return true;
64924
65077
  }
64925
65078
  return false;
64926
65079
  } catch {
64927
- fs44.unlinkSync(lockPath);
65080
+ fs45.unlinkSync(lockPath);
64928
65081
  return true;
64929
65082
  }
64930
65083
  }
@@ -65049,14 +65202,14 @@ async function executeSavePlan(args2, fallbackDir) {
65049
65202
  try {
65050
65203
  await savePlan(dir, plan);
65051
65204
  try {
65052
- const markerPath = path58.join(dir, ".swarm", ".plan-write-marker");
65205
+ const markerPath = path59.join(dir, ".swarm", ".plan-write-marker");
65053
65206
  const marker = JSON.stringify({
65054
65207
  source: "save_plan",
65055
65208
  timestamp: new Date().toISOString(),
65056
65209
  phases_count: plan.phases.length,
65057
65210
  tasks_count: tasksCount
65058
65211
  });
65059
- await fs45.promises.writeFile(markerPath, marker, "utf8");
65212
+ await fs46.promises.writeFile(markerPath, marker, "utf8");
65060
65213
  } catch {}
65061
65214
  const warnings = [];
65062
65215
  let criticReviewFound = false;
@@ -65072,7 +65225,7 @@ async function executeSavePlan(args2, fallbackDir) {
65072
65225
  return {
65073
65226
  success: true,
65074
65227
  message: "Plan saved successfully",
65075
- plan_path: path58.join(dir, ".swarm", "plan.json"),
65228
+ plan_path: path59.join(dir, ".swarm", "plan.json"),
65076
65229
  phases_count: plan.phases.length,
65077
65230
  tasks_count: tasksCount,
65078
65231
  ...warnings.length > 0 ? { warnings } : {}
@@ -65114,8 +65267,8 @@ var save_plan = createSwarmTool({
65114
65267
  // src/tools/sbom-generate.ts
65115
65268
  init_dist();
65116
65269
  init_manager();
65117
- import * as fs46 from "fs";
65118
- import * as path59 from "path";
65270
+ import * as fs47 from "fs";
65271
+ import * as path60 from "path";
65119
65272
 
65120
65273
  // src/sbom/detectors/index.ts
65121
65274
  init_utils();
@@ -65963,9 +66116,9 @@ function findManifestFiles(rootDir) {
65963
66116
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
65964
66117
  function searchDir(dir) {
65965
66118
  try {
65966
- const entries = fs46.readdirSync(dir, { withFileTypes: true });
66119
+ const entries = fs47.readdirSync(dir, { withFileTypes: true });
65967
66120
  for (const entry of entries) {
65968
- const fullPath = path59.join(dir, entry.name);
66121
+ const fullPath = path60.join(dir, entry.name);
65969
66122
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
65970
66123
  continue;
65971
66124
  }
@@ -65974,7 +66127,7 @@ function findManifestFiles(rootDir) {
65974
66127
  } else if (entry.isFile()) {
65975
66128
  for (const pattern of patterns) {
65976
66129
  if (simpleGlobToRegex(pattern).test(entry.name)) {
65977
- manifestFiles.push(path59.relative(rootDir, fullPath));
66130
+ manifestFiles.push(path60.relative(rootDir, fullPath));
65978
66131
  break;
65979
66132
  }
65980
66133
  }
@@ -65990,13 +66143,13 @@ function findManifestFilesInDirs(directories, workingDir) {
65990
66143
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
65991
66144
  for (const dir of directories) {
65992
66145
  try {
65993
- const entries = fs46.readdirSync(dir, { withFileTypes: true });
66146
+ const entries = fs47.readdirSync(dir, { withFileTypes: true });
65994
66147
  for (const entry of entries) {
65995
- const fullPath = path59.join(dir, entry.name);
66148
+ const fullPath = path60.join(dir, entry.name);
65996
66149
  if (entry.isFile()) {
65997
66150
  for (const pattern of patterns) {
65998
66151
  if (simpleGlobToRegex(pattern).test(entry.name)) {
65999
- found.push(path59.relative(workingDir, fullPath));
66152
+ found.push(path60.relative(workingDir, fullPath));
66000
66153
  break;
66001
66154
  }
66002
66155
  }
@@ -66009,11 +66162,11 @@ function findManifestFilesInDirs(directories, workingDir) {
66009
66162
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66010
66163
  const dirs = new Set;
66011
66164
  for (const file3 of changedFiles) {
66012
- let currentDir = path59.dirname(file3);
66165
+ let currentDir = path60.dirname(file3);
66013
66166
  while (true) {
66014
- if (currentDir && currentDir !== "." && currentDir !== path59.sep) {
66015
- dirs.add(path59.join(workingDir, currentDir));
66016
- const parent = path59.dirname(currentDir);
66167
+ if (currentDir && currentDir !== "." && currentDir !== path60.sep) {
66168
+ dirs.add(path60.join(workingDir, currentDir));
66169
+ const parent = path60.dirname(currentDir);
66017
66170
  if (parent === currentDir)
66018
66171
  break;
66019
66172
  currentDir = parent;
@@ -66027,7 +66180,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66027
66180
  }
66028
66181
  function ensureOutputDir(outputDir) {
66029
66182
  try {
66030
- fs46.mkdirSync(outputDir, { recursive: true });
66183
+ fs47.mkdirSync(outputDir, { recursive: true });
66031
66184
  } catch (error93) {
66032
66185
  if (!error93 || error93.code !== "EEXIST") {
66033
66186
  throw error93;
@@ -66097,7 +66250,7 @@ var sbom_generate = createSwarmTool({
66097
66250
  const changedFiles = obj.changed_files;
66098
66251
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
66099
66252
  const workingDir = directory;
66100
- const outputDir = path59.isAbsolute(relativeOutputDir) ? relativeOutputDir : path59.join(workingDir, relativeOutputDir);
66253
+ const outputDir = path60.isAbsolute(relativeOutputDir) ? relativeOutputDir : path60.join(workingDir, relativeOutputDir);
66101
66254
  let manifestFiles = [];
66102
66255
  if (scope === "all") {
66103
66256
  manifestFiles = findManifestFiles(workingDir);
@@ -66120,11 +66273,11 @@ var sbom_generate = createSwarmTool({
66120
66273
  const processedFiles = [];
66121
66274
  for (const manifestFile of manifestFiles) {
66122
66275
  try {
66123
- const fullPath = path59.isAbsolute(manifestFile) ? manifestFile : path59.join(workingDir, manifestFile);
66124
- if (!fs46.existsSync(fullPath)) {
66276
+ const fullPath = path60.isAbsolute(manifestFile) ? manifestFile : path60.join(workingDir, manifestFile);
66277
+ if (!fs47.existsSync(fullPath)) {
66125
66278
  continue;
66126
66279
  }
66127
- const content = fs46.readFileSync(fullPath, "utf-8");
66280
+ const content = fs47.readFileSync(fullPath, "utf-8");
66128
66281
  const components = detectComponents(manifestFile, content);
66129
66282
  processedFiles.push(manifestFile);
66130
66283
  if (components.length > 0) {
@@ -66137,8 +66290,8 @@ var sbom_generate = createSwarmTool({
66137
66290
  const bom = generateCycloneDX(allComponents);
66138
66291
  const bomJson = serializeCycloneDX(bom);
66139
66292
  const filename = generateSbomFilename();
66140
- const outputPath = path59.join(outputDir, filename);
66141
- fs46.writeFileSync(outputPath, bomJson, "utf-8");
66293
+ const outputPath = path60.join(outputDir, filename);
66294
+ fs47.writeFileSync(outputPath, bomJson, "utf-8");
66142
66295
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
66143
66296
  try {
66144
66297
  const timestamp = new Date().toISOString();
@@ -66180,8 +66333,8 @@ var sbom_generate = createSwarmTool({
66180
66333
  // src/tools/schema-drift.ts
66181
66334
  init_dist();
66182
66335
  init_create_tool();
66183
- import * as fs47 from "fs";
66184
- import * as path60 from "path";
66336
+ import * as fs48 from "fs";
66337
+ import * as path61 from "path";
66185
66338
  var SPEC_CANDIDATES = [
66186
66339
  "openapi.json",
66187
66340
  "openapi.yaml",
@@ -66213,28 +66366,28 @@ function normalizePath2(p) {
66213
66366
  }
66214
66367
  function discoverSpecFile(cwd, specFileArg) {
66215
66368
  if (specFileArg) {
66216
- const resolvedPath = path60.resolve(cwd, specFileArg);
66217
- const normalizedCwd = cwd.endsWith(path60.sep) ? cwd : cwd + path60.sep;
66369
+ const resolvedPath = path61.resolve(cwd, specFileArg);
66370
+ const normalizedCwd = cwd.endsWith(path61.sep) ? cwd : cwd + path61.sep;
66218
66371
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
66219
66372
  throw new Error("Invalid spec_file: path traversal detected");
66220
66373
  }
66221
- const ext = path60.extname(resolvedPath).toLowerCase();
66374
+ const ext = path61.extname(resolvedPath).toLowerCase();
66222
66375
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
66223
66376
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
66224
66377
  }
66225
- const stats = fs47.statSync(resolvedPath);
66378
+ const stats = fs48.statSync(resolvedPath);
66226
66379
  if (stats.size > MAX_SPEC_SIZE) {
66227
66380
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
66228
66381
  }
66229
- if (!fs47.existsSync(resolvedPath)) {
66382
+ if (!fs48.existsSync(resolvedPath)) {
66230
66383
  throw new Error(`Spec file not found: ${resolvedPath}`);
66231
66384
  }
66232
66385
  return resolvedPath;
66233
66386
  }
66234
66387
  for (const candidate of SPEC_CANDIDATES) {
66235
- const candidatePath = path60.resolve(cwd, candidate);
66236
- if (fs47.existsSync(candidatePath)) {
66237
- const stats = fs47.statSync(candidatePath);
66388
+ const candidatePath = path61.resolve(cwd, candidate);
66389
+ if (fs48.existsSync(candidatePath)) {
66390
+ const stats = fs48.statSync(candidatePath);
66238
66391
  if (stats.size <= MAX_SPEC_SIZE) {
66239
66392
  return candidatePath;
66240
66393
  }
@@ -66243,8 +66396,8 @@ function discoverSpecFile(cwd, specFileArg) {
66243
66396
  return null;
66244
66397
  }
66245
66398
  function parseSpec(specFile) {
66246
- const content = fs47.readFileSync(specFile, "utf-8");
66247
- const ext = path60.extname(specFile).toLowerCase();
66399
+ const content = fs48.readFileSync(specFile, "utf-8");
66400
+ const ext = path61.extname(specFile).toLowerCase();
66248
66401
  if (ext === ".json") {
66249
66402
  return parseJsonSpec(content);
66250
66403
  }
@@ -66315,12 +66468,12 @@ function extractRoutes(cwd) {
66315
66468
  function walkDir(dir) {
66316
66469
  let entries;
66317
66470
  try {
66318
- entries = fs47.readdirSync(dir, { withFileTypes: true });
66471
+ entries = fs48.readdirSync(dir, { withFileTypes: true });
66319
66472
  } catch {
66320
66473
  return;
66321
66474
  }
66322
66475
  for (const entry of entries) {
66323
- const fullPath = path60.join(dir, entry.name);
66476
+ const fullPath = path61.join(dir, entry.name);
66324
66477
  if (entry.isSymbolicLink()) {
66325
66478
  continue;
66326
66479
  }
@@ -66330,7 +66483,7 @@ function extractRoutes(cwd) {
66330
66483
  }
66331
66484
  walkDir(fullPath);
66332
66485
  } else if (entry.isFile()) {
66333
- const ext = path60.extname(entry.name).toLowerCase();
66486
+ const ext = path61.extname(entry.name).toLowerCase();
66334
66487
  const baseName = entry.name.toLowerCase();
66335
66488
  if (![".ts", ".js", ".mjs"].includes(ext)) {
66336
66489
  continue;
@@ -66348,7 +66501,7 @@ function extractRoutes(cwd) {
66348
66501
  }
66349
66502
  function extractRoutesFromFile(filePath) {
66350
66503
  const routes = [];
66351
- const content = fs47.readFileSync(filePath, "utf-8");
66504
+ const content = fs48.readFileSync(filePath, "utf-8");
66352
66505
  const lines = content.split(/\r?\n/);
66353
66506
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
66354
66507
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -66499,8 +66652,8 @@ init_secretscan();
66499
66652
  // src/tools/symbols.ts
66500
66653
  init_tool();
66501
66654
  init_create_tool();
66502
- import * as fs48 from "fs";
66503
- import * as path61 from "path";
66655
+ import * as fs49 from "fs";
66656
+ import * as path62 from "path";
66504
66657
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
66505
66658
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
66506
66659
  function containsWindowsAttacks(str) {
@@ -66517,11 +66670,11 @@ function containsWindowsAttacks(str) {
66517
66670
  }
66518
66671
  function isPathInWorkspace(filePath, workspace) {
66519
66672
  try {
66520
- const resolvedPath = path61.resolve(workspace, filePath);
66521
- const realWorkspace = fs48.realpathSync(workspace);
66522
- const realResolvedPath = fs48.realpathSync(resolvedPath);
66523
- const relativePath = path61.relative(realWorkspace, realResolvedPath);
66524
- if (relativePath.startsWith("..") || path61.isAbsolute(relativePath)) {
66673
+ const resolvedPath = path62.resolve(workspace, filePath);
66674
+ const realWorkspace = fs49.realpathSync(workspace);
66675
+ const realResolvedPath = fs49.realpathSync(resolvedPath);
66676
+ const relativePath = path62.relative(realWorkspace, realResolvedPath);
66677
+ if (relativePath.startsWith("..") || path62.isAbsolute(relativePath)) {
66525
66678
  return false;
66526
66679
  }
66527
66680
  return true;
@@ -66533,17 +66686,17 @@ function validatePathForRead(filePath, workspace) {
66533
66686
  return isPathInWorkspace(filePath, workspace);
66534
66687
  }
66535
66688
  function extractTSSymbols(filePath, cwd) {
66536
- const fullPath = path61.join(cwd, filePath);
66689
+ const fullPath = path62.join(cwd, filePath);
66537
66690
  if (!validatePathForRead(fullPath, cwd)) {
66538
66691
  return [];
66539
66692
  }
66540
66693
  let content;
66541
66694
  try {
66542
- const stats = fs48.statSync(fullPath);
66695
+ const stats = fs49.statSync(fullPath);
66543
66696
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66544
66697
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66545
66698
  }
66546
- content = fs48.readFileSync(fullPath, "utf-8");
66699
+ content = fs49.readFileSync(fullPath, "utf-8");
66547
66700
  } catch {
66548
66701
  return [];
66549
66702
  }
@@ -66685,17 +66838,17 @@ function extractTSSymbols(filePath, cwd) {
66685
66838
  });
66686
66839
  }
66687
66840
  function extractPythonSymbols(filePath, cwd) {
66688
- const fullPath = path61.join(cwd, filePath);
66841
+ const fullPath = path62.join(cwd, filePath);
66689
66842
  if (!validatePathForRead(fullPath, cwd)) {
66690
66843
  return [];
66691
66844
  }
66692
66845
  let content;
66693
66846
  try {
66694
- const stats = fs48.statSync(fullPath);
66847
+ const stats = fs49.statSync(fullPath);
66695
66848
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66696
66849
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66697
66850
  }
66698
- content = fs48.readFileSync(fullPath, "utf-8");
66851
+ content = fs49.readFileSync(fullPath, "utf-8");
66699
66852
  } catch {
66700
66853
  return [];
66701
66854
  }
@@ -66768,7 +66921,7 @@ var symbols = createSwarmTool({
66768
66921
  }, null, 2);
66769
66922
  }
66770
66923
  const cwd = directory;
66771
- const ext = path61.extname(file3);
66924
+ const ext = path62.extname(file3);
66772
66925
  if (containsControlChars(file3)) {
66773
66926
  return JSON.stringify({
66774
66927
  file: file3,
@@ -66839,8 +66992,8 @@ init_test_runner();
66839
66992
  init_dist();
66840
66993
  init_utils();
66841
66994
  init_create_tool();
66842
- import * as fs49 from "fs";
66843
- import * as path62 from "path";
66995
+ import * as fs50 from "fs";
66996
+ import * as path63 from "path";
66844
66997
  var MAX_TEXT_LENGTH = 200;
66845
66998
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
66846
66999
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -66905,9 +67058,9 @@ function validatePathsInput(paths, cwd) {
66905
67058
  return { error: "paths contains path traversal", resolvedPath: null };
66906
67059
  }
66907
67060
  try {
66908
- const resolvedPath = path62.resolve(paths);
66909
- const normalizedCwd = path62.resolve(cwd);
66910
- const normalizedResolved = path62.resolve(resolvedPath);
67061
+ const resolvedPath = path63.resolve(paths);
67062
+ const normalizedCwd = path63.resolve(cwd);
67063
+ const normalizedResolved = path63.resolve(resolvedPath);
66911
67064
  if (!normalizedResolved.startsWith(normalizedCwd)) {
66912
67065
  return {
66913
67066
  error: "paths must be within the current working directory",
@@ -66923,13 +67076,13 @@ function validatePathsInput(paths, cwd) {
66923
67076
  }
66924
67077
  }
66925
67078
  function isSupportedExtension(filePath) {
66926
- const ext = path62.extname(filePath).toLowerCase();
67079
+ const ext = path63.extname(filePath).toLowerCase();
66927
67080
  return SUPPORTED_EXTENSIONS2.has(ext);
66928
67081
  }
66929
67082
  function findSourceFiles2(dir, files = []) {
66930
67083
  let entries;
66931
67084
  try {
66932
- entries = fs49.readdirSync(dir);
67085
+ entries = fs50.readdirSync(dir);
66933
67086
  } catch {
66934
67087
  return files;
66935
67088
  }
@@ -66938,10 +67091,10 @@ function findSourceFiles2(dir, files = []) {
66938
67091
  if (SKIP_DIRECTORIES4.has(entry)) {
66939
67092
  continue;
66940
67093
  }
66941
- const fullPath = path62.join(dir, entry);
67094
+ const fullPath = path63.join(dir, entry);
66942
67095
  let stat2;
66943
67096
  try {
66944
- stat2 = fs49.statSync(fullPath);
67097
+ stat2 = fs50.statSync(fullPath);
66945
67098
  } catch {
66946
67099
  continue;
66947
67100
  }
@@ -67034,7 +67187,7 @@ var todo_extract = createSwarmTool({
67034
67187
  return JSON.stringify(errorResult, null, 2);
67035
67188
  }
67036
67189
  const scanPath = resolvedPath;
67037
- if (!fs49.existsSync(scanPath)) {
67190
+ if (!fs50.existsSync(scanPath)) {
67038
67191
  const errorResult = {
67039
67192
  error: `path not found: ${pathsInput}`,
67040
67193
  total: 0,
@@ -67044,13 +67197,13 @@ var todo_extract = createSwarmTool({
67044
67197
  return JSON.stringify(errorResult, null, 2);
67045
67198
  }
67046
67199
  const filesToScan = [];
67047
- const stat2 = fs49.statSync(scanPath);
67200
+ const stat2 = fs50.statSync(scanPath);
67048
67201
  if (stat2.isFile()) {
67049
67202
  if (isSupportedExtension(scanPath)) {
67050
67203
  filesToScan.push(scanPath);
67051
67204
  } else {
67052
67205
  const errorResult = {
67053
- error: `unsupported file extension: ${path62.extname(scanPath)}`,
67206
+ error: `unsupported file extension: ${path63.extname(scanPath)}`,
67054
67207
  total: 0,
67055
67208
  byPriority: { high: 0, medium: 0, low: 0 },
67056
67209
  entries: []
@@ -67063,11 +67216,11 @@ var todo_extract = createSwarmTool({
67063
67216
  const allEntries = [];
67064
67217
  for (const filePath of filesToScan) {
67065
67218
  try {
67066
- const fileStat = fs49.statSync(filePath);
67219
+ const fileStat = fs50.statSync(filePath);
67067
67220
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
67068
67221
  continue;
67069
67222
  }
67070
- const content = fs49.readFileSync(filePath, "utf-8");
67223
+ const content = fs50.readFileSync(filePath, "utf-8");
67071
67224
  const entries = parseTodoComments(content, filePath, tagsSet);
67072
67225
  allEntries.push(...entries);
67073
67226
  } catch {}
@@ -67096,18 +67249,18 @@ var todo_extract = createSwarmTool({
67096
67249
  init_tool();
67097
67250
  init_schema();
67098
67251
  init_gate_evidence();
67099
- import * as fs51 from "fs";
67100
- import * as path64 from "path";
67252
+ import * as fs52 from "fs";
67253
+ import * as path65 from "path";
67101
67254
 
67102
67255
  // src/hooks/diff-scope.ts
67103
- import * as fs50 from "fs";
67104
- import * as path63 from "path";
67256
+ import * as fs51 from "fs";
67257
+ import * as path64 from "path";
67105
67258
  function getDeclaredScope(taskId, directory) {
67106
67259
  try {
67107
- const planPath = path63.join(directory, ".swarm", "plan.json");
67108
- if (!fs50.existsSync(planPath))
67260
+ const planPath = path64.join(directory, ".swarm", "plan.json");
67261
+ if (!fs51.existsSync(planPath))
67109
67262
  return null;
67110
- const raw = fs50.readFileSync(planPath, "utf-8");
67263
+ const raw = fs51.readFileSync(planPath, "utf-8");
67111
67264
  const plan = JSON.parse(raw);
67112
67265
  for (const phase of plan.phases ?? []) {
67113
67266
  for (const task of phase.tasks ?? []) {
@@ -67220,7 +67373,7 @@ var TIER_3_PATTERNS = [
67220
67373
  ];
67221
67374
  function matchesTier3Pattern(files) {
67222
67375
  for (const file3 of files) {
67223
- const fileName = path64.basename(file3);
67376
+ const fileName = path65.basename(file3);
67224
67377
  for (const pattern of TIER_3_PATTERNS) {
67225
67378
  if (pattern.test(fileName)) {
67226
67379
  return true;
@@ -67234,8 +67387,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67234
67387
  if (hasActiveTurboMode()) {
67235
67388
  const resolvedDir2 = workingDirectory;
67236
67389
  try {
67237
- const planPath = path64.join(resolvedDir2, ".swarm", "plan.json");
67238
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67390
+ const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67391
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67239
67392
  const plan = JSON.parse(planRaw);
67240
67393
  for (const planPhase of plan.phases ?? []) {
67241
67394
  for (const task of planPhase.tasks ?? []) {
@@ -67301,8 +67454,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67301
67454
  }
67302
67455
  try {
67303
67456
  const resolvedDir2 = workingDirectory;
67304
- const planPath = path64.join(resolvedDir2, ".swarm", "plan.json");
67305
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67457
+ const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67458
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67306
67459
  const plan = JSON.parse(planRaw);
67307
67460
  for (const planPhase of plan.phases ?? []) {
67308
67461
  for (const task of planPhase.tasks ?? []) {
@@ -67484,8 +67637,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67484
67637
  };
67485
67638
  }
67486
67639
  }
67487
- normalizedDir = path64.normalize(args2.working_directory);
67488
- const pathParts = normalizedDir.split(path64.sep);
67640
+ normalizedDir = path65.normalize(args2.working_directory);
67641
+ const pathParts = normalizedDir.split(path65.sep);
67489
67642
  if (pathParts.includes("..")) {
67490
67643
  return {
67491
67644
  success: false,
@@ -67495,11 +67648,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67495
67648
  ]
67496
67649
  };
67497
67650
  }
67498
- const resolvedDir = path64.resolve(normalizedDir);
67651
+ const resolvedDir = path65.resolve(normalizedDir);
67499
67652
  try {
67500
- const realPath = fs51.realpathSync(resolvedDir);
67501
- const planPath = path64.join(realPath, ".swarm", "plan.json");
67502
- if (!fs51.existsSync(planPath)) {
67653
+ const realPath = fs52.realpathSync(resolvedDir);
67654
+ const planPath = path65.join(realPath, ".swarm", "plan.json");
67655
+ if (!fs52.existsSync(planPath)) {
67503
67656
  return {
67504
67657
  success: false,
67505
67658
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -67532,8 +67685,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67532
67685
  recoverTaskStateFromDelegations(args2.task_id);
67533
67686
  let phaseRequiresReviewer = true;
67534
67687
  try {
67535
- const planPath = path64.join(directory, ".swarm", "plan.json");
67536
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67688
+ const planPath = path65.join(directory, ".swarm", "plan.json");
67689
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67537
67690
  const plan = JSON.parse(planRaw);
67538
67691
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
67539
67692
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -67596,8 +67749,8 @@ var update_task_status = createSwarmTool({
67596
67749
  init_tool();
67597
67750
  init_utils2();
67598
67751
  init_create_tool();
67599
- import fs52 from "fs";
67600
- import path65 from "path";
67752
+ import fs53 from "fs";
67753
+ import path66 from "path";
67601
67754
  function normalizeVerdict(verdict) {
67602
67755
  switch (verdict) {
67603
67756
  case "APPROVED":
@@ -67644,7 +67797,7 @@ async function executeWriteDriftEvidence(args2, directory) {
67644
67797
  entries: [evidenceEntry]
67645
67798
  };
67646
67799
  const filename = "drift-verifier.json";
67647
- const relativePath = path65.join("evidence", String(phase), filename);
67800
+ const relativePath = path66.join("evidence", String(phase), filename);
67648
67801
  let validatedPath;
67649
67802
  try {
67650
67803
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -67655,12 +67808,12 @@ async function executeWriteDriftEvidence(args2, directory) {
67655
67808
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
67656
67809
  }, null, 2);
67657
67810
  }
67658
- const evidenceDir = path65.dirname(validatedPath);
67811
+ const evidenceDir = path66.dirname(validatedPath);
67659
67812
  try {
67660
- await fs52.promises.mkdir(evidenceDir, { recursive: true });
67661
- const tempPath = path65.join(evidenceDir, `.${filename}.tmp`);
67662
- await fs52.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
67663
- await fs52.promises.rename(tempPath, validatedPath);
67813
+ await fs53.promises.mkdir(evidenceDir, { recursive: true });
67814
+ const tempPath = path66.join(evidenceDir, `.${filename}.tmp`);
67815
+ await fs53.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
67816
+ await fs53.promises.rename(tempPath, validatedPath);
67664
67817
  return JSON.stringify({
67665
67818
  success: true,
67666
67819
  phase,
@@ -67848,7 +68001,7 @@ var OpenCodeSwarm = async (ctx) => {
67848
68001
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
67849
68002
  preflightTriggerManager = new PTM(automationConfig);
67850
68003
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
67851
- const swarmDir = path66.resolve(ctx.directory, ".swarm");
68004
+ const swarmDir = path67.resolve(ctx.directory, ".swarm");
67852
68005
  statusArtifact = new ASA(swarmDir);
67853
68006
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
67854
68007
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {