opencode-swarm 7.50.3 → 7.51.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
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.50.3",
72
+ version: "7.51.0",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -191,7 +191,7 @@ var init_tool_metadata = __esm(() => {
191
191
  agents: ["architect", "reviewer", "critic_oversight"]
192
192
  },
193
193
  syntax_check: {
194
- description: "syntax validation",
194
+ description: "check syntax of source files using tree-sitter parsers across multiple languages, returning per-file errors",
195
195
  agents: ["architect", "coder", "test_engineer"]
196
196
  },
197
197
  placeholder_scan: {
@@ -199,7 +199,7 @@ var init_tool_metadata = __esm(() => {
199
199
  agents: ["architect", "reviewer"]
200
200
  },
201
201
  imports: {
202
- description: "dependency audit",
202
+ description: "find all consumers that import from a given file — use before refactoring shared modules to avoid breaking unseen dependents",
203
203
  agents: [
204
204
  "architect",
205
205
  "sme",
@@ -217,11 +217,11 @@ var init_tool_metadata = __esm(() => {
217
217
  ]
218
218
  },
219
219
  lint: {
220
- description: "code quality",
220
+ description: "run project linter in check or fix mode; supports biome, eslint, ruff, clippy, and more, returns structured results",
221
221
  agents: ["architect", "reviewer", "coder"]
222
222
  },
223
223
  secretscan: {
224
- description: "secret detection",
224
+ description: "scan for secrets (API keys, tokens, passwords) via regex and entropy; returns redacted previews, excludes common dirs",
225
225
  agents: ["architect", "reviewer", "critic_oversight"]
226
226
  },
227
227
  sast_scan: {
@@ -229,7 +229,7 @@ var init_tool_metadata = __esm(() => {
229
229
  agents: ["architect", "reviewer", "critic_oversight"]
230
230
  },
231
231
  build_check: {
232
- description: "build verification",
232
+ description: "discover and run build, typecheck, and test commands for various project ecosystems in the working directory",
233
233
  agents: ["architect", "coder", "test_engineer"]
234
234
  },
235
235
  pre_check_batch: {
@@ -241,7 +241,7 @@ var init_tool_metadata = __esm(() => {
241
241
  agents: ["architect"]
242
242
  },
243
243
  symbols: {
244
- description: "code symbol search",
244
+ description: "extract exported symbols (functions, classes, interfaces, types) from source files; supports TypeScript, JavaScript, and Python",
245
245
  agents: [
246
246
  "architect",
247
247
  "sme",
@@ -312,7 +312,7 @@ var init_tool_metadata = __esm(() => {
312
312
  agents: ["architect"]
313
313
  },
314
314
  checkpoint: {
315
- description: "state snapshots",
315
+ description: "create named git checkpoints for save, restore, and delete — use before risky operations to enable rollback",
316
316
  agents: ["architect"]
317
317
  },
318
318
  pkg_audit: {
@@ -356,6 +356,10 @@ var init_tool_metadata = __esm(() => {
356
356
  "explorer"
357
357
  ]
358
358
  },
359
+ git_blame: {
360
+ description: "per-line git blame metadata: sha, author, date, summary for each line in a file",
361
+ agents: ["reviewer", "explorer", "architect"]
362
+ },
359
363
  gitingest: {
360
364
  description: "fetch a GitHub repository full content via gitingest.com",
361
365
  agents: ["architect", "docs", "explorer"]
@@ -40728,6 +40732,7 @@ function isParallelGuidancePhaseComplete(phase) {
40728
40732
  return phase.status === "complete" || phase.status === "completed" || phase.status === "closed";
40729
40733
  }
40730
40734
  async function getEvidenceTaskId(session, directory) {
40735
+ let resolvedPlanPath;
40731
40736
  const primary = session.currentTaskId ?? session.lastCoderDelegationTaskId;
40732
40737
  if (primary)
40733
40738
  return primary;
@@ -40740,12 +40745,12 @@ async function getEvidenceTaskId(session, directory) {
40740
40745
  }
40741
40746
  const resolvedDirectory = path19.resolve(directory);
40742
40747
  const planPath = path19.join(resolvedDirectory, ".swarm", "plan.json");
40743
- const resolvedPlanPath = path19.resolve(planPath);
40748
+ resolvedPlanPath = path19.resolve(planPath);
40744
40749
  if (!resolvedPlanPath.startsWith(resolvedDirectory + path19.sep) && resolvedPlanPath !== resolvedDirectory) {
40745
40750
  return null;
40746
40751
  }
40747
40752
  const planContent = await fs12.promises.readFile(resolvedPlanPath, "utf-8");
40748
- const plan = JSON.parse(planContent);
40753
+ const plan = EvidenceTaskIdPlanSchema.parse(JSON.parse(planContent));
40749
40754
  if (!plan || !Array.isArray(plan.phases)) {
40750
40755
  return null;
40751
40756
  }
@@ -40759,6 +40764,11 @@ async function getEvidenceTaskId(session, directory) {
40759
40764
  }
40760
40765
  }
40761
40766
  } catch (err2) {
40767
+ if (err2 instanceof ZodError) {
40768
+ const issueSummary = err2.issues.slice(0, 3).map((issue2) => issue2.message).join("; ");
40769
+ warn(`[delegation-gate] getEvidenceTaskId ignored invalid plan schema at ${resolvedPlanPath ?? "unknown path"}: ${issueSummary}`);
40770
+ return null;
40771
+ }
40762
40772
  if (process.env.DEBUG_SWARM && err2 instanceof Error) {
40763
40773
  warn(`[delegation-gate] getEvidenceTaskId error: ${err2.message} (code=${err2.code ?? "none"})`);
40764
40774
  }
@@ -41405,8 +41415,9 @@ ${warningLines.join(`
41405
41415
  toolAfter
41406
41416
  };
41407
41417
  }
41408
- var pendingCoderScopeByTaskId, ACTIVE_PARALLEL_TASK_STATES;
41418
+ var EvidenceTaskIdPlanSchema, pendingCoderScopeByTaskId, ACTIVE_PARALLEL_TASK_STATES;
41409
41419
  var init_delegation_gate = __esm(() => {
41420
+ init_zod();
41410
41421
  init_schema();
41411
41422
  init_manager();
41412
41423
  init_state();
@@ -41416,6 +41427,14 @@ var init_delegation_gate = __esm(() => {
41416
41427
  init_guardrails();
41417
41428
  init_normalize_tool_name();
41418
41429
  init_utils2();
41430
+ EvidenceTaskIdPlanSchema = exports_external.object({
41431
+ phases: exports_external.array(exports_external.object({
41432
+ tasks: exports_external.array(exports_external.object({
41433
+ id: exports_external.string(),
41434
+ status: exports_external.string().optional()
41435
+ }).passthrough()).optional()
41436
+ }).passthrough()).optional()
41437
+ }).passthrough();
41419
41438
  pendingCoderScopeByTaskId = new Map;
41420
41439
  ACTIVE_PARALLEL_TASK_STATES = new Set([
41421
41440
  "coder_delegated",
@@ -74590,11 +74609,14 @@ async function defaultSelectTestFramework(profile, dir) {
74590
74609
  function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}) {
74591
74610
  const scope = opts.scope ?? "all";
74592
74611
  const coverage = opts.coverage ?? false;
74612
+ const bail = opts.bail ?? false;
74593
74613
  switch (framework) {
74594
74614
  case "bun": {
74595
74615
  const args2 = ["bun", "test"];
74596
74616
  if (coverage)
74597
74617
  args2.push("--coverage");
74618
+ if (bail)
74619
+ args2.push("--bail");
74598
74620
  if (scope !== "all" && files.length > 0)
74599
74621
  args2.push(...files);
74600
74622
  return args2;
@@ -74610,6 +74632,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
74610
74632
  ];
74611
74633
  if (coverage)
74612
74634
  args2.push("--coverage");
74635
+ if (bail)
74636
+ args2.push("--bail");
74613
74637
  if (scope !== "all" && files.length > 0)
74614
74638
  args2.push(...files);
74615
74639
  return args2;
@@ -74618,12 +74642,16 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
74618
74642
  const args2 = ["npx", "jest", "--json"];
74619
74643
  if (coverage)
74620
74644
  args2.push("--coverage");
74645
+ if (bail)
74646
+ args2.push("--bail");
74621
74647
  if (scope !== "all" && files.length > 0)
74622
74648
  args2.push(...files);
74623
74649
  return args2;
74624
74650
  }
74625
74651
  case "mocha": {
74626
74652
  const args2 = ["npx", "mocha"];
74653
+ if (bail)
74654
+ args2.push("--bail");
74627
74655
  if (scope !== "all" && files.length > 0)
74628
74656
  args2.push(...files);
74629
74657
  return args2;
@@ -74633,6 +74661,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
74633
74661
  const args2 = isWindows ? ["python", "-m", "pytest"] : ["python3", "-m", "pytest"];
74634
74662
  if (coverage)
74635
74663
  args2.push("--cov=.", "--cov-report=term-missing");
74664
+ if (bail)
74665
+ args2.push("-x");
74636
74666
  if (scope !== "all" && files.length > 0)
74637
74667
  args2.push(...files);
74638
74668
  return args2;
@@ -74686,6 +74716,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
74686
74716
  return isCommandAvailable("flutter") ? ["flutter", "test", ...files] : ["dart", "test", ...files];
74687
74717
  case "rspec": {
74688
74718
  const args2 = isCommandAvailable("bundle") ? ["bundle", "exec", "rspec"] : ["rspec"];
74719
+ if (bail)
74720
+ args2.push("--fail-fast");
74689
74721
  if (scope !== "all" && files.length > 0)
74690
74722
  args2.push(...files);
74691
74723
  return args2;
@@ -76660,6 +76692,10 @@ function validateArgs2(args2) {
76660
76692
  if (typeof obj.coverage !== "boolean")
76661
76693
  return false;
76662
76694
  }
76695
+ if (obj.bail !== undefined) {
76696
+ if (typeof obj.bail !== "boolean")
76697
+ return false;
76698
+ }
76663
76699
  if (obj.timeout_ms !== undefined) {
76664
76700
  if (typeof obj.timeout_ms !== "number")
76665
76701
  return false;
@@ -76735,7 +76771,7 @@ async function detectTestFrameworkViaDispatch(cwd) {
76735
76771
  return "none";
76736
76772
  }
76737
76773
  }
76738
- async function buildTestCommandViaDispatch(framework, scope, files, coverage, baseDir) {
76774
+ async function buildTestCommandViaDispatch(framework, scope, files, coverage, baseDir, bail) {
76739
76775
  if (framework === "none")
76740
76776
  return null;
76741
76777
  try {
@@ -76744,7 +76780,8 @@ async function buildTestCommandViaDispatch(framework, scope, files, coverage, ba
76744
76780
  if (backend?.buildTestCommand) {
76745
76781
  const cmd = backend.buildTestCommand(framework, files, baseDir, {
76746
76782
  scope,
76747
- coverage
76783
+ coverage,
76784
+ bail
76748
76785
  });
76749
76786
  if (cmd)
76750
76787
  return cmd;
@@ -77113,12 +77150,14 @@ function getTargetedExecutionUnsupportedReason(framework) {
77113
77150
  return null;
77114
77151
  }
77115
77152
  }
77116
- function buildTestCommand2(framework, scope, files, coverage, baseDir) {
77153
+ function buildTestCommand2(framework, scope, files, coverage, baseDir, bail) {
77117
77154
  switch (framework) {
77118
77155
  case "bun": {
77119
77156
  const args2 = ["bun", "test"];
77120
77157
  if (coverage)
77121
77158
  args2.push("--coverage");
77159
+ if (bail)
77160
+ args2.push("--bail");
77122
77161
  if (scope !== "all" && files.length > 0) {
77123
77162
  args2.push(...files);
77124
77163
  }
@@ -77135,6 +77174,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
77135
77174
  ];
77136
77175
  if (coverage)
77137
77176
  args2.push("--coverage");
77177
+ if (bail)
77178
+ args2.push("--bail=1");
77138
77179
  if (scope !== "all" && files.length > 0) {
77139
77180
  args2.push(...files);
77140
77181
  }
@@ -77144,6 +77185,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
77144
77185
  const args2 = ["npx", "jest", "--json"];
77145
77186
  if (coverage)
77146
77187
  args2.push("--coverage");
77188
+ if (bail)
77189
+ args2.push("--bail");
77147
77190
  if (scope !== "all" && files.length > 0) {
77148
77191
  args2.push(...files);
77149
77192
  }
@@ -77151,6 +77194,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
77151
77194
  }
77152
77195
  case "mocha": {
77153
77196
  const args2 = ["npx", "mocha"];
77197
+ if (bail)
77198
+ args2.push("--bail");
77154
77199
  if (scope !== "all" && files.length > 0) {
77155
77200
  args2.push(...files);
77156
77201
  }
@@ -77161,6 +77206,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
77161
77206
  const args2 = isWindows ? ["python", "-m", "pytest"] : ["python3", "-m", "pytest"];
77162
77207
  if (coverage)
77163
77208
  args2.push("--cov=.", "--cov-report=term-missing");
77209
+ if (bail)
77210
+ args2.push("-x");
77164
77211
  if (scope !== "all" && files.length > 0) {
77165
77212
  args2.push(...files);
77166
77213
  }
@@ -77217,6 +77264,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
77217
77264
  return isCommandAvailable("flutter") ? ["flutter", "test", ...files] : ["dart", "test", ...files];
77218
77265
  case "rspec": {
77219
77266
  const args2 = isCommandAvailable("bundle") ? ["bundle", "exec", "rspec"] : ["rspec"];
77267
+ if (bail)
77268
+ args2.push("--fail-fast");
77220
77269
  if (scope !== "all" && files.length > 0) {
77221
77270
  args2.push(...files);
77222
77271
  }
@@ -77602,7 +77651,7 @@ async function readBoundedStream(stream, maxBytes) {
77602
77651
  }
77603
77652
  return { text: decoder.decode(combined), truncated };
77604
77653
  }
77605
- async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
77654
+ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail) {
77606
77655
  if (scope !== "all" && files.length > 0) {
77607
77656
  const unsupportedReason = getTargetedExecutionUnsupportedReason(framework);
77608
77657
  if (unsupportedReason) {
@@ -77617,7 +77666,7 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
77617
77666
  }
77618
77667
  }
77619
77668
  const useDispatchBuild = process.env.SWARM_LANG_BACKEND !== "legacy";
77620
- const command = useDispatchBuild ? await buildTestCommandViaDispatch(framework, scope, files, coverage, cwd) ?? buildTestCommand2(framework, scope, files, coverage, cwd) : buildTestCommand2(framework, scope, files, coverage, cwd);
77669
+ const command = useDispatchBuild ? await buildTestCommandViaDispatch(framework, scope, files, coverage, cwd, bail) ?? buildTestCommand2(framework, scope, files, coverage, cwd, bail) : buildTestCommand2(framework, scope, files, coverage, cwd, bail);
77621
77670
  if (!command) {
77622
77671
  return {
77623
77672
  success: false,
@@ -77965,6 +78014,7 @@ var init_test_runner = __esm(() => {
77965
78014
  scope: exports_external.enum(["all", "convention", "graph", "impact"]).optional().describe('Test scope: "all" runs full suite, "convention" accepts direct test files or maps source files to tests by naming, "graph" finds related tests via imports from source files, "impact" finds tests covering changed source files via test-impact analysis'),
77966
78015
  files: exports_external.array(exports_external.string()).optional().describe('Specific files to test. For "convention", pass source files or direct test files. For "graph" and "impact", pass source files only.'),
77967
78016
  coverage: exports_external.boolean().optional().describe("Enable coverage reporting if supported"),
78017
+ bail: exports_external.boolean().optional().describe("Stop running tests after the first failure. Default false. Note: coverage may be incomplete when bail=true with coverage=true."),
77968
78018
  timeout_ms: exports_external.number().optional().describe("Timeout in milliseconds (default 60000, max 300000)"),
77969
78019
  allow_full_suite: exports_external.boolean().optional().describe('Explicit opt-in for scope "all". Required because full-suite output can destabilize SSE streaming.'),
77970
78020
  working_directory: exports_external.string().optional().describe("Explicit project root directory. When provided, tests run relative to this path instead of the plugin context directory. Use this when CWD differs from the actual project root.")
@@ -78065,6 +78115,7 @@ var init_test_runner = __esm(() => {
78065
78115
  }
78066
78116
  const _files = args2.files || [];
78067
78117
  const coverage = args2.coverage || false;
78118
+ const bail = args2.bail || false;
78068
78119
  const timeout_ms = Math.min(args2.timeout_ms || DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);
78069
78120
  const useDispatch = process.env.SWARM_LANG_BACKEND !== "legacy";
78070
78121
  let framework;
@@ -78303,7 +78354,7 @@ var init_test_runner = __esm(() => {
78303
78354
  };
78304
78355
  return JSON.stringify(errorResult, null, 2);
78305
78356
  }
78306
- const result = await runTests(framework, effectiveScope, testFiles, coverage, timeout_ms, workingDir);
78357
+ const result = await runTests(framework, effectiveScope, testFiles, coverage, timeout_ms, workingDir, bail);
78307
78358
  recordAndAnalyzeResults(result, testFiles, workingDir, _files.length > 0 ? _files : undefined, result.testCases);
78308
78359
  let historyReport;
78309
78360
  if (!result.success && result.totals && result.totals.failed > 0) {
@@ -78319,6 +78370,9 @@ var init_test_runner = __esm(() => {
78319
78370
  if (graphFallbackReason && result.message) {
78320
78371
  result.message = `${result.message} (${graphFallbackReason})`;
78321
78372
  }
78373
+ if (bail && coverage && result.message) {
78374
+ result.message = `${result.message} (coverage may be incomplete: bail=true stopped early)`;
78375
+ }
78322
78376
  return JSON.stringify(result, null, 2);
78323
78377
  }
78324
78378
  });
@@ -78523,7 +78577,7 @@ async function runLintCheck(dir, linter, timeoutMs) {
78523
78577
  async function runTestsCheck(_dir, scope, timeoutMs) {
78524
78578
  const startTime = Date.now();
78525
78579
  try {
78526
- const result = await runTests("none", scope, [], false, timeoutMs, _dir);
78580
+ const result = await runTests("none", scope, [], false, timeoutMs, _dir, false);
78527
78581
  if (!result.success) {
78528
78582
  return {
78529
78583
  type: "tests",
@@ -91315,7 +91369,7 @@ async function scanDocIndex(directory) {
91315
91369
  const resolvedDirectory = await realpath3(directory).catch(() => directory);
91316
91370
  const discoveredFiles = [];
91317
91371
  let rootReadable = false;
91318
- const walkDir = async (dir) => {
91372
+ const walkDir2 = async (dir) => {
91319
91373
  let entries;
91320
91374
  try {
91321
91375
  entries = await readdir6(dir, { withFileTypes: true });
@@ -91343,8 +91397,8 @@ async function scanDocIndex(directory) {
91343
91397
  }
91344
91398
  }
91345
91399
  if (isDir) {
91346
- if (!SKIP_DIRECTORIES3.has(entry.name)) {
91347
- await walkDir(path94.join(dir, entry.name));
91400
+ if (!SKIP_DIRECTORIES4.has(entry.name)) {
91401
+ await walkDir2(path94.join(dir, entry.name));
91348
91402
  }
91349
91403
  continue;
91350
91404
  }
@@ -91386,7 +91440,7 @@ async function scanDocIndex(directory) {
91386
91440
  });
91387
91441
  }
91388
91442
  };
91389
- await walkDir(directory);
91443
+ await walkDir2(directory);
91390
91444
  if (!rootReadable) {
91391
91445
  return {
91392
91446
  manifest: {
@@ -91531,13 +91585,13 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
91531
91585
  }
91532
91586
  return { extracted: extractedCount, skipped: skippedCount, details };
91533
91587
  }
91534
- var SKIP_DIRECTORIES3, SKIP_PATTERNS, MAX_SUMMARY_LENGTH = 200, MAX_INDEXED_FILES = 100, READ_LINES_LIMIT = 30, MIN_LESSON_LENGTH = 15, MAX_CONSTRAINTS_PER_DOC = 5, MAX_CONSTRAINT_LENGTH = 200, RELEVANCE_THRESHOLD = 0.1, DEDUP_THRESHOLD = 0.6, CONSTRAINT_PATTERNS, ACTION_WORDS, doc_scan, doc_extract;
91588
+ var SKIP_DIRECTORIES4, SKIP_PATTERNS, MAX_SUMMARY_LENGTH = 200, MAX_INDEXED_FILES = 100, READ_LINES_LIMIT = 30, MIN_LESSON_LENGTH = 15, MAX_CONSTRAINTS_PER_DOC = 5, MAX_CONSTRAINT_LENGTH = 200, RELEVANCE_THRESHOLD = 0.1, DEDUP_THRESHOLD = 0.6, CONSTRAINT_PATTERNS, ACTION_WORDS, doc_scan, doc_extract;
91535
91589
  var init_doc_scan = __esm(() => {
91536
91590
  init_zod();
91537
91591
  init_schema();
91538
91592
  init_knowledge_store();
91539
91593
  init_create_tool();
91540
- SKIP_DIRECTORIES3 = new Set([
91594
+ SKIP_DIRECTORIES4 = new Set([
91541
91595
  "node_modules",
91542
91596
  ".git",
91543
91597
  ".swarm",
@@ -92391,11 +92445,11 @@ __export(exports_design_doc_drift, {
92391
92445
  runDesignDocDriftCheck: () => runDesignDocDriftCheck,
92392
92446
  _internals: () => _internals60
92393
92447
  });
92394
- import * as fs98 from "node:fs";
92395
- import * as path137 from "node:path";
92448
+ import * as fs99 from "node:fs";
92449
+ import * as path138 from "node:path";
92396
92450
  function mtimeMsOrNull(absPath) {
92397
92451
  try {
92398
- return fs98.statSync(absPath).mtimeMs;
92452
+ return fs99.statSync(absPath).mtimeMs;
92399
92453
  } catch {
92400
92454
  return null;
92401
92455
  }
@@ -92403,40 +92457,40 @@ function mtimeMsOrNull(absPath) {
92403
92457
  function resolveAnchorWithin(directory, anchor) {
92404
92458
  if (!anchor || typeof anchor !== "string")
92405
92459
  return null;
92406
- const root = path137.resolve(directory);
92407
- const resolved = path137.resolve(root, anchor);
92408
- const rel = path137.relative(root, resolved);
92409
- if (rel.startsWith("..") || path137.isAbsolute(rel))
92460
+ const root = path138.resolve(directory);
92461
+ const resolved = path138.resolve(root, anchor);
92462
+ const rel = path138.relative(root, resolved);
92463
+ if (rel.startsWith("..") || path138.isAbsolute(rel))
92410
92464
  return null;
92411
92465
  return resolved;
92412
92466
  }
92413
92467
  async function runDesignDocDriftCheck(directory, phase, outDir) {
92414
92468
  try {
92415
- const root = path137.resolve(directory);
92416
- const outAbs = path137.resolve(root, outDir);
92417
- const outRel = path137.relative(root, outAbs);
92418
- if (outRel.startsWith("..") || path137.isAbsolute(outRel)) {
92469
+ const root = path138.resolve(directory);
92470
+ const outAbs = path138.resolve(root, outDir);
92471
+ const outRel = path138.relative(root, outAbs);
92472
+ if (outRel.startsWith("..") || path138.isAbsolute(outRel)) {
92419
92473
  return null;
92420
92474
  }
92421
92475
  const docMtimes = new Map;
92422
92476
  const checkedDocs = [];
92423
92477
  const missingDocs = [];
92424
92478
  for (const [docName, relFile] of Object.entries(DESIGN_DOC_FILES)) {
92425
- const abs = path137.join(outAbs, relFile);
92479
+ const abs = path138.join(outAbs, relFile);
92426
92480
  const mtime = mtimeMsOrNull(abs);
92427
92481
  docMtimes.set(docName, mtime);
92428
92482
  if (mtime === null) {
92429
- missingDocs.push(path137.join(outDir, relFile));
92483
+ missingDocs.push(path138.join(outDir, relFile));
92430
92484
  } else {
92431
- checkedDocs.push(path137.join(outDir, relFile));
92485
+ checkedDocs.push(path138.join(outDir, relFile));
92432
92486
  }
92433
92487
  }
92434
- const traceabilityAbs = path137.join(outAbs, TRACEABILITY_REL);
92488
+ const traceabilityAbs = path138.join(outAbs, TRACEABILITY_REL);
92435
92489
  let registry3 = null;
92436
92490
  try {
92437
- const stat9 = await fs98.promises.stat(traceabilityAbs);
92491
+ const stat9 = await fs99.promises.stat(traceabilityAbs);
92438
92492
  if (stat9.size <= MAX_TRACEABILITY_BYTES) {
92439
- const raw = await fs98.promises.readFile(traceabilityAbs, "utf-8");
92493
+ const raw = await fs99.promises.readFile(traceabilityAbs, "utf-8");
92440
92494
  const parsed = JSON.parse(raw);
92441
92495
  registry3 = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
92442
92496
  }
@@ -92444,7 +92498,7 @@ async function runDesignDocDriftCheck(directory, phase, outDir) {
92444
92498
  registry3 = null;
92445
92499
  }
92446
92500
  const noDocs = checkedDocs.length === 0 || registry3 === null;
92447
- const specMtime = mtimeMsOrNull(path137.join(root, ".swarm", "spec.md"));
92501
+ const specMtime = mtimeMsOrNull(path138.join(root, ".swarm", "spec.md"));
92448
92502
  const staleSections = [];
92449
92503
  if (!noDocs && Array.isArray(registry3?.sections)) {
92450
92504
  for (const section of registry3.sections) {
@@ -92500,8 +92554,8 @@ async function runDesignDocDriftCheck(directory, phase, outDir) {
92500
92554
  };
92501
92555
  const filename = `${DOC_DRIFT_REPORT_PREFIX}${phase}.json`;
92502
92556
  const filePath = validateSwarmPath(directory, filename);
92503
- await fs98.promises.mkdir(path137.dirname(filePath), { recursive: true });
92504
- await fs98.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
92557
+ await fs99.promises.mkdir(path138.dirname(filePath), { recursive: true });
92558
+ await fs99.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
92505
92559
  getGlobalEventBus().publish("curator.docdrift.completed", {
92506
92560
  phase,
92507
92561
  verdict,
@@ -92531,10 +92585,10 @@ var init_design_doc_drift = __esm(() => {
92531
92585
  domain: "domain.md",
92532
92586
  "technical-spec": "technical-spec.md",
92533
92587
  "behavior-spec": "behavior-spec.md",
92534
- "reference-impl": path137.join("reference", "reference-impl.md"),
92535
- "idiom-notes": path137.join("reference", "idiom-notes.md")
92588
+ "reference-impl": path138.join("reference", "reference-impl.md"),
92589
+ "idiom-notes": path138.join("reference", "idiom-notes.md")
92536
92590
  };
92537
- TRACEABILITY_REL = path137.join("reference", "traceability.json");
92591
+ TRACEABILITY_REL = path138.join("reference", "traceability.json");
92538
92592
  _internals60 = {
92539
92593
  mtimeMsOrNull,
92540
92594
  resolveAnchorWithin,
@@ -92549,12 +92603,12 @@ __export(exports_project_context, {
92549
92603
  _internals: () => _internals71,
92550
92604
  LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
92551
92605
  });
92552
- import * as fs122 from "node:fs";
92553
- import * as path166 from "node:path";
92606
+ import * as fs123 from "node:fs";
92607
+ import * as path167 from "node:path";
92554
92608
  function detectFileExists2(directory, pattern) {
92555
92609
  if (pattern.includes("*") || pattern.includes("?")) {
92556
92610
  try {
92557
- const files = fs122.readdirSync(directory);
92611
+ const files = fs123.readdirSync(directory);
92558
92612
  const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
92559
92613
  return files.some((f) => regex.test(f));
92560
92614
  } catch {
@@ -92562,7 +92616,7 @@ function detectFileExists2(directory, pattern) {
92562
92616
  }
92563
92617
  }
92564
92618
  try {
92565
- fs122.accessSync(path166.join(directory, pattern));
92619
+ fs123.accessSync(path167.join(directory, pattern));
92566
92620
  return true;
92567
92621
  } catch {
92568
92622
  return false;
@@ -92571,7 +92625,7 @@ function detectFileExists2(directory, pattern) {
92571
92625
  function selectTestCommandFromScriptsTest(backend, directory) {
92572
92626
  let pkgRaw;
92573
92627
  try {
92574
- pkgRaw = fs122.readFileSync(path166.join(directory, "package.json"), "utf-8");
92628
+ pkgRaw = fs123.readFileSync(path167.join(directory, "package.json"), "utf-8");
92575
92629
  } catch {
92576
92630
  return null;
92577
92631
  }
@@ -92680,7 +92734,7 @@ var init_project_context = __esm(() => {
92680
92734
  init_package();
92681
92735
  init_agents2();
92682
92736
  init_critic();
92683
- import * as path167 from "node:path";
92737
+ import * as path168 from "node:path";
92684
92738
 
92685
92739
  // src/background/index.ts
92686
92740
  init_event_bus();
@@ -95444,7 +95498,29 @@ init_path_security();
95444
95498
  import * as fs49 from "node:fs";
95445
95499
  import * as path79 from "node:path";
95446
95500
  var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
95501
+ var MAX_WORKSPACE_RESULTS = 50;
95502
+ var MAX_WORKSPACE_SCANNED_FILES = 200;
95503
+ var WORKSPACE_TIMEOUT_MS = 1e4;
95447
95504
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
95505
+ var SYMBOL_EXTENSIONS = new Set([
95506
+ ".ts",
95507
+ ".tsx",
95508
+ ".js",
95509
+ ".jsx",
95510
+ ".mjs",
95511
+ ".cjs",
95512
+ ".py"
95513
+ ]);
95514
+ var SKIP_DIRECTORIES2 = new Set([
95515
+ "node_modules",
95516
+ ".git",
95517
+ "dist",
95518
+ "build",
95519
+ "out",
95520
+ ".next",
95521
+ "coverage",
95522
+ "__pycache__"
95523
+ ]);
95448
95524
  function containsWindowsAttacks(str) {
95449
95525
  if (/:[^\\/]/.test(str)) {
95450
95526
  return true;
@@ -95689,28 +95765,135 @@ function extractPythonSymbols(filePath, cwd) {
95689
95765
  return a.name.localeCompare(b.name);
95690
95766
  });
95691
95767
  }
95768
+ function findSourceFiles(cwd, maxFiles) {
95769
+ const files = [];
95770
+ walkDir(cwd, cwd, files, maxFiles);
95771
+ return files;
95772
+ }
95773
+ function walkDir(currentDir, rootDir, files, maxFiles) {
95774
+ let entries;
95775
+ try {
95776
+ entries = fs49.readdirSync(currentDir, { withFileTypes: true });
95777
+ } catch {
95778
+ return;
95779
+ }
95780
+ entries.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
95781
+ for (const entry of entries) {
95782
+ if (files.length >= maxFiles)
95783
+ return;
95784
+ if (SKIP_DIRECTORIES2.has(entry.name))
95785
+ continue;
95786
+ const fullPath = path79.join(currentDir, entry.name);
95787
+ if (entry.isDirectory()) {
95788
+ walkDir(fullPath, rootDir, files, maxFiles);
95789
+ } else if (entry.isFile() && SYMBOL_EXTENSIONS.has(path79.extname(entry.name).toLowerCase())) {
95790
+ files.push(path79.relative(rootDir, fullPath));
95791
+ }
95792
+ }
95793
+ }
95794
+ function searchWorkspaceSymbols(cwd, name2, exportedOnly = true) {
95795
+ const startTime = Date.now();
95796
+ const sourceFiles = findSourceFiles(cwd, MAX_WORKSPACE_SCANNED_FILES);
95797
+ const files = [];
95798
+ let scannedCount = 0;
95799
+ let truncated = false;
95800
+ if (sourceFiles.length >= MAX_WORKSPACE_SCANNED_FILES) {
95801
+ truncated = true;
95802
+ }
95803
+ let totalSymbols = 0;
95804
+ for (const relFile of sourceFiles) {
95805
+ if (Date.now() - startTime > WORKSPACE_TIMEOUT_MS) {
95806
+ truncated = true;
95807
+ break;
95808
+ }
95809
+ scannedCount++;
95810
+ let syms;
95811
+ const ext = path79.extname(relFile).toLowerCase();
95812
+ switch (ext) {
95813
+ case ".ts":
95814
+ case ".tsx":
95815
+ case ".js":
95816
+ case ".jsx":
95817
+ case ".mjs":
95818
+ case ".cjs":
95819
+ syms = extractTSSymbols(relFile, cwd);
95820
+ break;
95821
+ case ".py":
95822
+ syms = extractPythonSymbols(relFile, cwd);
95823
+ break;
95824
+ default:
95825
+ continue;
95826
+ }
95827
+ if (exportedOnly) {
95828
+ syms = syms.filter((s) => s.exported);
95829
+ }
95830
+ if (name2) {
95831
+ syms = syms.filter((s) => s.name.includes(name2));
95832
+ }
95833
+ if (syms.length > 0) {
95834
+ const remaining = MAX_WORKSPACE_RESULTS - totalSymbols;
95835
+ if (remaining <= 0) {
95836
+ truncated = true;
95837
+ break;
95838
+ }
95839
+ const cappedSyms = syms.slice(0, remaining);
95840
+ files.push({
95841
+ file: relFile,
95842
+ symbolCount: cappedSyms.length,
95843
+ symbols: cappedSyms
95844
+ });
95845
+ totalSymbols += cappedSyms.length;
95846
+ if (totalSymbols >= MAX_WORKSPACE_RESULTS) {
95847
+ truncated = syms.length > remaining || scannedCount < sourceFiles.length;
95848
+ break;
95849
+ }
95850
+ }
95851
+ }
95852
+ return {
95853
+ query: { workspace: true, name: name2 },
95854
+ fileCount: files.length,
95855
+ scannedFileCount: scannedCount,
95856
+ totalSymbols,
95857
+ files,
95858
+ truncated
95859
+ };
95860
+ }
95692
95861
  var symbols = createSwarmTool({
95693
95862
  description: "Extract all exported symbols from a source file: functions with signatures, " + "classes with public members, interfaces, types, enums, constants. " + "Supports TypeScript/JavaScript and Python. Use for architect planning, " + "designer scaffolding, and understanding module public API surface.",
95694
95863
  args: {
95695
- file: exports_external.string().describe('File path to extract symbols from (e.g., "src/auth/login.ts")'),
95696
- exported_only: exports_external.boolean().default(true).describe("If true, only return exported/public symbols. If false, include all top-level symbols.")
95864
+ file: exports_external.string().optional().describe('File path to extract symbols from (e.g., "src/auth/login.ts"). Required when not using workspace mode.'),
95865
+ exported_only: exports_external.boolean().default(true).describe("If true, only return exported/public symbols. If false, include all top-level symbols."),
95866
+ workspace: exports_external.boolean().optional().describe("When true, search across the workspace instead of a single file. Returns per-file symbol summaries."),
95867
+ name: exports_external.string().optional().describe("Search for symbols by name (case-sensitive substring match). When provided without workspace, only searches the specified file.")
95697
95868
  },
95698
95869
  execute: async (args2, directory) => {
95699
95870
  let file3;
95700
95871
  let exportedOnly = true;
95872
+ let workspace = false;
95873
+ let name2;
95701
95874
  try {
95702
95875
  const obj = args2;
95703
- file3 = String(obj.file);
95876
+ file3 = obj.file != null && typeof obj.file === "string" ? obj.file : undefined;
95704
95877
  exportedOnly = obj.exported_only === true;
95878
+ workspace = obj.workspace === true;
95879
+ name2 = obj.name != null && typeof obj.name === "string" ? obj.name : undefined;
95705
95880
  } catch {
95706
95881
  return JSON.stringify({
95707
95882
  file: "<unknown>",
95708
- error: "Invalid arguments: could not extract file path",
95883
+ error: "Invalid arguments: could not extract parameters",
95709
95884
  symbols: []
95710
95885
  }, null, 2);
95711
95886
  }
95712
95887
  const cwd = directory;
95713
- const ext = path79.extname(file3);
95888
+ if (workspace) {
95889
+ return JSON.stringify(searchWorkspaceSymbols(cwd, name2, exportedOnly), null, 2);
95890
+ }
95891
+ if (!file3) {
95892
+ return JSON.stringify({
95893
+ error: "file parameter is required when not using workspace mode",
95894
+ symbols: []
95895
+ }, null, 2);
95896
+ }
95714
95897
  if (containsControlChars(file3)) {
95715
95898
  return JSON.stringify({
95716
95899
  file: file3,
@@ -95739,6 +95922,7 @@ var symbols = createSwarmTool({
95739
95922
  symbols: []
95740
95923
  }, null, 2);
95741
95924
  }
95925
+ const ext = path79.extname(file3);
95742
95926
  let syms;
95743
95927
  switch (ext) {
95744
95928
  case ".ts":
@@ -95762,6 +95946,9 @@ var symbols = createSwarmTool({
95762
95946
  if (exportedOnly) {
95763
95947
  syms = syms.filter((s) => s.exported);
95764
95948
  }
95949
+ if (name2) {
95950
+ syms = syms.filter((s) => s.name.includes(name2));
95951
+ }
95765
95952
  return JSON.stringify({
95766
95953
  file: file3,
95767
95954
  symbolCount: syms.length,
@@ -95910,7 +96097,7 @@ var _internals43 = {
95910
96097
  extractPythonSymbols,
95911
96098
  parseFileImports
95912
96099
  };
95913
- var SKIP_DIRECTORIES2 = new Set([
96100
+ var SKIP_DIRECTORIES3 = new Set([
95914
96101
  "node_modules",
95915
96102
  ".git",
95916
96103
  "dist",
@@ -96143,7 +96330,7 @@ async function findSourceFilesAsync(dir, stats, options) {
96143
96330
  if (isWalkBudgetExceeded(ctx) || isFileCapReached(ctx, files.length)) {
96144
96331
  break;
96145
96332
  }
96146
- if (SKIP_DIRECTORIES2.has(entry.name)) {
96333
+ if (SKIP_DIRECTORIES3.has(entry.name)) {
96147
96334
  ctx.stats.skippedDirs++;
96148
96335
  continue;
96149
96336
  }
@@ -98147,7 +98334,7 @@ var DEFAULT_SKIP_DIRS = new Set([
98147
98334
  var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
98148
98335
  var DEFAULT_MAX_FILES = 1e4;
98149
98336
  var SOURCE_EXT_SET = new Set(SOURCE_EXTENSIONS2);
98150
- function findSourceFiles(workspaceRoot, skipDirs = DEFAULT_SKIP_DIRS) {
98337
+ function findSourceFiles2(workspaceRoot, skipDirs = DEFAULT_SKIP_DIRS) {
98151
98338
  const out2 = [];
98152
98339
  const stack = [workspaceRoot];
98153
98340
  while (stack.length > 0) {
@@ -98184,7 +98371,7 @@ function findSourceFiles(workspaceRoot, skipDirs = DEFAULT_SKIP_DIRS) {
98184
98371
  }
98185
98372
  async function buildRepoGraph(workspaceRoot, options = {}) {
98186
98373
  const skipDirs = options.skipDirs ? new Set([...DEFAULT_SKIP_DIRS, ...options.skipDirs]) : DEFAULT_SKIP_DIRS;
98187
- let files = findSourceFiles(workspaceRoot, skipDirs);
98374
+ let files = findSourceFiles2(workspaceRoot, skipDirs);
98188
98375
  const cap = typeof options.maxFiles === "number" && options.maxFiles > 0 ? options.maxFiles : DEFAULT_MAX_FILES;
98189
98376
  if (files.length > cap) {
98190
98377
  files = files.slice(0, cap);
@@ -108666,6 +108853,7 @@ ${body2}`);
108666
108853
  }
108667
108854
 
108668
108855
  // src/council/council-evidence-writer.ts
108856
+ init_zod();
108669
108857
  init_task_file();
108670
108858
  import { appendFileSync as appendFileSync12, existsSync as existsSync63, mkdirSync as mkdirSync29, readFileSync as readFileSync45 } from "node:fs";
108671
108859
  import { join as join95 } from "node:path";
@@ -108673,6 +108861,7 @@ var EVIDENCE_DIR2 = ".swarm/evidence";
108673
108861
  var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
108674
108862
  var COUNCIL_GATE_NAME = "council";
108675
108863
  var COUNCIL_AGENT_ID = "architect";
108864
+ var EvidenceFileSchema = exports_external.record(exports_external.string(), exports_external.unknown());
108676
108865
  var _internals53 = {
108677
108866
  withTaskEvidenceLock
108678
108867
  };
@@ -108712,10 +108901,8 @@ async function writeCouncilEvidence(workingDir, synthesis) {
108712
108901
  const existingRoot = Object.create(null);
108713
108902
  if (existsSync63(filePath)) {
108714
108903
  try {
108715
- const parsed = JSON.parse(readFileSync45(filePath, "utf-8"));
108716
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
108717
- safeAssignOwnProps(existingRoot, parsed);
108718
- }
108904
+ const parsed = EvidenceFileSchema.parse(JSON.parse(readFileSync45(filePath, "utf-8")));
108905
+ safeAssignOwnProps(existingRoot, parsed);
108719
108906
  } catch {}
108720
108907
  }
108721
108908
  const existingGatesRaw = existingRoot.gates;
@@ -109073,9 +109260,19 @@ function buildFinalCouncilFeedback(projectSummary, verdict, vetoedBy, requiredFi
109073
109260
  }
109074
109261
 
109075
109262
  // src/council/criteria-store.ts
109263
+ init_zod();
109076
109264
  import { existsSync as existsSync64, mkdirSync as mkdirSync30, readFileSync as readFileSync46, writeFileSync as writeFileSync22 } from "node:fs";
109077
109265
  import { join as join96 } from "node:path";
109078
109266
  var COUNCIL_DIR = ".swarm/council";
109267
+ var CouncilCriteriaSchema = exports_external.object({
109268
+ taskId: exports_external.string(),
109269
+ criteria: exports_external.array(exports_external.object({
109270
+ id: exports_external.string(),
109271
+ description: exports_external.string(),
109272
+ mandatory: exports_external.boolean()
109273
+ })),
109274
+ declaredAt: exports_external.string()
109275
+ });
109079
109276
  function writeCriteria(workingDir, taskId, criteria) {
109080
109277
  const dir = join96(workingDir, COUNCIL_DIR);
109081
109278
  mkdirSync30(dir, { recursive: true });
@@ -109091,11 +109288,7 @@ function readCriteria(workingDir, taskId) {
109091
109288
  if (!existsSync64(filePath))
109092
109289
  return null;
109093
109290
  try {
109094
- const parsed = JSON.parse(readFileSync46(filePath, "utf-8"));
109095
- if (parsed && typeof parsed === "object" && typeof parsed.taskId === "string" && Array.isArray(parsed.criteria)) {
109096
- return parsed;
109097
- }
109098
- return null;
109291
+ return CouncilCriteriaSchema.parse(JSON.parse(readFileSync46(filePath, "utf-8")));
109099
109292
  } catch {
109100
109293
  return null;
109101
109294
  }
@@ -110231,10 +110424,12 @@ var diff = createSwarmTool({
110231
110424
  description: "Analyze git diff for changed files, exports, interfaces, and function signatures. Returns structured output with contract change detection.",
110232
110425
  args: {
110233
110426
  base: exports_external.string().optional().describe('Base ref to diff against (default: HEAD). Use "staged" for staged changes, "unstaged" for working tree changes.'),
110234
- paths: exports_external.array(exports_external.string()).optional().describe("Optional file paths to restrict diff scope.")
110427
+ paths: exports_external.array(exports_external.string()).optional().describe("Optional file paths to restrict diff scope."),
110428
+ summaryOnly: exports_external.boolean().optional().describe("When true, return only file list with additions/deletions counts and hasContractChanges. No hunk content or AST diff. Default false.")
110235
110429
  },
110236
110430
  async execute(args2, directory, _ctx) {
110237
110431
  const typedArgs = args2;
110432
+ const summaryOnly = typedArgs.summaryOnly === true;
110238
110433
  try {
110239
110434
  let fileExistsInRef = function(refPath) {
110240
110435
  try {
@@ -110312,13 +110507,6 @@ var diff = createSwarmTool({
110312
110507
  cwd: directory,
110313
110508
  stdio: ["ignore", "pipe", "pipe"]
110314
110509
  });
110315
- const fullDiffOutput = child_process7.execFileSync("git", fullDiffArgs, {
110316
- encoding: "utf-8",
110317
- timeout: DIFF_TIMEOUT_MS,
110318
- maxBuffer: MAX_BUFFER_BYTES,
110319
- cwd: directory,
110320
- stdio: ["ignore", "pipe", "pipe"]
110321
- });
110322
110510
  const files = [];
110323
110511
  const numstatLines = numstatOutput.split(`
110324
110512
  `);
@@ -110333,6 +110521,50 @@ var diff = createSwarmTool({
110333
110521
  files.push({ path: path118, additions, deletions });
110334
110522
  }
110335
110523
  }
110524
+ if (summaryOnly) {
110525
+ let hasContractChanges2 = false;
110526
+ try {
110527
+ const contractDiffArgs = [...gitArgs, "-U0"];
110528
+ if (typedArgs.paths?.length) {
110529
+ contractDiffArgs.push("--", ...typedArgs.paths);
110530
+ }
110531
+ const contractDiffOutput = child_process7.execFileSync("git", contractDiffArgs, {
110532
+ encoding: "utf-8",
110533
+ timeout: DIFF_TIMEOUT_MS,
110534
+ maxBuffer: MAX_BUFFER_BYTES,
110535
+ cwd: directory,
110536
+ stdio: ["ignore", "pipe", "pipe"]
110537
+ });
110538
+ const contractDiffLines = contractDiffOutput.split(`
110539
+ `);
110540
+ for (const line of contractDiffLines) {
110541
+ for (const pattern of CONTRACT_PATTERNS) {
110542
+ if (pattern.test(line)) {
110543
+ hasContractChanges2 = true;
110544
+ break;
110545
+ }
110546
+ }
110547
+ if (hasContractChanges2)
110548
+ break;
110549
+ }
110550
+ } catch {
110551
+ hasContractChanges2 = true;
110552
+ }
110553
+ const result2 = {
110554
+ files,
110555
+ contractChanges: [],
110556
+ hasContractChanges: hasContractChanges2,
110557
+ summary: `${files.length} files changed (summary only)`
110558
+ };
110559
+ return JSON.stringify(result2, null, 2);
110560
+ }
110561
+ const fullDiffOutput = child_process7.execFileSync("git", fullDiffArgs, {
110562
+ encoding: "utf-8",
110563
+ timeout: DIFF_TIMEOUT_MS,
110564
+ maxBuffer: MAX_BUFFER_BYTES,
110565
+ cwd: directory,
110566
+ stdio: ["ignore", "pipe", "pipe"]
110567
+ });
110336
110568
  const contractChanges = [];
110337
110569
  const diffLines = fullDiffOutput.split(`
110338
110570
  `);
@@ -111398,13 +111630,389 @@ var get_qa_gate_profile = createSwarmTool({
111398
111630
  }
111399
111631
  });
111400
111632
 
111633
+ // src/tools/git-blame.ts
111634
+ init_zod();
111635
+ init_path_security();
111636
+ init_create_tool();
111637
+ import * as child_process9 from "node:child_process";
111638
+ import * as fs83 from "node:fs";
111639
+ import * as path121 from "node:path";
111640
+ var BLAME_TIMEOUT_MS = 30000;
111641
+ var MAX_OUTPUT_LINES2 = 500;
111642
+ var MAX_PATH_LENGTH2 = 500;
111643
+ var MAX_LINE_NUMBER = 1e6;
111644
+ var SHELL_METACHARACTERS3 = /[;|&$`(){}<>!'"]/;
111645
+ var BINARY_EXTENSIONS = new Set([
111646
+ ".png",
111647
+ ".jpg",
111648
+ ".jpeg",
111649
+ ".gif",
111650
+ ".bmp",
111651
+ ".ico",
111652
+ ".svg",
111653
+ ".webp",
111654
+ ".mp3",
111655
+ ".mp4",
111656
+ ".wav",
111657
+ ".avi",
111658
+ ".mov",
111659
+ ".wmv",
111660
+ ".flv",
111661
+ ".zip",
111662
+ ".tar",
111663
+ ".gz",
111664
+ ".rar",
111665
+ ".7z",
111666
+ ".bz2",
111667
+ ".pdf",
111668
+ ".doc",
111669
+ ".docx",
111670
+ ".xls",
111671
+ ".xlsx",
111672
+ ".ppt",
111673
+ ".pptx",
111674
+ ".exe",
111675
+ ".dll",
111676
+ ".so",
111677
+ ".dylib",
111678
+ ".bin",
111679
+ ".dat",
111680
+ ".o",
111681
+ ".obj",
111682
+ ".woff",
111683
+ ".woff2",
111684
+ ".ttf",
111685
+ ".eot",
111686
+ ".otf",
111687
+ ".sqlite",
111688
+ ".db"
111689
+ ]);
111690
+ function validateFilePath(filePath) {
111691
+ if (!filePath || filePath.length === 0) {
111692
+ return "file path is required";
111693
+ }
111694
+ if (filePath.length > MAX_PATH_LENGTH2) {
111695
+ return `file path exceeds maximum length of ${MAX_PATH_LENGTH2}`;
111696
+ }
111697
+ if (path121.isAbsolute(filePath)) {
111698
+ return "absolute paths are not allowed; use a relative path from the project root";
111699
+ }
111700
+ if (containsPathTraversal(filePath)) {
111701
+ return "path traversal detected";
111702
+ }
111703
+ if (containsControlChars(filePath)) {
111704
+ return "file path contains control characters";
111705
+ }
111706
+ if (SHELL_METACHARACTERS3.test(filePath)) {
111707
+ return "file path contains shell metacharacters";
111708
+ }
111709
+ if (filePath.startsWith("-")) {
111710
+ return 'file path cannot start with "-"';
111711
+ }
111712
+ return null;
111713
+ }
111714
+ function validateLineNumber(value, name2) {
111715
+ if (typeof value === "undefined")
111716
+ return null;
111717
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
111718
+ return `${name2} must be a positive integer`;
111719
+ }
111720
+ if (value > MAX_LINE_NUMBER) {
111721
+ return `${name2} exceeds maximum value of ${MAX_LINE_NUMBER}`;
111722
+ }
111723
+ return null;
111724
+ }
111725
+ function isBinaryFile2(filePath) {
111726
+ const ext = path121.extname(filePath).toLowerCase();
111727
+ return BINARY_EXTENSIONS.has(ext);
111728
+ }
111729
+ function parsePorcelainBlame(output, linesCap) {
111730
+ const entries = [];
111731
+ const outputLines = output.split(`
111732
+ `);
111733
+ const cappedLines = outputLines.slice(0, linesCap * 8);
111734
+ const commitCache = new Map;
111735
+ let currentSha = "";
111736
+ let currentLine = 0;
111737
+ let currentAuthor = "";
111738
+ let currentAuthorTime = "";
111739
+ let currentSummary = "";
111740
+ for (const rawLine of cappedLines) {
111741
+ const headerMatch = rawLine.match(/^([0-9a-f]{40})\s+(\d+)\s+(\d+)/);
111742
+ if (headerMatch) {
111743
+ currentSha = headerMatch[1];
111744
+ currentLine = Number.parseInt(headerMatch[3], 10);
111745
+ const cached3 = commitCache.get(currentSha);
111746
+ if (cached3) {
111747
+ currentAuthor = cached3.author;
111748
+ currentAuthorTime = cached3.authorTime;
111749
+ currentSummary = cached3.summary;
111750
+ } else {
111751
+ currentAuthor = "";
111752
+ currentAuthorTime = "";
111753
+ currentSummary = "";
111754
+ }
111755
+ continue;
111756
+ }
111757
+ if (rawLine.startsWith("author ")) {
111758
+ currentAuthor = rawLine.slice(7);
111759
+ let meta3 = commitCache.get(currentSha);
111760
+ if (!meta3) {
111761
+ meta3 = { author: "", authorTime: "", summary: "" };
111762
+ commitCache.set(currentSha, meta3);
111763
+ }
111764
+ meta3.author = currentAuthor;
111765
+ continue;
111766
+ }
111767
+ if (rawLine.startsWith("author-time ")) {
111768
+ currentAuthorTime = rawLine.slice(12);
111769
+ let meta3 = commitCache.get(currentSha);
111770
+ if (!meta3) {
111771
+ meta3 = { author: "", authorTime: "", summary: "" };
111772
+ commitCache.set(currentSha, meta3);
111773
+ }
111774
+ meta3.authorTime = currentAuthorTime;
111775
+ continue;
111776
+ }
111777
+ if (rawLine.startsWith("summary ")) {
111778
+ currentSummary = rawLine.slice(8);
111779
+ let meta3 = commitCache.get(currentSha);
111780
+ if (!meta3) {
111781
+ meta3 = { author: "", authorTime: "", summary: "" };
111782
+ commitCache.set(currentSha, meta3);
111783
+ }
111784
+ meta3.summary = currentSummary;
111785
+ continue;
111786
+ }
111787
+ if (rawLine.startsWith("\t")) {
111788
+ entries.push({
111789
+ line: currentLine,
111790
+ sha: currentSha.slice(0, 8),
111791
+ author: currentAuthor,
111792
+ authorTime: currentAuthorTime,
111793
+ summary: currentSummary,
111794
+ content: rawLine.slice(1)
111795
+ });
111796
+ if (entries.length >= linesCap)
111797
+ break;
111798
+ }
111799
+ }
111800
+ return entries.slice(0, linesCap);
111801
+ }
111802
+ var git_blame = createSwarmTool({
111803
+ description: "Analyze per-line git blame metadata for a file. Returns sha (abbreviated), author, date (ISO), summary, and content for each line. Uses git blame --porcelain. Rejects binary files and validates paths.",
111804
+ args: {
111805
+ file: exports_external.string().describe("Relative file path to blame (required, relative to project root)"),
111806
+ start: exports_external.number().optional().describe("Optional start line number (1-indexed). Requires end parameter."),
111807
+ end: exports_external.number().optional().describe("Optional end line number (1-indexed, inclusive). Requires start parameter.")
111808
+ },
111809
+ async execute(args2, directory) {
111810
+ let fileInput;
111811
+ let startInput;
111812
+ let endInput;
111813
+ try {
111814
+ if (args2 && typeof args2 === "object") {
111815
+ const obj = args2;
111816
+ fileInput = typeof obj.file === "string" ? obj.file : undefined;
111817
+ startInput = typeof obj.start === "number" ? obj.start : undefined;
111818
+ endInput = typeof obj.end === "number" ? obj.end : undefined;
111819
+ }
111820
+ } catch {}
111821
+ if (!fileInput) {
111822
+ return JSON.stringify({
111823
+ error: "file path is required",
111824
+ file: String(fileInput ?? ""),
111825
+ lineCount: 0,
111826
+ lines: []
111827
+ });
111828
+ }
111829
+ const file3 = fileInput;
111830
+ const pathError = validateFilePath(file3);
111831
+ if (pathError) {
111832
+ return JSON.stringify({
111833
+ error: pathError,
111834
+ file: file3,
111835
+ lineCount: 0,
111836
+ lines: []
111837
+ });
111838
+ }
111839
+ const startError = validateLineNumber(startInput, "start");
111840
+ if (startError) {
111841
+ return JSON.stringify({
111842
+ error: startError,
111843
+ file: file3,
111844
+ lineCount: 0,
111845
+ lines: []
111846
+ });
111847
+ }
111848
+ const endError = validateLineNumber(endInput, "end");
111849
+ if (endError) {
111850
+ return JSON.stringify({
111851
+ error: endError,
111852
+ file: file3,
111853
+ lineCount: 0,
111854
+ lines: []
111855
+ });
111856
+ }
111857
+ if (startInput !== undefined && endInput === undefined || startInput === undefined && endInput !== undefined) {
111858
+ return JSON.stringify({
111859
+ error: "both start and end must be provided together for a line range",
111860
+ file: file3,
111861
+ lineCount: 0,
111862
+ lines: []
111863
+ });
111864
+ }
111865
+ if (startInput !== undefined && endInput !== undefined && startInput > endInput) {
111866
+ return JSON.stringify({
111867
+ error: "start must be less than or equal to end",
111868
+ file: file3,
111869
+ lineCount: 0,
111870
+ lines: []
111871
+ });
111872
+ }
111873
+ const resolvedPath = path121.resolve(directory, file3);
111874
+ if (!fs83.existsSync(resolvedPath)) {
111875
+ return JSON.stringify({
111876
+ error: `file not found: ${file3}`,
111877
+ file: file3,
111878
+ lineCount: 0,
111879
+ lines: []
111880
+ });
111881
+ }
111882
+ const realDir = fs83.realpathSync(directory);
111883
+ const realPath = fs83.realpathSync(resolvedPath);
111884
+ const relative25 = path121.relative(realDir, realPath);
111885
+ if (relative25.startsWith("..") || path121.isAbsolute(relative25)) {
111886
+ return JSON.stringify({
111887
+ error: "file path resolves outside the workspace",
111888
+ file: file3,
111889
+ lineCount: 0,
111890
+ lines: []
111891
+ });
111892
+ }
111893
+ const stat9 = fs83.statSync(resolvedPath);
111894
+ if (stat9.isDirectory()) {
111895
+ return JSON.stringify({
111896
+ error: "path is a directory, not a file",
111897
+ file: file3,
111898
+ lineCount: 0,
111899
+ lines: []
111900
+ });
111901
+ }
111902
+ if (isBinaryFile2(file3)) {
111903
+ return JSON.stringify({
111904
+ error: "binary files are not supported for git blame",
111905
+ file: file3,
111906
+ lineCount: 0,
111907
+ lines: []
111908
+ });
111909
+ }
111910
+ const gitArgs = ["blame", "--porcelain"];
111911
+ if (startInput !== undefined && endInput !== undefined) {
111912
+ gitArgs.push("-L", `${startInput},${endInput}`);
111913
+ }
111914
+ gitArgs.push("--", file3);
111915
+ const result = child_process9.spawnSync("git", gitArgs, {
111916
+ cwd: directory,
111917
+ encoding: "utf-8",
111918
+ timeout: BLAME_TIMEOUT_MS,
111919
+ windowsHide: true,
111920
+ maxBuffer: 5 * 1024 * 1024,
111921
+ stdio: ["ignore", "pipe", "pipe"]
111922
+ });
111923
+ if (result.error) {
111924
+ const isTimeout = "code" in result.error && result.error.code === "ETIMEDOUT";
111925
+ if (isTimeout) {
111926
+ return JSON.stringify({
111927
+ error: "git blame timed out",
111928
+ file: file3,
111929
+ lineCount: 0,
111930
+ lines: []
111931
+ });
111932
+ }
111933
+ const message = result.error instanceof Error ? result.error.message : String(result.error);
111934
+ if (message.includes("ENOENT") || message.includes("not found")) {
111935
+ return JSON.stringify({
111936
+ error: "git is not available or not in PATH",
111937
+ file: file3,
111938
+ lineCount: 0,
111939
+ lines: []
111940
+ });
111941
+ }
111942
+ return JSON.stringify({
111943
+ error: `git execution failed: ${message}`,
111944
+ file: file3,
111945
+ lineCount: 0,
111946
+ lines: []
111947
+ });
111948
+ }
111949
+ if (result.status !== 0) {
111950
+ const stderr = (result.stderr ?? "").trim();
111951
+ if (stderr.includes("not a git repository") || stderr.includes("not in a git repository")) {
111952
+ return JSON.stringify({
111953
+ error: "not a git repository",
111954
+ file: file3,
111955
+ lineCount: 0,
111956
+ lines: []
111957
+ });
111958
+ }
111959
+ if (stderr.includes("no such path") || stderr.includes("did not match any files")) {
111960
+ return JSON.stringify({
111961
+ error: `file not tracked by git: ${file3}`,
111962
+ file: file3,
111963
+ lineCount: 0,
111964
+ lines: []
111965
+ });
111966
+ }
111967
+ return JSON.stringify({
111968
+ error: `git blame failed: ${stderr || `exit code ${result.status}`}`,
111969
+ file: file3,
111970
+ lineCount: 0,
111971
+ lines: []
111972
+ });
111973
+ }
111974
+ if (result.signal === "SIGTERM" || result.signal === "SIGKILL") {
111975
+ return JSON.stringify({
111976
+ error: "git blame timed out",
111977
+ file: file3,
111978
+ lineCount: 0,
111979
+ lines: []
111980
+ });
111981
+ }
111982
+ const stdout = result.stdout ?? "";
111983
+ if (!stdout.trim()) {
111984
+ return JSON.stringify({
111985
+ error: "no blame output (file may be empty or untracked)",
111986
+ file: file3,
111987
+ lineCount: 0,
111988
+ lines: []
111989
+ });
111990
+ }
111991
+ const rawEntries = parsePorcelainBlame(stdout, MAX_OUTPUT_LINES2);
111992
+ const lines = rawEntries.map((entry) => ({
111993
+ line: entry.line,
111994
+ sha: entry.sha,
111995
+ author: entry.author,
111996
+ date: Number.parseInt(entry.authorTime, 10) > 0 ? new Date(Number.parseInt(entry.authorTime, 10) * 1000).toISOString().slice(0, 10) : entry.authorTime,
111997
+ summary: entry.summary,
111998
+ content: entry.content
111999
+ }));
112000
+ const resultJson = {
112001
+ file: file3,
112002
+ lineCount: lines.length,
112003
+ lines
112004
+ };
112005
+ return JSON.stringify(resultJson, null, 2);
112006
+ }
112007
+ });
112008
+
111401
112009
  // src/tools/gitingest.ts
111402
112010
  init_zod();
111403
112011
  init_create_tool();
111404
112012
  var GITINGEST_TIMEOUT_MS = 1e4;
111405
112013
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
111406
112014
  var GITINGEST_MAX_RETRIES = 2;
111407
- var delay = (ms) => new Promise((resolve43) => setTimeout(resolve43, ms));
112015
+ var delay = (ms) => new Promise((resolve44) => setTimeout(resolve44, ms));
111408
112016
  async function fetchGitingest(args2) {
111409
112017
  for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
111410
112018
  try {
@@ -111492,8 +112100,8 @@ var gitingest = createSwarmTool({
111492
112100
  init_zod();
111493
112101
  init_create_tool();
111494
112102
  init_path_security();
111495
- import * as fs83 from "node:fs";
111496
- import * as path121 from "node:path";
112103
+ import * as fs84 from "node:fs";
112104
+ import * as path122 from "node:path";
111497
112105
  var MAX_FILE_PATH_LENGTH2 = 500;
111498
112106
  var MAX_SYMBOL_LENGTH = 256;
111499
112107
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
@@ -111540,8 +112148,8 @@ function validateSymbolInput(symbol3) {
111540
112148
  }
111541
112149
  return null;
111542
112150
  }
111543
- function isBinaryFile2(filePath, buffer) {
111544
- const ext = path121.extname(filePath).toLowerCase();
112151
+ function isBinaryFile3(filePath, buffer) {
112152
+ const ext = path122.extname(filePath).toLowerCase();
111545
112153
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
111546
112154
  return false;
111547
112155
  }
@@ -111565,15 +112173,15 @@ function parseImports(content, targetFile, targetSymbol) {
111565
112173
  const imports = [];
111566
112174
  let _resolvedTarget;
111567
112175
  try {
111568
- _resolvedTarget = path121.resolve(targetFile);
112176
+ _resolvedTarget = path122.resolve(targetFile);
111569
112177
  } catch {
111570
112178
  _resolvedTarget = targetFile;
111571
112179
  }
111572
- const targetBasename = path121.basename(targetFile, path121.extname(targetFile));
112180
+ const targetBasename = path122.basename(targetFile, path122.extname(targetFile));
111573
112181
  const targetWithExt = targetFile;
111574
112182
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
111575
- const normalizedTargetWithExt = path121.normalize(targetWithExt).replace(/\\/g, "/");
111576
- const normalizedTargetWithoutExt = path121.normalize(targetWithoutExt).replace(/\\/g, "/");
112183
+ const normalizedTargetWithExt = path122.normalize(targetWithExt).replace(/\\/g, "/");
112184
+ const normalizedTargetWithoutExt = path122.normalize(targetWithoutExt).replace(/\\/g, "/");
111577
112185
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
111578
112186
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
111579
112187
  const modulePath = match[1] || match[2] || match[3];
@@ -111596,9 +112204,9 @@ function parseImports(content, targetFile, targetSymbol) {
111596
112204
  }
111597
112205
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
111598
112206
  let isMatch = false;
111599
- const _targetDir = path121.dirname(targetFile);
111600
- const targetExt = path121.extname(targetFile);
111601
- const targetBasenameNoExt = path121.basename(targetFile, targetExt);
112207
+ const _targetDir = path122.dirname(targetFile);
112208
+ const targetExt = path122.extname(targetFile);
112209
+ const targetBasenameNoExt = path122.basename(targetFile, targetExt);
111602
112210
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
111603
112211
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
111604
112212
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -111638,7 +112246,7 @@ function parseImports(content, targetFile, targetSymbol) {
111638
112246
  }
111639
112247
  return imports;
111640
112248
  }
111641
- var SKIP_DIRECTORIES4 = new Set([
112249
+ var SKIP_DIRECTORIES5 = new Set([
111642
112250
  "node_modules",
111643
112251
  ".git",
111644
112252
  "dist",
@@ -111652,10 +112260,10 @@ var SKIP_DIRECTORIES4 = new Set([
111652
112260
  ".svn",
111653
112261
  ".hg"
111654
112262
  ]);
111655
- function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
112263
+ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
111656
112264
  let entries;
111657
112265
  try {
111658
- entries = fs83.readdirSync(dir);
112266
+ entries = fs84.readdirSync(dir);
111659
112267
  } catch (e) {
111660
112268
  stats.fileErrors.push({
111661
112269
  path: dir,
@@ -111665,14 +112273,14 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
111665
112273
  }
111666
112274
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
111667
112275
  for (const entry of entries) {
111668
- if (SKIP_DIRECTORIES4.has(entry)) {
111669
- stats.skippedDirs.push(path121.join(dir, entry));
112276
+ if (SKIP_DIRECTORIES5.has(entry)) {
112277
+ stats.skippedDirs.push(path122.join(dir, entry));
111670
112278
  continue;
111671
112279
  }
111672
- const fullPath = path121.join(dir, entry);
112280
+ const fullPath = path122.join(dir, entry);
111673
112281
  let stat9;
111674
112282
  try {
111675
- stat9 = fs83.statSync(fullPath);
112283
+ stat9 = fs84.statSync(fullPath);
111676
112284
  } catch (e) {
111677
112285
  stats.fileErrors.push({
111678
112286
  path: fullPath,
@@ -111681,9 +112289,9 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
111681
112289
  continue;
111682
112290
  }
111683
112291
  if (stat9.isDirectory()) {
111684
- findSourceFiles2(fullPath, files, stats);
112292
+ findSourceFiles3(fullPath, files, stats);
111685
112293
  } else if (stat9.isFile()) {
111686
- const ext = path121.extname(fullPath).toLowerCase();
112294
+ const ext = path122.extname(fullPath).toLowerCase();
111687
112295
  if (SUPPORTED_EXTENSIONS3.includes(ext)) {
111688
112296
  files.push(fullPath);
111689
112297
  }
@@ -111740,8 +112348,8 @@ var imports = createSwarmTool({
111740
112348
  return JSON.stringify(errorResult, null, 2);
111741
112349
  }
111742
112350
  try {
111743
- const targetFile = path121.resolve(file3);
111744
- if (!fs83.existsSync(targetFile)) {
112351
+ const targetFile = path122.resolve(file3);
112352
+ if (!fs84.existsSync(targetFile)) {
111745
112353
  const errorResult = {
111746
112354
  error: `target file not found: ${file3}`,
111747
112355
  target: file3,
@@ -111751,7 +112359,7 @@ var imports = createSwarmTool({
111751
112359
  };
111752
112360
  return JSON.stringify(errorResult, null, 2);
111753
112361
  }
111754
- const targetStat = fs83.statSync(targetFile);
112362
+ const targetStat = fs84.statSync(targetFile);
111755
112363
  if (!targetStat.isFile()) {
111756
112364
  const errorResult = {
111757
112365
  error: "target must be a file, not a directory",
@@ -111762,13 +112370,13 @@ var imports = createSwarmTool({
111762
112370
  };
111763
112371
  return JSON.stringify(errorResult, null, 2);
111764
112372
  }
111765
- const baseDir = path121.dirname(targetFile);
112373
+ const baseDir = path122.dirname(targetFile);
111766
112374
  const scanStats = {
111767
112375
  skippedDirs: [],
111768
112376
  skippedFiles: 0,
111769
112377
  fileErrors: []
111770
112378
  };
111771
- const sourceFiles = findSourceFiles2(baseDir, [], scanStats);
112379
+ const sourceFiles = findSourceFiles3(baseDir, [], scanStats);
111772
112380
  const filesToScan = sourceFiles.filter((f) => f !== targetFile).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).slice(0, MAX_CONSUMERS * 10);
111773
112381
  const consumers = [];
111774
112382
  let skippedFileCount = 0;
@@ -111777,13 +112385,13 @@ var imports = createSwarmTool({
111777
112385
  if (consumers.length >= MAX_CONSUMERS)
111778
112386
  break;
111779
112387
  try {
111780
- const stat9 = fs83.statSync(filePath);
112388
+ const stat9 = fs84.statSync(filePath);
111781
112389
  if (stat9.size > MAX_FILE_SIZE_BYTES7) {
111782
112390
  skippedFileCount++;
111783
112391
  continue;
111784
112392
  }
111785
- const buffer = fs83.readFileSync(filePath);
111786
- if (isBinaryFile2(filePath, buffer)) {
112393
+ const buffer = fs84.readFileSync(filePath);
112394
+ if (isBinaryFile3(filePath, buffer)) {
111787
112395
  skippedFileCount++;
111788
112396
  continue;
111789
112397
  }
@@ -112150,7 +112758,7 @@ init_zod();
112150
112758
  init_config();
112151
112759
  init_knowledge_store();
112152
112760
  init_create_tool();
112153
- import { existsSync as existsSync69 } from "node:fs";
112761
+ import { existsSync as existsSync70 } from "node:fs";
112154
112762
  var DEFAULT_LIMIT = 10;
112155
112763
  var MAX_LESSON_LENGTH = 200;
112156
112764
  var VALID_CATEGORIES3 = [
@@ -112226,14 +112834,14 @@ function validateLimit(limit) {
112226
112834
  }
112227
112835
  async function readSwarmKnowledge(directory) {
112228
112836
  const swarmPath = resolveSwarmKnowledgePath(directory);
112229
- if (!existsSync69(swarmPath)) {
112837
+ if (!existsSync70(swarmPath)) {
112230
112838
  return [];
112231
112839
  }
112232
112840
  return readKnowledge(swarmPath);
112233
112841
  }
112234
112842
  async function readHiveKnowledge() {
112235
112843
  const hivePath = resolveHiveKnowledgePath();
112236
- if (!existsSync69(hivePath)) {
112844
+ if (!existsSync70(hivePath)) {
112237
112845
  return [];
112238
112846
  }
112239
112847
  return readKnowledge(hivePath);
@@ -112658,12 +113266,12 @@ var lean_turbo_acquire_locks = createSwarmTool({
112658
113266
  // src/tools/lean-turbo-plan-lanes.ts
112659
113267
  init_zod();
112660
113268
  init_constants();
112661
- import * as fs85 from "node:fs";
112662
- import * as path123 from "node:path";
113269
+ import * as fs86 from "node:fs";
113270
+ import * as path124 from "node:path";
112663
113271
 
112664
113272
  // src/turbo/lean/conflicts.ts
112665
- import * as fs84 from "node:fs";
112666
- import * as path122 from "node:path";
113273
+ import * as fs85 from "node:fs";
113274
+ import * as path123 from "node:path";
112667
113275
  var DEFAULT_GLOBAL_FILES = [
112668
113276
  "package.json",
112669
113277
  "package-lock.json",
@@ -112790,12 +113398,12 @@ function isProtectedPath3(normalizedPath) {
112790
113398
  return false;
112791
113399
  }
112792
113400
  function readTaskScopes(directory, taskId) {
112793
- const scopePath = path122.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
113401
+ const scopePath = path123.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
112794
113402
  try {
112795
- if (!fs84.existsSync(scopePath)) {
113403
+ if (!fs85.existsSync(scopePath)) {
112796
113404
  return null;
112797
113405
  }
112798
- const raw = fs84.readFileSync(scopePath, "utf-8");
113406
+ const raw = fs85.readFileSync(scopePath, "utf-8");
112799
113407
  const parsed = JSON.parse(raw);
112800
113408
  if (!parsed || !Array.isArray(parsed.files)) {
112801
113409
  return null;
@@ -113178,12 +113786,12 @@ function createEmptyPlan(phaseNumber, planId) {
113178
113786
  // src/tools/lean-turbo-plan-lanes.ts
113179
113787
  init_create_tool();
113180
113788
  function readPlanJson(directory) {
113181
- const planPath = path123.join(directory, ".swarm", "plan.json");
113182
- if (!fs85.existsSync(planPath)) {
113789
+ const planPath = path124.join(directory, ".swarm", "plan.json");
113790
+ if (!fs86.existsSync(planPath)) {
113183
113791
  return null;
113184
113792
  }
113185
113793
  try {
113186
- return JSON.parse(fs85.readFileSync(planPath, "utf-8"));
113794
+ return JSON.parse(fs86.readFileSync(planPath, "utf-8"));
113187
113795
  } catch {
113188
113796
  return null;
113189
113797
  }
@@ -113233,16 +113841,16 @@ init_config();
113233
113841
 
113234
113842
  // src/turbo/lean/reviewer.ts
113235
113843
  init_state();
113236
- import * as fs87 from "node:fs/promises";
113237
- import * as path125 from "node:path";
113844
+ import * as fs88 from "node:fs/promises";
113845
+ import * as path126 from "node:path";
113238
113846
 
113239
113847
  // src/turbo/lean/evidence.ts
113240
113848
  init_bun_compat();
113241
113849
  import { rmSync as rmSync6 } from "node:fs";
113242
- import * as fs86 from "node:fs/promises";
113243
- import * as path124 from "node:path";
113850
+ import * as fs87 from "node:fs/promises";
113851
+ import * as path125 from "node:path";
113244
113852
  function leanTurboEvidenceDir(directory, phase) {
113245
- return path124.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
113853
+ return path125.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
113246
113854
  }
113247
113855
  function validateLaneId(laneId) {
113248
113856
  if (laneId.length === 0) {
@@ -113264,21 +113872,21 @@ function validateLaneId(laneId) {
113264
113872
  function laneEvidencePath(directory, phase, laneId) {
113265
113873
  validateLaneId(laneId);
113266
113874
  const expectedDir = leanTurboEvidenceDir(directory, phase);
113267
- const resolvedPath = path124.resolve(path124.join(expectedDir, `${laneId}.json`));
113268
- const resolvedDir = path124.resolve(expectedDir);
113269
- if (!resolvedPath.startsWith(resolvedDir + path124.sep) && resolvedPath !== resolvedDir) {
113875
+ const resolvedPath = path125.resolve(path125.join(expectedDir, `${laneId}.json`));
113876
+ const resolvedDir = path125.resolve(expectedDir);
113877
+ if (!resolvedPath.startsWith(resolvedDir + path125.sep) && resolvedPath !== resolvedDir) {
113270
113878
  throw new Error(`Invalid laneId: path traversal detected (got "${laneId}")`);
113271
113879
  }
113272
113880
  return resolvedPath;
113273
113881
  }
113274
113882
  async function atomicWriteJson(filePath, data) {
113275
113883
  const content = JSON.stringify(data, null, 2);
113276
- const dir = path124.dirname(filePath);
113277
- await fs86.mkdir(dir, { recursive: true });
113884
+ const dir = path125.dirname(filePath);
113885
+ await fs87.mkdir(dir, { recursive: true });
113278
113886
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
113279
113887
  try {
113280
113888
  await bunWrite(tempPath, content);
113281
- await fs86.rename(tempPath, filePath);
113889
+ await fs87.rename(tempPath, filePath);
113282
113890
  } catch (error93) {
113283
113891
  try {
113284
113892
  rmSync6(tempPath, { force: true });
@@ -113287,7 +113895,7 @@ async function atomicWriteJson(filePath, data) {
113287
113895
  }
113288
113896
  }
113289
113897
  function phaseEvidencePath(directory, phase) {
113290
- return path124.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
113898
+ return path125.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
113291
113899
  }
113292
113900
  async function writeLaneEvidence(directory, phase, evidence) {
113293
113901
  const targetPath = laneEvidencePath(directory, phase, evidence.laneId);
@@ -113297,7 +113905,7 @@ async function readPhaseEvidence(directory, phase) {
113297
113905
  const targetPath = phaseEvidencePath(directory, phase);
113298
113906
  let content;
113299
113907
  try {
113300
- content = await fs86.readFile(targetPath, "utf-8");
113908
+ content = await fs87.readFile(targetPath, "utf-8");
113301
113909
  } catch (error93) {
113302
113910
  const code = error93.code;
113303
113911
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -113315,7 +113923,7 @@ async function listLaneEvidence(directory, phase) {
113315
113923
  const evidenceDir = leanTurboEvidenceDir(directory, phase);
113316
113924
  let entries;
113317
113925
  try {
113318
- entries = await fs86.readdir(evidenceDir);
113926
+ entries = await fs87.readdir(evidenceDir);
113319
113927
  } catch (error93) {
113320
113928
  const code = error93.code;
113321
113929
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -113331,10 +113939,10 @@ async function listLaneEvidence(directory, phase) {
113331
113939
  if (entry === "lean-turbo-phase.json") {
113332
113940
  continue;
113333
113941
  }
113334
- const filePath = path124.join(evidenceDir, entry);
113942
+ const filePath = path125.join(evidenceDir, entry);
113335
113943
  let content;
113336
113944
  try {
113337
- content = await fs86.readFile(filePath, "utf-8");
113945
+ content = await fs87.readFile(filePath, "utf-8");
113338
113946
  } catch {
113339
113947
  continue;
113340
113948
  }
@@ -113462,9 +114070,9 @@ function parseReviewerVerdict(responseText) {
113462
114070
  return { verdict, reason };
113463
114071
  }
113464
114072
  async function writeReviewerEvidence(directory, phase, verdict, reason) {
113465
- const evidenceDir = path125.join(directory, ".swarm", "evidence", String(phase));
113466
- await fs87.mkdir(evidenceDir, { recursive: true });
113467
- const evidencePath = path125.join(evidenceDir, "lean-turbo-reviewer.json");
114073
+ const evidenceDir = path126.join(directory, ".swarm", "evidence", String(phase));
114074
+ await fs88.mkdir(evidenceDir, { recursive: true });
114075
+ const evidencePath = path126.join(evidenceDir, "lean-turbo-reviewer.json");
113468
114076
  const content = JSON.stringify({
113469
114077
  phase,
113470
114078
  verdict,
@@ -113473,11 +114081,11 @@ async function writeReviewerEvidence(directory, phase, verdict, reason) {
113473
114081
  }, null, 2);
113474
114082
  const tempPath = `${evidencePath}.tmp.${process.pid}.${Date.now()}`;
113475
114083
  try {
113476
- await fs87.writeFile(tempPath, content, "utf-8");
113477
- await fs87.rename(tempPath, evidencePath);
114084
+ await fs88.writeFile(tempPath, content, "utf-8");
114085
+ await fs88.rename(tempPath, evidencePath);
113478
114086
  } catch (error93) {
113479
114087
  try {
113480
- await fs87.unlink(tempPath);
114088
+ await fs88.unlink(tempPath);
113481
114089
  } catch {}
113482
114090
  throw error93;
113483
114091
  }
@@ -114275,8 +114883,8 @@ init_lint();
114275
114883
  // src/tools/lint-spec.ts
114276
114884
  init_spec_schema();
114277
114885
  init_create_tool();
114278
- import * as fs88 from "node:fs";
114279
- import * as path126 from "node:path";
114886
+ import * as fs89 from "node:fs";
114887
+ import * as path127 from "node:path";
114280
114888
  var SPEC_FILE_NAME = "spec.md";
114281
114889
  var SWARM_DIR2 = ".swarm";
114282
114890
  var OBLIGATION_KEYWORDS = ["MUST", "SHALL", "SHOULD", "MAY"];
@@ -114329,8 +114937,8 @@ var lint_spec = createSwarmTool({
114329
114937
  async execute(_args, directory) {
114330
114938
  const errors5 = [];
114331
114939
  const warnings = [];
114332
- const specPath = path126.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
114333
- if (!fs88.existsSync(specPath)) {
114940
+ const specPath = path127.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
114941
+ if (!fs89.existsSync(specPath)) {
114334
114942
  const result2 = {
114335
114943
  valid: false,
114336
114944
  specMtime: null,
@@ -114349,12 +114957,12 @@ var lint_spec = createSwarmTool({
114349
114957
  }
114350
114958
  let specMtime = null;
114351
114959
  try {
114352
- const stats = fs88.statSync(specPath);
114960
+ const stats = fs89.statSync(specPath);
114353
114961
  specMtime = stats.mtime.toISOString();
114354
114962
  } catch {}
114355
114963
  let content;
114356
114964
  try {
114357
- content = fs88.readFileSync(specPath, "utf-8");
114965
+ content = fs89.readFileSync(specPath, "utf-8");
114358
114966
  } catch (e) {
114359
114967
  const result2 = {
114360
114968
  valid: false,
@@ -114400,13 +115008,13 @@ var lint_spec = createSwarmTool({
114400
115008
 
114401
115009
  // src/tools/mutation-test.ts
114402
115010
  init_zod();
114403
- import * as fs89 from "node:fs";
114404
- import * as path128 from "node:path";
115011
+ import * as fs90 from "node:fs";
115012
+ import * as path129 from "node:path";
114405
115013
 
114406
115014
  // src/mutation/engine.ts
114407
- import { spawnSync as spawnSync8 } from "node:child_process";
115015
+ import { spawnSync as spawnSync9 } from "node:child_process";
114408
115016
  import { unlinkSync as unlinkSync18, writeFileSync as writeFileSync24 } from "node:fs";
114409
- import * as path127 from "node:path";
115017
+ import * as path128 from "node:path";
114410
115018
 
114411
115019
  // src/mutation/equivalence.ts
114412
115020
  function isStaticallyEquivalent(originalCode, mutatedCode) {
@@ -114541,7 +115149,7 @@ var _internals57 = {
114541
115149
  executeMutation,
114542
115150
  computeReport,
114543
115151
  executeMutationSuite,
114544
- spawnSync: spawnSync8
115152
+ spawnSync: spawnSync9
114545
115153
  };
114546
115154
  async function executeMutation(patch, testCommand, _testFiles, workingDir) {
114547
115155
  const startTime = Date.now();
@@ -114552,7 +115160,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
114552
115160
  let patchFile;
114553
115161
  try {
114554
115162
  const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
114555
- patchFile = path127.join(workingDir, `.mutation_patch_${safeId2}.diff`);
115163
+ patchFile = path128.join(workingDir, `.mutation_patch_${safeId2}.diff`);
114556
115164
  try {
114557
115165
  writeFileSync24(patchFile, patch.patch);
114558
115166
  } catch (writeErr) {
@@ -114956,8 +115564,8 @@ var mutation_test = createSwarmTool({
114956
115564
  ];
114957
115565
  for (const filePath of uniquePaths) {
114958
115566
  try {
114959
- const resolvedPath = path128.resolve(cwd, filePath);
114960
- sourceFiles.set(filePath, fs89.readFileSync(resolvedPath, "utf-8"));
115567
+ const resolvedPath = path129.resolve(cwd, filePath);
115568
+ sourceFiles.set(filePath, fs90.readFileSync(resolvedPath, "utf-8"));
114961
115569
  } catch {}
114962
115570
  }
114963
115571
  const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
@@ -114977,30 +115585,30 @@ init_zod();
114977
115585
  init_config();
114978
115586
  init_schema();
114979
115587
  init_manager2();
114980
- import * as fs99 from "node:fs";
114981
- import * as path138 from "node:path";
115588
+ import * as fs100 from "node:fs";
115589
+ import * as path139 from "node:path";
114982
115590
 
114983
115591
  // src/full-auto/phase-approval.ts
114984
115592
  init_utils2();
114985
115593
  init_logger();
114986
115594
  init_state2();
114987
- import * as fs90 from "node:fs";
114988
- import * as path129 from "node:path";
115595
+ import * as fs91 from "node:fs";
115596
+ import * as path130 from "node:path";
114989
115597
  var APPROVAL_TTL_MS = 24 * 60 * 60 * 1000;
114990
115598
  function readEvidenceDir(directory, phase) {
114991
115599
  try {
114992
- const dirPath = validateSwarmPath(directory, path129.posix.join("evidence", String(phase)));
114993
- if (!fs90.existsSync(dirPath))
115600
+ const dirPath = validateSwarmPath(directory, path130.posix.join("evidence", String(phase)));
115601
+ if (!fs91.existsSync(dirPath))
114994
115602
  return [];
114995
- const entries = fs90.readdirSync(dirPath);
114996
- return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path129.join(dirPath, e));
115603
+ const entries = fs91.readdirSync(dirPath);
115604
+ return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path130.join(dirPath, e));
114997
115605
  } catch {
114998
115606
  return [];
114999
115607
  }
115000
115608
  }
115001
115609
  function parseEvidence(filePath) {
115002
115610
  try {
115003
- const raw = fs90.readFileSync(filePath, "utf-8");
115611
+ const raw = fs91.readFileSync(filePath, "utf-8");
115004
115612
  const parsed = JSON.parse(raw);
115005
115613
  return parsed;
115006
115614
  } catch (error93) {
@@ -115089,9 +115697,9 @@ function verifyFullAutoPhaseApproval(directory, sessionID, phase, config3) {
115089
115697
  function phaseIsExplicitlyNonCode(directory, phase) {
115090
115698
  try {
115091
115699
  const planPath = validateSwarmPath(directory, "plan.json");
115092
- if (!fs90.existsSync(planPath))
115700
+ if (!fs91.existsSync(planPath))
115093
115701
  return false;
115094
- const raw = fs90.readFileSync(planPath, "utf-8");
115702
+ const raw = fs91.readFileSync(planPath, "utf-8");
115095
115703
  const plan = JSON.parse(raw);
115096
115704
  const phases = Array.isArray(plan.phases) ? plan.phases : [];
115097
115705
  const entry = phases.find((p) => p.id === phase || p.phase === phase);
@@ -115133,20 +115741,20 @@ init_file_locks();
115133
115741
  init_plan_schema();
115134
115742
  init_ledger();
115135
115743
  init_manager();
115136
- import * as fs91 from "node:fs";
115137
- import * as path130 from "node:path";
115744
+ import * as fs92 from "node:fs";
115745
+ import * as path131 from "node:path";
115138
115746
  async function writeCheckpoint(directory) {
115139
115747
  try {
115140
115748
  const plan = await loadPlan(directory);
115141
115749
  if (!plan)
115142
115750
  return;
115143
- const swarmDir = path130.join(directory, ".swarm");
115144
- fs91.mkdirSync(swarmDir, { recursive: true });
115145
- const jsonPath = path130.join(swarmDir, "SWARM_PLAN.json");
115146
- const mdPath = path130.join(swarmDir, "SWARM_PLAN.md");
115147
- fs91.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
115751
+ const swarmDir = path131.join(directory, ".swarm");
115752
+ fs92.mkdirSync(swarmDir, { recursive: true });
115753
+ const jsonPath = path131.join(swarmDir, "SWARM_PLAN.json");
115754
+ const mdPath = path131.join(swarmDir, "SWARM_PLAN.md");
115755
+ fs92.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
115148
115756
  const md = derivePlanMarkdown(plan);
115149
- fs91.writeFileSync(mdPath, md, "utf8");
115757
+ fs92.writeFileSync(mdPath, md, "utf8");
115150
115758
  } catch (error93) {
115151
115759
  console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
115152
115760
  }
@@ -115161,8 +115769,8 @@ init_telemetry();
115161
115769
 
115162
115770
  // src/turbo/lean/phase-ready.ts
115163
115771
  init_file_locks();
115164
- import * as fs92 from "node:fs";
115165
- import * as path131 from "node:path";
115772
+ import * as fs93 from "node:fs";
115773
+ import * as path132 from "node:path";
115166
115774
  init_state3();
115167
115775
  var DEFAULT_CONFIG3 = {
115168
115776
  phase_reviewer: true,
@@ -115171,10 +115779,10 @@ var DEFAULT_CONFIG3 = {
115171
115779
  };
115172
115780
  function defaultReadPlanJson(dir) {
115173
115781
  try {
115174
- const planPath = path131.join(dir, ".swarm", "plan.json");
115175
- if (!fs92.existsSync(planPath))
115782
+ const planPath = path132.join(dir, ".swarm", "plan.json");
115783
+ if (!fs93.existsSync(planPath))
115176
115784
  return null;
115177
- const raw = fs92.readFileSync(planPath, "utf-8");
115785
+ const raw = fs93.readFileSync(planPath, "utf-8");
115178
115786
  const plan = JSON.parse(raw);
115179
115787
  if (typeof plan !== "object" || plan === null || !Array.isArray(plan.phases)) {
115180
115788
  return null;
@@ -115186,11 +115794,11 @@ function defaultReadPlanJson(dir) {
115186
115794
  }
115187
115795
  function readReviewerEvidenceFromFile(directory, phase) {
115188
115796
  try {
115189
- const evidencePath = path131.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
115190
- if (!fs92.existsSync(evidencePath)) {
115797
+ const evidencePath = path132.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
115798
+ if (!fs93.existsSync(evidencePath)) {
115191
115799
  return null;
115192
115800
  }
115193
- const raw = fs92.readFileSync(evidencePath, "utf-8");
115801
+ const raw = fs93.readFileSync(evidencePath, "utf-8");
115194
115802
  const parsed = JSON.parse(raw);
115195
115803
  if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
115196
115804
  return null;
@@ -115206,11 +115814,11 @@ function readReviewerEvidenceFromFile(directory, phase) {
115206
115814
  }
115207
115815
  function readCriticEvidenceFromFile(directory, phase) {
115208
115816
  try {
115209
- const evidencePath = path131.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
115210
- if (!fs92.existsSync(evidencePath)) {
115817
+ const evidencePath = path132.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
115818
+ if (!fs93.existsSync(evidencePath)) {
115211
115819
  return null;
115212
115820
  }
115213
- const raw = fs92.readFileSync(evidencePath, "utf-8");
115821
+ const raw = fs93.readFileSync(evidencePath, "utf-8");
115214
115822
  const parsed = JSON.parse(raw);
115215
115823
  if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
115216
115824
  return null;
@@ -115225,10 +115833,10 @@ function readCriticEvidenceFromFile(directory, phase) {
115225
115833
  }
115226
115834
  }
115227
115835
  function listLaneEvidenceSync(directory, phase) {
115228
- const evidenceDir = path131.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
115836
+ const evidenceDir = path132.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
115229
115837
  let entries;
115230
115838
  try {
115231
- entries = fs92.readdirSync(evidenceDir);
115839
+ entries = fs93.readdirSync(evidenceDir);
115232
115840
  } catch {
115233
115841
  return [];
115234
115842
  }
@@ -115295,8 +115903,8 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
115295
115903
  ...DEFAULT_CONFIG3,
115296
115904
  ...actualConfig
115297
115905
  };
115298
- const statePath = path131.join(directory, ".swarm", "turbo-state.json");
115299
- if (!fs92.existsSync(statePath)) {
115906
+ const statePath = path132.join(directory, ".swarm", "turbo-state.json");
115907
+ if (!fs93.existsSync(statePath)) {
115300
115908
  return {
115301
115909
  ok: false,
115302
115910
  reason: "Lean Turbo state unreadable or missing"
@@ -115483,10 +116091,10 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
115483
116091
  }
115484
116092
  }
115485
116093
  if (mergedConfig.integrated_diff_required) {
115486
- const evidencePath = path131.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
116094
+ const evidencePath = path132.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
115487
116095
  let hasDiff = false;
115488
116096
  try {
115489
- const content = fs92.readFileSync(evidencePath, "utf-8");
116097
+ const content = fs93.readFileSync(evidencePath, "utf-8");
115490
116098
  const evidence = JSON.parse(content);
115491
116099
  hasDiff = !!evidence.integratedDiffSummary;
115492
116100
  } catch {}
@@ -115634,15 +116242,15 @@ async function runCompletionVerifyGate(ctx) {
115634
116242
  init_qa_gate_profile();
115635
116243
  init_manager();
115636
116244
  init_state();
115637
- import * as fs93 from "node:fs";
115638
- import * as path132 from "node:path";
116245
+ import * as fs94 from "node:fs";
116246
+ import * as path133 from "node:path";
115639
116247
  async function runDriftGate(ctx) {
115640
116248
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
115641
116249
  let driftCheckEnabled = true;
115642
116250
  let driftHasSpecMd = false;
115643
116251
  try {
115644
- const specMdPath = path132.join(dir, ".swarm", "spec.md");
115645
- driftHasSpecMd = fs93.existsSync(specMdPath);
116252
+ const specMdPath = path133.join(dir, ".swarm", "spec.md");
116253
+ driftHasSpecMd = fs94.existsSync(specMdPath);
115646
116254
  const gatePlan = await loadPlan(dir);
115647
116255
  if (gatePlan) {
115648
116256
  const gatePlanId = derivePlanId(gatePlan);
@@ -115669,9 +116277,9 @@ async function runDriftGate(ctx) {
115669
116277
  }
115670
116278
  let phaseType;
115671
116279
  try {
115672
- const planPath = path132.join(dir, ".swarm", "plan.json");
115673
- if (fs93.existsSync(planPath)) {
115674
- const planRaw = fs93.readFileSync(planPath, "utf-8");
116280
+ const planPath = path133.join(dir, ".swarm", "plan.json");
116281
+ if (fs94.existsSync(planPath)) {
116282
+ const planRaw = fs94.readFileSync(planPath, "utf-8");
115675
116283
  const plan = JSON.parse(planRaw);
115676
116284
  const targetPhase = plan.phases?.find((p) => p.id === phase);
115677
116285
  phaseType = targetPhase?.type;
@@ -115688,11 +116296,11 @@ async function runDriftGate(ctx) {
115688
116296
  };
115689
116297
  }
115690
116298
  try {
115691
- const driftEvidencePath = path132.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
116299
+ const driftEvidencePath = path133.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
115692
116300
  let driftVerdictFound = false;
115693
116301
  let driftVerdictApproved = false;
115694
116302
  try {
115695
- const driftEvidenceContent = fs93.readFileSync(driftEvidencePath, "utf-8");
116303
+ const driftEvidenceContent = fs94.readFileSync(driftEvidencePath, "utf-8");
115696
116304
  const driftEvidence = JSON.parse(driftEvidenceContent);
115697
116305
  const entries = driftEvidence.entries ?? [];
115698
116306
  for (const entry of entries) {
@@ -115724,9 +116332,9 @@ async function runDriftGate(ctx) {
115724
116332
  let incompleteTaskCount = 0;
115725
116333
  let planParseable = false;
115726
116334
  try {
115727
- const planPath = path132.join(dir, ".swarm", "plan.json");
115728
- if (fs93.existsSync(planPath)) {
115729
- const planRaw = fs93.readFileSync(planPath, "utf-8");
116335
+ const planPath = path133.join(dir, ".swarm", "plan.json");
116336
+ if (fs94.existsSync(planPath)) {
116337
+ const planRaw = fs94.readFileSync(planPath, "utf-8");
115730
116338
  const plan = JSON.parse(planRaw);
115731
116339
  planParseable = true;
115732
116340
  const planPhase = plan.phases?.find((p) => p.id === phase);
@@ -115805,8 +116413,8 @@ async function runDriftGate(ctx) {
115805
116413
  init_qa_gate_profile();
115806
116414
  init_manager();
115807
116415
  init_state();
115808
- import * as fs94 from "node:fs";
115809
- import * as path133 from "node:path";
116416
+ import * as fs95 from "node:fs";
116417
+ import * as path134 from "node:path";
115810
116418
  async function runFinalCouncilGate(ctx) {
115811
116419
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
115812
116420
  let finalCouncilEnabled = false;
@@ -115823,11 +116431,11 @@ async function runFinalCouncilGate(ctx) {
115823
116431
  const effective = getEffectiveGates(profile, overrides);
115824
116432
  if (effective.final_council === true) {
115825
116433
  finalCouncilEnabled = true;
115826
- const fcPath = path133.join(dir, ".swarm", "evidence", "final-council.json");
116434
+ const fcPath = path134.join(dir, ".swarm", "evidence", "final-council.json");
115827
116435
  let fcVerdictFound = false;
115828
116436
  let _fcVerdict;
115829
116437
  try {
115830
- const fcContent = fs94.readFileSync(fcPath, "utf-8");
116438
+ const fcContent = fs95.readFileSync(fcPath, "utf-8");
115831
116439
  const fcBundle = JSON.parse(fcContent);
115832
116440
  for (const entry of fcBundle.entries ?? []) {
115833
116441
  if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
@@ -115952,8 +116560,8 @@ async function runFinalCouncilGate(ctx) {
115952
116560
  init_qa_gate_profile();
115953
116561
  init_manager();
115954
116562
  init_state();
115955
- import * as fs95 from "node:fs";
115956
- import * as path134 from "node:path";
116563
+ import * as fs96 from "node:fs";
116564
+ import * as path135 from "node:path";
115957
116565
  async function runHallucinationGate(ctx) {
115958
116566
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
115959
116567
  try {
@@ -115966,11 +116574,11 @@ async function runHallucinationGate(ctx) {
115966
116574
  const overrides = session?.qaGateSessionOverrides ?? {};
115967
116575
  const effective = getEffectiveGates(profile, overrides);
115968
116576
  if (effective.hallucination_guard === true) {
115969
- const hgPath = path134.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
116577
+ const hgPath = path135.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
115970
116578
  let hgVerdictFound = false;
115971
116579
  let hgVerdictApproved = false;
115972
116580
  try {
115973
- const hgContent = fs95.readFileSync(hgPath, "utf-8");
116581
+ const hgContent = fs96.readFileSync(hgPath, "utf-8");
115974
116582
  const hgBundle = JSON.parse(hgContent);
115975
116583
  for (const entry of hgBundle.entries ?? []) {
115976
116584
  if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
@@ -116028,8 +116636,8 @@ async function runHallucinationGate(ctx) {
116028
116636
  init_qa_gate_profile();
116029
116637
  init_manager();
116030
116638
  init_state();
116031
- import * as fs96 from "node:fs";
116032
- import * as path135 from "node:path";
116639
+ import * as fs97 from "node:fs";
116640
+ import * as path136 from "node:path";
116033
116641
  async function runMutationGate(ctx) {
116034
116642
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
116035
116643
  try {
@@ -116042,11 +116650,11 @@ async function runMutationGate(ctx) {
116042
116650
  const overrides = session?.qaGateSessionOverrides ?? {};
116043
116651
  const effective = getEffectiveGates(profile, overrides);
116044
116652
  if (effective.mutation_test === true) {
116045
- const mgPath = path135.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
116653
+ const mgPath = path136.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
116046
116654
  let mgVerdictFound = false;
116047
116655
  let mgVerdict;
116048
116656
  try {
116049
- const mgContent = fs96.readFileSync(mgPath, "utf-8");
116657
+ const mgContent = fs97.readFileSync(mgPath, "utf-8");
116050
116658
  const mgBundle = JSON.parse(mgContent);
116051
116659
  for (const entry of mgBundle.entries ?? []) {
116052
116660
  if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
@@ -116104,8 +116712,8 @@ async function runMutationGate(ctx) {
116104
116712
  init_qa_gate_profile();
116105
116713
  init_manager();
116106
116714
  init_state();
116107
- import * as fs97 from "node:fs";
116108
- import * as path136 from "node:path";
116715
+ import * as fs98 from "node:fs";
116716
+ import * as path137 from "node:path";
116109
116717
  async function runPhaseCouncilGate(ctx) {
116110
116718
  const { phase, dir, sessionID, pluginConfig, agentsDispatched, safeWarn } = ctx;
116111
116719
  let councilModeEnabled = false;
@@ -116120,14 +116728,14 @@ async function runPhaseCouncilGate(ctx) {
116120
116728
  const effective = getEffectiveGates(profile, overrides);
116121
116729
  if (effective.council_mode === true) {
116122
116730
  councilModeEnabled = true;
116123
- const pcPath = path136.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
116731
+ const pcPath = path137.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
116124
116732
  let pcVerdictFound = false;
116125
116733
  let _pcVerdict;
116126
116734
  let pcQuorumSize;
116127
116735
  let pcTimestamp;
116128
116736
  let pcPhaseNumber;
116129
116737
  try {
116130
- const pcContent = fs97.readFileSync(pcPath, "utf-8");
116738
+ const pcContent = fs98.readFileSync(pcPath, "utf-8");
116131
116739
  const pcBundle = JSON.parse(pcContent);
116132
116740
  for (const entry of pcBundle.entries ?? []) {
116133
116741
  if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
@@ -116635,7 +117243,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116635
117243
  }
116636
117244
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
116637
117245
  try {
116638
- const projectName = path138.basename(dir);
117246
+ const projectName = path139.basename(dir);
116639
117247
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
116640
117248
  if (curationResult) {
116641
117249
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -116735,14 +117343,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116735
117343
  const markerPath = validateSwarmPath(dir, "skill-usage-last-processed.json");
116736
117344
  let sinceTimestamp;
116737
117345
  try {
116738
- const markerData = JSON.parse(fs99.readFileSync(markerPath, "utf-8"));
117346
+ const markerData = JSON.parse(fs100.readFileSync(markerPath, "utf-8"));
116739
117347
  sinceTimestamp = markerData.lastProcessedTimestamp;
116740
117348
  } catch {}
116741
117349
  const feedbackResult = await applySkillUsageFeedback(dir, {
116742
117350
  sinceTimestamp
116743
117351
  });
116744
117352
  try {
116745
- fs99.writeFileSync(markerPath, JSON.stringify({ lastProcessedTimestamp: new Date().toISOString() }), "utf-8");
117353
+ fs100.writeFileSync(markerPath, JSON.stringify({ lastProcessedTimestamp: new Date().toISOString() }), "utf-8");
116746
117354
  } catch {}
116747
117355
  if (feedbackResult.processed > 0) {
116748
117356
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -116762,7 +117370,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116762
117370
  let phaseRequiredAgents;
116763
117371
  try {
116764
117372
  const planPath = validateSwarmPath(dir, "plan.json");
116765
- const planRaw = fs99.readFileSync(planPath, "utf-8");
117373
+ const planRaw = fs100.readFileSync(planPath, "utf-8");
116766
117374
  const plan = JSON.parse(planRaw);
116767
117375
  const phaseObj = plan.phases.find((p) => p.id === phase);
116768
117376
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -116777,7 +117385,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116777
117385
  if (agentsMissing.length > 0) {
116778
117386
  try {
116779
117387
  const planPath = validateSwarmPath(dir, "plan.json");
116780
- const planRaw = fs99.readFileSync(planPath, "utf-8");
117388
+ const planRaw = fs100.readFileSync(planPath, "utf-8");
116781
117389
  const plan = JSON.parse(planRaw);
116782
117390
  const targetPhase = plan.phases.find((p) => p.id === phase);
116783
117391
  if (targetPhase && targetPhase.tasks.length > 0 && canInferMissingAgentsFromTaskGates(agentsMissing) && await allCompletedTasksHavePassedGateEvidence(dir, targetPhase.tasks)) {
@@ -116817,7 +117425,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116817
117425
  if (phaseCompleteConfig.regression_sweep?.enforce) {
116818
117426
  try {
116819
117427
  const planPath = validateSwarmPath(dir, "plan.json");
116820
- const planRaw = fs99.readFileSync(planPath, "utf-8");
117428
+ const planRaw = fs100.readFileSync(planPath, "utf-8");
116821
117429
  const plan = JSON.parse(planRaw);
116822
117430
  const targetPhase = plan.phases.find((p) => p.id === phase);
116823
117431
  if (targetPhase) {
@@ -116871,7 +117479,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116871
117479
  }
116872
117480
  try {
116873
117481
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
116874
- fs99.appendFileSync(eventsPath, `${JSON.stringify(event)}
117482
+ fs100.appendFileSync(eventsPath, `${JSON.stringify(event)}
116875
117483
  `, "utf-8");
116876
117484
  } catch (writeError) {
116877
117485
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -116946,12 +117554,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116946
117554
  warnings.push(`Warning: failed to update plan.json phase status`);
116947
117555
  try {
116948
117556
  const planPath = validateSwarmPath(dir, "plan.json");
116949
- const planRaw = fs99.readFileSync(planPath, "utf-8");
117557
+ const planRaw = fs100.readFileSync(planPath, "utf-8");
116950
117558
  const plan2 = JSON.parse(planRaw);
116951
117559
  const phaseObj = plan2.phases.find((p) => p.id === phase);
116952
117560
  if (phaseObj) {
116953
117561
  phaseObj.status = "complete";
116954
- fs99.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
117562
+ fs100.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
116955
117563
  }
116956
117564
  } catch {}
116957
117565
  } else if (plan) {
@@ -116988,12 +117596,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
116988
117596
  warnings.push(`Warning: failed to update plan.json phase status`);
116989
117597
  try {
116990
117598
  const planPath = validateSwarmPath(dir, "plan.json");
116991
- const planRaw = fs99.readFileSync(planPath, "utf-8");
117599
+ const planRaw = fs100.readFileSync(planPath, "utf-8");
116992
117600
  const plan = JSON.parse(planRaw);
116993
117601
  const phaseObj = plan.phases.find((p) => p.id === phase);
116994
117602
  if (phaseObj) {
116995
117603
  phaseObj.status = "complete";
116996
- fs99.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
117604
+ fs100.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
116997
117605
  }
116998
117606
  } catch {}
116999
117607
  }
@@ -117077,8 +117685,8 @@ init_discovery();
117077
117685
  init_utils();
117078
117686
  init_bun_compat();
117079
117687
  init_create_tool();
117080
- import * as fs100 from "node:fs";
117081
- import * as path139 from "node:path";
117688
+ import * as fs101 from "node:fs";
117689
+ import * as path140 from "node:path";
117082
117690
  var MAX_OUTPUT_BYTES6 = 52428800;
117083
117691
  var AUDIT_TIMEOUT_MS = 120000;
117084
117692
  function isValidEcosystem(value) {
@@ -117106,31 +117714,31 @@ function validateArgs3(args2) {
117106
117714
  function detectEcosystems(directory) {
117107
117715
  const ecosystems = [];
117108
117716
  const cwd = directory;
117109
- if (fs100.existsSync(path139.join(cwd, "package.json"))) {
117717
+ if (fs101.existsSync(path140.join(cwd, "package.json"))) {
117110
117718
  ecosystems.push("npm");
117111
117719
  }
117112
- if (fs100.existsSync(path139.join(cwd, "pyproject.toml")) || fs100.existsSync(path139.join(cwd, "requirements.txt"))) {
117720
+ if (fs101.existsSync(path140.join(cwd, "pyproject.toml")) || fs101.existsSync(path140.join(cwd, "requirements.txt"))) {
117113
117721
  ecosystems.push("pip");
117114
117722
  }
117115
- if (fs100.existsSync(path139.join(cwd, "Cargo.toml"))) {
117723
+ if (fs101.existsSync(path140.join(cwd, "Cargo.toml"))) {
117116
117724
  ecosystems.push("cargo");
117117
117725
  }
117118
- if (fs100.existsSync(path139.join(cwd, "go.mod"))) {
117726
+ if (fs101.existsSync(path140.join(cwd, "go.mod"))) {
117119
117727
  ecosystems.push("go");
117120
117728
  }
117121
117729
  try {
117122
- const files = fs100.readdirSync(cwd);
117730
+ const files = fs101.readdirSync(cwd);
117123
117731
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
117124
117732
  ecosystems.push("dotnet");
117125
117733
  }
117126
117734
  } catch {}
117127
- if (fs100.existsSync(path139.join(cwd, "Gemfile")) || fs100.existsSync(path139.join(cwd, "Gemfile.lock"))) {
117735
+ if (fs101.existsSync(path140.join(cwd, "Gemfile")) || fs101.existsSync(path140.join(cwd, "Gemfile.lock"))) {
117128
117736
  ecosystems.push("ruby");
117129
117737
  }
117130
- if (fs100.existsSync(path139.join(cwd, "pubspec.yaml"))) {
117738
+ if (fs101.existsSync(path140.join(cwd, "pubspec.yaml"))) {
117131
117739
  ecosystems.push("dart");
117132
117740
  }
117133
- if (fs100.existsSync(path139.join(cwd, "composer.lock"))) {
117741
+ if (fs101.existsSync(path140.join(cwd, "composer.lock"))) {
117134
117742
  ecosystems.push("composer");
117135
117743
  }
117136
117744
  return ecosystems;
@@ -117143,7 +117751,7 @@ async function runNpmAudit(directory) {
117143
117751
  stderr: "pipe",
117144
117752
  cwd: directory
117145
117753
  });
117146
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
117754
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117147
117755
  const result = await Promise.race([
117148
117756
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr2]) => ({ stdout: stdout2, stderr: stderr2 })),
117149
117757
  timeoutPromise
@@ -117263,7 +117871,7 @@ async function runPipAudit(directory) {
117263
117871
  stderr: "pipe",
117264
117872
  cwd: directory
117265
117873
  });
117266
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
117874
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117267
117875
  const result = await Promise.race([
117268
117876
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr2]) => ({ stdout: stdout2, stderr: stderr2 })),
117269
117877
  timeoutPromise
@@ -117391,7 +117999,7 @@ async function runCargoAudit(directory) {
117391
117999
  stderr: "pipe",
117392
118000
  cwd: directory
117393
118001
  });
117394
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
118002
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117395
118003
  const result = await Promise.race([
117396
118004
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr]) => ({ stdout: stdout2, stderr })),
117397
118005
  timeoutPromise
@@ -117515,7 +118123,7 @@ async function runGoAudit(directory) {
117515
118123
  stderr: "pipe",
117516
118124
  cwd: directory
117517
118125
  });
117518
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
118126
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117519
118127
  const result = await Promise.race([
117520
118128
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr]) => ({ stdout: stdout2, stderr })),
117521
118129
  timeoutPromise
@@ -117648,7 +118256,7 @@ async function runDotnetAudit(directory) {
117648
118256
  stderr: "pipe",
117649
118257
  cwd: directory
117650
118258
  });
117651
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
118259
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117652
118260
  const result = await Promise.race([
117653
118261
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr]) => ({ stdout: stdout2, stderr })),
117654
118262
  timeoutPromise
@@ -117764,7 +118372,7 @@ async function runBundleAudit(directory) {
117764
118372
  stderr: "pipe",
117765
118373
  cwd: directory
117766
118374
  });
117767
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
118375
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117768
118376
  const result = await Promise.race([
117769
118377
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr]) => ({ stdout: stdout2, stderr })),
117770
118378
  timeoutPromise
@@ -117909,7 +118517,7 @@ async function runDartAudit(directory) {
117909
118517
  stderr: "pipe",
117910
118518
  cwd: directory
117911
118519
  });
117912
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
118520
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
117913
118521
  const result = await Promise.race([
117914
118522
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr]) => ({ stdout: stdout2, stderr })),
117915
118523
  timeoutPromise
@@ -118024,7 +118632,7 @@ async function runComposerAudit(directory) {
118024
118632
  stderr: "pipe",
118025
118633
  cwd: directory
118026
118634
  });
118027
- const timeoutPromise = new Promise((resolve47) => setTimeout(() => resolve47("timeout"), AUDIT_TIMEOUT_MS));
118635
+ const timeoutPromise = new Promise((resolve48) => setTimeout(() => resolve48("timeout"), AUDIT_TIMEOUT_MS));
118028
118636
  const result = await Promise.race([
118029
118637
  Promise.all([proc.stdout.text(), proc.stderr.text()]).then(([stdout2, stderr]) => ({ stdout: stdout2, stderr })),
118030
118638
  timeoutPromise
@@ -118266,8 +118874,8 @@ var pkg_audit = createSwarmTool({
118266
118874
  // src/tools/placeholder-scan.ts
118267
118875
  init_zod();
118268
118876
  init_manager2();
118269
- import * as fs101 from "node:fs";
118270
- import * as path140 from "node:path";
118877
+ import * as fs102 from "node:fs";
118878
+ import * as path141 from "node:path";
118271
118879
  init_utils();
118272
118880
  init_create_tool();
118273
118881
  var MAX_FILE_SIZE = 1024 * 1024;
@@ -118390,7 +118998,7 @@ function isScaffoldFile(filePath) {
118390
118998
  if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
118391
118999
  return true;
118392
119000
  }
118393
- const filename = path140.basename(filePath);
119001
+ const filename = path141.basename(filePath);
118394
119002
  if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
118395
119003
  return true;
118396
119004
  }
@@ -118407,7 +119015,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
118407
119015
  if (regex.test(normalizedPath)) {
118408
119016
  return true;
118409
119017
  }
118410
- const filename = path140.basename(filePath);
119018
+ const filename = path141.basename(filePath);
118411
119019
  const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
118412
119020
  if (filenameRegex.test(filename)) {
118413
119021
  return true;
@@ -118416,7 +119024,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
118416
119024
  return false;
118417
119025
  }
118418
119026
  function isParserSupported(filePath) {
118419
- const ext = path140.extname(filePath).toLowerCase();
119027
+ const ext = path141.extname(filePath).toLowerCase();
118420
119028
  return SUPPORTED_PARSER_EXTENSIONS.has(ext);
118421
119029
  }
118422
119030
  function isPlanFile(filePath) {
@@ -118663,28 +119271,28 @@ async function placeholderScan(input, directory) {
118663
119271
  let filesScanned = 0;
118664
119272
  const filesWithFindings = new Set;
118665
119273
  for (const filePath of changed_files) {
118666
- const fullPath = path140.isAbsolute(filePath) ? filePath : path140.resolve(directory, filePath);
118667
- const resolvedDirectory = path140.resolve(directory);
118668
- if (!fullPath.startsWith(resolvedDirectory + path140.sep) && fullPath !== resolvedDirectory) {
119274
+ const fullPath = path141.isAbsolute(filePath) ? filePath : path141.resolve(directory, filePath);
119275
+ const resolvedDirectory = path141.resolve(directory);
119276
+ if (!fullPath.startsWith(resolvedDirectory + path141.sep) && fullPath !== resolvedDirectory) {
118669
119277
  continue;
118670
119278
  }
118671
- if (!fs101.existsSync(fullPath)) {
119279
+ if (!fs102.existsSync(fullPath)) {
118672
119280
  continue;
118673
119281
  }
118674
119282
  if (isAllowedByGlobs(filePath, allow_globs)) {
118675
119283
  continue;
118676
119284
  }
118677
- const relativeFilePath = path140.relative(directory, fullPath).replace(/\\/g, "/");
119285
+ const relativeFilePath = path141.relative(directory, fullPath).replace(/\\/g, "/");
118678
119286
  if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
118679
119287
  continue;
118680
119288
  }
118681
119289
  let content;
118682
119290
  try {
118683
- const stat9 = fs101.statSync(fullPath);
119291
+ const stat9 = fs102.statSync(fullPath);
118684
119292
  if (stat9.size > MAX_FILE_SIZE) {
118685
119293
  continue;
118686
119294
  }
118687
- content = fs101.readFileSync(fullPath, "utf-8");
119295
+ content = fs102.readFileSync(fullPath, "utf-8");
118688
119296
  } catch {
118689
119297
  continue;
118690
119298
  }
@@ -118746,8 +119354,8 @@ var placeholder_scan = createSwarmTool({
118746
119354
  });
118747
119355
 
118748
119356
  // src/tools/pre-check-batch.ts
118749
- import * as fs105 from "node:fs";
118750
- import * as path144 from "node:path";
119357
+ import * as fs106 from "node:fs";
119358
+ import * as path145 from "node:path";
118751
119359
  init_zod();
118752
119360
  init_manager2();
118753
119361
  init_utils();
@@ -118887,9 +119495,9 @@ var _internals61 = {
118887
119495
  init_zod();
118888
119496
  init_manager2();
118889
119497
  init_detector();
118890
- import * as fs104 from "node:fs";
118891
- import * as path143 from "node:path";
118892
- import { extname as extname20 } from "node:path";
119498
+ import * as fs105 from "node:fs";
119499
+ import * as path144 from "node:path";
119500
+ import { extname as extname21 } from "node:path";
118893
119501
 
118894
119502
  // src/sast/rules/c.ts
118895
119503
  var cRules = [
@@ -119602,9 +120210,9 @@ function executeRulesSync(filePath, content, language) {
119602
120210
  }
119603
120211
 
119604
120212
  // src/sast/semgrep.ts
119605
- import * as child_process9 from "node:child_process";
119606
- import * as fs102 from "node:fs";
119607
- import * as path141 from "node:path";
120213
+ import * as child_process10 from "node:child_process";
120214
+ import * as fs103 from "node:fs";
120215
+ import * as path142 from "node:path";
119608
120216
  var semgrepAvailableCache = null;
119609
120217
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
119610
120218
  var DEFAULT_TIMEOUT_MS3 = 30000;
@@ -119621,7 +120229,7 @@ function isSemgrepAvailable() {
119621
120229
  return semgrepAvailableCache;
119622
120230
  }
119623
120231
  try {
119624
- child_process9.execFileSync("semgrep", ["--version"], {
120232
+ child_process10.execFileSync("semgrep", ["--version"], {
119625
120233
  encoding: "utf-8",
119626
120234
  stdio: "pipe"
119627
120235
  });
@@ -119685,8 +120293,8 @@ function mapSemgrepSeverity(severity) {
119685
120293
  }
119686
120294
  }
119687
120295
  async function executeWithTimeout(command, args2, options) {
119688
- return new Promise((resolve49) => {
119689
- const child = child_process9.spawn(command, args2, {
120296
+ return new Promise((resolve50) => {
120297
+ const child = child_process10.spawn(command, args2, {
119690
120298
  shell: false,
119691
120299
  cwd: options.cwd
119692
120300
  });
@@ -119694,7 +120302,7 @@ async function executeWithTimeout(command, args2, options) {
119694
120302
  let stderr = "";
119695
120303
  const timeout = setTimeout(() => {
119696
120304
  child.kill("SIGTERM");
119697
- resolve49({
120305
+ resolve50({
119698
120306
  stdout,
119699
120307
  stderr: "Process timed out",
119700
120308
  exitCode: 124
@@ -119708,7 +120316,7 @@ async function executeWithTimeout(command, args2, options) {
119708
120316
  });
119709
120317
  child.on("close", (code) => {
119710
120318
  clearTimeout(timeout);
119711
- resolve49({
120319
+ resolve50({
119712
120320
  stdout,
119713
120321
  stderr,
119714
120322
  exitCode: code ?? 0
@@ -119716,7 +120324,7 @@ async function executeWithTimeout(command, args2, options) {
119716
120324
  });
119717
120325
  child.on("error", (err2) => {
119718
120326
  clearTimeout(timeout);
119719
- resolve49({
120327
+ resolve50({
119720
120328
  stdout,
119721
120329
  stderr: err2.message,
119722
120330
  exitCode: 1
@@ -119791,14 +120399,14 @@ async function runSemgrep(options) {
119791
120399
  }
119792
120400
  function getRulesDirectory(projectRoot) {
119793
120401
  if (projectRoot) {
119794
- return path141.resolve(projectRoot, DEFAULT_RULES_DIR);
120402
+ return path142.resolve(projectRoot, DEFAULT_RULES_DIR);
119795
120403
  }
119796
120404
  return DEFAULT_RULES_DIR;
119797
120405
  }
119798
120406
  function hasBundledRules(projectRoot) {
119799
120407
  const rulesDir = getRulesDirectory(projectRoot);
119800
120408
  try {
119801
- return fs102.existsSync(rulesDir);
120409
+ return fs103.existsSync(rulesDir);
119802
120410
  } catch {
119803
120411
  return false;
119804
120412
  }
@@ -119811,25 +120419,25 @@ init_create_tool();
119811
120419
  // src/tools/sast-baseline.ts
119812
120420
  init_utils2();
119813
120421
  import * as crypto11 from "node:crypto";
119814
- import * as fs103 from "node:fs";
119815
- import * as path142 from "node:path";
120422
+ import * as fs104 from "node:fs";
120423
+ import * as path143 from "node:path";
119816
120424
  var BASELINE_SCHEMA_VERSION = "1.0.0";
119817
120425
  var MAX_BASELINE_FINDINGS = 2000;
119818
120426
  var MAX_BASELINE_BYTES = 2 * 1048576;
119819
120427
  var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
119820
120428
  function normalizeFindingPath(directory, file3) {
119821
- const resolved = path142.isAbsolute(file3) ? file3 : path142.resolve(directory, file3);
119822
- const rel = path142.relative(path142.resolve(directory), resolved);
120429
+ const resolved = path143.isAbsolute(file3) ? file3 : path143.resolve(directory, file3);
120430
+ const rel = path143.relative(path143.resolve(directory), resolved);
119823
120431
  return rel.replace(/\\/g, "/");
119824
120432
  }
119825
120433
  function baselineRelPath(phase) {
119826
- return path142.join("evidence", String(phase), "sast-baseline.json");
120434
+ return path143.join("evidence", String(phase), "sast-baseline.json");
119827
120435
  }
119828
120436
  function tempRelPath(phase) {
119829
- return path142.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
120437
+ return path143.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
119830
120438
  }
119831
120439
  function lockRelPath(phase) {
119832
- return path142.join("evidence", String(phase), "sast-baseline.json.lock");
120440
+ return path143.join("evidence", String(phase), "sast-baseline.json.lock");
119833
120441
  }
119834
120442
  function getLine(lines, idx) {
119835
120443
  if (idx < 0 || idx >= lines.length)
@@ -119846,7 +120454,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
119846
120454
  }
119847
120455
  const lineNum = finding.location.line;
119848
120456
  try {
119849
- const content = fs103.readFileSync(finding.location.file, "utf-8");
120457
+ const content = fs104.readFileSync(finding.location.file, "utf-8");
119850
120458
  const lines = content.split(`
119851
120459
  `);
119852
120460
  const idx = lineNum - 1;
@@ -119877,7 +120485,7 @@ function assignOccurrenceIndices(findings, directory) {
119877
120485
  try {
119878
120486
  if (relFile.startsWith(".."))
119879
120487
  throw new Error("escapes workspace");
119880
- const content = fs103.readFileSync(finding.location.file, "utf-8");
120488
+ const content = fs104.readFileSync(finding.location.file, "utf-8");
119881
120489
  const lines = content.split(`
119882
120490
  `);
119883
120491
  const idx = lineNum - 1;
@@ -119906,16 +120514,16 @@ function assignOccurrenceIndices(findings, directory) {
119906
120514
  async function acquireLock2(lockPath) {
119907
120515
  for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
119908
120516
  try {
119909
- const fd = fs103.openSync(lockPath, "wx");
119910
- fs103.closeSync(fd);
120517
+ const fd = fs104.openSync(lockPath, "wx");
120518
+ fs104.closeSync(fd);
119911
120519
  return () => {
119912
120520
  try {
119913
- fs103.unlinkSync(lockPath);
120521
+ fs104.unlinkSync(lockPath);
119914
120522
  } catch {}
119915
120523
  };
119916
120524
  } catch {
119917
120525
  if (attempt < LOCK_RETRY_DELAYS_MS.length) {
119918
- await new Promise((resolve50) => setTimeout(resolve50, LOCK_RETRY_DELAYS_MS[attempt]));
120526
+ await new Promise((resolve51) => setTimeout(resolve51, LOCK_RETRY_DELAYS_MS[attempt]));
119919
120527
  }
119920
120528
  }
119921
120529
  }
@@ -119950,13 +120558,13 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
119950
120558
  message: e instanceof Error ? e.message : "Path validation failed"
119951
120559
  };
119952
120560
  }
119953
- fs103.mkdirSync(path142.dirname(baselinePath), { recursive: true });
119954
- fs103.mkdirSync(path142.dirname(tempPath), { recursive: true });
120561
+ fs104.mkdirSync(path143.dirname(baselinePath), { recursive: true });
120562
+ fs104.mkdirSync(path143.dirname(tempPath), { recursive: true });
119955
120563
  const releaseLock = await acquireLock2(lockPath);
119956
120564
  try {
119957
120565
  let existing = null;
119958
120566
  try {
119959
- const raw = fs103.readFileSync(baselinePath, "utf-8");
120567
+ const raw = fs104.readFileSync(baselinePath, "utf-8");
119960
120568
  const parsed = JSON.parse(raw);
119961
120569
  if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
119962
120570
  existing = parsed;
@@ -120016,8 +120624,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
120016
120624
  message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
120017
120625
  };
120018
120626
  }
120019
- fs103.writeFileSync(tempPath, json4, "utf-8");
120020
- fs103.renameSync(tempPath, baselinePath);
120627
+ fs104.writeFileSync(tempPath, json4, "utf-8");
120628
+ fs104.renameSync(tempPath, baselinePath);
120021
120629
  return {
120022
120630
  status: "merged",
120023
120631
  path: baselinePath,
@@ -120048,8 +120656,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
120048
120656
  message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
120049
120657
  };
120050
120658
  }
120051
- fs103.writeFileSync(tempPath, json3, "utf-8");
120052
- fs103.renameSync(tempPath, baselinePath);
120659
+ fs104.writeFileSync(tempPath, json3, "utf-8");
120660
+ fs104.renameSync(tempPath, baselinePath);
120053
120661
  return {
120054
120662
  status: "written",
120055
120663
  path: baselinePath,
@@ -120074,7 +120682,7 @@ function loadBaseline(directory, phase) {
120074
120682
  };
120075
120683
  }
120076
120684
  try {
120077
- const raw = fs103.readFileSync(baselinePath, "utf-8");
120685
+ const raw = fs104.readFileSync(baselinePath, "utf-8");
120078
120686
  const parsed = JSON.parse(raw);
120079
120687
  if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
120080
120688
  return {
@@ -120122,17 +120730,17 @@ var SEVERITY_ORDER = {
120122
120730
  };
120123
120731
  function shouldSkipFile(filePath) {
120124
120732
  try {
120125
- const stats = fs104.statSync(filePath);
120733
+ const stats = fs105.statSync(filePath);
120126
120734
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
120127
120735
  return { skip: true, reason: "file too large" };
120128
120736
  }
120129
120737
  if (stats.size === 0) {
120130
120738
  return { skip: true, reason: "empty file" };
120131
120739
  }
120132
- const fd = fs104.openSync(filePath, "r");
120740
+ const fd = fs105.openSync(filePath, "r");
120133
120741
  const buffer = Buffer.alloc(8192);
120134
- const bytesRead = fs104.readSync(fd, buffer, 0, 8192, 0);
120135
- fs104.closeSync(fd);
120742
+ const bytesRead = fs105.readSync(fd, buffer, 0, 8192, 0);
120743
+ fs105.closeSync(fd);
120136
120744
  if (bytesRead > 0) {
120137
120745
  let nullCount = 0;
120138
120746
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -120171,7 +120779,7 @@ function countBySeverity(findings) {
120171
120779
  }
120172
120780
  function scanFileWithTierA(filePath, language) {
120173
120781
  try {
120174
- const content = fs104.readFileSync(filePath, "utf-8");
120782
+ const content = fs105.readFileSync(filePath, "utf-8");
120175
120783
  const findings = executeRulesSync(filePath, content, language);
120176
120784
  return findings.map((f) => ({
120177
120785
  rule_id: f.rule_id,
@@ -120224,13 +120832,13 @@ async function sastScan(input, directory, config3) {
120224
120832
  _filesSkipped++;
120225
120833
  continue;
120226
120834
  }
120227
- const resolvedPath = path143.isAbsolute(filePath) ? filePath : path143.resolve(directory, filePath);
120228
- const resolvedDirectory = path143.resolve(directory);
120229
- if (!resolvedPath.startsWith(resolvedDirectory + path143.sep) && resolvedPath !== resolvedDirectory) {
120835
+ const resolvedPath = path144.isAbsolute(filePath) ? filePath : path144.resolve(directory, filePath);
120836
+ const resolvedDirectory = path144.resolve(directory);
120837
+ if (!resolvedPath.startsWith(resolvedDirectory + path144.sep) && resolvedPath !== resolvedDirectory) {
120230
120838
  _filesSkipped++;
120231
120839
  continue;
120232
120840
  }
120233
- if (!fs104.existsSync(resolvedPath)) {
120841
+ if (!fs105.existsSync(resolvedPath)) {
120234
120842
  _filesSkipped++;
120235
120843
  continue;
120236
120844
  }
@@ -120239,7 +120847,7 @@ async function sastScan(input, directory, config3) {
120239
120847
  _filesSkipped++;
120240
120848
  continue;
120241
120849
  }
120242
- const ext = extname20(resolvedPath).toLowerCase();
120850
+ const ext = extname21(resolvedPath).toLowerCase();
120243
120851
  const profile = getProfileForFile(resolvedPath);
120244
120852
  const langDef = getLanguageForExtension(ext);
120245
120853
  if (!profile && !langDef) {
@@ -120541,20 +121149,20 @@ function validatePath(inputPath, baseDir, workspaceDir) {
120541
121149
  let resolved;
120542
121150
  const isWinAbs = isWindowsAbsolutePath(inputPath);
120543
121151
  if (isWinAbs) {
120544
- resolved = path144.win32.resolve(inputPath);
120545
- } else if (path144.isAbsolute(inputPath)) {
120546
- resolved = path144.resolve(inputPath);
121152
+ resolved = path145.win32.resolve(inputPath);
121153
+ } else if (path145.isAbsolute(inputPath)) {
121154
+ resolved = path145.resolve(inputPath);
120547
121155
  } else {
120548
- resolved = path144.resolve(baseDir, inputPath);
121156
+ resolved = path145.resolve(baseDir, inputPath);
120549
121157
  }
120550
- const workspaceResolved = path144.resolve(workspaceDir);
120551
- let relative28;
121158
+ const workspaceResolved = path145.resolve(workspaceDir);
121159
+ let relative29;
120552
121160
  if (isWinAbs) {
120553
- relative28 = path144.win32.relative(workspaceResolved, resolved);
121161
+ relative29 = path145.win32.relative(workspaceResolved, resolved);
120554
121162
  } else {
120555
- relative28 = path144.relative(workspaceResolved, resolved);
121163
+ relative29 = path145.relative(workspaceResolved, resolved);
120556
121164
  }
120557
- if (relative28.startsWith("..")) {
121165
+ if (relative29.startsWith("..")) {
120558
121166
  return "path traversal detected";
120559
121167
  }
120560
121168
  return null;
@@ -120617,7 +121225,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
120617
121225
  if (typeof file3 !== "string") {
120618
121226
  continue;
120619
121227
  }
120620
- const resolvedPath = path144.resolve(file3);
121228
+ const resolvedPath = path145.resolve(file3);
120621
121229
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
120622
121230
  if (validationError) {
120623
121231
  continue;
@@ -120774,7 +121382,7 @@ async function runSecretscanWithFiles(files, directory) {
120774
121382
  skippedFiles++;
120775
121383
  continue;
120776
121384
  }
120777
- const resolvedPath = path144.resolve(file3);
121385
+ const resolvedPath = path145.resolve(file3);
120778
121386
  const validationError = validatePath(resolvedPath, directory, directory);
120779
121387
  if (validationError) {
120780
121388
  skippedFiles++;
@@ -120792,14 +121400,14 @@ async function runSecretscanWithFiles(files, directory) {
120792
121400
  };
120793
121401
  }
120794
121402
  for (const file3 of validatedFiles) {
120795
- const ext = path144.extname(file3).toLowerCase();
121403
+ const ext = path145.extname(file3).toLowerCase();
120796
121404
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
120797
121405
  skippedFiles++;
120798
121406
  continue;
120799
121407
  }
120800
121408
  let stat9;
120801
121409
  try {
120802
- stat9 = fs105.statSync(file3);
121410
+ stat9 = fs106.statSync(file3);
120803
121411
  } catch {
120804
121412
  skippedFiles++;
120805
121413
  continue;
@@ -120810,7 +121418,7 @@ async function runSecretscanWithFiles(files, directory) {
120810
121418
  }
120811
121419
  let content;
120812
121420
  try {
120813
- const buffer = fs105.readFileSync(file3);
121421
+ const buffer = fs106.readFileSync(file3);
120814
121422
  if (buffer.includes(0)) {
120815
121423
  skippedFiles++;
120816
121424
  continue;
@@ -121011,7 +121619,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
121011
121619
  const preexistingFindings = [];
121012
121620
  for (const finding of findings) {
121013
121621
  const filePath = finding.location.file;
121014
- const normalised = path144.relative(directory, filePath).replace(/\\/g, "/");
121622
+ const normalised = path145.relative(directory, filePath).replace(/\\/g, "/");
121015
121623
  const changedLines = changedLineRanges.get(normalised);
121016
121624
  if (changedLines?.has(finding.location.line)) {
121017
121625
  newFindings.push(finding);
@@ -121062,7 +121670,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
121062
121670
  warn(`pre_check_batch: Invalid file path: ${file3}`);
121063
121671
  continue;
121064
121672
  }
121065
- changedFiles.push(path144.resolve(directory, file3));
121673
+ changedFiles.push(path145.resolve(directory, file3));
121066
121674
  }
121067
121675
  if (changedFiles.length === 0) {
121068
121676
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -121263,9 +121871,9 @@ var pre_check_batch = createSwarmTool({
121263
121871
  };
121264
121872
  return JSON.stringify(errorResult, null, 2);
121265
121873
  }
121266
- const resolvedDirectory = path144.resolve(typedArgs.directory);
121267
- const workspaceAnchor = path144.resolve(directory);
121268
- if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor + path144.sep)) {
121874
+ const resolvedDirectory = path145.resolve(typedArgs.directory);
121875
+ const workspaceAnchor = path145.resolve(directory);
121876
+ if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor + path145.sep)) {
121269
121877
  const subDirError = `directory "${typedArgs.directory}" is a subdirectory of the project root — pre_check_batch requires the project root directory "${workspaceAnchor}"`;
121270
121878
  const subDirResult = {
121271
121879
  gates_passed: false,
@@ -121317,7 +121925,7 @@ var pre_check_batch = createSwarmTool({
121317
121925
 
121318
121926
  // src/tools/repo-map.ts
121319
121927
  init_zod();
121320
- import * as path145 from "node:path";
121928
+ import * as path146 from "node:path";
121321
121929
  init_path_security();
121322
121930
  init_create_tool();
121323
121931
  var VALID_ACTIONS = [
@@ -121342,7 +121950,7 @@ function validateFile(p) {
121342
121950
  return "file contains control characters";
121343
121951
  if (containsPathTraversal(p))
121344
121952
  return "file contains path traversal";
121345
- if (path145.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
121953
+ if (path146.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
121346
121954
  return "file must be a workspace-relative path, not absolute";
121347
121955
  }
121348
121956
  return null;
@@ -121365,8 +121973,8 @@ function ok(action, payload) {
121365
121973
  }
121366
121974
  function toRelativeGraphPath(input, workspaceRoot) {
121367
121975
  const normalized = input.replace(/\\/g, "/");
121368
- if (path145.isAbsolute(normalized)) {
121369
- const rel = path145.relative(workspaceRoot, normalized).replace(/\\/g, "/");
121976
+ if (path146.isAbsolute(normalized)) {
121977
+ const rel = path146.relative(workspaceRoot, normalized).replace(/\\/g, "/");
121370
121978
  return normalizeGraphPath2(rel);
121371
121979
  }
121372
121980
  return normalizeGraphPath2(normalized);
@@ -121511,8 +122119,8 @@ var repo_map = createSwarmTool({
121511
122119
  // src/tools/req-coverage.ts
121512
122120
  init_zod();
121513
122121
  init_create_tool();
121514
- import * as fs106 from "node:fs";
121515
- import * as path146 from "node:path";
122122
+ import * as fs107 from "node:fs";
122123
+ import * as path147 from "node:path";
121516
122124
  var SPEC_FILE = ".swarm/spec.md";
121517
122125
  var EVIDENCE_DIR4 = ".swarm/evidence";
121518
122126
  var OBLIGATION_KEYWORDS2 = ["MUST", "SHOULD", "SHALL"];
@@ -121571,19 +122179,19 @@ function extractObligationAndText(id, lineText) {
121571
122179
  var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
121572
122180
  function readTouchedFiles(evidenceDir, phase, cwd) {
121573
122181
  const touchedFiles = new Set;
121574
- if (!fs106.existsSync(evidenceDir) || !fs106.statSync(evidenceDir).isDirectory()) {
122182
+ if (!fs107.existsSync(evidenceDir) || !fs107.statSync(evidenceDir).isDirectory()) {
121575
122183
  return [];
121576
122184
  }
121577
122185
  let entries;
121578
122186
  try {
121579
- entries = fs106.readdirSync(evidenceDir);
122187
+ entries = fs107.readdirSync(evidenceDir);
121580
122188
  } catch {
121581
122189
  return [];
121582
122190
  }
121583
122191
  for (const entry of entries) {
121584
- const entryPath = path146.join(evidenceDir, entry);
122192
+ const entryPath = path147.join(evidenceDir, entry);
121585
122193
  try {
121586
- const stat9 = fs106.statSync(entryPath);
122194
+ const stat9 = fs107.statSync(entryPath);
121587
122195
  if (!stat9.isDirectory()) {
121588
122196
  continue;
121589
122197
  }
@@ -121597,14 +122205,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
121597
122205
  if (entryPhase !== String(phase)) {
121598
122206
  continue;
121599
122207
  }
121600
- const evidenceFilePath = path146.join(entryPath, "evidence.json");
122208
+ const evidenceFilePath = path147.join(entryPath, "evidence.json");
121601
122209
  try {
121602
- const resolvedPath = path146.resolve(evidenceFilePath);
121603
- const evidenceDirResolved = path146.resolve(evidenceDir);
121604
- if (!resolvedPath.startsWith(evidenceDirResolved + path146.sep)) {
122210
+ const resolvedPath = path147.resolve(evidenceFilePath);
122211
+ const evidenceDirResolved = path147.resolve(evidenceDir);
122212
+ if (!resolvedPath.startsWith(evidenceDirResolved + path147.sep)) {
121605
122213
  continue;
121606
122214
  }
121607
- const stat9 = fs106.lstatSync(evidenceFilePath);
122215
+ const stat9 = fs107.lstatSync(evidenceFilePath);
121608
122216
  if (!stat9.isFile()) {
121609
122217
  continue;
121610
122218
  }
@@ -121616,7 +122224,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
121616
122224
  }
121617
122225
  let content;
121618
122226
  try {
121619
- content = fs106.readFileSync(evidenceFilePath, "utf-8");
122227
+ content = fs107.readFileSync(evidenceFilePath, "utf-8");
121620
122228
  } catch {
121621
122229
  continue;
121622
122230
  }
@@ -121635,7 +122243,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
121635
122243
  if (Array.isArray(diffEntry.files_changed)) {
121636
122244
  for (const file3 of diffEntry.files_changed) {
121637
122245
  if (typeof file3 === "string") {
121638
- touchedFiles.add(path146.resolve(cwd, file3));
122246
+ touchedFiles.add(path147.resolve(cwd, file3));
121639
122247
  }
121640
122248
  }
121641
122249
  }
@@ -121648,12 +122256,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
121648
122256
  }
121649
122257
  function searchFileForKeywords(filePath, keywords, cwd) {
121650
122258
  try {
121651
- const resolvedPath = path146.resolve(filePath);
121652
- const cwdResolved = path146.resolve(cwd);
122259
+ const resolvedPath = path147.resolve(filePath);
122260
+ const cwdResolved = path147.resolve(cwd);
121653
122261
  if (!resolvedPath.startsWith(cwdResolved)) {
121654
122262
  return false;
121655
122263
  }
121656
- const content = fs106.readFileSync(resolvedPath, "utf-8");
122264
+ const content = fs107.readFileSync(resolvedPath, "utf-8");
121657
122265
  for (const keyword of keywords) {
121658
122266
  const regex = new RegExp(`\\b${keyword}\\b`, "i");
121659
122267
  if (regex.test(content)) {
@@ -121783,10 +122391,10 @@ var req_coverage = createSwarmTool({
121783
122391
  }, null, 2);
121784
122392
  }
121785
122393
  const cwd = inputDirectory || directory;
121786
- const specPath = path146.join(cwd, SPEC_FILE);
122394
+ const specPath = path147.join(cwd, SPEC_FILE);
121787
122395
  let specContent;
121788
122396
  try {
121789
- specContent = fs106.readFileSync(specPath, "utf-8");
122397
+ specContent = fs107.readFileSync(specPath, "utf-8");
121790
122398
  } catch (readError) {
121791
122399
  return JSON.stringify({
121792
122400
  success: false,
@@ -121810,7 +122418,7 @@ var req_coverage = createSwarmTool({
121810
122418
  message: "No FR requirements found in spec.md"
121811
122419
  }, null, 2);
121812
122420
  }
121813
- const evidenceDir = path146.join(cwd, EVIDENCE_DIR4);
122421
+ const evidenceDir = path147.join(cwd, EVIDENCE_DIR4);
121814
122422
  const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
121815
122423
  const analyzedRequirements = [];
121816
122424
  let coveredCount = 0;
@@ -121836,12 +122444,12 @@ var req_coverage = createSwarmTool({
121836
122444
  requirements: analyzedRequirements
121837
122445
  };
121838
122446
  const reportFilename = `req-coverage-phase-${phase}.json`;
121839
- const reportPath = path146.join(evidenceDir, reportFilename);
122447
+ const reportPath = path147.join(evidenceDir, reportFilename);
121840
122448
  try {
121841
- if (!fs106.existsSync(evidenceDir)) {
121842
- fs106.mkdirSync(evidenceDir, { recursive: true });
122449
+ if (!fs107.existsSync(evidenceDir)) {
122450
+ fs107.mkdirSync(evidenceDir, { recursive: true });
121843
122451
  }
121844
- fs106.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
122452
+ fs107.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
121845
122453
  } catch (writeError) {
121846
122454
  console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
121847
122455
  }
@@ -121925,8 +122533,8 @@ init_plan_schema();
121925
122533
  init_qa_gate_profile();
121926
122534
  init_file_locks();
121927
122535
  import * as crypto12 from "node:crypto";
121928
- import * as fs107 from "node:fs";
121929
- import * as path147 from "node:path";
122536
+ import * as fs108 from "node:fs";
122537
+ import * as path148 from "node:path";
121930
122538
  init_ledger();
121931
122539
  init_manager();
121932
122540
  init_state();
@@ -122007,17 +122615,17 @@ async function executeSavePlan(args2, fallbackDir) {
122007
122615
  };
122008
122616
  }
122009
122617
  if (args2.working_directory && fallbackDir) {
122010
- const resolvedTarget = path147.resolve(args2.working_directory);
122011
- const resolvedRoot = path147.resolve(fallbackDir);
122618
+ const resolvedTarget = path148.resolve(args2.working_directory);
122619
+ const resolvedRoot = path148.resolve(fallbackDir);
122012
122620
  let fallbackExists = false;
122013
122621
  try {
122014
- fs107.accessSync(resolvedRoot, fs107.constants.F_OK);
122622
+ fs108.accessSync(resolvedRoot, fs108.constants.F_OK);
122015
122623
  fallbackExists = true;
122016
122624
  } catch {
122017
122625
  fallbackExists = false;
122018
122626
  }
122019
122627
  if (fallbackExists) {
122020
- const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path147.sep);
122628
+ const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path148.sep);
122021
122629
  if (isSubdirectory) {
122022
122630
  return {
122023
122631
  success: false,
@@ -122033,11 +122641,11 @@ async function executeSavePlan(args2, fallbackDir) {
122033
122641
  let specMtime;
122034
122642
  let specHash;
122035
122643
  if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
122036
- const specPath = path147.join(targetWorkspace, ".swarm", "spec.md");
122644
+ const specPath = path148.join(targetWorkspace, ".swarm", "spec.md");
122037
122645
  try {
122038
- const stat9 = await fs107.promises.stat(specPath);
122646
+ const stat9 = await fs108.promises.stat(specPath);
122039
122647
  specMtime = stat9.mtime.toISOString();
122040
- const content = await fs107.promises.readFile(specPath, "utf8");
122648
+ const content = await fs108.promises.readFile(specPath, "utf8");
122041
122649
  specHash = crypto12.createHash("sha256").update(content).digest("hex");
122042
122650
  } catch {
122043
122651
  return {
@@ -122049,10 +122657,10 @@ async function executeSavePlan(args2, fallbackDir) {
122049
122657
  }
122050
122658
  }
122051
122659
  if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
122052
- const contextPath = path147.join(targetWorkspace, ".swarm", "context.md");
122660
+ const contextPath = path148.join(targetWorkspace, ".swarm", "context.md");
122053
122661
  let contextContent = "";
122054
122662
  try {
122055
- contextContent = await fs107.promises.readFile(contextPath, "utf8");
122663
+ contextContent = await fs108.promises.readFile(contextPath, "utf8");
122056
122664
  } catch {}
122057
122665
  const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
122058
122666
  if (!hasPendingSection) {
@@ -122339,14 +122947,14 @@ async function executeSavePlan(args2, fallbackDir) {
122339
122947
  }
122340
122948
  await writeCheckpoint(dir).catch(() => {});
122341
122949
  try {
122342
- const markerPath = path147.join(dir, ".swarm", ".plan-write-marker");
122950
+ const markerPath = path148.join(dir, ".swarm", ".plan-write-marker");
122343
122951
  const marker = JSON.stringify({
122344
122952
  source: "save_plan",
122345
122953
  timestamp: new Date().toISOString(),
122346
122954
  phases_count: plan.phases.length,
122347
122955
  tasks_count: tasksCount
122348
122956
  });
122349
- await fs107.promises.writeFile(markerPath, marker, "utf8");
122957
+ await fs108.promises.writeFile(markerPath, marker, "utf8");
122350
122958
  } catch {}
122351
122959
  const warnings = [];
122352
122960
  let criticReviewFound = false;
@@ -122362,7 +122970,7 @@ async function executeSavePlan(args2, fallbackDir) {
122362
122970
  return {
122363
122971
  success: true,
122364
122972
  message: "Plan saved successfully",
122365
- plan_path: path147.join(dir, ".swarm", "plan.json"),
122973
+ plan_path: path148.join(dir, ".swarm", "plan.json"),
122366
122974
  phases_count: plan.phases.length,
122367
122975
  tasks_count: tasksCount,
122368
122976
  ...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
@@ -122428,8 +123036,8 @@ var save_plan = createSwarmTool({
122428
123036
  // src/tools/sbom-generate.ts
122429
123037
  init_zod();
122430
123038
  init_manager2();
122431
- import * as fs108 from "node:fs";
122432
- import * as path148 from "node:path";
123039
+ import * as fs109 from "node:fs";
123040
+ import * as path149 from "node:path";
122433
123041
 
122434
123042
  // src/sbom/detectors/index.ts
122435
123043
  init_utils();
@@ -123277,9 +123885,9 @@ function findManifestFiles(rootDir) {
123277
123885
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
123278
123886
  function searchDir(dir) {
123279
123887
  try {
123280
- const entries = fs108.readdirSync(dir, { withFileTypes: true });
123888
+ const entries = fs109.readdirSync(dir, { withFileTypes: true });
123281
123889
  for (const entry of entries) {
123282
- const fullPath = path148.join(dir, entry.name);
123890
+ const fullPath = path149.join(dir, entry.name);
123283
123891
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
123284
123892
  continue;
123285
123893
  }
@@ -123288,7 +123896,7 @@ function findManifestFiles(rootDir) {
123288
123896
  } else if (entry.isFile()) {
123289
123897
  for (const pattern of patterns) {
123290
123898
  if (simpleGlobToRegex(pattern).test(entry.name)) {
123291
- manifestFiles.push(path148.relative(rootDir, fullPath));
123899
+ manifestFiles.push(path149.relative(rootDir, fullPath));
123292
123900
  break;
123293
123901
  }
123294
123902
  }
@@ -123304,13 +123912,13 @@ function findManifestFilesInDirs(directories, workingDir) {
123304
123912
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
123305
123913
  for (const dir of directories) {
123306
123914
  try {
123307
- const entries = fs108.readdirSync(dir, { withFileTypes: true });
123915
+ const entries = fs109.readdirSync(dir, { withFileTypes: true });
123308
123916
  for (const entry of entries) {
123309
- const fullPath = path148.join(dir, entry.name);
123917
+ const fullPath = path149.join(dir, entry.name);
123310
123918
  if (entry.isFile()) {
123311
123919
  for (const pattern of patterns) {
123312
123920
  if (simpleGlobToRegex(pattern).test(entry.name)) {
123313
- found.push(path148.relative(workingDir, fullPath));
123921
+ found.push(path149.relative(workingDir, fullPath));
123314
123922
  break;
123315
123923
  }
123316
123924
  }
@@ -123323,11 +123931,11 @@ function findManifestFilesInDirs(directories, workingDir) {
123323
123931
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
123324
123932
  const dirs = new Set;
123325
123933
  for (const file3 of changedFiles) {
123326
- let currentDir = path148.dirname(file3);
123934
+ let currentDir = path149.dirname(file3);
123327
123935
  while (true) {
123328
- if (currentDir && currentDir !== "." && currentDir !== path148.sep) {
123329
- dirs.add(path148.join(workingDir, currentDir));
123330
- const parent = path148.dirname(currentDir);
123936
+ if (currentDir && currentDir !== "." && currentDir !== path149.sep) {
123937
+ dirs.add(path149.join(workingDir, currentDir));
123938
+ const parent = path149.dirname(currentDir);
123331
123939
  if (parent === currentDir)
123332
123940
  break;
123333
123941
  currentDir = parent;
@@ -123341,7 +123949,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
123341
123949
  }
123342
123950
  function ensureOutputDir(outputDir) {
123343
123951
  try {
123344
- fs108.mkdirSync(outputDir, { recursive: true });
123952
+ fs109.mkdirSync(outputDir, { recursive: true });
123345
123953
  } catch (error93) {
123346
123954
  if (!error93 || error93.code !== "EEXIST") {
123347
123955
  throw error93;
@@ -123411,7 +124019,7 @@ var sbom_generate = createSwarmTool({
123411
124019
  const changedFiles = obj.changed_files;
123412
124020
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
123413
124021
  const workingDir = directory;
123414
- const outputDir = path148.isAbsolute(relativeOutputDir) ? relativeOutputDir : path148.join(workingDir, relativeOutputDir);
124022
+ const outputDir = path149.isAbsolute(relativeOutputDir) ? relativeOutputDir : path149.join(workingDir, relativeOutputDir);
123415
124023
  let manifestFiles = [];
123416
124024
  if (scope === "all") {
123417
124025
  manifestFiles = findManifestFiles(workingDir);
@@ -123434,11 +124042,11 @@ var sbom_generate = createSwarmTool({
123434
124042
  const processedFiles = [];
123435
124043
  for (const manifestFile of manifestFiles) {
123436
124044
  try {
123437
- const fullPath = path148.isAbsolute(manifestFile) ? manifestFile : path148.join(workingDir, manifestFile);
123438
- if (!fs108.existsSync(fullPath)) {
124045
+ const fullPath = path149.isAbsolute(manifestFile) ? manifestFile : path149.join(workingDir, manifestFile);
124046
+ if (!fs109.existsSync(fullPath)) {
123439
124047
  continue;
123440
124048
  }
123441
- const content = fs108.readFileSync(fullPath, "utf-8");
124049
+ const content = fs109.readFileSync(fullPath, "utf-8");
123442
124050
  const components = detectComponents(manifestFile, content);
123443
124051
  processedFiles.push(manifestFile);
123444
124052
  if (components.length > 0) {
@@ -123451,8 +124059,8 @@ var sbom_generate = createSwarmTool({
123451
124059
  const bom = generateCycloneDX(allComponents);
123452
124060
  const bomJson = serializeCycloneDX(bom);
123453
124061
  const filename = generateSbomFilename();
123454
- const outputPath = path148.join(outputDir, filename);
123455
- fs108.writeFileSync(outputPath, bomJson, "utf-8");
124062
+ const outputPath = path149.join(outputDir, filename);
124063
+ fs109.writeFileSync(outputPath, bomJson, "utf-8");
123456
124064
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
123457
124065
  try {
123458
124066
  const timestamp = new Date().toISOString();
@@ -123495,8 +124103,8 @@ var sbom_generate = createSwarmTool({
123495
124103
  // src/tools/schema-drift.ts
123496
124104
  init_zod();
123497
124105
  init_create_tool();
123498
- import * as fs109 from "node:fs";
123499
- import * as path149 from "node:path";
124106
+ import * as fs110 from "node:fs";
124107
+ import * as path150 from "node:path";
123500
124108
  var SPEC_CANDIDATES = [
123501
124109
  "openapi.json",
123502
124110
  "openapi.yaml",
@@ -123528,28 +124136,28 @@ function normalizePath5(p) {
123528
124136
  }
123529
124137
  function discoverSpecFile(cwd, specFileArg) {
123530
124138
  if (specFileArg) {
123531
- const resolvedPath = path149.resolve(cwd, specFileArg);
123532
- const normalizedCwd = cwd.endsWith(path149.sep) ? cwd : cwd + path149.sep;
124139
+ const resolvedPath = path150.resolve(cwd, specFileArg);
124140
+ const normalizedCwd = cwd.endsWith(path150.sep) ? cwd : cwd + path150.sep;
123533
124141
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
123534
124142
  throw new Error("Invalid spec_file: path traversal detected");
123535
124143
  }
123536
- const ext = path149.extname(resolvedPath).toLowerCase();
124144
+ const ext = path150.extname(resolvedPath).toLowerCase();
123537
124145
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
123538
124146
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
123539
124147
  }
123540
- const stats = fs109.statSync(resolvedPath);
124148
+ const stats = fs110.statSync(resolvedPath);
123541
124149
  if (stats.size > MAX_SPEC_SIZE) {
123542
124150
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
123543
124151
  }
123544
- if (!fs109.existsSync(resolvedPath)) {
124152
+ if (!fs110.existsSync(resolvedPath)) {
123545
124153
  throw new Error(`Spec file not found: ${resolvedPath}`);
123546
124154
  }
123547
124155
  return resolvedPath;
123548
124156
  }
123549
124157
  for (const candidate of SPEC_CANDIDATES) {
123550
- const candidatePath = path149.resolve(cwd, candidate);
123551
- if (fs109.existsSync(candidatePath)) {
123552
- const stats = fs109.statSync(candidatePath);
124158
+ const candidatePath = path150.resolve(cwd, candidate);
124159
+ if (fs110.existsSync(candidatePath)) {
124160
+ const stats = fs110.statSync(candidatePath);
123553
124161
  if (stats.size <= MAX_SPEC_SIZE) {
123554
124162
  return candidatePath;
123555
124163
  }
@@ -123558,8 +124166,8 @@ function discoverSpecFile(cwd, specFileArg) {
123558
124166
  return null;
123559
124167
  }
123560
124168
  function parseSpec(specFile) {
123561
- const content = fs109.readFileSync(specFile, "utf-8");
123562
- const ext = path149.extname(specFile).toLowerCase();
124169
+ const content = fs110.readFileSync(specFile, "utf-8");
124170
+ const ext = path150.extname(specFile).toLowerCase();
123563
124171
  if (ext === ".json") {
123564
124172
  return parseJsonSpec(content);
123565
124173
  }
@@ -123627,15 +124235,15 @@ function parseYamlSpec(content) {
123627
124235
  }
123628
124236
  function extractRoutes(cwd) {
123629
124237
  const routes = [];
123630
- function walkDir(dir) {
124238
+ function walkDir2(dir) {
123631
124239
  let entries;
123632
124240
  try {
123633
- entries = fs109.readdirSync(dir, { withFileTypes: true });
124241
+ entries = fs110.readdirSync(dir, { withFileTypes: true });
123634
124242
  } catch {
123635
124243
  return;
123636
124244
  }
123637
124245
  for (const entry of entries) {
123638
- const fullPath = path149.join(dir, entry.name);
124246
+ const fullPath = path150.join(dir, entry.name);
123639
124247
  if (entry.isSymbolicLink()) {
123640
124248
  continue;
123641
124249
  }
@@ -123643,9 +124251,9 @@ function extractRoutes(cwd) {
123643
124251
  if (SKIP_DIRS.includes(entry.name)) {
123644
124252
  continue;
123645
124253
  }
123646
- walkDir(fullPath);
124254
+ walkDir2(fullPath);
123647
124255
  } else if (entry.isFile()) {
123648
- const ext = path149.extname(entry.name).toLowerCase();
124256
+ const ext = path150.extname(entry.name).toLowerCase();
123649
124257
  const baseName = entry.name.toLowerCase();
123650
124258
  if (![".ts", ".js", ".mjs"].includes(ext)) {
123651
124259
  continue;
@@ -123658,12 +124266,12 @@ function extractRoutes(cwd) {
123658
124266
  }
123659
124267
  }
123660
124268
  }
123661
- walkDir(cwd);
124269
+ walkDir2(cwd);
123662
124270
  return routes;
123663
124271
  }
123664
124272
  function extractRoutesFromFile(filePath) {
123665
124273
  const routes = [];
123666
- const content = fs109.readFileSync(filePath, "utf-8");
124274
+ const content = fs110.readFileSync(filePath, "utf-8");
123667
124275
  const lines = content.split(/\r?\n/);
123668
124276
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
123669
124277
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -123813,8 +124421,8 @@ init_zod();
123813
124421
  init_bun_compat();
123814
124422
  init_path_security();
123815
124423
  init_create_tool();
123816
- import * as fs110 from "node:fs";
123817
- import * as path150 from "node:path";
124424
+ import * as fs111 from "node:fs";
124425
+ import * as path151 from "node:path";
123818
124426
  var DEFAULT_MAX_RESULTS = 100;
123819
124427
  var DEFAULT_MAX_LINES = 200;
123820
124428
  var REGEX_TIMEOUT_MS = 5000;
@@ -123850,11 +124458,11 @@ function containsWindowsAttacks4(str) {
123850
124458
  }
123851
124459
  function isPathInWorkspace3(filePath, workspace) {
123852
124460
  try {
123853
- const resolvedPath = path150.resolve(workspace, filePath);
123854
- const realWorkspace = fs110.realpathSync(workspace);
123855
- const realResolvedPath = fs110.realpathSync(resolvedPath);
123856
- const relativePath = path150.relative(realWorkspace, realResolvedPath);
123857
- if (relativePath.startsWith("..") || path150.isAbsolute(relativePath)) {
124461
+ const resolvedPath = path151.resolve(workspace, filePath);
124462
+ const realWorkspace = fs111.realpathSync(workspace);
124463
+ const realResolvedPath = fs111.realpathSync(resolvedPath);
124464
+ const relativePath = path151.relative(realWorkspace, realResolvedPath);
124465
+ if (relativePath.startsWith("..") || path151.isAbsolute(relativePath)) {
123858
124466
  return false;
123859
124467
  }
123860
124468
  return true;
@@ -123867,12 +124475,12 @@ function validatePathForRead2(filePath, workspace) {
123867
124475
  }
123868
124476
  function findRgInEnvPath() {
123869
124477
  const searchPath = process.env.PATH ?? "";
123870
- for (const dir of searchPath.split(path150.delimiter)) {
124478
+ for (const dir of searchPath.split(path151.delimiter)) {
123871
124479
  if (!dir)
123872
124480
  continue;
123873
124481
  const isWindows = process.platform === "win32";
123874
- const candidate = path150.join(dir, isWindows ? "rg.exe" : "rg");
123875
- if (fs110.existsSync(candidate))
124482
+ const candidate = path151.join(dir, isWindows ? "rg.exe" : "rg");
124483
+ if (fs111.existsSync(candidate))
123876
124484
  return candidate;
123877
124485
  }
123878
124486
  return null;
@@ -123926,7 +124534,7 @@ async function ripgrepSearch(opts) {
123926
124534
  stderr: "pipe",
123927
124535
  cwd: opts.workspace
123928
124536
  });
123929
- const timeout = new Promise((resolve56) => setTimeout(() => resolve56("timeout"), REGEX_TIMEOUT_MS));
124537
+ const timeout = new Promise((resolve57) => setTimeout(() => resolve57("timeout"), REGEX_TIMEOUT_MS));
123930
124538
  const exitPromise = proc.exited;
123931
124539
  const result = await Promise.race([exitPromise, timeout]);
123932
124540
  if (result === "timeout") {
@@ -123999,10 +124607,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
123999
124607
  return files;
124000
124608
  }
124001
124609
  try {
124002
- const entries = fs110.readdirSync(dir, { withFileTypes: true });
124610
+ const entries = fs111.readdirSync(dir, { withFileTypes: true });
124003
124611
  for (const entry of entries) {
124004
- const fullPath = path150.join(dir, entry.name);
124005
- const relativePath = path150.relative(workspace, fullPath);
124612
+ const fullPath = path151.join(dir, entry.name);
124613
+ const relativePath = path151.relative(workspace, fullPath);
124006
124614
  if (!validatePathForRead2(fullPath, workspace)) {
124007
124615
  continue;
124008
124616
  }
@@ -124043,13 +124651,13 @@ async function fallbackSearch(opts) {
124043
124651
  const matches = [];
124044
124652
  let total = 0;
124045
124653
  for (const file3 of files) {
124046
- const fullPath = path150.join(opts.workspace, file3);
124654
+ const fullPath = path151.join(opts.workspace, file3);
124047
124655
  if (!validatePathForRead2(fullPath, opts.workspace)) {
124048
124656
  continue;
124049
124657
  }
124050
124658
  let stats;
124051
124659
  try {
124052
- stats = fs110.statSync(fullPath);
124660
+ stats = fs111.statSync(fullPath);
124053
124661
  if (stats.size > MAX_FILE_SIZE_BYTES10) {
124054
124662
  continue;
124055
124663
  }
@@ -124058,7 +124666,7 @@ async function fallbackSearch(opts) {
124058
124666
  }
124059
124667
  let content;
124060
124668
  try {
124061
- content = fs110.readFileSync(fullPath, "utf-8");
124669
+ content = fs111.readFileSync(fullPath, "utf-8");
124062
124670
  } catch {
124063
124671
  continue;
124064
124672
  }
@@ -124170,7 +124778,7 @@ var search = createSwarmTool({
124170
124778
  message: "Exclude pattern contains invalid Windows-specific sequence"
124171
124779
  }, null, 2);
124172
124780
  }
124173
- if (!fs110.existsSync(directory)) {
124781
+ if (!fs111.existsSync(directory)) {
124174
124782
  return JSON.stringify({
124175
124783
  error: true,
124176
124784
  type: "unknown",
@@ -124456,7 +125064,7 @@ init_config();
124456
125064
  init_schema();
124457
125065
  init_create_tool();
124458
125066
  import { mkdir as mkdir24, rename as rename10, writeFile as writeFile19 } from "node:fs/promises";
124459
- import * as path151 from "node:path";
125067
+ import * as path152 from "node:path";
124460
125068
  var MAX_SPEC_BYTES = 256 * 1024;
124461
125069
  var spec_write = createSwarmTool({
124462
125070
  description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
@@ -124497,14 +125105,14 @@ var spec_write = createSwarmTool({
124497
125105
  reason: 'spec must contain at least one top-level "# Heading"'
124498
125106
  }, null, 2);
124499
125107
  }
124500
- const target = path151.join(directory, ".swarm", "spec.md");
124501
- await mkdir24(path151.dirname(target), { recursive: true });
125108
+ const target = path152.join(directory, ".swarm", "spec.md");
125109
+ await mkdir24(path152.dirname(target), { recursive: true });
124502
125110
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
124503
125111
  let finalContent = content;
124504
125112
  if (mode === "append") {
124505
125113
  try {
124506
- const fs111 = await import("node:fs/promises");
124507
- const prior = await fs111.readFile(target, "utf-8");
125114
+ const fs112 = await import("node:fs/promises");
125115
+ const prior = await fs112.readFile(target, "utf-8");
124508
125116
  finalContent = `${prior.replace(/\s+$/, "")}
124509
125117
 
124510
125118
  ${content}
@@ -124527,14 +125135,14 @@ ${content}
124527
125135
  init_zod();
124528
125136
  init_loader();
124529
125137
  import {
124530
- existsSync as existsSync85,
125138
+ existsSync as existsSync86,
124531
125139
  mkdirSync as mkdirSync36,
124532
125140
  readFileSync as readFileSync72,
124533
125141
  renameSync as renameSync22,
124534
125142
  unlinkSync as unlinkSync20,
124535
125143
  writeFileSync as writeFileSync30
124536
125144
  } from "node:fs";
124537
- import path152 from "node:path";
125145
+ import path153 from "node:path";
124538
125146
  init_create_tool();
124539
125147
  init_resolve_working_directory();
124540
125148
  var VerdictSchema2 = exports_external.object({
@@ -124664,7 +125272,7 @@ var submit_phase_council_verdicts = createSwarmTool({
124664
125272
  }
124665
125273
  });
124666
125274
  function getPhaseMutationGapFinding(phaseNumber, workingDir) {
124667
- const mutationGatePath = path152.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
125275
+ const mutationGatePath = path153.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
124668
125276
  try {
124669
125277
  const raw = readFileSync72(mutationGatePath, "utf-8");
124670
125278
  const parsed = JSON.parse(raw);
@@ -124726,9 +125334,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
124726
125334
  }
124727
125335
  }
124728
125336
  function writePhaseCouncilEvidence(workingDir, synthesis) {
124729
- const evidenceDir = path152.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
125337
+ const evidenceDir = path153.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
124730
125338
  mkdirSync36(evidenceDir, { recursive: true });
124731
- const evidenceFile = path152.join(evidenceDir, "phase-council.json");
125339
+ const evidenceFile = path153.join(evidenceDir, "phase-council.json");
124732
125340
  const evidenceBundle = {
124733
125341
  entries: [
124734
125342
  {
@@ -124764,7 +125372,7 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
124764
125372
  writeFileSync30(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
124765
125373
  renameSync22(tempFile, evidenceFile);
124766
125374
  } finally {
124767
- if (existsSync85(tempFile)) {
125375
+ if (existsSync86(tempFile)) {
124768
125376
  unlinkSync20(tempFile);
124769
125377
  }
124770
125378
  }
@@ -124789,8 +125397,30 @@ function formatMutationGapFeedback(finding) {
124789
125397
  init_zod();
124790
125398
  init_path_security();
124791
125399
  init_create_tool();
124792
- import * as fs111 from "node:fs";
124793
- import * as path153 from "node:path";
125400
+ import * as fs112 from "node:fs";
125401
+ import * as path154 from "node:path";
125402
+ var BINARY_EXTENSIONS2 = new Set([
125403
+ ".png",
125404
+ ".jpg",
125405
+ ".jpeg",
125406
+ ".gif",
125407
+ ".bmp",
125408
+ ".ico",
125409
+ ".svg",
125410
+ ".woff",
125411
+ ".woff2",
125412
+ ".ttf",
125413
+ ".eot",
125414
+ ".mp3",
125415
+ ".mp4",
125416
+ ".avi",
125417
+ ".mov",
125418
+ ".pdf",
125419
+ ".zip",
125420
+ ".tar",
125421
+ ".gz",
125422
+ ".rar"
125423
+ ]);
124794
125424
  var WINDOWS_RESERVED_NAMES5 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
124795
125425
  function containsWindowsAttacks5(str) {
124796
125426
  if (/:[^\\/]/.test(str))
@@ -124804,14 +125434,14 @@ function containsWindowsAttacks5(str) {
124804
125434
  }
124805
125435
  function isPathInWorkspace4(filePath, workspace) {
124806
125436
  try {
124807
- const resolvedPath = path153.resolve(workspace, filePath);
124808
- if (!fs111.existsSync(resolvedPath)) {
125437
+ const resolvedPath = path154.resolve(workspace, filePath);
125438
+ if (!fs112.existsSync(resolvedPath)) {
124809
125439
  return true;
124810
125440
  }
124811
- const realWorkspace = fs111.realpathSync(workspace);
124812
- const realResolvedPath = fs111.realpathSync(resolvedPath);
124813
- const relativePath = path153.relative(realWorkspace, realResolvedPath);
124814
- if (relativePath.startsWith("..") || path153.isAbsolute(relativePath)) {
125441
+ const realWorkspace = fs112.realpathSync(workspace);
125442
+ const realResolvedPath = fs112.realpathSync(resolvedPath);
125443
+ const relativePath = path154.relative(realWorkspace, realResolvedPath);
125444
+ if (relativePath.startsWith("..") || path154.isAbsolute(relativePath)) {
124815
125445
  return false;
124816
125446
  }
124817
125447
  return true;
@@ -124819,7 +125449,7 @@ function isPathInWorkspace4(filePath, workspace) {
124819
125449
  return false;
124820
125450
  }
124821
125451
  }
124822
- function validateFilePath(filePath, workspace) {
125452
+ function validateFilePath2(filePath, workspace) {
124823
125453
  if (!filePath || filePath.trim() === "")
124824
125454
  return false;
124825
125455
  if (containsPathTraversal(filePath))
@@ -124831,8 +125461,7 @@ function validateFilePath(filePath, workspace) {
124831
125461
  return isPathInWorkspace4(filePath, workspace);
124832
125462
  }
124833
125463
  function findContextMatch(content, contextBefore, contextAfter, oldContent) {
124834
- const lines = content.split(`
124835
- `);
125464
+ const lines = splitDiffLines(content);
124836
125465
  if ((!contextBefore || contextBefore.length === 0) && (!contextAfter || contextAfter.length === 0)) {
124837
125466
  return null;
124838
125467
  }
@@ -124854,8 +125483,7 @@ function findContextMatch(content, contextBefore, contextAfter, oldContent) {
124854
125483
  };
124855
125484
  } else {
124856
125485
  if (oldContent && oldContent.length > 0) {
124857
- const oldContentLines = oldContent.split(`
124858
- `);
125486
+ const oldContentLines = splitDiffLines(oldContent);
124859
125487
  const betweenLines = lines.slice(afterStart, j);
124860
125488
  if (arraysEqual2(betweenLines, oldContentLines)) {
124861
125489
  return {
@@ -124879,8 +125507,7 @@ function findContextMatch(content, contextBefore, contextAfter, oldContent) {
124879
125507
  return null;
124880
125508
  } else {
124881
125509
  if (oldContent && oldContent.length > 0) {
124882
- const oldContentLines = oldContent.split(`
124883
- `);
125510
+ const oldContentLines = splitDiffLines(oldContent);
124884
125511
  for (let k = afterStart;k <= lines.length - oldContentLines.length; k++) {
124885
125512
  const candidate = lines.slice(k, k + oldContentLines.length);
124886
125513
  if (arraysEqual2(candidate, oldContentLines)) {
@@ -124928,23 +125555,117 @@ function arraysEqual2(a, b) {
124928
125555
  }
124929
125556
  return true;
124930
125557
  }
124931
- function validateOldContent(lines, startIndex, endIndex, oldContent) {
125558
+ function isBinaryFile4(filePath) {
125559
+ const ext = path154.extname(filePath).toLowerCase();
125560
+ return BINARY_EXTENSIONS2.has(ext);
125561
+ }
125562
+ function splitDiffLines(content) {
125563
+ if (content === "")
125564
+ return [];
125565
+ return content.endsWith(`
125566
+ `) ? content.slice(0, -1).split(`
125567
+ `) : content.split(`
125568
+ `);
125569
+ }
125570
+ function generateFileHeader(file3) {
125571
+ return `diff --git a/${file3} b/${file3}
125572
+ ` + `--- a/${file3}
125573
+ ` + `+++ b/${file3}
125574
+ `;
125575
+ }
125576
+ function generateHunk(content, contextMatch, oldContent, newContent) {
125577
+ const lines = splitDiffLines(content);
125578
+ const originalEndsWithNewline = content.endsWith(`
125579
+ `);
125580
+ const newContentEndsWithNewline = newContent.endsWith(`
125581
+ `);
125582
+ const removalStartIdx = contextMatch.startLineIndex + contextMatch.matchedBefore.length;
125583
+ const removalLines = oldContent ? splitDiffLines(oldContent) : [];
125584
+ const removalEndIdx = removalLines.length > 0 ? removalStartIdx + removalLines.length - 1 : removalStartIdx - 1;
125585
+ const additionLines = splitDiffLines(newContent);
125586
+ const isAdjacentCase = contextMatch.matchedAfter.length > 0 && contextMatch.endLineIndex >= 0 && contextMatch.endLineIndex < lines.length && lines[contextMatch.endLineIndex] === contextMatch.matchedAfter[contextMatch.matchedAfter.length - 1];
125587
+ const contextAfterStartInFile = isAdjacentCase ? contextMatch.endLineIndex - contextMatch.matchedAfter.length + 1 : contextMatch.endLineIndex + 1;
125588
+ const overlapSkipCount = Math.max(0, removalLines.length > 0 ? removalEndIdx + 1 - contextAfterStartInFile : 0);
125589
+ const effectiveContextAfterCount = Math.max(0, contextMatch.matchedAfter.length - overlapSkipCount);
125590
+ const oldStart = contextMatch.matchedBefore.length > 0 ? contextMatch.startLineIndex + 1 : removalStartIdx + 1;
125591
+ const newStart = oldStart;
125592
+ const oldCount = contextMatch.matchedBefore.length + removalLines.length + effectiveContextAfterCount;
125593
+ const newCount = contextMatch.matchedBefore.length + additionLines.length + effectiveContextAfterCount;
125594
+ const hunkLines = [];
125595
+ let lastOldSidePos = -1;
125596
+ let lastNewSidePos = -1;
125597
+ for (const line of contextMatch.matchedBefore) {
125598
+ const idx = hunkLines.length;
125599
+ hunkLines.push(` ${line}`);
125600
+ lastOldSidePos = idx;
125601
+ lastNewSidePos = idx;
125602
+ }
125603
+ for (const line of removalLines) {
125604
+ const idx = hunkLines.length;
125605
+ hunkLines.push(`-${line}`);
125606
+ lastOldSidePos = idx;
125607
+ }
125608
+ for (const line of additionLines) {
125609
+ const idx = hunkLines.length;
125610
+ hunkLines.push(`+${line}`);
125611
+ lastNewSidePos = idx;
125612
+ }
125613
+ for (let k = overlapSkipCount;k < contextMatch.matchedAfter.length; k++) {
125614
+ const idx = hunkLines.length;
125615
+ hunkLines.push(` ${contextMatch.matchedAfter[k]}`);
125616
+ lastOldSidePos = idx;
125617
+ lastNewSidePos = idx;
125618
+ }
125619
+ const lastOldSideFileIdx = effectiveContextAfterCount > 0 ? contextAfterStartInFile + contextMatch.matchedAfter.length - 1 : removalLines.length > 0 ? removalEndIdx : contextMatch.matchedBefore.length > 0 ? contextMatch.startLineIndex + contextMatch.matchedBefore.length - 1 : -1;
125620
+ const isAtEof = lastOldSideFileIdx === lines.length - 1;
125621
+ const needsOldMarker = isAtEof && !originalEndsWithNewline && lastOldSidePos >= 0;
125622
+ const newSideEndsWithNewline = effectiveContextAfterCount > 0 ? originalEndsWithNewline : additionLines.length > 0 ? newContentEndsWithNewline : true;
125623
+ const needsNewMarker = isAtEof && !newSideEndsWithNewline && lastNewSidePos >= 0;
125624
+ const finalLines = [];
125625
+ let pendingOldMarker = needsOldMarker;
125626
+ let pendingNewMarker = needsNewMarker;
125627
+ for (let i2 = 0;i2 < hunkLines.length; i2++) {
125628
+ finalLines.push(hunkLines[i2]);
125629
+ if (pendingOldMarker && i2 === lastOldSidePos) {
125630
+ finalLines.push("\");
125631
+ pendingOldMarker = false;
125632
+ }
125633
+ if (pendingNewMarker && i2 === lastNewSidePos) {
125634
+ finalLines.push("\");
125635
+ pendingNewMarker = false;
125636
+ }
125637
+ }
125638
+ const oldCountStr = oldCount === 0 ? "0" : String(oldCount);
125639
+ const newCountStr = newCount === 0 ? "0" : String(newCount);
125640
+ let diff2 = "";
125641
+ diff2 += `@@ -${oldStart},${oldCountStr} +${newStart},${newCountStr} @@
125642
+ `;
125643
+ diff2 += finalLines.join(`
125644
+ `);
125645
+ diff2 += `
125646
+ `;
125647
+ return diff2;
125648
+ }
125649
+ function validateOldContent(lines, contextMatch, oldContent) {
124932
125650
  if (!oldContent) {
124933
125651
  return { valid: true };
124934
125652
  }
124935
- const currentContent = lines.slice(startIndex, endIndex + 1).join(`
124936
- `);
124937
- if (currentContent !== oldContent) {
125653
+ const expectedLines = splitDiffLines(oldContent);
125654
+ const removalStartIdx = contextMatch.startLineIndex + contextMatch.matchedBefore.length;
125655
+ const actualLines = lines.slice(removalStartIdx, removalStartIdx + expectedLines.length);
125656
+ if (!arraysEqual2(actualLines, expectedLines)) {
124938
125657
  return {
124939
125658
  valid: false,
124940
- expected: oldContent,
124941
- actual: currentContent
125659
+ expected: expectedLines.join(`
125660
+ `),
125661
+ actual: actualLines.join(`
125662
+ `)
124942
125663
  };
124943
125664
  }
124944
125665
  return { valid: true };
124945
125666
  }
124946
125667
  var suggestPatch = createSwarmTool({
124947
- description: "Suggest a structured patch for specified files without modifying them. " + "Returns context-based patch proposals with anchors for reviewer use. " + "This is a read-only tool — it does not modify any files.",
125668
+ description: "Suggest a structured patch for specified files without modifying them. " + "Returns context-based patch proposals with anchors for reviewer use. " + 'When format="unified", also produces a unified diff string consumable by apply_patch. ' + "This is a read-only tool — it does not modify any files.",
124948
125669
  args: {
124949
125670
  targetFiles: exports_external.array(exports_external.string()).describe("Array of file paths to patch").min(1),
124950
125671
  changes: exports_external.array(exports_external.object({
@@ -124953,7 +125674,8 @@ var suggestPatch = createSwarmTool({
124953
125674
  contextAfter: exports_external.array(exports_external.string()).optional().describe("Lines after the change region (anchor)"),
124954
125675
  oldContent: exports_external.string().optional().describe("Current content to be replaced"),
124955
125676
  newContent: exports_external.string().describe("New content to replace with")
124956
- })).describe("Array of change descriptions with context anchors").min(1)
125677
+ })).describe("Array of change descriptions with context anchors").min(1),
125678
+ format: exports_external.enum(["json", "unified"]).optional().default("json").describe('Output format: "json" (default, existing structured output) or "unified" (unified diff string for apply_patch)')
124957
125679
  },
124958
125680
  execute: async (args2, directory) => {
124959
125681
  if (!args2 || typeof args2 !== "object") {
@@ -124967,6 +125689,7 @@ var suggestPatch = createSwarmTool({
124967
125689
  const obj = args2;
124968
125690
  const targetFiles = obj.targetFiles ?? [];
124969
125691
  const changes = obj.changes ?? [];
125692
+ const format = obj.format ?? "json";
124970
125693
  if (!targetFiles || targetFiles.length === 0) {
124971
125694
  return JSON.stringify({
124972
125695
  success: false,
@@ -124983,7 +125706,7 @@ var suggestPatch = createSwarmTool({
124983
125706
  message: "changes cannot be empty"
124984
125707
  }, null, 2);
124985
125708
  }
124986
- if (!fs111.existsSync(directory)) {
125709
+ if (!fs112.existsSync(directory)) {
124987
125710
  return JSON.stringify({
124988
125711
  success: false,
124989
125712
  error: true,
@@ -124994,9 +125717,28 @@ var suggestPatch = createSwarmTool({
124994
125717
  const patches = [];
124995
125718
  const filesModifiedSet = new Set;
124996
125719
  const errors5 = [];
125720
+ const unifiedDiffEntries = [];
124997
125721
  const targetFileSet = new Set(targetFiles);
125722
+ const skippedBinaryFiles = new Set;
125723
+ if (format === "unified") {
125724
+ for (const change of changes) {
125725
+ if (isBinaryFile4(change.file)) {
125726
+ errors5.push({
125727
+ success: false,
125728
+ error: true,
125729
+ type: "parse-error",
125730
+ message: `Binary files are not supported in unified diff mode: ${change.file}`,
125731
+ details: { location: change.file }
125732
+ });
125733
+ skippedBinaryFiles.add(change.file);
125734
+ }
125735
+ }
125736
+ }
124998
125737
  for (let changeIndex = 0;changeIndex < changes.length; changeIndex++) {
124999
125738
  const change = changes[changeIndex];
125739
+ if (format === "unified" && skippedBinaryFiles.has(change.file)) {
125740
+ continue;
125741
+ }
125000
125742
  if (!targetFileSet.has(change.file)) {
125001
125743
  errors5.push({
125002
125744
  success: false,
@@ -125007,7 +125749,7 @@ var suggestPatch = createSwarmTool({
125007
125749
  });
125008
125750
  continue;
125009
125751
  }
125010
- if (!validateFilePath(change.file, directory)) {
125752
+ if (!validateFilePath2(change.file, directory)) {
125011
125753
  errors5.push({
125012
125754
  success: false,
125013
125755
  error: true,
@@ -125019,8 +125761,8 @@ var suggestPatch = createSwarmTool({
125019
125761
  });
125020
125762
  continue;
125021
125763
  }
125022
- const fullPath = path153.resolve(directory, change.file);
125023
- if (!fs111.existsSync(fullPath)) {
125764
+ const fullPath = path154.resolve(directory, change.file);
125765
+ if (!fs112.existsSync(fullPath)) {
125024
125766
  errors5.push({
125025
125767
  success: false,
125026
125768
  error: true,
@@ -125034,7 +125776,7 @@ var suggestPatch = createSwarmTool({
125034
125776
  }
125035
125777
  let content;
125036
125778
  try {
125037
- content = fs111.readFileSync(fullPath, "utf-8");
125779
+ content = fs112.readFileSync(fullPath, "utf-8");
125038
125780
  } catch (err3) {
125039
125781
  errors5.push({
125040
125782
  success: false,
@@ -125060,9 +125802,8 @@ var suggestPatch = createSwarmTool({
125060
125802
  });
125061
125803
  continue;
125062
125804
  }
125063
- const lines = content.split(`
125064
- `);
125065
- const oldContentValidation = validateOldContent(lines, contextMatch.startLineIndex + contextMatch.matchedBefore.length, contextMatch.endLineIndex - contextMatch.matchedAfter.length + 1, change.oldContent);
125805
+ const lines = splitDiffLines(content);
125806
+ const oldContentValidation = validateOldContent(lines, contextMatch, change.oldContent);
125066
125807
  if (!oldContentValidation.valid) {
125067
125808
  errors5.push({
125068
125809
  success: false,
@@ -125089,14 +125830,51 @@ var suggestPatch = createSwarmTool({
125089
125830
  hunkIndex: changeIndex
125090
125831
  });
125091
125832
  filesModifiedSet.add(change.file);
125833
+ if (format === "unified") {
125834
+ unifiedDiffEntries.push({
125835
+ file: change.file,
125836
+ contextMatch,
125837
+ oldContent: change.oldContent,
125838
+ newContent: change.newContent
125839
+ });
125840
+ }
125092
125841
  }
125093
125842
  if (patches.length > 0) {
125094
- return JSON.stringify({
125843
+ const baseResult = {
125095
125844
  success: true,
125096
125845
  patches,
125097
125846
  filesModified: Array.from(filesModifiedSet),
125098
125847
  ...errors5.length > 0 && { errors: errors5 }
125099
- }, null, 2);
125848
+ };
125849
+ if (format === "unified") {
125850
+ const fileGroups = new Map;
125851
+ for (const entry of unifiedDiffEntries) {
125852
+ const group = fileGroups.get(entry.file) ?? [];
125853
+ group.push(entry);
125854
+ fileGroups.set(entry.file, group);
125855
+ }
125856
+ const unifiedParts = [];
125857
+ for (const [file3, entries] of fileGroups) {
125858
+ entries.sort((a, b) => a.contextMatch.startLineIndex - b.contextMatch.startLineIndex);
125859
+ const entryFullPath = path154.resolve(directory, file3);
125860
+ let entryContent;
125861
+ try {
125862
+ entryContent = fs112.readFileSync(entryFullPath, "utf-8");
125863
+ } catch {
125864
+ continue;
125865
+ }
125866
+ unifiedParts.push(generateFileHeader(file3));
125867
+ for (const entry of entries) {
125868
+ unifiedParts.push(generateHunk(entryContent, entry.contextMatch, entry.oldContent, entry.newContent));
125869
+ }
125870
+ }
125871
+ const unifiedPatch = unifiedParts.join("");
125872
+ return JSON.stringify({
125873
+ ...baseResult,
125874
+ unifiedPatch
125875
+ }, null, 2);
125876
+ }
125877
+ return JSON.stringify(baseResult, null, 2);
125100
125878
  }
125101
125879
  if (errors5.length === 1) {
125102
125880
  return JSON.stringify(errors5[0], null, 2);
@@ -125422,8 +126200,8 @@ function getContextAgent3(ctx) {
125422
126200
  init_zod();
125423
126201
  init_manager2();
125424
126202
  init_detector();
125425
- import * as fs112 from "node:fs";
125426
- import * as path154 from "node:path";
126203
+ import * as fs113 from "node:fs";
126204
+ import * as path155 from "node:path";
125427
126205
  init_create_tool();
125428
126206
  var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
125429
126207
  var BINARY_CHECK_BYTES = 8192;
@@ -125489,7 +126267,7 @@ async function syntaxCheck(input, directory, config3) {
125489
126267
  if (languages?.length) {
125490
126268
  const lowerLangs = languages.map((l) => l.toLowerCase());
125491
126269
  filesToCheck = filesToCheck.filter((file3) => {
125492
- const ext = path154.extname(file3.path).toLowerCase();
126270
+ const ext = path155.extname(file3.path).toLowerCase();
125493
126271
  const langDef = getLanguageForExtension(ext);
125494
126272
  const fileProfile = getProfileForFile(file3.path);
125495
126273
  const langId = fileProfile?.id || langDef?.id;
@@ -125502,7 +126280,7 @@ async function syntaxCheck(input, directory, config3) {
125502
126280
  let skippedCount = 0;
125503
126281
  for (const fileInfo of filesToCheck) {
125504
126282
  const { path: filePath } = fileInfo;
125505
- const fullPath = path154.isAbsolute(filePath) ? filePath : path154.join(directory, filePath);
126283
+ const fullPath = path155.isAbsolute(filePath) ? filePath : path155.join(directory, filePath);
125506
126284
  const result = {
125507
126285
  path: filePath,
125508
126286
  language: "",
@@ -125532,7 +126310,7 @@ async function syntaxCheck(input, directory, config3) {
125532
126310
  }
125533
126311
  let content;
125534
126312
  try {
125535
- content = fs112.readFileSync(fullPath, "utf8");
126313
+ content = fs113.readFileSync(fullPath, "utf8");
125536
126314
  } catch {
125537
126315
  result.skipped_reason = "file_read_error";
125538
126316
  skippedCount++;
@@ -125551,7 +126329,7 @@ async function syntaxCheck(input, directory, config3) {
125551
126329
  results.push(result);
125552
126330
  continue;
125553
126331
  }
125554
- const ext = path154.extname(filePath).toLowerCase();
126332
+ const ext = path155.extname(filePath).toLowerCase();
125555
126333
  const langDef = getLanguageForExtension(ext);
125556
126334
  result.language = profile?.id || langDef?.id || "unknown";
125557
126335
  const errors5 = extractSyntaxErrors(parser, content);
@@ -125649,8 +126427,8 @@ init_zod();
125649
126427
  init_utils();
125650
126428
  init_create_tool();
125651
126429
  init_path_security();
125652
- import * as fs113 from "node:fs";
125653
- import * as path155 from "node:path";
126430
+ import * as fs114 from "node:fs";
126431
+ import * as path156 from "node:path";
125654
126432
  var MAX_TEXT_LENGTH = 200;
125655
126433
  var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
125656
126434
  var SUPPORTED_EXTENSIONS4 = new Set([
@@ -125673,7 +126451,7 @@ var SUPPORTED_EXTENSIONS4 = new Set([
125673
126451
  ".swift",
125674
126452
  ".kt"
125675
126453
  ]);
125676
- var SKIP_DIRECTORIES5 = new Set([
126454
+ var SKIP_DIRECTORIES6 = new Set([
125677
126455
  "node_modules",
125678
126456
  "dist",
125679
126457
  "build",
@@ -125716,9 +126494,9 @@ function validatePathsInput(paths, cwd) {
125716
126494
  return { error: "paths contains path traversal", resolvedPath: null };
125717
126495
  }
125718
126496
  try {
125719
- const resolvedPath = path155.resolve(paths);
125720
- const normalizedCwd = path155.resolve(cwd);
125721
- const normalizedResolved = path155.resolve(resolvedPath);
126497
+ const resolvedPath = path156.resolve(paths);
126498
+ const normalizedCwd = path156.resolve(cwd);
126499
+ const normalizedResolved = path156.resolve(resolvedPath);
125722
126500
  if (!normalizedResolved.startsWith(normalizedCwd)) {
125723
126501
  return {
125724
126502
  error: "paths must be within the current working directory",
@@ -125734,30 +126512,30 @@ function validatePathsInput(paths, cwd) {
125734
126512
  }
125735
126513
  }
125736
126514
  function isSupportedExtension(filePath) {
125737
- const ext = path155.extname(filePath).toLowerCase();
126515
+ const ext = path156.extname(filePath).toLowerCase();
125738
126516
  return SUPPORTED_EXTENSIONS4.has(ext);
125739
126517
  }
125740
- function findSourceFiles3(dir, files = []) {
126518
+ function findSourceFiles4(dir, files = []) {
125741
126519
  let entries;
125742
126520
  try {
125743
- entries = fs113.readdirSync(dir);
126521
+ entries = fs114.readdirSync(dir);
125744
126522
  } catch {
125745
126523
  return files;
125746
126524
  }
125747
126525
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
125748
126526
  for (const entry of entries) {
125749
- if (SKIP_DIRECTORIES5.has(entry)) {
126527
+ if (SKIP_DIRECTORIES6.has(entry)) {
125750
126528
  continue;
125751
126529
  }
125752
- const fullPath = path155.join(dir, entry);
126530
+ const fullPath = path156.join(dir, entry);
125753
126531
  let stat9;
125754
126532
  try {
125755
- stat9 = fs113.statSync(fullPath);
126533
+ stat9 = fs114.statSync(fullPath);
125756
126534
  } catch {
125757
126535
  continue;
125758
126536
  }
125759
126537
  if (stat9.isDirectory()) {
125760
- findSourceFiles3(fullPath, files);
126538
+ findSourceFiles4(fullPath, files);
125761
126539
  } else if (stat9.isFile()) {
125762
126540
  if (isSupportedExtension(fullPath)) {
125763
126541
  files.push(fullPath);
@@ -125845,7 +126623,7 @@ var todo_extract = createSwarmTool({
125845
126623
  return JSON.stringify(errorResult, null, 2);
125846
126624
  }
125847
126625
  const scanPath = resolvedPath;
125848
- if (!fs113.existsSync(scanPath)) {
126626
+ if (!fs114.existsSync(scanPath)) {
125849
126627
  const errorResult = {
125850
126628
  error: `path not found: ${pathsInput}`,
125851
126629
  total: 0,
@@ -125855,13 +126633,13 @@ var todo_extract = createSwarmTool({
125855
126633
  return JSON.stringify(errorResult, null, 2);
125856
126634
  }
125857
126635
  const filesToScan = [];
125858
- const stat9 = fs113.statSync(scanPath);
126636
+ const stat9 = fs114.statSync(scanPath);
125859
126637
  if (stat9.isFile()) {
125860
126638
  if (isSupportedExtension(scanPath)) {
125861
126639
  filesToScan.push(scanPath);
125862
126640
  } else {
125863
126641
  const errorResult = {
125864
- error: `unsupported file extension: ${path155.extname(scanPath)}`,
126642
+ error: `unsupported file extension: ${path156.extname(scanPath)}`,
125865
126643
  total: 0,
125866
126644
  byPriority: { high: 0, medium: 0, low: 0 },
125867
126645
  entries: []
@@ -125869,16 +126647,16 @@ var todo_extract = createSwarmTool({
125869
126647
  return JSON.stringify(errorResult, null, 2);
125870
126648
  }
125871
126649
  } else {
125872
- findSourceFiles3(scanPath, filesToScan);
126650
+ findSourceFiles4(scanPath, filesToScan);
125873
126651
  }
125874
126652
  const allEntries = [];
125875
126653
  for (const filePath of filesToScan) {
125876
126654
  try {
125877
- const fileStat = fs113.statSync(filePath);
126655
+ const fileStat = fs114.statSync(filePath);
125878
126656
  if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
125879
126657
  continue;
125880
126658
  }
125881
- const content = fs113.readFileSync(filePath, "utf-8");
126659
+ const content = fs114.readFileSync(filePath, "utf-8");
125882
126660
  const entries = parseTodoComments(content, filePath, tagsSet);
125883
126661
  allEntries.push(...entries);
125884
126662
  } catch {}
@@ -125910,18 +126688,18 @@ init_loader();
125910
126688
  init_schema();
125911
126689
  init_qa_gate_profile();
125912
126690
  init_gate_evidence();
125913
- import * as fs117 from "node:fs";
125914
- import * as path159 from "node:path";
126691
+ import * as fs118 from "node:fs";
126692
+ import * as path160 from "node:path";
125915
126693
 
125916
126694
  // src/hooks/diff-scope.ts
125917
126695
  init_bun_compat();
125918
- import * as fs115 from "node:fs";
125919
- import * as path157 from "node:path";
126696
+ import * as fs116 from "node:fs";
126697
+ import * as path158 from "node:path";
125920
126698
 
125921
126699
  // src/utils/gitignore-warning.ts
125922
126700
  init_bun_compat();
125923
- import * as fs114 from "node:fs";
125924
- import * as path156 from "node:path";
126701
+ import * as fs115 from "node:fs";
126702
+ import * as path157 from "node:path";
125925
126703
  var _internals67 = { bunSpawn };
125926
126704
  var _swarmGitExcludedChecked = false;
125927
126705
  function fileCoversSwarm(content) {
@@ -125995,16 +126773,16 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
125995
126773
  const excludeRelPath = excludePathRaw.trim();
125996
126774
  if (!excludeRelPath)
125997
126775
  return;
125998
- const excludePath = path156.isAbsolute(excludeRelPath) ? excludeRelPath : path156.join(directory, excludeRelPath);
126776
+ const excludePath = path157.isAbsolute(excludeRelPath) ? excludeRelPath : path157.join(directory, excludeRelPath);
125999
126777
  if (checkIgnoreExitCode !== 0) {
126000
126778
  try {
126001
- fs114.mkdirSync(path156.dirname(excludePath), { recursive: true });
126779
+ fs115.mkdirSync(path157.dirname(excludePath), { recursive: true });
126002
126780
  let existing = "";
126003
126781
  try {
126004
- existing = fs114.readFileSync(excludePath, "utf8");
126782
+ existing = fs115.readFileSync(excludePath, "utf8");
126005
126783
  } catch {}
126006
126784
  if (!fileCoversSwarm(existing)) {
126007
- fs114.appendFileSync(excludePath, `
126785
+ fs115.appendFileSync(excludePath, `
126008
126786
  # opencode-swarm local runtime state
126009
126787
  .swarm/
126010
126788
  `, "utf8");
@@ -126042,10 +126820,10 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
126042
126820
  var _internals68 = { bunSpawn };
126043
126821
  function getDeclaredScope(taskId, directory) {
126044
126822
  try {
126045
- const planPath = path157.join(directory, ".swarm", "plan.json");
126046
- if (!fs115.existsSync(planPath))
126823
+ const planPath = path158.join(directory, ".swarm", "plan.json");
126824
+ if (!fs116.existsSync(planPath))
126047
126825
  return null;
126048
- const raw = fs115.readFileSync(planPath, "utf-8");
126826
+ const raw = fs116.readFileSync(planPath, "utf-8");
126049
126827
  const plan = JSON.parse(raw);
126050
126828
  for (const phase of plan.phases ?? []) {
126051
126829
  for (const task of phase.tasks ?? []) {
@@ -126147,8 +126925,8 @@ init_telemetry();
126147
126925
 
126148
126926
  // src/turbo/lean/task-completion.ts
126149
126927
  init_file_locks();
126150
- import * as fs116 from "node:fs";
126151
- import * as path158 from "node:path";
126928
+ import * as fs117 from "node:fs";
126929
+ import * as path159 from "node:path";
126152
126930
  var _internals69 = {
126153
126931
  listActiveLocks,
126154
126932
  verifyLeanTurboTaskCompletion
@@ -126167,7 +126945,7 @@ var TIER_3_PATTERNS = [
126167
126945
  ];
126168
126946
  function matchesTier3Pattern(files) {
126169
126947
  for (const file3 of files) {
126170
- const fileName = path158.basename(file3);
126948
+ const fileName = path159.basename(file3);
126171
126949
  for (const pattern of TIER_3_PATTERNS) {
126172
126950
  if (pattern.test(fileName)) {
126173
126951
  return true;
@@ -126179,14 +126957,14 @@ function matchesTier3Pattern(files) {
126179
126957
  function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
126180
126958
  let persisted = null;
126181
126959
  try {
126182
- const statePath = path158.join(directory, ".swarm", "turbo-state.json");
126183
- if (!fs116.existsSync(statePath)) {
126960
+ const statePath = path159.join(directory, ".swarm", "turbo-state.json");
126961
+ if (!fs117.existsSync(statePath)) {
126184
126962
  return {
126185
126963
  ok: false,
126186
126964
  reason: "Lean Turbo state file not found"
126187
126965
  };
126188
126966
  }
126189
- const raw = fs116.readFileSync(statePath, "utf-8");
126967
+ const raw = fs117.readFileSync(statePath, "utf-8");
126190
126968
  persisted = JSON.parse(raw);
126191
126969
  } catch {
126192
126970
  return {
@@ -126263,11 +127041,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
126263
127041
  };
126264
127042
  }
126265
127043
  const phase = runState.phase ?? 0;
126266
- const evidencePath = path158.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
126267
- const expectedDir = path158.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
126268
- const resolvedPath = path158.resolve(evidencePath);
126269
- const resolvedDir = path158.resolve(expectedDir);
126270
- if (!resolvedPath.startsWith(resolvedDir + path158.sep) && resolvedPath !== resolvedDir) {
127044
+ const evidencePath = path159.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
127045
+ const expectedDir = path159.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
127046
+ const resolvedPath = path159.resolve(evidencePath);
127047
+ const resolvedDir = path159.resolve(expectedDir);
127048
+ if (!resolvedPath.startsWith(resolvedDir + path159.sep) && resolvedPath !== resolvedDir) {
126271
127049
  return {
126272
127050
  ok: false,
126273
127051
  reason: `Lane ID causes path traversal: ${lane.laneId}`,
@@ -126279,7 +127057,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
126279
127057
  }
126280
127058
  };
126281
127059
  }
126282
- if (!fs116.existsSync(evidencePath)) {
127060
+ if (!fs117.existsSync(evidencePath)) {
126283
127061
  return {
126284
127062
  ok: false,
126285
127063
  reason: `Lane ${lane.laneId} evidence file not found: ${evidencePath}`,
@@ -126307,8 +127085,8 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
126307
127085
  }
126308
127086
  let filesTouched = [];
126309
127087
  try {
126310
- const planPath = path158.join(directory, ".swarm", "plan.json");
126311
- const planRaw = fs116.readFileSync(planPath, "utf-8");
127088
+ const planPath = path159.join(directory, ".swarm", "plan.json");
127089
+ const planRaw = fs117.readFileSync(planPath, "utf-8");
126312
127090
  const plan = JSON.parse(planRaw);
126313
127091
  for (const planPhase of plan.phases ?? []) {
126314
127092
  for (const task of planPhase.tasks ?? []) {
@@ -126391,7 +127169,7 @@ var TIER_3_PATTERNS2 = [
126391
127169
  ];
126392
127170
  function matchesTier3Pattern2(files) {
126393
127171
  for (const file3 of files) {
126394
- const fileName = path159.basename(file3);
127172
+ const fileName = path160.basename(file3);
126395
127173
  for (const pattern of TIER_3_PATTERNS2) {
126396
127174
  if (pattern.test(fileName)) {
126397
127175
  return true;
@@ -126430,8 +127208,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
126430
127208
  if (!skipStandardTurboBypass && hasActiveTurboMode()) {
126431
127209
  const resolvedDir2 = workingDirectory;
126432
127210
  try {
126433
- const planPath = path159.join(resolvedDir2, ".swarm", "plan.json");
126434
- const planRaw = fs117.readFileSync(planPath, "utf-8");
127211
+ const planPath = path160.join(resolvedDir2, ".swarm", "plan.json");
127212
+ const planRaw = fs118.readFileSync(planPath, "utf-8");
126435
127213
  const plan = JSON.parse(planRaw);
126436
127214
  for (const planPhase of plan.phases ?? []) {
126437
127215
  for (const task of planPhase.tasks ?? []) {
@@ -126508,8 +127286,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
126508
127286
  }
126509
127287
  if (resolvedDir) {
126510
127288
  try {
126511
- const planPath = path159.join(resolvedDir, ".swarm", "plan.json");
126512
- const planRaw = fs117.readFileSync(planPath, "utf-8");
127289
+ const planPath = path160.join(resolvedDir, ".swarm", "plan.json");
127290
+ const planRaw = fs118.readFileSync(planPath, "utf-8");
126513
127291
  const plan = JSON.parse(planRaw);
126514
127292
  for (const planPhase of plan.phases ?? []) {
126515
127293
  for (const task of planPhase.tasks ?? []) {
@@ -126744,8 +127522,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
126744
127522
  };
126745
127523
  }
126746
127524
  directory = resolveResult.directory;
126747
- const planPath = path159.join(directory, ".swarm", "plan.json");
126748
- if (!fs117.existsSync(planPath)) {
127525
+ const planPath = path160.join(directory, ".swarm", "plan.json");
127526
+ if (!fs118.existsSync(planPath)) {
126749
127527
  return {
126750
127528
  success: false,
126751
127529
  message: `Invalid working_directory: plan not found in "${directory}"`,
@@ -126753,9 +127531,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
126753
127531
  };
126754
127532
  }
126755
127533
  if (fallbackDir && directory !== fallbackDir) {
126756
- const canonicalDir = fs117.realpathSync(path159.resolve(directory));
126757
- const canonicalRoot = fs117.realpathSync(path159.resolve(fallbackDir));
126758
- if (canonicalDir.startsWith(canonicalRoot + path159.sep)) {
127534
+ const canonicalDir = fs118.realpathSync(path160.resolve(directory));
127535
+ const canonicalRoot = fs118.realpathSync(path160.resolve(fallbackDir));
127536
+ if (canonicalDir.startsWith(canonicalRoot + path160.sep)) {
126759
127537
  return {
126760
127538
  success: false,
126761
127539
  message: `Invalid working_directory: "${directory}" is a subdirectory of ` + `the project root "${fallbackDir}". Pass the project root path or ` + `omit working_directory entirely.`,
@@ -126767,22 +127545,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
126767
127545
  }
126768
127546
  if (args2.status === "in_progress") {
126769
127547
  try {
126770
- const evidencePath = path159.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
126771
- fs117.mkdirSync(path159.dirname(evidencePath), { recursive: true });
126772
- const fd = fs117.openSync(evidencePath, "wx");
127548
+ const evidencePath = path160.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
127549
+ fs118.mkdirSync(path160.dirname(evidencePath), { recursive: true });
127550
+ const fd = fs118.openSync(evidencePath, "wx");
126773
127551
  let writeOk = false;
126774
127552
  try {
126775
- fs117.writeSync(fd, JSON.stringify({
127553
+ fs118.writeSync(fd, JSON.stringify({
126776
127554
  taskId: args2.task_id,
126777
127555
  required_gates: [],
126778
127556
  gates: {}
126779
127557
  }, null, 2));
126780
127558
  writeOk = true;
126781
127559
  } finally {
126782
- fs117.closeSync(fd);
127560
+ fs118.closeSync(fd);
126783
127561
  if (!writeOk) {
126784
127562
  try {
126785
- fs117.unlinkSync(evidencePath);
127563
+ fs118.unlinkSync(evidencePath);
126786
127564
  } catch {}
126787
127565
  }
126788
127566
  }
@@ -126792,8 +127570,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
126792
127570
  recoverTaskStateFromDelegations(args2.task_id, directory);
126793
127571
  let phaseRequiresReviewer = true;
126794
127572
  try {
126795
- const planPath2 = path159.join(directory, ".swarm", "plan.json");
126796
- const planRaw = fs117.readFileSync(planPath2, "utf-8");
127573
+ const planPath2 = path160.join(directory, ".swarm", "plan.json");
127574
+ const planRaw = fs118.readFileSync(planPath2, "utf-8");
126797
127575
  const plan = JSON.parse(planRaw);
126798
127576
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
126799
127577
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -127021,7 +127799,7 @@ init_utils2();
127021
127799
  init_redaction();
127022
127800
  import { createHash as createHash12 } from "node:crypto";
127023
127801
  import { appendFile as appendFile14, mkdir as mkdir25 } from "node:fs/promises";
127024
- import * as path160 from "node:path";
127802
+ import * as path161 from "node:path";
127025
127803
  var EVIDENCE_CACHE_FILE = "evidence-cache/documents.jsonl";
127026
127804
  var MAX_EVIDENCE_TEXT_LENGTH = 4000;
127027
127805
  async function writeEvidenceDocuments(directory, inputs, now = () => new Date) {
@@ -127029,7 +127807,7 @@ async function writeEvidenceDocuments(directory, inputs, now = () => new Date) {
127029
127807
  const capturedAt = now().toISOString();
127030
127808
  const records = inputs.map((input) => createEvidenceDocumentRecord(input, capturedAt)).filter((record3) => record3 !== null);
127031
127809
  if (records.length > 0) {
127032
- await mkdir25(path160.dirname(filePath), { recursive: true });
127810
+ await mkdir25(path161.dirname(filePath), { recursive: true });
127033
127811
  await appendFile14(filePath, `${records.map((record3) => JSON.stringify(record3)).join(`
127034
127812
  `)}
127035
127813
  `, "utf-8");
@@ -127226,7 +128004,7 @@ init_schema3();
127226
128004
  init_store();
127227
128005
  init_create_tool();
127228
128006
  init_resolve_working_directory();
127229
- import * as path161 from "node:path";
128007
+ import * as path162 from "node:path";
127230
128008
  var FindingSchema2 = exports_external.object({
127231
128009
  severity: exports_external.enum(["low", "medium", "high", "critical"]),
127232
128010
  category: exports_external.string().min(1),
@@ -127290,7 +128068,7 @@ var write_architecture_supervisor_evidence = createSwarmTool({
127290
128068
  if (config3.architectural_supervision?.persist_knowledge_recommendations && args2.knowledge_recommendations.length > 0) {
127291
128069
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
127292
128070
  const lessons = args2.knowledge_recommendations.map((r) => r.lesson);
127293
- const result = await curateAndStoreSwarm(lessons, path161.basename(dirResult.directory), { phase_number: args2.phase }, dirResult.directory, knowledgeConfig, { skipAutoPromotion: true });
128071
+ const result = await curateAndStoreSwarm(lessons, path162.basename(dirResult.directory), { phase_number: args2.phase }, dirResult.directory, knowledgeConfig, { skipAutoPromotion: true });
127294
128072
  knowledgeProposed = result.stored;
127295
128073
  }
127296
128074
  } catch {}
@@ -127325,8 +128103,8 @@ init_utils2();
127325
128103
  init_ledger();
127326
128104
  init_manager();
127327
128105
  init_create_tool();
127328
- import fs118 from "node:fs";
127329
- import path162 from "node:path";
128106
+ import fs119 from "node:fs";
128107
+ import path163 from "node:path";
127330
128108
  function normalizeVerdict(verdict) {
127331
128109
  switch (verdict) {
127332
128110
  case "APPROVED":
@@ -127374,7 +128152,7 @@ async function executeWriteDriftEvidence(args2, directory) {
127374
128152
  entries: [evidenceEntry]
127375
128153
  };
127376
128154
  const filename = "drift-verifier.json";
127377
- const relativePath = path162.join("evidence", String(phase), filename);
128155
+ const relativePath = path163.join("evidence", String(phase), filename);
127378
128156
  let validatedPath;
127379
128157
  try {
127380
128158
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -127385,12 +128163,12 @@ async function executeWriteDriftEvidence(args2, directory) {
127385
128163
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
127386
128164
  }, null, 2);
127387
128165
  }
127388
- const evidenceDir = path162.dirname(validatedPath);
128166
+ const evidenceDir = path163.dirname(validatedPath);
127389
128167
  try {
127390
- await fs118.promises.mkdir(evidenceDir, { recursive: true });
127391
- const tempPath = path162.join(evidenceDir, `.${filename}.tmp`);
127392
- await fs118.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
127393
- await fs118.promises.rename(tempPath, validatedPath);
128168
+ await fs119.promises.mkdir(evidenceDir, { recursive: true });
128169
+ const tempPath = path163.join(evidenceDir, `.${filename}.tmp`);
128170
+ await fs119.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
128171
+ await fs119.promises.rename(tempPath, validatedPath);
127394
128172
  let snapshotInfo;
127395
128173
  let snapshotError;
127396
128174
  let qaProfileLocked;
@@ -127484,8 +128262,8 @@ var write_drift_evidence = createSwarmTool({
127484
128262
  // src/tools/write-final-council-evidence.ts
127485
128263
  init_zod();
127486
128264
  init_loader();
127487
- import fs119 from "node:fs";
127488
- import path163 from "node:path";
128265
+ import fs120 from "node:fs";
128266
+ import path164 from "node:path";
127489
128267
  init_utils2();
127490
128268
  init_manager();
127491
128269
  init_create_tool();
@@ -127573,7 +128351,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
127573
128351
  timestamp: synthesis.timestamp
127574
128352
  };
127575
128353
  const filename = "final-council.json";
127576
- const relativePath = path163.join("evidence", filename);
128354
+ const relativePath = path164.join("evidence", filename);
127577
128355
  let validatedPath;
127578
128356
  try {
127579
128357
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -127587,12 +128365,12 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
127587
128365
  const evidenceContent = {
127588
128366
  entries: [evidenceEntry]
127589
128367
  };
127590
- const evidenceDir = path163.dirname(validatedPath);
128368
+ const evidenceDir = path164.dirname(validatedPath);
127591
128369
  try {
127592
- await fs119.promises.mkdir(evidenceDir, { recursive: true });
127593
- const tempPath = path163.join(evidenceDir, `.${filename}.tmp`);
127594
- await fs119.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
127595
- await fs119.promises.rename(tempPath, validatedPath);
128370
+ await fs120.promises.mkdir(evidenceDir, { recursive: true });
128371
+ const tempPath = path164.join(evidenceDir, `.${filename}.tmp`);
128372
+ await fs120.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
128373
+ await fs120.promises.rename(tempPath, validatedPath);
127596
128374
  return JSON.stringify({
127597
128375
  success: true,
127598
128376
  phase: input.phase,
@@ -127649,8 +128427,8 @@ var write_final_council_evidence = createSwarmTool({
127649
128427
  init_zod();
127650
128428
  init_utils2();
127651
128429
  init_create_tool();
127652
- import fs120 from "node:fs";
127653
- import path164 from "node:path";
128430
+ import fs121 from "node:fs";
128431
+ import path165 from "node:path";
127654
128432
  function normalizeVerdict2(verdict) {
127655
128433
  switch (verdict) {
127656
128434
  case "APPROVED":
@@ -127698,7 +128476,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
127698
128476
  entries: [evidenceEntry]
127699
128477
  };
127700
128478
  const filename = "hallucination-guard.json";
127701
- const relativePath = path164.join("evidence", String(phase), filename);
128479
+ const relativePath = path165.join("evidence", String(phase), filename);
127702
128480
  let validatedPath;
127703
128481
  try {
127704
128482
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -127709,12 +128487,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
127709
128487
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
127710
128488
  }, null, 2);
127711
128489
  }
127712
- const evidenceDir = path164.dirname(validatedPath);
128490
+ const evidenceDir = path165.dirname(validatedPath);
127713
128491
  try {
127714
- await fs120.promises.mkdir(evidenceDir, { recursive: true });
127715
- const tempPath = path164.join(evidenceDir, `.${filename}.tmp`);
127716
- await fs120.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
127717
- await fs120.promises.rename(tempPath, validatedPath);
128492
+ await fs121.promises.mkdir(evidenceDir, { recursive: true });
128493
+ const tempPath = path165.join(evidenceDir, `.${filename}.tmp`);
128494
+ await fs121.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
128495
+ await fs121.promises.rename(tempPath, validatedPath);
127718
128496
  return JSON.stringify({
127719
128497
  success: true,
127720
128498
  phase,
@@ -127761,8 +128539,8 @@ var write_hallucination_evidence = createSwarmTool({
127761
128539
  init_zod();
127762
128540
  init_utils2();
127763
128541
  init_create_tool();
127764
- import fs121 from "node:fs";
127765
- import path165 from "node:path";
128542
+ import fs122 from "node:fs";
128543
+ import path166 from "node:path";
127766
128544
  function normalizeVerdict3(verdict) {
127767
128545
  switch (verdict) {
127768
128546
  case "PASS":
@@ -127836,7 +128614,7 @@ async function executeWriteMutationEvidence(args2, directory) {
127836
128614
  entries: [evidenceEntry]
127837
128615
  };
127838
128616
  const filename = "mutation-gate.json";
127839
- const relativePath = path165.join("evidence", String(phase), filename);
128617
+ const relativePath = path166.join("evidence", String(phase), filename);
127840
128618
  let validatedPath;
127841
128619
  try {
127842
128620
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -127847,12 +128625,12 @@ async function executeWriteMutationEvidence(args2, directory) {
127847
128625
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
127848
128626
  }, null, 2);
127849
128627
  }
127850
- const evidenceDir = path165.dirname(validatedPath);
128628
+ const evidenceDir = path166.dirname(validatedPath);
127851
128629
  try {
127852
- await fs121.promises.mkdir(evidenceDir, { recursive: true });
127853
- const tempPath = path165.join(evidenceDir, `.${filename}.tmp`);
127854
- await fs121.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
127855
- await fs121.promises.rename(tempPath, validatedPath);
128630
+ await fs122.promises.mkdir(evidenceDir, { recursive: true });
128631
+ const tempPath = path166.join(evidenceDir, `.${filename}.tmp`);
128632
+ await fs122.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
128633
+ await fs122.promises.rename(tempPath, validatedPath);
127856
128634
  return JSON.stringify({
127857
128635
  success: true,
127858
128636
  phase,
@@ -127934,6 +128712,7 @@ var TOOL_MANIFEST = defineHandlers({
127934
128712
  mutation_test: () => mutation_test,
127935
128713
  generate_mutants: () => generate_mutants,
127936
128714
  detect_domains: () => detect_domains,
128715
+ git_blame: () => git_blame,
127937
128716
  gitingest: () => gitingest,
127938
128717
  retrieve_summary: () => retrieve_summary,
127939
128718
  extract_code_blocks: () => extract_code_blocks,
@@ -128298,7 +129077,7 @@ async function initializeOpenCodeSwarm(ctx) {
128298
129077
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
128299
129078
  preflightTriggerManager = new PTM(automationConfig);
128300
129079
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
128301
- const swarmDir = path167.resolve(ctx.directory, ".swarm");
129080
+ const swarmDir = path168.resolve(ctx.directory, ".swarm");
128302
129081
  statusArtifact = new ASA(swarmDir);
128303
129082
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
128304
129083
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -128812,7 +129591,7 @@ ${promptRaw}`;
128812
129591
  const meta3 = readSkillMetadata(s.skillPath, ctx.directory);
128813
129592
  let desc = meta3.description || "";
128814
129593
  if (!desc || desc === "No description provided") {
128815
- desc = path167.basename(path167.dirname(s.skillPath));
129594
+ desc = path168.basename(path168.dirname(s.skillPath));
128816
129595
  }
128817
129596
  desc = desc.replace(/,/g, ";");
128818
129597
  return `file:${s.skillPath} (-- ${desc})`;
@@ -128822,7 +129601,7 @@ ${promptRaw}`;
128822
129601
 
128823
129602
  ${promptRaw}`;
128824
129603
  argsRecord.prompt = newPrompt;
128825
- const skillNames = topSkills.map((s) => `${path167.basename(s.skillPath)} (score: ${s.score.toFixed(2)})`).join(", ");
129604
+ const skillNames = topSkills.map((s) => `${path168.basename(s.skillPath)} (score: ${s.score.toFixed(2)})`).join(", ");
128826
129605
  console.warn(`[skill-propagation-gate] Injected skills: ${skillNames}`);
128827
129606
  for (const skill of topSkills) {
128828
129607
  try {