opencode-swarm 6.41.2 → 6.41.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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,
@@ -55146,10 +55233,10 @@ function createSystemEnhancerHook(config3, directory) {
55146
55233
  });
55147
55234
  if (darkMatter && darkMatter.length > 0) {
55148
55235
  const darkMatterReport = formatDarkMatterOutput2(darkMatter);
55149
- await fs27.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55236
+ await fs28.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55150
55237
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
55151
55238
  try {
55152
- const projectName = path39.basename(path39.resolve(directory));
55239
+ const projectName = path40.basename(path40.resolve(directory));
55153
55240
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
55154
55241
  const knowledgePath = resolveSwarmKnowledgePath(directory);
55155
55242
  const existingEntries = await readKnowledge(knowledgePath);
@@ -55200,11 +55287,11 @@ function createSystemEnhancerHook(config3, directory) {
55200
55287
  if (handoffContent) {
55201
55288
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55202
55289
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55203
- if (fs27.existsSync(consumedPath)) {
55290
+ if (fs28.existsSync(consumedPath)) {
55204
55291
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55205
- fs27.unlinkSync(consumedPath);
55292
+ fs28.unlinkSync(consumedPath);
55206
55293
  }
55207
- fs27.renameSync(handoffPath, consumedPath);
55294
+ fs28.renameSync(handoffPath, consumedPath);
55208
55295
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55209
55296
  The previous model's session ended. Here is your starting context:
55210
55297
 
@@ -55485,11 +55572,11 @@ ${budgetWarning}`);
55485
55572
  if (handoffContent) {
55486
55573
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55487
55574
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55488
- if (fs27.existsSync(consumedPath)) {
55575
+ if (fs28.existsSync(consumedPath)) {
55489
55576
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55490
- fs27.unlinkSync(consumedPath);
55577
+ fs28.unlinkSync(consumedPath);
55491
55578
  }
55492
- fs27.renameSync(handoffPath, consumedPath);
55579
+ fs28.renameSync(handoffPath, consumedPath);
55493
55580
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55494
55581
  The previous model's session ended. Here is your starting context:
55495
55582
 
@@ -56259,14 +56346,14 @@ function isReadTool(toolName) {
56259
56346
  }
56260
56347
 
56261
56348
  // src/hooks/incremental-verify.ts
56262
- import * as fs28 from "fs";
56263
- import * as path40 from "path";
56349
+ import * as fs29 from "fs";
56350
+ import * as path41 from "path";
56264
56351
 
56265
56352
  // src/hooks/spawn-helper.ts
56266
56353
  import { spawn } from "child_process";
56267
56354
  var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
56268
56355
  function spawnAsync(command, cwd, timeoutMs) {
56269
- return new Promise((resolve12) => {
56356
+ return new Promise((resolve13) => {
56270
56357
  try {
56271
56358
  const [rawCmd, ...args2] = command;
56272
56359
  const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
@@ -56310,24 +56397,24 @@ function spawnAsync(command, cwd, timeoutMs) {
56310
56397
  try {
56311
56398
  proc.kill();
56312
56399
  } catch {}
56313
- resolve12(null);
56400
+ resolve13(null);
56314
56401
  }, timeoutMs);
56315
56402
  proc.on("close", (code) => {
56316
56403
  if (done)
56317
56404
  return;
56318
56405
  done = true;
56319
56406
  clearTimeout(timer);
56320
- resolve12({ exitCode: code ?? 1, stdout, stderr });
56407
+ resolve13({ exitCode: code ?? 1, stdout, stderr });
56321
56408
  });
56322
56409
  proc.on("error", () => {
56323
56410
  if (done)
56324
56411
  return;
56325
56412
  done = true;
56326
56413
  clearTimeout(timer);
56327
- resolve12(null);
56414
+ resolve13(null);
56328
56415
  });
56329
56416
  } catch {
56330
- resolve12(null);
56417
+ resolve13(null);
56331
56418
  }
56332
56419
  });
56333
56420
  }
@@ -56335,21 +56422,21 @@ function spawnAsync(command, cwd, timeoutMs) {
56335
56422
  // src/hooks/incremental-verify.ts
56336
56423
  var emittedSkipAdvisories = new Set;
56337
56424
  function detectPackageManager(projectDir) {
56338
- if (fs28.existsSync(path40.join(projectDir, "bun.lockb")))
56425
+ if (fs29.existsSync(path41.join(projectDir, "bun.lockb")))
56339
56426
  return "bun";
56340
- if (fs28.existsSync(path40.join(projectDir, "pnpm-lock.yaml")))
56427
+ if (fs29.existsSync(path41.join(projectDir, "pnpm-lock.yaml")))
56341
56428
  return "pnpm";
56342
- if (fs28.existsSync(path40.join(projectDir, "yarn.lock")))
56429
+ if (fs29.existsSync(path41.join(projectDir, "yarn.lock")))
56343
56430
  return "yarn";
56344
- if (fs28.existsSync(path40.join(projectDir, "package-lock.json")))
56431
+ if (fs29.existsSync(path41.join(projectDir, "package-lock.json")))
56345
56432
  return "npm";
56346
56433
  return "bun";
56347
56434
  }
56348
56435
  function detectTypecheckCommand(projectDir) {
56349
- const pkgPath = path40.join(projectDir, "package.json");
56350
- if (fs28.existsSync(pkgPath)) {
56436
+ const pkgPath = path41.join(projectDir, "package.json");
56437
+ if (fs29.existsSync(pkgPath)) {
56351
56438
  try {
56352
- const pkg = JSON.parse(fs28.readFileSync(pkgPath, "utf8"));
56439
+ const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
56353
56440
  const scripts = pkg.scripts;
56354
56441
  if (scripts?.typecheck) {
56355
56442
  const pm = detectPackageManager(projectDir);
@@ -56363,8 +56450,8 @@ function detectTypecheckCommand(projectDir) {
56363
56450
  ...pkg.dependencies,
56364
56451
  ...pkg.devDependencies
56365
56452
  };
56366
- if (!deps?.typescript && !fs28.existsSync(path40.join(projectDir, "tsconfig.json"))) {}
56367
- const hasTSMarkers = deps?.typescript || fs28.existsSync(path40.join(projectDir, "tsconfig.json"));
56453
+ if (!deps?.typescript && !fs29.existsSync(path41.join(projectDir, "tsconfig.json"))) {}
56454
+ const hasTSMarkers = deps?.typescript || fs29.existsSync(path41.join(projectDir, "tsconfig.json"));
56368
56455
  if (hasTSMarkers) {
56369
56456
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
56370
56457
  }
@@ -56372,17 +56459,17 @@ function detectTypecheckCommand(projectDir) {
56372
56459
  return null;
56373
56460
  }
56374
56461
  }
56375
- if (fs28.existsSync(path40.join(projectDir, "go.mod"))) {
56462
+ if (fs29.existsSync(path41.join(projectDir, "go.mod"))) {
56376
56463
  return { command: ["go", "vet", "./..."], language: "go" };
56377
56464
  }
56378
- if (fs28.existsSync(path40.join(projectDir, "Cargo.toml"))) {
56465
+ if (fs29.existsSync(path41.join(projectDir, "Cargo.toml"))) {
56379
56466
  return { command: ["cargo", "check"], language: "rust" };
56380
56467
  }
56381
- if (fs28.existsSync(path40.join(projectDir, "pyproject.toml")) || fs28.existsSync(path40.join(projectDir, "requirements.txt")) || fs28.existsSync(path40.join(projectDir, "setup.py"))) {
56468
+ if (fs29.existsSync(path41.join(projectDir, "pyproject.toml")) || fs29.existsSync(path41.join(projectDir, "requirements.txt")) || fs29.existsSync(path41.join(projectDir, "setup.py"))) {
56382
56469
  return { command: null, language: "python" };
56383
56470
  }
56384
56471
  try {
56385
- const entries = fs28.readdirSync(projectDir);
56472
+ const entries = fs29.readdirSync(projectDir);
56386
56473
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
56387
56474
  return {
56388
56475
  command: ["dotnet", "build", "--no-restore"],
@@ -56691,7 +56778,7 @@ ${injectionText}`;
56691
56778
  // src/hooks/scope-guard.ts
56692
56779
  init_constants();
56693
56780
  init_schema();
56694
- import * as path42 from "path";
56781
+ import * as path43 from "path";
56695
56782
  var WRITE_TOOLS = new Set([
56696
56783
  "write",
56697
56784
  "edit",
@@ -56753,13 +56840,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
56753
56840
  }
56754
56841
  function isFileInScope(filePath, scopeEntries, directory) {
56755
56842
  const dir = directory ?? process.cwd();
56756
- const resolvedFile = path42.resolve(dir, filePath);
56843
+ const resolvedFile = path43.resolve(dir, filePath);
56757
56844
  return scopeEntries.some((scope) => {
56758
- const resolvedScope = path42.resolve(dir, scope);
56845
+ const resolvedScope = path43.resolve(dir, scope);
56759
56846
  if (resolvedFile === resolvedScope)
56760
56847
  return true;
56761
- const rel = path42.relative(resolvedScope, resolvedFile);
56762
- return rel.length > 0 && !rel.startsWith("..") && !path42.isAbsolute(rel);
56848
+ const rel = path43.relative(resolvedScope, resolvedFile);
56849
+ return rel.length > 0 && !rel.startsWith("..") && !path43.isAbsolute(rel);
56763
56850
  });
56764
56851
  }
56765
56852
 
@@ -56808,8 +56895,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
56808
56895
  }
56809
56896
 
56810
56897
  // src/hooks/slop-detector.ts
56811
- import * as fs30 from "fs";
56812
- import * as path43 from "path";
56898
+ import * as fs31 from "fs";
56899
+ import * as path44 from "path";
56813
56900
  var WRITE_EDIT_TOOLS = new Set([
56814
56901
  "write",
56815
56902
  "edit",
@@ -56854,12 +56941,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
56854
56941
  function walkFiles(dir, exts, deadline) {
56855
56942
  const results = [];
56856
56943
  try {
56857
- for (const entry of fs30.readdirSync(dir, { withFileTypes: true })) {
56944
+ for (const entry of fs31.readdirSync(dir, { withFileTypes: true })) {
56858
56945
  if (deadline !== undefined && Date.now() > deadline)
56859
56946
  break;
56860
56947
  if (entry.isSymbolicLink())
56861
56948
  continue;
56862
- const full = path43.join(dir, entry.name);
56949
+ const full = path44.join(dir, entry.name);
56863
56950
  if (entry.isDirectory()) {
56864
56951
  if (entry.name === "node_modules" || entry.name === ".git")
56865
56952
  continue;
@@ -56874,7 +56961,7 @@ function walkFiles(dir, exts, deadline) {
56874
56961
  return results;
56875
56962
  }
56876
56963
  function checkDeadExports(content, projectDir, startTime) {
56877
- const hasPackageJson = fs30.existsSync(path43.join(projectDir, "package.json"));
56964
+ const hasPackageJson = fs31.existsSync(path44.join(projectDir, "package.json"));
56878
56965
  if (!hasPackageJson)
56879
56966
  return null;
56880
56967
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -56897,7 +56984,7 @@ function checkDeadExports(content, projectDir, startTime) {
56897
56984
  if (found || Date.now() - startTime > 480)
56898
56985
  break;
56899
56986
  try {
56900
- const text = fs30.readFileSync(file3, "utf-8");
56987
+ const text = fs31.readFileSync(file3, "utf-8");
56901
56988
  if (importPattern.test(text))
56902
56989
  found = true;
56903
56990
  importPattern.lastIndex = 0;
@@ -57030,7 +57117,7 @@ Review before proceeding.`;
57030
57117
 
57031
57118
  // src/hooks/steering-consumed.ts
57032
57119
  init_utils2();
57033
- import * as fs31 from "fs";
57120
+ import * as fs32 from "fs";
57034
57121
  function recordSteeringConsumed(directory, directiveId) {
57035
57122
  try {
57036
57123
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -57039,7 +57126,7 @@ function recordSteeringConsumed(directory, directiveId) {
57039
57126
  directiveId,
57040
57127
  timestamp: new Date().toISOString()
57041
57128
  };
57042
- fs31.appendFileSync(eventsPath, `${JSON.stringify(event)}
57129
+ fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
57043
57130
  `, "utf-8");
57044
57131
  } catch {}
57045
57132
  }
@@ -57329,21 +57416,24 @@ async function executeCommand(command) {
57329
57416
  cmd = ["/bin/sh"];
57330
57417
  args2 = ["-c", command.command];
57331
57418
  }
57332
- const result = await Bun.spawn({
57419
+ const result = Bun.spawn({
57333
57420
  cmd: [...cmd, ...args2],
57334
57421
  cwd: command.cwd,
57335
57422
  stdout: "pipe",
57336
57423
  stderr: "pipe",
57337
57424
  timeout: DEFAULT_TIMEOUT_MS2
57338
57425
  });
57426
+ const [exitCode, stdout, stderr] = await Promise.all([
57427
+ result.exited,
57428
+ new Response(result.stdout).text(),
57429
+ new Response(result.stderr).text()
57430
+ ]);
57339
57431
  const duration_ms = Date.now() - startTime;
57340
- const stdout = await new Response(result.stdout).text();
57341
- const stderr = await new Response(result.stderr).text();
57342
57432
  return {
57343
57433
  kind,
57344
57434
  command: command.command,
57345
57435
  cwd: command.cwd,
57346
- exit_code: result.exitCode ?? -1,
57436
+ exit_code: exitCode ?? -1,
57347
57437
  duration_ms,
57348
57438
  stdout_tail: truncateOutput(stdout),
57349
57439
  stderr_tail: truncateOutput(stderr)
@@ -57448,8 +57538,9 @@ var build_check = createSwarmTool({
57448
57538
  init_dist();
57449
57539
  init_manager();
57450
57540
  init_create_tool();
57451
- import * as fs32 from "fs";
57452
- import * as path44 from "path";
57541
+ init_resolve_working_directory();
57542
+ import * as fs33 from "fs";
57543
+ import * as path45 from "path";
57453
57544
  var EVIDENCE_DIR = ".swarm/evidence";
57454
57545
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
57455
57546
  function isValidTaskId3(taskId) {
@@ -57466,18 +57557,18 @@ function isValidTaskId3(taskId) {
57466
57557
  return TASK_ID_PATTERN2.test(taskId);
57467
57558
  }
57468
57559
  function isPathWithinSwarm(filePath, workspaceRoot) {
57469
- const normalizedWorkspace = path44.resolve(workspaceRoot);
57470
- const swarmPath = path44.join(normalizedWorkspace, ".swarm", "evidence");
57471
- const normalizedPath = path44.resolve(filePath);
57560
+ const normalizedWorkspace = path45.resolve(workspaceRoot);
57561
+ const swarmPath = path45.join(normalizedWorkspace, ".swarm", "evidence");
57562
+ const normalizedPath = path45.resolve(filePath);
57472
57563
  return normalizedPath.startsWith(swarmPath);
57473
57564
  }
57474
57565
  function readEvidenceFile(evidencePath) {
57475
- if (!fs32.existsSync(evidencePath)) {
57566
+ if (!fs33.existsSync(evidencePath)) {
57476
57567
  return null;
57477
57568
  }
57478
57569
  let content;
57479
57570
  try {
57480
- content = fs32.readFileSync(evidencePath, "utf-8");
57571
+ content = fs33.readFileSync(evidencePath, "utf-8");
57481
57572
  } catch {
57482
57573
  return null;
57483
57574
  }
@@ -57495,16 +57586,34 @@ function readEvidenceFile(evidencePath) {
57495
57586
  var check_gate_status = createSwarmTool({
57496
57587
  description: "Read-only tool to check the gate status of a specific task. Reads .swarm/evidence/{taskId}.json and returns structured JSON describing required, passed, and missing gates.",
57497
57588
  args: {
57498
- task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")')
57589
+ task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")'),
57590
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/evidence/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
57499
57591
  },
57500
57592
  async execute(args2, directory) {
57501
57593
  let taskIdInput;
57594
+ let workingDirInput;
57502
57595
  try {
57503
57596
  if (args2 && typeof args2 === "object") {
57504
57597
  const obj = args2;
57505
57598
  taskIdInput = typeof obj.task_id === "string" ? obj.task_id : undefined;
57599
+ workingDirInput = typeof obj.working_directory === "string" ? obj.working_directory : undefined;
57506
57600
  }
57507
57601
  } catch {}
57602
+ const dirResult = resolveWorkingDirectory(workingDirInput, directory);
57603
+ if (!dirResult.success) {
57604
+ const errorResult = {
57605
+ taskId: taskIdInput ?? "",
57606
+ status: "no_evidence",
57607
+ required_gates: [],
57608
+ passed_gates: [],
57609
+ missing_gates: [],
57610
+ gates: {},
57611
+ message: dirResult.message,
57612
+ todo_scan: null
57613
+ };
57614
+ return JSON.stringify(errorResult, null, 2);
57615
+ }
57616
+ directory = dirResult.directory;
57508
57617
  if (!taskIdInput) {
57509
57618
  const errorResult = {
57510
57619
  taskId: "",
@@ -57531,7 +57640,7 @@ var check_gate_status = createSwarmTool({
57531
57640
  };
57532
57641
  return JSON.stringify(errorResult, null, 2);
57533
57642
  }
57534
- const evidencePath = path44.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57643
+ const evidencePath = path45.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57535
57644
  if (!isPathWithinSwarm(evidencePath, directory)) {
57536
57645
  const errorResult = {
57537
57646
  taskId: taskIdInput,
@@ -57624,9 +57733,10 @@ init_co_change_analyzer();
57624
57733
  // src/tools/completion-verify.ts
57625
57734
  init_dist();
57626
57735
  init_utils2();
57627
- import * as fs33 from "fs";
57628
- import * as path45 from "path";
57736
+ import * as fs34 from "fs";
57737
+ import * as path46 from "path";
57629
57738
  init_create_tool();
57739
+ init_resolve_working_directory();
57630
57740
  function extractMatches(regex, text) {
57631
57741
  return Array.from(text.matchAll(regex));
57632
57742
  }
@@ -57720,7 +57830,7 @@ async function executeCompletionVerify(args2, directory) {
57720
57830
  let plan;
57721
57831
  try {
57722
57832
  const planPath = validateSwarmPath(directory, "plan.json");
57723
- const planRaw = fs33.readFileSync(planPath, "utf-8");
57833
+ const planRaw = fs34.readFileSync(planPath, "utf-8");
57724
57834
  plan = JSON.parse(planRaw);
57725
57835
  } catch {
57726
57836
  const result2 = {
@@ -57778,10 +57888,10 @@ async function executeCompletionVerify(args2, directory) {
57778
57888
  let hasFileReadFailure = false;
57779
57889
  for (const filePath of fileTargets) {
57780
57890
  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);
57891
+ const resolvedPath = path46.resolve(directory, normalizedPath);
57892
+ const projectRoot = path46.resolve(directory);
57893
+ const relative6 = path46.relative(projectRoot, resolvedPath);
57894
+ const withinProject = relative6 === "" || !relative6.startsWith("..") && !path46.isAbsolute(relative6);
57785
57895
  if (!withinProject) {
57786
57896
  blockedTasks.push({
57787
57897
  task_id: task.id,
@@ -57794,7 +57904,7 @@ async function executeCompletionVerify(args2, directory) {
57794
57904
  }
57795
57905
  let fileContent;
57796
57906
  try {
57797
- fileContent = fs33.readFileSync(resolvedPath, "utf-8");
57907
+ fileContent = fs34.readFileSync(resolvedPath, "utf-8");
57798
57908
  } catch {
57799
57909
  blockedTasks.push({
57800
57910
  task_id: task.id,
@@ -57836,9 +57946,9 @@ async function executeCompletionVerify(args2, directory) {
57836
57946
  blockedTasks
57837
57947
  };
57838
57948
  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 });
57949
+ const evidenceDir = path46.join(directory, ".swarm", "evidence", `${phase}`);
57950
+ const evidencePath = path46.join(evidenceDir, "completion-verify.json");
57951
+ fs34.mkdirSync(evidenceDir, { recursive: true });
57842
57952
  const evidenceBundle = {
57843
57953
  schema_version: "1.0.0",
57844
57954
  task_id: "completion-verify",
@@ -57859,7 +57969,7 @@ async function executeCompletionVerify(args2, directory) {
57859
57969
  }
57860
57970
  ]
57861
57971
  };
57862
- fs33.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57972
+ fs34.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57863
57973
  } catch {}
57864
57974
  return JSON.stringify(result, null, 2);
57865
57975
  }
@@ -57867,7 +57977,8 @@ var completion_verify = createSwarmTool({
57867
57977
  description: "Deterministic pre-check verifying that plan task identifiers exist in their target source files before phase completion. Blocks if obviously incomplete.",
57868
57978
  args: {
57869
57979
  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)")
57980
+ sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
57981
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
57871
57982
  },
57872
57983
  execute: async (args2, directory) => {
57873
57984
  let parsedArgs;
@@ -57876,7 +57987,8 @@ var completion_verify = createSwarmTool({
57876
57987
  const obj = args2;
57877
57988
  parsedArgs = {
57878
57989
  phase: typeof obj.phase === "number" ? obj.phase : typeof obj.phase === "string" ? Number(obj.phase) : 0,
57879
- sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined
57990
+ sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined,
57991
+ working_directory: typeof obj.working_directory === "string" ? obj.working_directory : undefined
57880
57992
  };
57881
57993
  } else {
57882
57994
  parsedArgs = { phase: 0 };
@@ -57893,17 +58005,30 @@ var completion_verify = createSwarmTool({
57893
58005
  blockedTasks: []
57894
58006
  }, null, 2);
57895
58007
  }
57896
- return executeCompletionVerify(parsedArgs, directory);
58008
+ const dirResult = resolveWorkingDirectory(parsedArgs.working_directory, directory);
58009
+ if (!dirResult.success) {
58010
+ return JSON.stringify({
58011
+ success: false,
58012
+ phase: parsedArgs.phase,
58013
+ status: "blocked",
58014
+ reason: dirResult.message,
58015
+ tasksChecked: 0,
58016
+ tasksSkipped: 0,
58017
+ tasksBlocked: 0,
58018
+ blockedTasks: []
58019
+ }, null, 2);
58020
+ }
58021
+ return executeCompletionVerify(parsedArgs, dirResult.directory);
57897
58022
  }
57898
58023
  });
57899
58024
  // src/tools/complexity-hotspots.ts
57900
58025
  init_dist();
57901
- import * as fs35 from "fs";
57902
- import * as path47 from "path";
58026
+ import * as fs36 from "fs";
58027
+ import * as path48 from "path";
57903
58028
 
57904
58029
  // src/quality/metrics.ts
57905
- import * as fs34 from "fs";
57906
- import * as path46 from "path";
58030
+ import * as fs35 from "fs";
58031
+ import * as path47 from "path";
57907
58032
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
57908
58033
  var MIN_DUPLICATION_LINES = 10;
57909
58034
  function estimateCyclomaticComplexity(content) {
@@ -57941,11 +58066,11 @@ function estimateCyclomaticComplexity(content) {
57941
58066
  }
57942
58067
  function getComplexityForFile(filePath) {
57943
58068
  try {
57944
- const stat2 = fs34.statSync(filePath);
58069
+ const stat2 = fs35.statSync(filePath);
57945
58070
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
57946
58071
  return null;
57947
58072
  }
57948
- const content = fs34.readFileSync(filePath, "utf-8");
58073
+ const content = fs35.readFileSync(filePath, "utf-8");
57949
58074
  return estimateCyclomaticComplexity(content);
57950
58075
  } catch {
57951
58076
  return null;
@@ -57955,8 +58080,8 @@ async function computeComplexityDelta(files, workingDir) {
57955
58080
  let totalComplexity = 0;
57956
58081
  const analyzedFiles = [];
57957
58082
  for (const file3 of files) {
57958
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
57959
- if (!fs34.existsSync(fullPath)) {
58083
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58084
+ if (!fs35.existsSync(fullPath)) {
57960
58085
  continue;
57961
58086
  }
57962
58087
  const complexity = getComplexityForFile(fullPath);
@@ -58077,8 +58202,8 @@ function countGoExports(content) {
58077
58202
  }
58078
58203
  function getExportCountForFile(filePath) {
58079
58204
  try {
58080
- const content = fs34.readFileSync(filePath, "utf-8");
58081
- const ext = path46.extname(filePath).toLowerCase();
58205
+ const content = fs35.readFileSync(filePath, "utf-8");
58206
+ const ext = path47.extname(filePath).toLowerCase();
58082
58207
  switch (ext) {
58083
58208
  case ".ts":
58084
58209
  case ".tsx":
@@ -58104,8 +58229,8 @@ async function computePublicApiDelta(files, workingDir) {
58104
58229
  let totalExports = 0;
58105
58230
  const analyzedFiles = [];
58106
58231
  for (const file3 of files) {
58107
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
58108
- if (!fs34.existsSync(fullPath)) {
58232
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58233
+ if (!fs35.existsSync(fullPath)) {
58109
58234
  continue;
58110
58235
  }
58111
58236
  const exports = getExportCountForFile(fullPath);
@@ -58138,16 +58263,16 @@ async function computeDuplicationRatio(files, workingDir) {
58138
58263
  let duplicateLines = 0;
58139
58264
  const analyzedFiles = [];
58140
58265
  for (const file3 of files) {
58141
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
58142
- if (!fs34.existsSync(fullPath)) {
58266
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58267
+ if (!fs35.existsSync(fullPath)) {
58143
58268
  continue;
58144
58269
  }
58145
58270
  try {
58146
- const stat2 = fs34.statSync(fullPath);
58271
+ const stat2 = fs35.statSync(fullPath);
58147
58272
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58148
58273
  continue;
58149
58274
  }
58150
- const content = fs34.readFileSync(fullPath, "utf-8");
58275
+ const content = fs35.readFileSync(fullPath, "utf-8");
58151
58276
  const lines = content.split(`
58152
58277
  `).filter((line) => line.trim().length > 0);
58153
58278
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -58171,8 +58296,8 @@ function countCodeLines(content) {
58171
58296
  return lines.length;
58172
58297
  }
58173
58298
  function isTestFile(filePath) {
58174
- const basename7 = path46.basename(filePath);
58175
- const _ext = path46.extname(filePath).toLowerCase();
58299
+ const basename7 = path47.basename(filePath);
58300
+ const _ext = path47.extname(filePath).toLowerCase();
58176
58301
  const testPatterns = [
58177
58302
  ".test.",
58178
58303
  ".spec.",
@@ -58253,8 +58378,8 @@ function matchGlobSegment(globSegments, pathSegments) {
58253
58378
  }
58254
58379
  return gIndex === globSegments.length && pIndex === pathSegments.length;
58255
58380
  }
58256
- function matchesGlobSegment(path47, glob) {
58257
- const normalizedPath = path47.replace(/\\/g, "/");
58381
+ function matchesGlobSegment(path48, glob) {
58382
+ const normalizedPath = path48.replace(/\\/g, "/");
58258
58383
  const normalizedGlob = glob.replace(/\\/g, "/");
58259
58384
  if (normalizedPath.includes("//")) {
58260
58385
  return false;
@@ -58285,8 +58410,8 @@ function simpleGlobToRegex2(glob) {
58285
58410
  function hasGlobstar(glob) {
58286
58411
  return glob.includes("**");
58287
58412
  }
58288
- function globMatches(path47, glob) {
58289
- const normalizedPath = path47.replace(/\\/g, "/");
58413
+ function globMatches(path48, glob) {
58414
+ const normalizedPath = path48.replace(/\\/g, "/");
58290
58415
  if (!glob || glob === "") {
58291
58416
  if (normalizedPath.includes("//")) {
58292
58417
  return false;
@@ -58322,31 +58447,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
58322
58447
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58323
58448
  let testLines = 0;
58324
58449
  let codeLines = 0;
58325
- const srcDir = path46.join(workingDir, "src");
58326
- if (fs34.existsSync(srcDir)) {
58450
+ const srcDir = path47.join(workingDir, "src");
58451
+ if (fs35.existsSync(srcDir)) {
58327
58452
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
58328
58453
  codeLines += lines;
58329
58454
  });
58330
58455
  }
58331
58456
  const possibleSrcDirs = ["lib", "app", "source", "core"];
58332
58457
  for (const dir of possibleSrcDirs) {
58333
- const dirPath = path46.join(workingDir, dir);
58334
- if (fs34.existsSync(dirPath)) {
58458
+ const dirPath = path47.join(workingDir, dir);
58459
+ if (fs35.existsSync(dirPath)) {
58335
58460
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
58336
58461
  codeLines += lines;
58337
58462
  });
58338
58463
  }
58339
58464
  }
58340
- const testsDir = path46.join(workingDir, "tests");
58341
- if (fs34.existsSync(testsDir)) {
58465
+ const testsDir = path47.join(workingDir, "tests");
58466
+ if (fs35.existsSync(testsDir)) {
58342
58467
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
58343
58468
  testLines += lines;
58344
58469
  });
58345
58470
  }
58346
58471
  const possibleTestDirs = ["test", "__tests__", "specs"];
58347
58472
  for (const dir of possibleTestDirs) {
58348
- const dirPath = path46.join(workingDir, dir);
58349
- if (fs34.existsSync(dirPath) && dirPath !== testsDir) {
58473
+ const dirPath = path47.join(workingDir, dir);
58474
+ if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
58350
58475
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
58351
58476
  testLines += lines;
58352
58477
  });
@@ -58358,9 +58483,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58358
58483
  }
58359
58484
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
58360
58485
  try {
58361
- const entries = fs34.readdirSync(dirPath, { withFileTypes: true });
58486
+ const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
58362
58487
  for (const entry of entries) {
58363
- const fullPath = path46.join(dirPath, entry.name);
58488
+ const fullPath = path47.join(dirPath, entry.name);
58364
58489
  if (entry.isDirectory()) {
58365
58490
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
58366
58491
  continue;
@@ -58368,7 +58493,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58368
58493
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
58369
58494
  } else if (entry.isFile()) {
58370
58495
  const relativePath = fullPath.replace(`${dirPath}/`, "");
58371
- const ext = path46.extname(entry.name).toLowerCase();
58496
+ const ext = path47.extname(entry.name).toLowerCase();
58372
58497
  const validExts = [
58373
58498
  ".ts",
58374
58499
  ".tsx",
@@ -58404,7 +58529,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58404
58529
  continue;
58405
58530
  }
58406
58531
  try {
58407
- const content = fs34.readFileSync(fullPath, "utf-8");
58532
+ const content = fs35.readFileSync(fullPath, "utf-8");
58408
58533
  const lines = countCodeLines(content);
58409
58534
  callback(lines);
58410
58535
  } catch {}
@@ -58583,8 +58708,10 @@ async function getGitChurn(days, directory) {
58583
58708
  stderr: "pipe",
58584
58709
  cwd: directory
58585
58710
  });
58586
- const stdout = await new Response(proc.stdout).text();
58587
- await proc.exited;
58711
+ const [stdout] = await Promise.all([
58712
+ new Response(proc.stdout).text(),
58713
+ proc.exited
58714
+ ]);
58588
58715
  const lines = stdout.split(/\r?\n/);
58589
58716
  for (const line of lines) {
58590
58717
  const normalizedPath = line.replace(/\\/g, "/");
@@ -58603,11 +58730,11 @@ async function getGitChurn(days, directory) {
58603
58730
  }
58604
58731
  function getComplexityForFile2(filePath) {
58605
58732
  try {
58606
- const stat2 = fs35.statSync(filePath);
58733
+ const stat2 = fs36.statSync(filePath);
58607
58734
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
58608
58735
  return null;
58609
58736
  }
58610
- const content = fs35.readFileSync(filePath, "utf-8");
58737
+ const content = fs36.readFileSync(filePath, "utf-8");
58611
58738
  return estimateCyclomaticComplexity(content);
58612
58739
  } catch {
58613
58740
  return null;
@@ -58618,7 +58745,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58618
58745
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
58619
58746
  const filteredChurn = new Map;
58620
58747
  for (const [file3, count] of churnMap) {
58621
- const ext = path47.extname(file3).toLowerCase();
58748
+ const ext = path48.extname(file3).toLowerCase();
58622
58749
  if (extSet.has(ext)) {
58623
58750
  filteredChurn.set(file3, count);
58624
58751
  }
@@ -58628,8 +58755,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58628
58755
  let analyzedFiles = 0;
58629
58756
  for (const [file3, churnCount] of filteredChurn) {
58630
58757
  let fullPath = file3;
58631
- if (!fs35.existsSync(fullPath)) {
58632
- fullPath = path47.join(cwd, file3);
58758
+ if (!fs36.existsSync(fullPath)) {
58759
+ fullPath = path48.join(cwd, file3);
58633
58760
  }
58634
58761
  const complexity = getComplexityForFile2(fullPath);
58635
58762
  if (complexity !== null) {
@@ -58837,8 +58964,8 @@ var curator_analyze = createSwarmTool({
58837
58964
  });
58838
58965
  // src/tools/declare-scope.ts
58839
58966
  init_tool();
58840
- import * as fs36 from "fs";
58841
- import * as path48 from "path";
58967
+ import * as fs37 from "fs";
58968
+ import * as path49 from "path";
58842
58969
  init_create_tool();
58843
58970
  function validateTaskIdFormat(taskId) {
58844
58971
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -58917,8 +59044,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58917
59044
  };
58918
59045
  }
58919
59046
  }
58920
- normalizedDir = path48.normalize(args2.working_directory);
58921
- const pathParts = normalizedDir.split(path48.sep);
59047
+ normalizedDir = path49.normalize(args2.working_directory);
59048
+ const pathParts = normalizedDir.split(path49.sep);
58922
59049
  if (pathParts.includes("..")) {
58923
59050
  return {
58924
59051
  success: false,
@@ -58928,11 +59055,11 @@ async function executeDeclareScope(args2, fallbackDir) {
58928
59055
  ]
58929
59056
  };
58930
59057
  }
58931
- const resolvedDir = path48.resolve(normalizedDir);
59058
+ const resolvedDir = path49.resolve(normalizedDir);
58932
59059
  try {
58933
- const realPath = fs36.realpathSync(resolvedDir);
58934
- const planPath2 = path48.join(realPath, ".swarm", "plan.json");
58935
- if (!fs36.existsSync(planPath2)) {
59060
+ const realPath = fs37.realpathSync(resolvedDir);
59061
+ const planPath2 = path49.join(realPath, ".swarm", "plan.json");
59062
+ if (!fs37.existsSync(planPath2)) {
58936
59063
  return {
58937
59064
  success: false,
58938
59065
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -58955,8 +59082,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58955
59082
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
58956
59083
  }
58957
59084
  const directory = normalizedDir || fallbackDir;
58958
- const planPath = path48.resolve(directory, ".swarm", "plan.json");
58959
- if (!fs36.existsSync(planPath)) {
59085
+ const planPath = path49.resolve(directory, ".swarm", "plan.json");
59086
+ if (!fs37.existsSync(planPath)) {
58960
59087
  return {
58961
59088
  success: false,
58962
59089
  message: "No plan found",
@@ -58965,7 +59092,7 @@ async function executeDeclareScope(args2, fallbackDir) {
58965
59092
  }
58966
59093
  let planContent;
58967
59094
  try {
58968
- planContent = JSON.parse(fs36.readFileSync(planPath, "utf-8"));
59095
+ planContent = JSON.parse(fs37.readFileSync(planPath, "utf-8"));
58969
59096
  } catch {
58970
59097
  return {
58971
59098
  success: false,
@@ -58997,8 +59124,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58997
59124
  const normalizeErrors = [];
58998
59125
  const dir = normalizedDir || fallbackDir || process.cwd();
58999
59126
  const mergedFiles = rawMergedFiles.map((file3) => {
59000
- if (path48.isAbsolute(file3)) {
59001
- const relativePath = path48.relative(dir, file3).replace(/\\/g, "/");
59127
+ if (path49.isAbsolute(file3)) {
59128
+ const relativePath = path49.relative(dir, file3).replace(/\\/g, "/");
59002
59129
  if (relativePath.startsWith("..")) {
59003
59130
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
59004
59131
  return file3;
@@ -59324,20 +59451,20 @@ function validateBase(base) {
59324
59451
  function validatePaths(paths) {
59325
59452
  if (!paths)
59326
59453
  return null;
59327
- for (const path50 of paths) {
59328
- if (!path50 || path50.length === 0) {
59454
+ for (const path51 of paths) {
59455
+ if (!path51 || path51.length === 0) {
59329
59456
  return "empty path not allowed";
59330
59457
  }
59331
- if (path50.length > MAX_PATH_LENGTH) {
59458
+ if (path51.length > MAX_PATH_LENGTH) {
59332
59459
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
59333
59460
  }
59334
- if (SHELL_METACHARACTERS2.test(path50)) {
59461
+ if (SHELL_METACHARACTERS2.test(path51)) {
59335
59462
  return "path contains shell metacharacters";
59336
59463
  }
59337
- if (path50.startsWith("-")) {
59464
+ if (path51.startsWith("-")) {
59338
59465
  return 'path cannot start with "-" (option-like arguments not allowed)';
59339
59466
  }
59340
- if (CONTROL_CHAR_PATTERN2.test(path50)) {
59467
+ if (CONTROL_CHAR_PATTERN2.test(path51)) {
59341
59468
  return "path contains control characters";
59342
59469
  }
59343
59470
  }
@@ -59418,8 +59545,8 @@ var diff = createSwarmTool({
59418
59545
  if (parts2.length >= 3) {
59419
59546
  const additions = parseInt(parts2[0], 10) || 0;
59420
59547
  const deletions = parseInt(parts2[1], 10) || 0;
59421
- const path50 = parts2[2];
59422
- files.push({ path: path50, additions, deletions });
59548
+ const path51 = parts2[2];
59549
+ files.push({ path: path51, additions, deletions });
59423
59550
  }
59424
59551
  }
59425
59552
  const contractChanges = [];
@@ -59701,8 +59828,8 @@ Use these as DOMAIN values when delegating to @sme.`;
59701
59828
  // src/tools/evidence-check.ts
59702
59829
  init_dist();
59703
59830
  init_create_tool();
59704
- import * as fs37 from "fs";
59705
- import * as path50 from "path";
59831
+ import * as fs38 from "fs";
59832
+ import * as path51 from "path";
59706
59833
  var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
59707
59834
  var MAX_EVIDENCE_FILES = 1000;
59708
59835
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -59729,9 +59856,9 @@ function validateRequiredTypes(input) {
59729
59856
  return null;
59730
59857
  }
59731
59858
  function isPathWithinSwarm2(filePath, cwd) {
59732
- const normalizedCwd = path50.resolve(cwd);
59733
- const swarmPath = path50.join(normalizedCwd, ".swarm");
59734
- const normalizedPath = path50.resolve(filePath);
59859
+ const normalizedCwd = path51.resolve(cwd);
59860
+ const swarmPath = path51.join(normalizedCwd, ".swarm");
59861
+ const normalizedPath = path51.resolve(filePath);
59735
59862
  return normalizedPath.startsWith(swarmPath);
59736
59863
  }
59737
59864
  function parseCompletedTasks(planContent) {
@@ -59747,12 +59874,12 @@ function parseCompletedTasks(planContent) {
59747
59874
  }
59748
59875
  function readEvidenceFiles(evidenceDir, _cwd) {
59749
59876
  const evidence = [];
59750
- if (!fs37.existsSync(evidenceDir) || !fs37.statSync(evidenceDir).isDirectory()) {
59877
+ if (!fs38.existsSync(evidenceDir) || !fs38.statSync(evidenceDir).isDirectory()) {
59751
59878
  return evidence;
59752
59879
  }
59753
59880
  let files;
59754
59881
  try {
59755
- files = fs37.readdirSync(evidenceDir);
59882
+ files = fs38.readdirSync(evidenceDir);
59756
59883
  } catch {
59757
59884
  return evidence;
59758
59885
  }
@@ -59761,14 +59888,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59761
59888
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
59762
59889
  continue;
59763
59890
  }
59764
- const filePath = path50.join(evidenceDir, filename);
59891
+ const filePath = path51.join(evidenceDir, filename);
59765
59892
  try {
59766
- const resolvedPath = path50.resolve(filePath);
59767
- const evidenceDirResolved = path50.resolve(evidenceDir);
59893
+ const resolvedPath = path51.resolve(filePath);
59894
+ const evidenceDirResolved = path51.resolve(evidenceDir);
59768
59895
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
59769
59896
  continue;
59770
59897
  }
59771
- const stat2 = fs37.lstatSync(filePath);
59898
+ const stat2 = fs38.lstatSync(filePath);
59772
59899
  if (!stat2.isFile()) {
59773
59900
  continue;
59774
59901
  }
@@ -59777,7 +59904,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59777
59904
  }
59778
59905
  let fileStat;
59779
59906
  try {
59780
- fileStat = fs37.statSync(filePath);
59907
+ fileStat = fs38.statSync(filePath);
59781
59908
  if (fileStat.size > MAX_FILE_SIZE_BYTES4) {
59782
59909
  continue;
59783
59910
  }
@@ -59786,7 +59913,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59786
59913
  }
59787
59914
  let content;
59788
59915
  try {
59789
- content = fs37.readFileSync(filePath, "utf-8");
59916
+ content = fs38.readFileSync(filePath, "utf-8");
59790
59917
  } catch {
59791
59918
  continue;
59792
59919
  }
@@ -59882,7 +60009,7 @@ var evidence_check = createSwarmTool({
59882
60009
  return JSON.stringify(errorResult, null, 2);
59883
60010
  }
59884
60011
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
59885
- const planPath = path50.join(cwd, PLAN_FILE);
60012
+ const planPath = path51.join(cwd, PLAN_FILE);
59886
60013
  if (!isPathWithinSwarm2(planPath, cwd)) {
59887
60014
  const errorResult = {
59888
60015
  error: "plan file path validation failed",
@@ -59896,7 +60023,7 @@ var evidence_check = createSwarmTool({
59896
60023
  }
59897
60024
  let planContent;
59898
60025
  try {
59899
- planContent = fs37.readFileSync(planPath, "utf-8");
60026
+ planContent = fs38.readFileSync(planPath, "utf-8");
59900
60027
  } catch {
59901
60028
  const result2 = {
59902
60029
  message: "No completed tasks found in plan.",
@@ -59914,7 +60041,7 @@ var evidence_check = createSwarmTool({
59914
60041
  };
59915
60042
  return JSON.stringify(result2, null, 2);
59916
60043
  }
59917
- const evidenceDir = path50.join(cwd, EVIDENCE_DIR2);
60044
+ const evidenceDir = path51.join(cwd, EVIDENCE_DIR2);
59918
60045
  const evidence = readEvidenceFiles(evidenceDir, cwd);
59919
60046
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
59920
60047
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -59931,8 +60058,8 @@ var evidence_check = createSwarmTool({
59931
60058
  // src/tools/file-extractor.ts
59932
60059
  init_tool();
59933
60060
  init_create_tool();
59934
- import * as fs38 from "fs";
59935
- import * as path51 from "path";
60061
+ import * as fs39 from "fs";
60062
+ import * as path52 from "path";
59936
60063
  var EXT_MAP = {
59937
60064
  python: ".py",
59938
60065
  py: ".py",
@@ -59994,8 +60121,8 @@ var extract_code_blocks = createSwarmTool({
59994
60121
  execute: async (args2, directory) => {
59995
60122
  const { content, output_dir, prefix } = args2;
59996
60123
  const targetDir = output_dir || directory;
59997
- if (!fs38.existsSync(targetDir)) {
59998
- fs38.mkdirSync(targetDir, { recursive: true });
60124
+ if (!fs39.existsSync(targetDir)) {
60125
+ fs39.mkdirSync(targetDir, { recursive: true });
59999
60126
  }
60000
60127
  if (!content) {
60001
60128
  return "Error: content is required";
@@ -60013,16 +60140,16 @@ var extract_code_blocks = createSwarmTool({
60013
60140
  if (prefix) {
60014
60141
  filename = `${prefix}_${filename}`;
60015
60142
  }
60016
- let filepath = path51.join(targetDir, filename);
60017
- const base = path51.basename(filepath, path51.extname(filepath));
60018
- const ext = path51.extname(filepath);
60143
+ let filepath = path52.join(targetDir, filename);
60144
+ const base = path52.basename(filepath, path52.extname(filepath));
60145
+ const ext = path52.extname(filepath);
60019
60146
  let counter = 1;
60020
- while (fs38.existsSync(filepath)) {
60021
- filepath = path51.join(targetDir, `${base}_${counter}${ext}`);
60147
+ while (fs39.existsSync(filepath)) {
60148
+ filepath = path52.join(targetDir, `${base}_${counter}${ext}`);
60022
60149
  counter++;
60023
60150
  }
60024
60151
  try {
60025
- fs38.writeFileSync(filepath, code.trim(), "utf-8");
60152
+ fs39.writeFileSync(filepath, code.trim(), "utf-8");
60026
60153
  savedFiles.push(filepath);
60027
60154
  } catch (error93) {
60028
60155
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -60052,7 +60179,7 @@ init_create_tool();
60052
60179
  var GITINGEST_TIMEOUT_MS = 1e4;
60053
60180
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
60054
60181
  var GITINGEST_MAX_RETRIES = 2;
60055
- var delay = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
60182
+ var delay = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms));
60056
60183
  async function fetchGitingest(args2) {
60057
60184
  for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
60058
60185
  try {
@@ -60138,8 +60265,8 @@ var gitingest = createSwarmTool({
60138
60265
  // src/tools/imports.ts
60139
60266
  init_dist();
60140
60267
  init_create_tool();
60141
- import * as fs39 from "fs";
60142
- import * as path52 from "path";
60268
+ import * as fs40 from "fs";
60269
+ import * as path53 from "path";
60143
60270
  var MAX_FILE_PATH_LENGTH2 = 500;
60144
60271
  var MAX_SYMBOL_LENGTH = 256;
60145
60272
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
@@ -60187,7 +60314,7 @@ function validateSymbolInput(symbol3) {
60187
60314
  return null;
60188
60315
  }
60189
60316
  function isBinaryFile2(filePath, buffer) {
60190
- const ext = path52.extname(filePath).toLowerCase();
60317
+ const ext = path53.extname(filePath).toLowerCase();
60191
60318
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
60192
60319
  return false;
60193
60320
  }
@@ -60211,15 +60338,15 @@ function parseImports(content, targetFile, targetSymbol) {
60211
60338
  const imports = [];
60212
60339
  let _resolvedTarget;
60213
60340
  try {
60214
- _resolvedTarget = path52.resolve(targetFile);
60341
+ _resolvedTarget = path53.resolve(targetFile);
60215
60342
  } catch {
60216
60343
  _resolvedTarget = targetFile;
60217
60344
  }
60218
- const targetBasename = path52.basename(targetFile, path52.extname(targetFile));
60345
+ const targetBasename = path53.basename(targetFile, path53.extname(targetFile));
60219
60346
  const targetWithExt = targetFile;
60220
60347
  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, "/");
60348
+ const normalizedTargetWithExt = path53.normalize(targetWithExt).replace(/\\/g, "/");
60349
+ const normalizedTargetWithoutExt = path53.normalize(targetWithoutExt).replace(/\\/g, "/");
60223
60350
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
60224
60351
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
60225
60352
  const modulePath = match[1] || match[2] || match[3];
@@ -60242,9 +60369,9 @@ function parseImports(content, targetFile, targetSymbol) {
60242
60369
  }
60243
60370
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
60244
60371
  let isMatch = false;
60245
- const _targetDir = path52.dirname(targetFile);
60246
- const targetExt = path52.extname(targetFile);
60247
- const targetBasenameNoExt = path52.basename(targetFile, targetExt);
60372
+ const _targetDir = path53.dirname(targetFile);
60373
+ const targetExt = path53.extname(targetFile);
60374
+ const targetBasenameNoExt = path53.basename(targetFile, targetExt);
60248
60375
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
60249
60376
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
60250
60377
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -60301,7 +60428,7 @@ var SKIP_DIRECTORIES3 = new Set([
60301
60428
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
60302
60429
  let entries;
60303
60430
  try {
60304
- entries = fs39.readdirSync(dir);
60431
+ entries = fs40.readdirSync(dir);
60305
60432
  } catch (e) {
60306
60433
  stats.fileErrors.push({
60307
60434
  path: dir,
@@ -60312,13 +60439,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60312
60439
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
60313
60440
  for (const entry of entries) {
60314
60441
  if (SKIP_DIRECTORIES3.has(entry)) {
60315
- stats.skippedDirs.push(path52.join(dir, entry));
60442
+ stats.skippedDirs.push(path53.join(dir, entry));
60316
60443
  continue;
60317
60444
  }
60318
- const fullPath = path52.join(dir, entry);
60445
+ const fullPath = path53.join(dir, entry);
60319
60446
  let stat2;
60320
60447
  try {
60321
- stat2 = fs39.statSync(fullPath);
60448
+ stat2 = fs40.statSync(fullPath);
60322
60449
  } catch (e) {
60323
60450
  stats.fileErrors.push({
60324
60451
  path: fullPath,
@@ -60329,7 +60456,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60329
60456
  if (stat2.isDirectory()) {
60330
60457
  findSourceFiles(fullPath, files, stats);
60331
60458
  } else if (stat2.isFile()) {
60332
- const ext = path52.extname(fullPath).toLowerCase();
60459
+ const ext = path53.extname(fullPath).toLowerCase();
60333
60460
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
60334
60461
  files.push(fullPath);
60335
60462
  }
@@ -60386,8 +60513,8 @@ var imports = createSwarmTool({
60386
60513
  return JSON.stringify(errorResult, null, 2);
60387
60514
  }
60388
60515
  try {
60389
- const targetFile = path52.resolve(file3);
60390
- if (!fs39.existsSync(targetFile)) {
60516
+ const targetFile = path53.resolve(file3);
60517
+ if (!fs40.existsSync(targetFile)) {
60391
60518
  const errorResult = {
60392
60519
  error: `target file not found: ${file3}`,
60393
60520
  target: file3,
@@ -60397,7 +60524,7 @@ var imports = createSwarmTool({
60397
60524
  };
60398
60525
  return JSON.stringify(errorResult, null, 2);
60399
60526
  }
60400
- const targetStat = fs39.statSync(targetFile);
60527
+ const targetStat = fs40.statSync(targetFile);
60401
60528
  if (!targetStat.isFile()) {
60402
60529
  const errorResult = {
60403
60530
  error: "target must be a file, not a directory",
@@ -60408,7 +60535,7 @@ var imports = createSwarmTool({
60408
60535
  };
60409
60536
  return JSON.stringify(errorResult, null, 2);
60410
60537
  }
60411
- const baseDir = path52.dirname(targetFile);
60538
+ const baseDir = path53.dirname(targetFile);
60412
60539
  const scanStats = {
60413
60540
  skippedDirs: [],
60414
60541
  skippedFiles: 0,
@@ -60423,12 +60550,12 @@ var imports = createSwarmTool({
60423
60550
  if (consumers.length >= MAX_CONSUMERS)
60424
60551
  break;
60425
60552
  try {
60426
- const stat2 = fs39.statSync(filePath);
60553
+ const stat2 = fs40.statSync(filePath);
60427
60554
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
60428
60555
  skippedFileCount++;
60429
60556
  continue;
60430
60557
  }
60431
- const buffer = fs39.readFileSync(filePath);
60558
+ const buffer = fs40.readFileSync(filePath);
60432
60559
  if (isBinaryFile2(filePath, buffer)) {
60433
60560
  skippedFileCount++;
60434
60561
  continue;
@@ -61017,11 +61144,12 @@ init_dist();
61017
61144
  init_config();
61018
61145
  init_schema();
61019
61146
  init_manager();
61020
- import * as fs40 from "fs";
61021
- import * as path53 from "path";
61147
+ import * as fs41 from "fs";
61148
+ import * as path54 from "path";
61022
61149
  init_utils2();
61023
61150
  init_telemetry();
61024
61151
  init_create_tool();
61152
+ init_resolve_working_directory();
61025
61153
  function safeWarn(message, error93) {
61026
61154
  try {
61027
61155
  console.warn(message, error93 instanceof Error ? error93.message : String(error93));
@@ -61238,11 +61366,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61238
61366
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
61239
61367
  }
61240
61368
  try {
61241
- const driftEvidencePath = path53.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61369
+ const driftEvidencePath = path54.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61242
61370
  let driftVerdictFound = false;
61243
61371
  let driftVerdictApproved = false;
61244
61372
  try {
61245
- const driftEvidenceContent = fs40.readFileSync(driftEvidencePath, "utf-8");
61373
+ const driftEvidenceContent = fs41.readFileSync(driftEvidencePath, "utf-8");
61246
61374
  const driftEvidence = JSON.parse(driftEvidenceContent);
61247
61375
  const entries = driftEvidence.entries ?? [];
61248
61376
  for (const entry of entries) {
@@ -61272,14 +61400,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61272
61400
  driftVerdictFound = false;
61273
61401
  }
61274
61402
  if (!driftVerdictFound) {
61275
- const specPath = path53.join(dir, ".swarm", "spec.md");
61276
- const specExists = fs40.existsSync(specPath);
61403
+ const specPath = path54.join(dir, ".swarm", "spec.md");
61404
+ const specExists = fs41.existsSync(specPath);
61277
61405
  if (!specExists) {
61278
61406
  let incompleteTaskCount = 0;
61279
61407
  let planPhaseFound = false;
61280
61408
  try {
61281
61409
  const planPath = validateSwarmPath(dir, "plan.json");
61282
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61410
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61283
61411
  const plan = JSON.parse(planRaw);
61284
61412
  const targetPhase = plan.phases.find((p) => p.id === phase);
61285
61413
  if (targetPhase) {
@@ -61346,7 +61474,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61346
61474
  };
61347
61475
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
61348
61476
  try {
61349
- const projectName = path53.basename(dir);
61477
+ const projectName = path54.basename(dir);
61350
61478
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
61351
61479
  if (curationResult) {
61352
61480
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -61391,7 +61519,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61391
61519
  let phaseRequiredAgents;
61392
61520
  try {
61393
61521
  const planPath = validateSwarmPath(dir, "plan.json");
61394
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61522
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61395
61523
  const plan = JSON.parse(planRaw);
61396
61524
  const phaseObj = plan.phases.find((p) => p.id === phase);
61397
61525
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -61406,7 +61534,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61406
61534
  if (agentsMissing.length > 0) {
61407
61535
  try {
61408
61536
  const planPath = validateSwarmPath(dir, "plan.json");
61409
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61537
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61410
61538
  const plan = JSON.parse(planRaw);
61411
61539
  const targetPhase = plan.phases.find((p) => p.id === phase);
61412
61540
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -61437,7 +61565,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61437
61565
  if (phaseCompleteConfig.regression_sweep?.enforce) {
61438
61566
  try {
61439
61567
  const planPath = validateSwarmPath(dir, "plan.json");
61440
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61568
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61441
61569
  const plan = JSON.parse(planRaw);
61442
61570
  const targetPhase = plan.phases.find((p) => p.id === phase);
61443
61571
  if (targetPhase) {
@@ -61475,7 +61603,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61475
61603
  };
61476
61604
  try {
61477
61605
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
61478
- fs40.appendFileSync(eventsPath, `${JSON.stringify(event)}
61606
+ fs41.appendFileSync(eventsPath, `${JSON.stringify(event)}
61479
61607
  `, "utf-8");
61480
61608
  } catch (writeError) {
61481
61609
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -61499,12 +61627,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61499
61627
  }
61500
61628
  try {
61501
61629
  const planPath = validateSwarmPath(dir, "plan.json");
61502
- const planJson = fs40.readFileSync(planPath, "utf-8");
61630
+ const planJson = fs41.readFileSync(planPath, "utf-8");
61503
61631
  const plan = JSON.parse(planJson);
61504
61632
  const phaseObj = plan.phases.find((p) => p.id === phase);
61505
61633
  if (phaseObj) {
61506
61634
  phaseObj.status = "completed";
61507
- fs40.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61635
+ fs41.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61508
61636
  `, "utf-8");
61509
61637
  }
61510
61638
  } catch (error93) {
@@ -61531,16 +61659,19 @@ var phase_complete = createSwarmTool({
61531
61659
  args: {
61532
61660
  phase: tool.schema.number().int().min(1).describe("The phase number being completed \u2014 a positive integer (e.g., 1, 2, 3)"),
61533
61661
  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)")
61662
+ sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
61663
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
61535
61664
  },
61536
61665
  execute: async (args2, directory, ctx) => {
61537
61666
  let phaseCompleteArgs;
61667
+ let workingDirInput;
61538
61668
  try {
61539
61669
  phaseCompleteArgs = {
61540
61670
  phase: Number(args2.phase),
61541
61671
  summary: args2.summary !== undefined ? String(args2.summary) : undefined,
61542
61672
  sessionID: ctx?.sessionID ?? (args2.sessionID !== undefined ? String(args2.sessionID) : undefined)
61543
61673
  };
61674
+ workingDirInput = args2.working_directory !== undefined ? String(args2.working_directory) : undefined;
61544
61675
  } catch {
61545
61676
  return JSON.stringify({
61546
61677
  success: false,
@@ -61550,7 +61681,17 @@ var phase_complete = createSwarmTool({
61550
61681
  warnings: ["Failed to parse arguments"]
61551
61682
  }, null, 2);
61552
61683
  }
61553
- return executePhaseComplete(phaseCompleteArgs, undefined, directory);
61684
+ const dirResult = resolveWorkingDirectory(workingDirInput, directory);
61685
+ if (!dirResult.success) {
61686
+ return JSON.stringify({
61687
+ success: false,
61688
+ phase: phaseCompleteArgs.phase,
61689
+ message: dirResult.message,
61690
+ agentsDispatched: [],
61691
+ warnings: [dirResult.message]
61692
+ }, null, 2);
61693
+ }
61694
+ return executePhaseComplete(phaseCompleteArgs, dirResult.directory, dirResult.directory);
61554
61695
  }
61555
61696
  });
61556
61697
  // src/tools/pkg-audit.ts
@@ -61558,8 +61699,8 @@ init_dist();
61558
61699
  init_discovery();
61559
61700
  init_utils();
61560
61701
  init_create_tool();
61561
- import * as fs41 from "fs";
61562
- import * as path54 from "path";
61702
+ import * as fs42 from "fs";
61703
+ import * as path55 from "path";
61563
61704
  var MAX_OUTPUT_BYTES5 = 52428800;
61564
61705
  var AUDIT_TIMEOUT_MS = 120000;
61565
61706
  function isValidEcosystem(value) {
@@ -61577,28 +61718,28 @@ function validateArgs3(args2) {
61577
61718
  function detectEcosystems(directory) {
61578
61719
  const ecosystems = [];
61579
61720
  const cwd = directory;
61580
- if (fs41.existsSync(path54.join(cwd, "package.json"))) {
61721
+ if (fs42.existsSync(path55.join(cwd, "package.json"))) {
61581
61722
  ecosystems.push("npm");
61582
61723
  }
61583
- if (fs41.existsSync(path54.join(cwd, "pyproject.toml")) || fs41.existsSync(path54.join(cwd, "requirements.txt"))) {
61724
+ if (fs42.existsSync(path55.join(cwd, "pyproject.toml")) || fs42.existsSync(path55.join(cwd, "requirements.txt"))) {
61584
61725
  ecosystems.push("pip");
61585
61726
  }
61586
- if (fs41.existsSync(path54.join(cwd, "Cargo.toml"))) {
61727
+ if (fs42.existsSync(path55.join(cwd, "Cargo.toml"))) {
61587
61728
  ecosystems.push("cargo");
61588
61729
  }
61589
- if (fs41.existsSync(path54.join(cwd, "go.mod"))) {
61730
+ if (fs42.existsSync(path55.join(cwd, "go.mod"))) {
61590
61731
  ecosystems.push("go");
61591
61732
  }
61592
61733
  try {
61593
- const files = fs41.readdirSync(cwd);
61734
+ const files = fs42.readdirSync(cwd);
61594
61735
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
61595
61736
  ecosystems.push("dotnet");
61596
61737
  }
61597
61738
  } catch {}
61598
- if (fs41.existsSync(path54.join(cwd, "Gemfile")) || fs41.existsSync(path54.join(cwd, "Gemfile.lock"))) {
61739
+ if (fs42.existsSync(path55.join(cwd, "Gemfile")) || fs42.existsSync(path55.join(cwd, "Gemfile.lock"))) {
61599
61740
  ecosystems.push("ruby");
61600
61741
  }
61601
- if (fs41.existsSync(path54.join(cwd, "pubspec.yaml"))) {
61742
+ if (fs42.existsSync(path55.join(cwd, "pubspec.yaml"))) {
61602
61743
  ecosystems.push("dart");
61603
61744
  }
61604
61745
  return ecosystems;
@@ -61611,7 +61752,7 @@ async function runNpmAudit(directory) {
61611
61752
  stderr: "pipe",
61612
61753
  cwd: directory
61613
61754
  });
61614
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
61755
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61615
61756
  const result = await Promise.race([
61616
61757
  Promise.all([
61617
61758
  new Response(proc.stdout).text(),
@@ -61734,7 +61875,7 @@ async function runPipAudit(directory) {
61734
61875
  stderr: "pipe",
61735
61876
  cwd: directory
61736
61877
  });
61737
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
61878
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61738
61879
  const result = await Promise.race([
61739
61880
  Promise.all([
61740
61881
  new Response(proc.stdout).text(),
@@ -61865,7 +62006,7 @@ async function runCargoAudit(directory) {
61865
62006
  stderr: "pipe",
61866
62007
  cwd: directory
61867
62008
  });
61868
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62009
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61869
62010
  const result = await Promise.race([
61870
62011
  Promise.all([
61871
62012
  new Response(proc.stdout).text(),
@@ -61992,7 +62133,7 @@ async function runGoAudit(directory) {
61992
62133
  stderr: "pipe",
61993
62134
  cwd: directory
61994
62135
  });
61995
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62136
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61996
62137
  const result = await Promise.race([
61997
62138
  Promise.all([
61998
62139
  new Response(proc.stdout).text(),
@@ -62128,7 +62269,7 @@ async function runDotnetAudit(directory) {
62128
62269
  stderr: "pipe",
62129
62270
  cwd: directory
62130
62271
  });
62131
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62272
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62132
62273
  const result = await Promise.race([
62133
62274
  Promise.all([
62134
62275
  new Response(proc.stdout).text(),
@@ -62247,7 +62388,7 @@ async function runBundleAudit(directory) {
62247
62388
  stderr: "pipe",
62248
62389
  cwd: directory
62249
62390
  });
62250
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62391
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62251
62392
  const result = await Promise.race([
62252
62393
  Promise.all([
62253
62394
  new Response(proc.stdout).text(),
@@ -62394,7 +62535,7 @@ async function runDartAudit(directory) {
62394
62535
  stderr: "pipe",
62395
62536
  cwd: directory
62396
62537
  });
62397
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62538
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62398
62539
  const result = await Promise.race([
62399
62540
  Promise.all([
62400
62541
  new Response(proc.stdout).text(),
@@ -62619,8 +62760,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
62619
62760
  ]);
62620
62761
  // src/tools/pre-check-batch.ts
62621
62762
  init_dist();
62622
- import * as fs43 from "fs";
62623
- import * as path56 from "path";
62763
+ import * as fs44 from "fs";
62764
+ import * as path57 from "path";
62624
62765
 
62625
62766
  // node_modules/yocto-queue/index.js
62626
62767
  class Node2 {
@@ -62711,26 +62852,26 @@ function pLimit(concurrency) {
62711
62852
  activeCount--;
62712
62853
  resumeNext();
62713
62854
  };
62714
- const run2 = async (function_, resolve18, arguments_2) => {
62855
+ const run2 = async (function_, resolve19, arguments_2) => {
62715
62856
  const result = (async () => function_(...arguments_2))();
62716
- resolve18(result);
62857
+ resolve19(result);
62717
62858
  try {
62718
62859
  await result;
62719
62860
  } catch {}
62720
62861
  next();
62721
62862
  };
62722
- const enqueue = (function_, resolve18, reject, arguments_2) => {
62863
+ const enqueue = (function_, resolve19, reject, arguments_2) => {
62723
62864
  const queueItem = { reject };
62724
62865
  new Promise((internalResolve) => {
62725
62866
  queueItem.run = internalResolve;
62726
62867
  queue.enqueue(queueItem);
62727
- }).then(run2.bind(undefined, function_, resolve18, arguments_2));
62868
+ }).then(run2.bind(undefined, function_, resolve19, arguments_2));
62728
62869
  if (activeCount < concurrency) {
62729
62870
  resumeNext();
62730
62871
  }
62731
62872
  };
62732
- const generator = (function_, ...arguments_2) => new Promise((resolve18, reject) => {
62733
- enqueue(function_, resolve18, reject, arguments_2);
62873
+ const generator = (function_, ...arguments_2) => new Promise((resolve19, reject) => {
62874
+ enqueue(function_, resolve19, reject, arguments_2);
62734
62875
  });
62735
62876
  Object.defineProperties(generator, {
62736
62877
  activeCount: {
@@ -62894,8 +63035,8 @@ async function qualityBudget(input, directory) {
62894
63035
  init_dist();
62895
63036
  init_manager();
62896
63037
  init_detector();
62897
- import * as fs42 from "fs";
62898
- import * as path55 from "path";
63038
+ import * as fs43 from "fs";
63039
+ import * as path56 from "path";
62899
63040
  import { extname as extname10 } from "path";
62900
63041
 
62901
63042
  // src/sast/rules/c.ts
@@ -63646,7 +63787,7 @@ function mapSemgrepSeverity(severity) {
63646
63787
  }
63647
63788
  }
63648
63789
  async function executeWithTimeout(command, args2, options) {
63649
- return new Promise((resolve18) => {
63790
+ return new Promise((resolve19) => {
63650
63791
  const child = spawn2(command, args2, {
63651
63792
  shell: false,
63652
63793
  cwd: options.cwd
@@ -63655,7 +63796,7 @@ async function executeWithTimeout(command, args2, options) {
63655
63796
  let stderr = "";
63656
63797
  const timeout = setTimeout(() => {
63657
63798
  child.kill("SIGTERM");
63658
- resolve18({
63799
+ resolve19({
63659
63800
  stdout,
63660
63801
  stderr: "Process timed out",
63661
63802
  exitCode: 124
@@ -63669,7 +63810,7 @@ async function executeWithTimeout(command, args2, options) {
63669
63810
  });
63670
63811
  child.on("close", (code) => {
63671
63812
  clearTimeout(timeout);
63672
- resolve18({
63813
+ resolve19({
63673
63814
  stdout,
63674
63815
  stderr,
63675
63816
  exitCode: code ?? 0
@@ -63677,7 +63818,7 @@ async function executeWithTimeout(command, args2, options) {
63677
63818
  });
63678
63819
  child.on("error", (err2) => {
63679
63820
  clearTimeout(timeout);
63680
- resolve18({
63821
+ resolve19({
63681
63822
  stdout,
63682
63823
  stderr: err2.message,
63683
63824
  exitCode: 1
@@ -63765,17 +63906,17 @@ var SEVERITY_ORDER = {
63765
63906
  };
63766
63907
  function shouldSkipFile(filePath) {
63767
63908
  try {
63768
- const stats = fs42.statSync(filePath);
63909
+ const stats = fs43.statSync(filePath);
63769
63910
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
63770
63911
  return { skip: true, reason: "file too large" };
63771
63912
  }
63772
63913
  if (stats.size === 0) {
63773
63914
  return { skip: true, reason: "empty file" };
63774
63915
  }
63775
- const fd = fs42.openSync(filePath, "r");
63916
+ const fd = fs43.openSync(filePath, "r");
63776
63917
  const buffer = Buffer.alloc(8192);
63777
- const bytesRead = fs42.readSync(fd, buffer, 0, 8192, 0);
63778
- fs42.closeSync(fd);
63918
+ const bytesRead = fs43.readSync(fd, buffer, 0, 8192, 0);
63919
+ fs43.closeSync(fd);
63779
63920
  if (bytesRead > 0) {
63780
63921
  let nullCount = 0;
63781
63922
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -63814,7 +63955,7 @@ function countBySeverity(findings) {
63814
63955
  }
63815
63956
  function scanFileWithTierA(filePath, language) {
63816
63957
  try {
63817
- const content = fs42.readFileSync(filePath, "utf-8");
63958
+ const content = fs43.readFileSync(filePath, "utf-8");
63818
63959
  const findings = executeRulesSync(filePath, content, language);
63819
63960
  return findings.map((f) => ({
63820
63961
  rule_id: f.rule_id,
@@ -63861,8 +64002,8 @@ async function sastScan(input, directory, config3) {
63861
64002
  _filesSkipped++;
63862
64003
  continue;
63863
64004
  }
63864
- const resolvedPath = path55.isAbsolute(filePath) ? filePath : path55.resolve(directory, filePath);
63865
- if (!fs42.existsSync(resolvedPath)) {
64005
+ const resolvedPath = path56.isAbsolute(filePath) ? filePath : path56.resolve(directory, filePath);
64006
+ if (!fs43.existsSync(resolvedPath)) {
63866
64007
  _filesSkipped++;
63867
64008
  continue;
63868
64009
  }
@@ -64060,18 +64201,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
64060
64201
  let resolved;
64061
64202
  const isWinAbs = isWindowsAbsolutePath(inputPath);
64062
64203
  if (isWinAbs) {
64063
- resolved = path56.win32.resolve(inputPath);
64064
- } else if (path56.isAbsolute(inputPath)) {
64065
- resolved = path56.resolve(inputPath);
64204
+ resolved = path57.win32.resolve(inputPath);
64205
+ } else if (path57.isAbsolute(inputPath)) {
64206
+ resolved = path57.resolve(inputPath);
64066
64207
  } else {
64067
- resolved = path56.resolve(baseDir, inputPath);
64208
+ resolved = path57.resolve(baseDir, inputPath);
64068
64209
  }
64069
- const workspaceResolved = path56.resolve(workspaceDir);
64210
+ const workspaceResolved = path57.resolve(workspaceDir);
64070
64211
  let relative8;
64071
64212
  if (isWinAbs) {
64072
- relative8 = path56.win32.relative(workspaceResolved, resolved);
64213
+ relative8 = path57.win32.relative(workspaceResolved, resolved);
64073
64214
  } else {
64074
- relative8 = path56.relative(workspaceResolved, resolved);
64215
+ relative8 = path57.relative(workspaceResolved, resolved);
64075
64216
  }
64076
64217
  if (relative8.startsWith("..")) {
64077
64218
  return "path traversal detected";
@@ -64132,13 +64273,13 @@ async function runLintWrapped(files, directory, _config) {
64132
64273
  }
64133
64274
  async function runLintOnFiles(linter, files, workspaceDir) {
64134
64275
  const isWindows = process.platform === "win32";
64135
- const binDir = path56.join(workspaceDir, "node_modules", ".bin");
64276
+ const binDir = path57.join(workspaceDir, "node_modules", ".bin");
64136
64277
  const validatedFiles = [];
64137
64278
  for (const file3 of files) {
64138
64279
  if (typeof file3 !== "string") {
64139
64280
  continue;
64140
64281
  }
64141
- const resolvedPath = path56.resolve(file3);
64282
+ const resolvedPath = path57.resolve(file3);
64142
64283
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
64143
64284
  if (validationError) {
64144
64285
  continue;
@@ -64156,10 +64297,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
64156
64297
  }
64157
64298
  let command;
64158
64299
  if (linter === "biome") {
64159
- const biomeBin = isWindows ? path56.join(binDir, "biome.EXE") : path56.join(binDir, "biome");
64300
+ const biomeBin = isWindows ? path57.join(binDir, "biome.EXE") : path57.join(binDir, "biome");
64160
64301
  command = [biomeBin, "check", ...validatedFiles];
64161
64302
  } else {
64162
- const eslintBin = isWindows ? path56.join(binDir, "eslint.cmd") : path56.join(binDir, "eslint");
64303
+ const eslintBin = isWindows ? path57.join(binDir, "eslint.cmd") : path57.join(binDir, "eslint");
64163
64304
  command = [eslintBin, ...validatedFiles];
64164
64305
  }
64165
64306
  try {
@@ -64296,7 +64437,7 @@ async function runSecretscanWithFiles(files, directory) {
64296
64437
  skippedFiles++;
64297
64438
  continue;
64298
64439
  }
64299
- const resolvedPath = path56.resolve(file3);
64440
+ const resolvedPath = path57.resolve(file3);
64300
64441
  const validationError = validatePath(resolvedPath, directory, directory);
64301
64442
  if (validationError) {
64302
64443
  skippedFiles++;
@@ -64314,14 +64455,14 @@ async function runSecretscanWithFiles(files, directory) {
64314
64455
  };
64315
64456
  }
64316
64457
  for (const file3 of validatedFiles) {
64317
- const ext = path56.extname(file3).toLowerCase();
64458
+ const ext = path57.extname(file3).toLowerCase();
64318
64459
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
64319
64460
  skippedFiles++;
64320
64461
  continue;
64321
64462
  }
64322
64463
  let stat2;
64323
64464
  try {
64324
- stat2 = fs43.statSync(file3);
64465
+ stat2 = fs44.statSync(file3);
64325
64466
  } catch {
64326
64467
  skippedFiles++;
64327
64468
  continue;
@@ -64332,7 +64473,7 @@ async function runSecretscanWithFiles(files, directory) {
64332
64473
  }
64333
64474
  let content;
64334
64475
  try {
64335
- const buffer = fs43.readFileSync(file3);
64476
+ const buffer = fs44.readFileSync(file3);
64336
64477
  if (buffer.includes(0)) {
64337
64478
  skippedFiles++;
64338
64479
  continue;
@@ -64520,7 +64661,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
64520
64661
  const preexistingFindings = [];
64521
64662
  for (const finding of findings) {
64522
64663
  const filePath = finding.location.file;
64523
- const normalised = path56.relative(directory, filePath).replace(/\\/g, "/");
64664
+ const normalised = path57.relative(directory, filePath).replace(/\\/g, "/");
64524
64665
  const changedLines = changedLineRanges.get(normalised);
64525
64666
  if (changedLines && changedLines.has(finding.location.line)) {
64526
64667
  newFindings.push(finding);
@@ -64571,7 +64712,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
64571
64712
  warn(`pre_check_batch: Invalid file path: ${file3}`);
64572
64713
  continue;
64573
64714
  }
64574
- changedFiles.push(path56.resolve(directory, file3));
64715
+ changedFiles.push(path57.resolve(directory, file3));
64575
64716
  }
64576
64717
  if (changedFiles.length === 0) {
64577
64718
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -64759,7 +64900,7 @@ var pre_check_batch = createSwarmTool({
64759
64900
  };
64760
64901
  return JSON.stringify(errorResult, null, 2);
64761
64902
  }
64762
- const resolvedDirectory = path56.resolve(typedArgs.directory);
64903
+ const resolvedDirectory = path57.resolve(typedArgs.directory);
64763
64904
  const workspaceAnchor = resolvedDirectory;
64764
64905
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
64765
64906
  if (dirError) {
@@ -64865,38 +65006,38 @@ ${paginatedContent}`;
64865
65006
  });
64866
65007
  // src/tools/save-plan.ts
64867
65008
  init_tool();
64868
- import * as fs45 from "fs";
64869
- import * as path58 from "path";
65009
+ import * as fs46 from "fs";
65010
+ import * as path59 from "path";
64870
65011
 
64871
65012
  // src/parallel/file-locks.ts
64872
- import * as fs44 from "fs";
64873
- import * as path57 from "path";
65013
+ import * as fs45 from "fs";
65014
+ import * as path58 from "path";
64874
65015
  var LOCKS_DIR = ".swarm/locks";
64875
65016
  var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
64876
65017
  function getLockFilePath(directory, filePath) {
64877
- const normalized = path57.resolve(directory, filePath);
64878
- if (!normalized.startsWith(path57.resolve(directory))) {
65018
+ const normalized = path58.resolve(directory, filePath);
65019
+ if (!normalized.startsWith(path58.resolve(directory))) {
64879
65020
  throw new Error("Invalid file path: path traversal not allowed");
64880
65021
  }
64881
65022
  const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
64882
- return path57.join(directory, LOCKS_DIR, `${hash3}.lock`);
65023
+ return path58.join(directory, LOCKS_DIR, `${hash3}.lock`);
64883
65024
  }
64884
65025
  function tryAcquireLock(directory, filePath, agent, taskId) {
64885
65026
  const lockPath = getLockFilePath(directory, filePath);
64886
- const locksDir = path57.dirname(lockPath);
64887
- if (!fs44.existsSync(locksDir)) {
64888
- fs44.mkdirSync(locksDir, { recursive: true });
65027
+ const locksDir = path58.dirname(lockPath);
65028
+ if (!fs45.existsSync(locksDir)) {
65029
+ fs45.mkdirSync(locksDir, { recursive: true });
64889
65030
  }
64890
- if (fs44.existsSync(lockPath)) {
65031
+ if (fs45.existsSync(lockPath)) {
64891
65032
  try {
64892
- const existingLock = JSON.parse(fs44.readFileSync(lockPath, "utf-8"));
65033
+ const existingLock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
64893
65034
  if (Date.now() > existingLock.expiresAt) {
64894
- fs44.unlinkSync(lockPath);
65035
+ fs45.unlinkSync(lockPath);
64895
65036
  } else {
64896
65037
  return { acquired: false, existing: existingLock };
64897
65038
  }
64898
65039
  } catch {
64899
- fs44.unlinkSync(lockPath);
65040
+ fs45.unlinkSync(lockPath);
64900
65041
  }
64901
65042
  }
64902
65043
  const lock = {
@@ -64907,24 +65048,24 @@ function tryAcquireLock(directory, filePath, agent, taskId) {
64907
65048
  expiresAt: Date.now() + LOCK_TIMEOUT_MS
64908
65049
  };
64909
65050
  const tempPath = `${lockPath}.tmp`;
64910
- fs44.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
64911
- fs44.renameSync(tempPath, lockPath);
65051
+ fs45.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65052
+ fs45.renameSync(tempPath, lockPath);
64912
65053
  return { acquired: true, lock };
64913
65054
  }
64914
65055
  function releaseLock(directory, filePath, taskId) {
64915
65056
  const lockPath = getLockFilePath(directory, filePath);
64916
- if (!fs44.existsSync(lockPath)) {
65057
+ if (!fs45.existsSync(lockPath)) {
64917
65058
  return true;
64918
65059
  }
64919
65060
  try {
64920
- const lock = JSON.parse(fs44.readFileSync(lockPath, "utf-8"));
65061
+ const lock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
64921
65062
  if (lock.taskId === taskId) {
64922
- fs44.unlinkSync(lockPath);
65063
+ fs45.unlinkSync(lockPath);
64923
65064
  return true;
64924
65065
  }
64925
65066
  return false;
64926
65067
  } catch {
64927
- fs44.unlinkSync(lockPath);
65068
+ fs45.unlinkSync(lockPath);
64928
65069
  return true;
64929
65070
  }
64930
65071
  }
@@ -65049,14 +65190,14 @@ async function executeSavePlan(args2, fallbackDir) {
65049
65190
  try {
65050
65191
  await savePlan(dir, plan);
65051
65192
  try {
65052
- const markerPath = path58.join(dir, ".swarm", ".plan-write-marker");
65193
+ const markerPath = path59.join(dir, ".swarm", ".plan-write-marker");
65053
65194
  const marker = JSON.stringify({
65054
65195
  source: "save_plan",
65055
65196
  timestamp: new Date().toISOString(),
65056
65197
  phases_count: plan.phases.length,
65057
65198
  tasks_count: tasksCount
65058
65199
  });
65059
- await fs45.promises.writeFile(markerPath, marker, "utf8");
65200
+ await fs46.promises.writeFile(markerPath, marker, "utf8");
65060
65201
  } catch {}
65061
65202
  const warnings = [];
65062
65203
  let criticReviewFound = false;
@@ -65072,7 +65213,7 @@ async function executeSavePlan(args2, fallbackDir) {
65072
65213
  return {
65073
65214
  success: true,
65074
65215
  message: "Plan saved successfully",
65075
- plan_path: path58.join(dir, ".swarm", "plan.json"),
65216
+ plan_path: path59.join(dir, ".swarm", "plan.json"),
65076
65217
  phases_count: plan.phases.length,
65077
65218
  tasks_count: tasksCount,
65078
65219
  ...warnings.length > 0 ? { warnings } : {}
@@ -65114,8 +65255,8 @@ var save_plan = createSwarmTool({
65114
65255
  // src/tools/sbom-generate.ts
65115
65256
  init_dist();
65116
65257
  init_manager();
65117
- import * as fs46 from "fs";
65118
- import * as path59 from "path";
65258
+ import * as fs47 from "fs";
65259
+ import * as path60 from "path";
65119
65260
 
65120
65261
  // src/sbom/detectors/index.ts
65121
65262
  init_utils();
@@ -65963,9 +66104,9 @@ function findManifestFiles(rootDir) {
65963
66104
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
65964
66105
  function searchDir(dir) {
65965
66106
  try {
65966
- const entries = fs46.readdirSync(dir, { withFileTypes: true });
66107
+ const entries = fs47.readdirSync(dir, { withFileTypes: true });
65967
66108
  for (const entry of entries) {
65968
- const fullPath = path59.join(dir, entry.name);
66109
+ const fullPath = path60.join(dir, entry.name);
65969
66110
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
65970
66111
  continue;
65971
66112
  }
@@ -65974,7 +66115,7 @@ function findManifestFiles(rootDir) {
65974
66115
  } else if (entry.isFile()) {
65975
66116
  for (const pattern of patterns) {
65976
66117
  if (simpleGlobToRegex(pattern).test(entry.name)) {
65977
- manifestFiles.push(path59.relative(rootDir, fullPath));
66118
+ manifestFiles.push(path60.relative(rootDir, fullPath));
65978
66119
  break;
65979
66120
  }
65980
66121
  }
@@ -65990,13 +66131,13 @@ function findManifestFilesInDirs(directories, workingDir) {
65990
66131
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
65991
66132
  for (const dir of directories) {
65992
66133
  try {
65993
- const entries = fs46.readdirSync(dir, { withFileTypes: true });
66134
+ const entries = fs47.readdirSync(dir, { withFileTypes: true });
65994
66135
  for (const entry of entries) {
65995
- const fullPath = path59.join(dir, entry.name);
66136
+ const fullPath = path60.join(dir, entry.name);
65996
66137
  if (entry.isFile()) {
65997
66138
  for (const pattern of patterns) {
65998
66139
  if (simpleGlobToRegex(pattern).test(entry.name)) {
65999
- found.push(path59.relative(workingDir, fullPath));
66140
+ found.push(path60.relative(workingDir, fullPath));
66000
66141
  break;
66001
66142
  }
66002
66143
  }
@@ -66009,11 +66150,11 @@ function findManifestFilesInDirs(directories, workingDir) {
66009
66150
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66010
66151
  const dirs = new Set;
66011
66152
  for (const file3 of changedFiles) {
66012
- let currentDir = path59.dirname(file3);
66153
+ let currentDir = path60.dirname(file3);
66013
66154
  while (true) {
66014
- if (currentDir && currentDir !== "." && currentDir !== path59.sep) {
66015
- dirs.add(path59.join(workingDir, currentDir));
66016
- const parent = path59.dirname(currentDir);
66155
+ if (currentDir && currentDir !== "." && currentDir !== path60.sep) {
66156
+ dirs.add(path60.join(workingDir, currentDir));
66157
+ const parent = path60.dirname(currentDir);
66017
66158
  if (parent === currentDir)
66018
66159
  break;
66019
66160
  currentDir = parent;
@@ -66027,7 +66168,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66027
66168
  }
66028
66169
  function ensureOutputDir(outputDir) {
66029
66170
  try {
66030
- fs46.mkdirSync(outputDir, { recursive: true });
66171
+ fs47.mkdirSync(outputDir, { recursive: true });
66031
66172
  } catch (error93) {
66032
66173
  if (!error93 || error93.code !== "EEXIST") {
66033
66174
  throw error93;
@@ -66097,7 +66238,7 @@ var sbom_generate = createSwarmTool({
66097
66238
  const changedFiles = obj.changed_files;
66098
66239
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
66099
66240
  const workingDir = directory;
66100
- const outputDir = path59.isAbsolute(relativeOutputDir) ? relativeOutputDir : path59.join(workingDir, relativeOutputDir);
66241
+ const outputDir = path60.isAbsolute(relativeOutputDir) ? relativeOutputDir : path60.join(workingDir, relativeOutputDir);
66101
66242
  let manifestFiles = [];
66102
66243
  if (scope === "all") {
66103
66244
  manifestFiles = findManifestFiles(workingDir);
@@ -66120,11 +66261,11 @@ var sbom_generate = createSwarmTool({
66120
66261
  const processedFiles = [];
66121
66262
  for (const manifestFile of manifestFiles) {
66122
66263
  try {
66123
- const fullPath = path59.isAbsolute(manifestFile) ? manifestFile : path59.join(workingDir, manifestFile);
66124
- if (!fs46.existsSync(fullPath)) {
66264
+ const fullPath = path60.isAbsolute(manifestFile) ? manifestFile : path60.join(workingDir, manifestFile);
66265
+ if (!fs47.existsSync(fullPath)) {
66125
66266
  continue;
66126
66267
  }
66127
- const content = fs46.readFileSync(fullPath, "utf-8");
66268
+ const content = fs47.readFileSync(fullPath, "utf-8");
66128
66269
  const components = detectComponents(manifestFile, content);
66129
66270
  processedFiles.push(manifestFile);
66130
66271
  if (components.length > 0) {
@@ -66137,8 +66278,8 @@ var sbom_generate = createSwarmTool({
66137
66278
  const bom = generateCycloneDX(allComponents);
66138
66279
  const bomJson = serializeCycloneDX(bom);
66139
66280
  const filename = generateSbomFilename();
66140
- const outputPath = path59.join(outputDir, filename);
66141
- fs46.writeFileSync(outputPath, bomJson, "utf-8");
66281
+ const outputPath = path60.join(outputDir, filename);
66282
+ fs47.writeFileSync(outputPath, bomJson, "utf-8");
66142
66283
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
66143
66284
  try {
66144
66285
  const timestamp = new Date().toISOString();
@@ -66180,8 +66321,8 @@ var sbom_generate = createSwarmTool({
66180
66321
  // src/tools/schema-drift.ts
66181
66322
  init_dist();
66182
66323
  init_create_tool();
66183
- import * as fs47 from "fs";
66184
- import * as path60 from "path";
66324
+ import * as fs48 from "fs";
66325
+ import * as path61 from "path";
66185
66326
  var SPEC_CANDIDATES = [
66186
66327
  "openapi.json",
66187
66328
  "openapi.yaml",
@@ -66213,28 +66354,28 @@ function normalizePath2(p) {
66213
66354
  }
66214
66355
  function discoverSpecFile(cwd, specFileArg) {
66215
66356
  if (specFileArg) {
66216
- const resolvedPath = path60.resolve(cwd, specFileArg);
66217
- const normalizedCwd = cwd.endsWith(path60.sep) ? cwd : cwd + path60.sep;
66357
+ const resolvedPath = path61.resolve(cwd, specFileArg);
66358
+ const normalizedCwd = cwd.endsWith(path61.sep) ? cwd : cwd + path61.sep;
66218
66359
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
66219
66360
  throw new Error("Invalid spec_file: path traversal detected");
66220
66361
  }
66221
- const ext = path60.extname(resolvedPath).toLowerCase();
66362
+ const ext = path61.extname(resolvedPath).toLowerCase();
66222
66363
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
66223
66364
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
66224
66365
  }
66225
- const stats = fs47.statSync(resolvedPath);
66366
+ const stats = fs48.statSync(resolvedPath);
66226
66367
  if (stats.size > MAX_SPEC_SIZE) {
66227
66368
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
66228
66369
  }
66229
- if (!fs47.existsSync(resolvedPath)) {
66370
+ if (!fs48.existsSync(resolvedPath)) {
66230
66371
  throw new Error(`Spec file not found: ${resolvedPath}`);
66231
66372
  }
66232
66373
  return resolvedPath;
66233
66374
  }
66234
66375
  for (const candidate of SPEC_CANDIDATES) {
66235
- const candidatePath = path60.resolve(cwd, candidate);
66236
- if (fs47.existsSync(candidatePath)) {
66237
- const stats = fs47.statSync(candidatePath);
66376
+ const candidatePath = path61.resolve(cwd, candidate);
66377
+ if (fs48.existsSync(candidatePath)) {
66378
+ const stats = fs48.statSync(candidatePath);
66238
66379
  if (stats.size <= MAX_SPEC_SIZE) {
66239
66380
  return candidatePath;
66240
66381
  }
@@ -66243,8 +66384,8 @@ function discoverSpecFile(cwd, specFileArg) {
66243
66384
  return null;
66244
66385
  }
66245
66386
  function parseSpec(specFile) {
66246
- const content = fs47.readFileSync(specFile, "utf-8");
66247
- const ext = path60.extname(specFile).toLowerCase();
66387
+ const content = fs48.readFileSync(specFile, "utf-8");
66388
+ const ext = path61.extname(specFile).toLowerCase();
66248
66389
  if (ext === ".json") {
66249
66390
  return parseJsonSpec(content);
66250
66391
  }
@@ -66315,12 +66456,12 @@ function extractRoutes(cwd) {
66315
66456
  function walkDir(dir) {
66316
66457
  let entries;
66317
66458
  try {
66318
- entries = fs47.readdirSync(dir, { withFileTypes: true });
66459
+ entries = fs48.readdirSync(dir, { withFileTypes: true });
66319
66460
  } catch {
66320
66461
  return;
66321
66462
  }
66322
66463
  for (const entry of entries) {
66323
- const fullPath = path60.join(dir, entry.name);
66464
+ const fullPath = path61.join(dir, entry.name);
66324
66465
  if (entry.isSymbolicLink()) {
66325
66466
  continue;
66326
66467
  }
@@ -66330,7 +66471,7 @@ function extractRoutes(cwd) {
66330
66471
  }
66331
66472
  walkDir(fullPath);
66332
66473
  } else if (entry.isFile()) {
66333
- const ext = path60.extname(entry.name).toLowerCase();
66474
+ const ext = path61.extname(entry.name).toLowerCase();
66334
66475
  const baseName = entry.name.toLowerCase();
66335
66476
  if (![".ts", ".js", ".mjs"].includes(ext)) {
66336
66477
  continue;
@@ -66348,7 +66489,7 @@ function extractRoutes(cwd) {
66348
66489
  }
66349
66490
  function extractRoutesFromFile(filePath) {
66350
66491
  const routes = [];
66351
- const content = fs47.readFileSync(filePath, "utf-8");
66492
+ const content = fs48.readFileSync(filePath, "utf-8");
66352
66493
  const lines = content.split(/\r?\n/);
66353
66494
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
66354
66495
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -66499,8 +66640,8 @@ init_secretscan();
66499
66640
  // src/tools/symbols.ts
66500
66641
  init_tool();
66501
66642
  init_create_tool();
66502
- import * as fs48 from "fs";
66503
- import * as path61 from "path";
66643
+ import * as fs49 from "fs";
66644
+ import * as path62 from "path";
66504
66645
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
66505
66646
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
66506
66647
  function containsWindowsAttacks(str) {
@@ -66517,11 +66658,11 @@ function containsWindowsAttacks(str) {
66517
66658
  }
66518
66659
  function isPathInWorkspace(filePath, workspace) {
66519
66660
  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)) {
66661
+ const resolvedPath = path62.resolve(workspace, filePath);
66662
+ const realWorkspace = fs49.realpathSync(workspace);
66663
+ const realResolvedPath = fs49.realpathSync(resolvedPath);
66664
+ const relativePath = path62.relative(realWorkspace, realResolvedPath);
66665
+ if (relativePath.startsWith("..") || path62.isAbsolute(relativePath)) {
66525
66666
  return false;
66526
66667
  }
66527
66668
  return true;
@@ -66533,17 +66674,17 @@ function validatePathForRead(filePath, workspace) {
66533
66674
  return isPathInWorkspace(filePath, workspace);
66534
66675
  }
66535
66676
  function extractTSSymbols(filePath, cwd) {
66536
- const fullPath = path61.join(cwd, filePath);
66677
+ const fullPath = path62.join(cwd, filePath);
66537
66678
  if (!validatePathForRead(fullPath, cwd)) {
66538
66679
  return [];
66539
66680
  }
66540
66681
  let content;
66541
66682
  try {
66542
- const stats = fs48.statSync(fullPath);
66683
+ const stats = fs49.statSync(fullPath);
66543
66684
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66544
66685
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66545
66686
  }
66546
- content = fs48.readFileSync(fullPath, "utf-8");
66687
+ content = fs49.readFileSync(fullPath, "utf-8");
66547
66688
  } catch {
66548
66689
  return [];
66549
66690
  }
@@ -66685,17 +66826,17 @@ function extractTSSymbols(filePath, cwd) {
66685
66826
  });
66686
66827
  }
66687
66828
  function extractPythonSymbols(filePath, cwd) {
66688
- const fullPath = path61.join(cwd, filePath);
66829
+ const fullPath = path62.join(cwd, filePath);
66689
66830
  if (!validatePathForRead(fullPath, cwd)) {
66690
66831
  return [];
66691
66832
  }
66692
66833
  let content;
66693
66834
  try {
66694
- const stats = fs48.statSync(fullPath);
66835
+ const stats = fs49.statSync(fullPath);
66695
66836
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66696
66837
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66697
66838
  }
66698
- content = fs48.readFileSync(fullPath, "utf-8");
66839
+ content = fs49.readFileSync(fullPath, "utf-8");
66699
66840
  } catch {
66700
66841
  return [];
66701
66842
  }
@@ -66768,7 +66909,7 @@ var symbols = createSwarmTool({
66768
66909
  }, null, 2);
66769
66910
  }
66770
66911
  const cwd = directory;
66771
- const ext = path61.extname(file3);
66912
+ const ext = path62.extname(file3);
66772
66913
  if (containsControlChars(file3)) {
66773
66914
  return JSON.stringify({
66774
66915
  file: file3,
@@ -66839,8 +66980,8 @@ init_test_runner();
66839
66980
  init_dist();
66840
66981
  init_utils();
66841
66982
  init_create_tool();
66842
- import * as fs49 from "fs";
66843
- import * as path62 from "path";
66983
+ import * as fs50 from "fs";
66984
+ import * as path63 from "path";
66844
66985
  var MAX_TEXT_LENGTH = 200;
66845
66986
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
66846
66987
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -66905,9 +67046,9 @@ function validatePathsInput(paths, cwd) {
66905
67046
  return { error: "paths contains path traversal", resolvedPath: null };
66906
67047
  }
66907
67048
  try {
66908
- const resolvedPath = path62.resolve(paths);
66909
- const normalizedCwd = path62.resolve(cwd);
66910
- const normalizedResolved = path62.resolve(resolvedPath);
67049
+ const resolvedPath = path63.resolve(paths);
67050
+ const normalizedCwd = path63.resolve(cwd);
67051
+ const normalizedResolved = path63.resolve(resolvedPath);
66911
67052
  if (!normalizedResolved.startsWith(normalizedCwd)) {
66912
67053
  return {
66913
67054
  error: "paths must be within the current working directory",
@@ -66923,13 +67064,13 @@ function validatePathsInput(paths, cwd) {
66923
67064
  }
66924
67065
  }
66925
67066
  function isSupportedExtension(filePath) {
66926
- const ext = path62.extname(filePath).toLowerCase();
67067
+ const ext = path63.extname(filePath).toLowerCase();
66927
67068
  return SUPPORTED_EXTENSIONS2.has(ext);
66928
67069
  }
66929
67070
  function findSourceFiles2(dir, files = []) {
66930
67071
  let entries;
66931
67072
  try {
66932
- entries = fs49.readdirSync(dir);
67073
+ entries = fs50.readdirSync(dir);
66933
67074
  } catch {
66934
67075
  return files;
66935
67076
  }
@@ -66938,10 +67079,10 @@ function findSourceFiles2(dir, files = []) {
66938
67079
  if (SKIP_DIRECTORIES4.has(entry)) {
66939
67080
  continue;
66940
67081
  }
66941
- const fullPath = path62.join(dir, entry);
67082
+ const fullPath = path63.join(dir, entry);
66942
67083
  let stat2;
66943
67084
  try {
66944
- stat2 = fs49.statSync(fullPath);
67085
+ stat2 = fs50.statSync(fullPath);
66945
67086
  } catch {
66946
67087
  continue;
66947
67088
  }
@@ -67034,7 +67175,7 @@ var todo_extract = createSwarmTool({
67034
67175
  return JSON.stringify(errorResult, null, 2);
67035
67176
  }
67036
67177
  const scanPath = resolvedPath;
67037
- if (!fs49.existsSync(scanPath)) {
67178
+ if (!fs50.existsSync(scanPath)) {
67038
67179
  const errorResult = {
67039
67180
  error: `path not found: ${pathsInput}`,
67040
67181
  total: 0,
@@ -67044,13 +67185,13 @@ var todo_extract = createSwarmTool({
67044
67185
  return JSON.stringify(errorResult, null, 2);
67045
67186
  }
67046
67187
  const filesToScan = [];
67047
- const stat2 = fs49.statSync(scanPath);
67188
+ const stat2 = fs50.statSync(scanPath);
67048
67189
  if (stat2.isFile()) {
67049
67190
  if (isSupportedExtension(scanPath)) {
67050
67191
  filesToScan.push(scanPath);
67051
67192
  } else {
67052
67193
  const errorResult = {
67053
- error: `unsupported file extension: ${path62.extname(scanPath)}`,
67194
+ error: `unsupported file extension: ${path63.extname(scanPath)}`,
67054
67195
  total: 0,
67055
67196
  byPriority: { high: 0, medium: 0, low: 0 },
67056
67197
  entries: []
@@ -67063,11 +67204,11 @@ var todo_extract = createSwarmTool({
67063
67204
  const allEntries = [];
67064
67205
  for (const filePath of filesToScan) {
67065
67206
  try {
67066
- const fileStat = fs49.statSync(filePath);
67207
+ const fileStat = fs50.statSync(filePath);
67067
67208
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
67068
67209
  continue;
67069
67210
  }
67070
- const content = fs49.readFileSync(filePath, "utf-8");
67211
+ const content = fs50.readFileSync(filePath, "utf-8");
67071
67212
  const entries = parseTodoComments(content, filePath, tagsSet);
67072
67213
  allEntries.push(...entries);
67073
67214
  } catch {}
@@ -67096,18 +67237,18 @@ var todo_extract = createSwarmTool({
67096
67237
  init_tool();
67097
67238
  init_schema();
67098
67239
  init_gate_evidence();
67099
- import * as fs51 from "fs";
67100
- import * as path64 from "path";
67240
+ import * as fs52 from "fs";
67241
+ import * as path65 from "path";
67101
67242
 
67102
67243
  // src/hooks/diff-scope.ts
67103
- import * as fs50 from "fs";
67104
- import * as path63 from "path";
67244
+ import * as fs51 from "fs";
67245
+ import * as path64 from "path";
67105
67246
  function getDeclaredScope(taskId, directory) {
67106
67247
  try {
67107
- const planPath = path63.join(directory, ".swarm", "plan.json");
67108
- if (!fs50.existsSync(planPath))
67248
+ const planPath = path64.join(directory, ".swarm", "plan.json");
67249
+ if (!fs51.existsSync(planPath))
67109
67250
  return null;
67110
- const raw = fs50.readFileSync(planPath, "utf-8");
67251
+ const raw = fs51.readFileSync(planPath, "utf-8");
67111
67252
  const plan = JSON.parse(raw);
67112
67253
  for (const phase of plan.phases ?? []) {
67113
67254
  for (const task of phase.tasks ?? []) {
@@ -67220,7 +67361,7 @@ var TIER_3_PATTERNS = [
67220
67361
  ];
67221
67362
  function matchesTier3Pattern(files) {
67222
67363
  for (const file3 of files) {
67223
- const fileName = path64.basename(file3);
67364
+ const fileName = path65.basename(file3);
67224
67365
  for (const pattern of TIER_3_PATTERNS) {
67225
67366
  if (pattern.test(fileName)) {
67226
67367
  return true;
@@ -67234,8 +67375,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67234
67375
  if (hasActiveTurboMode()) {
67235
67376
  const resolvedDir2 = workingDirectory;
67236
67377
  try {
67237
- const planPath = path64.join(resolvedDir2, ".swarm", "plan.json");
67238
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67378
+ const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67379
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67239
67380
  const plan = JSON.parse(planRaw);
67240
67381
  for (const planPhase of plan.phases ?? []) {
67241
67382
  for (const task of planPhase.tasks ?? []) {
@@ -67301,8 +67442,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67301
67442
  }
67302
67443
  try {
67303
67444
  const resolvedDir2 = workingDirectory;
67304
- const planPath = path64.join(resolvedDir2, ".swarm", "plan.json");
67305
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67445
+ const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67446
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67306
67447
  const plan = JSON.parse(planRaw);
67307
67448
  for (const planPhase of plan.phases ?? []) {
67308
67449
  for (const task of planPhase.tasks ?? []) {
@@ -67484,8 +67625,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67484
67625
  };
67485
67626
  }
67486
67627
  }
67487
- normalizedDir = path64.normalize(args2.working_directory);
67488
- const pathParts = normalizedDir.split(path64.sep);
67628
+ normalizedDir = path65.normalize(args2.working_directory);
67629
+ const pathParts = normalizedDir.split(path65.sep);
67489
67630
  if (pathParts.includes("..")) {
67490
67631
  return {
67491
67632
  success: false,
@@ -67495,11 +67636,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67495
67636
  ]
67496
67637
  };
67497
67638
  }
67498
- const resolvedDir = path64.resolve(normalizedDir);
67639
+ const resolvedDir = path65.resolve(normalizedDir);
67499
67640
  try {
67500
- const realPath = fs51.realpathSync(resolvedDir);
67501
- const planPath = path64.join(realPath, ".swarm", "plan.json");
67502
- if (!fs51.existsSync(planPath)) {
67641
+ const realPath = fs52.realpathSync(resolvedDir);
67642
+ const planPath = path65.join(realPath, ".swarm", "plan.json");
67643
+ if (!fs52.existsSync(planPath)) {
67503
67644
  return {
67504
67645
  success: false,
67505
67646
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -67532,8 +67673,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67532
67673
  recoverTaskStateFromDelegations(args2.task_id);
67533
67674
  let phaseRequiresReviewer = true;
67534
67675
  try {
67535
- const planPath = path64.join(directory, ".swarm", "plan.json");
67536
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67676
+ const planPath = path65.join(directory, ".swarm", "plan.json");
67677
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67537
67678
  const plan = JSON.parse(planRaw);
67538
67679
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
67539
67680
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -67596,8 +67737,8 @@ var update_task_status = createSwarmTool({
67596
67737
  init_tool();
67597
67738
  init_utils2();
67598
67739
  init_create_tool();
67599
- import fs52 from "fs";
67600
- import path65 from "path";
67740
+ import fs53 from "fs";
67741
+ import path66 from "path";
67601
67742
  function normalizeVerdict(verdict) {
67602
67743
  switch (verdict) {
67603
67744
  case "APPROVED":
@@ -67644,7 +67785,7 @@ async function executeWriteDriftEvidence(args2, directory) {
67644
67785
  entries: [evidenceEntry]
67645
67786
  };
67646
67787
  const filename = "drift-verifier.json";
67647
- const relativePath = path65.join("evidence", String(phase), filename);
67788
+ const relativePath = path66.join("evidence", String(phase), filename);
67648
67789
  let validatedPath;
67649
67790
  try {
67650
67791
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -67655,12 +67796,12 @@ async function executeWriteDriftEvidence(args2, directory) {
67655
67796
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
67656
67797
  }, null, 2);
67657
67798
  }
67658
- const evidenceDir = path65.dirname(validatedPath);
67799
+ const evidenceDir = path66.dirname(validatedPath);
67659
67800
  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);
67801
+ await fs53.promises.mkdir(evidenceDir, { recursive: true });
67802
+ const tempPath = path66.join(evidenceDir, `.${filename}.tmp`);
67803
+ await fs53.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
67804
+ await fs53.promises.rename(tempPath, validatedPath);
67664
67805
  return JSON.stringify({
67665
67806
  success: true,
67666
67807
  phase,
@@ -67848,7 +67989,7 @@ var OpenCodeSwarm = async (ctx) => {
67848
67989
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
67849
67990
  preflightTriggerManager = new PTM(automationConfig);
67850
67991
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
67851
- const swarmDir = path66.resolve(ctx.directory, ".swarm");
67992
+ const swarmDir = path67.resolve(ctx.directory, ".swarm");
67852
67993
  statusArtifact = new ASA(swarmDir);
67853
67994
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
67854
67995
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {