opencode-swarm 6.41.1 → 6.41.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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();
@@ -47074,7 +47161,7 @@ async function executeWriteRetro(args2, directory) {
47074
47161
  var write_retro = createSwarmTool({
47075
47162
  description: "Write a retrospective evidence bundle for a completed phase. " + "Accepts flat retro fields and writes a correctly-wrapped EvidenceBundle to " + ".swarm/evidence/retro-{phase}/evidence.json. " + "Use this instead of manually writing retro JSON to avoid schema validation failures in phase_complete.",
47076
47163
  args: {
47077
- phase: tool.schema.number().int().positive().max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),
47164
+ phase: tool.schema.number().int().min(1).max(99).describe("The phase number being completed (e.g., 1, 2, 3)"),
47078
47165
  summary: tool.schema.string().describe("Human-readable summary of the phase"),
47079
47166
  task_count: tool.schema.number().int().min(1).max(9999).describe("Count of tasks completed in this phase"),
47080
47167
  task_complexity: tool.schema.enum(["trivial", "simple", "moderate", "complex"]).describe("Complexity level of the completed tasks"),
@@ -50040,7 +50127,7 @@ async function handlePromoteCommand(directory, args2) {
50040
50127
  }
50041
50128
 
50042
50129
  // src/commands/reset.ts
50043
- import * as 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
  }
@@ -57676,6 +57786,19 @@ function parseFilePaths(description, filesTouched) {
57676
57786
  }
57677
57787
  return filePaths;
57678
57788
  }
57789
+ function buildVerifySummary(tasksChecked, tasksSkipped, tasksBlocked) {
57790
+ if (tasksBlocked > 0) {
57791
+ return `Blocked: ${tasksBlocked} task(s) with missing identifiers`;
57792
+ }
57793
+ const verified = tasksChecked - tasksSkipped;
57794
+ if (tasksSkipped === tasksChecked) {
57795
+ return `All ${tasksChecked} completed task(s) skipped \u2014 research/inventory tasks`;
57796
+ }
57797
+ if (tasksSkipped > 0) {
57798
+ return `${verified} task(s) verified, ${tasksSkipped} skipped (research tasks)`;
57799
+ }
57800
+ return `All ${tasksChecked} completed tasks verified successfully`;
57801
+ }
57679
57802
  async function executeCompletionVerify(args2, directory) {
57680
57803
  const phase = Number(args2.phase);
57681
57804
  if (Number.isNaN(phase) || phase < 1 || !Number.isFinite(phase)) {
@@ -57707,7 +57830,7 @@ async function executeCompletionVerify(args2, directory) {
57707
57830
  let plan;
57708
57831
  try {
57709
57832
  const planPath = validateSwarmPath(directory, "plan.json");
57710
- const planRaw = fs33.readFileSync(planPath, "utf-8");
57833
+ const planRaw = fs34.readFileSync(planPath, "utf-8");
57711
57834
  plan = JSON.parse(planRaw);
57712
57835
  } catch {
57713
57836
  const result2 = {
@@ -57737,7 +57860,7 @@ async function executeCompletionVerify(args2, directory) {
57737
57860
  return JSON.stringify(result2, null, 2);
57738
57861
  }
57739
57862
  let tasksChecked = 0;
57740
- const tasksSkipped = 0;
57863
+ let tasksSkipped = 0;
57741
57864
  let tasksBlocked = 0;
57742
57865
  const blockedTasks = [];
57743
57866
  for (const task of targetPhase.tasks) {
@@ -57748,13 +57871,7 @@ async function executeCompletionVerify(args2, directory) {
57748
57871
  const fileTargets = parseFilePaths(task.description, task.files_touched);
57749
57872
  const identifiers = parseIdentifiers(task.description);
57750
57873
  if (fileTargets.length === 0) {
57751
- blockedTasks.push({
57752
- task_id: task.id,
57753
- identifier: "",
57754
- file_path: "",
57755
- reason: "No file targets \u2014 cannot verify completion without files_touched"
57756
- });
57757
- tasksBlocked++;
57874
+ tasksSkipped++;
57758
57875
  continue;
57759
57876
  }
57760
57877
  if (identifiers.length === 0) {
@@ -57771,10 +57888,23 @@ async function executeCompletionVerify(args2, directory) {
57771
57888
  let hasFileReadFailure = false;
57772
57889
  for (const filePath of fileTargets) {
57773
57890
  const normalizedPath = filePath.replace(/\\/g, "/");
57774
- const resolvedPath = path45.resolve(directory, normalizedPath);
57891
+ const resolvedPath = path46.resolve(directory, normalizedPath);
57892
+ const projectRoot = path46.resolve(directory);
57893
+ const relative6 = path46.relative(projectRoot, resolvedPath);
57894
+ const withinProject = relative6 === "" || !relative6.startsWith("..") && !path46.isAbsolute(relative6);
57895
+ if (!withinProject) {
57896
+ blockedTasks.push({
57897
+ task_id: task.id,
57898
+ identifier: "",
57899
+ file_path: filePath,
57900
+ reason: `File path '${filePath}' escapes the project directory \u2014 cannot verify completion`
57901
+ });
57902
+ hasFileReadFailure = true;
57903
+ continue;
57904
+ }
57775
57905
  let fileContent;
57776
57906
  try {
57777
- fileContent = fs33.readFileSync(resolvedPath, "utf-8");
57907
+ fileContent = fs34.readFileSync(resolvedPath, "utf-8");
57778
57908
  } catch {
57779
57909
  blockedTasks.push({
57780
57910
  task_id: task.id,
@@ -57816,9 +57946,9 @@ async function executeCompletionVerify(args2, directory) {
57816
57946
  blockedTasks
57817
57947
  };
57818
57948
  try {
57819
- const evidenceDir = path45.join(directory, ".swarm", "evidence", `${phase}`);
57820
- const evidencePath = path45.join(evidenceDir, "completion-verify.json");
57821
- 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 });
57822
57952
  const evidenceBundle = {
57823
57953
  schema_version: "1.0.0",
57824
57954
  task_id: "completion-verify",
@@ -57830,7 +57960,7 @@ async function executeCompletionVerify(args2, directory) {
57830
57960
  timestamp: now,
57831
57961
  agent: "completion_verify",
57832
57962
  verdict: tasksBlocked === 0 ? "pass" : "fail",
57833
- summary: tasksBlocked === 0 ? `All ${tasksChecked} completed tasks verified successfully` : `Blocked: ${tasksBlocked} task(s) with missing identifiers`,
57963
+ summary: buildVerifySummary(tasksChecked, tasksSkipped, tasksBlocked),
57834
57964
  phase,
57835
57965
  tasks_checked: tasksChecked,
57836
57966
  tasks_skipped: tasksSkipped,
@@ -57839,7 +57969,7 @@ async function executeCompletionVerify(args2, directory) {
57839
57969
  }
57840
57970
  ]
57841
57971
  };
57842
- fs33.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57972
+ fs34.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57843
57973
  } catch {}
57844
57974
  return JSON.stringify(result, null, 2);
57845
57975
  }
@@ -57847,7 +57977,8 @@ var completion_verify = createSwarmTool({
57847
57977
  description: "Deterministic pre-check verifying that plan task identifiers exist in their target source files before phase completion. Blocks if obviously incomplete.",
57848
57978
  args: {
57849
57979
  phase: tool.schema.number().describe("The phase number to check"),
57850
- sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
57980
+ sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
57981
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
57851
57982
  },
57852
57983
  execute: async (args2, directory) => {
57853
57984
  let parsedArgs;
@@ -57856,7 +57987,8 @@ var completion_verify = createSwarmTool({
57856
57987
  const obj = args2;
57857
57988
  parsedArgs = {
57858
57989
  phase: typeof obj.phase === "number" ? obj.phase : typeof obj.phase === "string" ? Number(obj.phase) : 0,
57859
- sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined
57990
+ sessionID: typeof obj.sessionID === "string" ? obj.sessionID : undefined,
57991
+ working_directory: typeof obj.working_directory === "string" ? obj.working_directory : undefined
57860
57992
  };
57861
57993
  } else {
57862
57994
  parsedArgs = { phase: 0 };
@@ -57873,17 +58005,30 @@ var completion_verify = createSwarmTool({
57873
58005
  blockedTasks: []
57874
58006
  }, null, 2);
57875
58007
  }
57876
- 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);
57877
58022
  }
57878
58023
  });
57879
58024
  // src/tools/complexity-hotspots.ts
57880
58025
  init_dist();
57881
- import * as fs35 from "fs";
57882
- import * as path47 from "path";
58026
+ import * as fs36 from "fs";
58027
+ import * as path48 from "path";
57883
58028
 
57884
58029
  // src/quality/metrics.ts
57885
- import * as fs34 from "fs";
57886
- import * as path46 from "path";
58030
+ import * as fs35 from "fs";
58031
+ import * as path47 from "path";
57887
58032
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
57888
58033
  var MIN_DUPLICATION_LINES = 10;
57889
58034
  function estimateCyclomaticComplexity(content) {
@@ -57921,11 +58066,11 @@ function estimateCyclomaticComplexity(content) {
57921
58066
  }
57922
58067
  function getComplexityForFile(filePath) {
57923
58068
  try {
57924
- const stat2 = fs34.statSync(filePath);
58069
+ const stat2 = fs35.statSync(filePath);
57925
58070
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
57926
58071
  return null;
57927
58072
  }
57928
- const content = fs34.readFileSync(filePath, "utf-8");
58073
+ const content = fs35.readFileSync(filePath, "utf-8");
57929
58074
  return estimateCyclomaticComplexity(content);
57930
58075
  } catch {
57931
58076
  return null;
@@ -57935,8 +58080,8 @@ async function computeComplexityDelta(files, workingDir) {
57935
58080
  let totalComplexity = 0;
57936
58081
  const analyzedFiles = [];
57937
58082
  for (const file3 of files) {
57938
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
57939
- if (!fs34.existsSync(fullPath)) {
58083
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58084
+ if (!fs35.existsSync(fullPath)) {
57940
58085
  continue;
57941
58086
  }
57942
58087
  const complexity = getComplexityForFile(fullPath);
@@ -58057,8 +58202,8 @@ function countGoExports(content) {
58057
58202
  }
58058
58203
  function getExportCountForFile(filePath) {
58059
58204
  try {
58060
- const content = fs34.readFileSync(filePath, "utf-8");
58061
- const ext = path46.extname(filePath).toLowerCase();
58205
+ const content = fs35.readFileSync(filePath, "utf-8");
58206
+ const ext = path47.extname(filePath).toLowerCase();
58062
58207
  switch (ext) {
58063
58208
  case ".ts":
58064
58209
  case ".tsx":
@@ -58084,8 +58229,8 @@ async function computePublicApiDelta(files, workingDir) {
58084
58229
  let totalExports = 0;
58085
58230
  const analyzedFiles = [];
58086
58231
  for (const file3 of files) {
58087
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
58088
- if (!fs34.existsSync(fullPath)) {
58232
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58233
+ if (!fs35.existsSync(fullPath)) {
58089
58234
  continue;
58090
58235
  }
58091
58236
  const exports = getExportCountForFile(fullPath);
@@ -58118,16 +58263,16 @@ async function computeDuplicationRatio(files, workingDir) {
58118
58263
  let duplicateLines = 0;
58119
58264
  const analyzedFiles = [];
58120
58265
  for (const file3 of files) {
58121
- const fullPath = path46.isAbsolute(file3) ? file3 : path46.join(workingDir, file3);
58122
- if (!fs34.existsSync(fullPath)) {
58266
+ const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58267
+ if (!fs35.existsSync(fullPath)) {
58123
58268
  continue;
58124
58269
  }
58125
58270
  try {
58126
- const stat2 = fs34.statSync(fullPath);
58271
+ const stat2 = fs35.statSync(fullPath);
58127
58272
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58128
58273
  continue;
58129
58274
  }
58130
- const content = fs34.readFileSync(fullPath, "utf-8");
58275
+ const content = fs35.readFileSync(fullPath, "utf-8");
58131
58276
  const lines = content.split(`
58132
58277
  `).filter((line) => line.trim().length > 0);
58133
58278
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -58151,8 +58296,8 @@ function countCodeLines(content) {
58151
58296
  return lines.length;
58152
58297
  }
58153
58298
  function isTestFile(filePath) {
58154
- const basename7 = path46.basename(filePath);
58155
- const _ext = path46.extname(filePath).toLowerCase();
58299
+ const basename7 = path47.basename(filePath);
58300
+ const _ext = path47.extname(filePath).toLowerCase();
58156
58301
  const testPatterns = [
58157
58302
  ".test.",
58158
58303
  ".spec.",
@@ -58233,8 +58378,8 @@ function matchGlobSegment(globSegments, pathSegments) {
58233
58378
  }
58234
58379
  return gIndex === globSegments.length && pIndex === pathSegments.length;
58235
58380
  }
58236
- function matchesGlobSegment(path47, glob) {
58237
- const normalizedPath = path47.replace(/\\/g, "/");
58381
+ function matchesGlobSegment(path48, glob) {
58382
+ const normalizedPath = path48.replace(/\\/g, "/");
58238
58383
  const normalizedGlob = glob.replace(/\\/g, "/");
58239
58384
  if (normalizedPath.includes("//")) {
58240
58385
  return false;
@@ -58265,8 +58410,8 @@ function simpleGlobToRegex2(glob) {
58265
58410
  function hasGlobstar(glob) {
58266
58411
  return glob.includes("**");
58267
58412
  }
58268
- function globMatches(path47, glob) {
58269
- const normalizedPath = path47.replace(/\\/g, "/");
58413
+ function globMatches(path48, glob) {
58414
+ const normalizedPath = path48.replace(/\\/g, "/");
58270
58415
  if (!glob || glob === "") {
58271
58416
  if (normalizedPath.includes("//")) {
58272
58417
  return false;
@@ -58302,31 +58447,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
58302
58447
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58303
58448
  let testLines = 0;
58304
58449
  let codeLines = 0;
58305
- const srcDir = path46.join(workingDir, "src");
58306
- if (fs34.existsSync(srcDir)) {
58450
+ const srcDir = path47.join(workingDir, "src");
58451
+ if (fs35.existsSync(srcDir)) {
58307
58452
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
58308
58453
  codeLines += lines;
58309
58454
  });
58310
58455
  }
58311
58456
  const possibleSrcDirs = ["lib", "app", "source", "core"];
58312
58457
  for (const dir of possibleSrcDirs) {
58313
- const dirPath = path46.join(workingDir, dir);
58314
- if (fs34.existsSync(dirPath)) {
58458
+ const dirPath = path47.join(workingDir, dir);
58459
+ if (fs35.existsSync(dirPath)) {
58315
58460
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
58316
58461
  codeLines += lines;
58317
58462
  });
58318
58463
  }
58319
58464
  }
58320
- const testsDir = path46.join(workingDir, "tests");
58321
- if (fs34.existsSync(testsDir)) {
58465
+ const testsDir = path47.join(workingDir, "tests");
58466
+ if (fs35.existsSync(testsDir)) {
58322
58467
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
58323
58468
  testLines += lines;
58324
58469
  });
58325
58470
  }
58326
58471
  const possibleTestDirs = ["test", "__tests__", "specs"];
58327
58472
  for (const dir of possibleTestDirs) {
58328
- const dirPath = path46.join(workingDir, dir);
58329
- if (fs34.existsSync(dirPath) && dirPath !== testsDir) {
58473
+ const dirPath = path47.join(workingDir, dir);
58474
+ if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
58330
58475
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
58331
58476
  testLines += lines;
58332
58477
  });
@@ -58338,9 +58483,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58338
58483
  }
58339
58484
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
58340
58485
  try {
58341
- const entries = fs34.readdirSync(dirPath, { withFileTypes: true });
58486
+ const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
58342
58487
  for (const entry of entries) {
58343
- const fullPath = path46.join(dirPath, entry.name);
58488
+ const fullPath = path47.join(dirPath, entry.name);
58344
58489
  if (entry.isDirectory()) {
58345
58490
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
58346
58491
  continue;
@@ -58348,7 +58493,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58348
58493
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
58349
58494
  } else if (entry.isFile()) {
58350
58495
  const relativePath = fullPath.replace(`${dirPath}/`, "");
58351
- const ext = path46.extname(entry.name).toLowerCase();
58496
+ const ext = path47.extname(entry.name).toLowerCase();
58352
58497
  const validExts = [
58353
58498
  ".ts",
58354
58499
  ".tsx",
@@ -58384,7 +58529,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58384
58529
  continue;
58385
58530
  }
58386
58531
  try {
58387
- const content = fs34.readFileSync(fullPath, "utf-8");
58532
+ const content = fs35.readFileSync(fullPath, "utf-8");
58388
58533
  const lines = countCodeLines(content);
58389
58534
  callback(lines);
58390
58535
  } catch {}
@@ -58563,8 +58708,10 @@ async function getGitChurn(days, directory) {
58563
58708
  stderr: "pipe",
58564
58709
  cwd: directory
58565
58710
  });
58566
- const stdout = await new Response(proc.stdout).text();
58567
- await proc.exited;
58711
+ const [stdout] = await Promise.all([
58712
+ new Response(proc.stdout).text(),
58713
+ proc.exited
58714
+ ]);
58568
58715
  const lines = stdout.split(/\r?\n/);
58569
58716
  for (const line of lines) {
58570
58717
  const normalizedPath = line.replace(/\\/g, "/");
@@ -58583,11 +58730,11 @@ async function getGitChurn(days, directory) {
58583
58730
  }
58584
58731
  function getComplexityForFile2(filePath) {
58585
58732
  try {
58586
- const stat2 = fs35.statSync(filePath);
58733
+ const stat2 = fs36.statSync(filePath);
58587
58734
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
58588
58735
  return null;
58589
58736
  }
58590
- const content = fs35.readFileSync(filePath, "utf-8");
58737
+ const content = fs36.readFileSync(filePath, "utf-8");
58591
58738
  return estimateCyclomaticComplexity(content);
58592
58739
  } catch {
58593
58740
  return null;
@@ -58598,7 +58745,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58598
58745
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
58599
58746
  const filteredChurn = new Map;
58600
58747
  for (const [file3, count] of churnMap) {
58601
- const ext = path47.extname(file3).toLowerCase();
58748
+ const ext = path48.extname(file3).toLowerCase();
58602
58749
  if (extSet.has(ext)) {
58603
58750
  filteredChurn.set(file3, count);
58604
58751
  }
@@ -58608,8 +58755,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58608
58755
  let analyzedFiles = 0;
58609
58756
  for (const [file3, churnCount] of filteredChurn) {
58610
58757
  let fullPath = file3;
58611
- if (!fs35.existsSync(fullPath)) {
58612
- fullPath = path47.join(cwd, file3);
58758
+ if (!fs36.existsSync(fullPath)) {
58759
+ fullPath = path48.join(cwd, file3);
58613
58760
  }
58614
58761
  const complexity = getComplexityForFile2(fullPath);
58615
58762
  if (complexity !== null) {
@@ -58817,8 +58964,8 @@ var curator_analyze = createSwarmTool({
58817
58964
  });
58818
58965
  // src/tools/declare-scope.ts
58819
58966
  init_tool();
58820
- import * as fs36 from "fs";
58821
- import * as path48 from "path";
58967
+ import * as fs37 from "fs";
58968
+ import * as path49 from "path";
58822
58969
  init_create_tool();
58823
58970
  function validateTaskIdFormat(taskId) {
58824
58971
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -58897,8 +59044,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58897
59044
  };
58898
59045
  }
58899
59046
  }
58900
- normalizedDir = path48.normalize(args2.working_directory);
58901
- const pathParts = normalizedDir.split(path48.sep);
59047
+ normalizedDir = path49.normalize(args2.working_directory);
59048
+ const pathParts = normalizedDir.split(path49.sep);
58902
59049
  if (pathParts.includes("..")) {
58903
59050
  return {
58904
59051
  success: false,
@@ -58908,11 +59055,11 @@ async function executeDeclareScope(args2, fallbackDir) {
58908
59055
  ]
58909
59056
  };
58910
59057
  }
58911
- const resolvedDir = path48.resolve(normalizedDir);
59058
+ const resolvedDir = path49.resolve(normalizedDir);
58912
59059
  try {
58913
- const realPath = fs36.realpathSync(resolvedDir);
58914
- const planPath2 = path48.join(realPath, ".swarm", "plan.json");
58915
- if (!fs36.existsSync(planPath2)) {
59060
+ const realPath = fs37.realpathSync(resolvedDir);
59061
+ const planPath2 = path49.join(realPath, ".swarm", "plan.json");
59062
+ if (!fs37.existsSync(planPath2)) {
58916
59063
  return {
58917
59064
  success: false,
58918
59065
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -58935,8 +59082,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58935
59082
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
58936
59083
  }
58937
59084
  const directory = normalizedDir || fallbackDir;
58938
- const planPath = path48.resolve(directory, ".swarm", "plan.json");
58939
- if (!fs36.existsSync(planPath)) {
59085
+ const planPath = path49.resolve(directory, ".swarm", "plan.json");
59086
+ if (!fs37.existsSync(planPath)) {
58940
59087
  return {
58941
59088
  success: false,
58942
59089
  message: "No plan found",
@@ -58945,7 +59092,7 @@ async function executeDeclareScope(args2, fallbackDir) {
58945
59092
  }
58946
59093
  let planContent;
58947
59094
  try {
58948
- planContent = JSON.parse(fs36.readFileSync(planPath, "utf-8"));
59095
+ planContent = JSON.parse(fs37.readFileSync(planPath, "utf-8"));
58949
59096
  } catch {
58950
59097
  return {
58951
59098
  success: false,
@@ -58977,8 +59124,8 @@ async function executeDeclareScope(args2, fallbackDir) {
58977
59124
  const normalizeErrors = [];
58978
59125
  const dir = normalizedDir || fallbackDir || process.cwd();
58979
59126
  const mergedFiles = rawMergedFiles.map((file3) => {
58980
- if (path48.isAbsolute(file3)) {
58981
- const relativePath = path48.relative(dir, file3).replace(/\\/g, "/");
59127
+ if (path49.isAbsolute(file3)) {
59128
+ const relativePath = path49.relative(dir, file3).replace(/\\/g, "/");
58982
59129
  if (relativePath.startsWith("..")) {
58983
59130
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
58984
59131
  return file3;
@@ -59304,20 +59451,20 @@ function validateBase(base) {
59304
59451
  function validatePaths(paths) {
59305
59452
  if (!paths)
59306
59453
  return null;
59307
- for (const path50 of paths) {
59308
- if (!path50 || path50.length === 0) {
59454
+ for (const path51 of paths) {
59455
+ if (!path51 || path51.length === 0) {
59309
59456
  return "empty path not allowed";
59310
59457
  }
59311
- if (path50.length > MAX_PATH_LENGTH) {
59458
+ if (path51.length > MAX_PATH_LENGTH) {
59312
59459
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
59313
59460
  }
59314
- if (SHELL_METACHARACTERS2.test(path50)) {
59461
+ if (SHELL_METACHARACTERS2.test(path51)) {
59315
59462
  return "path contains shell metacharacters";
59316
59463
  }
59317
- if (path50.startsWith("-")) {
59464
+ if (path51.startsWith("-")) {
59318
59465
  return 'path cannot start with "-" (option-like arguments not allowed)';
59319
59466
  }
59320
- if (CONTROL_CHAR_PATTERN2.test(path50)) {
59467
+ if (CONTROL_CHAR_PATTERN2.test(path51)) {
59321
59468
  return "path contains control characters";
59322
59469
  }
59323
59470
  }
@@ -59398,8 +59545,8 @@ var diff = createSwarmTool({
59398
59545
  if (parts2.length >= 3) {
59399
59546
  const additions = parseInt(parts2[0], 10) || 0;
59400
59547
  const deletions = parseInt(parts2[1], 10) || 0;
59401
- const path50 = parts2[2];
59402
- files.push({ path: path50, additions, deletions });
59548
+ const path51 = parts2[2];
59549
+ files.push({ path: path51, additions, deletions });
59403
59550
  }
59404
59551
  }
59405
59552
  const contractChanges = [];
@@ -59681,8 +59828,8 @@ Use these as DOMAIN values when delegating to @sme.`;
59681
59828
  // src/tools/evidence-check.ts
59682
59829
  init_dist();
59683
59830
  init_create_tool();
59684
- import * as fs37 from "fs";
59685
- import * as path50 from "path";
59831
+ import * as fs38 from "fs";
59832
+ import * as path51 from "path";
59686
59833
  var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
59687
59834
  var MAX_EVIDENCE_FILES = 1000;
59688
59835
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -59709,9 +59856,9 @@ function validateRequiredTypes(input) {
59709
59856
  return null;
59710
59857
  }
59711
59858
  function isPathWithinSwarm2(filePath, cwd) {
59712
- const normalizedCwd = path50.resolve(cwd);
59713
- const swarmPath = path50.join(normalizedCwd, ".swarm");
59714
- const normalizedPath = path50.resolve(filePath);
59859
+ const normalizedCwd = path51.resolve(cwd);
59860
+ const swarmPath = path51.join(normalizedCwd, ".swarm");
59861
+ const normalizedPath = path51.resolve(filePath);
59715
59862
  return normalizedPath.startsWith(swarmPath);
59716
59863
  }
59717
59864
  function parseCompletedTasks(planContent) {
@@ -59727,12 +59874,12 @@ function parseCompletedTasks(planContent) {
59727
59874
  }
59728
59875
  function readEvidenceFiles(evidenceDir, _cwd) {
59729
59876
  const evidence = [];
59730
- if (!fs37.existsSync(evidenceDir) || !fs37.statSync(evidenceDir).isDirectory()) {
59877
+ if (!fs38.existsSync(evidenceDir) || !fs38.statSync(evidenceDir).isDirectory()) {
59731
59878
  return evidence;
59732
59879
  }
59733
59880
  let files;
59734
59881
  try {
59735
- files = fs37.readdirSync(evidenceDir);
59882
+ files = fs38.readdirSync(evidenceDir);
59736
59883
  } catch {
59737
59884
  return evidence;
59738
59885
  }
@@ -59741,14 +59888,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59741
59888
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
59742
59889
  continue;
59743
59890
  }
59744
- const filePath = path50.join(evidenceDir, filename);
59891
+ const filePath = path51.join(evidenceDir, filename);
59745
59892
  try {
59746
- const resolvedPath = path50.resolve(filePath);
59747
- const evidenceDirResolved = path50.resolve(evidenceDir);
59893
+ const resolvedPath = path51.resolve(filePath);
59894
+ const evidenceDirResolved = path51.resolve(evidenceDir);
59748
59895
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
59749
59896
  continue;
59750
59897
  }
59751
- const stat2 = fs37.lstatSync(filePath);
59898
+ const stat2 = fs38.lstatSync(filePath);
59752
59899
  if (!stat2.isFile()) {
59753
59900
  continue;
59754
59901
  }
@@ -59757,7 +59904,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59757
59904
  }
59758
59905
  let fileStat;
59759
59906
  try {
59760
- fileStat = fs37.statSync(filePath);
59907
+ fileStat = fs38.statSync(filePath);
59761
59908
  if (fileStat.size > MAX_FILE_SIZE_BYTES4) {
59762
59909
  continue;
59763
59910
  }
@@ -59766,7 +59913,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59766
59913
  }
59767
59914
  let content;
59768
59915
  try {
59769
- content = fs37.readFileSync(filePath, "utf-8");
59916
+ content = fs38.readFileSync(filePath, "utf-8");
59770
59917
  } catch {
59771
59918
  continue;
59772
59919
  }
@@ -59862,7 +60009,7 @@ var evidence_check = createSwarmTool({
59862
60009
  return JSON.stringify(errorResult, null, 2);
59863
60010
  }
59864
60011
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
59865
- const planPath = path50.join(cwd, PLAN_FILE);
60012
+ const planPath = path51.join(cwd, PLAN_FILE);
59866
60013
  if (!isPathWithinSwarm2(planPath, cwd)) {
59867
60014
  const errorResult = {
59868
60015
  error: "plan file path validation failed",
@@ -59876,7 +60023,7 @@ var evidence_check = createSwarmTool({
59876
60023
  }
59877
60024
  let planContent;
59878
60025
  try {
59879
- planContent = fs37.readFileSync(planPath, "utf-8");
60026
+ planContent = fs38.readFileSync(planPath, "utf-8");
59880
60027
  } catch {
59881
60028
  const result2 = {
59882
60029
  message: "No completed tasks found in plan.",
@@ -59894,7 +60041,7 @@ var evidence_check = createSwarmTool({
59894
60041
  };
59895
60042
  return JSON.stringify(result2, null, 2);
59896
60043
  }
59897
- const evidenceDir = path50.join(cwd, EVIDENCE_DIR2);
60044
+ const evidenceDir = path51.join(cwd, EVIDENCE_DIR2);
59898
60045
  const evidence = readEvidenceFiles(evidenceDir, cwd);
59899
60046
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
59900
60047
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -59911,8 +60058,8 @@ var evidence_check = createSwarmTool({
59911
60058
  // src/tools/file-extractor.ts
59912
60059
  init_tool();
59913
60060
  init_create_tool();
59914
- import * as fs38 from "fs";
59915
- import * as path51 from "path";
60061
+ import * as fs39 from "fs";
60062
+ import * as path52 from "path";
59916
60063
  var EXT_MAP = {
59917
60064
  python: ".py",
59918
60065
  py: ".py",
@@ -59974,8 +60121,8 @@ var extract_code_blocks = createSwarmTool({
59974
60121
  execute: async (args2, directory) => {
59975
60122
  const { content, output_dir, prefix } = args2;
59976
60123
  const targetDir = output_dir || directory;
59977
- if (!fs38.existsSync(targetDir)) {
59978
- fs38.mkdirSync(targetDir, { recursive: true });
60124
+ if (!fs39.existsSync(targetDir)) {
60125
+ fs39.mkdirSync(targetDir, { recursive: true });
59979
60126
  }
59980
60127
  if (!content) {
59981
60128
  return "Error: content is required";
@@ -59993,16 +60140,16 @@ var extract_code_blocks = createSwarmTool({
59993
60140
  if (prefix) {
59994
60141
  filename = `${prefix}_${filename}`;
59995
60142
  }
59996
- let filepath = path51.join(targetDir, filename);
59997
- const base = path51.basename(filepath, path51.extname(filepath));
59998
- 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);
59999
60146
  let counter = 1;
60000
- while (fs38.existsSync(filepath)) {
60001
- filepath = path51.join(targetDir, `${base}_${counter}${ext}`);
60147
+ while (fs39.existsSync(filepath)) {
60148
+ filepath = path52.join(targetDir, `${base}_${counter}${ext}`);
60002
60149
  counter++;
60003
60150
  }
60004
60151
  try {
60005
- fs38.writeFileSync(filepath, code.trim(), "utf-8");
60152
+ fs39.writeFileSync(filepath, code.trim(), "utf-8");
60006
60153
  savedFiles.push(filepath);
60007
60154
  } catch (error93) {
60008
60155
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -60032,7 +60179,7 @@ init_create_tool();
60032
60179
  var GITINGEST_TIMEOUT_MS = 1e4;
60033
60180
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
60034
60181
  var GITINGEST_MAX_RETRIES = 2;
60035
- var delay = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms));
60182
+ var delay = (ms) => new Promise((resolve18) => setTimeout(resolve18, ms));
60036
60183
  async function fetchGitingest(args2) {
60037
60184
  for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
60038
60185
  try {
@@ -60118,8 +60265,8 @@ var gitingest = createSwarmTool({
60118
60265
  // src/tools/imports.ts
60119
60266
  init_dist();
60120
60267
  init_create_tool();
60121
- import * as fs39 from "fs";
60122
- import * as path52 from "path";
60268
+ import * as fs40 from "fs";
60269
+ import * as path53 from "path";
60123
60270
  var MAX_FILE_PATH_LENGTH2 = 500;
60124
60271
  var MAX_SYMBOL_LENGTH = 256;
60125
60272
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
@@ -60167,7 +60314,7 @@ function validateSymbolInput(symbol3) {
60167
60314
  return null;
60168
60315
  }
60169
60316
  function isBinaryFile2(filePath, buffer) {
60170
- const ext = path52.extname(filePath).toLowerCase();
60317
+ const ext = path53.extname(filePath).toLowerCase();
60171
60318
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
60172
60319
  return false;
60173
60320
  }
@@ -60191,15 +60338,15 @@ function parseImports(content, targetFile, targetSymbol) {
60191
60338
  const imports = [];
60192
60339
  let _resolvedTarget;
60193
60340
  try {
60194
- _resolvedTarget = path52.resolve(targetFile);
60341
+ _resolvedTarget = path53.resolve(targetFile);
60195
60342
  } catch {
60196
60343
  _resolvedTarget = targetFile;
60197
60344
  }
60198
- const targetBasename = path52.basename(targetFile, path52.extname(targetFile));
60345
+ const targetBasename = path53.basename(targetFile, path53.extname(targetFile));
60199
60346
  const targetWithExt = targetFile;
60200
60347
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
60201
- const normalizedTargetWithExt = path52.normalize(targetWithExt).replace(/\\/g, "/");
60202
- const normalizedTargetWithoutExt = path52.normalize(targetWithoutExt).replace(/\\/g, "/");
60348
+ const normalizedTargetWithExt = path53.normalize(targetWithExt).replace(/\\/g, "/");
60349
+ const normalizedTargetWithoutExt = path53.normalize(targetWithoutExt).replace(/\\/g, "/");
60203
60350
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
60204
60351
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
60205
60352
  const modulePath = match[1] || match[2] || match[3];
@@ -60222,9 +60369,9 @@ function parseImports(content, targetFile, targetSymbol) {
60222
60369
  }
60223
60370
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
60224
60371
  let isMatch = false;
60225
- const _targetDir = path52.dirname(targetFile);
60226
- const targetExt = path52.extname(targetFile);
60227
- 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);
60228
60375
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
60229
60376
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
60230
60377
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -60281,7 +60428,7 @@ var SKIP_DIRECTORIES3 = new Set([
60281
60428
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
60282
60429
  let entries;
60283
60430
  try {
60284
- entries = fs39.readdirSync(dir);
60431
+ entries = fs40.readdirSync(dir);
60285
60432
  } catch (e) {
60286
60433
  stats.fileErrors.push({
60287
60434
  path: dir,
@@ -60292,13 +60439,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60292
60439
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
60293
60440
  for (const entry of entries) {
60294
60441
  if (SKIP_DIRECTORIES3.has(entry)) {
60295
- stats.skippedDirs.push(path52.join(dir, entry));
60442
+ stats.skippedDirs.push(path53.join(dir, entry));
60296
60443
  continue;
60297
60444
  }
60298
- const fullPath = path52.join(dir, entry);
60445
+ const fullPath = path53.join(dir, entry);
60299
60446
  let stat2;
60300
60447
  try {
60301
- stat2 = fs39.statSync(fullPath);
60448
+ stat2 = fs40.statSync(fullPath);
60302
60449
  } catch (e) {
60303
60450
  stats.fileErrors.push({
60304
60451
  path: fullPath,
@@ -60309,7 +60456,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60309
60456
  if (stat2.isDirectory()) {
60310
60457
  findSourceFiles(fullPath, files, stats);
60311
60458
  } else if (stat2.isFile()) {
60312
- const ext = path52.extname(fullPath).toLowerCase();
60459
+ const ext = path53.extname(fullPath).toLowerCase();
60313
60460
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
60314
60461
  files.push(fullPath);
60315
60462
  }
@@ -60366,8 +60513,8 @@ var imports = createSwarmTool({
60366
60513
  return JSON.stringify(errorResult, null, 2);
60367
60514
  }
60368
60515
  try {
60369
- const targetFile = path52.resolve(file3);
60370
- if (!fs39.existsSync(targetFile)) {
60516
+ const targetFile = path53.resolve(file3);
60517
+ if (!fs40.existsSync(targetFile)) {
60371
60518
  const errorResult = {
60372
60519
  error: `target file not found: ${file3}`,
60373
60520
  target: file3,
@@ -60377,7 +60524,7 @@ var imports = createSwarmTool({
60377
60524
  };
60378
60525
  return JSON.stringify(errorResult, null, 2);
60379
60526
  }
60380
- const targetStat = fs39.statSync(targetFile);
60527
+ const targetStat = fs40.statSync(targetFile);
60381
60528
  if (!targetStat.isFile()) {
60382
60529
  const errorResult = {
60383
60530
  error: "target must be a file, not a directory",
@@ -60388,7 +60535,7 @@ var imports = createSwarmTool({
60388
60535
  };
60389
60536
  return JSON.stringify(errorResult, null, 2);
60390
60537
  }
60391
- const baseDir = path52.dirname(targetFile);
60538
+ const baseDir = path53.dirname(targetFile);
60392
60539
  const scanStats = {
60393
60540
  skippedDirs: [],
60394
60541
  skippedFiles: 0,
@@ -60403,12 +60550,12 @@ var imports = createSwarmTool({
60403
60550
  if (consumers.length >= MAX_CONSUMERS)
60404
60551
  break;
60405
60552
  try {
60406
- const stat2 = fs39.statSync(filePath);
60553
+ const stat2 = fs40.statSync(filePath);
60407
60554
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
60408
60555
  skippedFileCount++;
60409
60556
  continue;
60410
60557
  }
60411
- const buffer = fs39.readFileSync(filePath);
60558
+ const buffer = fs40.readFileSync(filePath);
60412
60559
  if (isBinaryFile2(filePath, buffer)) {
60413
60560
  skippedFileCount++;
60414
60561
  continue;
@@ -60997,11 +61144,12 @@ init_dist();
60997
61144
  init_config();
60998
61145
  init_schema();
60999
61146
  init_manager();
61000
- import * as fs40 from "fs";
61001
- import * as path53 from "path";
61147
+ import * as fs41 from "fs";
61148
+ import * as path54 from "path";
61002
61149
  init_utils2();
61003
61150
  init_telemetry();
61004
61151
  init_create_tool();
61152
+ init_resolve_working_directory();
61005
61153
  function safeWarn(message, error93) {
61006
61154
  try {
61007
61155
  console.warn(message, error93 instanceof Error ? error93.message : String(error93));
@@ -61218,11 +61366,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61218
61366
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
61219
61367
  }
61220
61368
  try {
61221
- const driftEvidencePath = path53.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61369
+ const driftEvidencePath = path54.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61222
61370
  let driftVerdictFound = false;
61223
61371
  let driftVerdictApproved = false;
61224
61372
  try {
61225
- const driftEvidenceContent = fs40.readFileSync(driftEvidencePath, "utf-8");
61373
+ const driftEvidenceContent = fs41.readFileSync(driftEvidencePath, "utf-8");
61226
61374
  const driftEvidence = JSON.parse(driftEvidenceContent);
61227
61375
  const entries = driftEvidence.entries ?? [];
61228
61376
  for (const entry of entries) {
@@ -61252,14 +61400,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61252
61400
  driftVerdictFound = false;
61253
61401
  }
61254
61402
  if (!driftVerdictFound) {
61255
- const specPath = path53.join(dir, ".swarm", "spec.md");
61256
- const specExists = fs40.existsSync(specPath);
61403
+ const specPath = path54.join(dir, ".swarm", "spec.md");
61404
+ const specExists = fs41.existsSync(specPath);
61257
61405
  if (!specExists) {
61258
61406
  let incompleteTaskCount = 0;
61259
61407
  let planPhaseFound = false;
61260
61408
  try {
61261
61409
  const planPath = validateSwarmPath(dir, "plan.json");
61262
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61410
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61263
61411
  const plan = JSON.parse(planRaw);
61264
61412
  const targetPhase = plan.phases.find((p) => p.id === phase);
61265
61413
  if (targetPhase) {
@@ -61326,7 +61474,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61326
61474
  };
61327
61475
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
61328
61476
  try {
61329
- const projectName = path53.basename(dir);
61477
+ const projectName = path54.basename(dir);
61330
61478
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
61331
61479
  if (curationResult) {
61332
61480
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -61371,7 +61519,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61371
61519
  let phaseRequiredAgents;
61372
61520
  try {
61373
61521
  const planPath = validateSwarmPath(dir, "plan.json");
61374
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61522
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61375
61523
  const plan = JSON.parse(planRaw);
61376
61524
  const phaseObj = plan.phases.find((p) => p.id === phase);
61377
61525
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -61386,7 +61534,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61386
61534
  if (agentsMissing.length > 0) {
61387
61535
  try {
61388
61536
  const planPath = validateSwarmPath(dir, "plan.json");
61389
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61537
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61390
61538
  const plan = JSON.parse(planRaw);
61391
61539
  const targetPhase = plan.phases.find((p) => p.id === phase);
61392
61540
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -61417,7 +61565,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61417
61565
  if (phaseCompleteConfig.regression_sweep?.enforce) {
61418
61566
  try {
61419
61567
  const planPath = validateSwarmPath(dir, "plan.json");
61420
- const planRaw = fs40.readFileSync(planPath, "utf-8");
61568
+ const planRaw = fs41.readFileSync(planPath, "utf-8");
61421
61569
  const plan = JSON.parse(planRaw);
61422
61570
  const targetPhase = plan.phases.find((p) => p.id === phase);
61423
61571
  if (targetPhase) {
@@ -61455,7 +61603,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61455
61603
  };
61456
61604
  try {
61457
61605
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
61458
- fs40.appendFileSync(eventsPath, `${JSON.stringify(event)}
61606
+ fs41.appendFileSync(eventsPath, `${JSON.stringify(event)}
61459
61607
  `, "utf-8");
61460
61608
  } catch (writeError) {
61461
61609
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -61479,12 +61627,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61479
61627
  }
61480
61628
  try {
61481
61629
  const planPath = validateSwarmPath(dir, "plan.json");
61482
- const planJson = fs40.readFileSync(planPath, "utf-8");
61630
+ const planJson = fs41.readFileSync(planPath, "utf-8");
61483
61631
  const plan = JSON.parse(planJson);
61484
61632
  const phaseObj = plan.phases.find((p) => p.id === phase);
61485
61633
  if (phaseObj) {
61486
61634
  phaseObj.status = "completed";
61487
- fs40.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61635
+ fs41.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61488
61636
  `, "utf-8");
61489
61637
  }
61490
61638
  } catch (error93) {
@@ -61509,18 +61657,21 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61509
61657
  var phase_complete = createSwarmTool({
61510
61658
  description: "Mark a phase as complete and track which agents were dispatched. Used for phase completion gating and tracking. Accepts phase number and optional summary. Returns list of agents that were dispatched.",
61511
61659
  args: {
61512
- phase: tool.schema.number().describe("The phase number being completed (e.g., 1, 2, 3)"),
61660
+ phase: tool.schema.number().int().min(1).describe("The phase number being completed \u2014 a positive integer (e.g., 1, 2, 3)"),
61513
61661
  summary: tool.schema.string().optional().describe("Optional summary of what was accomplished in this phase"),
61514
- sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)")
61662
+ sessionID: tool.schema.string().optional().describe("Session ID for tracking state (auto-provided by plugin context)"),
61663
+ working_directory: tool.schema.string().optional().describe("Explicit project root directory. When provided, .swarm/ is resolved relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
61515
61664
  },
61516
61665
  execute: async (args2, directory, ctx) => {
61517
61666
  let phaseCompleteArgs;
61667
+ let workingDirInput;
61518
61668
  try {
61519
61669
  phaseCompleteArgs = {
61520
61670
  phase: Number(args2.phase),
61521
61671
  summary: args2.summary !== undefined ? String(args2.summary) : undefined,
61522
61672
  sessionID: ctx?.sessionID ?? (args2.sessionID !== undefined ? String(args2.sessionID) : undefined)
61523
61673
  };
61674
+ workingDirInput = args2.working_directory !== undefined ? String(args2.working_directory) : undefined;
61524
61675
  } catch {
61525
61676
  return JSON.stringify({
61526
61677
  success: false,
@@ -61530,7 +61681,17 @@ var phase_complete = createSwarmTool({
61530
61681
  warnings: ["Failed to parse arguments"]
61531
61682
  }, null, 2);
61532
61683
  }
61533
- 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);
61534
61695
  }
61535
61696
  });
61536
61697
  // src/tools/pkg-audit.ts
@@ -61538,8 +61699,8 @@ init_dist();
61538
61699
  init_discovery();
61539
61700
  init_utils();
61540
61701
  init_create_tool();
61541
- import * as fs41 from "fs";
61542
- import * as path54 from "path";
61702
+ import * as fs42 from "fs";
61703
+ import * as path55 from "path";
61543
61704
  var MAX_OUTPUT_BYTES5 = 52428800;
61544
61705
  var AUDIT_TIMEOUT_MS = 120000;
61545
61706
  function isValidEcosystem(value) {
@@ -61557,28 +61718,28 @@ function validateArgs3(args2) {
61557
61718
  function detectEcosystems(directory) {
61558
61719
  const ecosystems = [];
61559
61720
  const cwd = directory;
61560
- if (fs41.existsSync(path54.join(cwd, "package.json"))) {
61721
+ if (fs42.existsSync(path55.join(cwd, "package.json"))) {
61561
61722
  ecosystems.push("npm");
61562
61723
  }
61563
- 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"))) {
61564
61725
  ecosystems.push("pip");
61565
61726
  }
61566
- if (fs41.existsSync(path54.join(cwd, "Cargo.toml"))) {
61727
+ if (fs42.existsSync(path55.join(cwd, "Cargo.toml"))) {
61567
61728
  ecosystems.push("cargo");
61568
61729
  }
61569
- if (fs41.existsSync(path54.join(cwd, "go.mod"))) {
61730
+ if (fs42.existsSync(path55.join(cwd, "go.mod"))) {
61570
61731
  ecosystems.push("go");
61571
61732
  }
61572
61733
  try {
61573
- const files = fs41.readdirSync(cwd);
61734
+ const files = fs42.readdirSync(cwd);
61574
61735
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
61575
61736
  ecosystems.push("dotnet");
61576
61737
  }
61577
61738
  } catch {}
61578
- if (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"))) {
61579
61740
  ecosystems.push("ruby");
61580
61741
  }
61581
- if (fs41.existsSync(path54.join(cwd, "pubspec.yaml"))) {
61742
+ if (fs42.existsSync(path55.join(cwd, "pubspec.yaml"))) {
61582
61743
  ecosystems.push("dart");
61583
61744
  }
61584
61745
  return ecosystems;
@@ -61591,7 +61752,7 @@ async function runNpmAudit(directory) {
61591
61752
  stderr: "pipe",
61592
61753
  cwd: directory
61593
61754
  });
61594
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
61755
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61595
61756
  const result = await Promise.race([
61596
61757
  Promise.all([
61597
61758
  new Response(proc.stdout).text(),
@@ -61714,7 +61875,7 @@ async function runPipAudit(directory) {
61714
61875
  stderr: "pipe",
61715
61876
  cwd: directory
61716
61877
  });
61717
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
61878
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61718
61879
  const result = await Promise.race([
61719
61880
  Promise.all([
61720
61881
  new Response(proc.stdout).text(),
@@ -61845,7 +62006,7 @@ async function runCargoAudit(directory) {
61845
62006
  stderr: "pipe",
61846
62007
  cwd: directory
61847
62008
  });
61848
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62009
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61849
62010
  const result = await Promise.race([
61850
62011
  Promise.all([
61851
62012
  new Response(proc.stdout).text(),
@@ -61972,7 +62133,7 @@ async function runGoAudit(directory) {
61972
62133
  stderr: "pipe",
61973
62134
  cwd: directory
61974
62135
  });
61975
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62136
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
61976
62137
  const result = await Promise.race([
61977
62138
  Promise.all([
61978
62139
  new Response(proc.stdout).text(),
@@ -62108,7 +62269,7 @@ async function runDotnetAudit(directory) {
62108
62269
  stderr: "pipe",
62109
62270
  cwd: directory
62110
62271
  });
62111
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62272
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62112
62273
  const result = await Promise.race([
62113
62274
  Promise.all([
62114
62275
  new Response(proc.stdout).text(),
@@ -62227,7 +62388,7 @@ async function runBundleAudit(directory) {
62227
62388
  stderr: "pipe",
62228
62389
  cwd: directory
62229
62390
  });
62230
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62391
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62231
62392
  const result = await Promise.race([
62232
62393
  Promise.all([
62233
62394
  new Response(proc.stdout).text(),
@@ -62374,7 +62535,7 @@ async function runDartAudit(directory) {
62374
62535
  stderr: "pipe",
62375
62536
  cwd: directory
62376
62537
  });
62377
- const timeoutPromise = new Promise((resolve18) => setTimeout(() => resolve18("timeout"), AUDIT_TIMEOUT_MS));
62538
+ const timeoutPromise = new Promise((resolve19) => setTimeout(() => resolve19("timeout"), AUDIT_TIMEOUT_MS));
62378
62539
  const result = await Promise.race([
62379
62540
  Promise.all([
62380
62541
  new Response(proc.stdout).text(),
@@ -62599,8 +62760,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
62599
62760
  ]);
62600
62761
  // src/tools/pre-check-batch.ts
62601
62762
  init_dist();
62602
- import * as fs43 from "fs";
62603
- import * as path56 from "path";
62763
+ import * as fs44 from "fs";
62764
+ import * as path57 from "path";
62604
62765
 
62605
62766
  // node_modules/yocto-queue/index.js
62606
62767
  class Node2 {
@@ -62691,26 +62852,26 @@ function pLimit(concurrency) {
62691
62852
  activeCount--;
62692
62853
  resumeNext();
62693
62854
  };
62694
- const run2 = async (function_, resolve18, arguments_2) => {
62855
+ const run2 = async (function_, resolve19, arguments_2) => {
62695
62856
  const result = (async () => function_(...arguments_2))();
62696
- resolve18(result);
62857
+ resolve19(result);
62697
62858
  try {
62698
62859
  await result;
62699
62860
  } catch {}
62700
62861
  next();
62701
62862
  };
62702
- const enqueue = (function_, resolve18, reject, arguments_2) => {
62863
+ const enqueue = (function_, resolve19, reject, arguments_2) => {
62703
62864
  const queueItem = { reject };
62704
62865
  new Promise((internalResolve) => {
62705
62866
  queueItem.run = internalResolve;
62706
62867
  queue.enqueue(queueItem);
62707
- }).then(run2.bind(undefined, function_, resolve18, arguments_2));
62868
+ }).then(run2.bind(undefined, function_, resolve19, arguments_2));
62708
62869
  if (activeCount < concurrency) {
62709
62870
  resumeNext();
62710
62871
  }
62711
62872
  };
62712
- const generator = (function_, ...arguments_2) => new Promise((resolve18, reject) => {
62713
- enqueue(function_, resolve18, reject, arguments_2);
62873
+ const generator = (function_, ...arguments_2) => new Promise((resolve19, reject) => {
62874
+ enqueue(function_, resolve19, reject, arguments_2);
62714
62875
  });
62715
62876
  Object.defineProperties(generator, {
62716
62877
  activeCount: {
@@ -62874,8 +63035,8 @@ async function qualityBudget(input, directory) {
62874
63035
  init_dist();
62875
63036
  init_manager();
62876
63037
  init_detector();
62877
- import * as fs42 from "fs";
62878
- import * as path55 from "path";
63038
+ import * as fs43 from "fs";
63039
+ import * as path56 from "path";
62879
63040
  import { extname as extname10 } from "path";
62880
63041
 
62881
63042
  // src/sast/rules/c.ts
@@ -63626,7 +63787,7 @@ function mapSemgrepSeverity(severity) {
63626
63787
  }
63627
63788
  }
63628
63789
  async function executeWithTimeout(command, args2, options) {
63629
- return new Promise((resolve18) => {
63790
+ return new Promise((resolve19) => {
63630
63791
  const child = spawn2(command, args2, {
63631
63792
  shell: false,
63632
63793
  cwd: options.cwd
@@ -63635,7 +63796,7 @@ async function executeWithTimeout(command, args2, options) {
63635
63796
  let stderr = "";
63636
63797
  const timeout = setTimeout(() => {
63637
63798
  child.kill("SIGTERM");
63638
- resolve18({
63799
+ resolve19({
63639
63800
  stdout,
63640
63801
  stderr: "Process timed out",
63641
63802
  exitCode: 124
@@ -63649,7 +63810,7 @@ async function executeWithTimeout(command, args2, options) {
63649
63810
  });
63650
63811
  child.on("close", (code) => {
63651
63812
  clearTimeout(timeout);
63652
- resolve18({
63813
+ resolve19({
63653
63814
  stdout,
63654
63815
  stderr,
63655
63816
  exitCode: code ?? 0
@@ -63657,7 +63818,7 @@ async function executeWithTimeout(command, args2, options) {
63657
63818
  });
63658
63819
  child.on("error", (err2) => {
63659
63820
  clearTimeout(timeout);
63660
- resolve18({
63821
+ resolve19({
63661
63822
  stdout,
63662
63823
  stderr: err2.message,
63663
63824
  exitCode: 1
@@ -63745,17 +63906,17 @@ var SEVERITY_ORDER = {
63745
63906
  };
63746
63907
  function shouldSkipFile(filePath) {
63747
63908
  try {
63748
- const stats = fs42.statSync(filePath);
63909
+ const stats = fs43.statSync(filePath);
63749
63910
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
63750
63911
  return { skip: true, reason: "file too large" };
63751
63912
  }
63752
63913
  if (stats.size === 0) {
63753
63914
  return { skip: true, reason: "empty file" };
63754
63915
  }
63755
- const fd = fs42.openSync(filePath, "r");
63916
+ const fd = fs43.openSync(filePath, "r");
63756
63917
  const buffer = Buffer.alloc(8192);
63757
- const bytesRead = fs42.readSync(fd, buffer, 0, 8192, 0);
63758
- fs42.closeSync(fd);
63918
+ const bytesRead = fs43.readSync(fd, buffer, 0, 8192, 0);
63919
+ fs43.closeSync(fd);
63759
63920
  if (bytesRead > 0) {
63760
63921
  let nullCount = 0;
63761
63922
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -63794,7 +63955,7 @@ function countBySeverity(findings) {
63794
63955
  }
63795
63956
  function scanFileWithTierA(filePath, language) {
63796
63957
  try {
63797
- const content = fs42.readFileSync(filePath, "utf-8");
63958
+ const content = fs43.readFileSync(filePath, "utf-8");
63798
63959
  const findings = executeRulesSync(filePath, content, language);
63799
63960
  return findings.map((f) => ({
63800
63961
  rule_id: f.rule_id,
@@ -63841,8 +64002,8 @@ async function sastScan(input, directory, config3) {
63841
64002
  _filesSkipped++;
63842
64003
  continue;
63843
64004
  }
63844
- const resolvedPath = path55.isAbsolute(filePath) ? filePath : path55.resolve(directory, filePath);
63845
- if (!fs42.existsSync(resolvedPath)) {
64005
+ const resolvedPath = path56.isAbsolute(filePath) ? filePath : path56.resolve(directory, filePath);
64006
+ if (!fs43.existsSync(resolvedPath)) {
63846
64007
  _filesSkipped++;
63847
64008
  continue;
63848
64009
  }
@@ -64040,20 +64201,20 @@ function validatePath(inputPath, baseDir, workspaceDir) {
64040
64201
  let resolved;
64041
64202
  const isWinAbs = isWindowsAbsolutePath(inputPath);
64042
64203
  if (isWinAbs) {
64043
- resolved = path56.win32.resolve(inputPath);
64044
- } else if (path56.isAbsolute(inputPath)) {
64045
- resolved = path56.resolve(inputPath);
64204
+ resolved = path57.win32.resolve(inputPath);
64205
+ } else if (path57.isAbsolute(inputPath)) {
64206
+ resolved = path57.resolve(inputPath);
64046
64207
  } else {
64047
- resolved = path56.resolve(baseDir, inputPath);
64208
+ resolved = path57.resolve(baseDir, inputPath);
64048
64209
  }
64049
- const workspaceResolved = path56.resolve(workspaceDir);
64050
- let relative7;
64210
+ const workspaceResolved = path57.resolve(workspaceDir);
64211
+ let relative8;
64051
64212
  if (isWinAbs) {
64052
- relative7 = path56.win32.relative(workspaceResolved, resolved);
64213
+ relative8 = path57.win32.relative(workspaceResolved, resolved);
64053
64214
  } else {
64054
- relative7 = path56.relative(workspaceResolved, resolved);
64215
+ relative8 = path57.relative(workspaceResolved, resolved);
64055
64216
  }
64056
- if (relative7.startsWith("..")) {
64217
+ if (relative8.startsWith("..")) {
64057
64218
  return "path traversal detected";
64058
64219
  }
64059
64220
  return null;
@@ -64112,13 +64273,13 @@ async function runLintWrapped(files, directory, _config) {
64112
64273
  }
64113
64274
  async function runLintOnFiles(linter, files, workspaceDir) {
64114
64275
  const isWindows = process.platform === "win32";
64115
- const binDir = path56.join(workspaceDir, "node_modules", ".bin");
64276
+ const binDir = path57.join(workspaceDir, "node_modules", ".bin");
64116
64277
  const validatedFiles = [];
64117
64278
  for (const file3 of files) {
64118
64279
  if (typeof file3 !== "string") {
64119
64280
  continue;
64120
64281
  }
64121
- const resolvedPath = path56.resolve(file3);
64282
+ const resolvedPath = path57.resolve(file3);
64122
64283
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
64123
64284
  if (validationError) {
64124
64285
  continue;
@@ -64136,10 +64297,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
64136
64297
  }
64137
64298
  let command;
64138
64299
  if (linter === "biome") {
64139
- const biomeBin = isWindows ? path56.join(binDir, "biome.EXE") : path56.join(binDir, "biome");
64300
+ const biomeBin = isWindows ? path57.join(binDir, "biome.EXE") : path57.join(binDir, "biome");
64140
64301
  command = [biomeBin, "check", ...validatedFiles];
64141
64302
  } else {
64142
- const eslintBin = isWindows ? path56.join(binDir, "eslint.cmd") : path56.join(binDir, "eslint");
64303
+ const eslintBin = isWindows ? path57.join(binDir, "eslint.cmd") : path57.join(binDir, "eslint");
64143
64304
  command = [eslintBin, ...validatedFiles];
64144
64305
  }
64145
64306
  try {
@@ -64276,7 +64437,7 @@ async function runSecretscanWithFiles(files, directory) {
64276
64437
  skippedFiles++;
64277
64438
  continue;
64278
64439
  }
64279
- const resolvedPath = path56.resolve(file3);
64440
+ const resolvedPath = path57.resolve(file3);
64280
64441
  const validationError = validatePath(resolvedPath, directory, directory);
64281
64442
  if (validationError) {
64282
64443
  skippedFiles++;
@@ -64294,14 +64455,14 @@ async function runSecretscanWithFiles(files, directory) {
64294
64455
  };
64295
64456
  }
64296
64457
  for (const file3 of validatedFiles) {
64297
- const ext = path56.extname(file3).toLowerCase();
64458
+ const ext = path57.extname(file3).toLowerCase();
64298
64459
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
64299
64460
  skippedFiles++;
64300
64461
  continue;
64301
64462
  }
64302
64463
  let stat2;
64303
64464
  try {
64304
- stat2 = fs43.statSync(file3);
64465
+ stat2 = fs44.statSync(file3);
64305
64466
  } catch {
64306
64467
  skippedFiles++;
64307
64468
  continue;
@@ -64312,7 +64473,7 @@ async function runSecretscanWithFiles(files, directory) {
64312
64473
  }
64313
64474
  let content;
64314
64475
  try {
64315
- const buffer = fs43.readFileSync(file3);
64476
+ const buffer = fs44.readFileSync(file3);
64316
64477
  if (buffer.includes(0)) {
64317
64478
  skippedFiles++;
64318
64479
  continue;
@@ -64500,7 +64661,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
64500
64661
  const preexistingFindings = [];
64501
64662
  for (const finding of findings) {
64502
64663
  const filePath = finding.location.file;
64503
- const normalised = path56.relative(directory, filePath).replace(/\\/g, "/");
64664
+ const normalised = path57.relative(directory, filePath).replace(/\\/g, "/");
64504
64665
  const changedLines = changedLineRanges.get(normalised);
64505
64666
  if (changedLines && changedLines.has(finding.location.line)) {
64506
64667
  newFindings.push(finding);
@@ -64551,7 +64712,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
64551
64712
  warn(`pre_check_batch: Invalid file path: ${file3}`);
64552
64713
  continue;
64553
64714
  }
64554
- changedFiles.push(path56.resolve(directory, file3));
64715
+ changedFiles.push(path57.resolve(directory, file3));
64555
64716
  }
64556
64717
  if (changedFiles.length === 0) {
64557
64718
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -64739,7 +64900,7 @@ var pre_check_batch = createSwarmTool({
64739
64900
  };
64740
64901
  return JSON.stringify(errorResult, null, 2);
64741
64902
  }
64742
- const resolvedDirectory = path56.resolve(typedArgs.directory);
64903
+ const resolvedDirectory = path57.resolve(typedArgs.directory);
64743
64904
  const workspaceAnchor = resolvedDirectory;
64744
64905
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
64745
64906
  if (dirError) {
@@ -64845,38 +65006,38 @@ ${paginatedContent}`;
64845
65006
  });
64846
65007
  // src/tools/save-plan.ts
64847
65008
  init_tool();
64848
- import * as fs45 from "fs";
64849
- import * as path58 from "path";
65009
+ import * as fs46 from "fs";
65010
+ import * as path59 from "path";
64850
65011
 
64851
65012
  // src/parallel/file-locks.ts
64852
- import * as fs44 from "fs";
64853
- import * as path57 from "path";
65013
+ import * as fs45 from "fs";
65014
+ import * as path58 from "path";
64854
65015
  var LOCKS_DIR = ".swarm/locks";
64855
65016
  var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
64856
65017
  function getLockFilePath(directory, filePath) {
64857
- const normalized = path57.resolve(directory, filePath);
64858
- if (!normalized.startsWith(path57.resolve(directory))) {
65018
+ const normalized = path58.resolve(directory, filePath);
65019
+ if (!normalized.startsWith(path58.resolve(directory))) {
64859
65020
  throw new Error("Invalid file path: path traversal not allowed");
64860
65021
  }
64861
65022
  const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
64862
- return path57.join(directory, LOCKS_DIR, `${hash3}.lock`);
65023
+ return path58.join(directory, LOCKS_DIR, `${hash3}.lock`);
64863
65024
  }
64864
65025
  function tryAcquireLock(directory, filePath, agent, taskId) {
64865
65026
  const lockPath = getLockFilePath(directory, filePath);
64866
- const locksDir = path57.dirname(lockPath);
64867
- if (!fs44.existsSync(locksDir)) {
64868
- fs44.mkdirSync(locksDir, { recursive: true });
65027
+ const locksDir = path58.dirname(lockPath);
65028
+ if (!fs45.existsSync(locksDir)) {
65029
+ fs45.mkdirSync(locksDir, { recursive: true });
64869
65030
  }
64870
- if (fs44.existsSync(lockPath)) {
65031
+ if (fs45.existsSync(lockPath)) {
64871
65032
  try {
64872
- const existingLock = JSON.parse(fs44.readFileSync(lockPath, "utf-8"));
65033
+ const existingLock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
64873
65034
  if (Date.now() > existingLock.expiresAt) {
64874
- fs44.unlinkSync(lockPath);
65035
+ fs45.unlinkSync(lockPath);
64875
65036
  } else {
64876
65037
  return { acquired: false, existing: existingLock };
64877
65038
  }
64878
65039
  } catch {
64879
- fs44.unlinkSync(lockPath);
65040
+ fs45.unlinkSync(lockPath);
64880
65041
  }
64881
65042
  }
64882
65043
  const lock = {
@@ -64887,24 +65048,24 @@ function tryAcquireLock(directory, filePath, agent, taskId) {
64887
65048
  expiresAt: Date.now() + LOCK_TIMEOUT_MS
64888
65049
  };
64889
65050
  const tempPath = `${lockPath}.tmp`;
64890
- fs44.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
64891
- fs44.renameSync(tempPath, lockPath);
65051
+ fs45.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65052
+ fs45.renameSync(tempPath, lockPath);
64892
65053
  return { acquired: true, lock };
64893
65054
  }
64894
65055
  function releaseLock(directory, filePath, taskId) {
64895
65056
  const lockPath = getLockFilePath(directory, filePath);
64896
- if (!fs44.existsSync(lockPath)) {
65057
+ if (!fs45.existsSync(lockPath)) {
64897
65058
  return true;
64898
65059
  }
64899
65060
  try {
64900
- const lock = JSON.parse(fs44.readFileSync(lockPath, "utf-8"));
65061
+ const lock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
64901
65062
  if (lock.taskId === taskId) {
64902
- fs44.unlinkSync(lockPath);
65063
+ fs45.unlinkSync(lockPath);
64903
65064
  return true;
64904
65065
  }
64905
65066
  return false;
64906
65067
  } catch {
64907
- fs44.unlinkSync(lockPath);
65068
+ fs45.unlinkSync(lockPath);
64908
65069
  return true;
64909
65070
  }
64910
65071
  }
@@ -64962,7 +65123,7 @@ async function executeSavePlan(args2, fallbackDir) {
64962
65123
  success: false,
64963
65124
  message: "Plan rejected: invalid phase or task IDs",
64964
65125
  errors: validationErrors,
64965
- recovery_guidance: "Use save_plan with corrected inputs to create or restructure plans. Never write .swarm/plan.json or .swarm/plan.md directly."
65126
+ recovery_guidance: "Phase IDs must be positive integers: 1, 2, 3 (not 0, -1, or decimals). " + 'Task IDs must use N.M format: "1.1", "2.3", "3.1". ' + "Call save_plan again with corrected ids. " + "Never write .swarm/plan.json or .swarm/plan.md directly."
64966
65127
  };
64967
65128
  }
64968
65129
  const placeholderIssues = detectPlaceholderContent(args2);
@@ -65029,14 +65190,14 @@ async function executeSavePlan(args2, fallbackDir) {
65029
65190
  try {
65030
65191
  await savePlan(dir, plan);
65031
65192
  try {
65032
- const markerPath = path58.join(dir, ".swarm", ".plan-write-marker");
65193
+ const markerPath = path59.join(dir, ".swarm", ".plan-write-marker");
65033
65194
  const marker = JSON.stringify({
65034
65195
  source: "save_plan",
65035
65196
  timestamp: new Date().toISOString(),
65036
65197
  phases_count: plan.phases.length,
65037
65198
  tasks_count: tasksCount
65038
65199
  });
65039
- await fs45.promises.writeFile(markerPath, marker, "utf8");
65200
+ await fs46.promises.writeFile(markerPath, marker, "utf8");
65040
65201
  } catch {}
65041
65202
  const warnings = [];
65042
65203
  let criticReviewFound = false;
@@ -65052,7 +65213,7 @@ async function executeSavePlan(args2, fallbackDir) {
65052
65213
  return {
65053
65214
  success: true,
65054
65215
  message: "Plan saved successfully",
65055
- plan_path: path58.join(dir, ".swarm", "plan.json"),
65216
+ plan_path: path59.join(dir, ".swarm", "plan.json"),
65056
65217
  phases_count: plan.phases.length,
65057
65218
  tasks_count: tasksCount,
65058
65219
  ...warnings.length > 0 ? { warnings } : {}
@@ -65075,7 +65236,7 @@ var save_plan = createSwarmTool({
65075
65236
  title: tool.schema.string().min(1).describe("Plan title \u2014 the REAL project name from the spec. NOT a placeholder like [Project]."),
65076
65237
  swarm_id: tool.schema.string().min(1).describe('Swarm identifier (e.g. "mega")'),
65077
65238
  phases: tool.schema.array(tool.schema.object({
65078
- id: tool.schema.number().int().positive().describe("Phase number, starting at 1"),
65239
+ id: tool.schema.number().int().min(1).describe("Phase number \u2014 a positive integer starting at 1. Use 1, 2, 3, etc."),
65079
65240
  name: tool.schema.string().min(1).describe("Descriptive phase name derived from the spec"),
65080
65241
  tasks: tool.schema.array(tool.schema.object({
65081
65242
  id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M format, e.g. "1.1"').describe('Task ID in N.M format, e.g. "1.1", "2.3"'),
@@ -65094,8 +65255,8 @@ var save_plan = createSwarmTool({
65094
65255
  // src/tools/sbom-generate.ts
65095
65256
  init_dist();
65096
65257
  init_manager();
65097
- import * as fs46 from "fs";
65098
- import * as path59 from "path";
65258
+ import * as fs47 from "fs";
65259
+ import * as path60 from "path";
65099
65260
 
65100
65261
  // src/sbom/detectors/index.ts
65101
65262
  init_utils();
@@ -65943,9 +66104,9 @@ function findManifestFiles(rootDir) {
65943
66104
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
65944
66105
  function searchDir(dir) {
65945
66106
  try {
65946
- const entries = fs46.readdirSync(dir, { withFileTypes: true });
66107
+ const entries = fs47.readdirSync(dir, { withFileTypes: true });
65947
66108
  for (const entry of entries) {
65948
- const fullPath = path59.join(dir, entry.name);
66109
+ const fullPath = path60.join(dir, entry.name);
65949
66110
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
65950
66111
  continue;
65951
66112
  }
@@ -65954,7 +66115,7 @@ function findManifestFiles(rootDir) {
65954
66115
  } else if (entry.isFile()) {
65955
66116
  for (const pattern of patterns) {
65956
66117
  if (simpleGlobToRegex(pattern).test(entry.name)) {
65957
- manifestFiles.push(path59.relative(rootDir, fullPath));
66118
+ manifestFiles.push(path60.relative(rootDir, fullPath));
65958
66119
  break;
65959
66120
  }
65960
66121
  }
@@ -65970,13 +66131,13 @@ function findManifestFilesInDirs(directories, workingDir) {
65970
66131
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
65971
66132
  for (const dir of directories) {
65972
66133
  try {
65973
- const entries = fs46.readdirSync(dir, { withFileTypes: true });
66134
+ const entries = fs47.readdirSync(dir, { withFileTypes: true });
65974
66135
  for (const entry of entries) {
65975
- const fullPath = path59.join(dir, entry.name);
66136
+ const fullPath = path60.join(dir, entry.name);
65976
66137
  if (entry.isFile()) {
65977
66138
  for (const pattern of patterns) {
65978
66139
  if (simpleGlobToRegex(pattern).test(entry.name)) {
65979
- found.push(path59.relative(workingDir, fullPath));
66140
+ found.push(path60.relative(workingDir, fullPath));
65980
66141
  break;
65981
66142
  }
65982
66143
  }
@@ -65989,11 +66150,11 @@ function findManifestFilesInDirs(directories, workingDir) {
65989
66150
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
65990
66151
  const dirs = new Set;
65991
66152
  for (const file3 of changedFiles) {
65992
- let currentDir = path59.dirname(file3);
66153
+ let currentDir = path60.dirname(file3);
65993
66154
  while (true) {
65994
- if (currentDir && currentDir !== "." && currentDir !== path59.sep) {
65995
- dirs.add(path59.join(workingDir, currentDir));
65996
- 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);
65997
66158
  if (parent === currentDir)
65998
66159
  break;
65999
66160
  currentDir = parent;
@@ -66007,7 +66168,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66007
66168
  }
66008
66169
  function ensureOutputDir(outputDir) {
66009
66170
  try {
66010
- fs46.mkdirSync(outputDir, { recursive: true });
66171
+ fs47.mkdirSync(outputDir, { recursive: true });
66011
66172
  } catch (error93) {
66012
66173
  if (!error93 || error93.code !== "EEXIST") {
66013
66174
  throw error93;
@@ -66077,7 +66238,7 @@ var sbom_generate = createSwarmTool({
66077
66238
  const changedFiles = obj.changed_files;
66078
66239
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
66079
66240
  const workingDir = directory;
66080
- const outputDir = path59.isAbsolute(relativeOutputDir) ? relativeOutputDir : path59.join(workingDir, relativeOutputDir);
66241
+ const outputDir = path60.isAbsolute(relativeOutputDir) ? relativeOutputDir : path60.join(workingDir, relativeOutputDir);
66081
66242
  let manifestFiles = [];
66082
66243
  if (scope === "all") {
66083
66244
  manifestFiles = findManifestFiles(workingDir);
@@ -66100,11 +66261,11 @@ var sbom_generate = createSwarmTool({
66100
66261
  const processedFiles = [];
66101
66262
  for (const manifestFile of manifestFiles) {
66102
66263
  try {
66103
- const fullPath = path59.isAbsolute(manifestFile) ? manifestFile : path59.join(workingDir, manifestFile);
66104
- if (!fs46.existsSync(fullPath)) {
66264
+ const fullPath = path60.isAbsolute(manifestFile) ? manifestFile : path60.join(workingDir, manifestFile);
66265
+ if (!fs47.existsSync(fullPath)) {
66105
66266
  continue;
66106
66267
  }
66107
- const content = fs46.readFileSync(fullPath, "utf-8");
66268
+ const content = fs47.readFileSync(fullPath, "utf-8");
66108
66269
  const components = detectComponents(manifestFile, content);
66109
66270
  processedFiles.push(manifestFile);
66110
66271
  if (components.length > 0) {
@@ -66117,8 +66278,8 @@ var sbom_generate = createSwarmTool({
66117
66278
  const bom = generateCycloneDX(allComponents);
66118
66279
  const bomJson = serializeCycloneDX(bom);
66119
66280
  const filename = generateSbomFilename();
66120
- const outputPath = path59.join(outputDir, filename);
66121
- fs46.writeFileSync(outputPath, bomJson, "utf-8");
66281
+ const outputPath = path60.join(outputDir, filename);
66282
+ fs47.writeFileSync(outputPath, bomJson, "utf-8");
66122
66283
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
66123
66284
  try {
66124
66285
  const timestamp = new Date().toISOString();
@@ -66160,8 +66321,8 @@ var sbom_generate = createSwarmTool({
66160
66321
  // src/tools/schema-drift.ts
66161
66322
  init_dist();
66162
66323
  init_create_tool();
66163
- import * as fs47 from "fs";
66164
- import * as path60 from "path";
66324
+ import * as fs48 from "fs";
66325
+ import * as path61 from "path";
66165
66326
  var SPEC_CANDIDATES = [
66166
66327
  "openapi.json",
66167
66328
  "openapi.yaml",
@@ -66193,28 +66354,28 @@ function normalizePath2(p) {
66193
66354
  }
66194
66355
  function discoverSpecFile(cwd, specFileArg) {
66195
66356
  if (specFileArg) {
66196
- const resolvedPath = path60.resolve(cwd, specFileArg);
66197
- 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;
66198
66359
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
66199
66360
  throw new Error("Invalid spec_file: path traversal detected");
66200
66361
  }
66201
- const ext = path60.extname(resolvedPath).toLowerCase();
66362
+ const ext = path61.extname(resolvedPath).toLowerCase();
66202
66363
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
66203
66364
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
66204
66365
  }
66205
- const stats = fs47.statSync(resolvedPath);
66366
+ const stats = fs48.statSync(resolvedPath);
66206
66367
  if (stats.size > MAX_SPEC_SIZE) {
66207
66368
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
66208
66369
  }
66209
- if (!fs47.existsSync(resolvedPath)) {
66370
+ if (!fs48.existsSync(resolvedPath)) {
66210
66371
  throw new Error(`Spec file not found: ${resolvedPath}`);
66211
66372
  }
66212
66373
  return resolvedPath;
66213
66374
  }
66214
66375
  for (const candidate of SPEC_CANDIDATES) {
66215
- const candidatePath = path60.resolve(cwd, candidate);
66216
- if (fs47.existsSync(candidatePath)) {
66217
- const stats = fs47.statSync(candidatePath);
66376
+ const candidatePath = path61.resolve(cwd, candidate);
66377
+ if (fs48.existsSync(candidatePath)) {
66378
+ const stats = fs48.statSync(candidatePath);
66218
66379
  if (stats.size <= MAX_SPEC_SIZE) {
66219
66380
  return candidatePath;
66220
66381
  }
@@ -66223,8 +66384,8 @@ function discoverSpecFile(cwd, specFileArg) {
66223
66384
  return null;
66224
66385
  }
66225
66386
  function parseSpec(specFile) {
66226
- const content = fs47.readFileSync(specFile, "utf-8");
66227
- const ext = path60.extname(specFile).toLowerCase();
66387
+ const content = fs48.readFileSync(specFile, "utf-8");
66388
+ const ext = path61.extname(specFile).toLowerCase();
66228
66389
  if (ext === ".json") {
66229
66390
  return parseJsonSpec(content);
66230
66391
  }
@@ -66295,12 +66456,12 @@ function extractRoutes(cwd) {
66295
66456
  function walkDir(dir) {
66296
66457
  let entries;
66297
66458
  try {
66298
- entries = fs47.readdirSync(dir, { withFileTypes: true });
66459
+ entries = fs48.readdirSync(dir, { withFileTypes: true });
66299
66460
  } catch {
66300
66461
  return;
66301
66462
  }
66302
66463
  for (const entry of entries) {
66303
- const fullPath = path60.join(dir, entry.name);
66464
+ const fullPath = path61.join(dir, entry.name);
66304
66465
  if (entry.isSymbolicLink()) {
66305
66466
  continue;
66306
66467
  }
@@ -66310,7 +66471,7 @@ function extractRoutes(cwd) {
66310
66471
  }
66311
66472
  walkDir(fullPath);
66312
66473
  } else if (entry.isFile()) {
66313
- const ext = path60.extname(entry.name).toLowerCase();
66474
+ const ext = path61.extname(entry.name).toLowerCase();
66314
66475
  const baseName = entry.name.toLowerCase();
66315
66476
  if (![".ts", ".js", ".mjs"].includes(ext)) {
66316
66477
  continue;
@@ -66328,7 +66489,7 @@ function extractRoutes(cwd) {
66328
66489
  }
66329
66490
  function extractRoutesFromFile(filePath) {
66330
66491
  const routes = [];
66331
- const content = fs47.readFileSync(filePath, "utf-8");
66492
+ const content = fs48.readFileSync(filePath, "utf-8");
66332
66493
  const lines = content.split(/\r?\n/);
66333
66494
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
66334
66495
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -66479,8 +66640,8 @@ init_secretscan();
66479
66640
  // src/tools/symbols.ts
66480
66641
  init_tool();
66481
66642
  init_create_tool();
66482
- import * as fs48 from "fs";
66483
- import * as path61 from "path";
66643
+ import * as fs49 from "fs";
66644
+ import * as path62 from "path";
66484
66645
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
66485
66646
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
66486
66647
  function containsWindowsAttacks(str) {
@@ -66497,11 +66658,11 @@ function containsWindowsAttacks(str) {
66497
66658
  }
66498
66659
  function isPathInWorkspace(filePath, workspace) {
66499
66660
  try {
66500
- const resolvedPath = path61.resolve(workspace, filePath);
66501
- const realWorkspace = fs48.realpathSync(workspace);
66502
- const realResolvedPath = fs48.realpathSync(resolvedPath);
66503
- const relativePath = path61.relative(realWorkspace, realResolvedPath);
66504
- 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)) {
66505
66666
  return false;
66506
66667
  }
66507
66668
  return true;
@@ -66513,17 +66674,17 @@ function validatePathForRead(filePath, workspace) {
66513
66674
  return isPathInWorkspace(filePath, workspace);
66514
66675
  }
66515
66676
  function extractTSSymbols(filePath, cwd) {
66516
- const fullPath = path61.join(cwd, filePath);
66677
+ const fullPath = path62.join(cwd, filePath);
66517
66678
  if (!validatePathForRead(fullPath, cwd)) {
66518
66679
  return [];
66519
66680
  }
66520
66681
  let content;
66521
66682
  try {
66522
- const stats = fs48.statSync(fullPath);
66683
+ const stats = fs49.statSync(fullPath);
66523
66684
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66524
66685
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66525
66686
  }
66526
- content = fs48.readFileSync(fullPath, "utf-8");
66687
+ content = fs49.readFileSync(fullPath, "utf-8");
66527
66688
  } catch {
66528
66689
  return [];
66529
66690
  }
@@ -66665,17 +66826,17 @@ function extractTSSymbols(filePath, cwd) {
66665
66826
  });
66666
66827
  }
66667
66828
  function extractPythonSymbols(filePath, cwd) {
66668
- const fullPath = path61.join(cwd, filePath);
66829
+ const fullPath = path62.join(cwd, filePath);
66669
66830
  if (!validatePathForRead(fullPath, cwd)) {
66670
66831
  return [];
66671
66832
  }
66672
66833
  let content;
66673
66834
  try {
66674
- const stats = fs48.statSync(fullPath);
66835
+ const stats = fs49.statSync(fullPath);
66675
66836
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66676
66837
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66677
66838
  }
66678
- content = fs48.readFileSync(fullPath, "utf-8");
66839
+ content = fs49.readFileSync(fullPath, "utf-8");
66679
66840
  } catch {
66680
66841
  return [];
66681
66842
  }
@@ -66748,7 +66909,7 @@ var symbols = createSwarmTool({
66748
66909
  }, null, 2);
66749
66910
  }
66750
66911
  const cwd = directory;
66751
- const ext = path61.extname(file3);
66912
+ const ext = path62.extname(file3);
66752
66913
  if (containsControlChars(file3)) {
66753
66914
  return JSON.stringify({
66754
66915
  file: file3,
@@ -66819,8 +66980,8 @@ init_test_runner();
66819
66980
  init_dist();
66820
66981
  init_utils();
66821
66982
  init_create_tool();
66822
- import * as fs49 from "fs";
66823
- import * as path62 from "path";
66983
+ import * as fs50 from "fs";
66984
+ import * as path63 from "path";
66824
66985
  var MAX_TEXT_LENGTH = 200;
66825
66986
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
66826
66987
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -66885,9 +67046,9 @@ function validatePathsInput(paths, cwd) {
66885
67046
  return { error: "paths contains path traversal", resolvedPath: null };
66886
67047
  }
66887
67048
  try {
66888
- const resolvedPath = path62.resolve(paths);
66889
- const normalizedCwd = path62.resolve(cwd);
66890
- const normalizedResolved = path62.resolve(resolvedPath);
67049
+ const resolvedPath = path63.resolve(paths);
67050
+ const normalizedCwd = path63.resolve(cwd);
67051
+ const normalizedResolved = path63.resolve(resolvedPath);
66891
67052
  if (!normalizedResolved.startsWith(normalizedCwd)) {
66892
67053
  return {
66893
67054
  error: "paths must be within the current working directory",
@@ -66903,13 +67064,13 @@ function validatePathsInput(paths, cwd) {
66903
67064
  }
66904
67065
  }
66905
67066
  function isSupportedExtension(filePath) {
66906
- const ext = path62.extname(filePath).toLowerCase();
67067
+ const ext = path63.extname(filePath).toLowerCase();
66907
67068
  return SUPPORTED_EXTENSIONS2.has(ext);
66908
67069
  }
66909
67070
  function findSourceFiles2(dir, files = []) {
66910
67071
  let entries;
66911
67072
  try {
66912
- entries = fs49.readdirSync(dir);
67073
+ entries = fs50.readdirSync(dir);
66913
67074
  } catch {
66914
67075
  return files;
66915
67076
  }
@@ -66918,10 +67079,10 @@ function findSourceFiles2(dir, files = []) {
66918
67079
  if (SKIP_DIRECTORIES4.has(entry)) {
66919
67080
  continue;
66920
67081
  }
66921
- const fullPath = path62.join(dir, entry);
67082
+ const fullPath = path63.join(dir, entry);
66922
67083
  let stat2;
66923
67084
  try {
66924
- stat2 = fs49.statSync(fullPath);
67085
+ stat2 = fs50.statSync(fullPath);
66925
67086
  } catch {
66926
67087
  continue;
66927
67088
  }
@@ -67014,7 +67175,7 @@ var todo_extract = createSwarmTool({
67014
67175
  return JSON.stringify(errorResult, null, 2);
67015
67176
  }
67016
67177
  const scanPath = resolvedPath;
67017
- if (!fs49.existsSync(scanPath)) {
67178
+ if (!fs50.existsSync(scanPath)) {
67018
67179
  const errorResult = {
67019
67180
  error: `path not found: ${pathsInput}`,
67020
67181
  total: 0,
@@ -67024,13 +67185,13 @@ var todo_extract = createSwarmTool({
67024
67185
  return JSON.stringify(errorResult, null, 2);
67025
67186
  }
67026
67187
  const filesToScan = [];
67027
- const stat2 = fs49.statSync(scanPath);
67188
+ const stat2 = fs50.statSync(scanPath);
67028
67189
  if (stat2.isFile()) {
67029
67190
  if (isSupportedExtension(scanPath)) {
67030
67191
  filesToScan.push(scanPath);
67031
67192
  } else {
67032
67193
  const errorResult = {
67033
- error: `unsupported file extension: ${path62.extname(scanPath)}`,
67194
+ error: `unsupported file extension: ${path63.extname(scanPath)}`,
67034
67195
  total: 0,
67035
67196
  byPriority: { high: 0, medium: 0, low: 0 },
67036
67197
  entries: []
@@ -67043,11 +67204,11 @@ var todo_extract = createSwarmTool({
67043
67204
  const allEntries = [];
67044
67205
  for (const filePath of filesToScan) {
67045
67206
  try {
67046
- const fileStat = fs49.statSync(filePath);
67207
+ const fileStat = fs50.statSync(filePath);
67047
67208
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
67048
67209
  continue;
67049
67210
  }
67050
- const content = fs49.readFileSync(filePath, "utf-8");
67211
+ const content = fs50.readFileSync(filePath, "utf-8");
67051
67212
  const entries = parseTodoComments(content, filePath, tagsSet);
67052
67213
  allEntries.push(...entries);
67053
67214
  } catch {}
@@ -67076,18 +67237,18 @@ var todo_extract = createSwarmTool({
67076
67237
  init_tool();
67077
67238
  init_schema();
67078
67239
  init_gate_evidence();
67079
- import * as fs51 from "fs";
67080
- import * as path64 from "path";
67240
+ import * as fs52 from "fs";
67241
+ import * as path65 from "path";
67081
67242
 
67082
67243
  // src/hooks/diff-scope.ts
67083
- import * as fs50 from "fs";
67084
- import * as path63 from "path";
67244
+ import * as fs51 from "fs";
67245
+ import * as path64 from "path";
67085
67246
  function getDeclaredScope(taskId, directory) {
67086
67247
  try {
67087
- const planPath = path63.join(directory, ".swarm", "plan.json");
67088
- if (!fs50.existsSync(planPath))
67248
+ const planPath = path64.join(directory, ".swarm", "plan.json");
67249
+ if (!fs51.existsSync(planPath))
67089
67250
  return null;
67090
- const raw = fs50.readFileSync(planPath, "utf-8");
67251
+ const raw = fs51.readFileSync(planPath, "utf-8");
67091
67252
  const plan = JSON.parse(raw);
67092
67253
  for (const phase of plan.phases ?? []) {
67093
67254
  for (const task of phase.tasks ?? []) {
@@ -67200,7 +67361,7 @@ var TIER_3_PATTERNS = [
67200
67361
  ];
67201
67362
  function matchesTier3Pattern(files) {
67202
67363
  for (const file3 of files) {
67203
- const fileName = path64.basename(file3);
67364
+ const fileName = path65.basename(file3);
67204
67365
  for (const pattern of TIER_3_PATTERNS) {
67205
67366
  if (pattern.test(fileName)) {
67206
67367
  return true;
@@ -67214,8 +67375,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67214
67375
  if (hasActiveTurboMode()) {
67215
67376
  const resolvedDir2 = workingDirectory;
67216
67377
  try {
67217
- const planPath = path64.join(resolvedDir2, ".swarm", "plan.json");
67218
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67378
+ const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67379
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67219
67380
  const plan = JSON.parse(planRaw);
67220
67381
  for (const planPhase of plan.phases ?? []) {
67221
67382
  for (const task of planPhase.tasks ?? []) {
@@ -67281,8 +67442,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67281
67442
  }
67282
67443
  try {
67283
67444
  const resolvedDir2 = workingDirectory;
67284
- const planPath = path64.join(resolvedDir2, ".swarm", "plan.json");
67285
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67445
+ const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67446
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67286
67447
  const plan = JSON.parse(planRaw);
67287
67448
  for (const planPhase of plan.phases ?? []) {
67288
67449
  for (const task of planPhase.tasks ?? []) {
@@ -67464,8 +67625,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67464
67625
  };
67465
67626
  }
67466
67627
  }
67467
- normalizedDir = path64.normalize(args2.working_directory);
67468
- const pathParts = normalizedDir.split(path64.sep);
67628
+ normalizedDir = path65.normalize(args2.working_directory);
67629
+ const pathParts = normalizedDir.split(path65.sep);
67469
67630
  if (pathParts.includes("..")) {
67470
67631
  return {
67471
67632
  success: false,
@@ -67475,11 +67636,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67475
67636
  ]
67476
67637
  };
67477
67638
  }
67478
- const resolvedDir = path64.resolve(normalizedDir);
67639
+ const resolvedDir = path65.resolve(normalizedDir);
67479
67640
  try {
67480
- const realPath = fs51.realpathSync(resolvedDir);
67481
- const planPath = path64.join(realPath, ".swarm", "plan.json");
67482
- if (!fs51.existsSync(planPath)) {
67641
+ const realPath = fs52.realpathSync(resolvedDir);
67642
+ const planPath = path65.join(realPath, ".swarm", "plan.json");
67643
+ if (!fs52.existsSync(planPath)) {
67483
67644
  return {
67484
67645
  success: false,
67485
67646
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -67512,8 +67673,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67512
67673
  recoverTaskStateFromDelegations(args2.task_id);
67513
67674
  let phaseRequiresReviewer = true;
67514
67675
  try {
67515
- const planPath = path64.join(directory, ".swarm", "plan.json");
67516
- const planRaw = fs51.readFileSync(planPath, "utf-8");
67676
+ const planPath = path65.join(directory, ".swarm", "plan.json");
67677
+ const planRaw = fs52.readFileSync(planPath, "utf-8");
67517
67678
  const plan = JSON.parse(planRaw);
67518
67679
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
67519
67680
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -67576,8 +67737,8 @@ var update_task_status = createSwarmTool({
67576
67737
  init_tool();
67577
67738
  init_utils2();
67578
67739
  init_create_tool();
67579
- import fs52 from "fs";
67580
- import path65 from "path";
67740
+ import fs53 from "fs";
67741
+ import path66 from "path";
67581
67742
  function normalizeVerdict(verdict) {
67582
67743
  switch (verdict) {
67583
67744
  case "APPROVED":
@@ -67624,7 +67785,7 @@ async function executeWriteDriftEvidence(args2, directory) {
67624
67785
  entries: [evidenceEntry]
67625
67786
  };
67626
67787
  const filename = "drift-verifier.json";
67627
- const relativePath = path65.join("evidence", String(phase), filename);
67788
+ const relativePath = path66.join("evidence", String(phase), filename);
67628
67789
  let validatedPath;
67629
67790
  try {
67630
67791
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -67635,12 +67796,12 @@ async function executeWriteDriftEvidence(args2, directory) {
67635
67796
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
67636
67797
  }, null, 2);
67637
67798
  }
67638
- const evidenceDir = path65.dirname(validatedPath);
67799
+ const evidenceDir = path66.dirname(validatedPath);
67639
67800
  try {
67640
- await fs52.promises.mkdir(evidenceDir, { recursive: true });
67641
- const tempPath = path65.join(evidenceDir, `.${filename}.tmp`);
67642
- await fs52.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
67643
- 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);
67644
67805
  return JSON.stringify({
67645
67806
  success: true,
67646
67807
  phase,
@@ -67658,7 +67819,7 @@ async function executeWriteDriftEvidence(args2, directory) {
67658
67819
  var write_drift_evidence = createSwarmTool({
67659
67820
  description: "Write drift verification evidence for a completed phase. " + "Normalizes verdict (APPROVED->approved, NEEDS_REVISION->rejected) and writes " + "a gate-contract formatted EvidenceBundle to .swarm/evidence/{phase}/drift-verifier.json. " + "Use this after critic_drift_verifier delegation to persist the verification result.",
67660
67821
  args: {
67661
- phase: tool.schema.number().int().positive().describe("The phase number for the drift verification"),
67822
+ phase: tool.schema.number().int().min(1).describe("The phase number for the drift verification (e.g., 1, 2, 3)"),
67662
67823
  verdict: tool.schema.enum(["APPROVED", "NEEDS_REVISION"]).describe("Verdict of the drift verification: 'APPROVED' or 'NEEDS_REVISION'"),
67663
67824
  summary: tool.schema.string().describe("Human-readable summary of the drift verification")
67664
67825
  },
@@ -67828,7 +67989,7 @@ var OpenCodeSwarm = async (ctx) => {
67828
67989
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
67829
67990
  preflightTriggerManager = new PTM(automationConfig);
67830
67991
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
67831
- const swarmDir = path66.resolve(ctx.directory, ".swarm");
67992
+ const swarmDir = path67.resolve(ctx.directory, ".swarm");
67832
67993
  statusArtifact = new ASA(swarmDir);
67833
67994
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
67834
67995
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {