opencode-swarm 6.45.1 → 6.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14573,7 +14573,7 @@ function resolveGuardrailsConfig(config2, agentName) {
14573
14573
  };
14574
14574
  return resolved;
14575
14575
  }
14576
- var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PluginConfigSchema;
14576
+ var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, PluginConfigSchema;
14577
14577
  var init_schema = __esm(() => {
14578
14578
  init_zod();
14579
14579
  init_constants();
@@ -15047,6 +15047,17 @@ var init_schema = __esm(() => {
15047
15047
  emergencyThreshold: exports_external.number().min(1).max(99).default(80),
15048
15048
  preserveLastNTurns: exports_external.number().int().min(1).default(5)
15049
15049
  });
15050
+ AgentAuthorityRuleSchema = exports_external.object({
15051
+ readOnly: exports_external.boolean().optional(),
15052
+ blockedExact: exports_external.array(exports_external.string()).optional(),
15053
+ blockedPrefix: exports_external.array(exports_external.string()).optional(),
15054
+ allowedPrefix: exports_external.array(exports_external.string()).optional(),
15055
+ blockedZones: exports_external.array(exports_external.enum(["production", "test", "config", "generated", "docs", "build"])).optional()
15056
+ });
15057
+ AuthorityConfigSchema = exports_external.object({
15058
+ enabled: exports_external.boolean().default(true),
15059
+ rules: exports_external.record(exports_external.string(), AgentAuthorityRuleSchema).default({})
15060
+ });
15050
15061
  PluginConfigSchema = exports_external.object({
15051
15062
  agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
15052
15063
  swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
@@ -15063,6 +15074,7 @@ var init_schema = __esm(() => {
15063
15074
  watchdog: WatchdogConfigSchema.optional(),
15064
15075
  self_review: SelfReviewConfigSchema.optional(),
15065
15076
  tool_filter: ToolFilterConfigSchema.optional(),
15077
+ authority: AuthorityConfigSchema.optional(),
15066
15078
  plan_cursor: PlanCursorConfigSchema.optional(),
15067
15079
  evidence: EvidenceConfigSchema.optional(),
15068
15080
  summaries: SummaryConfigSchema.optional(),
@@ -32521,7 +32533,7 @@ __export(exports_co_change_analyzer, {
32521
32533
  import * as child_process2 from "child_process";
32522
32534
  import { randomUUID as randomUUID2 } from "crypto";
32523
32535
  import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
32524
- import * as path19 from "path";
32536
+ import * as path20 from "path";
32525
32537
  import { promisify } from "util";
32526
32538
  function getExecFileAsync() {
32527
32539
  return promisify(child_process2.execFile);
@@ -32623,7 +32635,7 @@ async function scanSourceFiles(dir) {
32623
32635
  try {
32624
32636
  const entries = await readdir2(dir, { withFileTypes: true });
32625
32637
  for (const entry of entries) {
32626
- const fullPath = path19.join(dir, entry.name);
32638
+ const fullPath = path20.join(dir, entry.name);
32627
32639
  if (entry.isDirectory()) {
32628
32640
  if (skipDirs.has(entry.name)) {
32629
32641
  continue;
@@ -32631,7 +32643,7 @@ async function scanSourceFiles(dir) {
32631
32643
  const subFiles = await scanSourceFiles(fullPath);
32632
32644
  results.push(...subFiles);
32633
32645
  } else if (entry.isFile()) {
32634
- const ext = path19.extname(entry.name);
32646
+ const ext = path20.extname(entry.name);
32635
32647
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
32636
32648
  results.push(fullPath);
32637
32649
  }
@@ -32653,8 +32665,8 @@ async function getStaticEdges(directory) {
32653
32665
  continue;
32654
32666
  }
32655
32667
  try {
32656
- const sourceDir = path19.dirname(sourceFile);
32657
- const resolvedPath = path19.resolve(sourceDir, importPath);
32668
+ const sourceDir = path20.dirname(sourceFile);
32669
+ const resolvedPath = path20.resolve(sourceDir, importPath);
32658
32670
  const extensions = [
32659
32671
  "",
32660
32672
  ".ts",
@@ -32679,8 +32691,8 @@ async function getStaticEdges(directory) {
32679
32691
  if (!targetFile) {
32680
32692
  continue;
32681
32693
  }
32682
- const relSource = path19.relative(directory, sourceFile).replace(/\\/g, "/");
32683
- const relTarget = path19.relative(directory, targetFile).replace(/\\/g, "/");
32694
+ const relSource = path20.relative(directory, sourceFile).replace(/\\/g, "/");
32695
+ const relTarget = path20.relative(directory, targetFile).replace(/\\/g, "/");
32684
32696
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
32685
32697
  edges.add(key);
32686
32698
  } catch {}
@@ -32692,7 +32704,7 @@ async function getStaticEdges(directory) {
32692
32704
  function isTestImplementationPair(fileA, fileB) {
32693
32705
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
32694
32706
  const getBaseName = (filePath) => {
32695
- const base = path19.basename(filePath);
32707
+ const base = path20.basename(filePath);
32696
32708
  for (const pattern of testPatterns) {
32697
32709
  if (base.endsWith(pattern)) {
32698
32710
  return base.slice(0, -pattern.length);
@@ -32702,16 +32714,16 @@ function isTestImplementationPair(fileA, fileB) {
32702
32714
  };
32703
32715
  const baseA = getBaseName(fileA);
32704
32716
  const baseB = getBaseName(fileB);
32705
- return baseA === baseB && baseA !== path19.basename(fileA) && baseA !== path19.basename(fileB);
32717
+ return baseA === baseB && baseA !== path20.basename(fileA) && baseA !== path20.basename(fileB);
32706
32718
  }
32707
32719
  function hasSharedPrefix(fileA, fileB) {
32708
- const dirA = path19.dirname(fileA);
32709
- const dirB = path19.dirname(fileB);
32720
+ const dirA = path20.dirname(fileA);
32721
+ const dirB = path20.dirname(fileB);
32710
32722
  if (dirA !== dirB) {
32711
32723
  return false;
32712
32724
  }
32713
- const baseA = path19.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
32714
- const baseB = path19.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
32725
+ const baseA = path20.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
32726
+ const baseB = path20.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
32715
32727
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
32716
32728
  return true;
32717
32729
  }
@@ -32765,8 +32777,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
32765
32777
  const entries = [];
32766
32778
  const now = new Date().toISOString();
32767
32779
  for (const pair of pairs.slice(0, 10)) {
32768
- const baseA = path19.basename(pair.fileA);
32769
- const baseB = path19.basename(pair.fileB);
32780
+ const baseA = path20.basename(pair.fileA);
32781
+ const baseB = path20.basename(pair.fileB);
32770
32782
  let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
32771
32783
  if (lesson.length > 280) {
32772
32784
  lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
@@ -32875,13 +32887,13 @@ __export(exports_config_doctor, {
32875
32887
  import * as crypto3 from "crypto";
32876
32888
  import * as fs13 from "fs";
32877
32889
  import * as os5 from "os";
32878
- import * as path22 from "path";
32890
+ import * as path23 from "path";
32879
32891
  function getUserConfigDir3() {
32880
- return process.env.XDG_CONFIG_HOME || path22.join(os5.homedir(), ".config");
32892
+ return process.env.XDG_CONFIG_HOME || path23.join(os5.homedir(), ".config");
32881
32893
  }
32882
32894
  function getConfigPaths(directory) {
32883
- const userConfigPath = path22.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
32884
- const projectConfigPath = path22.join(directory, ".opencode", "opencode-swarm.json");
32895
+ const userConfigPath = path23.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
32896
+ const projectConfigPath = path23.join(directory, ".opencode", "opencode-swarm.json");
32885
32897
  return { userConfigPath, projectConfigPath };
32886
32898
  }
32887
32899
  function computeHash(content) {
@@ -32906,9 +32918,9 @@ function isValidConfigPath(configPath, directory) {
32906
32918
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
32907
32919
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
32908
32920
  try {
32909
- const resolvedConfig = path22.resolve(configPath);
32910
- const resolvedUser = path22.resolve(normalizedUser);
32911
- const resolvedProject = path22.resolve(normalizedProject);
32921
+ const resolvedConfig = path23.resolve(configPath);
32922
+ const resolvedUser = path23.resolve(normalizedUser);
32923
+ const resolvedProject = path23.resolve(normalizedProject);
32912
32924
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
32913
32925
  } catch {
32914
32926
  return false;
@@ -32948,12 +32960,12 @@ function createConfigBackup(directory) {
32948
32960
  };
32949
32961
  }
32950
32962
  function writeBackupArtifact(directory, backup) {
32951
- const swarmDir = path22.join(directory, ".swarm");
32963
+ const swarmDir = path23.join(directory, ".swarm");
32952
32964
  if (!fs13.existsSync(swarmDir)) {
32953
32965
  fs13.mkdirSync(swarmDir, { recursive: true });
32954
32966
  }
32955
32967
  const backupFilename = `config-backup-${backup.createdAt}.json`;
32956
- const backupPath = path22.join(swarmDir, backupFilename);
32968
+ const backupPath = path23.join(swarmDir, backupFilename);
32957
32969
  const artifact = {
32958
32970
  createdAt: backup.createdAt,
32959
32971
  configPath: backup.configPath,
@@ -32983,7 +32995,7 @@ function restoreFromBackup(backupPath, directory) {
32983
32995
  return null;
32984
32996
  }
32985
32997
  const targetPath = artifact.configPath;
32986
- const targetDir = path22.dirname(targetPath);
32998
+ const targetDir = path23.dirname(targetPath);
32987
32999
  if (!fs13.existsSync(targetDir)) {
32988
33000
  fs13.mkdirSync(targetDir, { recursive: true });
32989
33001
  }
@@ -33014,9 +33026,9 @@ function readConfigFromFile(directory) {
33014
33026
  return null;
33015
33027
  }
33016
33028
  }
33017
- function validateConfigKey(path23, value, _config) {
33029
+ function validateConfigKey(path24, value, _config) {
33018
33030
  const findings = [];
33019
- switch (path23) {
33031
+ switch (path24) {
33020
33032
  case "agents": {
33021
33033
  if (value !== undefined) {
33022
33034
  findings.push({
@@ -33263,27 +33275,27 @@ function validateConfigKey(path23, value, _config) {
33263
33275
  }
33264
33276
  return findings;
33265
33277
  }
33266
- function walkConfigAndValidate(obj, path23, config3, findings) {
33278
+ function walkConfigAndValidate(obj, path24, config3, findings) {
33267
33279
  if (obj === null || obj === undefined) {
33268
33280
  return;
33269
33281
  }
33270
- if (path23 && typeof obj === "object" && !Array.isArray(obj)) {
33271
- const keyFindings = validateConfigKey(path23, obj, config3);
33282
+ if (path24 && typeof obj === "object" && !Array.isArray(obj)) {
33283
+ const keyFindings = validateConfigKey(path24, obj, config3);
33272
33284
  findings.push(...keyFindings);
33273
33285
  }
33274
33286
  if (typeof obj !== "object") {
33275
- const keyFindings = validateConfigKey(path23, obj, config3);
33287
+ const keyFindings = validateConfigKey(path24, obj, config3);
33276
33288
  findings.push(...keyFindings);
33277
33289
  return;
33278
33290
  }
33279
33291
  if (Array.isArray(obj)) {
33280
33292
  obj.forEach((item, index) => {
33281
- walkConfigAndValidate(item, `${path23}[${index}]`, config3, findings);
33293
+ walkConfigAndValidate(item, `${path24}[${index}]`, config3, findings);
33282
33294
  });
33283
33295
  return;
33284
33296
  }
33285
33297
  for (const [key, value] of Object.entries(obj)) {
33286
- const newPath = path23 ? `${path23}.${key}` : key;
33298
+ const newPath = path24 ? `${path24}.${key}` : key;
33287
33299
  walkConfigAndValidate(value, newPath, config3, findings);
33288
33300
  }
33289
33301
  }
@@ -33403,7 +33415,7 @@ function applySafeAutoFixes(directory, result) {
33403
33415
  }
33404
33416
  }
33405
33417
  if (appliedFixes.length > 0) {
33406
- const configDir = path22.dirname(configPath);
33418
+ const configDir = path23.dirname(configPath);
33407
33419
  if (!fs13.existsSync(configDir)) {
33408
33420
  fs13.mkdirSync(configDir, { recursive: true });
33409
33421
  }
@@ -33413,12 +33425,12 @@ function applySafeAutoFixes(directory, result) {
33413
33425
  return { appliedFixes, updatedConfigPath };
33414
33426
  }
33415
33427
  function writeDoctorArtifact(directory, result) {
33416
- const swarmDir = path22.join(directory, ".swarm");
33428
+ const swarmDir = path23.join(directory, ".swarm");
33417
33429
  if (!fs13.existsSync(swarmDir)) {
33418
33430
  fs13.mkdirSync(swarmDir, { recursive: true });
33419
33431
  }
33420
33432
  const artifactFilename = "config-doctor.json";
33421
- const artifactPath = path22.join(swarmDir, artifactFilename);
33433
+ const artifactPath = path23.join(swarmDir, artifactFilename);
33422
33434
  const guiOutput = {
33423
33435
  timestamp: result.timestamp,
33424
33436
  summary: result.summary,
@@ -34472,7 +34484,7 @@ var init_detector = __esm(() => {
34472
34484
 
34473
34485
  // src/build/discovery.ts
34474
34486
  import * as fs14 from "fs";
34475
- import * as path24 from "path";
34487
+ import * as path25 from "path";
34476
34488
  function isCommandAvailable(command) {
34477
34489
  if (toolchainCache.has(command)) {
34478
34490
  return toolchainCache.get(command);
@@ -34505,11 +34517,11 @@ function findBuildFiles(workingDir, patterns) {
34505
34517
  const regex = simpleGlobToRegex(pattern);
34506
34518
  const matches = files.filter((f) => regex.test(f));
34507
34519
  if (matches.length > 0) {
34508
- return path24.join(dir, matches[0]);
34520
+ return path25.join(dir, matches[0]);
34509
34521
  }
34510
34522
  } catch {}
34511
34523
  } else {
34512
- const filePath = path24.join(workingDir, pattern);
34524
+ const filePath = path25.join(workingDir, pattern);
34513
34525
  if (fs14.existsSync(filePath)) {
34514
34526
  return filePath;
34515
34527
  }
@@ -34518,7 +34530,7 @@ function findBuildFiles(workingDir, patterns) {
34518
34530
  return null;
34519
34531
  }
34520
34532
  function getRepoDefinedScripts(workingDir, scripts) {
34521
- const packageJsonPath = path24.join(workingDir, "package.json");
34533
+ const packageJsonPath = path25.join(workingDir, "package.json");
34522
34534
  if (!fs14.existsSync(packageJsonPath)) {
34523
34535
  return [];
34524
34536
  }
@@ -34559,7 +34571,7 @@ function findAllBuildFiles(workingDir) {
34559
34571
  const regex = simpleGlobToRegex(pattern);
34560
34572
  findFilesRecursive(workingDir, regex, allBuildFiles);
34561
34573
  } else {
34562
- const filePath = path24.join(workingDir, pattern);
34574
+ const filePath = path25.join(workingDir, pattern);
34563
34575
  if (fs14.existsSync(filePath)) {
34564
34576
  allBuildFiles.add(filePath);
34565
34577
  }
@@ -34572,7 +34584,7 @@ function findFilesRecursive(dir, regex, results) {
34572
34584
  try {
34573
34585
  const entries = fs14.readdirSync(dir, { withFileTypes: true });
34574
34586
  for (const entry of entries) {
34575
- const fullPath = path24.join(dir, entry.name);
34587
+ const fullPath = path25.join(dir, entry.name);
34576
34588
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
34577
34589
  findFilesRecursive(fullPath, regex, results);
34578
34590
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -34595,7 +34607,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
34595
34607
  let foundCommand = false;
34596
34608
  for (const cmd of sortedCommands) {
34597
34609
  if (cmd.detectFile) {
34598
- const detectFilePath = path24.join(workingDir, cmd.detectFile);
34610
+ const detectFilePath = path25.join(workingDir, cmd.detectFile);
34599
34611
  if (!fs14.existsSync(detectFilePath)) {
34600
34612
  continue;
34601
34613
  }
@@ -34852,7 +34864,7 @@ function validateDirectory(directory) {
34852
34864
 
34853
34865
  // src/tools/lint.ts
34854
34866
  import * as fs15 from "fs";
34855
- import * as path25 from "path";
34867
+ import * as path26 from "path";
34856
34868
  function validateArgs(args2) {
34857
34869
  if (typeof args2 !== "object" || args2 === null)
34858
34870
  return false;
@@ -34863,9 +34875,9 @@ function validateArgs(args2) {
34863
34875
  }
34864
34876
  function getLinterCommand(linter, mode, projectDir) {
34865
34877
  const isWindows = process.platform === "win32";
34866
- const binDir = path25.join(projectDir, "node_modules", ".bin");
34867
- const biomeBin = isWindows ? path25.join(binDir, "biome.EXE") : path25.join(binDir, "biome");
34868
- const eslintBin = isWindows ? path25.join(binDir, "eslint.cmd") : path25.join(binDir, "eslint");
34878
+ const binDir = path26.join(projectDir, "node_modules", ".bin");
34879
+ const biomeBin = isWindows ? path26.join(binDir, "biome.EXE") : path26.join(binDir, "biome");
34880
+ const eslintBin = isWindows ? path26.join(binDir, "eslint.cmd") : path26.join(binDir, "eslint");
34869
34881
  switch (linter) {
34870
34882
  case "biome":
34871
34883
  if (mode === "fix") {
@@ -34881,7 +34893,7 @@ function getLinterCommand(linter, mode, projectDir) {
34881
34893
  }
34882
34894
  function getAdditionalLinterCommand(linter, mode, cwd) {
34883
34895
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
34884
- const gradlew = fs15.existsSync(path25.join(cwd, gradlewName)) ? path25.join(cwd, gradlewName) : null;
34896
+ const gradlew = fs15.existsSync(path26.join(cwd, gradlewName)) ? path26.join(cwd, gradlewName) : null;
34885
34897
  switch (linter) {
34886
34898
  case "ruff":
34887
34899
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -34915,10 +34927,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
34915
34927
  }
34916
34928
  }
34917
34929
  function detectRuff(cwd) {
34918
- if (fs15.existsSync(path25.join(cwd, "ruff.toml")))
34930
+ if (fs15.existsSync(path26.join(cwd, "ruff.toml")))
34919
34931
  return isCommandAvailable("ruff");
34920
34932
  try {
34921
- const pyproject = path25.join(cwd, "pyproject.toml");
34933
+ const pyproject = path26.join(cwd, "pyproject.toml");
34922
34934
  if (fs15.existsSync(pyproject)) {
34923
34935
  const content = fs15.readFileSync(pyproject, "utf-8");
34924
34936
  if (content.includes("[tool.ruff]"))
@@ -34928,19 +34940,19 @@ function detectRuff(cwd) {
34928
34940
  return false;
34929
34941
  }
34930
34942
  function detectClippy(cwd) {
34931
- return fs15.existsSync(path25.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
34943
+ return fs15.existsSync(path26.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
34932
34944
  }
34933
34945
  function detectGolangciLint(cwd) {
34934
- return fs15.existsSync(path25.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
34946
+ return fs15.existsSync(path26.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
34935
34947
  }
34936
34948
  function detectCheckstyle(cwd) {
34937
- const hasMaven = fs15.existsSync(path25.join(cwd, "pom.xml"));
34938
- const hasGradle = fs15.existsSync(path25.join(cwd, "build.gradle")) || fs15.existsSync(path25.join(cwd, "build.gradle.kts"));
34939
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs15.existsSync(path25.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
34949
+ const hasMaven = fs15.existsSync(path26.join(cwd, "pom.xml"));
34950
+ const hasGradle = fs15.existsSync(path26.join(cwd, "build.gradle")) || fs15.existsSync(path26.join(cwd, "build.gradle.kts"));
34951
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs15.existsSync(path26.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
34940
34952
  return (hasMaven || hasGradle) && hasBinary;
34941
34953
  }
34942
34954
  function detectKtlint(cwd) {
34943
- const hasKotlin = fs15.existsSync(path25.join(cwd, "build.gradle.kts")) || fs15.existsSync(path25.join(cwd, "build.gradle")) || (() => {
34955
+ const hasKotlin = fs15.existsSync(path26.join(cwd, "build.gradle.kts")) || fs15.existsSync(path26.join(cwd, "build.gradle")) || (() => {
34944
34956
  try {
34945
34957
  return fs15.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
34946
34958
  } catch {
@@ -34959,11 +34971,11 @@ function detectDotnetFormat(cwd) {
34959
34971
  }
34960
34972
  }
34961
34973
  function detectCppcheck(cwd) {
34962
- if (fs15.existsSync(path25.join(cwd, "CMakeLists.txt"))) {
34974
+ if (fs15.existsSync(path26.join(cwd, "CMakeLists.txt"))) {
34963
34975
  return isCommandAvailable("cppcheck");
34964
34976
  }
34965
34977
  try {
34966
- const dirsToCheck = [cwd, path25.join(cwd, "src")];
34978
+ const dirsToCheck = [cwd, path26.join(cwd, "src")];
34967
34979
  const hasCpp = dirsToCheck.some((dir) => {
34968
34980
  try {
34969
34981
  return fs15.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
@@ -34977,13 +34989,13 @@ function detectCppcheck(cwd) {
34977
34989
  }
34978
34990
  }
34979
34991
  function detectSwiftlint(cwd) {
34980
- return fs15.existsSync(path25.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
34992
+ return fs15.existsSync(path26.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
34981
34993
  }
34982
34994
  function detectDartAnalyze(cwd) {
34983
- return fs15.existsSync(path25.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
34995
+ return fs15.existsSync(path26.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
34984
34996
  }
34985
34997
  function detectRubocop(cwd) {
34986
- return (fs15.existsSync(path25.join(cwd, "Gemfile")) || fs15.existsSync(path25.join(cwd, "gems.rb")) || fs15.existsSync(path25.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
34998
+ return (fs15.existsSync(path26.join(cwd, "Gemfile")) || fs15.existsSync(path26.join(cwd, "gems.rb")) || fs15.existsSync(path26.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
34987
34999
  }
34988
35000
  function detectAdditionalLinter(cwd) {
34989
35001
  if (detectRuff(cwd))
@@ -35011,10 +35023,10 @@ function detectAdditionalLinter(cwd) {
35011
35023
  function resolveLinterBinPath(linter, projectDir) {
35012
35024
  const isWindows = process.platform === "win32";
35013
35025
  const binName = linter === "biome" ? isWindows ? "biome.EXE" : "biome" : isWindows ? "eslint.cmd" : "eslint";
35014
- const localBin = path25.join(projectDir, "node_modules", ".bin", binName);
35026
+ const localBin = path26.join(projectDir, "node_modules", ".bin", binName);
35015
35027
  if (fs15.existsSync(localBin))
35016
35028
  return localBin;
35017
- const ancestor = findBinInAncestors(path25.dirname(projectDir), binName);
35029
+ const ancestor = findBinInAncestors(path26.dirname(projectDir), binName);
35018
35030
  if (ancestor)
35019
35031
  return ancestor;
35020
35032
  const fromPath = findBinInEnvPath(binName);
@@ -35025,10 +35037,10 @@ function resolveLinterBinPath(linter, projectDir) {
35025
35037
  function findBinInAncestors(startDir, binName) {
35026
35038
  let dir = startDir;
35027
35039
  while (true) {
35028
- const candidate = path25.join(dir, "node_modules", ".bin", binName);
35040
+ const candidate = path26.join(dir, "node_modules", ".bin", binName);
35029
35041
  if (fs15.existsSync(candidate))
35030
35042
  return candidate;
35031
- const parent = path25.dirname(dir);
35043
+ const parent = path26.dirname(dir);
35032
35044
  if (parent === dir)
35033
35045
  break;
35034
35046
  dir = parent;
@@ -35037,10 +35049,10 @@ function findBinInAncestors(startDir, binName) {
35037
35049
  }
35038
35050
  function findBinInEnvPath(binName) {
35039
35051
  const searchPath = process.env.PATH ?? "";
35040
- for (const dir of searchPath.split(path25.delimiter)) {
35052
+ for (const dir of searchPath.split(path26.delimiter)) {
35041
35053
  if (!dir)
35042
35054
  continue;
35043
- const candidate = path25.join(dir, binName);
35055
+ const candidate = path26.join(dir, binName);
35044
35056
  if (fs15.existsSync(candidate))
35045
35057
  return candidate;
35046
35058
  }
@@ -35053,13 +35065,13 @@ async function detectAvailableLinter(directory) {
35053
35065
  return null;
35054
35066
  const projectDir = directory;
35055
35067
  const isWindows = process.platform === "win32";
35056
- const biomeBin = isWindows ? path25.join(projectDir, "node_modules", ".bin", "biome.EXE") : path25.join(projectDir, "node_modules", ".bin", "biome");
35057
- const eslintBin = isWindows ? path25.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path25.join(projectDir, "node_modules", ".bin", "eslint");
35068
+ const biomeBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "biome.EXE") : path26.join(projectDir, "node_modules", ".bin", "biome");
35069
+ const eslintBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path26.join(projectDir, "node_modules", ".bin", "eslint");
35058
35070
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
35059
35071
  if (localResult)
35060
35072
  return localResult;
35061
- const biomeAncestor = findBinInAncestors(path25.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
35062
- const eslintAncestor = findBinInAncestors(path25.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
35073
+ const biomeAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
35074
+ const eslintAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
35063
35075
  if (biomeAncestor || eslintAncestor) {
35064
35076
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
35065
35077
  }
@@ -35274,7 +35286,7 @@ For Rust: rustup component add clippy`
35274
35286
 
35275
35287
  // src/tools/secretscan.ts
35276
35288
  import * as fs16 from "fs";
35277
- import * as path26 from "path";
35289
+ import * as path27 from "path";
35278
35290
  function calculateShannonEntropy(str) {
35279
35291
  if (str.length === 0)
35280
35292
  return 0;
@@ -35322,7 +35334,7 @@ function isGlobOrPathPattern(pattern) {
35322
35334
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
35323
35335
  }
35324
35336
  function loadSecretScanIgnore(scanDir) {
35325
- const ignorePath = path26.join(scanDir, ".secretscanignore");
35337
+ const ignorePath = path27.join(scanDir, ".secretscanignore");
35326
35338
  try {
35327
35339
  if (!fs16.existsSync(ignorePath))
35328
35340
  return [];
@@ -35345,7 +35357,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
35345
35357
  if (exactNames.has(entry))
35346
35358
  return true;
35347
35359
  for (const pattern of globPatterns) {
35348
- if (path26.matchesGlob(relPath, pattern))
35360
+ if (path27.matchesGlob(relPath, pattern))
35349
35361
  return true;
35350
35362
  }
35351
35363
  return false;
@@ -35366,7 +35378,7 @@ function validateDirectoryInput(dir) {
35366
35378
  return null;
35367
35379
  }
35368
35380
  function isBinaryFile(filePath, buffer) {
35369
- const ext = path26.extname(filePath).toLowerCase();
35381
+ const ext = path27.extname(filePath).toLowerCase();
35370
35382
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
35371
35383
  return true;
35372
35384
  }
@@ -35502,9 +35514,9 @@ function isSymlinkLoop(realPath, visited) {
35502
35514
  return false;
35503
35515
  }
35504
35516
  function isPathWithinScope(realPath, scanDir) {
35505
- const resolvedScanDir = path26.resolve(scanDir);
35506
- const resolvedRealPath = path26.resolve(realPath);
35507
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path26.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
35517
+ const resolvedScanDir = path27.resolve(scanDir);
35518
+ const resolvedRealPath = path27.resolve(realPath);
35519
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path27.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
35508
35520
  }
35509
35521
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
35510
35522
  skippedDirs: 0,
@@ -35530,8 +35542,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
35530
35542
  return a.localeCompare(b);
35531
35543
  });
35532
35544
  for (const entry of entries) {
35533
- const fullPath = path26.join(dir, entry);
35534
- const relPath = path26.relative(scanDir, fullPath).replace(/\\/g, "/");
35545
+ const fullPath = path27.join(dir, entry);
35546
+ const relPath = path27.relative(scanDir, fullPath).replace(/\\/g, "/");
35535
35547
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
35536
35548
  stats.skippedDirs++;
35537
35549
  continue;
@@ -35566,7 +35578,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
35566
35578
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
35567
35579
  files.push(...subFiles);
35568
35580
  } else if (lstat.isFile()) {
35569
- const ext = path26.extname(fullPath).toLowerCase();
35581
+ const ext = path27.extname(fullPath).toLowerCase();
35570
35582
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
35571
35583
  files.push(fullPath);
35572
35584
  } else {
@@ -35824,7 +35836,7 @@ var init_secretscan = __esm(() => {
35824
35836
  }
35825
35837
  }
35826
35838
  try {
35827
- const _scanDirRaw = path26.resolve(directory);
35839
+ const _scanDirRaw = path27.resolve(directory);
35828
35840
  const scanDir = (() => {
35829
35841
  try {
35830
35842
  return fs16.realpathSync(_scanDirRaw);
@@ -35967,7 +35979,7 @@ var init_secretscan = __esm(() => {
35967
35979
 
35968
35980
  // src/tools/resolve-working-directory.ts
35969
35981
  import * as fs17 from "fs";
35970
- import * as path27 from "path";
35982
+ import * as path28 from "path";
35971
35983
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
35972
35984
  if (workingDirectory == null || workingDirectory === "") {
35973
35985
  return { success: true, directory: fallbackDirectory };
@@ -35987,15 +35999,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
35987
35999
  };
35988
36000
  }
35989
36001
  }
35990
- const normalizedDir = path27.normalize(workingDirectory);
35991
- const pathParts = normalizedDir.split(path27.sep);
36002
+ const normalizedDir = path28.normalize(workingDirectory);
36003
+ const pathParts = normalizedDir.split(path28.sep);
35992
36004
  if (pathParts.includes("..")) {
35993
36005
  return {
35994
36006
  success: false,
35995
36007
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
35996
36008
  };
35997
36009
  }
35998
- const resolvedDir = path27.resolve(normalizedDir);
36010
+ const resolvedDir = path28.resolve(normalizedDir);
35999
36011
  try {
36000
36012
  const realPath = fs17.realpathSync(resolvedDir);
36001
36013
  return { success: true, directory: realPath };
@@ -36010,7 +36022,7 @@ var init_resolve_working_directory = () => {};
36010
36022
 
36011
36023
  // src/tools/test-runner.ts
36012
36024
  import * as fs18 from "fs";
36013
- import * as path28 from "path";
36025
+ import * as path29 from "path";
36014
36026
  function isAbsolutePath(str) {
36015
36027
  if (str.startsWith("/"))
36016
36028
  return true;
@@ -36075,14 +36087,14 @@ function hasDevDependency(devDeps, ...patterns) {
36075
36087
  return hasPackageJsonDependency(devDeps, ...patterns);
36076
36088
  }
36077
36089
  function detectGoTest(cwd) {
36078
- return fs18.existsSync(path28.join(cwd, "go.mod")) && isCommandAvailable("go");
36090
+ return fs18.existsSync(path29.join(cwd, "go.mod")) && isCommandAvailable("go");
36079
36091
  }
36080
36092
  function detectJavaMaven(cwd) {
36081
- return fs18.existsSync(path28.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
36093
+ return fs18.existsSync(path29.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
36082
36094
  }
36083
36095
  function detectGradle(cwd) {
36084
- const hasBuildFile = fs18.existsSync(path28.join(cwd, "build.gradle")) || fs18.existsSync(path28.join(cwd, "build.gradle.kts"));
36085
- const hasGradlew = fs18.existsSync(path28.join(cwd, "gradlew")) || fs18.existsSync(path28.join(cwd, "gradlew.bat"));
36096
+ const hasBuildFile = fs18.existsSync(path29.join(cwd, "build.gradle")) || fs18.existsSync(path29.join(cwd, "build.gradle.kts"));
36097
+ const hasGradlew = fs18.existsSync(path29.join(cwd, "gradlew")) || fs18.existsSync(path29.join(cwd, "gradlew.bat"));
36086
36098
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
36087
36099
  }
36088
36100
  function detectDotnetTest(cwd) {
@@ -36095,30 +36107,30 @@ function detectDotnetTest(cwd) {
36095
36107
  }
36096
36108
  }
36097
36109
  function detectCTest(cwd) {
36098
- const hasSource = fs18.existsSync(path28.join(cwd, "CMakeLists.txt"));
36099
- const hasBuildCache = fs18.existsSync(path28.join(cwd, "CMakeCache.txt")) || fs18.existsSync(path28.join(cwd, "build", "CMakeCache.txt"));
36110
+ const hasSource = fs18.existsSync(path29.join(cwd, "CMakeLists.txt"));
36111
+ const hasBuildCache = fs18.existsSync(path29.join(cwd, "CMakeCache.txt")) || fs18.existsSync(path29.join(cwd, "build", "CMakeCache.txt"));
36100
36112
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
36101
36113
  }
36102
36114
  function detectSwiftTest(cwd) {
36103
- return fs18.existsSync(path28.join(cwd, "Package.swift")) && isCommandAvailable("swift");
36115
+ return fs18.existsSync(path29.join(cwd, "Package.swift")) && isCommandAvailable("swift");
36104
36116
  }
36105
36117
  function detectDartTest(cwd) {
36106
- return fs18.existsSync(path28.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
36118
+ return fs18.existsSync(path29.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
36107
36119
  }
36108
36120
  function detectRSpec(cwd) {
36109
- const hasRSpecFile = fs18.existsSync(path28.join(cwd, ".rspec"));
36110
- const hasGemfile = fs18.existsSync(path28.join(cwd, "Gemfile"));
36111
- const hasSpecDir = fs18.existsSync(path28.join(cwd, "spec"));
36121
+ const hasRSpecFile = fs18.existsSync(path29.join(cwd, ".rspec"));
36122
+ const hasGemfile = fs18.existsSync(path29.join(cwd, "Gemfile"));
36123
+ const hasSpecDir = fs18.existsSync(path29.join(cwd, "spec"));
36112
36124
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
36113
36125
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
36114
36126
  }
36115
36127
  function detectMinitest(cwd) {
36116
- return fs18.existsSync(path28.join(cwd, "test")) && (fs18.existsSync(path28.join(cwd, "Gemfile")) || fs18.existsSync(path28.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
36128
+ return fs18.existsSync(path29.join(cwd, "test")) && (fs18.existsSync(path29.join(cwd, "Gemfile")) || fs18.existsSync(path29.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
36117
36129
  }
36118
36130
  async function detectTestFramework(cwd) {
36119
36131
  const baseDir = cwd;
36120
36132
  try {
36121
- const packageJsonPath = path28.join(baseDir, "package.json");
36133
+ const packageJsonPath = path29.join(baseDir, "package.json");
36122
36134
  if (fs18.existsSync(packageJsonPath)) {
36123
36135
  const content = fs18.readFileSync(packageJsonPath, "utf-8");
36124
36136
  const pkg = JSON.parse(content);
@@ -36139,16 +36151,16 @@ async function detectTestFramework(cwd) {
36139
36151
  return "jest";
36140
36152
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
36141
36153
  return "mocha";
36142
- if (fs18.existsSync(path28.join(baseDir, "bun.lockb")) || fs18.existsSync(path28.join(baseDir, "bun.lock"))) {
36154
+ if (fs18.existsSync(path29.join(baseDir, "bun.lockb")) || fs18.existsSync(path29.join(baseDir, "bun.lock"))) {
36143
36155
  if (scripts.test?.includes("bun"))
36144
36156
  return "bun";
36145
36157
  }
36146
36158
  }
36147
36159
  } catch {}
36148
36160
  try {
36149
- const pyprojectTomlPath = path28.join(baseDir, "pyproject.toml");
36150
- const setupCfgPath = path28.join(baseDir, "setup.cfg");
36151
- const requirementsTxtPath = path28.join(baseDir, "requirements.txt");
36161
+ const pyprojectTomlPath = path29.join(baseDir, "pyproject.toml");
36162
+ const setupCfgPath = path29.join(baseDir, "setup.cfg");
36163
+ const requirementsTxtPath = path29.join(baseDir, "requirements.txt");
36152
36164
  if (fs18.existsSync(pyprojectTomlPath)) {
36153
36165
  const content = fs18.readFileSync(pyprojectTomlPath, "utf-8");
36154
36166
  if (content.includes("[tool.pytest"))
@@ -36168,7 +36180,7 @@ async function detectTestFramework(cwd) {
36168
36180
  }
36169
36181
  } catch {}
36170
36182
  try {
36171
- const cargoTomlPath = path28.join(baseDir, "Cargo.toml");
36183
+ const cargoTomlPath = path29.join(baseDir, "Cargo.toml");
36172
36184
  if (fs18.existsSync(cargoTomlPath)) {
36173
36185
  const content = fs18.readFileSync(cargoTomlPath, "utf-8");
36174
36186
  if (content.includes("[dev-dependencies]")) {
@@ -36179,9 +36191,9 @@ async function detectTestFramework(cwd) {
36179
36191
  }
36180
36192
  } catch {}
36181
36193
  try {
36182
- const pesterConfigPath = path28.join(baseDir, "pester.config.ps1");
36183
- const pesterConfigJsonPath = path28.join(baseDir, "pester.config.ps1.json");
36184
- const pesterPs1Path = path28.join(baseDir, "tests.ps1");
36194
+ const pesterConfigPath = path29.join(baseDir, "pester.config.ps1");
36195
+ const pesterConfigJsonPath = path29.join(baseDir, "pester.config.ps1.json");
36196
+ const pesterPs1Path = path29.join(baseDir, "tests.ps1");
36185
36197
  if (fs18.existsSync(pesterConfigPath) || fs18.existsSync(pesterConfigJsonPath) || fs18.existsSync(pesterPs1Path)) {
36186
36198
  return "pester";
36187
36199
  }
@@ -36214,8 +36226,8 @@ function getTestFilesFromConvention(sourceFiles) {
36214
36226
  const testFiles = [];
36215
36227
  for (const file3 of sourceFiles) {
36216
36228
  const normalizedPath = file3.replace(/\\/g, "/");
36217
- const basename5 = path28.basename(file3);
36218
- const dirname12 = path28.dirname(file3);
36229
+ const basename5 = path29.basename(file3);
36230
+ const dirname12 = path29.dirname(file3);
36219
36231
  if (hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
36220
36232
  if (!testFiles.includes(file3)) {
36221
36233
  testFiles.push(file3);
@@ -36224,13 +36236,13 @@ function getTestFilesFromConvention(sourceFiles) {
36224
36236
  }
36225
36237
  for (const _pattern of TEST_PATTERNS) {
36226
36238
  const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
36227
- const ext = path28.extname(basename5);
36239
+ const ext = path29.extname(basename5);
36228
36240
  const possibleTestFiles = [
36229
- path28.join(dirname12, `${nameWithoutExt}.spec${ext}`),
36230
- path28.join(dirname12, `${nameWithoutExt}.test${ext}`),
36231
- path28.join(dirname12, "__tests__", `${nameWithoutExt}${ext}`),
36232
- path28.join(dirname12, "tests", `${nameWithoutExt}${ext}`),
36233
- path28.join(dirname12, "test", `${nameWithoutExt}${ext}`)
36241
+ path29.join(dirname12, `${nameWithoutExt}.spec${ext}`),
36242
+ path29.join(dirname12, `${nameWithoutExt}.test${ext}`),
36243
+ path29.join(dirname12, "__tests__", `${nameWithoutExt}${ext}`),
36244
+ path29.join(dirname12, "tests", `${nameWithoutExt}${ext}`),
36245
+ path29.join(dirname12, "test", `${nameWithoutExt}${ext}`)
36234
36246
  ];
36235
36247
  for (const testFile of possibleTestFiles) {
36236
36248
  if (fs18.existsSync(testFile) && !testFiles.includes(testFile)) {
@@ -36250,7 +36262,7 @@ async function getTestFilesFromGraph(sourceFiles) {
36250
36262
  for (const testFile of candidateTestFiles) {
36251
36263
  try {
36252
36264
  const content = fs18.readFileSync(testFile, "utf-8");
36253
- const testDir = path28.dirname(testFile);
36265
+ const testDir = path29.dirname(testFile);
36254
36266
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
36255
36267
  let match;
36256
36268
  match = importRegex.exec(content);
@@ -36258,8 +36270,8 @@ async function getTestFilesFromGraph(sourceFiles) {
36258
36270
  const importPath = match[1];
36259
36271
  let resolvedImport;
36260
36272
  if (importPath.startsWith(".")) {
36261
- resolvedImport = path28.resolve(testDir, importPath);
36262
- const existingExt = path28.extname(resolvedImport);
36273
+ resolvedImport = path29.resolve(testDir, importPath);
36274
+ const existingExt = path29.extname(resolvedImport);
36263
36275
  if (!existingExt) {
36264
36276
  for (const extToTry of [
36265
36277
  ".ts",
@@ -36279,12 +36291,12 @@ async function getTestFilesFromGraph(sourceFiles) {
36279
36291
  } else {
36280
36292
  continue;
36281
36293
  }
36282
- const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
36283
- const importDir = path28.dirname(resolvedImport);
36294
+ const importBasename = path29.basename(resolvedImport, path29.extname(resolvedImport));
36295
+ const importDir = path29.dirname(resolvedImport);
36284
36296
  for (const sourceFile of sourceFiles) {
36285
- const sourceDir = path28.dirname(sourceFile);
36286
- const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
36287
- const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test");
36297
+ const sourceDir = path29.dirname(sourceFile);
36298
+ const sourceBasename = path29.basename(sourceFile, path29.extname(sourceFile));
36299
+ const isRelatedDir = importDir === sourceDir || importDir === path29.join(sourceDir, "__tests__") || importDir === path29.join(sourceDir, "tests") || importDir === path29.join(sourceDir, "test");
36288
36300
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
36289
36301
  if (!testFiles.includes(testFile)) {
36290
36302
  testFiles.push(testFile);
@@ -36299,8 +36311,8 @@ async function getTestFilesFromGraph(sourceFiles) {
36299
36311
  while (match !== null) {
36300
36312
  const importPath = match[1];
36301
36313
  if (importPath.startsWith(".")) {
36302
- let resolvedImport = path28.resolve(testDir, importPath);
36303
- const existingExt = path28.extname(resolvedImport);
36314
+ let resolvedImport = path29.resolve(testDir, importPath);
36315
+ const existingExt = path29.extname(resolvedImport);
36304
36316
  if (!existingExt) {
36305
36317
  for (const extToTry of [
36306
36318
  ".ts",
@@ -36317,12 +36329,12 @@ async function getTestFilesFromGraph(sourceFiles) {
36317
36329
  }
36318
36330
  }
36319
36331
  }
36320
- const importDir = path28.dirname(resolvedImport);
36321
- const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
36332
+ const importDir = path29.dirname(resolvedImport);
36333
+ const importBasename = path29.basename(resolvedImport, path29.extname(resolvedImport));
36322
36334
  for (const sourceFile of sourceFiles) {
36323
- const sourceDir = path28.dirname(sourceFile);
36324
- const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
36325
- const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test");
36335
+ const sourceDir = path29.dirname(sourceFile);
36336
+ const sourceBasename = path29.basename(sourceFile, path29.extname(sourceFile));
36337
+ const isRelatedDir = importDir === sourceDir || importDir === path29.join(sourceDir, "__tests__") || importDir === path29.join(sourceDir, "tests") || importDir === path29.join(sourceDir, "test");
36326
36338
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
36327
36339
  if (!testFiles.includes(testFile)) {
36328
36340
  testFiles.push(testFile);
@@ -36407,8 +36419,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
36407
36419
  return ["mvn", "test"];
36408
36420
  case "gradle": {
36409
36421
  const isWindows = process.platform === "win32";
36410
- const hasGradlewBat = fs18.existsSync(path28.join(baseDir, "gradlew.bat"));
36411
- const hasGradlew = fs18.existsSync(path28.join(baseDir, "gradlew"));
36422
+ const hasGradlewBat = fs18.existsSync(path29.join(baseDir, "gradlew.bat"));
36423
+ const hasGradlew = fs18.existsSync(path29.join(baseDir, "gradlew"));
36412
36424
  if (hasGradlewBat && isWindows)
36413
36425
  return ["gradlew.bat", "test"];
36414
36426
  if (hasGradlew)
@@ -36425,7 +36437,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
36425
36437
  "cmake-build-release",
36426
36438
  "out"
36427
36439
  ];
36428
- const actualBuildDir = buildDirCandidates.find((d) => fs18.existsSync(path28.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
36440
+ const actualBuildDir = buildDirCandidates.find((d) => fs18.existsSync(path29.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
36429
36441
  return ["ctest", "--test-dir", actualBuildDir];
36430
36442
  }
36431
36443
  case "swift-test":
@@ -36993,7 +37005,7 @@ var init_test_runner = __esm(() => {
36993
37005
  let effectiveScope = scope;
36994
37006
  if (scope === "all") {} else if (scope === "convention") {
36995
37007
  const sourceFiles = args2.files.filter((f) => {
36996
- const ext = path28.extname(f).toLowerCase();
37008
+ const ext = path29.extname(f).toLowerCase();
36997
37009
  return SOURCE_EXTENSIONS.has(ext);
36998
37010
  });
36999
37011
  if (sourceFiles.length === 0) {
@@ -37009,7 +37021,7 @@ var init_test_runner = __esm(() => {
37009
37021
  testFiles = getTestFilesFromConvention(sourceFiles);
37010
37022
  } else if (scope === "graph") {
37011
37023
  const sourceFiles = args2.files.filter((f) => {
37012
- const ext = path28.extname(f).toLowerCase();
37024
+ const ext = path29.extname(f).toLowerCase();
37013
37025
  return SOURCE_EXTENSIONS.has(ext);
37014
37026
  });
37015
37027
  if (sourceFiles.length === 0) {
@@ -37063,7 +37075,7 @@ var init_test_runner = __esm(() => {
37063
37075
 
37064
37076
  // src/services/preflight-service.ts
37065
37077
  import * as fs19 from "fs";
37066
- import * as path29 from "path";
37078
+ import * as path30 from "path";
37067
37079
  function validateDirectoryPath(dir) {
37068
37080
  if (!dir || typeof dir !== "string") {
37069
37081
  throw new Error("Directory path is required");
@@ -37071,8 +37083,8 @@ function validateDirectoryPath(dir) {
37071
37083
  if (dir.includes("..")) {
37072
37084
  throw new Error("Directory path must not contain path traversal sequences");
37073
37085
  }
37074
- const normalized = path29.normalize(dir);
37075
- const absolutePath = path29.isAbsolute(normalized) ? normalized : path29.resolve(normalized);
37086
+ const normalized = path30.normalize(dir);
37087
+ const absolutePath = path30.isAbsolute(normalized) ? normalized : path30.resolve(normalized);
37076
37088
  return absolutePath;
37077
37089
  }
37078
37090
  function validateTimeout(timeoutMs, defaultValue) {
@@ -37095,7 +37107,7 @@ function validateTimeout(timeoutMs, defaultValue) {
37095
37107
  }
37096
37108
  function getPackageVersion(dir) {
37097
37109
  try {
37098
- const packagePath = path29.join(dir, "package.json");
37110
+ const packagePath = path30.join(dir, "package.json");
37099
37111
  if (fs19.existsSync(packagePath)) {
37100
37112
  const content = fs19.readFileSync(packagePath, "utf-8");
37101
37113
  const pkg = JSON.parse(content);
@@ -37106,7 +37118,7 @@ function getPackageVersion(dir) {
37106
37118
  }
37107
37119
  function getChangelogVersion(dir) {
37108
37120
  try {
37109
- const changelogPath = path29.join(dir, "CHANGELOG.md");
37121
+ const changelogPath = path30.join(dir, "CHANGELOG.md");
37110
37122
  if (fs19.existsSync(changelogPath)) {
37111
37123
  const content = fs19.readFileSync(changelogPath, "utf-8");
37112
37124
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
@@ -37120,7 +37132,7 @@ function getChangelogVersion(dir) {
37120
37132
  function getVersionFileVersion(dir) {
37121
37133
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
37122
37134
  for (const file3 of possibleFiles) {
37123
- const filePath = path29.join(dir, file3);
37135
+ const filePath = path30.join(dir, file3);
37124
37136
  if (fs19.existsSync(filePath)) {
37125
37137
  try {
37126
37138
  const content = fs19.readFileSync(filePath, "utf-8").trim();
@@ -37648,7 +37660,7 @@ __export(exports_gate_evidence, {
37648
37660
  DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
37649
37661
  });
37650
37662
  import { mkdirSync as mkdirSync12, readFileSync as readFileSync17, renameSync as renameSync10, unlinkSync as unlinkSync5 } from "fs";
37651
- import * as path36 from "path";
37663
+ import * as path37 from "path";
37652
37664
  function isValidTaskId2(taskId) {
37653
37665
  if (!taskId)
37654
37666
  return false;
@@ -37695,10 +37707,10 @@ function expandRequiredGates(existingGates, newAgentType) {
37695
37707
  return combined.sort();
37696
37708
  }
37697
37709
  function getEvidenceDir(directory) {
37698
- return path36.join(directory, ".swarm", "evidence");
37710
+ return path37.join(directory, ".swarm", "evidence");
37699
37711
  }
37700
37712
  function getEvidencePath(directory, taskId) {
37701
- return path36.join(getEvidenceDir(directory), `${taskId}.json`);
37713
+ return path37.join(getEvidenceDir(directory), `${taskId}.json`);
37702
37714
  }
37703
37715
  function readExisting(evidencePath) {
37704
37716
  try {
@@ -37809,12 +37821,12 @@ __export(exports_review_receipt, {
37809
37821
  });
37810
37822
  import * as crypto5 from "crypto";
37811
37823
  import * as fs28 from "fs";
37812
- import * as path38 from "path";
37824
+ import * as path39 from "path";
37813
37825
  function resolveReceiptsDir(directory) {
37814
- return path38.join(directory, ".swarm", "review-receipts");
37826
+ return path39.join(directory, ".swarm", "review-receipts");
37815
37827
  }
37816
37828
  function resolveReceiptIndexPath(directory) {
37817
- return path38.join(resolveReceiptsDir(directory), "index.json");
37829
+ return path39.join(resolveReceiptsDir(directory), "index.json");
37818
37830
  }
37819
37831
  function buildReceiptFilename(id, date9) {
37820
37832
  const dateStr = date9.toISOString().slice(0, 10);
@@ -37853,7 +37865,7 @@ async function readReceiptIndex(directory) {
37853
37865
  }
37854
37866
  async function writeReceiptIndex(directory, index) {
37855
37867
  const indexPath = resolveReceiptIndexPath(directory);
37856
- const dir = path38.dirname(indexPath);
37868
+ const dir = path39.dirname(indexPath);
37857
37869
  await fs28.promises.mkdir(dir, { recursive: true });
37858
37870
  const tmpPath = `${indexPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
37859
37871
  await fs28.promises.writeFile(tmpPath, JSON.stringify(index, null, 2), "utf-8");
@@ -37864,7 +37876,7 @@ async function persistReviewReceipt(directory, receipt) {
37864
37876
  await fs28.promises.mkdir(receiptsDir, { recursive: true });
37865
37877
  const now = new Date(receipt.reviewed_at);
37866
37878
  const filename = buildReceiptFilename(receipt.id, now);
37867
- const receiptPath = path38.join(receiptsDir, filename);
37879
+ const receiptPath = path39.join(receiptsDir, filename);
37868
37880
  const tmpPath = `${receiptPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
37869
37881
  await fs28.promises.writeFile(tmpPath, JSON.stringify(receipt, null, 2), "utf-8");
37870
37882
  fs28.renameSync(tmpPath, receiptPath);
@@ -37886,7 +37898,7 @@ async function readReceiptById(directory, receiptId) {
37886
37898
  const entry = index.entries.find((e) => e.id === receiptId);
37887
37899
  if (!entry)
37888
37900
  return null;
37889
- const receiptPath = path38.join(resolveReceiptsDir(directory), entry.filename);
37901
+ const receiptPath = path39.join(resolveReceiptsDir(directory), entry.filename);
37890
37902
  try {
37891
37903
  const content = await fs28.promises.readFile(receiptPath, "utf-8");
37892
37904
  return JSON.parse(content);
@@ -37899,7 +37911,7 @@ async function readReceiptsByScopeHash(directory, scopeHash) {
37899
37911
  const matching = index.entries.filter((e) => e.scope_hash === scopeHash).sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
37900
37912
  const receipts = [];
37901
37913
  for (const entry of matching) {
37902
- const receiptPath = path38.join(resolveReceiptsDir(directory), entry.filename);
37914
+ const receiptPath = path39.join(resolveReceiptsDir(directory), entry.filename);
37903
37915
  try {
37904
37916
  const content = await fs28.promises.readFile(receiptPath, "utf-8");
37905
37917
  receipts.push(JSON.parse(content));
@@ -37912,7 +37924,7 @@ async function readAllReceipts(directory) {
37912
37924
  const sorted = [...index.entries].sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
37913
37925
  const receipts = [];
37914
37926
  for (const entry of sorted) {
37915
- const receiptPath = path38.join(resolveReceiptsDir(directory), entry.filename);
37927
+ const receiptPath = path39.join(resolveReceiptsDir(directory), entry.filename);
37916
37928
  try {
37917
37929
  const content = await fs28.promises.readFile(receiptPath, "utf-8");
37918
37930
  receipts.push(JSON.parse(content));
@@ -38048,13 +38060,13 @@ __export(exports_doc_scan, {
38048
38060
  import * as crypto6 from "crypto";
38049
38061
  import * as fs31 from "fs";
38050
38062
  import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
38051
- import * as path42 from "path";
38063
+ import * as path43 from "path";
38052
38064
  function normalizeSeparators(filePath) {
38053
38065
  return filePath.replace(/\\/g, "/");
38054
38066
  }
38055
38067
  function matchesDocPattern(filePath, patterns) {
38056
38068
  const normalizedPath = normalizeSeparators(filePath);
38057
- const basename6 = path42.basename(filePath);
38069
+ const basename6 = path43.basename(filePath);
38058
38070
  for (const pattern of patterns) {
38059
38071
  if (!pattern.includes("/") && !pattern.includes("\\")) {
38060
38072
  if (basename6 === pattern) {
@@ -38110,7 +38122,7 @@ function stripMarkdown(text) {
38110
38122
  return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
38111
38123
  }
38112
38124
  async function scanDocIndex(directory) {
38113
- const manifestPath = path42.join(directory, ".swarm", "doc-manifest.json");
38125
+ const manifestPath = path43.join(directory, ".swarm", "doc-manifest.json");
38114
38126
  const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
38115
38127
  const extraPatterns = [
38116
38128
  "ARCHITECTURE.md",
@@ -38127,7 +38139,7 @@ async function scanDocIndex(directory) {
38127
38139
  let cacheValid = true;
38128
38140
  for (const file3 of existingManifest.files) {
38129
38141
  try {
38130
- const fullPath = path42.join(directory, file3.path);
38142
+ const fullPath = path43.join(directory, file3.path);
38131
38143
  const stat2 = fs31.statSync(fullPath);
38132
38144
  if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
38133
38145
  cacheValid = false;
@@ -38157,7 +38169,7 @@ async function scanDocIndex(directory) {
38157
38169
  }
38158
38170
  const entries = rawEntries.filter((e) => typeof e === "string");
38159
38171
  for (const entry of entries) {
38160
- const fullPath = path42.join(directory, entry);
38172
+ const fullPath = path43.join(directory, entry);
38161
38173
  let stat2;
38162
38174
  try {
38163
38175
  stat2 = fs31.statSync(fullPath);
@@ -38193,7 +38205,7 @@ async function scanDocIndex(directory) {
38193
38205
  } catch {
38194
38206
  continue;
38195
38207
  }
38196
- const { title, summary } = extractTitleAndSummary(content, path42.basename(entry));
38208
+ const { title, summary } = extractTitleAndSummary(content, path43.basename(entry));
38197
38209
  const lineCount = content.split(`
38198
38210
  `).length;
38199
38211
  discoveredFiles.push({
@@ -38219,7 +38231,7 @@ async function scanDocIndex(directory) {
38219
38231
  files: discoveredFiles
38220
38232
  };
38221
38233
  try {
38222
- await mkdir6(path42.dirname(manifestPath), { recursive: true });
38234
+ await mkdir6(path43.dirname(manifestPath), { recursive: true });
38223
38235
  await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
38224
38236
  } catch {}
38225
38237
  return { manifest, cached: false };
@@ -38258,7 +38270,7 @@ function extractConstraintsFromContent(content) {
38258
38270
  return constraints;
38259
38271
  }
38260
38272
  async function extractDocConstraints(directory, taskFiles, taskDescription) {
38261
- const manifestPath = path42.join(directory, ".swarm", "doc-manifest.json");
38273
+ const manifestPath = path43.join(directory, ".swarm", "doc-manifest.json");
38262
38274
  let manifest;
38263
38275
  try {
38264
38276
  const content = await readFile6(manifestPath, "utf-8");
@@ -38284,7 +38296,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
38284
38296
  }
38285
38297
  let fullContent;
38286
38298
  try {
38287
- fullContent = await readFile6(path42.join(directory, docFile.path), "utf-8");
38299
+ fullContent = await readFile6(path43.join(directory, docFile.path), "utf-8");
38288
38300
  } catch {
38289
38301
  skippedCount++;
38290
38302
  continue;
@@ -38307,7 +38319,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
38307
38319
  tier: "swarm",
38308
38320
  lesson: constraint,
38309
38321
  category: "architecture",
38310
- tags: ["doc-scan", path42.basename(docFile.path)],
38322
+ tags: ["doc-scan", path43.basename(docFile.path)],
38311
38323
  scope: "global",
38312
38324
  confidence: 0.5,
38313
38325
  status: "candidate",
@@ -38380,7 +38392,7 @@ var init_doc_scan = __esm(() => {
38380
38392
  }
38381
38393
  } catch {}
38382
38394
  if (force) {
38383
- const manifestPath = path42.join(directory, ".swarm", "doc-manifest.json");
38395
+ const manifestPath = path43.join(directory, ".swarm", "doc-manifest.json");
38384
38396
  try {
38385
38397
  fs31.unlinkSync(manifestPath);
38386
38398
  } catch {}
@@ -38435,9 +38447,9 @@ __export(exports_curator_drift, {
38435
38447
  buildDriftInjectionText: () => buildDriftInjectionText
38436
38448
  });
38437
38449
  import * as fs34 from "fs";
38438
- import * as path45 from "path";
38450
+ import * as path46 from "path";
38439
38451
  async function readPriorDriftReports(directory) {
38440
- const swarmDir = path45.join(directory, ".swarm");
38452
+ const swarmDir = path46.join(directory, ".swarm");
38441
38453
  const entries = await fs34.promises.readdir(swarmDir).catch(() => null);
38442
38454
  if (entries === null)
38443
38455
  return [];
@@ -38464,7 +38476,7 @@ async function readPriorDriftReports(directory) {
38464
38476
  async function writeDriftReport(directory, report) {
38465
38477
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
38466
38478
  const filePath = validateSwarmPath(directory, filename);
38467
- const swarmDir = path45.dirname(filePath);
38479
+ const swarmDir = path46.dirname(filePath);
38468
38480
  await fs34.promises.mkdir(swarmDir, { recursive: true });
38469
38481
  try {
38470
38482
  await fs34.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
@@ -40057,11 +40069,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
40057
40069
  throw toThrow;
40058
40070
  }, "quit_");
40059
40071
  var scriptDirectory = "";
40060
- function locateFile(path55) {
40072
+ function locateFile(path56) {
40061
40073
  if (Module["locateFile"]) {
40062
- return Module["locateFile"](path55, scriptDirectory);
40074
+ return Module["locateFile"](path56, scriptDirectory);
40063
40075
  }
40064
- return scriptDirectory + path55;
40076
+ return scriptDirectory + path56;
40065
40077
  }
40066
40078
  __name(locateFile, "locateFile");
40067
40079
  var readAsync, readBinary;
@@ -41801,13 +41813,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
41801
41813
  });
41802
41814
 
41803
41815
  // src/lang/runtime.ts
41804
- import * as path55 from "path";
41816
+ import * as path56 from "path";
41805
41817
  import { fileURLToPath as fileURLToPath2 } from "url";
41806
41818
  async function initTreeSitter() {
41807
41819
  if (treeSitterInitialized) {
41808
41820
  return;
41809
41821
  }
41810
- const thisDir = path55.dirname(fileURLToPath2(import.meta.url));
41822
+ const thisDir = path56.dirname(fileURLToPath2(import.meta.url));
41811
41823
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41812
41824
  if (isSource) {
41813
41825
  await Parser.init();
@@ -41815,7 +41827,7 @@ async function initTreeSitter() {
41815
41827
  const grammarsDir = getGrammarsDirAbsolute();
41816
41828
  await Parser.init({
41817
41829
  locateFile(scriptName) {
41818
- return path55.join(grammarsDir, scriptName);
41830
+ return path56.join(grammarsDir, scriptName);
41819
41831
  }
41820
41832
  });
41821
41833
  }
@@ -41836,9 +41848,9 @@ function getWasmFileName(languageId) {
41836
41848
  return `tree-sitter-${sanitized}.wasm`;
41837
41849
  }
41838
41850
  function getGrammarsDirAbsolute() {
41839
- const thisDir = path55.dirname(fileURLToPath2(import.meta.url));
41851
+ const thisDir = path56.dirname(fileURLToPath2(import.meta.url));
41840
41852
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41841
- return isSource ? path55.join(thisDir, "grammars") : path55.join(thisDir, "lang", "grammars");
41853
+ return isSource ? path56.join(thisDir, "grammars") : path56.join(thisDir, "lang", "grammars");
41842
41854
  }
41843
41855
  async function loadGrammar(languageId) {
41844
41856
  if (typeof languageId !== "string" || languageId.length > 100) {
@@ -41854,7 +41866,7 @@ async function loadGrammar(languageId) {
41854
41866
  await initTreeSitter();
41855
41867
  const parser = new Parser;
41856
41868
  const wasmFileName = getWasmFileName(normalizedId);
41857
- const wasmPath = path55.join(getGrammarsDirAbsolute(), wasmFileName);
41869
+ const wasmPath = path56.join(getGrammarsDirAbsolute(), wasmFileName);
41858
41870
  const { existsSync: existsSync33 } = await import("fs");
41859
41871
  if (!existsSync33(wasmPath)) {
41860
41872
  throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
@@ -41901,7 +41913,7 @@ var init_runtime = __esm(() => {
41901
41913
  });
41902
41914
 
41903
41915
  // src/index.ts
41904
- import * as path73 from "path";
41916
+ import * as path74 from "path";
41905
41917
 
41906
41918
  // src/agents/index.ts
41907
41919
  init_config();
@@ -46668,7 +46680,9 @@ async function handleClarifyCommand(_directory, args2) {
46668
46680
  // src/commands/close.ts
46669
46681
  init_schema();
46670
46682
  init_manager();
46683
+ import { execFileSync } from "child_process";
46671
46684
  import { promises as fs11 } from "fs";
46685
+ import path17 from "path";
46672
46686
 
46673
46687
  // src/hooks/knowledge-reader.ts
46674
46688
  init_knowledge_store();
@@ -48053,87 +48067,183 @@ var write_retro = createSwarmTool({
48053
48067
  });
48054
48068
 
48055
48069
  // src/commands/close.ts
48056
- async function handleCloseCommand(directory, _args) {
48070
+ async function handleCloseCommand(directory, args2) {
48057
48071
  const planPath = validateSwarmPath(directory, "plan.json");
48058
- let planData;
48072
+ let planExists = false;
48073
+ let planData = {
48074
+ title: path17.basename(directory) || "Ad-hoc session",
48075
+ phases: []
48076
+ };
48059
48077
  try {
48060
48078
  const content = await fs11.readFile(planPath, "utf-8");
48061
48079
  planData = JSON.parse(content);
48080
+ planExists = true;
48062
48081
  } catch (error93) {
48063
- return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
48082
+ if (error93?.code !== "ENOENT") {
48083
+ return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
48084
+ }
48085
+ const swarmDirExists = await fs11.access(path17.join(directory, ".swarm")).then(() => true).catch(() => false);
48086
+ if (!swarmDirExists) {
48087
+ return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
48088
+ }
48064
48089
  }
48065
48090
  const phases = planData.phases ?? [];
48066
48091
  const inProgressPhases = phases.filter((p) => p.status === "in_progress");
48067
- const allDone = phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
48068
- if (allDone) {
48069
- const closedCount = phases.filter((p) => p.status === "closed").length;
48070
- const blockedCount = phases.filter((p) => p.status === "blocked").length;
48071
- const completeCount = phases.filter((p) => p.status === "complete" || p.status === "completed").length;
48072
- return `\u2139\uFE0F Swarm already closed. ${completeCount} phases complete, ${closedCount} phases closed, ${blockedCount} phases blocked. No action taken.`;
48092
+ let planAlreadyDone = false;
48093
+ if (planExists) {
48094
+ planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
48073
48095
  }
48074
48096
  const config3 = KnowledgeConfigSchema.parse({});
48075
48097
  const projectName = planData.title ?? "Unknown Project";
48076
48098
  const closedPhases = [];
48077
48099
  const closedTasks = [];
48078
48100
  const warnings = [];
48079
- for (const phase of inProgressPhases) {
48080
- closedPhases.push(phase.id);
48081
- const retroResult = await executeWriteRetro({
48082
- phase: phase.id,
48083
- summary: "Phase closed via /swarm close",
48084
- task_count: Math.max(1, (phase.tasks ?? []).length),
48085
- task_complexity: "simple",
48086
- total_tool_calls: 0,
48087
- coder_revisions: 0,
48088
- reviewer_rejections: 0,
48089
- test_failures: 0,
48090
- security_findings: 0,
48091
- integration_issues: 0
48092
- }, directory);
48093
- try {
48094
- const parsed = JSON.parse(retroResult);
48095
- if (parsed.success !== true) {
48096
- warnings.push(`Retrospective write failed for phase ${phase.id}`);
48101
+ if (!planAlreadyDone) {
48102
+ for (const phase of inProgressPhases) {
48103
+ closedPhases.push(phase.id);
48104
+ let retroResult;
48105
+ try {
48106
+ retroResult = await executeWriteRetro({
48107
+ phase: phase.id,
48108
+ summary: "Phase closed via /swarm close",
48109
+ task_count: Math.max(1, (phase.tasks ?? []).length),
48110
+ task_complexity: "simple",
48111
+ total_tool_calls: 0,
48112
+ coder_revisions: 0,
48113
+ reviewer_rejections: 0,
48114
+ test_failures: 0,
48115
+ security_findings: 0,
48116
+ integration_issues: 0
48117
+ }, directory);
48118
+ } catch (retroError) {
48119
+ warnings.push(`Retrospective write threw for phase ${phase.id}: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
48120
+ }
48121
+ if (retroResult !== undefined) {
48122
+ try {
48123
+ const parsed = JSON.parse(retroResult);
48124
+ if (parsed.success !== true) {
48125
+ warnings.push(`Retrospective write failed for phase ${phase.id}`);
48126
+ }
48127
+ } catch {}
48097
48128
  }
48098
- } catch {}
48099
- for (const task of phase.tasks ?? []) {
48100
- if (task.status !== "completed" && task.status !== "complete") {
48101
- closedTasks.push(task.id);
48129
+ for (const task of phase.tasks ?? []) {
48130
+ if (task.status !== "completed" && task.status !== "complete") {
48131
+ closedTasks.push(task.id);
48132
+ }
48102
48133
  }
48103
48134
  }
48104
48135
  }
48136
+ const lessonsFilePath = path17.join(directory, ".swarm", "close-lessons.md");
48137
+ let explicitLessons = [];
48105
48138
  try {
48106
- await curateAndStoreSwarm([], projectName, { phase_number: 0 }, directory, config3);
48139
+ const lessonsText = await fs11.readFile(lessonsFilePath, "utf-8");
48140
+ explicitLessons = lessonsText.split(`
48141
+ `).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
48142
+ } catch {}
48143
+ let curationSucceeded = false;
48144
+ try {
48145
+ await curateAndStoreSwarm(explicitLessons, projectName, { phase_number: 0 }, directory, config3);
48146
+ curationSucceeded = true;
48107
48147
  } catch (error93) {
48108
48148
  console.warn("[close-command] curateAndStoreSwarm error:", error93);
48109
48149
  }
48110
- for (const phase of phases) {
48111
- if (phase.status !== "complete" && phase.status !== "completed") {
48112
- phase.status = "closed";
48113
- if (!closedPhases.includes(phase.id)) {
48114
- closedPhases.push(phase.id);
48150
+ if (curationSucceeded && explicitLessons.length > 0) {
48151
+ await fs11.unlink(lessonsFilePath).catch(() => {});
48152
+ }
48153
+ if (planExists && !planAlreadyDone) {
48154
+ for (const phase of phases) {
48155
+ if (phase.status !== "complete" && phase.status !== "completed") {
48156
+ phase.status = "closed";
48157
+ if (!closedPhases.includes(phase.id)) {
48158
+ closedPhases.push(phase.id);
48159
+ }
48115
48160
  }
48116
- }
48117
- for (const task of phase.tasks ?? []) {
48118
- if (task.status !== "completed" && task.status !== "complete") {
48119
- task.status = "closed";
48120
- if (!closedTasks.includes(task.id)) {
48121
- closedTasks.push(task.id);
48161
+ for (const task of phase.tasks ?? []) {
48162
+ if (task.status !== "completed" && task.status !== "complete") {
48163
+ task.status = "closed";
48164
+ if (!closedTasks.includes(task.id)) {
48165
+ closedTasks.push(task.id);
48166
+ }
48122
48167
  }
48123
48168
  }
48124
48169
  }
48170
+ try {
48171
+ await fs11.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
48172
+ } catch (error93) {
48173
+ console.warn("[close-command] Failed to write plan.json:", error93);
48174
+ }
48125
48175
  }
48126
48176
  try {
48127
- await fs11.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
48177
+ await archiveEvidence(directory, 30, 10);
48128
48178
  } catch (error93) {
48129
- console.warn("[close-command] Failed to write plan.json:", error93);
48179
+ console.warn("[close-command] archiveEvidence error:", error93);
48130
48180
  }
48181
+ const swarmDir = path17.join(directory, ".swarm");
48182
+ let configBackupsRemoved = 0;
48131
48183
  try {
48132
- await archiveEvidence(directory, 30, 10);
48184
+ const swarmFiles = await fs11.readdir(swarmDir);
48185
+ const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
48186
+ for (const backup of configBackups) {
48187
+ try {
48188
+ await fs11.unlink(path17.join(swarmDir, backup));
48189
+ configBackupsRemoved++;
48190
+ } catch {}
48191
+ }
48192
+ } catch {}
48193
+ const contextPath = path17.join(directory, ".swarm", "context.md");
48194
+ const contextContent = [
48195
+ "# Context",
48196
+ "",
48197
+ "## Status",
48198
+ `Session closed after: ${projectName}`,
48199
+ `Closed: ${new Date().toISOString()}`,
48200
+ "No active plan. Next session starts fresh.",
48201
+ ""
48202
+ ].join(`
48203
+ `);
48204
+ try {
48205
+ await fs11.writeFile(contextPath, contextContent, "utf-8");
48133
48206
  } catch (error93) {
48134
- console.warn("[close-command] archiveEvidence error:", error93);
48207
+ console.warn("[close-command] Failed to write context.md:", error93);
48208
+ }
48209
+ const pruneBranches = args2.includes("--prune-branches");
48210
+ const prunedBranches = [];
48211
+ const pruneErrors = [];
48212
+ if (pruneBranches) {
48213
+ try {
48214
+ const branchOutput = execFileSync("git", ["branch", "-vv"], {
48215
+ cwd: directory,
48216
+ encoding: "utf-8",
48217
+ stdio: ["pipe", "pipe", "pipe"]
48218
+ });
48219
+ const goneBranches = branchOutput.split(`
48220
+ `).filter((line) => line.includes(": gone]")).map((line) => line.trim().replace(/^[*+]\s+/, "").split(/\s+/)[0]).filter(Boolean);
48221
+ for (const branch of goneBranches) {
48222
+ try {
48223
+ execFileSync("git", ["branch", "-d", branch], {
48224
+ cwd: directory,
48225
+ encoding: "utf-8",
48226
+ stdio: ["pipe", "pipe", "pipe"]
48227
+ });
48228
+ prunedBranches.push(branch);
48229
+ } catch {
48230
+ pruneErrors.push(branch);
48231
+ }
48232
+ }
48233
+ } catch {}
48135
48234
  }
48136
48235
  const closeSummaryPath = validateSwarmPath(directory, "close-summary.md");
48236
+ const actionsPerformed = [
48237
+ ...!planAlreadyDone && inProgressPhases.length > 0 ? ["- Wrote retrospectives for in-progress phases"] : [],
48238
+ "- Archived evidence bundles",
48239
+ "- Reset context.md for next session",
48240
+ ...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
48241
+ ...prunedBranches.length > 0 ? [
48242
+ `- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
48243
+ ] : [],
48244
+ "- Cleared agent sessions and delegation chains",
48245
+ ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : []
48246
+ ];
48137
48247
  const summaryContent = [
48138
48248
  "# Swarm Close Summary",
48139
48249
  "",
@@ -48141,18 +48251,15 @@ async function handleCloseCommand(directory, _args) {
48141
48251
  `**Closed:** ${new Date().toISOString()}`,
48142
48252
  "",
48143
48253
  `## Phases Closed: ${closedPhases.length}`,
48144
- closedPhases.map((id) => `- Phase ${id}`).join(`
48145
- `),
48254
+ !planExists ? "_No plan \u2014 ad-hoc session_" : closedPhases.length > 0 ? closedPhases.map((id) => `- Phase ${id}`).join(`
48255
+ `) : "_No phases to close_",
48146
48256
  "",
48147
48257
  `## Tasks Closed: ${closedTasks.length}`,
48148
48258
  closedTasks.length > 0 ? closedTasks.map((id) => `- ${id}`).join(`
48149
48259
  `) : "_No incomplete tasks_",
48150
48260
  "",
48151
48261
  "## Actions Performed",
48152
- "- Wrote retrospectives for in-progress phases",
48153
- "- Archived evidence bundles",
48154
- "- Cleared agent sessions and delegation chains",
48155
- "- Set non-completed phases/tasks to closed status"
48262
+ ...actionsPerformed
48156
48263
  ].join(`
48157
48264
  `);
48158
48265
  try {
@@ -48168,21 +48275,27 @@ async function handleCloseCommand(directory, _args) {
48168
48275
  await writeCheckpoint(directory).catch(() => {});
48169
48276
  swarmState.agentSessions.clear();
48170
48277
  swarmState.delegationChains.clear();
48278
+ if (pruneErrors.length > 0) {
48279
+ warnings.push(`Could not prune ${pruneErrors.length} branch(es) (unmerged or checked out): ${pruneErrors.join(", ")}`);
48280
+ }
48171
48281
  const warningMsg = warnings.length > 0 ? ` Warnings: ${warnings.join("; ")}.` : "";
48282
+ if (planAlreadyDone) {
48283
+ return `\u2705 Session closed. Plan was already in a terminal state \u2014 cleanup steps applied.${warningMsg}`;
48284
+ }
48172
48285
  return `\u2705 Swarm closed successfully. ${closedPhases.length} phase(s) closed, ${closedTasks.length} incomplete task(s) marked closed.${warningMsg}`;
48173
48286
  }
48174
48287
 
48175
48288
  // src/commands/config.ts
48176
48289
  init_loader();
48177
48290
  import * as os4 from "os";
48178
- import * as path17 from "path";
48291
+ import * as path18 from "path";
48179
48292
  function getUserConfigDir2() {
48180
- return process.env.XDG_CONFIG_HOME || path17.join(os4.homedir(), ".config");
48293
+ return process.env.XDG_CONFIG_HOME || path18.join(os4.homedir(), ".config");
48181
48294
  }
48182
48295
  async function handleConfigCommand(directory, _args) {
48183
48296
  const config3 = loadPluginConfig(directory);
48184
- const userConfigPath = path17.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
48185
- const projectConfigPath = path17.join(directory, ".opencode", "opencode-swarm.json");
48297
+ const userConfigPath = path18.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
48298
+ const projectConfigPath = path18.join(directory, ".opencode", "opencode-swarm.json");
48186
48299
  const lines = [
48187
48300
  "## Swarm Configuration",
48188
48301
  "",
@@ -48205,7 +48318,7 @@ init_schema();
48205
48318
  // src/hooks/curator.ts
48206
48319
  import { randomUUID } from "crypto";
48207
48320
  import * as fs12 from "fs";
48208
- import * as path18 from "path";
48321
+ import * as path19 from "path";
48209
48322
  init_event_bus();
48210
48323
  init_manager2();
48211
48324
  init_knowledge_store();
@@ -48259,7 +48372,7 @@ async function readCuratorSummary(directory) {
48259
48372
  }
48260
48373
  async function writeCuratorSummary(directory, summary) {
48261
48374
  const resolvedPath = validateSwarmPath(directory, "curator-summary.json");
48262
- fs12.mkdirSync(path18.dirname(resolvedPath), { recursive: true });
48375
+ fs12.mkdirSync(path19.dirname(resolvedPath), { recursive: true });
48263
48376
  const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
48264
48377
  await Bun.write(tempPath, JSON.stringify(summary, null, 2));
48265
48378
  fs12.renameSync(tempPath, resolvedPath);
@@ -48630,7 +48743,7 @@ ${phaseDigest.summary}`,
48630
48743
  };
48631
48744
  }
48632
48745
  await writeCuratorSummary(directory, updatedSummary);
48633
- const eventsPath = path18.join(directory, ".swarm", "events.jsonl");
48746
+ const eventsPath = path19.join(directory, ".swarm", "events.jsonl");
48634
48747
  for (const obs of complianceObservations) {
48635
48748
  await appendKnowledge(eventsPath, {
48636
48749
  type: "curator_compliance",
@@ -48772,7 +48885,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, _knowled
48772
48885
  created_at: now,
48773
48886
  updated_at: now,
48774
48887
  auto_generated: true,
48775
- project_name: path18.basename(directory)
48888
+ project_name: path19.basename(directory)
48776
48889
  };
48777
48890
  await appendKnowledge(knowledgePath, newEntry);
48778
48891
  applied++;
@@ -48990,7 +49103,7 @@ function formatCurationSummary(summary) {
48990
49103
  // src/commands/dark-matter.ts
48991
49104
  init_knowledge_store();
48992
49105
  init_co_change_analyzer();
48993
- import path20 from "path";
49106
+ import path21 from "path";
48994
49107
  async function handleDarkMatterCommand(directory, args2) {
48995
49108
  const options = {};
48996
49109
  for (let i2 = 0;i2 < args2.length; i2++) {
@@ -49012,7 +49125,7 @@ async function handleDarkMatterCommand(directory, args2) {
49012
49125
  const output = formatDarkMatterOutput(pairs);
49013
49126
  if (pairs.length > 0) {
49014
49127
  try {
49015
- const projectName = path20.basename(path20.resolve(directory));
49128
+ const projectName = path21.basename(path21.resolve(directory));
49016
49129
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
49017
49130
  if (entries.length > 0) {
49018
49131
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -49038,7 +49151,7 @@ init_utils2();
49038
49151
  init_manager2();
49039
49152
  import * as child_process3 from "child_process";
49040
49153
  import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
49041
- import path21 from "path";
49154
+ import path22 from "path";
49042
49155
  import { fileURLToPath } from "url";
49043
49156
  function validateTaskDag(plan) {
49044
49157
  const allTaskIds = new Set;
@@ -49335,7 +49448,7 @@ async function checkSpecStaleness(directory, plan) {
49335
49448
  };
49336
49449
  }
49337
49450
  async function checkConfigParseability(directory) {
49338
- const configPath = path21.join(directory, ".opencode/opencode-swarm.json");
49451
+ const configPath = path22.join(directory, ".opencode/opencode-swarm.json");
49339
49452
  if (!existsSync10(configPath)) {
49340
49453
  return {
49341
49454
  name: "Config Parseability",
@@ -49382,15 +49495,15 @@ async function checkGrammarWasmFiles() {
49382
49495
  "tree-sitter-ini.wasm",
49383
49496
  "tree-sitter-regex.wasm"
49384
49497
  ];
49385
- const thisDir = path21.dirname(fileURLToPath(import.meta.url));
49498
+ const thisDir = path22.dirname(fileURLToPath(import.meta.url));
49386
49499
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
49387
- const grammarDir = isSource ? path21.join(thisDir, "..", "lang", "grammars") : path21.join(thisDir, "lang", "grammars");
49500
+ const grammarDir = isSource ? path22.join(thisDir, "..", "lang", "grammars") : path22.join(thisDir, "lang", "grammars");
49388
49501
  const missing = [];
49389
- if (!existsSync10(path21.join(grammarDir, "tree-sitter.wasm"))) {
49502
+ if (!existsSync10(path22.join(grammarDir, "tree-sitter.wasm"))) {
49390
49503
  missing.push("tree-sitter.wasm (core runtime)");
49391
49504
  }
49392
49505
  for (const file3 of grammarFiles) {
49393
- if (!existsSync10(path21.join(grammarDir, file3))) {
49506
+ if (!existsSync10(path22.join(grammarDir, file3))) {
49394
49507
  missing.push(file3);
49395
49508
  }
49396
49509
  }
@@ -49408,7 +49521,7 @@ async function checkGrammarWasmFiles() {
49408
49521
  };
49409
49522
  }
49410
49523
  async function checkCheckpointManifest(directory) {
49411
- const manifestPath = path21.join(directory, ".swarm/checkpoints.json");
49524
+ const manifestPath = path22.join(directory, ".swarm/checkpoints.json");
49412
49525
  if (!existsSync10(manifestPath)) {
49413
49526
  return {
49414
49527
  name: "Checkpoint Manifest",
@@ -49460,7 +49573,7 @@ async function checkCheckpointManifest(directory) {
49460
49573
  }
49461
49574
  }
49462
49575
  async function checkEventStreamIntegrity(directory) {
49463
- const eventsPath = path21.join(directory, ".swarm/events.jsonl");
49576
+ const eventsPath = path22.join(directory, ".swarm/events.jsonl");
49464
49577
  if (!existsSync10(eventsPath)) {
49465
49578
  return {
49466
49579
  name: "Event Stream",
@@ -49501,7 +49614,7 @@ async function checkEventStreamIntegrity(directory) {
49501
49614
  }
49502
49615
  }
49503
49616
  async function checkSteeringDirectives(directory) {
49504
- const eventsPath = path21.join(directory, ".swarm/events.jsonl");
49617
+ const eventsPath = path22.join(directory, ".swarm/events.jsonl");
49505
49618
  if (!existsSync10(eventsPath)) {
49506
49619
  return {
49507
49620
  name: "Steering Directives",
@@ -49557,7 +49670,7 @@ async function checkCurator(directory) {
49557
49670
  detail: "Disabled (enable via curator.enabled)"
49558
49671
  };
49559
49672
  }
49560
- const summaryPath = path21.join(directory, ".swarm/curator-summary.json");
49673
+ const summaryPath = path22.join(directory, ".swarm/curator-summary.json");
49561
49674
  if (!existsSync10(summaryPath)) {
49562
49675
  return {
49563
49676
  name: "Curator",
@@ -50459,10 +50572,10 @@ init_knowledge_store();
50459
50572
  import { randomUUID as randomUUID3 } from "crypto";
50460
50573
  import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
50461
50574
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
50462
- import * as path23 from "path";
50575
+ import * as path24 from "path";
50463
50576
  async function migrateContextToKnowledge(directory, config3) {
50464
- const sentinelPath = path23.join(directory, ".swarm", ".knowledge-migrated");
50465
- const contextPath = path23.join(directory, ".swarm", "context.md");
50577
+ const sentinelPath = path24.join(directory, ".swarm", ".knowledge-migrated");
50578
+ const contextPath = path24.join(directory, ".swarm", "context.md");
50466
50579
  const knowledgePath = resolveSwarmKnowledgePath(directory);
50467
50580
  if (existsSync12(sentinelPath)) {
50468
50581
  return {
@@ -50658,7 +50771,7 @@ function truncateLesson(text) {
50658
50771
  return `${text.slice(0, 277)}...`;
50659
50772
  }
50660
50773
  function inferProjectName(directory) {
50661
- const packageJsonPath = path23.join(directory, "package.json");
50774
+ const packageJsonPath = path24.join(directory, "package.json");
50662
50775
  if (existsSync12(packageJsonPath)) {
50663
50776
  try {
50664
50777
  const pkg = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
@@ -50667,7 +50780,7 @@ function inferProjectName(directory) {
50667
50780
  }
50668
50781
  } catch {}
50669
50782
  }
50670
- return path23.basename(directory);
50783
+ return path24.basename(directory);
50671
50784
  }
50672
50785
  async function writeSentinel(sentinelPath, migrated, dropped) {
50673
50786
  const sentinel = {
@@ -50679,7 +50792,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
50679
50792
  schema_version: 1,
50680
50793
  migration_tool: "knowledge-migrator.ts"
50681
50794
  };
50682
- await mkdir4(path23.dirname(sentinelPath), { recursive: true });
50795
+ await mkdir4(path24.dirname(sentinelPath), { recursive: true });
50683
50796
  await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
50684
50797
  }
50685
50798
 
@@ -50919,7 +51032,7 @@ init_preflight_service();
50919
51032
  // src/knowledge/hive-promoter.ts
50920
51033
  import * as fs20 from "fs";
50921
51034
  import * as os6 from "os";
50922
- import * as path30 from "path";
51035
+ import * as path31 from "path";
50923
51036
  var DANGEROUS_PATTERNS = [
50924
51037
  [/rm\s+-rf/, "rm\\s+-rf"],
50925
51038
  [/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
@@ -50965,13 +51078,13 @@ function getHiveFilePath() {
50965
51078
  const home = os6.homedir();
50966
51079
  let dataDir;
50967
51080
  if (platform === "win32") {
50968
- dataDir = path30.join(process.env.LOCALAPPDATA || path30.join(home, "AppData", "Local"), "opencode-swarm", "Data");
51081
+ dataDir = path31.join(process.env.LOCALAPPDATA || path31.join(home, "AppData", "Local"), "opencode-swarm", "Data");
50969
51082
  } else if (platform === "darwin") {
50970
- dataDir = path30.join(home, "Library", "Application Support", "opencode-swarm");
51083
+ dataDir = path31.join(home, "Library", "Application Support", "opencode-swarm");
50971
51084
  } else {
50972
- dataDir = path30.join(process.env.XDG_DATA_HOME || path30.join(home, ".local", "share"), "opencode-swarm");
51085
+ dataDir = path31.join(process.env.XDG_DATA_HOME || path31.join(home, ".local", "share"), "opencode-swarm");
50973
51086
  }
50974
- return path30.join(dataDir, "hive-knowledge.jsonl");
51087
+ return path31.join(dataDir, "hive-knowledge.jsonl");
50975
51088
  }
50976
51089
  async function promoteToHive(_directory, lesson, category) {
50977
51090
  const trimmed = (lesson ?? "").trim();
@@ -50983,7 +51096,7 @@ async function promoteToHive(_directory, lesson, category) {
50983
51096
  throw new Error(`Lesson rejected by validator: ${validation.reason}`);
50984
51097
  }
50985
51098
  const hivePath = getHiveFilePath();
50986
- const hiveDir = path30.dirname(hivePath);
51099
+ const hiveDir = path31.dirname(hivePath);
50987
51100
  if (!fs20.existsSync(hiveDir)) {
50988
51101
  fs20.mkdirSync(hiveDir, { recursive: true });
50989
51102
  }
@@ -51005,7 +51118,7 @@ async function promoteToHive(_directory, lesson, category) {
51005
51118
  return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
51006
51119
  }
51007
51120
  async function promoteFromSwarm(directory, lessonId) {
51008
- const knowledgePath = path30.join(directory, ".swarm", "knowledge.jsonl");
51121
+ const knowledgePath = path31.join(directory, ".swarm", "knowledge.jsonl");
51009
51122
  const entries = [];
51010
51123
  if (fs20.existsSync(knowledgePath)) {
51011
51124
  const content = fs20.readFileSync(knowledgePath, "utf-8");
@@ -51032,7 +51145,7 @@ async function promoteFromSwarm(directory, lessonId) {
51032
51145
  throw new Error(`Lesson rejected by validator: ${validation.reason}`);
51033
51146
  }
51034
51147
  const hivePath = getHiveFilePath();
51035
- const hiveDir = path30.dirname(hivePath);
51148
+ const hiveDir = path31.dirname(hivePath);
51036
51149
  if (!fs20.existsSync(hiveDir)) {
51037
51150
  fs20.mkdirSync(hiveDir, { recursive: true });
51038
51151
  }
@@ -51163,7 +51276,7 @@ async function handleResetCommand(directory, args2) {
51163
51276
  // src/commands/reset-session.ts
51164
51277
  init_utils2();
51165
51278
  import * as fs22 from "fs";
51166
- import * as path31 from "path";
51279
+ import * as path32 from "path";
51167
51280
  async function handleResetSessionCommand(directory, _args) {
51168
51281
  const results = [];
51169
51282
  try {
@@ -51178,13 +51291,13 @@ async function handleResetSessionCommand(directory, _args) {
51178
51291
  results.push("\u274C Failed to delete state.json");
51179
51292
  }
51180
51293
  try {
51181
- const sessionDir = path31.dirname(validateSwarmPath(directory, "session/state.json"));
51294
+ const sessionDir = path32.dirname(validateSwarmPath(directory, "session/state.json"));
51182
51295
  if (fs22.existsSync(sessionDir)) {
51183
51296
  const files = fs22.readdirSync(sessionDir);
51184
51297
  const otherFiles = files.filter((f) => f !== "state.json");
51185
51298
  let deletedCount = 0;
51186
51299
  for (const file3 of otherFiles) {
51187
- const filePath = path31.join(sessionDir, file3);
51300
+ const filePath = path32.join(sessionDir, file3);
51188
51301
  if (fs22.lstatSync(filePath).isFile()) {
51189
51302
  fs22.unlinkSync(filePath);
51190
51303
  deletedCount++;
@@ -51215,7 +51328,7 @@ async function handleResetSessionCommand(directory, _args) {
51215
51328
  init_utils2();
51216
51329
  init_utils();
51217
51330
  import { mkdirSync as mkdirSync11, readdirSync as readdirSync8, renameSync as renameSync8, rmSync as rmSync3, statSync as statSync8 } from "fs";
51218
- import * as path32 from "path";
51331
+ import * as path33 from "path";
51219
51332
  var SUMMARY_ID_REGEX = /^S\d+$/;
51220
51333
  function sanitizeSummaryId(id) {
51221
51334
  if (!id || id.length === 0) {
@@ -51250,9 +51363,9 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
51250
51363
  if (serializedSize > maxStoredBytes) {
51251
51364
  throw new Error(`Summary entry size (${serializedSize} bytes) exceeds maximum (${maxStoredBytes} bytes)`);
51252
51365
  }
51253
- const relativePath = path32.join("summaries", `${sanitizedId}.json`);
51366
+ const relativePath = path33.join("summaries", `${sanitizedId}.json`);
51254
51367
  const summaryPath = validateSwarmPath(directory, relativePath);
51255
- const summaryDir = path32.dirname(summaryPath);
51368
+ const summaryDir = path33.dirname(summaryPath);
51256
51369
  const entry = {
51257
51370
  id: sanitizedId,
51258
51371
  summaryText,
@@ -51262,7 +51375,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
51262
51375
  };
51263
51376
  const entryJson = JSON.stringify(entry);
51264
51377
  mkdirSync11(summaryDir, { recursive: true });
51265
- const tempPath = path32.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
51378
+ const tempPath = path33.join(summaryDir, `${sanitizedId}.json.tmp.${Date.now()}.${process.pid}`);
51266
51379
  try {
51267
51380
  await Bun.write(tempPath, entryJson);
51268
51381
  renameSync8(tempPath, summaryPath);
@@ -51275,7 +51388,7 @@ async function storeSummary(directory, id, fullOutput, summaryText, maxStoredByt
51275
51388
  }
51276
51389
  async function loadFullOutput(directory, id) {
51277
51390
  const sanitizedId = sanitizeSummaryId(id);
51278
- const relativePath = path32.join("summaries", `${sanitizedId}.json`);
51391
+ const relativePath = path33.join("summaries", `${sanitizedId}.json`);
51279
51392
  validateSwarmPath(directory, relativePath);
51280
51393
  const content = await readSwarmFileAsync(directory, relativePath);
51281
51394
  if (content === null) {
@@ -51329,7 +51442,7 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
51329
51442
  // src/commands/rollback.ts
51330
51443
  init_utils2();
51331
51444
  import * as fs23 from "fs";
51332
- import * as path33 from "path";
51445
+ import * as path34 from "path";
51333
51446
  async function handleRollbackCommand(directory, args2) {
51334
51447
  const phaseArg = args2[0];
51335
51448
  if (!phaseArg) {
@@ -51387,8 +51500,8 @@ async function handleRollbackCommand(directory, args2) {
51387
51500
  const successes = [];
51388
51501
  const failures = [];
51389
51502
  for (const file3 of checkpointFiles) {
51390
- const src = path33.join(checkpointDir, file3);
51391
- const dest = path33.join(swarmDir, file3);
51503
+ const src = path34.join(checkpointDir, file3);
51504
+ const dest = path34.join(swarmDir, file3);
51392
51505
  try {
51393
51506
  fs23.cpSync(src, dest, { recursive: true, force: true });
51394
51507
  successes.push(file3);
@@ -51452,9 +51565,9 @@ async function handleSimulateCommand(directory, args2) {
51452
51565
  const report = reportLines.filter(Boolean).join(`
51453
51566
  `);
51454
51567
  const fs24 = await import("fs/promises");
51455
- const path34 = await import("path");
51456
- const reportPath = path34.join(directory, ".swarm", "simulate-report.md");
51457
- await fs24.mkdir(path34.dirname(reportPath), { recursive: true });
51568
+ const path35 = await import("path");
51569
+ const reportPath = path35.join(directory, ".swarm", "simulate-report.md");
51570
+ await fs24.mkdir(path35.dirname(reportPath), { recursive: true });
51458
51571
  await fs24.writeFile(reportPath, report, "utf-8");
51459
51572
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
51460
51573
  }
@@ -51813,7 +51926,7 @@ init_manager2();
51813
51926
 
51814
51927
  // src/services/compaction-service.ts
51815
51928
  import * as fs24 from "fs";
51816
- import * as path34 from "path";
51929
+ import * as path35 from "path";
51817
51930
  function makeInitialState() {
51818
51931
  return {
51819
51932
  lastObservationAt: 0,
@@ -51836,7 +51949,7 @@ function getSessionState(sessionId) {
51836
51949
  }
51837
51950
  function appendSnapshot(directory, tier, budgetPct, message) {
51838
51951
  try {
51839
- const snapshotPath = path34.join(directory, ".swarm", "context-snapshot.md");
51952
+ const snapshotPath = path35.join(directory, ".swarm", "context-snapshot.md");
51840
51953
  const timestamp = new Date().toISOString();
51841
51954
  const entry = `
51842
51955
  ## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
@@ -52567,11 +52680,11 @@ async function doFlush(directory) {
52567
52680
  const activitySection = renderActivitySection();
52568
52681
  const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
52569
52682
  const flushedCount = swarmState.pendingEvents;
52570
- const path35 = nodePath2.join(directory, ".swarm", "context.md");
52571
- const tempPath = `${path35}.tmp`;
52683
+ const path36 = nodePath2.join(directory, ".swarm", "context.md");
52684
+ const tempPath = `${path36}.tmp`;
52572
52685
  try {
52573
52686
  await Bun.write(tempPath, updated);
52574
- renameSync9(tempPath, path35);
52687
+ renameSync9(tempPath, path36);
52575
52688
  } catch (writeError) {
52576
52689
  try {
52577
52690
  unlinkSync4(tempPath);
@@ -53248,7 +53361,7 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
53248
53361
  // src/hooks/delegation-gate.ts
53249
53362
  init_schema();
53250
53363
  import * as fs26 from "fs";
53251
- import * as path37 from "path";
53364
+ import * as path38 from "path";
53252
53365
 
53253
53366
  // src/parallel/review-router.ts
53254
53367
  async function computeComplexity(directory, changedFiles) {
@@ -53261,8 +53374,8 @@ async function computeComplexity(directory, changedFiles) {
53261
53374
  }
53262
53375
  try {
53263
53376
  const fs26 = await import("fs");
53264
- const path35 = await import("path");
53265
- const filePath = path35.join(directory, file3);
53377
+ const path36 = await import("path");
53378
+ const filePath = path36.join(directory, file3);
53266
53379
  if (!fs26.existsSync(filePath)) {
53267
53380
  continue;
53268
53381
  }
@@ -53314,7 +53427,7 @@ function shouldParallelizeReview(routing) {
53314
53427
  init_telemetry();
53315
53428
 
53316
53429
  // src/hooks/guardrails.ts
53317
- import * as path35 from "path";
53430
+ import * as path36 from "path";
53318
53431
  init_constants();
53319
53432
  init_schema();
53320
53433
 
@@ -53478,10 +53591,10 @@ function isArchitect(sessionId) {
53478
53591
  function isOutsideSwarmDir(filePath, directory) {
53479
53592
  if (!filePath)
53480
53593
  return false;
53481
- const swarmDir = path35.resolve(directory, ".swarm");
53482
- const resolved = path35.resolve(directory, filePath);
53483
- const relative5 = path35.relative(swarmDir, resolved);
53484
- return relative5.startsWith("..") || path35.isAbsolute(relative5);
53594
+ const swarmDir = path36.resolve(directory, ".swarm");
53595
+ const resolved = path36.resolve(directory, filePath);
53596
+ const relative5 = path36.relative(swarmDir, resolved);
53597
+ return relative5.startsWith("..") || path36.isAbsolute(relative5);
53485
53598
  }
53486
53599
  function isSourceCodePath(filePath) {
53487
53600
  if (!filePath)
@@ -53549,16 +53662,16 @@ function getCurrentTaskId(sessionId) {
53549
53662
  }
53550
53663
  function isInDeclaredScope(filePath, scopeEntries, cwd) {
53551
53664
  const dir = cwd ?? process.cwd();
53552
- const resolvedFile = path35.resolve(dir, filePath);
53665
+ const resolvedFile = path36.resolve(dir, filePath);
53553
53666
  return scopeEntries.some((scope) => {
53554
- const resolvedScope = path35.resolve(dir, scope);
53667
+ const resolvedScope = path36.resolve(dir, scope);
53555
53668
  if (resolvedFile === resolvedScope)
53556
53669
  return true;
53557
- const rel = path35.relative(resolvedScope, resolvedFile);
53558
- return rel.length > 0 && !rel.startsWith("..") && !path35.isAbsolute(rel);
53670
+ const rel = path36.relative(resolvedScope, resolvedFile);
53671
+ return rel.length > 0 && !rel.startsWith("..") && !path36.isAbsolute(rel);
53559
53672
  });
53560
53673
  }
53561
- function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53674
+ function createGuardrailsHooks(directory, directoryOrConfig, config3, authorityConfig) {
53562
53675
  let guardrailsConfig;
53563
53676
  if (directory && typeof directory === "object" && "enabled" in directory) {
53564
53677
  console.warn("[guardrails] Legacy call without directory, falling back to process.cwd()");
@@ -53576,6 +53689,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53576
53689
  messagesTransform: async () => {}
53577
53690
  };
53578
53691
  }
53692
+ const precomputedAuthorityRules = buildEffectiveRules(authorityConfig);
53579
53693
  const cfg = guardrailsConfig;
53580
53694
  const requiredQaGates = cfg.qa_gates?.required_tools ?? [
53581
53695
  "diff",
@@ -53670,7 +53784,7 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53670
53784
  if (typeof delegTargetPath === "string" && delegTargetPath.length > 0) {
53671
53785
  const agentName = swarmState.activeAgent.get(sessionID) ?? "unknown";
53672
53786
  const cwd = effectiveDirectory;
53673
- const authorityCheck = checkFileAuthority(agentName, delegTargetPath, cwd);
53787
+ const authorityCheck = checkFileAuthorityWithRules(agentName, delegTargetPath, cwd, precomputedAuthorityRules);
53674
53788
  if (!authorityCheck.allowed) {
53675
53789
  throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${delegTargetPath}". Reason: ${authorityCheck.reason}`);
53676
53790
  }
@@ -53679,6 +53793,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53679
53793
  }
53680
53794
  }
53681
53795
  }
53796
+ if (tool3 === "apply_patch" || tool3 === "patch") {
53797
+ const agentName = swarmState.activeAgent.get(sessionID) ?? "unknown";
53798
+ const cwd = effectiveDirectory;
53799
+ for (const p of extractPatchTargetPaths(tool3, args2)) {
53800
+ const authorityCheck = checkFileAuthorityWithRules(agentName, p, cwd, precomputedAuthorityRules);
53801
+ if (!authorityCheck.allowed) {
53802
+ throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${p}" (via patch). Reason: ${authorityCheck.reason}`);
53803
+ }
53804
+ if (!currentSession.modifiedFilesThisCoderTask.includes(p)) {
53805
+ currentSession.modifiedFilesThisCoderTask.push(p);
53806
+ }
53807
+ }
53808
+ }
53682
53809
  } else if (isArchitect(sessionID)) {
53683
53810
  const coderDelegArgs = args2;
53684
53811
  const rawSubagentType = coderDelegArgs?.subagent_type;
@@ -53747,84 +53874,90 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53747
53874
  }
53748
53875
  }
53749
53876
  }
53877
+ function extractPatchTargetPaths(tool3, args2) {
53878
+ if (tool3 !== "apply_patch" && tool3 !== "patch")
53879
+ return [];
53880
+ const toolArgs = args2;
53881
+ const patchText = toolArgs?.input ?? toolArgs?.patch ?? (Array.isArray(toolArgs?.cmd) ? toolArgs.cmd[1] : undefined);
53882
+ if (typeof patchText !== "string")
53883
+ return [];
53884
+ if (patchText.length > 1e6) {
53885
+ throw new Error("WRITE BLOCKED: Patch payload exceeds 1 MB \u2014 authority cannot be verified for all modified paths. Split into smaller patches.");
53886
+ }
53887
+ const paths = new Set;
53888
+ const patchPathPattern = /\*\*\*\s+(?:Update|Add|Delete)\s+File:\s*(.+)/gi;
53889
+ const diffPathPattern = /\+\+\+\s+b\/(.+)/gm;
53890
+ const gitDiffPathPattern = /^diff --git a\/(.+?) b\/(.+?)$/gm;
53891
+ const minusPathPattern = /^---\s+a\/(.+)$/gm;
53892
+ const traditionalMinusPattern = /^---\s+([^\s].+?)(?:\t.*)?$/gm;
53893
+ const traditionalPlusPattern = /^\+\+\+\s+([^\s].+?)(?:\t.*)?$/gm;
53894
+ for (const match of patchText.matchAll(patchPathPattern))
53895
+ paths.add(match[1].trim());
53896
+ for (const match of patchText.matchAll(diffPathPattern)) {
53897
+ const p = match[1].trim();
53898
+ if (p !== "/dev/null")
53899
+ paths.add(p);
53900
+ }
53901
+ for (const match of patchText.matchAll(gitDiffPathPattern)) {
53902
+ const aPath = match[1].trim();
53903
+ const bPath = match[2].trim();
53904
+ if (aPath !== "/dev/null")
53905
+ paths.add(aPath);
53906
+ if (bPath !== "/dev/null")
53907
+ paths.add(bPath);
53908
+ }
53909
+ for (const match of patchText.matchAll(minusPathPattern)) {
53910
+ const p = match[1].trim();
53911
+ if (p !== "/dev/null")
53912
+ paths.add(p);
53913
+ }
53914
+ for (const match of patchText.matchAll(traditionalMinusPattern)) {
53915
+ const p = match[1].trim();
53916
+ if (p !== "/dev/null" && !p.startsWith("a/") && !p.startsWith("b/"))
53917
+ paths.add(p);
53918
+ }
53919
+ for (const match of patchText.matchAll(traditionalPlusPattern)) {
53920
+ const p = match[1].trim();
53921
+ if (p !== "/dev/null" && !p.startsWith("a/") && !p.startsWith("b/"))
53922
+ paths.add(p);
53923
+ }
53924
+ return Array.from(paths);
53925
+ }
53750
53926
  function handlePlanAndScopeProtection(sessionID, tool3, args2) {
53751
53927
  const toolArgs = args2;
53752
53928
  const targetPath = toolArgs?.filePath ?? toolArgs?.path ?? toolArgs?.file ?? toolArgs?.target;
53753
53929
  if (typeof targetPath === "string" && targetPath.length > 0) {
53754
- const resolvedTarget = path35.resolve(effectiveDirectory, targetPath).toLowerCase();
53755
- const planMdPath = path35.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
53756
- const planJsonPath = path35.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
53930
+ const resolvedTarget = path36.resolve(effectiveDirectory, targetPath).toLowerCase();
53931
+ const planMdPath = path36.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
53932
+ const planJsonPath = path36.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
53757
53933
  if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
53758
53934
  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.");
53759
53935
  }
53760
53936
  }
53761
53937
  if (!targetPath && (tool3 === "apply_patch" || tool3 === "patch")) {
53762
- const patchText = toolArgs?.input ?? toolArgs?.patch ?? (Array.isArray(toolArgs?.cmd) ? toolArgs.cmd[1] : undefined);
53763
- if (typeof patchText === "string" && patchText.length <= 1e6) {
53764
- const patchPathPattern = /\*\*\*\s+(?:Update|Add|Delete)\s+File:\s*(.+)/gi;
53765
- const diffPathPattern = /\+\+\+\s+b\/(.+)/gm;
53766
- const paths = new Set;
53767
- for (const match of patchText.matchAll(patchPathPattern)) {
53768
- paths.add(match[1].trim());
53769
- }
53770
- for (const match of patchText.matchAll(diffPathPattern)) {
53771
- const p = match[1].trim();
53772
- if (p !== "/dev/null")
53773
- paths.add(p);
53774
- }
53775
- const gitDiffPathPattern = /^diff --git a\/(.+?) b\/(.+?)$/gm;
53776
- for (const match of patchText.matchAll(gitDiffPathPattern)) {
53777
- const aPath = match[1].trim();
53778
- const bPath = match[2].trim();
53779
- if (aPath !== "/dev/null")
53780
- paths.add(aPath);
53781
- if (bPath !== "/dev/null")
53782
- paths.add(bPath);
53783
- }
53784
- const minusPathPattern = /^---\s+a\/(.+)$/gm;
53785
- for (const match of patchText.matchAll(minusPathPattern)) {
53786
- const p = match[1].trim();
53787
- if (p !== "/dev/null")
53788
- paths.add(p);
53789
- }
53790
- const traditionalMinusPattern = /^---\s+([^\s].+?)(?:\t.*)?$/gm;
53791
- const traditionalPlusPattern = /^\+\+\+\s+([^\s].+?)(?:\t.*)?$/gm;
53792
- for (const match of patchText.matchAll(traditionalMinusPattern)) {
53793
- const p = match[1].trim();
53794
- if (p !== "/dev/null" && !p.startsWith("a/") && !p.startsWith("b/")) {
53795
- paths.add(p);
53796
- }
53797
- }
53798
- for (const match of patchText.matchAll(traditionalPlusPattern)) {
53799
- const p = match[1].trim();
53800
- if (p !== "/dev/null" && !p.startsWith("a/") && !p.startsWith("b/")) {
53801
- paths.add(p);
53802
- }
53803
- }
53804
- for (const p of paths) {
53805
- const resolvedP = path35.resolve(effectiveDirectory, p);
53806
- const planMdPath = path35.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
53807
- const planJsonPath = path35.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
53808
- if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
53809
- 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.");
53810
- }
53811
- if (isOutsideSwarmDir(p, effectiveDirectory) && (isSourceCodePath(p) || hasTraversalSegments(p))) {
53812
- const session = swarmState.agentSessions.get(sessionID);
53813
- if (session) {
53814
- session.architectWriteCount++;
53815
- warn("Architect direct code edit detected via apply_patch", {
53816
- tool: tool3,
53817
- sessionID,
53818
- targetPath: p,
53819
- writeCount: session.architectWriteCount
53820
- });
53821
- }
53822
- break;
53938
+ for (const p of extractPatchTargetPaths(tool3, args2)) {
53939
+ const resolvedP = path36.resolve(effectiveDirectory, p);
53940
+ const planMdPath = path36.resolve(effectiveDirectory, ".swarm", "plan.md").toLowerCase();
53941
+ const planJsonPath = path36.resolve(effectiveDirectory, ".swarm", "plan.json").toLowerCase();
53942
+ if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
53943
+ 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.");
53944
+ }
53945
+ if (isOutsideSwarmDir(p, effectiveDirectory) && (isSourceCodePath(p) || hasTraversalSegments(p))) {
53946
+ const session = swarmState.agentSessions.get(sessionID);
53947
+ if (session) {
53948
+ session.architectWriteCount++;
53949
+ warn("Architect direct code edit detected via apply_patch", {
53950
+ tool: tool3,
53951
+ sessionID,
53952
+ targetPath: p,
53953
+ writeCount: session.architectWriteCount
53954
+ });
53823
53955
  }
53956
+ break;
53824
53957
  }
53825
53958
  }
53826
53959
  }
53827
- if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, effectiveDirectory) && isSourceCodePath(path35.relative(effectiveDirectory, path35.resolve(effectiveDirectory, targetPath)))) {
53960
+ if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, effectiveDirectory) && isSourceCodePath(path36.relative(effectiveDirectory, path36.resolve(effectiveDirectory, targetPath)))) {
53828
53961
  const session = swarmState.agentSessions.get(sessionID);
53829
53962
  if (session) {
53830
53963
  session.architectWriteCount++;
@@ -53917,6 +54050,24 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
53917
54050
  handleTestSuiteBlocking(input.tool, output.args);
53918
54051
  if (isArchitect(input.sessionID) && isWriteTool(input.tool)) {
53919
54052
  handlePlanAndScopeProtection(input.sessionID, input.tool, output.args);
54053
+ const toolArgs = output.args;
54054
+ const targetPath = toolArgs?.filePath ?? toolArgs?.path ?? toolArgs?.file ?? toolArgs?.target;
54055
+ if (typeof targetPath === "string" && targetPath.length > 0) {
54056
+ const agentName = swarmState.activeAgent.get(input.sessionID) ?? "architect";
54057
+ const authorityCheck = checkFileAuthorityWithRules(agentName, targetPath, effectiveDirectory, precomputedAuthorityRules);
54058
+ if (!authorityCheck.allowed) {
54059
+ throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${targetPath}". Reason: ${authorityCheck.reason}`);
54060
+ }
54061
+ }
54062
+ }
54063
+ if (input.tool === "apply_patch" || input.tool === "patch") {
54064
+ const agentName = swarmState.activeAgent.get(input.sessionID) ?? "architect";
54065
+ for (const p of extractPatchTargetPaths(input.tool, output.args)) {
54066
+ const authorityCheck = checkFileAuthorityWithRules(agentName, p, effectiveDirectory, precomputedAuthorityRules);
54067
+ if (!authorityCheck.allowed) {
54068
+ throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${p}" (via patch). Reason: ${authorityCheck.reason}`);
54069
+ }
54070
+ }
53920
54071
  }
53921
54072
  const resolved = resolveSessionAndWindow(input.sessionID);
53922
54073
  if (!resolved)
@@ -54411,7 +54562,7 @@ function hashArgs(args2) {
54411
54562
  return 0;
54412
54563
  }
54413
54564
  }
54414
- var AGENT_AUTHORITY_RULES = {
54565
+ var DEFAULT_AGENT_AUTHORITY_RULES = {
54415
54566
  architect: {
54416
54567
  blockedExact: [".swarm/plan.md", ".swarm/plan.json"],
54417
54568
  blockedZones: ["generated"]
@@ -54452,12 +54603,38 @@ var AGENT_AUTHORITY_RULES = {
54452
54603
  blockedZones: ["generated"]
54453
54604
  }
54454
54605
  };
54455
- function checkFileAuthority(agentName, filePath, cwd) {
54606
+ function buildEffectiveRules(authorityConfig) {
54607
+ if (authorityConfig?.enabled === false || !authorityConfig?.rules) {
54608
+ return DEFAULT_AGENT_AUTHORITY_RULES;
54609
+ }
54610
+ const entries = Object.entries(authorityConfig.rules);
54611
+ if (entries.length === 0) {
54612
+ return DEFAULT_AGENT_AUTHORITY_RULES;
54613
+ }
54614
+ const merged = {
54615
+ ...DEFAULT_AGENT_AUTHORITY_RULES
54616
+ };
54617
+ for (const [agent, userRule] of entries) {
54618
+ const normalizedRuleKey = agent.toLowerCase();
54619
+ const existing = merged[normalizedRuleKey] ?? {};
54620
+ merged[normalizedRuleKey] = {
54621
+ ...existing,
54622
+ ...userRule,
54623
+ blockedExact: userRule.blockedExact ?? existing.blockedExact,
54624
+ blockedPrefix: userRule.blockedPrefix ?? existing.blockedPrefix,
54625
+ allowedPrefix: userRule.allowedPrefix ?? existing.allowedPrefix,
54626
+ blockedZones: userRule.blockedZones ?? existing.blockedZones
54627
+ };
54628
+ }
54629
+ return merged;
54630
+ }
54631
+ function checkFileAuthorityWithRules(agentName, filePath, cwd, effectiveRules) {
54456
54632
  const normalizedAgent = agentName.toLowerCase();
54633
+ const strippedAgent = stripKnownSwarmPrefix(agentName).toLowerCase();
54457
54634
  const dir = cwd || process.cwd();
54458
- const resolved = path35.resolve(dir, filePath);
54459
- const normalizedPath = path35.relative(dir, resolved).replace(/\\/g, "/");
54460
- const rules = AGENT_AUTHORITY_RULES[normalizedAgent];
54635
+ const resolved = path36.resolve(dir, filePath);
54636
+ const normalizedPath = path36.relative(dir, resolved).replace(/\\/g, "/");
54637
+ const rules = effectiveRules[normalizedAgent] ?? effectiveRules[strippedAgent];
54461
54638
  if (!rules) {
54462
54639
  return { allowed: false, reason: `Unknown agent: ${agentName}` };
54463
54640
  }
@@ -54484,8 +54661,8 @@ function checkFileAuthority(agentName, filePath, cwd) {
54484
54661
  }
54485
54662
  }
54486
54663
  }
54487
- if (rules.allowedPrefix && rules.allowedPrefix.length > 0) {
54488
- const isAllowed = rules.allowedPrefix.some((prefix) => normalizedPath.startsWith(prefix));
54664
+ if (rules.allowedPrefix != null) {
54665
+ const isAllowed = rules.allowedPrefix.length > 0 ? rules.allowedPrefix.some((prefix) => normalizedPath.startsWith(prefix)) : false;
54489
54666
  if (!isAllowed) {
54490
54667
  return {
54491
54668
  allowed: false,
@@ -54538,10 +54715,10 @@ async function getEvidenceTaskId(session, directory) {
54538
54715
  if (typeof directory !== "string" || directory.length === 0) {
54539
54716
  return null;
54540
54717
  }
54541
- const resolvedDirectory = path37.resolve(directory);
54542
- const planPath = path37.join(resolvedDirectory, ".swarm", "plan.json");
54543
- const resolvedPlanPath = path37.resolve(planPath);
54544
- if (!resolvedPlanPath.startsWith(resolvedDirectory + path37.sep) && resolvedPlanPath !== resolvedDirectory) {
54718
+ const resolvedDirectory = path38.resolve(directory);
54719
+ const planPath = path38.join(resolvedDirectory, ".swarm", "plan.json");
54720
+ const resolvedPlanPath = path38.resolve(planPath);
54721
+ if (!resolvedPlanPath.startsWith(resolvedDirectory + path38.sep) && resolvedPlanPath !== resolvedDirectory) {
54545
54722
  return null;
54546
54723
  }
54547
54724
  const planContent = await fs26.promises.readFile(resolvedPlanPath, "utf-8");
@@ -55269,7 +55446,7 @@ function consolidateSystemMessages(messages) {
55269
55446
  // src/hooks/phase-monitor.ts
55270
55447
  init_schema();
55271
55448
  init_manager2();
55272
- import * as path39 from "path";
55449
+ import * as path40 from "path";
55273
55450
  init_utils2();
55274
55451
  function createPhaseMonitorHook(directory, preflightManager, curatorRunner, delegateFactory) {
55275
55452
  let lastKnownPhase = null;
@@ -55290,9 +55467,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, dele
55290
55467
  const llmDelegate = delegateFactory?.(sessionId);
55291
55468
  const initResult = await runner(directory, curatorConfig, llmDelegate);
55292
55469
  if (initResult.briefing) {
55293
- const briefingPath = path39.join(directory, ".swarm", "curator-briefing.md");
55470
+ const briefingPath = path40.join(directory, ".swarm", "curator-briefing.md");
55294
55471
  const { mkdir: mkdir5, writeFile: writeFile5 } = await import("fs/promises");
55295
- await mkdir5(path39.dirname(briefingPath), { recursive: true });
55472
+ await mkdir5(path40.dirname(briefingPath), { recursive: true });
55296
55473
  await writeFile5(briefingPath, initResult.briefing, "utf-8");
55297
55474
  const { buildApprovedReceipt: buildApprovedReceipt2, persistReviewReceipt: persistReviewReceipt2 } = await Promise.resolve().then(() => (init_review_receipt(), exports_review_receipt));
55298
55475
  const initReceipt = buildApprovedReceipt2({
@@ -55426,14 +55603,14 @@ init_manager();
55426
55603
  init_detector();
55427
55604
  init_manager2();
55428
55605
  import * as fs32 from "fs";
55429
- import * as path43 from "path";
55606
+ import * as path44 from "path";
55430
55607
 
55431
55608
  // src/services/decision-drift-analyzer.ts
55432
55609
  init_utils2();
55433
55610
  init_manager2();
55434
55611
  init_utils();
55435
55612
  import * as fs29 from "fs";
55436
- import * as path40 from "path";
55613
+ import * as path41 from "path";
55437
55614
  var DEFAULT_DRIFT_CONFIG = {
55438
55615
  staleThresholdPhases: 1,
55439
55616
  detectContradictions: true,
@@ -55587,7 +55764,7 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
55587
55764
  currentPhase = legacyPhase;
55588
55765
  }
55589
55766
  }
55590
- const contextPath = path40.join(directory, ".swarm", "context.md");
55767
+ const contextPath = path41.join(directory, ".swarm", "context.md");
55591
55768
  let contextContent = "";
55592
55769
  try {
55593
55770
  if (fs29.existsSync(contextPath)) {
@@ -55717,7 +55894,7 @@ init_utils();
55717
55894
  init_constants();
55718
55895
  init_schema();
55719
55896
  import * as fs30 from "fs/promises";
55720
- import * as path41 from "path";
55897
+ import * as path42 from "path";
55721
55898
  function safeGet(obj, key) {
55722
55899
  if (!obj || !Object.hasOwn(obj, key))
55723
55900
  return;
@@ -55931,9 +56108,9 @@ async function handleDebuggingSpiral(match, taskId, directory) {
55931
56108
  let eventLogged = false;
55932
56109
  let checkpointCreated = false;
55933
56110
  try {
55934
- const swarmDir = path41.join(directory, ".swarm");
56111
+ const swarmDir = path42.join(directory, ".swarm");
55935
56112
  await fs30.mkdir(swarmDir, { recursive: true });
55936
- const eventsPath = path41.join(swarmDir, "events.jsonl");
56113
+ const eventsPath = path42.join(swarmDir, "events.jsonl");
55937
56114
  await fs30.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
55938
56115
  `);
55939
56116
  eventLogged = true;
@@ -56330,7 +56507,7 @@ function createSystemEnhancerHook(config3, directory) {
56330
56507
  await fs32.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
56331
56508
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
56332
56509
  try {
56333
- const projectName = path43.basename(path43.resolve(directory));
56510
+ const projectName = path44.basename(path44.resolve(directory));
56334
56511
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
56335
56512
  const knowledgePath = resolveSwarmKnowledgePath(directory);
56336
56513
  const existingEntries = await readKnowledge(knowledgePath);
@@ -57454,7 +57631,7 @@ function isReadTool(toolName) {
57454
57631
 
57455
57632
  // src/hooks/incremental-verify.ts
57456
57633
  import * as fs33 from "fs";
57457
- import * as path44 from "path";
57634
+ import * as path45 from "path";
57458
57635
 
57459
57636
  // src/hooks/spawn-helper.ts
57460
57637
  import * as child_process4 from "child_process";
@@ -57532,18 +57709,18 @@ function spawnAsync(command, cwd, timeoutMs) {
57532
57709
  // src/hooks/incremental-verify.ts
57533
57710
  var emittedSkipAdvisories = new Set;
57534
57711
  function detectPackageManager(projectDir) {
57535
- if (fs33.existsSync(path44.join(projectDir, "bun.lockb")))
57712
+ if (fs33.existsSync(path45.join(projectDir, "bun.lockb")))
57536
57713
  return "bun";
57537
- if (fs33.existsSync(path44.join(projectDir, "pnpm-lock.yaml")))
57714
+ if (fs33.existsSync(path45.join(projectDir, "pnpm-lock.yaml")))
57538
57715
  return "pnpm";
57539
- if (fs33.existsSync(path44.join(projectDir, "yarn.lock")))
57716
+ if (fs33.existsSync(path45.join(projectDir, "yarn.lock")))
57540
57717
  return "yarn";
57541
- if (fs33.existsSync(path44.join(projectDir, "package-lock.json")))
57718
+ if (fs33.existsSync(path45.join(projectDir, "package-lock.json")))
57542
57719
  return "npm";
57543
57720
  return "bun";
57544
57721
  }
57545
57722
  function detectTypecheckCommand(projectDir) {
57546
- const pkgPath = path44.join(projectDir, "package.json");
57723
+ const pkgPath = path45.join(projectDir, "package.json");
57547
57724
  if (fs33.existsSync(pkgPath)) {
57548
57725
  try {
57549
57726
  const pkg = JSON.parse(fs33.readFileSync(pkgPath, "utf8"));
@@ -57560,8 +57737,8 @@ function detectTypecheckCommand(projectDir) {
57560
57737
  ...pkg.dependencies,
57561
57738
  ...pkg.devDependencies
57562
57739
  };
57563
- if (!deps?.typescript && !fs33.existsSync(path44.join(projectDir, "tsconfig.json"))) {}
57564
- const hasTSMarkers = deps?.typescript || fs33.existsSync(path44.join(projectDir, "tsconfig.json"));
57740
+ if (!deps?.typescript && !fs33.existsSync(path45.join(projectDir, "tsconfig.json"))) {}
57741
+ const hasTSMarkers = deps?.typescript || fs33.existsSync(path45.join(projectDir, "tsconfig.json"));
57565
57742
  if (hasTSMarkers) {
57566
57743
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
57567
57744
  }
@@ -57569,13 +57746,13 @@ function detectTypecheckCommand(projectDir) {
57569
57746
  return null;
57570
57747
  }
57571
57748
  }
57572
- if (fs33.existsSync(path44.join(projectDir, "go.mod"))) {
57749
+ if (fs33.existsSync(path45.join(projectDir, "go.mod"))) {
57573
57750
  return { command: ["go", "vet", "./..."], language: "go" };
57574
57751
  }
57575
- if (fs33.existsSync(path44.join(projectDir, "Cargo.toml"))) {
57752
+ if (fs33.existsSync(path45.join(projectDir, "Cargo.toml"))) {
57576
57753
  return { command: ["cargo", "check"], language: "rust" };
57577
57754
  }
57578
- if (fs33.existsSync(path44.join(projectDir, "pyproject.toml")) || fs33.existsSync(path44.join(projectDir, "requirements.txt")) || fs33.existsSync(path44.join(projectDir, "setup.py"))) {
57755
+ if (fs33.existsSync(path45.join(projectDir, "pyproject.toml")) || fs33.existsSync(path45.join(projectDir, "requirements.txt")) || fs33.existsSync(path45.join(projectDir, "setup.py"))) {
57579
57756
  return { command: null, language: "python" };
57580
57757
  }
57581
57758
  try {
@@ -57876,7 +58053,7 @@ ${injectionText}`;
57876
58053
  // src/hooks/scope-guard.ts
57877
58054
  init_constants();
57878
58055
  init_schema();
57879
- import * as path46 from "path";
58056
+ import * as path47 from "path";
57880
58057
  var WRITE_TOOLS = new Set(WRITE_TOOL_NAMES);
57881
58058
  function createScopeGuardHook(config3, directory, injectAdvisory) {
57882
58059
  const enabled = config3.enabled ?? true;
@@ -57928,13 +58105,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
57928
58105
  }
57929
58106
  function isFileInScope(filePath, scopeEntries, directory) {
57930
58107
  const dir = directory ?? process.cwd();
57931
- const resolvedFile = path46.resolve(dir, filePath);
58108
+ const resolvedFile = path47.resolve(dir, filePath);
57932
58109
  return scopeEntries.some((scope) => {
57933
- const resolvedScope = path46.resolve(dir, scope);
58110
+ const resolvedScope = path47.resolve(dir, scope);
57934
58111
  if (resolvedFile === resolvedScope)
57935
58112
  return true;
57936
- const rel = path46.relative(resolvedScope, resolvedFile);
57937
- return rel.length > 0 && !rel.startsWith("..") && !path46.isAbsolute(rel);
58113
+ const rel = path47.relative(resolvedScope, resolvedFile);
58114
+ return rel.length > 0 && !rel.startsWith("..") && !path47.isAbsolute(rel);
57938
58115
  });
57939
58116
  }
57940
58117
 
@@ -57984,7 +58161,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
57984
58161
 
57985
58162
  // src/hooks/slop-detector.ts
57986
58163
  import * as fs35 from "fs";
57987
- import * as path47 from "path";
58164
+ import * as path48 from "path";
57988
58165
  var WRITE_EDIT_TOOLS = new Set([
57989
58166
  "write",
57990
58167
  "edit",
@@ -58034,7 +58211,7 @@ function walkFiles(dir, exts, deadline) {
58034
58211
  break;
58035
58212
  if (entry.isSymbolicLink())
58036
58213
  continue;
58037
- const full = path47.join(dir, entry.name);
58214
+ const full = path48.join(dir, entry.name);
58038
58215
  if (entry.isDirectory()) {
58039
58216
  if (entry.name === "node_modules" || entry.name === ".git")
58040
58217
  continue;
@@ -58049,7 +58226,7 @@ function walkFiles(dir, exts, deadline) {
58049
58226
  return results;
58050
58227
  }
58051
58228
  function checkDeadExports(content, projectDir, startTime) {
58052
- const hasPackageJson = fs35.existsSync(path47.join(projectDir, "package.json"));
58229
+ const hasPackageJson = fs35.existsSync(path48.join(projectDir, "package.json"));
58053
58230
  if (!hasPackageJson)
58054
58231
  return null;
58055
58232
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -58452,13 +58629,13 @@ init_telemetry();
58452
58629
  init_tool();
58453
58630
  init_create_tool();
58454
58631
  import * as fs38 from "fs";
58455
- import * as path49 from "path";
58632
+ import * as path50 from "path";
58456
58633
 
58457
58634
  // src/tools/symbols.ts
58458
58635
  init_tool();
58459
58636
  init_create_tool();
58460
58637
  import * as fs37 from "fs";
58461
- import * as path48 from "path";
58638
+ import * as path49 from "path";
58462
58639
  var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
58463
58640
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
58464
58641
  function containsWindowsAttacks(str) {
@@ -58475,11 +58652,11 @@ function containsWindowsAttacks(str) {
58475
58652
  }
58476
58653
  function isPathInWorkspace(filePath, workspace) {
58477
58654
  try {
58478
- const resolvedPath = path48.resolve(workspace, filePath);
58655
+ const resolvedPath = path49.resolve(workspace, filePath);
58479
58656
  const realWorkspace = fs37.realpathSync(workspace);
58480
58657
  const realResolvedPath = fs37.realpathSync(resolvedPath);
58481
- const relativePath = path48.relative(realWorkspace, realResolvedPath);
58482
- if (relativePath.startsWith("..") || path48.isAbsolute(relativePath)) {
58658
+ const relativePath = path49.relative(realWorkspace, realResolvedPath);
58659
+ if (relativePath.startsWith("..") || path49.isAbsolute(relativePath)) {
58483
58660
  return false;
58484
58661
  }
58485
58662
  return true;
@@ -58491,7 +58668,7 @@ function validatePathForRead(filePath, workspace) {
58491
58668
  return isPathInWorkspace(filePath, workspace);
58492
58669
  }
58493
58670
  function extractTSSymbols(filePath, cwd) {
58494
- const fullPath = path48.join(cwd, filePath);
58671
+ const fullPath = path49.join(cwd, filePath);
58495
58672
  if (!validatePathForRead(fullPath, cwd)) {
58496
58673
  return [];
58497
58674
  }
@@ -58643,7 +58820,7 @@ function extractTSSymbols(filePath, cwd) {
58643
58820
  });
58644
58821
  }
58645
58822
  function extractPythonSymbols(filePath, cwd) {
58646
- const fullPath = path48.join(cwd, filePath);
58823
+ const fullPath = path49.join(cwd, filePath);
58647
58824
  if (!validatePathForRead(fullPath, cwd)) {
58648
58825
  return [];
58649
58826
  }
@@ -58726,7 +58903,7 @@ var symbols = createSwarmTool({
58726
58903
  }, null, 2);
58727
58904
  }
58728
58905
  const cwd = directory;
58729
- const ext = path48.extname(file3);
58906
+ const ext = path49.extname(file3);
58730
58907
  if (containsControlChars(file3)) {
58731
58908
  return JSON.stringify({
58732
58909
  file: file3,
@@ -58802,14 +58979,14 @@ function containsWindowsAttacks2(str) {
58802
58979
  }
58803
58980
  function isPathInWorkspace2(filePath, workspace) {
58804
58981
  try {
58805
- const resolvedPath = path49.resolve(workspace, filePath);
58982
+ const resolvedPath = path50.resolve(workspace, filePath);
58806
58983
  if (!fs38.existsSync(resolvedPath)) {
58807
58984
  return true;
58808
58985
  }
58809
58986
  const realWorkspace = fs38.realpathSync(workspace);
58810
58987
  const realResolvedPath = fs38.realpathSync(resolvedPath);
58811
- const relativePath = path49.relative(realWorkspace, realResolvedPath);
58812
- if (relativePath.startsWith("..") || path49.isAbsolute(relativePath)) {
58988
+ const relativePath = path50.relative(realWorkspace, realResolvedPath);
58989
+ if (relativePath.startsWith("..") || path50.isAbsolute(relativePath)) {
58813
58990
  return false;
58814
58991
  }
58815
58992
  return true;
@@ -58818,7 +58995,7 @@ function isPathInWorkspace2(filePath, workspace) {
58818
58995
  }
58819
58996
  }
58820
58997
  function processFile(file3, cwd, exportedOnly) {
58821
- const ext = path49.extname(file3);
58998
+ const ext = path50.extname(file3);
58822
58999
  if (containsControlChars(file3)) {
58823
59000
  return {
58824
59001
  file: file3,
@@ -58851,7 +59028,7 @@ function processFile(file3, cwd, exportedOnly) {
58851
59028
  errorType: "path-outside-workspace"
58852
59029
  };
58853
59030
  }
58854
- const fullPath = path49.join(cwd, file3);
59031
+ const fullPath = path50.join(cwd, file3);
58855
59032
  if (!fs38.existsSync(fullPath)) {
58856
59033
  return {
58857
59034
  file: file3,
@@ -59142,7 +59319,7 @@ init_manager();
59142
59319
  init_create_tool();
59143
59320
  init_resolve_working_directory();
59144
59321
  import * as fs39 from "fs";
59145
- import * as path50 from "path";
59322
+ import * as path51 from "path";
59146
59323
  var EVIDENCE_DIR = ".swarm/evidence";
59147
59324
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
59148
59325
  function isValidTaskId3(taskId) {
@@ -59159,9 +59336,9 @@ function isValidTaskId3(taskId) {
59159
59336
  return TASK_ID_PATTERN2.test(taskId);
59160
59337
  }
59161
59338
  function isPathWithinSwarm(filePath, workspaceRoot) {
59162
- const normalizedWorkspace = path50.resolve(workspaceRoot);
59163
- const swarmPath = path50.join(normalizedWorkspace, ".swarm", "evidence");
59164
- const normalizedPath = path50.resolve(filePath);
59339
+ const normalizedWorkspace = path51.resolve(workspaceRoot);
59340
+ const swarmPath = path51.join(normalizedWorkspace, ".swarm", "evidence");
59341
+ const normalizedPath = path51.resolve(filePath);
59165
59342
  return normalizedPath.startsWith(swarmPath);
59166
59343
  }
59167
59344
  function readEvidenceFile(evidencePath) {
@@ -59242,7 +59419,7 @@ var check_gate_status = createSwarmTool({
59242
59419
  };
59243
59420
  return JSON.stringify(errorResult, null, 2);
59244
59421
  }
59245
- const evidencePath = path50.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
59422
+ const evidencePath = path51.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
59246
59423
  if (!isPathWithinSwarm(evidencePath, directory)) {
59247
59424
  const errorResult = {
59248
59425
  taskId: taskIdInput,
@@ -59336,7 +59513,7 @@ init_co_change_analyzer();
59336
59513
  init_dist();
59337
59514
  init_utils2();
59338
59515
  import * as fs40 from "fs";
59339
- import * as path51 from "path";
59516
+ import * as path52 from "path";
59340
59517
  init_create_tool();
59341
59518
  init_resolve_working_directory();
59342
59519
  function extractMatches(regex, text) {
@@ -59490,10 +59667,10 @@ async function executeCompletionVerify(args2, directory) {
59490
59667
  let hasFileReadFailure = false;
59491
59668
  for (const filePath of fileTargets) {
59492
59669
  const normalizedPath = filePath.replace(/\\/g, "/");
59493
- const resolvedPath = path51.resolve(directory, normalizedPath);
59494
- const projectRoot = path51.resolve(directory);
59495
- const relative9 = path51.relative(projectRoot, resolvedPath);
59496
- const withinProject = relative9 === "" || !relative9.startsWith("..") && !path51.isAbsolute(relative9);
59670
+ const resolvedPath = path52.resolve(directory, normalizedPath);
59671
+ const projectRoot = path52.resolve(directory);
59672
+ const relative9 = path52.relative(projectRoot, resolvedPath);
59673
+ const withinProject = relative9 === "" || !relative9.startsWith("..") && !path52.isAbsolute(relative9);
59497
59674
  if (!withinProject) {
59498
59675
  blockedTasks.push({
59499
59676
  task_id: task.id,
@@ -59548,8 +59725,8 @@ async function executeCompletionVerify(args2, directory) {
59548
59725
  blockedTasks
59549
59726
  };
59550
59727
  try {
59551
- const evidenceDir = path51.join(directory, ".swarm", "evidence", `${phase}`);
59552
- const evidencePath = path51.join(evidenceDir, "completion-verify.json");
59728
+ const evidenceDir = path52.join(directory, ".swarm", "evidence", `${phase}`);
59729
+ const evidencePath = path52.join(evidenceDir, "completion-verify.json");
59553
59730
  fs40.mkdirSync(evidenceDir, { recursive: true });
59554
59731
  const evidenceBundle = {
59555
59732
  schema_version: "1.0.0",
@@ -59626,11 +59803,11 @@ var completion_verify = createSwarmTool({
59626
59803
  // src/tools/complexity-hotspots.ts
59627
59804
  init_dist();
59628
59805
  import * as fs42 from "fs";
59629
- import * as path53 from "path";
59806
+ import * as path54 from "path";
59630
59807
 
59631
59808
  // src/quality/metrics.ts
59632
59809
  import * as fs41 from "fs";
59633
- import * as path52 from "path";
59810
+ import * as path53 from "path";
59634
59811
  var MAX_FILE_SIZE_BYTES3 = 256 * 1024;
59635
59812
  var MIN_DUPLICATION_LINES = 10;
59636
59813
  function estimateCyclomaticComplexity(content) {
@@ -59682,7 +59859,7 @@ async function computeComplexityDelta(files, workingDir) {
59682
59859
  let totalComplexity = 0;
59683
59860
  const analyzedFiles = [];
59684
59861
  for (const file3 of files) {
59685
- const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
59862
+ const fullPath = path53.isAbsolute(file3) ? file3 : path53.join(workingDir, file3);
59686
59863
  if (!fs41.existsSync(fullPath)) {
59687
59864
  continue;
59688
59865
  }
@@ -59805,7 +59982,7 @@ function countGoExports(content) {
59805
59982
  function getExportCountForFile(filePath) {
59806
59983
  try {
59807
59984
  const content = fs41.readFileSync(filePath, "utf-8");
59808
- const ext = path52.extname(filePath).toLowerCase();
59985
+ const ext = path53.extname(filePath).toLowerCase();
59809
59986
  switch (ext) {
59810
59987
  case ".ts":
59811
59988
  case ".tsx":
@@ -59831,7 +60008,7 @@ async function computePublicApiDelta(files, workingDir) {
59831
60008
  let totalExports = 0;
59832
60009
  const analyzedFiles = [];
59833
60010
  for (const file3 of files) {
59834
- const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
60011
+ const fullPath = path53.isAbsolute(file3) ? file3 : path53.join(workingDir, file3);
59835
60012
  if (!fs41.existsSync(fullPath)) {
59836
60013
  continue;
59837
60014
  }
@@ -59865,7 +60042,7 @@ async function computeDuplicationRatio(files, workingDir) {
59865
60042
  let duplicateLines = 0;
59866
60043
  const analyzedFiles = [];
59867
60044
  for (const file3 of files) {
59868
- const fullPath = path52.isAbsolute(file3) ? file3 : path52.join(workingDir, file3);
60045
+ const fullPath = path53.isAbsolute(file3) ? file3 : path53.join(workingDir, file3);
59869
60046
  if (!fs41.existsSync(fullPath)) {
59870
60047
  continue;
59871
60048
  }
@@ -59898,8 +60075,8 @@ function countCodeLines(content) {
59898
60075
  return lines.length;
59899
60076
  }
59900
60077
  function isTestFile(filePath) {
59901
- const basename8 = path52.basename(filePath);
59902
- const _ext = path52.extname(filePath).toLowerCase();
60078
+ const basename8 = path53.basename(filePath);
60079
+ const _ext = path53.extname(filePath).toLowerCase();
59903
60080
  const testPatterns = [
59904
60081
  ".test.",
59905
60082
  ".spec.",
@@ -59980,8 +60157,8 @@ function matchGlobSegment(globSegments, pathSegments) {
59980
60157
  }
59981
60158
  return gIndex === globSegments.length && pIndex === pathSegments.length;
59982
60159
  }
59983
- function matchesGlobSegment(path53, glob) {
59984
- const normalizedPath = path53.replace(/\\/g, "/");
60160
+ function matchesGlobSegment(path54, glob) {
60161
+ const normalizedPath = path54.replace(/\\/g, "/");
59985
60162
  const normalizedGlob = glob.replace(/\\/g, "/");
59986
60163
  if (normalizedPath.includes("//")) {
59987
60164
  return false;
@@ -60012,8 +60189,8 @@ function simpleGlobToRegex2(glob) {
60012
60189
  function hasGlobstar(glob) {
60013
60190
  return glob.includes("**");
60014
60191
  }
60015
- function globMatches(path53, glob) {
60016
- const normalizedPath = path53.replace(/\\/g, "/");
60192
+ function globMatches(path54, glob) {
60193
+ const normalizedPath = path54.replace(/\\/g, "/");
60017
60194
  if (!glob || glob === "") {
60018
60195
  if (normalizedPath.includes("//")) {
60019
60196
  return false;
@@ -60049,7 +60226,7 @@ function shouldExcludeFile(filePath, excludeGlobs) {
60049
60226
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60050
60227
  let testLines = 0;
60051
60228
  let codeLines = 0;
60052
- const srcDir = path52.join(workingDir, "src");
60229
+ const srcDir = path53.join(workingDir, "src");
60053
60230
  if (fs41.existsSync(srcDir)) {
60054
60231
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
60055
60232
  codeLines += lines;
@@ -60057,14 +60234,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60057
60234
  }
60058
60235
  const possibleSrcDirs = ["lib", "app", "source", "core"];
60059
60236
  for (const dir of possibleSrcDirs) {
60060
- const dirPath = path52.join(workingDir, dir);
60237
+ const dirPath = path53.join(workingDir, dir);
60061
60238
  if (fs41.existsSync(dirPath)) {
60062
60239
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
60063
60240
  codeLines += lines;
60064
60241
  });
60065
60242
  }
60066
60243
  }
60067
- const testsDir = path52.join(workingDir, "tests");
60244
+ const testsDir = path53.join(workingDir, "tests");
60068
60245
  if (fs41.existsSync(testsDir)) {
60069
60246
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
60070
60247
  testLines += lines;
@@ -60072,7 +60249,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60072
60249
  }
60073
60250
  const possibleTestDirs = ["test", "__tests__", "specs"];
60074
60251
  for (const dir of possibleTestDirs) {
60075
- const dirPath = path52.join(workingDir, dir);
60252
+ const dirPath = path53.join(workingDir, dir);
60076
60253
  if (fs41.existsSync(dirPath) && dirPath !== testsDir) {
60077
60254
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
60078
60255
  testLines += lines;
@@ -60087,7 +60264,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
60087
60264
  try {
60088
60265
  const entries = fs41.readdirSync(dirPath, { withFileTypes: true });
60089
60266
  for (const entry of entries) {
60090
- const fullPath = path52.join(dirPath, entry.name);
60267
+ const fullPath = path53.join(dirPath, entry.name);
60091
60268
  if (entry.isDirectory()) {
60092
60269
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
60093
60270
  continue;
@@ -60095,7 +60272,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
60095
60272
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
60096
60273
  } else if (entry.isFile()) {
60097
60274
  const relativePath = fullPath.replace(`${dirPath}/`, "");
60098
- const ext = path52.extname(entry.name).toLowerCase();
60275
+ const ext = path53.extname(entry.name).toLowerCase();
60099
60276
  const validExts = [
60100
60277
  ".ts",
60101
60278
  ".tsx",
@@ -60347,7 +60524,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
60347
60524
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
60348
60525
  const filteredChurn = new Map;
60349
60526
  for (const [file3, count] of churnMap) {
60350
- const ext = path53.extname(file3).toLowerCase();
60527
+ const ext = path54.extname(file3).toLowerCase();
60351
60528
  if (extSet.has(ext)) {
60352
60529
  filteredChurn.set(file3, count);
60353
60530
  }
@@ -60358,7 +60535,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
60358
60535
  for (const [file3, churnCount] of filteredChurn) {
60359
60536
  let fullPath = file3;
60360
60537
  if (!fs42.existsSync(fullPath)) {
60361
- fullPath = path53.join(cwd, file3);
60538
+ fullPath = path54.join(cwd, file3);
60362
60539
  }
60363
60540
  const complexity = getComplexityForFile2(fullPath);
60364
60541
  if (complexity !== null) {
@@ -60606,7 +60783,7 @@ var curator_analyze = createSwarmTool({
60606
60783
  // src/tools/declare-scope.ts
60607
60784
  init_tool();
60608
60785
  import * as fs43 from "fs";
60609
- import * as path54 from "path";
60786
+ import * as path55 from "path";
60610
60787
  init_create_tool();
60611
60788
  function validateTaskIdFormat(taskId) {
60612
60789
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -60685,8 +60862,8 @@ async function executeDeclareScope(args2, fallbackDir) {
60685
60862
  };
60686
60863
  }
60687
60864
  }
60688
- normalizedDir = path54.normalize(args2.working_directory);
60689
- const pathParts = normalizedDir.split(path54.sep);
60865
+ normalizedDir = path55.normalize(args2.working_directory);
60866
+ const pathParts = normalizedDir.split(path55.sep);
60690
60867
  if (pathParts.includes("..")) {
60691
60868
  return {
60692
60869
  success: false,
@@ -60696,10 +60873,10 @@ async function executeDeclareScope(args2, fallbackDir) {
60696
60873
  ]
60697
60874
  };
60698
60875
  }
60699
- const resolvedDir = path54.resolve(normalizedDir);
60876
+ const resolvedDir = path55.resolve(normalizedDir);
60700
60877
  try {
60701
60878
  const realPath = fs43.realpathSync(resolvedDir);
60702
- const planPath2 = path54.join(realPath, ".swarm", "plan.json");
60879
+ const planPath2 = path55.join(realPath, ".swarm", "plan.json");
60703
60880
  if (!fs43.existsSync(planPath2)) {
60704
60881
  return {
60705
60882
  success: false,
@@ -60723,7 +60900,7 @@ async function executeDeclareScope(args2, fallbackDir) {
60723
60900
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
60724
60901
  }
60725
60902
  const directory = normalizedDir || fallbackDir;
60726
- const planPath = path54.resolve(directory, ".swarm", "plan.json");
60903
+ const planPath = path55.resolve(directory, ".swarm", "plan.json");
60727
60904
  if (!fs43.existsSync(planPath)) {
60728
60905
  return {
60729
60906
  success: false,
@@ -60765,8 +60942,8 @@ async function executeDeclareScope(args2, fallbackDir) {
60765
60942
  const normalizeErrors = [];
60766
60943
  const dir = normalizedDir || fallbackDir || process.cwd();
60767
60944
  const mergedFiles = rawMergedFiles.map((file3) => {
60768
- if (path54.isAbsolute(file3)) {
60769
- const relativePath = path54.relative(dir, file3).replace(/\\/g, "/");
60945
+ if (path55.isAbsolute(file3)) {
60946
+ const relativePath = path55.relative(dir, file3).replace(/\\/g, "/");
60770
60947
  if (relativePath.startsWith("..")) {
60771
60948
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
60772
60949
  return file3;
@@ -61092,20 +61269,20 @@ function validateBase(base) {
61092
61269
  function validatePaths(paths) {
61093
61270
  if (!paths)
61094
61271
  return null;
61095
- for (const path56 of paths) {
61096
- if (!path56 || path56.length === 0) {
61272
+ for (const path57 of paths) {
61273
+ if (!path57 || path57.length === 0) {
61097
61274
  return "empty path not allowed";
61098
61275
  }
61099
- if (path56.length > MAX_PATH_LENGTH) {
61276
+ if (path57.length > MAX_PATH_LENGTH) {
61100
61277
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
61101
61278
  }
61102
- if (SHELL_METACHARACTERS2.test(path56)) {
61279
+ if (SHELL_METACHARACTERS2.test(path57)) {
61103
61280
  return "path contains shell metacharacters";
61104
61281
  }
61105
- if (path56.startsWith("-")) {
61282
+ if (path57.startsWith("-")) {
61106
61283
  return 'path cannot start with "-" (option-like arguments not allowed)';
61107
61284
  }
61108
- if (CONTROL_CHAR_PATTERN2.test(path56)) {
61285
+ if (CONTROL_CHAR_PATTERN2.test(path57)) {
61109
61286
  return "path contains control characters";
61110
61287
  }
61111
61288
  }
@@ -61186,8 +61363,8 @@ var diff = createSwarmTool({
61186
61363
  if (parts2.length >= 3) {
61187
61364
  const additions = parseInt(parts2[0], 10) || 0;
61188
61365
  const deletions = parseInt(parts2[1], 10) || 0;
61189
- const path56 = parts2[2];
61190
- files.push({ path: path56, additions, deletions });
61366
+ const path57 = parts2[2];
61367
+ files.push({ path: path57, additions, deletions });
61191
61368
  }
61192
61369
  }
61193
61370
  const contractChanges = [];
@@ -61470,7 +61647,7 @@ Use these as DOMAIN values when delegating to @sme.`;
61470
61647
  init_dist();
61471
61648
  init_create_tool();
61472
61649
  import * as fs44 from "fs";
61473
- import * as path56 from "path";
61650
+ import * as path57 from "path";
61474
61651
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
61475
61652
  var MAX_EVIDENCE_FILES = 1000;
61476
61653
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -61497,9 +61674,9 @@ function validateRequiredTypes(input) {
61497
61674
  return null;
61498
61675
  }
61499
61676
  function isPathWithinSwarm2(filePath, cwd) {
61500
- const normalizedCwd = path56.resolve(cwd);
61501
- const swarmPath = path56.join(normalizedCwd, ".swarm");
61502
- const normalizedPath = path56.resolve(filePath);
61677
+ const normalizedCwd = path57.resolve(cwd);
61678
+ const swarmPath = path57.join(normalizedCwd, ".swarm");
61679
+ const normalizedPath = path57.resolve(filePath);
61503
61680
  return normalizedPath.startsWith(swarmPath);
61504
61681
  }
61505
61682
  function parseCompletedTasks(planContent) {
@@ -61529,10 +61706,10 @@ function readEvidenceFiles(evidenceDir, _cwd) {
61529
61706
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
61530
61707
  continue;
61531
61708
  }
61532
- const filePath = path56.join(evidenceDir, filename);
61709
+ const filePath = path57.join(evidenceDir, filename);
61533
61710
  try {
61534
- const resolvedPath = path56.resolve(filePath);
61535
- const evidenceDirResolved = path56.resolve(evidenceDir);
61711
+ const resolvedPath = path57.resolve(filePath);
61712
+ const evidenceDirResolved = path57.resolve(evidenceDir);
61536
61713
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
61537
61714
  continue;
61538
61715
  }
@@ -61650,7 +61827,7 @@ var evidence_check = createSwarmTool({
61650
61827
  return JSON.stringify(errorResult, null, 2);
61651
61828
  }
61652
61829
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
61653
- const planPath = path56.join(cwd, PLAN_FILE);
61830
+ const planPath = path57.join(cwd, PLAN_FILE);
61654
61831
  if (!isPathWithinSwarm2(planPath, cwd)) {
61655
61832
  const errorResult = {
61656
61833
  error: "plan file path validation failed",
@@ -61682,7 +61859,7 @@ var evidence_check = createSwarmTool({
61682
61859
  };
61683
61860
  return JSON.stringify(result2, null, 2);
61684
61861
  }
61685
- const evidenceDir = path56.join(cwd, EVIDENCE_DIR2);
61862
+ const evidenceDir = path57.join(cwd, EVIDENCE_DIR2);
61686
61863
  const evidence = readEvidenceFiles(evidenceDir, cwd);
61687
61864
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
61688
61865
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -61700,7 +61877,7 @@ var evidence_check = createSwarmTool({
61700
61877
  init_tool();
61701
61878
  init_create_tool();
61702
61879
  import * as fs45 from "fs";
61703
- import * as path57 from "path";
61880
+ import * as path58 from "path";
61704
61881
  var EXT_MAP = {
61705
61882
  python: ".py",
61706
61883
  py: ".py",
@@ -61781,12 +61958,12 @@ var extract_code_blocks = createSwarmTool({
61781
61958
  if (prefix) {
61782
61959
  filename = `${prefix}_${filename}`;
61783
61960
  }
61784
- let filepath = path57.join(targetDir, filename);
61785
- const base = path57.basename(filepath, path57.extname(filepath));
61786
- const ext = path57.extname(filepath);
61961
+ let filepath = path58.join(targetDir, filename);
61962
+ const base = path58.basename(filepath, path58.extname(filepath));
61963
+ const ext = path58.extname(filepath);
61787
61964
  let counter = 1;
61788
61965
  while (fs45.existsSync(filepath)) {
61789
- filepath = path57.join(targetDir, `${base}_${counter}${ext}`);
61966
+ filepath = path58.join(targetDir, `${base}_${counter}${ext}`);
61790
61967
  counter++;
61791
61968
  }
61792
61969
  try {
@@ -61907,7 +62084,7 @@ var gitingest = createSwarmTool({
61907
62084
  init_dist();
61908
62085
  init_create_tool();
61909
62086
  import * as fs46 from "fs";
61910
- import * as path58 from "path";
62087
+ import * as path59 from "path";
61911
62088
  var MAX_FILE_PATH_LENGTH2 = 500;
61912
62089
  var MAX_SYMBOL_LENGTH = 256;
61913
62090
  var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
@@ -61955,7 +62132,7 @@ function validateSymbolInput(symbol3) {
61955
62132
  return null;
61956
62133
  }
61957
62134
  function isBinaryFile2(filePath, buffer) {
61958
- const ext = path58.extname(filePath).toLowerCase();
62135
+ const ext = path59.extname(filePath).toLowerCase();
61959
62136
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
61960
62137
  return false;
61961
62138
  }
@@ -61979,15 +62156,15 @@ function parseImports(content, targetFile, targetSymbol) {
61979
62156
  const imports = [];
61980
62157
  let _resolvedTarget;
61981
62158
  try {
61982
- _resolvedTarget = path58.resolve(targetFile);
62159
+ _resolvedTarget = path59.resolve(targetFile);
61983
62160
  } catch {
61984
62161
  _resolvedTarget = targetFile;
61985
62162
  }
61986
- const targetBasename = path58.basename(targetFile, path58.extname(targetFile));
62163
+ const targetBasename = path59.basename(targetFile, path59.extname(targetFile));
61987
62164
  const targetWithExt = targetFile;
61988
62165
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
61989
- const normalizedTargetWithExt = path58.normalize(targetWithExt).replace(/\\/g, "/");
61990
- const normalizedTargetWithoutExt = path58.normalize(targetWithoutExt).replace(/\\/g, "/");
62166
+ const normalizedTargetWithExt = path59.normalize(targetWithExt).replace(/\\/g, "/");
62167
+ const normalizedTargetWithoutExt = path59.normalize(targetWithoutExt).replace(/\\/g, "/");
61991
62168
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
61992
62169
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
61993
62170
  const modulePath = match[1] || match[2] || match[3];
@@ -62010,9 +62187,9 @@ function parseImports(content, targetFile, targetSymbol) {
62010
62187
  }
62011
62188
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
62012
62189
  let isMatch = false;
62013
- const _targetDir = path58.dirname(targetFile);
62014
- const targetExt = path58.extname(targetFile);
62015
- const targetBasenameNoExt = path58.basename(targetFile, targetExt);
62190
+ const _targetDir = path59.dirname(targetFile);
62191
+ const targetExt = path59.extname(targetFile);
62192
+ const targetBasenameNoExt = path59.basename(targetFile, targetExt);
62016
62193
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
62017
62194
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
62018
62195
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -62080,10 +62257,10 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
62080
62257
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
62081
62258
  for (const entry of entries) {
62082
62259
  if (SKIP_DIRECTORIES3.has(entry)) {
62083
- stats.skippedDirs.push(path58.join(dir, entry));
62260
+ stats.skippedDirs.push(path59.join(dir, entry));
62084
62261
  continue;
62085
62262
  }
62086
- const fullPath = path58.join(dir, entry);
62263
+ const fullPath = path59.join(dir, entry);
62087
62264
  let stat2;
62088
62265
  try {
62089
62266
  stat2 = fs46.statSync(fullPath);
@@ -62097,7 +62274,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
62097
62274
  if (stat2.isDirectory()) {
62098
62275
  findSourceFiles(fullPath, files, stats);
62099
62276
  } else if (stat2.isFile()) {
62100
- const ext = path58.extname(fullPath).toLowerCase();
62277
+ const ext = path59.extname(fullPath).toLowerCase();
62101
62278
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
62102
62279
  files.push(fullPath);
62103
62280
  }
@@ -62154,7 +62331,7 @@ var imports = createSwarmTool({
62154
62331
  return JSON.stringify(errorResult, null, 2);
62155
62332
  }
62156
62333
  try {
62157
- const targetFile = path58.resolve(file3);
62334
+ const targetFile = path59.resolve(file3);
62158
62335
  if (!fs46.existsSync(targetFile)) {
62159
62336
  const errorResult = {
62160
62337
  error: `target file not found: ${file3}`,
@@ -62176,7 +62353,7 @@ var imports = createSwarmTool({
62176
62353
  };
62177
62354
  return JSON.stringify(errorResult, null, 2);
62178
62355
  }
62179
- const baseDir = path58.dirname(targetFile);
62356
+ const baseDir = path59.dirname(targetFile);
62180
62357
  const scanStats = {
62181
62358
  skippedDirs: [],
62182
62359
  skippedFiles: 0,
@@ -62786,7 +62963,7 @@ init_config();
62786
62963
  init_schema();
62787
62964
  init_manager();
62788
62965
  import * as fs47 from "fs";
62789
- import * as path59 from "path";
62966
+ import * as path60 from "path";
62790
62967
  init_review_receipt();
62791
62968
  init_utils2();
62792
62969
  init_ledger();
@@ -63010,7 +63187,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63010
63187
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
63011
63188
  }
63012
63189
  try {
63013
- const driftEvidencePath = path59.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
63190
+ const driftEvidencePath = path60.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
63014
63191
  let driftVerdictFound = false;
63015
63192
  let driftVerdictApproved = false;
63016
63193
  try {
@@ -63044,7 +63221,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63044
63221
  driftVerdictFound = false;
63045
63222
  }
63046
63223
  if (!driftVerdictFound) {
63047
- const specPath = path59.join(dir, ".swarm", "spec.md");
63224
+ const specPath = path60.join(dir, ".swarm", "spec.md");
63048
63225
  const specExists = fs47.existsSync(specPath);
63049
63226
  if (!specExists) {
63050
63227
  let incompleteTaskCount = 0;
@@ -63096,7 +63273,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63096
63273
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
63097
63274
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
63098
63275
  try {
63099
- const projectName = path59.basename(dir);
63276
+ const projectName = path60.basename(dir);
63100
63277
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
63101
63278
  if (curationResult) {
63102
63279
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -63416,7 +63593,7 @@ init_discovery();
63416
63593
  init_utils();
63417
63594
  init_create_tool();
63418
63595
  import * as fs48 from "fs";
63419
- import * as path60 from "path";
63596
+ import * as path61 from "path";
63420
63597
  var MAX_OUTPUT_BYTES5 = 52428800;
63421
63598
  var AUDIT_TIMEOUT_MS = 120000;
63422
63599
  function isValidEcosystem(value) {
@@ -63434,16 +63611,16 @@ function validateArgs3(args2) {
63434
63611
  function detectEcosystems(directory) {
63435
63612
  const ecosystems = [];
63436
63613
  const cwd = directory;
63437
- if (fs48.existsSync(path60.join(cwd, "package.json"))) {
63614
+ if (fs48.existsSync(path61.join(cwd, "package.json"))) {
63438
63615
  ecosystems.push("npm");
63439
63616
  }
63440
- if (fs48.existsSync(path60.join(cwd, "pyproject.toml")) || fs48.existsSync(path60.join(cwd, "requirements.txt"))) {
63617
+ if (fs48.existsSync(path61.join(cwd, "pyproject.toml")) || fs48.existsSync(path61.join(cwd, "requirements.txt"))) {
63441
63618
  ecosystems.push("pip");
63442
63619
  }
63443
- if (fs48.existsSync(path60.join(cwd, "Cargo.toml"))) {
63620
+ if (fs48.existsSync(path61.join(cwd, "Cargo.toml"))) {
63444
63621
  ecosystems.push("cargo");
63445
63622
  }
63446
- if (fs48.existsSync(path60.join(cwd, "go.mod"))) {
63623
+ if (fs48.existsSync(path61.join(cwd, "go.mod"))) {
63447
63624
  ecosystems.push("go");
63448
63625
  }
63449
63626
  try {
@@ -63452,10 +63629,10 @@ function detectEcosystems(directory) {
63452
63629
  ecosystems.push("dotnet");
63453
63630
  }
63454
63631
  } catch {}
63455
- if (fs48.existsSync(path60.join(cwd, "Gemfile")) || fs48.existsSync(path60.join(cwd, "Gemfile.lock"))) {
63632
+ if (fs48.existsSync(path61.join(cwd, "Gemfile")) || fs48.existsSync(path61.join(cwd, "Gemfile.lock"))) {
63456
63633
  ecosystems.push("ruby");
63457
63634
  }
63458
- if (fs48.existsSync(path60.join(cwd, "pubspec.yaml"))) {
63635
+ if (fs48.existsSync(path61.join(cwd, "pubspec.yaml"))) {
63459
63636
  ecosystems.push("dart");
63460
63637
  }
63461
63638
  return ecosystems;
@@ -64478,7 +64655,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
64478
64655
  // src/tools/pre-check-batch.ts
64479
64656
  init_dist();
64480
64657
  import * as fs50 from "fs";
64481
- import * as path62 from "path";
64658
+ import * as path63 from "path";
64482
64659
 
64483
64660
  // node_modules/yocto-queue/index.js
64484
64661
  class Node2 {
@@ -64753,7 +64930,7 @@ init_dist();
64753
64930
  init_manager();
64754
64931
  init_detector();
64755
64932
  import * as fs49 from "fs";
64756
- import * as path61 from "path";
64933
+ import * as path62 from "path";
64757
64934
  import { extname as extname12 } from "path";
64758
64935
 
64759
64936
  // src/sast/rules/c.ts
@@ -65719,9 +65896,9 @@ async function sastScan(input, directory, config3) {
65719
65896
  _filesSkipped++;
65720
65897
  continue;
65721
65898
  }
65722
- const resolvedPath = path61.isAbsolute(filePath) ? filePath : path61.resolve(directory, filePath);
65723
- const resolvedDirectory = path61.resolve(directory);
65724
- if (!resolvedPath.startsWith(resolvedDirectory + path61.sep) && resolvedPath !== resolvedDirectory) {
65899
+ const resolvedPath = path62.isAbsolute(filePath) ? filePath : path62.resolve(directory, filePath);
65900
+ const resolvedDirectory = path62.resolve(directory);
65901
+ if (!resolvedPath.startsWith(resolvedDirectory + path62.sep) && resolvedPath !== resolvedDirectory) {
65725
65902
  _filesSkipped++;
65726
65903
  continue;
65727
65904
  }
@@ -65923,18 +66100,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
65923
66100
  let resolved;
65924
66101
  const isWinAbs = isWindowsAbsolutePath(inputPath);
65925
66102
  if (isWinAbs) {
65926
- resolved = path62.win32.resolve(inputPath);
65927
- } else if (path62.isAbsolute(inputPath)) {
65928
- resolved = path62.resolve(inputPath);
66103
+ resolved = path63.win32.resolve(inputPath);
66104
+ } else if (path63.isAbsolute(inputPath)) {
66105
+ resolved = path63.resolve(inputPath);
65929
66106
  } else {
65930
- resolved = path62.resolve(baseDir, inputPath);
66107
+ resolved = path63.resolve(baseDir, inputPath);
65931
66108
  }
65932
- const workspaceResolved = path62.resolve(workspaceDir);
66109
+ const workspaceResolved = path63.resolve(workspaceDir);
65933
66110
  let relative11;
65934
66111
  if (isWinAbs) {
65935
- relative11 = path62.win32.relative(workspaceResolved, resolved);
66112
+ relative11 = path63.win32.relative(workspaceResolved, resolved);
65936
66113
  } else {
65937
- relative11 = path62.relative(workspaceResolved, resolved);
66114
+ relative11 = path63.relative(workspaceResolved, resolved);
65938
66115
  }
65939
66116
  if (relative11.startsWith("..")) {
65940
66117
  return "path traversal detected";
@@ -65999,7 +66176,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
65999
66176
  if (typeof file3 !== "string") {
66000
66177
  continue;
66001
66178
  }
66002
- const resolvedPath = path62.resolve(file3);
66179
+ const resolvedPath = path63.resolve(file3);
66003
66180
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
66004
66181
  if (validationError) {
66005
66182
  continue;
@@ -66156,7 +66333,7 @@ async function runSecretscanWithFiles(files, directory) {
66156
66333
  skippedFiles++;
66157
66334
  continue;
66158
66335
  }
66159
- const resolvedPath = path62.resolve(file3);
66336
+ const resolvedPath = path63.resolve(file3);
66160
66337
  const validationError = validatePath(resolvedPath, directory, directory);
66161
66338
  if (validationError) {
66162
66339
  skippedFiles++;
@@ -66174,7 +66351,7 @@ async function runSecretscanWithFiles(files, directory) {
66174
66351
  };
66175
66352
  }
66176
66353
  for (const file3 of validatedFiles) {
66177
- const ext = path62.extname(file3).toLowerCase();
66354
+ const ext = path63.extname(file3).toLowerCase();
66178
66355
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
66179
66356
  skippedFiles++;
66180
66357
  continue;
@@ -66380,7 +66557,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
66380
66557
  const preexistingFindings = [];
66381
66558
  for (const finding of findings) {
66382
66559
  const filePath = finding.location.file;
66383
- const normalised = path62.relative(directory, filePath).replace(/\\/g, "/");
66560
+ const normalised = path63.relative(directory, filePath).replace(/\\/g, "/");
66384
66561
  const changedLines = changedLineRanges.get(normalised);
66385
66562
  if (changedLines && changedLines.has(finding.location.line)) {
66386
66563
  newFindings.push(finding);
@@ -66431,7 +66608,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
66431
66608
  warn(`pre_check_batch: Invalid file path: ${file3}`);
66432
66609
  continue;
66433
66610
  }
66434
- changedFiles.push(path62.resolve(directory, file3));
66611
+ changedFiles.push(path63.resolve(directory, file3));
66435
66612
  }
66436
66613
  if (changedFiles.length === 0) {
66437
66614
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -66619,7 +66796,7 @@ var pre_check_batch = createSwarmTool({
66619
66796
  };
66620
66797
  return JSON.stringify(errorResult, null, 2);
66621
66798
  }
66622
- const resolvedDirectory = path62.resolve(typedArgs.directory);
66799
+ const resolvedDirectory = path63.resolve(typedArgs.directory);
66623
66800
  const workspaceAnchor = resolvedDirectory;
66624
66801
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
66625
66802
  if (dirError) {
@@ -66726,25 +66903,25 @@ ${paginatedContent}`;
66726
66903
  // src/tools/save-plan.ts
66727
66904
  init_tool();
66728
66905
  import * as fs52 from "fs";
66729
- import * as path64 from "path";
66906
+ import * as path65 from "path";
66730
66907
 
66731
66908
  // src/parallel/file-locks.ts
66732
66909
  var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
66733
66910
  import * as fs51 from "fs";
66734
- import * as path63 from "path";
66911
+ import * as path64 from "path";
66735
66912
  var LOCKS_DIR = ".swarm/locks";
66736
66913
  var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
66737
66914
  function getLockFilePath(directory, filePath) {
66738
- const normalized = path63.resolve(directory, filePath);
66739
- if (!normalized.startsWith(path63.resolve(directory))) {
66915
+ const normalized = path64.resolve(directory, filePath);
66916
+ if (!normalized.startsWith(path64.resolve(directory))) {
66740
66917
  throw new Error("Invalid file path: path traversal not allowed");
66741
66918
  }
66742
66919
  const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
66743
- return path63.join(directory, LOCKS_DIR, `${hash3}.lock`);
66920
+ return path64.join(directory, LOCKS_DIR, `${hash3}.lock`);
66744
66921
  }
66745
66922
  async function tryAcquireLock(directory, filePath, agent, taskId) {
66746
66923
  const lockPath = getLockFilePath(directory, filePath);
66747
- const locksDir = path63.dirname(lockPath);
66924
+ const locksDir = path64.dirname(lockPath);
66748
66925
  if (!fs51.existsSync(locksDir)) {
66749
66926
  fs51.mkdirSync(locksDir, { recursive: true });
66750
66927
  }
@@ -66897,7 +67074,7 @@ async function executeSavePlan(args2, fallbackDir) {
66897
67074
  await savePlan(dir, plan);
66898
67075
  await writeCheckpoint(dir).catch(() => {});
66899
67076
  try {
66900
- const markerPath = path64.join(dir, ".swarm", ".plan-write-marker");
67077
+ const markerPath = path65.join(dir, ".swarm", ".plan-write-marker");
66901
67078
  const marker = JSON.stringify({
66902
67079
  source: "save_plan",
66903
67080
  timestamp: new Date().toISOString(),
@@ -66920,7 +67097,7 @@ async function executeSavePlan(args2, fallbackDir) {
66920
67097
  return {
66921
67098
  success: true,
66922
67099
  message: "Plan saved successfully",
66923
- plan_path: path64.join(dir, ".swarm", "plan.json"),
67100
+ plan_path: path65.join(dir, ".swarm", "plan.json"),
66924
67101
  phases_count: plan.phases.length,
66925
67102
  tasks_count: tasksCount,
66926
67103
  ...warnings.length > 0 ? { warnings } : {}
@@ -66965,7 +67142,7 @@ var save_plan = createSwarmTool({
66965
67142
  init_dist();
66966
67143
  init_manager();
66967
67144
  import * as fs53 from "fs";
66968
- import * as path65 from "path";
67145
+ import * as path66 from "path";
66969
67146
 
66970
67147
  // src/sbom/detectors/index.ts
66971
67148
  init_utils();
@@ -67815,7 +67992,7 @@ function findManifestFiles(rootDir) {
67815
67992
  try {
67816
67993
  const entries = fs53.readdirSync(dir, { withFileTypes: true });
67817
67994
  for (const entry of entries) {
67818
- const fullPath = path65.join(dir, entry.name);
67995
+ const fullPath = path66.join(dir, entry.name);
67819
67996
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
67820
67997
  continue;
67821
67998
  }
@@ -67824,7 +68001,7 @@ function findManifestFiles(rootDir) {
67824
68001
  } else if (entry.isFile()) {
67825
68002
  for (const pattern of patterns) {
67826
68003
  if (simpleGlobToRegex(pattern).test(entry.name)) {
67827
- manifestFiles.push(path65.relative(rootDir, fullPath));
68004
+ manifestFiles.push(path66.relative(rootDir, fullPath));
67828
68005
  break;
67829
68006
  }
67830
68007
  }
@@ -67842,11 +68019,11 @@ function findManifestFilesInDirs(directories, workingDir) {
67842
68019
  try {
67843
68020
  const entries = fs53.readdirSync(dir, { withFileTypes: true });
67844
68021
  for (const entry of entries) {
67845
- const fullPath = path65.join(dir, entry.name);
68022
+ const fullPath = path66.join(dir, entry.name);
67846
68023
  if (entry.isFile()) {
67847
68024
  for (const pattern of patterns) {
67848
68025
  if (simpleGlobToRegex(pattern).test(entry.name)) {
67849
- found.push(path65.relative(workingDir, fullPath));
68026
+ found.push(path66.relative(workingDir, fullPath));
67850
68027
  break;
67851
68028
  }
67852
68029
  }
@@ -67859,11 +68036,11 @@ function findManifestFilesInDirs(directories, workingDir) {
67859
68036
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
67860
68037
  const dirs = new Set;
67861
68038
  for (const file3 of changedFiles) {
67862
- let currentDir = path65.dirname(file3);
68039
+ let currentDir = path66.dirname(file3);
67863
68040
  while (true) {
67864
- if (currentDir && currentDir !== "." && currentDir !== path65.sep) {
67865
- dirs.add(path65.join(workingDir, currentDir));
67866
- const parent = path65.dirname(currentDir);
68041
+ if (currentDir && currentDir !== "." && currentDir !== path66.sep) {
68042
+ dirs.add(path66.join(workingDir, currentDir));
68043
+ const parent = path66.dirname(currentDir);
67867
68044
  if (parent === currentDir)
67868
68045
  break;
67869
68046
  currentDir = parent;
@@ -67947,7 +68124,7 @@ var sbom_generate = createSwarmTool({
67947
68124
  const changedFiles = obj.changed_files;
67948
68125
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
67949
68126
  const workingDir = directory;
67950
- const outputDir = path65.isAbsolute(relativeOutputDir) ? relativeOutputDir : path65.join(workingDir, relativeOutputDir);
68127
+ const outputDir = path66.isAbsolute(relativeOutputDir) ? relativeOutputDir : path66.join(workingDir, relativeOutputDir);
67951
68128
  let manifestFiles = [];
67952
68129
  if (scope === "all") {
67953
68130
  manifestFiles = findManifestFiles(workingDir);
@@ -67970,7 +68147,7 @@ var sbom_generate = createSwarmTool({
67970
68147
  const processedFiles = [];
67971
68148
  for (const manifestFile of manifestFiles) {
67972
68149
  try {
67973
- const fullPath = path65.isAbsolute(manifestFile) ? manifestFile : path65.join(workingDir, manifestFile);
68150
+ const fullPath = path66.isAbsolute(manifestFile) ? manifestFile : path66.join(workingDir, manifestFile);
67974
68151
  if (!fs53.existsSync(fullPath)) {
67975
68152
  continue;
67976
68153
  }
@@ -67987,7 +68164,7 @@ var sbom_generate = createSwarmTool({
67987
68164
  const bom = generateCycloneDX(allComponents);
67988
68165
  const bomJson = serializeCycloneDX(bom);
67989
68166
  const filename = generateSbomFilename();
67990
- const outputPath = path65.join(outputDir, filename);
68167
+ const outputPath = path66.join(outputDir, filename);
67991
68168
  fs53.writeFileSync(outputPath, bomJson, "utf-8");
67992
68169
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
67993
68170
  try {
@@ -68031,7 +68208,7 @@ var sbom_generate = createSwarmTool({
68031
68208
  init_dist();
68032
68209
  init_create_tool();
68033
68210
  import * as fs54 from "fs";
68034
- import * as path66 from "path";
68211
+ import * as path67 from "path";
68035
68212
  var SPEC_CANDIDATES = [
68036
68213
  "openapi.json",
68037
68214
  "openapi.yaml",
@@ -68063,12 +68240,12 @@ function normalizePath2(p) {
68063
68240
  }
68064
68241
  function discoverSpecFile(cwd, specFileArg) {
68065
68242
  if (specFileArg) {
68066
- const resolvedPath = path66.resolve(cwd, specFileArg);
68067
- const normalizedCwd = cwd.endsWith(path66.sep) ? cwd : cwd + path66.sep;
68243
+ const resolvedPath = path67.resolve(cwd, specFileArg);
68244
+ const normalizedCwd = cwd.endsWith(path67.sep) ? cwd : cwd + path67.sep;
68068
68245
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
68069
68246
  throw new Error("Invalid spec_file: path traversal detected");
68070
68247
  }
68071
- const ext = path66.extname(resolvedPath).toLowerCase();
68248
+ const ext = path67.extname(resolvedPath).toLowerCase();
68072
68249
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
68073
68250
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
68074
68251
  }
@@ -68082,7 +68259,7 @@ function discoverSpecFile(cwd, specFileArg) {
68082
68259
  return resolvedPath;
68083
68260
  }
68084
68261
  for (const candidate of SPEC_CANDIDATES) {
68085
- const candidatePath = path66.resolve(cwd, candidate);
68262
+ const candidatePath = path67.resolve(cwd, candidate);
68086
68263
  if (fs54.existsSync(candidatePath)) {
68087
68264
  const stats = fs54.statSync(candidatePath);
68088
68265
  if (stats.size <= MAX_SPEC_SIZE) {
@@ -68094,7 +68271,7 @@ function discoverSpecFile(cwd, specFileArg) {
68094
68271
  }
68095
68272
  function parseSpec(specFile) {
68096
68273
  const content = fs54.readFileSync(specFile, "utf-8");
68097
- const ext = path66.extname(specFile).toLowerCase();
68274
+ const ext = path67.extname(specFile).toLowerCase();
68098
68275
  if (ext === ".json") {
68099
68276
  return parseJsonSpec(content);
68100
68277
  }
@@ -68170,7 +68347,7 @@ function extractRoutes(cwd) {
68170
68347
  return;
68171
68348
  }
68172
68349
  for (const entry of entries) {
68173
- const fullPath = path66.join(dir, entry.name);
68350
+ const fullPath = path67.join(dir, entry.name);
68174
68351
  if (entry.isSymbolicLink()) {
68175
68352
  continue;
68176
68353
  }
@@ -68180,7 +68357,7 @@ function extractRoutes(cwd) {
68180
68357
  }
68181
68358
  walkDir(fullPath);
68182
68359
  } else if (entry.isFile()) {
68183
- const ext = path66.extname(entry.name).toLowerCase();
68360
+ const ext = path67.extname(entry.name).toLowerCase();
68184
68361
  const baseName = entry.name.toLowerCase();
68185
68362
  if (![".ts", ".js", ".mjs"].includes(ext)) {
68186
68363
  continue;
@@ -68346,7 +68523,7 @@ var schema_drift = createSwarmTool({
68346
68523
  init_tool();
68347
68524
  init_create_tool();
68348
68525
  import * as fs55 from "fs";
68349
- import * as path67 from "path";
68526
+ import * as path68 from "path";
68350
68527
  var DEFAULT_MAX_RESULTS = 100;
68351
68528
  var DEFAULT_MAX_LINES = 200;
68352
68529
  var REGEX_TIMEOUT_MS = 5000;
@@ -68382,11 +68559,11 @@ function containsWindowsAttacks3(str) {
68382
68559
  }
68383
68560
  function isPathInWorkspace3(filePath, workspace) {
68384
68561
  try {
68385
- const resolvedPath = path67.resolve(workspace, filePath);
68562
+ const resolvedPath = path68.resolve(workspace, filePath);
68386
68563
  const realWorkspace = fs55.realpathSync(workspace);
68387
68564
  const realResolvedPath = fs55.realpathSync(resolvedPath);
68388
- const relativePath = path67.relative(realWorkspace, realResolvedPath);
68389
- if (relativePath.startsWith("..") || path67.isAbsolute(relativePath)) {
68565
+ const relativePath = path68.relative(realWorkspace, realResolvedPath);
68566
+ if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
68390
68567
  return false;
68391
68568
  }
68392
68569
  return true;
@@ -68399,11 +68576,11 @@ function validatePathForRead2(filePath, workspace) {
68399
68576
  }
68400
68577
  function findRgInEnvPath() {
68401
68578
  const searchPath = process.env.PATH ?? "";
68402
- for (const dir of searchPath.split(path67.delimiter)) {
68579
+ for (const dir of searchPath.split(path68.delimiter)) {
68403
68580
  if (!dir)
68404
68581
  continue;
68405
68582
  const isWindows = process.platform === "win32";
68406
- const candidate = path67.join(dir, isWindows ? "rg.exe" : "rg");
68583
+ const candidate = path68.join(dir, isWindows ? "rg.exe" : "rg");
68407
68584
  if (fs55.existsSync(candidate))
68408
68585
  return candidate;
68409
68586
  }
@@ -68533,8 +68710,8 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
68533
68710
  try {
68534
68711
  const entries = fs55.readdirSync(dir, { withFileTypes: true });
68535
68712
  for (const entry of entries) {
68536
- const fullPath = path67.join(dir, entry.name);
68537
- const relativePath = path67.relative(workspace, fullPath);
68713
+ const fullPath = path68.join(dir, entry.name);
68714
+ const relativePath = path68.relative(workspace, fullPath);
68538
68715
  if (!validatePathForRead2(fullPath, workspace)) {
68539
68716
  continue;
68540
68717
  }
@@ -68575,7 +68752,7 @@ async function fallbackSearch(opts) {
68575
68752
  const matches = [];
68576
68753
  let total = 0;
68577
68754
  for (const file3 of files) {
68578
- const fullPath = path67.join(opts.workspace, file3);
68755
+ const fullPath = path68.join(opts.workspace, file3);
68579
68756
  if (!validatePathForRead2(fullPath, opts.workspace)) {
68580
68757
  continue;
68581
68758
  }
@@ -68746,7 +68923,7 @@ init_secretscan();
68746
68923
  init_tool();
68747
68924
  init_create_tool();
68748
68925
  import * as fs56 from "fs";
68749
- import * as path68 from "path";
68926
+ import * as path69 from "path";
68750
68927
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
68751
68928
  function containsWindowsAttacks4(str) {
68752
68929
  if (/:[^\\/]/.test(str))
@@ -68760,14 +68937,14 @@ function containsWindowsAttacks4(str) {
68760
68937
  }
68761
68938
  function isPathInWorkspace4(filePath, workspace) {
68762
68939
  try {
68763
- const resolvedPath = path68.resolve(workspace, filePath);
68940
+ const resolvedPath = path69.resolve(workspace, filePath);
68764
68941
  if (!fs56.existsSync(resolvedPath)) {
68765
68942
  return true;
68766
68943
  }
68767
68944
  const realWorkspace = fs56.realpathSync(workspace);
68768
68945
  const realResolvedPath = fs56.realpathSync(resolvedPath);
68769
- const relativePath = path68.relative(realWorkspace, realResolvedPath);
68770
- if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
68946
+ const relativePath = path69.relative(realWorkspace, realResolvedPath);
68947
+ if (relativePath.startsWith("..") || path69.isAbsolute(relativePath)) {
68771
68948
  return false;
68772
68949
  }
68773
68950
  return true;
@@ -68975,7 +69152,7 @@ var suggestPatch = createSwarmTool({
68975
69152
  });
68976
69153
  continue;
68977
69154
  }
68978
- const fullPath = path68.resolve(directory, change.file);
69155
+ const fullPath = path69.resolve(directory, change.file);
68979
69156
  if (!fs56.existsSync(fullPath)) {
68980
69157
  errors5.push({
68981
69158
  success: false,
@@ -69079,7 +69256,7 @@ init_dist();
69079
69256
  init_utils();
69080
69257
  init_create_tool();
69081
69258
  import * as fs57 from "fs";
69082
- import * as path69 from "path";
69259
+ import * as path70 from "path";
69083
69260
  var MAX_TEXT_LENGTH = 200;
69084
69261
  var MAX_FILE_SIZE_BYTES9 = 1024 * 1024;
69085
69262
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -69144,9 +69321,9 @@ function validatePathsInput(paths, cwd) {
69144
69321
  return { error: "paths contains path traversal", resolvedPath: null };
69145
69322
  }
69146
69323
  try {
69147
- const resolvedPath = path69.resolve(paths);
69148
- const normalizedCwd = path69.resolve(cwd);
69149
- const normalizedResolved = path69.resolve(resolvedPath);
69324
+ const resolvedPath = path70.resolve(paths);
69325
+ const normalizedCwd = path70.resolve(cwd);
69326
+ const normalizedResolved = path70.resolve(resolvedPath);
69150
69327
  if (!normalizedResolved.startsWith(normalizedCwd)) {
69151
69328
  return {
69152
69329
  error: "paths must be within the current working directory",
@@ -69162,7 +69339,7 @@ function validatePathsInput(paths, cwd) {
69162
69339
  }
69163
69340
  }
69164
69341
  function isSupportedExtension(filePath) {
69165
- const ext = path69.extname(filePath).toLowerCase();
69342
+ const ext = path70.extname(filePath).toLowerCase();
69166
69343
  return SUPPORTED_EXTENSIONS2.has(ext);
69167
69344
  }
69168
69345
  function findSourceFiles2(dir, files = []) {
@@ -69177,7 +69354,7 @@ function findSourceFiles2(dir, files = []) {
69177
69354
  if (SKIP_DIRECTORIES4.has(entry)) {
69178
69355
  continue;
69179
69356
  }
69180
- const fullPath = path69.join(dir, entry);
69357
+ const fullPath = path70.join(dir, entry);
69181
69358
  let stat2;
69182
69359
  try {
69183
69360
  stat2 = fs57.statSync(fullPath);
@@ -69289,7 +69466,7 @@ var todo_extract = createSwarmTool({
69289
69466
  filesToScan.push(scanPath);
69290
69467
  } else {
69291
69468
  const errorResult = {
69292
- error: `unsupported file extension: ${path69.extname(scanPath)}`,
69469
+ error: `unsupported file extension: ${path70.extname(scanPath)}`,
69293
69470
  total: 0,
69294
69471
  byPriority: { high: 0, medium: 0, low: 0 },
69295
69472
  entries: []
@@ -69336,14 +69513,14 @@ init_tool();
69336
69513
  init_schema();
69337
69514
  init_gate_evidence();
69338
69515
  import * as fs59 from "fs";
69339
- import * as path71 from "path";
69516
+ import * as path72 from "path";
69340
69517
 
69341
69518
  // src/hooks/diff-scope.ts
69342
69519
  import * as fs58 from "fs";
69343
- import * as path70 from "path";
69520
+ import * as path71 from "path";
69344
69521
  function getDeclaredScope(taskId, directory) {
69345
69522
  try {
69346
- const planPath = path70.join(directory, ".swarm", "plan.json");
69523
+ const planPath = path71.join(directory, ".swarm", "plan.json");
69347
69524
  if (!fs58.existsSync(planPath))
69348
69525
  return null;
69349
69526
  const raw = fs58.readFileSync(planPath, "utf-8");
@@ -69459,7 +69636,7 @@ var TIER_3_PATTERNS = [
69459
69636
  ];
69460
69637
  function matchesTier3Pattern(files) {
69461
69638
  for (const file3 of files) {
69462
- const fileName = path71.basename(file3);
69639
+ const fileName = path72.basename(file3);
69463
69640
  for (const pattern of TIER_3_PATTERNS) {
69464
69641
  if (pattern.test(fileName)) {
69465
69642
  return true;
@@ -69473,7 +69650,7 @@ function checkReviewerGate(taskId, workingDirectory) {
69473
69650
  if (hasActiveTurboMode()) {
69474
69651
  const resolvedDir2 = workingDirectory;
69475
69652
  try {
69476
- const planPath = path71.join(resolvedDir2, ".swarm", "plan.json");
69653
+ const planPath = path72.join(resolvedDir2, ".swarm", "plan.json");
69477
69654
  const planRaw = fs59.readFileSync(planPath, "utf-8");
69478
69655
  const plan = JSON.parse(planRaw);
69479
69656
  for (const planPhase of plan.phases ?? []) {
@@ -69540,7 +69717,7 @@ function checkReviewerGate(taskId, workingDirectory) {
69540
69717
  }
69541
69718
  try {
69542
69719
  const resolvedDir2 = workingDirectory;
69543
- const planPath = path71.join(resolvedDir2, ".swarm", "plan.json");
69720
+ const planPath = path72.join(resolvedDir2, ".swarm", "plan.json");
69544
69721
  const planRaw = fs59.readFileSync(planPath, "utf-8");
69545
69722
  const plan = JSON.parse(planRaw);
69546
69723
  for (const planPhase of plan.phases ?? []) {
@@ -69723,8 +69900,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
69723
69900
  };
69724
69901
  }
69725
69902
  }
69726
- normalizedDir = path71.normalize(args2.working_directory);
69727
- const pathParts = normalizedDir.split(path71.sep);
69903
+ normalizedDir = path72.normalize(args2.working_directory);
69904
+ const pathParts = normalizedDir.split(path72.sep);
69728
69905
  if (pathParts.includes("..")) {
69729
69906
  return {
69730
69907
  success: false,
@@ -69734,10 +69911,10 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
69734
69911
  ]
69735
69912
  };
69736
69913
  }
69737
- const resolvedDir = path71.resolve(normalizedDir);
69914
+ const resolvedDir = path72.resolve(normalizedDir);
69738
69915
  try {
69739
69916
  const realPath = fs59.realpathSync(resolvedDir);
69740
- const planPath = path71.join(realPath, ".swarm", "plan.json");
69917
+ const planPath = path72.join(realPath, ".swarm", "plan.json");
69741
69918
  if (!fs59.existsSync(planPath)) {
69742
69919
  return {
69743
69920
  success: false,
@@ -69771,7 +69948,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
69771
69948
  recoverTaskStateFromDelegations(args2.task_id);
69772
69949
  let phaseRequiresReviewer = true;
69773
69950
  try {
69774
- const planPath = path71.join(directory, ".swarm", "plan.json");
69951
+ const planPath = path72.join(directory, ".swarm", "plan.json");
69775
69952
  const planRaw = fs59.readFileSync(planPath, "utf-8");
69776
69953
  const plan = JSON.parse(planRaw);
69777
69954
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
@@ -69836,7 +70013,7 @@ init_tool();
69836
70013
  init_utils2();
69837
70014
  init_create_tool();
69838
70015
  import fs60 from "fs";
69839
- import path72 from "path";
70016
+ import path73 from "path";
69840
70017
  function normalizeVerdict(verdict) {
69841
70018
  switch (verdict) {
69842
70019
  case "APPROVED":
@@ -69883,7 +70060,7 @@ async function executeWriteDriftEvidence(args2, directory) {
69883
70060
  entries: [evidenceEntry]
69884
70061
  };
69885
70062
  const filename = "drift-verifier.json";
69886
- const relativePath = path72.join("evidence", String(phase), filename);
70063
+ const relativePath = path73.join("evidence", String(phase), filename);
69887
70064
  let validatedPath;
69888
70065
  try {
69889
70066
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -69894,10 +70071,10 @@ async function executeWriteDriftEvidence(args2, directory) {
69894
70071
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
69895
70072
  }, null, 2);
69896
70073
  }
69897
- const evidenceDir = path72.dirname(validatedPath);
70074
+ const evidenceDir = path73.dirname(validatedPath);
69898
70075
  try {
69899
70076
  await fs60.promises.mkdir(evidenceDir, { recursive: true });
69900
- const tempPath = path72.join(evidenceDir, `.${filename}.tmp`);
70077
+ const tempPath = path73.join(evidenceDir, `.${filename}.tmp`);
69901
70078
  await fs60.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
69902
70079
  await fs60.promises.rename(tempPath, validatedPath);
69903
70080
  return JSON.stringify({
@@ -70013,7 +70190,8 @@ var OpenCodeSwarm = async (ctx) => {
70013
70190
  console.warn("");
70014
70191
  }
70015
70192
  const delegationHandler = createDelegationTrackerHook(config3, guardrailsConfig.enabled);
70016
- const guardrailsHooks = createGuardrailsHooks(ctx.directory, undefined, guardrailsConfig);
70193
+ const authorityConfig = AuthorityConfigSchema.parse(config3.authority ?? {});
70194
+ const guardrailsHooks = createGuardrailsHooks(ctx.directory, undefined, guardrailsConfig, authorityConfig);
70017
70195
  const watchdogConfig = WatchdogConfigSchema.parse(config3.watchdog ?? {});
70018
70196
  const advisoryInjector = (sessionId, message) => {
70019
70197
  const s = swarmState.agentSessions.get(sessionId);
@@ -70090,7 +70268,7 @@ var OpenCodeSwarm = async (ctx) => {
70090
70268
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
70091
70269
  preflightTriggerManager = new PTM(automationConfig);
70092
70270
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
70093
- const swarmDir = path73.resolve(ctx.directory, ".swarm");
70271
+ const swarmDir = path74.resolve(ctx.directory, ".swarm");
70094
70272
  statusArtifact = new ASA(swarmDir);
70095
70273
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
70096
70274
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {