opencode-swarm 6.41.3 → 6.42.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
@@ -14961,7 +14961,7 @@ var init_schema = __esm(() => {
14961
14961
  max_encounter_score: exports_external.number().min(1).max(20).default(10)
14962
14962
  });
14963
14963
  CuratorConfigSchema = exports_external.object({
14964
- enabled: exports_external.boolean().default(false),
14964
+ enabled: exports_external.boolean().default(true),
14965
14965
  init_enabled: exports_external.boolean().default(true),
14966
14966
  phase_enabled: exports_external.boolean().default(true),
14967
14967
  max_summary_tokens: exports_external.number().min(500).max(8000).default(2000),
@@ -31982,6 +31982,13 @@ async function rewriteKnowledge(filePath, entries) {
31982
31982
  }
31983
31983
  }
31984
31984
  }
31985
+ async function enforceKnowledgeCap(filePath, maxEntries) {
31986
+ const entries = await readKnowledge(filePath);
31987
+ if (entries.length > maxEntries) {
31988
+ const trimmed = entries.slice(entries.length - maxEntries);
31989
+ await rewriteKnowledge(filePath, trimmed);
31990
+ }
31991
+ }
31985
31992
  async function appendRejectedLesson(directory, lesson) {
31986
31993
  const filePath = resolveSwarmRejectedPath(directory);
31987
31994
  const existing = await readRejectedLessons(directory);
@@ -32342,7 +32349,7 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
32342
32349
  lesson,
32343
32350
  category: "architecture",
32344
32351
  tags: ["hidden-coupling", "co-change", "dark-matter"],
32345
- scope: "project",
32352
+ scope: "global",
32346
32353
  confidence,
32347
32354
  status: "candidate",
32348
32355
  confirmed_by: [],
@@ -37293,6 +37300,184 @@ var init_gate_evidence = __esm(() => {
37293
37300
  TASK_ID_PATTERN = /^\d+\.\d+(\.\d+)*$/;
37294
37301
  });
37295
37302
 
37303
+ // src/hooks/review-receipt.ts
37304
+ var exports_review_receipt = {};
37305
+ __export(exports_review_receipt, {
37306
+ resolveReceiptsDir: () => resolveReceiptsDir,
37307
+ resolveReceiptIndexPath: () => resolveReceiptIndexPath,
37308
+ readReceiptsByScopeHash: () => readReceiptsByScopeHash,
37309
+ readReceiptById: () => readReceiptById,
37310
+ readAllReceipts: () => readAllReceipts,
37311
+ persistReviewReceipt: () => persistReviewReceipt,
37312
+ isScopeStale: () => isScopeStale,
37313
+ computeScopeFingerprint: () => computeScopeFingerprint,
37314
+ buildRejectedReceipt: () => buildRejectedReceipt,
37315
+ buildReceiptContextForDrift: () => buildReceiptContextForDrift,
37316
+ buildApprovedReceipt: () => buildApprovedReceipt
37317
+ });
37318
+ import * as crypto4 from "crypto";
37319
+ import * as fs25 from "fs";
37320
+ import * as path36 from "path";
37321
+ function resolveReceiptsDir(directory) {
37322
+ return path36.join(directory, ".swarm", "review-receipts");
37323
+ }
37324
+ function resolveReceiptIndexPath(directory) {
37325
+ return path36.join(resolveReceiptsDir(directory), "index.json");
37326
+ }
37327
+ function buildReceiptFilename(id, date9) {
37328
+ const dateStr = date9.toISOString().slice(0, 10);
37329
+ return `${dateStr}-${id}.json`;
37330
+ }
37331
+ function computeScopeFingerprint(content, scopeDescription) {
37332
+ const hash3 = crypto4.createHash("sha256").update(content, "utf-8").digest("hex");
37333
+ return {
37334
+ hash: hash3,
37335
+ scope_description: scopeDescription,
37336
+ content_length: content.length
37337
+ };
37338
+ }
37339
+ function isScopeStale(receipt, currentContent) {
37340
+ if (currentContent === undefined) {
37341
+ return true;
37342
+ }
37343
+ const currentHash = crypto4.createHash("sha256").update(currentContent, "utf-8").digest("hex");
37344
+ return currentHash !== receipt.scope_fingerprint.hash;
37345
+ }
37346
+ async function readReceiptIndex(directory) {
37347
+ const indexPath = resolveReceiptIndexPath(directory);
37348
+ if (!fs25.existsSync(indexPath)) {
37349
+ return { schema_version: 1, entries: [] };
37350
+ }
37351
+ try {
37352
+ const content = await fs25.promises.readFile(indexPath, "utf-8");
37353
+ const parsed = JSON.parse(content);
37354
+ if (parsed.schema_version !== 1 || !Array.isArray(parsed.entries)) {
37355
+ return { schema_version: 1, entries: [] };
37356
+ }
37357
+ return parsed;
37358
+ } catch {
37359
+ return { schema_version: 1, entries: [] };
37360
+ }
37361
+ }
37362
+ async function writeReceiptIndex(directory, index) {
37363
+ const indexPath = resolveReceiptIndexPath(directory);
37364
+ const dir = path36.dirname(indexPath);
37365
+ await fs25.promises.mkdir(dir, { recursive: true });
37366
+ const tmpPath = `${indexPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
37367
+ await fs25.promises.writeFile(tmpPath, JSON.stringify(index, null, 2), "utf-8");
37368
+ fs25.renameSync(tmpPath, indexPath);
37369
+ }
37370
+ async function persistReviewReceipt(directory, receipt) {
37371
+ const receiptsDir = resolveReceiptsDir(directory);
37372
+ await fs25.promises.mkdir(receiptsDir, { recursive: true });
37373
+ const now = new Date(receipt.reviewed_at);
37374
+ const filename = buildReceiptFilename(receipt.id, now);
37375
+ const receiptPath = path36.join(receiptsDir, filename);
37376
+ const tmpPath = `${receiptPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
37377
+ await fs25.promises.writeFile(tmpPath, JSON.stringify(receipt, null, 2), "utf-8");
37378
+ fs25.renameSync(tmpPath, receiptPath);
37379
+ const index = await readReceiptIndex(directory);
37380
+ const entry = {
37381
+ id: receipt.id,
37382
+ verdict: receipt.verdict,
37383
+ reviewed_at: receipt.reviewed_at,
37384
+ scope_hash: receipt.scope_fingerprint.hash,
37385
+ agent: receipt.reviewer.agent,
37386
+ filename
37387
+ };
37388
+ index.entries.push(entry);
37389
+ await writeReceiptIndex(directory, index);
37390
+ return receiptPath;
37391
+ }
37392
+ async function readReceiptById(directory, receiptId) {
37393
+ const index = await readReceiptIndex(directory);
37394
+ const entry = index.entries.find((e) => e.id === receiptId);
37395
+ if (!entry)
37396
+ return null;
37397
+ const receiptPath = path36.join(resolveReceiptsDir(directory), entry.filename);
37398
+ try {
37399
+ const content = await fs25.promises.readFile(receiptPath, "utf-8");
37400
+ return JSON.parse(content);
37401
+ } catch {
37402
+ return null;
37403
+ }
37404
+ }
37405
+ async function readReceiptsByScopeHash(directory, scopeHash) {
37406
+ const index = await readReceiptIndex(directory);
37407
+ const matching = index.entries.filter((e) => e.scope_hash === scopeHash).sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
37408
+ const receipts = [];
37409
+ for (const entry of matching) {
37410
+ const receiptPath = path36.join(resolveReceiptsDir(directory), entry.filename);
37411
+ try {
37412
+ const content = await fs25.promises.readFile(receiptPath, "utf-8");
37413
+ receipts.push(JSON.parse(content));
37414
+ } catch {}
37415
+ }
37416
+ return receipts;
37417
+ }
37418
+ async function readAllReceipts(directory) {
37419
+ const index = await readReceiptIndex(directory);
37420
+ const sorted = [...index.entries].sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
37421
+ const receipts = [];
37422
+ for (const entry of sorted) {
37423
+ const receiptPath = path36.join(resolveReceiptsDir(directory), entry.filename);
37424
+ try {
37425
+ const content = await fs25.promises.readFile(receiptPath, "utf-8");
37426
+ receipts.push(JSON.parse(content));
37427
+ } catch {}
37428
+ }
37429
+ return receipts;
37430
+ }
37431
+ function buildRejectedReceipt(opts) {
37432
+ return {
37433
+ schema_version: 1,
37434
+ id: crypto4.randomUUID(),
37435
+ receipt_type: "rejected",
37436
+ verdict: "rejected",
37437
+ reviewer: { agent: opts.agent, session_id: opts.sessionId },
37438
+ reviewed_at: new Date().toISOString(),
37439
+ scope_fingerprint: computeScopeFingerprint(opts.scopeContent, opts.scopeDescription),
37440
+ blocking_findings: opts.blockingFindings,
37441
+ evidence_references: opts.evidenceReferences,
37442
+ pass_conditions: opts.passConditions,
37443
+ summary: opts.summary
37444
+ };
37445
+ }
37446
+ function buildApprovedReceipt(opts) {
37447
+ return {
37448
+ schema_version: 1,
37449
+ id: crypto4.randomUUID(),
37450
+ receipt_type: "approved",
37451
+ verdict: "approved",
37452
+ reviewer: { agent: opts.agent, session_id: opts.sessionId },
37453
+ reviewed_at: new Date().toISOString(),
37454
+ scope_fingerprint: computeScopeFingerprint(opts.scopeContent, opts.scopeDescription),
37455
+ checked_aspects: opts.checkedAspects,
37456
+ validated_claims: opts.validatedClaims,
37457
+ caveats: opts.caveats
37458
+ };
37459
+ }
37460
+ function buildReceiptContextForDrift(receipts, currentScopeContent, maxChars = 1000) {
37461
+ if (receipts.length === 0)
37462
+ return "";
37463
+ const lines = ["## Prior Review Receipts (supporting context)"];
37464
+ for (const receipt of receipts) {
37465
+ const stale = receipt.verdict === "approved" ? isScopeStale(receipt, currentScopeContent) : false;
37466
+ const staleTag = stale ? " [SCOPE-STALE \u2014 treat as context only]" : "";
37467
+ if (receipt.verdict === "rejected") {
37468
+ const r = receipt;
37469
+ lines.push(`- REJECTED by ${r.reviewer.agent} at ${r.reviewed_at.slice(0, 10)}: ` + `${r.blocking_findings.length} blocking finding(s). ` + `Pass conditions: ${r.pass_conditions.slice(0, 2).join("; ")}.`);
37470
+ } else {
37471
+ const a = receipt;
37472
+ lines.push(`- APPROVED by ${a.reviewer.agent} at ${a.reviewed_at.slice(0, 10)}${staleTag}: ` + `checked [${a.checked_aspects.join(", ")}]. ` + (a.caveats && a.caveats.length > 0 ? `Caveats: ${a.caveats[0]}.` : "No caveats recorded."));
37473
+ }
37474
+ }
37475
+ lines.push("Note: Approved receipts are supporting evidence only. Stale receipts must not be blindly trusted.");
37476
+ return lines.join(`
37477
+ `).slice(0, maxChars);
37478
+ }
37479
+ var init_review_receipt = () => {};
37480
+
37296
37481
  // src/services/preflight-integration.ts
37297
37482
  var exports_preflight_integration = {};
37298
37483
  __export(exports_preflight_integration, {
@@ -37368,16 +37553,16 @@ __export(exports_doc_scan, {
37368
37553
  doc_scan: () => doc_scan,
37369
37554
  doc_extract: () => doc_extract
37370
37555
  });
37371
- import * as crypto4 from "crypto";
37372
- import * as fs27 from "fs";
37556
+ import * as crypto5 from "crypto";
37557
+ import * as fs28 from "fs";
37373
37558
  import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
37374
- import * as path39 from "path";
37559
+ import * as path40 from "path";
37375
37560
  function normalizeSeparators(filePath) {
37376
37561
  return filePath.replace(/\\/g, "/");
37377
37562
  }
37378
37563
  function matchesDocPattern(filePath, patterns) {
37379
37564
  const normalizedPath = normalizeSeparators(filePath);
37380
- const basename5 = path39.basename(filePath);
37565
+ const basename5 = path40.basename(filePath);
37381
37566
  for (const pattern of patterns) {
37382
37567
  if (!pattern.includes("/") && !pattern.includes("\\")) {
37383
37568
  if (basename5 === pattern) {
@@ -37433,7 +37618,7 @@ function stripMarkdown(text) {
37433
37618
  return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
37434
37619
  }
37435
37620
  async function scanDocIndex(directory) {
37436
- const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
37621
+ const manifestPath = path40.join(directory, ".swarm", "doc-manifest.json");
37437
37622
  const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
37438
37623
  const extraPatterns = [
37439
37624
  "ARCHITECTURE.md",
@@ -37450,8 +37635,8 @@ async function scanDocIndex(directory) {
37450
37635
  let cacheValid = true;
37451
37636
  for (const file3 of existingManifest.files) {
37452
37637
  try {
37453
- const fullPath = path39.join(directory, file3.path);
37454
- const stat2 = fs27.statSync(fullPath);
37638
+ const fullPath = path40.join(directory, file3.path);
37639
+ const stat2 = fs28.statSync(fullPath);
37455
37640
  if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
37456
37641
  cacheValid = false;
37457
37642
  break;
@@ -37469,7 +37654,7 @@ async function scanDocIndex(directory) {
37469
37654
  const discoveredFiles = [];
37470
37655
  let rawEntries;
37471
37656
  try {
37472
- rawEntries = fs27.readdirSync(directory, { recursive: true });
37657
+ rawEntries = fs28.readdirSync(directory, { recursive: true });
37473
37658
  } catch {
37474
37659
  const manifest2 = {
37475
37660
  schema_version: 1,
@@ -37480,10 +37665,10 @@ async function scanDocIndex(directory) {
37480
37665
  }
37481
37666
  const entries = rawEntries.filter((e) => typeof e === "string");
37482
37667
  for (const entry of entries) {
37483
- const fullPath = path39.join(directory, entry);
37668
+ const fullPath = path40.join(directory, entry);
37484
37669
  let stat2;
37485
37670
  try {
37486
- stat2 = fs27.statSync(fullPath);
37671
+ stat2 = fs28.statSync(fullPath);
37487
37672
  } catch {
37488
37673
  continue;
37489
37674
  }
@@ -37512,11 +37697,11 @@ async function scanDocIndex(directory) {
37512
37697
  }
37513
37698
  let content;
37514
37699
  try {
37515
- content = fs27.readFileSync(fullPath, "utf-8");
37700
+ content = fs28.readFileSync(fullPath, "utf-8");
37516
37701
  } catch {
37517
37702
  continue;
37518
37703
  }
37519
- const { title, summary } = extractTitleAndSummary(content, path39.basename(entry));
37704
+ const { title, summary } = extractTitleAndSummary(content, path40.basename(entry));
37520
37705
  const lineCount = content.split(`
37521
37706
  `).length;
37522
37707
  discoveredFiles.push({
@@ -37542,7 +37727,7 @@ async function scanDocIndex(directory) {
37542
37727
  files: discoveredFiles
37543
37728
  };
37544
37729
  try {
37545
- await mkdir6(path39.dirname(manifestPath), { recursive: true });
37730
+ await mkdir6(path40.dirname(manifestPath), { recursive: true });
37546
37731
  await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
37547
37732
  } catch {}
37548
37733
  return { manifest, cached: false };
@@ -37581,7 +37766,7 @@ function extractConstraintsFromContent(content) {
37581
37766
  return constraints;
37582
37767
  }
37583
37768
  async function extractDocConstraints(directory, taskFiles, taskDescription) {
37584
- const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
37769
+ const manifestPath = path40.join(directory, ".swarm", "doc-manifest.json");
37585
37770
  let manifest;
37586
37771
  try {
37587
37772
  const content = await readFile6(manifestPath, "utf-8");
@@ -37607,7 +37792,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
37607
37792
  }
37608
37793
  let fullContent;
37609
37794
  try {
37610
- fullContent = await readFile6(path39.join(directory, docFile.path), "utf-8");
37795
+ fullContent = await readFile6(path40.join(directory, docFile.path), "utf-8");
37611
37796
  } catch {
37612
37797
  skippedCount++;
37613
37798
  continue;
@@ -37626,11 +37811,11 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
37626
37811
  const duplicate = findNearDuplicate(constraint, existingEntries, DEDUP_THRESHOLD);
37627
37812
  if (!duplicate) {
37628
37813
  const entry = {
37629
- id: crypto4.randomUUID(),
37814
+ id: crypto5.randomUUID(),
37630
37815
  tier: "swarm",
37631
37816
  lesson: constraint,
37632
37817
  category: "architecture",
37633
- tags: ["doc-scan", path39.basename(docFile.path)],
37818
+ tags: ["doc-scan", path40.basename(docFile.path)],
37634
37819
  scope: "global",
37635
37820
  confidence: 0.5,
37636
37821
  status: "candidate",
@@ -37703,9 +37888,9 @@ var init_doc_scan = __esm(() => {
37703
37888
  }
37704
37889
  } catch {}
37705
37890
  if (force) {
37706
- const manifestPath = path39.join(directory, ".swarm", "doc-manifest.json");
37891
+ const manifestPath = path40.join(directory, ".swarm", "doc-manifest.json");
37707
37892
  try {
37708
- fs27.unlinkSync(manifestPath);
37893
+ fs28.unlinkSync(manifestPath);
37709
37894
  } catch {}
37710
37895
  }
37711
37896
  const { manifest, cached: cached3 } = await scanDocIndex(directory);
@@ -37757,11 +37942,11 @@ __export(exports_curator_drift, {
37757
37942
  readPriorDriftReports: () => readPriorDriftReports,
37758
37943
  buildDriftInjectionText: () => buildDriftInjectionText
37759
37944
  });
37760
- import * as fs30 from "fs";
37761
- import * as path42 from "path";
37945
+ import * as fs31 from "fs";
37946
+ import * as path43 from "path";
37762
37947
  async function readPriorDriftReports(directory) {
37763
- const swarmDir = path42.join(directory, ".swarm");
37764
- const entries = await fs30.promises.readdir(swarmDir).catch(() => null);
37948
+ const swarmDir = path43.join(directory, ".swarm");
37949
+ const entries = await fs31.promises.readdir(swarmDir).catch(() => null);
37765
37950
  if (entries === null)
37766
37951
  return [];
37767
37952
  const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
@@ -37787,10 +37972,10 @@ async function readPriorDriftReports(directory) {
37787
37972
  async function writeDriftReport(directory, report) {
37788
37973
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
37789
37974
  const filePath = validateSwarmPath(directory, filename);
37790
- const swarmDir = path42.dirname(filePath);
37791
- await fs30.promises.mkdir(swarmDir, { recursive: true });
37975
+ const swarmDir = path43.dirname(filePath);
37976
+ await fs31.promises.mkdir(swarmDir, { recursive: true });
37792
37977
  try {
37793
- await fs30.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
37978
+ await fs31.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
37794
37979
  } catch (err2) {
37795
37980
  throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
37796
37981
  }
@@ -39380,11 +39565,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
39380
39565
  throw toThrow;
39381
39566
  }, "quit_");
39382
39567
  var scriptDirectory = "";
39383
- function locateFile(path50) {
39568
+ function locateFile(path51) {
39384
39569
  if (Module["locateFile"]) {
39385
- return Module["locateFile"](path50, scriptDirectory);
39570
+ return Module["locateFile"](path51, scriptDirectory);
39386
39571
  }
39387
- return scriptDirectory + path50;
39572
+ return scriptDirectory + path51;
39388
39573
  }
39389
39574
  __name(locateFile, "locateFile");
39390
39575
  var readAsync, readBinary;
@@ -41124,13 +41309,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
41124
41309
  });
41125
41310
 
41126
41311
  // src/lang/runtime.ts
41127
- import * as path50 from "path";
41312
+ import * as path51 from "path";
41128
41313
  import { fileURLToPath as fileURLToPath2 } from "url";
41129
41314
  async function initTreeSitter() {
41130
41315
  if (treeSitterInitialized) {
41131
41316
  return;
41132
41317
  }
41133
- const thisDir = path50.dirname(fileURLToPath2(import.meta.url));
41318
+ const thisDir = path51.dirname(fileURLToPath2(import.meta.url));
41134
41319
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41135
41320
  if (isSource) {
41136
41321
  await Parser.init();
@@ -41138,7 +41323,7 @@ async function initTreeSitter() {
41138
41323
  const grammarsDir = getGrammarsDirAbsolute();
41139
41324
  await Parser.init({
41140
41325
  locateFile(scriptName) {
41141
- return path50.join(grammarsDir, scriptName);
41326
+ return path51.join(grammarsDir, scriptName);
41142
41327
  }
41143
41328
  });
41144
41329
  }
@@ -41159,9 +41344,9 @@ function getWasmFileName(languageId) {
41159
41344
  return `tree-sitter-${sanitized}.wasm`;
41160
41345
  }
41161
41346
  function getGrammarsDirAbsolute() {
41162
- const thisDir = path50.dirname(fileURLToPath2(import.meta.url));
41347
+ const thisDir = path51.dirname(fileURLToPath2(import.meta.url));
41163
41348
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41164
- return isSource ? path50.join(thisDir, "grammars") : path50.join(thisDir, "lang", "grammars");
41349
+ return isSource ? path51.join(thisDir, "grammars") : path51.join(thisDir, "lang", "grammars");
41165
41350
  }
41166
41351
  async function loadGrammar(languageId) {
41167
41352
  if (typeof languageId !== "string" || languageId.length > 100) {
@@ -41177,9 +41362,9 @@ async function loadGrammar(languageId) {
41177
41362
  await initTreeSitter();
41178
41363
  const parser = new Parser;
41179
41364
  const wasmFileName = getWasmFileName(normalizedId);
41180
- const wasmPath = path50.join(getGrammarsDirAbsolute(), wasmFileName);
41181
- const { existsSync: existsSync29 } = await import("fs");
41182
- if (!existsSync29(wasmPath)) {
41365
+ const wasmPath = path51.join(getGrammarsDirAbsolute(), wasmFileName);
41366
+ const { existsSync: existsSync30 } = await import("fs");
41367
+ if (!existsSync30(wasmPath)) {
41183
41368
  throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
41184
41369
  Make sure to run 'bun run build' to copy grammar files to dist/lang/grammars/`);
41185
41370
  }
@@ -41224,7 +41409,7 @@ var init_runtime = __esm(() => {
41224
41409
  });
41225
41410
 
41226
41411
  // src/index.ts
41227
- import * as path67 from "path";
41412
+ import * as path68 from "path";
41228
41413
 
41229
41414
  // src/agents/index.ts
41230
41415
  init_config();
@@ -41245,6 +41430,7 @@ var swarmState = {
41245
41430
  activeAgent: new Map,
41246
41431
  delegationChains: new Map,
41247
41432
  pendingEvents: 0,
41433
+ opencodeClient: null,
41248
41434
  lastBudgetPct: 0,
41249
41435
  agentSessions: new Map,
41250
41436
  pendingRehydrations: new Set
@@ -41750,7 +41936,7 @@ Output to .swarm/plan.md MUST use "## Phase N" headers. Do not write MODE labels
41750
41936
  1. DELEGATE all coding to {{AGENT_PREFIX}}coder. You do NOT write code.
41751
41937
  // IMPORTANT: This list MUST match AGENT_TOOL_MAP['architect'] in src/config/constants.ts
41752
41938
  // If you add a tool to the map, add it here. If you remove it from the map, remove it here.
41753
- YOUR TOOLS: Task (delegation), checkpoint, check_gate_status, complexity_hotspots, declare_scope, detect_domains, diff, evidence_check, extract_code_blocks, gitingest, imports, knowledge_query, lint, pkg_audit, pre_check_batch, retrieve_summary, save_plan, schema_drift, secretscan, symbols, test_runner, todo_extract, update_task_status, write_retro.
41939
+ YOUR TOOLS: Task (delegation), build_check, check_gate_status, checkpoint, co_change_analyzer, completion_verify, complexity_hotspots, curator_analyze, declare_scope, detect_domains, diff, doc_extract, doc_scan, evidence_check, extract_code_blocks, gitingest, imports, knowledgeAdd, knowledge_query, knowledgeRecall, knowledgeRemove, lint, phase_complete, pkg_audit, placeholder_scan, pre_check_batch, quality_budget, retrieve_summary, sast_scan, save_plan, sbom_generate, schema_drift, secretscan, symbols, syntax_check, test_runner, todo_extract, update_task_status, write_drift_evidence, write_retro.
41754
41940
  CODER'S TOOLS: write, edit, patch, apply_patch, create_file, insert, replace \u2014 any tool that modifies file contents.
41755
41941
  If a tool modifies a file, it is a CODER tool. Delegate.
41756
41942
  2. ONE agent per message. Send, STOP, wait for response.
@@ -45913,7 +46099,9 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
45913
46099
  const content = await readFile3(shownFile, "utf-8");
45914
46100
  shownData = JSON.parse(content);
45915
46101
  }
45916
- shownData[currentPhase] = lessonIds;
46102
+ const phaseMatch = /^Phase\s+(\d+)/i.exec(currentPhase);
46103
+ const canonicalKey = phaseMatch ? `Phase ${phaseMatch[1]}` : currentPhase;
46104
+ shownData[canonicalKey] = lessonIds;
45917
46105
  await mkdir2(path12.dirname(shownFile), { recursive: true });
45918
46106
  await writeFile2(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
45919
46107
  } catch {
@@ -46637,6 +46825,7 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
46637
46825
  stored++;
46638
46826
  existingEntries.push(entry);
46639
46827
  }
46828
+ await enforceKnowledgeCap(knowledgePath, config3.swarm_max_entries);
46640
46829
  await runAutoPromotion(directory, config3);
46641
46830
  return { stored, skipped, rejected };
46642
46831
  }
@@ -48003,6 +48192,9 @@ async function checkHivePromotions(swarmEntries, config3) {
48003
48192
  if (hiveModified) {
48004
48193
  await rewriteKnowledge(resolveHiveKnowledgePath(), hiveEntries);
48005
48194
  }
48195
+ if (newPromotions > 0 || hiveModified) {
48196
+ await enforceKnowledgeCap(resolveHiveKnowledgePath(), config3.hive_max_entries);
48197
+ }
48006
48198
  return {
48007
48199
  timestamp: new Date().toISOString(),
48008
48200
  new_promotions: newPromotions,
@@ -52176,6 +52368,43 @@ function maskToolOutput(msg, _threshold) {
52176
52368
  }
52177
52369
  return freedTokens;
52178
52370
  }
52371
+ // src/hooks/curator-llm-factory.ts
52372
+ function createCuratorLLMDelegate(directory) {
52373
+ const client = swarmState.opencodeClient;
52374
+ if (!client)
52375
+ return;
52376
+ return async (systemPrompt, userInput) => {
52377
+ let ephemeralSessionId;
52378
+ try {
52379
+ const createResult = await client.session.create({
52380
+ query: { directory }
52381
+ });
52382
+ if (!createResult.data) {
52383
+ throw new Error(`Failed to create curator session: ${JSON.stringify(createResult.error)}`);
52384
+ }
52385
+ ephemeralSessionId = createResult.data.id;
52386
+ const promptResult = await client.session.prompt({
52387
+ path: { id: ephemeralSessionId },
52388
+ body: {
52389
+ agent: "explorer",
52390
+ system: systemPrompt,
52391
+ tools: { write: false, edit: false, patch: false },
52392
+ parts: [{ type: "text", text: userInput }]
52393
+ }
52394
+ });
52395
+ if (!promptResult.data) {
52396
+ throw new Error(`Curator LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
52397
+ }
52398
+ const textParts = promptResult.data.parts.filter((p) => p.type === "text");
52399
+ return textParts.map((p) => p.text).join(`
52400
+ `);
52401
+ } finally {
52402
+ if (ephemeralSessionId) {
52403
+ client.session.delete({ path: { id: ephemeralSessionId } }).catch(() => {});
52404
+ }
52405
+ }
52406
+ };
52407
+ }
52179
52408
  // src/hooks/delegation-gate.ts
52180
52409
  init_schema();
52181
52410
  import * as fs23 from "fs";
@@ -54198,11 +54427,12 @@ function consolidateSystemMessages(messages) {
54198
54427
  // src/hooks/phase-monitor.ts
54199
54428
  init_schema();
54200
54429
  init_manager2();
54201
- import * as path36 from "path";
54430
+ import * as path37 from "path";
54202
54431
  init_utils2();
54203
- function createPhaseMonitorHook(directory, preflightManager, curatorRunner = runCuratorInit) {
54432
+ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, llmDelegate) {
54204
54433
  let lastKnownPhase = null;
54205
54434
  const handler = async (_input, _output) => {
54435
+ const runner = curatorRunner ?? runCuratorInit;
54206
54436
  const plan = await loadPlan(directory);
54207
54437
  if (!plan)
54208
54438
  return;
@@ -54214,12 +54444,29 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner = run
54214
54444
  const { config: config3 } = loadPluginConfigWithMeta2(directory);
54215
54445
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
54216
54446
  if (curatorConfig.enabled && curatorConfig.init_enabled) {
54217
- const initResult = await curatorRunner(directory, curatorConfig);
54447
+ const initResult = await runner(directory, curatorConfig, llmDelegate);
54218
54448
  if (initResult.briefing) {
54219
- const briefingPath = path36.join(directory, ".swarm", "curator-briefing.md");
54449
+ const briefingPath = path37.join(directory, ".swarm", "curator-briefing.md");
54220
54450
  const { mkdir: mkdir5, writeFile: writeFile5 } = await import("fs/promises");
54221
- await mkdir5(path36.dirname(briefingPath), { recursive: true });
54451
+ await mkdir5(path37.dirname(briefingPath), { recursive: true });
54222
54452
  await writeFile5(briefingPath, initResult.briefing, "utf-8");
54453
+ const { buildApprovedReceipt: buildApprovedReceipt2, persistReviewReceipt: persistReviewReceipt2 } = await Promise.resolve().then(() => (init_review_receipt(), exports_review_receipt));
54454
+ const initReceipt = buildApprovedReceipt2({
54455
+ agent: "curator",
54456
+ scopeContent: initResult.briefing,
54457
+ scopeDescription: "curator-init-briefing",
54458
+ checkedAspects: [
54459
+ "knowledge_entries",
54460
+ "prior_phase_summaries",
54461
+ "contradiction_detection"
54462
+ ],
54463
+ validatedClaims: [
54464
+ `knowledge_entries_reviewed: ${initResult.knowledge_entries_reviewed}`,
54465
+ `prior_phases_covered: ${initResult.prior_phases_covered}`,
54466
+ `contradictions: ${initResult.contradictions.length}`
54467
+ ]
54468
+ });
54469
+ persistReviewReceipt2(directory, initReceipt).catch(() => {});
54223
54470
  }
54224
54471
  }
54225
54472
  } catch {}
@@ -54324,21 +54571,25 @@ ${originalText}`;
54324
54571
  })
54325
54572
  };
54326
54573
  }
54574
+
54575
+ // src/hooks/index.ts
54576
+ init_review_receipt();
54577
+
54327
54578
  // src/hooks/system-enhancer.ts
54328
54579
  init_constants();
54329
54580
  init_schema();
54330
54581
  init_manager();
54331
54582
  init_detector();
54332
54583
  init_manager2();
54333
- import * as fs28 from "fs";
54334
- import * as path40 from "path";
54584
+ import * as fs29 from "fs";
54585
+ import * as path41 from "path";
54335
54586
 
54336
54587
  // src/services/decision-drift-analyzer.ts
54337
54588
  init_utils2();
54338
54589
  init_manager2();
54339
54590
  init_utils();
54340
- import * as fs25 from "fs";
54341
- import * as path37 from "path";
54591
+ import * as fs26 from "fs";
54592
+ import * as path38 from "path";
54342
54593
  var DEFAULT_DRIFT_CONFIG = {
54343
54594
  staleThresholdPhases: 1,
54344
54595
  detectContradictions: true,
@@ -54492,11 +54743,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
54492
54743
  currentPhase = legacyPhase;
54493
54744
  }
54494
54745
  }
54495
- const contextPath = path37.join(directory, ".swarm", "context.md");
54746
+ const contextPath = path38.join(directory, ".swarm", "context.md");
54496
54747
  let contextContent = "";
54497
54748
  try {
54498
- if (fs25.existsSync(contextPath)) {
54499
- contextContent = fs25.readFileSync(contextPath, "utf-8");
54749
+ if (fs26.existsSync(contextPath)) {
54750
+ contextContent = fs26.readFileSync(contextPath, "utf-8");
54500
54751
  }
54501
54752
  } catch (error93) {
54502
54753
  log("[DecisionDriftAnalyzer] context file read failed", {
@@ -54621,8 +54872,8 @@ init_utils();
54621
54872
  // src/hooks/adversarial-detector.ts
54622
54873
  init_constants();
54623
54874
  init_schema();
54624
- import * as fs26 from "fs/promises";
54625
- import * as path38 from "path";
54875
+ import * as fs27 from "fs/promises";
54876
+ import * as path39 from "path";
54626
54877
  function safeGet(obj, key) {
54627
54878
  if (!obj || !Object.hasOwn(obj, key))
54628
54879
  return;
@@ -54836,10 +55087,10 @@ async function handleDebuggingSpiral(match, taskId, directory) {
54836
55087
  let eventLogged = false;
54837
55088
  let checkpointCreated = false;
54838
55089
  try {
54839
- const swarmDir = path38.join(directory, ".swarm");
54840
- await fs26.mkdir(swarmDir, { recursive: true });
54841
- const eventsPath = path38.join(swarmDir, "events.jsonl");
54842
- await fs26.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
55090
+ const swarmDir = path39.join(directory, ".swarm");
55091
+ await fs27.mkdir(swarmDir, { recursive: true });
55092
+ const eventsPath = path39.join(swarmDir, "events.jsonl");
55093
+ await fs27.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
54843
55094
  `);
54844
55095
  eventLogged = true;
54845
55096
  } catch {}
@@ -55220,7 +55471,7 @@ function createSystemEnhancerHook(config3, directory) {
55220
55471
  } catch {}
55221
55472
  try {
55222
55473
  const darkMatterPath = validateSwarmPath(directory, "dark-matter.md");
55223
- if (!fs28.existsSync(darkMatterPath)) {
55474
+ if (!fs29.existsSync(darkMatterPath)) {
55224
55475
  const {
55225
55476
  detectDarkMatter: detectDarkMatter2,
55226
55477
  formatDarkMatterOutput: formatDarkMatterOutput2,
@@ -55228,15 +55479,14 @@ function createSystemEnhancerHook(config3, directory) {
55228
55479
  } = await Promise.resolve().then(() => (init_co_change_analyzer(), exports_co_change_analyzer));
55229
55480
  const darkMatter = await detectDarkMatter2(directory, {
55230
55481
  minCommits: 20,
55231
- minCoChanges: 3,
55232
- npmiThreshold: 0.3
55482
+ minCoChanges: 3
55233
55483
  });
55234
55484
  if (darkMatter && darkMatter.length > 0) {
55235
55485
  const darkMatterReport = formatDarkMatterOutput2(darkMatter);
55236
- await fs28.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55486
+ await fs29.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55237
55487
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
55238
55488
  try {
55239
- const projectName = path40.basename(path40.resolve(directory));
55489
+ const projectName = path41.basename(path41.resolve(directory));
55240
55490
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
55241
55491
  const knowledgePath = resolveSwarmKnowledgePath(directory);
55242
55492
  const existingEntries = await readKnowledge(knowledgePath);
@@ -55255,6 +55505,19 @@ function createSystemEnhancerHook(config3, directory) {
55255
55505
  }
55256
55506
  }
55257
55507
  }
55508
+ try {
55509
+ const knowledgePath = resolveSwarmKnowledgePath(directory);
55510
+ const allEntries = await readKnowledge(knowledgePath);
55511
+ const stale = allEntries.filter((e) => e.scope === "project" && e.auto_generated === true && Array.isArray(e.tags) && e.tags.includes("dark-matter"));
55512
+ if (stale.length > 0) {
55513
+ for (const e of stale) {
55514
+ e.scope = "global";
55515
+ e.updated_at = new Date().toISOString();
55516
+ }
55517
+ await rewriteKnowledge(knowledgePath, allEntries);
55518
+ warn(`[system-enhancer] Repaired ${stale.length} dark matter knowledge entries (scope: 'project' \u2192 'global')`);
55519
+ }
55520
+ } catch {}
55258
55521
  } catch {}
55259
55522
  const scoringEnabled = config3.context_budget?.scoring?.enabled === true;
55260
55523
  if (!scoringEnabled) {
@@ -55287,11 +55550,11 @@ function createSystemEnhancerHook(config3, directory) {
55287
55550
  if (handoffContent) {
55288
55551
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55289
55552
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55290
- if (fs28.existsSync(consumedPath)) {
55553
+ if (fs29.existsSync(consumedPath)) {
55291
55554
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55292
- fs28.unlinkSync(consumedPath);
55555
+ fs29.unlinkSync(consumedPath);
55293
55556
  }
55294
- fs28.renameSync(handoffPath, consumedPath);
55557
+ fs29.renameSync(handoffPath, consumedPath);
55295
55558
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55296
55559
  The previous model's session ended. Here is your starting context:
55297
55560
 
@@ -55572,11 +55835,11 @@ ${budgetWarning}`);
55572
55835
  if (handoffContent) {
55573
55836
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55574
55837
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55575
- if (fs28.existsSync(consumedPath)) {
55838
+ if (fs29.existsSync(consumedPath)) {
55576
55839
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55577
- fs28.unlinkSync(consumedPath);
55840
+ fs29.unlinkSync(consumedPath);
55578
55841
  }
55579
- fs28.renameSync(handoffPath, consumedPath);
55842
+ fs29.renameSync(handoffPath, consumedPath);
55580
55843
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55581
55844
  The previous model's session ended. Here is your starting context:
55582
55845
 
@@ -56346,8 +56609,8 @@ function isReadTool(toolName) {
56346
56609
  }
56347
56610
 
56348
56611
  // src/hooks/incremental-verify.ts
56349
- import * as fs29 from "fs";
56350
- import * as path41 from "path";
56612
+ import * as fs30 from "fs";
56613
+ import * as path42 from "path";
56351
56614
 
56352
56615
  // src/hooks/spawn-helper.ts
56353
56616
  import { spawn } from "child_process";
@@ -56422,21 +56685,21 @@ function spawnAsync(command, cwd, timeoutMs) {
56422
56685
  // src/hooks/incremental-verify.ts
56423
56686
  var emittedSkipAdvisories = new Set;
56424
56687
  function detectPackageManager(projectDir) {
56425
- if (fs29.existsSync(path41.join(projectDir, "bun.lockb")))
56688
+ if (fs30.existsSync(path42.join(projectDir, "bun.lockb")))
56426
56689
  return "bun";
56427
- if (fs29.existsSync(path41.join(projectDir, "pnpm-lock.yaml")))
56690
+ if (fs30.existsSync(path42.join(projectDir, "pnpm-lock.yaml")))
56428
56691
  return "pnpm";
56429
- if (fs29.existsSync(path41.join(projectDir, "yarn.lock")))
56692
+ if (fs30.existsSync(path42.join(projectDir, "yarn.lock")))
56430
56693
  return "yarn";
56431
- if (fs29.existsSync(path41.join(projectDir, "package-lock.json")))
56694
+ if (fs30.existsSync(path42.join(projectDir, "package-lock.json")))
56432
56695
  return "npm";
56433
56696
  return "bun";
56434
56697
  }
56435
56698
  function detectTypecheckCommand(projectDir) {
56436
- const pkgPath = path41.join(projectDir, "package.json");
56437
- if (fs29.existsSync(pkgPath)) {
56699
+ const pkgPath = path42.join(projectDir, "package.json");
56700
+ if (fs30.existsSync(pkgPath)) {
56438
56701
  try {
56439
- const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
56702
+ const pkg = JSON.parse(fs30.readFileSync(pkgPath, "utf8"));
56440
56703
  const scripts = pkg.scripts;
56441
56704
  if (scripts?.typecheck) {
56442
56705
  const pm = detectPackageManager(projectDir);
@@ -56450,8 +56713,8 @@ function detectTypecheckCommand(projectDir) {
56450
56713
  ...pkg.dependencies,
56451
56714
  ...pkg.devDependencies
56452
56715
  };
56453
- if (!deps?.typescript && !fs29.existsSync(path41.join(projectDir, "tsconfig.json"))) {}
56454
- const hasTSMarkers = deps?.typescript || fs29.existsSync(path41.join(projectDir, "tsconfig.json"));
56716
+ if (!deps?.typescript && !fs30.existsSync(path42.join(projectDir, "tsconfig.json"))) {}
56717
+ const hasTSMarkers = deps?.typescript || fs30.existsSync(path42.join(projectDir, "tsconfig.json"));
56455
56718
  if (hasTSMarkers) {
56456
56719
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
56457
56720
  }
@@ -56459,17 +56722,17 @@ function detectTypecheckCommand(projectDir) {
56459
56722
  return null;
56460
56723
  }
56461
56724
  }
56462
- if (fs29.existsSync(path41.join(projectDir, "go.mod"))) {
56725
+ if (fs30.existsSync(path42.join(projectDir, "go.mod"))) {
56463
56726
  return { command: ["go", "vet", "./..."], language: "go" };
56464
56727
  }
56465
- if (fs29.existsSync(path41.join(projectDir, "Cargo.toml"))) {
56728
+ if (fs30.existsSync(path42.join(projectDir, "Cargo.toml"))) {
56466
56729
  return { command: ["cargo", "check"], language: "rust" };
56467
56730
  }
56468
- if (fs29.existsSync(path41.join(projectDir, "pyproject.toml")) || fs29.existsSync(path41.join(projectDir, "requirements.txt")) || fs29.existsSync(path41.join(projectDir, "setup.py"))) {
56731
+ if (fs30.existsSync(path42.join(projectDir, "pyproject.toml")) || fs30.existsSync(path42.join(projectDir, "requirements.txt")) || fs30.existsSync(path42.join(projectDir, "setup.py"))) {
56469
56732
  return { command: null, language: "python" };
56470
56733
  }
56471
56734
  try {
56472
- const entries = fs29.readdirSync(projectDir);
56735
+ const entries = fs30.readdirSync(projectDir);
56473
56736
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
56474
56737
  return {
56475
56738
  command: ["dotnet", "build", "--no-restore"],
@@ -56649,19 +56912,7 @@ function sanitizeLessonForContext(text) {
56649
56912
  }
56650
56913
  function isOrchestratorAgent(agentName) {
56651
56914
  const stripped = stripKnownSwarmPrefix(agentName);
56652
- const nonOrchestratorAgents = new Set([
56653
- "coder",
56654
- "reviewer",
56655
- "test_engineer",
56656
- "security_reviewer",
56657
- "integration_analyst",
56658
- "docs_writer",
56659
- "designer",
56660
- "critic",
56661
- "docs",
56662
- "explorer"
56663
- ]);
56664
- return !nonOrchestratorAgents.has(stripped.toLowerCase());
56915
+ return stripped.toLowerCase() === "architect";
56665
56916
  }
56666
56917
  function injectKnowledgeMessage(output, text) {
56667
56918
  if (!output.messages)
@@ -56778,7 +57029,7 @@ ${injectionText}`;
56778
57029
  // src/hooks/scope-guard.ts
56779
57030
  init_constants();
56780
57031
  init_schema();
56781
- import * as path43 from "path";
57032
+ import * as path44 from "path";
56782
57033
  var WRITE_TOOLS = new Set([
56783
57034
  "write",
56784
57035
  "edit",
@@ -56840,13 +57091,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
56840
57091
  }
56841
57092
  function isFileInScope(filePath, scopeEntries, directory) {
56842
57093
  const dir = directory ?? process.cwd();
56843
- const resolvedFile = path43.resolve(dir, filePath);
57094
+ const resolvedFile = path44.resolve(dir, filePath);
56844
57095
  return scopeEntries.some((scope) => {
56845
- const resolvedScope = path43.resolve(dir, scope);
57096
+ const resolvedScope = path44.resolve(dir, scope);
56846
57097
  if (resolvedFile === resolvedScope)
56847
57098
  return true;
56848
- const rel = path43.relative(resolvedScope, resolvedFile);
56849
- return rel.length > 0 && !rel.startsWith("..") && !path43.isAbsolute(rel);
57099
+ const rel = path44.relative(resolvedScope, resolvedFile);
57100
+ return rel.length > 0 && !rel.startsWith("..") && !path44.isAbsolute(rel);
56850
57101
  });
56851
57102
  }
56852
57103
 
@@ -56895,8 +57146,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
56895
57146
  }
56896
57147
 
56897
57148
  // src/hooks/slop-detector.ts
56898
- import * as fs31 from "fs";
56899
- import * as path44 from "path";
57149
+ import * as fs32 from "fs";
57150
+ import * as path45 from "path";
56900
57151
  var WRITE_EDIT_TOOLS = new Set([
56901
57152
  "write",
56902
57153
  "edit",
@@ -56941,12 +57192,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
56941
57192
  function walkFiles(dir, exts, deadline) {
56942
57193
  const results = [];
56943
57194
  try {
56944
- for (const entry of fs31.readdirSync(dir, { withFileTypes: true })) {
57195
+ for (const entry of fs32.readdirSync(dir, { withFileTypes: true })) {
56945
57196
  if (deadline !== undefined && Date.now() > deadline)
56946
57197
  break;
56947
57198
  if (entry.isSymbolicLink())
56948
57199
  continue;
56949
- const full = path44.join(dir, entry.name);
57200
+ const full = path45.join(dir, entry.name);
56950
57201
  if (entry.isDirectory()) {
56951
57202
  if (entry.name === "node_modules" || entry.name === ".git")
56952
57203
  continue;
@@ -56961,7 +57212,7 @@ function walkFiles(dir, exts, deadline) {
56961
57212
  return results;
56962
57213
  }
56963
57214
  function checkDeadExports(content, projectDir, startTime) {
56964
- const hasPackageJson = fs31.existsSync(path44.join(projectDir, "package.json"));
57215
+ const hasPackageJson = fs32.existsSync(path45.join(projectDir, "package.json"));
56965
57216
  if (!hasPackageJson)
56966
57217
  return null;
56967
57218
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -56984,7 +57235,7 @@ function checkDeadExports(content, projectDir, startTime) {
56984
57235
  if (found || Date.now() - startTime > 480)
56985
57236
  break;
56986
57237
  try {
56987
- const text = fs31.readFileSync(file3, "utf-8");
57238
+ const text = fs32.readFileSync(file3, "utf-8");
56988
57239
  if (importPattern.test(text))
56989
57240
  found = true;
56990
57241
  importPattern.lastIndex = 0;
@@ -57117,7 +57368,7 @@ Review before proceeding.`;
57117
57368
 
57118
57369
  // src/hooks/steering-consumed.ts
57119
57370
  init_utils2();
57120
- import * as fs32 from "fs";
57371
+ import * as fs33 from "fs";
57121
57372
  function recordSteeringConsumed(directory, directiveId) {
57122
57373
  try {
57123
57374
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -57126,7 +57377,7 @@ function recordSteeringConsumed(directory, directiveId) {
57126
57377
  directiveId,
57127
57378
  timestamp: new Date().toISOString()
57128
57379
  };
57129
- fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
57380
+ fs33.appendFileSync(eventsPath, `${JSON.stringify(event)}
57130
57381
  `, "utf-8");
57131
57382
  } catch {}
57132
57383
  }
@@ -57171,7 +57422,7 @@ init_config_doctor();
57171
57422
 
57172
57423
  // src/session/snapshot-reader.ts
57173
57424
  init_utils2();
57174
- import { renameSync as renameSync11 } from "fs";
57425
+ import { renameSync as renameSync12 } from "fs";
57175
57426
  var TRANSIENT_SESSION_FIELDS = [
57176
57427
  { name: "revisionLimitHit", resetValue: false },
57177
57428
  { name: "coderRevisions", resetValue: 0 },
@@ -57282,7 +57533,7 @@ async function readSnapshot(directory) {
57282
57533
  if (parsed.version !== 1 && parsed.version !== 2) {
57283
57534
  try {
57284
57535
  const quarantinePath = validateSwarmPath(directory, "session/state.json.quarantine");
57285
- renameSync11(resolvedPath, quarantinePath);
57536
+ renameSync12(resolvedPath, quarantinePath);
57286
57537
  } catch {}
57287
57538
  return null;
57288
57539
  }
@@ -57539,8 +57790,8 @@ init_dist();
57539
57790
  init_manager();
57540
57791
  init_create_tool();
57541
57792
  init_resolve_working_directory();
57542
- import * as fs33 from "fs";
57543
- import * as path45 from "path";
57793
+ import * as fs34 from "fs";
57794
+ import * as path46 from "path";
57544
57795
  var EVIDENCE_DIR = ".swarm/evidence";
57545
57796
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
57546
57797
  function isValidTaskId3(taskId) {
@@ -57557,18 +57808,18 @@ function isValidTaskId3(taskId) {
57557
57808
  return TASK_ID_PATTERN2.test(taskId);
57558
57809
  }
57559
57810
  function isPathWithinSwarm(filePath, workspaceRoot) {
57560
- const normalizedWorkspace = path45.resolve(workspaceRoot);
57561
- const swarmPath = path45.join(normalizedWorkspace, ".swarm", "evidence");
57562
- const normalizedPath = path45.resolve(filePath);
57811
+ const normalizedWorkspace = path46.resolve(workspaceRoot);
57812
+ const swarmPath = path46.join(normalizedWorkspace, ".swarm", "evidence");
57813
+ const normalizedPath = path46.resolve(filePath);
57563
57814
  return normalizedPath.startsWith(swarmPath);
57564
57815
  }
57565
57816
  function readEvidenceFile(evidencePath) {
57566
- if (!fs33.existsSync(evidencePath)) {
57817
+ if (!fs34.existsSync(evidencePath)) {
57567
57818
  return null;
57568
57819
  }
57569
57820
  let content;
57570
57821
  try {
57571
- content = fs33.readFileSync(evidencePath, "utf-8");
57822
+ content = fs34.readFileSync(evidencePath, "utf-8");
57572
57823
  } catch {
57573
57824
  return null;
57574
57825
  }
@@ -57640,7 +57891,7 @@ var check_gate_status = createSwarmTool({
57640
57891
  };
57641
57892
  return JSON.stringify(errorResult, null, 2);
57642
57893
  }
57643
- const evidencePath = path45.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57894
+ const evidencePath = path46.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57644
57895
  if (!isPathWithinSwarm(evidencePath, directory)) {
57645
57896
  const errorResult = {
57646
57897
  taskId: taskIdInput,
@@ -57733,8 +57984,8 @@ init_co_change_analyzer();
57733
57984
  // src/tools/completion-verify.ts
57734
57985
  init_dist();
57735
57986
  init_utils2();
57736
- import * as fs34 from "fs";
57737
- import * as path46 from "path";
57987
+ import * as fs35 from "fs";
57988
+ import * as path47 from "path";
57738
57989
  init_create_tool();
57739
57990
  init_resolve_working_directory();
57740
57991
  function extractMatches(regex, text) {
@@ -57830,7 +58081,7 @@ async function executeCompletionVerify(args2, directory) {
57830
58081
  let plan;
57831
58082
  try {
57832
58083
  const planPath = validateSwarmPath(directory, "plan.json");
57833
- const planRaw = fs34.readFileSync(planPath, "utf-8");
58084
+ const planRaw = fs35.readFileSync(planPath, "utf-8");
57834
58085
  plan = JSON.parse(planRaw);
57835
58086
  } catch {
57836
58087
  const result2 = {
@@ -57888,10 +58139,10 @@ async function executeCompletionVerify(args2, directory) {
57888
58139
  let hasFileReadFailure = false;
57889
58140
  for (const filePath of fileTargets) {
57890
58141
  const normalizedPath = filePath.replace(/\\/g, "/");
57891
- const resolvedPath = path46.resolve(directory, normalizedPath);
57892
- const projectRoot = path46.resolve(directory);
57893
- const relative6 = path46.relative(projectRoot, resolvedPath);
57894
- const withinProject = relative6 === "" || !relative6.startsWith("..") && !path46.isAbsolute(relative6);
58142
+ const resolvedPath = path47.resolve(directory, normalizedPath);
58143
+ const projectRoot = path47.resolve(directory);
58144
+ const relative6 = path47.relative(projectRoot, resolvedPath);
58145
+ const withinProject = relative6 === "" || !relative6.startsWith("..") && !path47.isAbsolute(relative6);
57895
58146
  if (!withinProject) {
57896
58147
  blockedTasks.push({
57897
58148
  task_id: task.id,
@@ -57904,7 +58155,7 @@ async function executeCompletionVerify(args2, directory) {
57904
58155
  }
57905
58156
  let fileContent;
57906
58157
  try {
57907
- fileContent = fs34.readFileSync(resolvedPath, "utf-8");
58158
+ fileContent = fs35.readFileSync(resolvedPath, "utf-8");
57908
58159
  } catch {
57909
58160
  blockedTasks.push({
57910
58161
  task_id: task.id,
@@ -57946,9 +58197,9 @@ async function executeCompletionVerify(args2, directory) {
57946
58197
  blockedTasks
57947
58198
  };
57948
58199
  try {
57949
- const evidenceDir = path46.join(directory, ".swarm", "evidence", `${phase}`);
57950
- const evidencePath = path46.join(evidenceDir, "completion-verify.json");
57951
- fs34.mkdirSync(evidenceDir, { recursive: true });
58200
+ const evidenceDir = path47.join(directory, ".swarm", "evidence", `${phase}`);
58201
+ const evidencePath = path47.join(evidenceDir, "completion-verify.json");
58202
+ fs35.mkdirSync(evidenceDir, { recursive: true });
57952
58203
  const evidenceBundle = {
57953
58204
  schema_version: "1.0.0",
57954
58205
  task_id: "completion-verify",
@@ -57969,7 +58220,7 @@ async function executeCompletionVerify(args2, directory) {
57969
58220
  }
57970
58221
  ]
57971
58222
  };
57972
- fs34.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
58223
+ fs35.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57973
58224
  } catch {}
57974
58225
  return JSON.stringify(result, null, 2);
57975
58226
  }
@@ -58023,12 +58274,12 @@ var completion_verify = createSwarmTool({
58023
58274
  });
58024
58275
  // src/tools/complexity-hotspots.ts
58025
58276
  init_dist();
58026
- import * as fs36 from "fs";
58027
- import * as path48 from "path";
58277
+ import * as fs37 from "fs";
58278
+ import * as path49 from "path";
58028
58279
 
58029
58280
  // src/quality/metrics.ts
58030
- import * as fs35 from "fs";
58031
- import * as path47 from "path";
58281
+ import * as fs36 from "fs";
58282
+ import * as path48 from "path";
58032
58283
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
58033
58284
  var MIN_DUPLICATION_LINES = 10;
58034
58285
  function estimateCyclomaticComplexity(content) {
@@ -58066,11 +58317,11 @@ function estimateCyclomaticComplexity(content) {
58066
58317
  }
58067
58318
  function getComplexityForFile(filePath) {
58068
58319
  try {
58069
- const stat2 = fs35.statSync(filePath);
58320
+ const stat2 = fs36.statSync(filePath);
58070
58321
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58071
58322
  return null;
58072
58323
  }
58073
- const content = fs35.readFileSync(filePath, "utf-8");
58324
+ const content = fs36.readFileSync(filePath, "utf-8");
58074
58325
  return estimateCyclomaticComplexity(content);
58075
58326
  } catch {
58076
58327
  return null;
@@ -58080,8 +58331,8 @@ async function computeComplexityDelta(files, workingDir) {
58080
58331
  let totalComplexity = 0;
58081
58332
  const analyzedFiles = [];
58082
58333
  for (const file3 of files) {
58083
- const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58084
- if (!fs35.existsSync(fullPath)) {
58334
+ const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
58335
+ if (!fs36.existsSync(fullPath)) {
58085
58336
  continue;
58086
58337
  }
58087
58338
  const complexity = getComplexityForFile(fullPath);
@@ -58202,8 +58453,8 @@ function countGoExports(content) {
58202
58453
  }
58203
58454
  function getExportCountForFile(filePath) {
58204
58455
  try {
58205
- const content = fs35.readFileSync(filePath, "utf-8");
58206
- const ext = path47.extname(filePath).toLowerCase();
58456
+ const content = fs36.readFileSync(filePath, "utf-8");
58457
+ const ext = path48.extname(filePath).toLowerCase();
58207
58458
  switch (ext) {
58208
58459
  case ".ts":
58209
58460
  case ".tsx":
@@ -58229,8 +58480,8 @@ async function computePublicApiDelta(files, workingDir) {
58229
58480
  let totalExports = 0;
58230
58481
  const analyzedFiles = [];
58231
58482
  for (const file3 of files) {
58232
- const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58233
- if (!fs35.existsSync(fullPath)) {
58483
+ const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
58484
+ if (!fs36.existsSync(fullPath)) {
58234
58485
  continue;
58235
58486
  }
58236
58487
  const exports = getExportCountForFile(fullPath);
@@ -58263,16 +58514,16 @@ async function computeDuplicationRatio(files, workingDir) {
58263
58514
  let duplicateLines = 0;
58264
58515
  const analyzedFiles = [];
58265
58516
  for (const file3 of files) {
58266
- const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58267
- if (!fs35.existsSync(fullPath)) {
58517
+ const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
58518
+ if (!fs36.existsSync(fullPath)) {
58268
58519
  continue;
58269
58520
  }
58270
58521
  try {
58271
- const stat2 = fs35.statSync(fullPath);
58522
+ const stat2 = fs36.statSync(fullPath);
58272
58523
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58273
58524
  continue;
58274
58525
  }
58275
- const content = fs35.readFileSync(fullPath, "utf-8");
58526
+ const content = fs36.readFileSync(fullPath, "utf-8");
58276
58527
  const lines = content.split(`
58277
58528
  `).filter((line) => line.trim().length > 0);
58278
58529
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -58296,8 +58547,8 @@ function countCodeLines(content) {
58296
58547
  return lines.length;
58297
58548
  }
58298
58549
  function isTestFile(filePath) {
58299
- const basename7 = path47.basename(filePath);
58300
- const _ext = path47.extname(filePath).toLowerCase();
58550
+ const basename7 = path48.basename(filePath);
58551
+ const _ext = path48.extname(filePath).toLowerCase();
58301
58552
  const testPatterns = [
58302
58553
  ".test.",
58303
58554
  ".spec.",
@@ -58378,8 +58629,8 @@ function matchGlobSegment(globSegments, pathSegments) {
58378
58629
  }
58379
58630
  return gIndex === globSegments.length && pIndex === pathSegments.length;
58380
58631
  }
58381
- function matchesGlobSegment(path48, glob) {
58382
- const normalizedPath = path48.replace(/\\/g, "/");
58632
+ function matchesGlobSegment(path49, glob) {
58633
+ const normalizedPath = path49.replace(/\\/g, "/");
58383
58634
  const normalizedGlob = glob.replace(/\\/g, "/");
58384
58635
  if (normalizedPath.includes("//")) {
58385
58636
  return false;
@@ -58410,8 +58661,8 @@ function simpleGlobToRegex2(glob) {
58410
58661
  function hasGlobstar(glob) {
58411
58662
  return glob.includes("**");
58412
58663
  }
58413
- function globMatches(path48, glob) {
58414
- const normalizedPath = path48.replace(/\\/g, "/");
58664
+ function globMatches(path49, glob) {
58665
+ const normalizedPath = path49.replace(/\\/g, "/");
58415
58666
  if (!glob || glob === "") {
58416
58667
  if (normalizedPath.includes("//")) {
58417
58668
  return false;
@@ -58447,31 +58698,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
58447
58698
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58448
58699
  let testLines = 0;
58449
58700
  let codeLines = 0;
58450
- const srcDir = path47.join(workingDir, "src");
58451
- if (fs35.existsSync(srcDir)) {
58701
+ const srcDir = path48.join(workingDir, "src");
58702
+ if (fs36.existsSync(srcDir)) {
58452
58703
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
58453
58704
  codeLines += lines;
58454
58705
  });
58455
58706
  }
58456
58707
  const possibleSrcDirs = ["lib", "app", "source", "core"];
58457
58708
  for (const dir of possibleSrcDirs) {
58458
- const dirPath = path47.join(workingDir, dir);
58459
- if (fs35.existsSync(dirPath)) {
58709
+ const dirPath = path48.join(workingDir, dir);
58710
+ if (fs36.existsSync(dirPath)) {
58460
58711
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
58461
58712
  codeLines += lines;
58462
58713
  });
58463
58714
  }
58464
58715
  }
58465
- const testsDir = path47.join(workingDir, "tests");
58466
- if (fs35.existsSync(testsDir)) {
58716
+ const testsDir = path48.join(workingDir, "tests");
58717
+ if (fs36.existsSync(testsDir)) {
58467
58718
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
58468
58719
  testLines += lines;
58469
58720
  });
58470
58721
  }
58471
58722
  const possibleTestDirs = ["test", "__tests__", "specs"];
58472
58723
  for (const dir of possibleTestDirs) {
58473
- const dirPath = path47.join(workingDir, dir);
58474
- if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
58724
+ const dirPath = path48.join(workingDir, dir);
58725
+ if (fs36.existsSync(dirPath) && dirPath !== testsDir) {
58475
58726
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
58476
58727
  testLines += lines;
58477
58728
  });
@@ -58483,9 +58734,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58483
58734
  }
58484
58735
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
58485
58736
  try {
58486
- const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
58737
+ const entries = fs36.readdirSync(dirPath, { withFileTypes: true });
58487
58738
  for (const entry of entries) {
58488
- const fullPath = path47.join(dirPath, entry.name);
58739
+ const fullPath = path48.join(dirPath, entry.name);
58489
58740
  if (entry.isDirectory()) {
58490
58741
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
58491
58742
  continue;
@@ -58493,7 +58744,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58493
58744
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
58494
58745
  } else if (entry.isFile()) {
58495
58746
  const relativePath = fullPath.replace(`${dirPath}/`, "");
58496
- const ext = path47.extname(entry.name).toLowerCase();
58747
+ const ext = path48.extname(entry.name).toLowerCase();
58497
58748
  const validExts = [
58498
58749
  ".ts",
58499
58750
  ".tsx",
@@ -58529,7 +58780,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58529
58780
  continue;
58530
58781
  }
58531
58782
  try {
58532
- const content = fs35.readFileSync(fullPath, "utf-8");
58783
+ const content = fs36.readFileSync(fullPath, "utf-8");
58533
58784
  const lines = countCodeLines(content);
58534
58785
  callback(lines);
58535
58786
  } catch {}
@@ -58730,11 +58981,11 @@ async function getGitChurn(days, directory) {
58730
58981
  }
58731
58982
  function getComplexityForFile2(filePath) {
58732
58983
  try {
58733
- const stat2 = fs36.statSync(filePath);
58984
+ const stat2 = fs37.statSync(filePath);
58734
58985
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
58735
58986
  return null;
58736
58987
  }
58737
- const content = fs36.readFileSync(filePath, "utf-8");
58988
+ const content = fs37.readFileSync(filePath, "utf-8");
58738
58989
  return estimateCyclomaticComplexity(content);
58739
58990
  } catch {
58740
58991
  return null;
@@ -58745,7 +58996,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58745
58996
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
58746
58997
  const filteredChurn = new Map;
58747
58998
  for (const [file3, count] of churnMap) {
58748
- const ext = path48.extname(file3).toLowerCase();
58999
+ const ext = path49.extname(file3).toLowerCase();
58749
59000
  if (extSet.has(ext)) {
58750
59001
  filteredChurn.set(file3, count);
58751
59002
  }
@@ -58755,8 +59006,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58755
59006
  let analyzedFiles = 0;
58756
59007
  for (const [file3, churnCount] of filteredChurn) {
58757
59008
  let fullPath = file3;
58758
- if (!fs36.existsSync(fullPath)) {
58759
- fullPath = path48.join(cwd, file3);
59009
+ if (!fs37.existsSync(fullPath)) {
59010
+ fullPath = path49.join(cwd, file3);
58760
59011
  }
58761
59012
  const complexity = getComplexityForFile2(fullPath);
58762
59013
  if (complexity !== null) {
@@ -58905,6 +59156,7 @@ var complexity_hotspots = createSwarmTool({
58905
59156
  init_dist();
58906
59157
  init_config();
58907
59158
  init_schema();
59159
+ init_review_receipt();
58908
59160
  init_create_tool();
58909
59161
  var curator_analyze = createSwarmTool({
58910
59162
  description: "Run curator phase analysis and optionally apply knowledge recommendations. " + "Call this after reviewing a phase to apply knowledge updates. " + "If recommendations is provided, applies them via applyCuratorKnowledgeUpdates.",
@@ -58940,7 +59192,40 @@ var curator_analyze = createSwarmTool({
58940
59192
  const { config: config3 } = loadPluginConfigWithMeta(directory);
58941
59193
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
58942
59194
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
58943
- const curatorResult = await runCuratorPhase(directory, typedArgs.phase, [], curatorConfig, {});
59195
+ const llmDelegate = createCuratorLLMDelegate(directory);
59196
+ const curatorResult = await runCuratorPhase(directory, typedArgs.phase, [], curatorConfig, {}, llmDelegate);
59197
+ {
59198
+ const scopeContent = curatorResult.digest?.summary ?? `Phase ${typedArgs.phase} curator analysis`;
59199
+ const complianceWarnings = curatorResult.compliance.filter((c) => c.severity === "warning");
59200
+ const receipt = complianceWarnings.length > 0 ? buildRejectedReceipt({
59201
+ agent: "curator",
59202
+ scopeContent,
59203
+ scopeDescription: "phase-digest",
59204
+ blockingFindings: complianceWarnings.map((c) => ({
59205
+ location: `phase-${c.phase}`,
59206
+ summary: c.description,
59207
+ severity: c.type === "missing_reviewer" ? "high" : "medium"
59208
+ })),
59209
+ evidenceReferences: [],
59210
+ passConditions: [
59211
+ "resolve all compliance warnings before phase completion"
59212
+ ]
59213
+ }) : buildApprovedReceipt({
59214
+ agent: "curator",
59215
+ scopeContent,
59216
+ scopeDescription: "phase-digest",
59217
+ checkedAspects: [
59218
+ "phase_compliance",
59219
+ "knowledge_recommendations",
59220
+ "phase_digest"
59221
+ ],
59222
+ validatedClaims: [
59223
+ `phase: ${typedArgs.phase}`,
59224
+ `knowledge_recommendations: ${curatorResult.knowledge_recommendations.length}`
59225
+ ]
59226
+ });
59227
+ persistReviewReceipt(directory, receipt).catch(() => {});
59228
+ }
58944
59229
  let applied = 0;
58945
59230
  let skipped = 0;
58946
59231
  if (typedArgs.recommendations && typedArgs.recommendations.length > 0) {
@@ -58964,8 +59249,8 @@ var curator_analyze = createSwarmTool({
58964
59249
  });
58965
59250
  // src/tools/declare-scope.ts
58966
59251
  init_tool();
58967
- import * as fs37 from "fs";
58968
- import * as path49 from "path";
59252
+ import * as fs38 from "fs";
59253
+ import * as path50 from "path";
58969
59254
  init_create_tool();
58970
59255
  function validateTaskIdFormat(taskId) {
58971
59256
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -59044,8 +59329,8 @@ async function executeDeclareScope(args2, fallbackDir) {
59044
59329
  };
59045
59330
  }
59046
59331
  }
59047
- normalizedDir = path49.normalize(args2.working_directory);
59048
- const pathParts = normalizedDir.split(path49.sep);
59332
+ normalizedDir = path50.normalize(args2.working_directory);
59333
+ const pathParts = normalizedDir.split(path50.sep);
59049
59334
  if (pathParts.includes("..")) {
59050
59335
  return {
59051
59336
  success: false,
@@ -59055,11 +59340,11 @@ async function executeDeclareScope(args2, fallbackDir) {
59055
59340
  ]
59056
59341
  };
59057
59342
  }
59058
- const resolvedDir = path49.resolve(normalizedDir);
59343
+ const resolvedDir = path50.resolve(normalizedDir);
59059
59344
  try {
59060
- const realPath = fs37.realpathSync(resolvedDir);
59061
- const planPath2 = path49.join(realPath, ".swarm", "plan.json");
59062
- if (!fs37.existsSync(planPath2)) {
59345
+ const realPath = fs38.realpathSync(resolvedDir);
59346
+ const planPath2 = path50.join(realPath, ".swarm", "plan.json");
59347
+ if (!fs38.existsSync(planPath2)) {
59063
59348
  return {
59064
59349
  success: false,
59065
59350
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -59082,8 +59367,8 @@ async function executeDeclareScope(args2, fallbackDir) {
59082
59367
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
59083
59368
  }
59084
59369
  const directory = normalizedDir || fallbackDir;
59085
- const planPath = path49.resolve(directory, ".swarm", "plan.json");
59086
- if (!fs37.existsSync(planPath)) {
59370
+ const planPath = path50.resolve(directory, ".swarm", "plan.json");
59371
+ if (!fs38.existsSync(planPath)) {
59087
59372
  return {
59088
59373
  success: false,
59089
59374
  message: "No plan found",
@@ -59092,7 +59377,7 @@ async function executeDeclareScope(args2, fallbackDir) {
59092
59377
  }
59093
59378
  let planContent;
59094
59379
  try {
59095
- planContent = JSON.parse(fs37.readFileSync(planPath, "utf-8"));
59380
+ planContent = JSON.parse(fs38.readFileSync(planPath, "utf-8"));
59096
59381
  } catch {
59097
59382
  return {
59098
59383
  success: false,
@@ -59124,8 +59409,8 @@ async function executeDeclareScope(args2, fallbackDir) {
59124
59409
  const normalizeErrors = [];
59125
59410
  const dir = normalizedDir || fallbackDir || process.cwd();
59126
59411
  const mergedFiles = rawMergedFiles.map((file3) => {
59127
- if (path49.isAbsolute(file3)) {
59128
- const relativePath = path49.relative(dir, file3).replace(/\\/g, "/");
59412
+ if (path50.isAbsolute(file3)) {
59413
+ const relativePath = path50.relative(dir, file3).replace(/\\/g, "/");
59129
59414
  if (relativePath.startsWith("..")) {
59130
59415
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
59131
59416
  return file3;
@@ -59451,20 +59736,20 @@ function validateBase(base) {
59451
59736
  function validatePaths(paths) {
59452
59737
  if (!paths)
59453
59738
  return null;
59454
- for (const path51 of paths) {
59455
- if (!path51 || path51.length === 0) {
59739
+ for (const path52 of paths) {
59740
+ if (!path52 || path52.length === 0) {
59456
59741
  return "empty path not allowed";
59457
59742
  }
59458
- if (path51.length > MAX_PATH_LENGTH) {
59743
+ if (path52.length > MAX_PATH_LENGTH) {
59459
59744
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
59460
59745
  }
59461
- if (SHELL_METACHARACTERS2.test(path51)) {
59746
+ if (SHELL_METACHARACTERS2.test(path52)) {
59462
59747
  return "path contains shell metacharacters";
59463
59748
  }
59464
- if (path51.startsWith("-")) {
59749
+ if (path52.startsWith("-")) {
59465
59750
  return 'path cannot start with "-" (option-like arguments not allowed)';
59466
59751
  }
59467
- if (CONTROL_CHAR_PATTERN2.test(path51)) {
59752
+ if (CONTROL_CHAR_PATTERN2.test(path52)) {
59468
59753
  return "path contains control characters";
59469
59754
  }
59470
59755
  }
@@ -59545,8 +59830,8 @@ var diff = createSwarmTool({
59545
59830
  if (parts2.length >= 3) {
59546
59831
  const additions = parseInt(parts2[0], 10) || 0;
59547
59832
  const deletions = parseInt(parts2[1], 10) || 0;
59548
- const path51 = parts2[2];
59549
- files.push({ path: path51, additions, deletions });
59833
+ const path52 = parts2[2];
59834
+ files.push({ path: path52, additions, deletions });
59550
59835
  }
59551
59836
  }
59552
59837
  const contractChanges = [];
@@ -59828,8 +60113,8 @@ Use these as DOMAIN values when delegating to @sme.`;
59828
60113
  // src/tools/evidence-check.ts
59829
60114
  init_dist();
59830
60115
  init_create_tool();
59831
- import * as fs38 from "fs";
59832
- import * as path51 from "path";
60116
+ import * as fs39 from "fs";
60117
+ import * as path52 from "path";
59833
60118
  var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
59834
60119
  var MAX_EVIDENCE_FILES = 1000;
59835
60120
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -59856,9 +60141,9 @@ function validateRequiredTypes(input) {
59856
60141
  return null;
59857
60142
  }
59858
60143
  function isPathWithinSwarm2(filePath, cwd) {
59859
- const normalizedCwd = path51.resolve(cwd);
59860
- const swarmPath = path51.join(normalizedCwd, ".swarm");
59861
- const normalizedPath = path51.resolve(filePath);
60144
+ const normalizedCwd = path52.resolve(cwd);
60145
+ const swarmPath = path52.join(normalizedCwd, ".swarm");
60146
+ const normalizedPath = path52.resolve(filePath);
59862
60147
  return normalizedPath.startsWith(swarmPath);
59863
60148
  }
59864
60149
  function parseCompletedTasks(planContent) {
@@ -59874,12 +60159,12 @@ function parseCompletedTasks(planContent) {
59874
60159
  }
59875
60160
  function readEvidenceFiles(evidenceDir, _cwd) {
59876
60161
  const evidence = [];
59877
- if (!fs38.existsSync(evidenceDir) || !fs38.statSync(evidenceDir).isDirectory()) {
60162
+ if (!fs39.existsSync(evidenceDir) || !fs39.statSync(evidenceDir).isDirectory()) {
59878
60163
  return evidence;
59879
60164
  }
59880
60165
  let files;
59881
60166
  try {
59882
- files = fs38.readdirSync(evidenceDir);
60167
+ files = fs39.readdirSync(evidenceDir);
59883
60168
  } catch {
59884
60169
  return evidence;
59885
60170
  }
@@ -59888,14 +60173,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59888
60173
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
59889
60174
  continue;
59890
60175
  }
59891
- const filePath = path51.join(evidenceDir, filename);
60176
+ const filePath = path52.join(evidenceDir, filename);
59892
60177
  try {
59893
- const resolvedPath = path51.resolve(filePath);
59894
- const evidenceDirResolved = path51.resolve(evidenceDir);
60178
+ const resolvedPath = path52.resolve(filePath);
60179
+ const evidenceDirResolved = path52.resolve(evidenceDir);
59895
60180
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
59896
60181
  continue;
59897
60182
  }
59898
- const stat2 = fs38.lstatSync(filePath);
60183
+ const stat2 = fs39.lstatSync(filePath);
59899
60184
  if (!stat2.isFile()) {
59900
60185
  continue;
59901
60186
  }
@@ -59904,7 +60189,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59904
60189
  }
59905
60190
  let fileStat;
59906
60191
  try {
59907
- fileStat = fs38.statSync(filePath);
60192
+ fileStat = fs39.statSync(filePath);
59908
60193
  if (fileStat.size > MAX_FILE_SIZE_BYTES4) {
59909
60194
  continue;
59910
60195
  }
@@ -59913,7 +60198,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59913
60198
  }
59914
60199
  let content;
59915
60200
  try {
59916
- content = fs38.readFileSync(filePath, "utf-8");
60201
+ content = fs39.readFileSync(filePath, "utf-8");
59917
60202
  } catch {
59918
60203
  continue;
59919
60204
  }
@@ -60009,7 +60294,7 @@ var evidence_check = createSwarmTool({
60009
60294
  return JSON.stringify(errorResult, null, 2);
60010
60295
  }
60011
60296
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
60012
- const planPath = path51.join(cwd, PLAN_FILE);
60297
+ const planPath = path52.join(cwd, PLAN_FILE);
60013
60298
  if (!isPathWithinSwarm2(planPath, cwd)) {
60014
60299
  const errorResult = {
60015
60300
  error: "plan file path validation failed",
@@ -60023,7 +60308,7 @@ var evidence_check = createSwarmTool({
60023
60308
  }
60024
60309
  let planContent;
60025
60310
  try {
60026
- planContent = fs38.readFileSync(planPath, "utf-8");
60311
+ planContent = fs39.readFileSync(planPath, "utf-8");
60027
60312
  } catch {
60028
60313
  const result2 = {
60029
60314
  message: "No completed tasks found in plan.",
@@ -60041,7 +60326,7 @@ var evidence_check = createSwarmTool({
60041
60326
  };
60042
60327
  return JSON.stringify(result2, null, 2);
60043
60328
  }
60044
- const evidenceDir = path51.join(cwd, EVIDENCE_DIR2);
60329
+ const evidenceDir = path52.join(cwd, EVIDENCE_DIR2);
60045
60330
  const evidence = readEvidenceFiles(evidenceDir, cwd);
60046
60331
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
60047
60332
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -60058,8 +60343,8 @@ var evidence_check = createSwarmTool({
60058
60343
  // src/tools/file-extractor.ts
60059
60344
  init_tool();
60060
60345
  init_create_tool();
60061
- import * as fs39 from "fs";
60062
- import * as path52 from "path";
60346
+ import * as fs40 from "fs";
60347
+ import * as path53 from "path";
60063
60348
  var EXT_MAP = {
60064
60349
  python: ".py",
60065
60350
  py: ".py",
@@ -60121,8 +60406,8 @@ var extract_code_blocks = createSwarmTool({
60121
60406
  execute: async (args2, directory) => {
60122
60407
  const { content, output_dir, prefix } = args2;
60123
60408
  const targetDir = output_dir || directory;
60124
- if (!fs39.existsSync(targetDir)) {
60125
- fs39.mkdirSync(targetDir, { recursive: true });
60409
+ if (!fs40.existsSync(targetDir)) {
60410
+ fs40.mkdirSync(targetDir, { recursive: true });
60126
60411
  }
60127
60412
  if (!content) {
60128
60413
  return "Error: content is required";
@@ -60140,16 +60425,16 @@ var extract_code_blocks = createSwarmTool({
60140
60425
  if (prefix) {
60141
60426
  filename = `${prefix}_${filename}`;
60142
60427
  }
60143
- let filepath = path52.join(targetDir, filename);
60144
- const base = path52.basename(filepath, path52.extname(filepath));
60145
- const ext = path52.extname(filepath);
60428
+ let filepath = path53.join(targetDir, filename);
60429
+ const base = path53.basename(filepath, path53.extname(filepath));
60430
+ const ext = path53.extname(filepath);
60146
60431
  let counter = 1;
60147
- while (fs39.existsSync(filepath)) {
60148
- filepath = path52.join(targetDir, `${base}_${counter}${ext}`);
60432
+ while (fs40.existsSync(filepath)) {
60433
+ filepath = path53.join(targetDir, `${base}_${counter}${ext}`);
60149
60434
  counter++;
60150
60435
  }
60151
60436
  try {
60152
- fs39.writeFileSync(filepath, code.trim(), "utf-8");
60437
+ fs40.writeFileSync(filepath, code.trim(), "utf-8");
60153
60438
  savedFiles.push(filepath);
60154
60439
  } catch (error93) {
60155
60440
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -60265,8 +60550,8 @@ var gitingest = createSwarmTool({
60265
60550
  // src/tools/imports.ts
60266
60551
  init_dist();
60267
60552
  init_create_tool();
60268
- import * as fs40 from "fs";
60269
- import * as path53 from "path";
60553
+ import * as fs41 from "fs";
60554
+ import * as path54 from "path";
60270
60555
  var MAX_FILE_PATH_LENGTH2 = 500;
60271
60556
  var MAX_SYMBOL_LENGTH = 256;
60272
60557
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
@@ -60314,7 +60599,7 @@ function validateSymbolInput(symbol3) {
60314
60599
  return null;
60315
60600
  }
60316
60601
  function isBinaryFile2(filePath, buffer) {
60317
- const ext = path53.extname(filePath).toLowerCase();
60602
+ const ext = path54.extname(filePath).toLowerCase();
60318
60603
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
60319
60604
  return false;
60320
60605
  }
@@ -60338,15 +60623,15 @@ function parseImports(content, targetFile, targetSymbol) {
60338
60623
  const imports = [];
60339
60624
  let _resolvedTarget;
60340
60625
  try {
60341
- _resolvedTarget = path53.resolve(targetFile);
60626
+ _resolvedTarget = path54.resolve(targetFile);
60342
60627
  } catch {
60343
60628
  _resolvedTarget = targetFile;
60344
60629
  }
60345
- const targetBasename = path53.basename(targetFile, path53.extname(targetFile));
60630
+ const targetBasename = path54.basename(targetFile, path54.extname(targetFile));
60346
60631
  const targetWithExt = targetFile;
60347
60632
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
60348
- const normalizedTargetWithExt = path53.normalize(targetWithExt).replace(/\\/g, "/");
60349
- const normalizedTargetWithoutExt = path53.normalize(targetWithoutExt).replace(/\\/g, "/");
60633
+ const normalizedTargetWithExt = path54.normalize(targetWithExt).replace(/\\/g, "/");
60634
+ const normalizedTargetWithoutExt = path54.normalize(targetWithoutExt).replace(/\\/g, "/");
60350
60635
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
60351
60636
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
60352
60637
  const modulePath = match[1] || match[2] || match[3];
@@ -60369,9 +60654,9 @@ function parseImports(content, targetFile, targetSymbol) {
60369
60654
  }
60370
60655
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
60371
60656
  let isMatch = false;
60372
- const _targetDir = path53.dirname(targetFile);
60373
- const targetExt = path53.extname(targetFile);
60374
- const targetBasenameNoExt = path53.basename(targetFile, targetExt);
60657
+ const _targetDir = path54.dirname(targetFile);
60658
+ const targetExt = path54.extname(targetFile);
60659
+ const targetBasenameNoExt = path54.basename(targetFile, targetExt);
60375
60660
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
60376
60661
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
60377
60662
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -60428,7 +60713,7 @@ var SKIP_DIRECTORIES3 = new Set([
60428
60713
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
60429
60714
  let entries;
60430
60715
  try {
60431
- entries = fs40.readdirSync(dir);
60716
+ entries = fs41.readdirSync(dir);
60432
60717
  } catch (e) {
60433
60718
  stats.fileErrors.push({
60434
60719
  path: dir,
@@ -60439,13 +60724,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60439
60724
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
60440
60725
  for (const entry of entries) {
60441
60726
  if (SKIP_DIRECTORIES3.has(entry)) {
60442
- stats.skippedDirs.push(path53.join(dir, entry));
60727
+ stats.skippedDirs.push(path54.join(dir, entry));
60443
60728
  continue;
60444
60729
  }
60445
- const fullPath = path53.join(dir, entry);
60730
+ const fullPath = path54.join(dir, entry);
60446
60731
  let stat2;
60447
60732
  try {
60448
- stat2 = fs40.statSync(fullPath);
60733
+ stat2 = fs41.statSync(fullPath);
60449
60734
  } catch (e) {
60450
60735
  stats.fileErrors.push({
60451
60736
  path: fullPath,
@@ -60456,7 +60741,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60456
60741
  if (stat2.isDirectory()) {
60457
60742
  findSourceFiles(fullPath, files, stats);
60458
60743
  } else if (stat2.isFile()) {
60459
- const ext = path53.extname(fullPath).toLowerCase();
60744
+ const ext = path54.extname(fullPath).toLowerCase();
60460
60745
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
60461
60746
  files.push(fullPath);
60462
60747
  }
@@ -60513,8 +60798,8 @@ var imports = createSwarmTool({
60513
60798
  return JSON.stringify(errorResult, null, 2);
60514
60799
  }
60515
60800
  try {
60516
- const targetFile = path53.resolve(file3);
60517
- if (!fs40.existsSync(targetFile)) {
60801
+ const targetFile = path54.resolve(file3);
60802
+ if (!fs41.existsSync(targetFile)) {
60518
60803
  const errorResult = {
60519
60804
  error: `target file not found: ${file3}`,
60520
60805
  target: file3,
@@ -60524,7 +60809,7 @@ var imports = createSwarmTool({
60524
60809
  };
60525
60810
  return JSON.stringify(errorResult, null, 2);
60526
60811
  }
60527
- const targetStat = fs40.statSync(targetFile);
60812
+ const targetStat = fs41.statSync(targetFile);
60528
60813
  if (!targetStat.isFile()) {
60529
60814
  const errorResult = {
60530
60815
  error: "target must be a file, not a directory",
@@ -60535,7 +60820,7 @@ var imports = createSwarmTool({
60535
60820
  };
60536
60821
  return JSON.stringify(errorResult, null, 2);
60537
60822
  }
60538
- const baseDir = path53.dirname(targetFile);
60823
+ const baseDir = path54.dirname(targetFile);
60539
60824
  const scanStats = {
60540
60825
  skippedDirs: [],
60541
60826
  skippedFiles: 0,
@@ -60550,12 +60835,12 @@ var imports = createSwarmTool({
60550
60835
  if (consumers.length >= MAX_CONSUMERS)
60551
60836
  break;
60552
60837
  try {
60553
- const stat2 = fs40.statSync(filePath);
60838
+ const stat2 = fs41.statSync(filePath);
60554
60839
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
60555
60840
  skippedFileCount++;
60556
60841
  continue;
60557
60842
  }
60558
- const buffer = fs40.readFileSync(filePath);
60843
+ const buffer = fs41.readFileSync(filePath);
60559
60844
  if (isBinaryFile2(filePath, buffer)) {
60560
60845
  skippedFileCount++;
60561
60846
  continue;
@@ -60622,7 +60907,7 @@ var imports = createSwarmTool({
60622
60907
  init_dist();
60623
60908
  init_config();
60624
60909
  init_knowledge_store();
60625
- import { randomUUID as randomUUID4 } from "crypto";
60910
+ import { randomUUID as randomUUID5 } from "crypto";
60626
60911
  init_manager2();
60627
60912
  init_create_tool();
60628
60913
  var VALID_CATEGORIES2 = [
@@ -60697,7 +60982,7 @@ var knowledgeAdd = createSwarmTool({
60697
60982
  project_name = plan?.title ?? "";
60698
60983
  } catch {}
60699
60984
  const entry = {
60700
- id: randomUUID4(),
60985
+ id: randomUUID5(),
60701
60986
  tier: "swarm",
60702
60987
  lesson,
60703
60988
  category,
@@ -60755,7 +61040,7 @@ init_dist();
60755
61040
  init_config();
60756
61041
  init_knowledge_store();
60757
61042
  init_create_tool();
60758
- import { existsSync as existsSync32 } from "fs";
61043
+ import { existsSync as existsSync33 } from "fs";
60759
61044
  var DEFAULT_LIMIT = 10;
60760
61045
  var MAX_LESSON_LENGTH = 200;
60761
61046
  var VALID_CATEGORIES3 = [
@@ -60824,14 +61109,14 @@ function validateLimit(limit) {
60824
61109
  }
60825
61110
  async function readSwarmKnowledge(directory) {
60826
61111
  const swarmPath = resolveSwarmKnowledgePath(directory);
60827
- if (!existsSync32(swarmPath)) {
61112
+ if (!existsSync33(swarmPath)) {
60828
61113
  return [];
60829
61114
  }
60830
61115
  return readKnowledge(swarmPath);
60831
61116
  }
60832
61117
  async function readHiveKnowledge() {
60833
61118
  const hivePath = resolveHiveKnowledgePath();
60834
- if (!existsSync32(hivePath)) {
61119
+ if (!existsSync33(hivePath)) {
60835
61120
  return [];
60836
61121
  }
60837
61122
  return readKnowledge(hivePath);
@@ -61144,8 +61429,9 @@ init_dist();
61144
61429
  init_config();
61145
61430
  init_schema();
61146
61431
  init_manager();
61147
- import * as fs41 from "fs";
61148
- import * as path54 from "path";
61432
+ import * as fs42 from "fs";
61433
+ import * as path55 from "path";
61434
+ init_review_receipt();
61149
61435
  init_utils2();
61150
61436
  init_telemetry();
61151
61437
  init_create_tool();
@@ -61366,11 +61652,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61366
61652
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
61367
61653
  }
61368
61654
  try {
61369
- const driftEvidencePath = path54.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61655
+ const driftEvidencePath = path55.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
61370
61656
  let driftVerdictFound = false;
61371
61657
  let driftVerdictApproved = false;
61372
61658
  try {
61373
- const driftEvidenceContent = fs41.readFileSync(driftEvidencePath, "utf-8");
61659
+ const driftEvidenceContent = fs42.readFileSync(driftEvidencePath, "utf-8");
61374
61660
  const driftEvidence = JSON.parse(driftEvidenceContent);
61375
61661
  const entries = driftEvidence.entries ?? [];
61376
61662
  for (const entry of entries) {
@@ -61400,14 +61686,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61400
61686
  driftVerdictFound = false;
61401
61687
  }
61402
61688
  if (!driftVerdictFound) {
61403
- const specPath = path54.join(dir, ".swarm", "spec.md");
61404
- const specExists = fs41.existsSync(specPath);
61689
+ const specPath = path55.join(dir, ".swarm", "spec.md");
61690
+ const specExists = fs42.existsSync(specPath);
61405
61691
  if (!specExists) {
61406
61692
  let incompleteTaskCount = 0;
61407
61693
  let planPhaseFound = false;
61408
61694
  try {
61409
61695
  const planPath = validateSwarmPath(dir, "plan.json");
61410
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61696
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61411
61697
  const plan = JSON.parse(planRaw);
61412
61698
  const targetPhase = plan.phases.find((p) => p.id === phase);
61413
61699
  if (targetPhase) {
@@ -61449,32 +61735,10 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61449
61735
  safeWarn(`[phase_complete] Drift verifier error (non-blocking):`, driftError);
61450
61736
  }
61451
61737
  }
61452
- const knowledgeConfig = {
61453
- enabled: true,
61454
- swarm_max_entries: 100,
61455
- hive_max_entries: 200,
61456
- auto_promote_days: 90,
61457
- max_inject_count: 5,
61458
- dedup_threshold: 0.6,
61459
- scope_filter: ["global"],
61460
- hive_enabled: true,
61461
- rejected_max_entries: 20,
61462
- validation_enabled: true,
61463
- evergreen_confidence: 0.9,
61464
- evergreen_utility: 0.8,
61465
- low_utility_threshold: 0.3,
61466
- min_retrievals_for_utility: 3,
61467
- schema_version: 1,
61468
- same_project_weight: 1,
61469
- cross_project_weight: 0.5,
61470
- min_encounter_score: 0.1,
61471
- initial_encounter_score: 1,
61472
- encounter_increment: 0.1,
61473
- max_encounter_score: 10
61474
- };
61738
+ const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
61475
61739
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
61476
61740
  try {
61477
- const projectName = path54.basename(dir);
61741
+ const projectName = path55.basename(dir);
61478
61742
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
61479
61743
  if (curationResult) {
61480
61744
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -61483,6 +61747,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61483
61747
  sessionState.pendingAdvisoryMessages.push(`[CURATOR] Knowledge curation: ${curationResult.stored} stored, ${curationResult.skipped} skipped, ${curationResult.rejected} rejected.`);
61484
61748
  }
61485
61749
  }
61750
+ await updateRetrievalOutcome(dir, `Phase ${phase}`, true);
61486
61751
  } catch (error93) {
61487
61752
  safeWarn("[phase_complete] Failed to curate lessons from retrospective:", error93);
61488
61753
  }
@@ -61491,7 +61756,41 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61491
61756
  try {
61492
61757
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
61493
61758
  if (curatorConfig.enabled && curatorConfig.phase_enabled) {
61494
- const curatorResult = await runCuratorPhase(dir, phase, agentsDispatched, curatorConfig, {});
61759
+ const llmDelegate = createCuratorLLMDelegate(dir);
61760
+ const curatorResult = await runCuratorPhase(dir, phase, agentsDispatched, curatorConfig, {}, llmDelegate);
61761
+ {
61762
+ const scopeContent = curatorResult.digest?.summary ?? `Phase ${phase} curator analysis`;
61763
+ const complianceWarnings2 = curatorResult.compliance.filter((c) => c.severity === "warning");
61764
+ const receipt = complianceWarnings2.length > 0 ? buildRejectedReceipt({
61765
+ agent: "curator",
61766
+ scopeContent,
61767
+ scopeDescription: "phase-digest",
61768
+ blockingFindings: complianceWarnings2.map((c) => ({
61769
+ location: `phase-${c.phase}`,
61770
+ summary: c.description,
61771
+ severity: c.type === "missing_reviewer" ? "high" : "medium"
61772
+ })),
61773
+ evidenceReferences: [],
61774
+ passConditions: [
61775
+ "resolve all compliance warnings before phase completion"
61776
+ ]
61777
+ }) : buildApprovedReceipt({
61778
+ agent: "curator",
61779
+ scopeContent,
61780
+ scopeDescription: "phase-digest",
61781
+ checkedAspects: [
61782
+ "phase_compliance",
61783
+ "knowledge_recommendations",
61784
+ "phase_digest"
61785
+ ],
61786
+ validatedClaims: [
61787
+ `phase: ${phase}`,
61788
+ `agents_dispatched: ${agentsDispatched.length}`,
61789
+ `knowledge_recommendations: ${curatorResult.knowledge_recommendations.length}`
61790
+ ]
61791
+ });
61792
+ persistReviewReceipt(dir, receipt).catch(() => {});
61793
+ }
61495
61794
  const knowledgeResult = await applyCuratorKnowledgeUpdates(dir, curatorResult.knowledge_recommendations, knowledgeConfig);
61496
61795
  const callerSessionState = swarmState.agentSessions.get(sessionID);
61497
61796
  if (callerSessionState) {
@@ -61519,7 +61818,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61519
61818
  let phaseRequiredAgents;
61520
61819
  try {
61521
61820
  const planPath = validateSwarmPath(dir, "plan.json");
61522
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61821
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61523
61822
  const plan = JSON.parse(planRaw);
61524
61823
  const phaseObj = plan.phases.find((p) => p.id === phase);
61525
61824
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -61534,7 +61833,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61534
61833
  if (agentsMissing.length > 0) {
61535
61834
  try {
61536
61835
  const planPath = validateSwarmPath(dir, "plan.json");
61537
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61836
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61538
61837
  const plan = JSON.parse(planRaw);
61539
61838
  const targetPhase = plan.phases.find((p) => p.id === phase);
61540
61839
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -61565,7 +61864,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61565
61864
  if (phaseCompleteConfig.regression_sweep?.enforce) {
61566
61865
  try {
61567
61866
  const planPath = validateSwarmPath(dir, "plan.json");
61568
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61867
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61569
61868
  const plan = JSON.parse(planRaw);
61570
61869
  const targetPhase = plan.phases.find((p) => p.id === phase);
61571
61870
  if (targetPhase) {
@@ -61603,7 +61902,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61603
61902
  };
61604
61903
  try {
61605
61904
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
61606
- fs41.appendFileSync(eventsPath, `${JSON.stringify(event)}
61905
+ fs42.appendFileSync(eventsPath, `${JSON.stringify(event)}
61607
61906
  `, "utf-8");
61608
61907
  } catch (writeError) {
61609
61908
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -61627,12 +61926,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61627
61926
  }
61628
61927
  try {
61629
61928
  const planPath = validateSwarmPath(dir, "plan.json");
61630
- const planJson = fs41.readFileSync(planPath, "utf-8");
61929
+ const planJson = fs42.readFileSync(planPath, "utf-8");
61631
61930
  const plan = JSON.parse(planJson);
61632
61931
  const phaseObj = plan.phases.find((p) => p.id === phase);
61633
61932
  if (phaseObj) {
61634
61933
  phaseObj.status = "completed";
61635
- fs41.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61934
+ fs42.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61636
61935
  `, "utf-8");
61637
61936
  }
61638
61937
  } catch (error93) {
@@ -61699,8 +61998,8 @@ init_dist();
61699
61998
  init_discovery();
61700
61999
  init_utils();
61701
62000
  init_create_tool();
61702
- import * as fs42 from "fs";
61703
- import * as path55 from "path";
62001
+ import * as fs43 from "fs";
62002
+ import * as path56 from "path";
61704
62003
  var MAX_OUTPUT_BYTES5 = 52428800;
61705
62004
  var AUDIT_TIMEOUT_MS = 120000;
61706
62005
  function isValidEcosystem(value) {
@@ -61718,28 +62017,28 @@ function validateArgs3(args2) {
61718
62017
  function detectEcosystems(directory) {
61719
62018
  const ecosystems = [];
61720
62019
  const cwd = directory;
61721
- if (fs42.existsSync(path55.join(cwd, "package.json"))) {
62020
+ if (fs43.existsSync(path56.join(cwd, "package.json"))) {
61722
62021
  ecosystems.push("npm");
61723
62022
  }
61724
- if (fs42.existsSync(path55.join(cwd, "pyproject.toml")) || fs42.existsSync(path55.join(cwd, "requirements.txt"))) {
62023
+ if (fs43.existsSync(path56.join(cwd, "pyproject.toml")) || fs43.existsSync(path56.join(cwd, "requirements.txt"))) {
61725
62024
  ecosystems.push("pip");
61726
62025
  }
61727
- if (fs42.existsSync(path55.join(cwd, "Cargo.toml"))) {
62026
+ if (fs43.existsSync(path56.join(cwd, "Cargo.toml"))) {
61728
62027
  ecosystems.push("cargo");
61729
62028
  }
61730
- if (fs42.existsSync(path55.join(cwd, "go.mod"))) {
62029
+ if (fs43.existsSync(path56.join(cwd, "go.mod"))) {
61731
62030
  ecosystems.push("go");
61732
62031
  }
61733
62032
  try {
61734
- const files = fs42.readdirSync(cwd);
62033
+ const files = fs43.readdirSync(cwd);
61735
62034
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
61736
62035
  ecosystems.push("dotnet");
61737
62036
  }
61738
62037
  } catch {}
61739
- if (fs42.existsSync(path55.join(cwd, "Gemfile")) || fs42.existsSync(path55.join(cwd, "Gemfile.lock"))) {
62038
+ if (fs43.existsSync(path56.join(cwd, "Gemfile")) || fs43.existsSync(path56.join(cwd, "Gemfile.lock"))) {
61740
62039
  ecosystems.push("ruby");
61741
62040
  }
61742
- if (fs42.existsSync(path55.join(cwd, "pubspec.yaml"))) {
62041
+ if (fs43.existsSync(path56.join(cwd, "pubspec.yaml"))) {
61743
62042
  ecosystems.push("dart");
61744
62043
  }
61745
62044
  return ecosystems;
@@ -62760,8 +63059,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
62760
63059
  ]);
62761
63060
  // src/tools/pre-check-batch.ts
62762
63061
  init_dist();
62763
- import * as fs44 from "fs";
62764
- import * as path57 from "path";
63062
+ import * as fs45 from "fs";
63063
+ import * as path58 from "path";
62765
63064
 
62766
63065
  // node_modules/yocto-queue/index.js
62767
63066
  class Node2 {
@@ -62906,8 +63205,8 @@ function pLimit(concurrency) {
62906
63205
  },
62907
63206
  map: {
62908
63207
  async value(iterable, function_) {
62909
- const promises5 = Array.from(iterable, (value, index) => this(function_, value, index));
62910
- return Promise.all(promises5);
63208
+ const promises6 = Array.from(iterable, (value, index) => this(function_, value, index));
63209
+ return Promise.all(promises6);
62911
63210
  }
62912
63211
  }
62913
63212
  });
@@ -63035,8 +63334,8 @@ async function qualityBudget(input, directory) {
63035
63334
  init_dist();
63036
63335
  init_manager();
63037
63336
  init_detector();
63038
- import * as fs43 from "fs";
63039
- import * as path56 from "path";
63337
+ import * as fs44 from "fs";
63338
+ import * as path57 from "path";
63040
63339
  import { extname as extname10 } from "path";
63041
63340
 
63042
63341
  // src/sast/rules/c.ts
@@ -63906,17 +64205,17 @@ var SEVERITY_ORDER = {
63906
64205
  };
63907
64206
  function shouldSkipFile(filePath) {
63908
64207
  try {
63909
- const stats = fs43.statSync(filePath);
64208
+ const stats = fs44.statSync(filePath);
63910
64209
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
63911
64210
  return { skip: true, reason: "file too large" };
63912
64211
  }
63913
64212
  if (stats.size === 0) {
63914
64213
  return { skip: true, reason: "empty file" };
63915
64214
  }
63916
- const fd = fs43.openSync(filePath, "r");
64215
+ const fd = fs44.openSync(filePath, "r");
63917
64216
  const buffer = Buffer.alloc(8192);
63918
- const bytesRead = fs43.readSync(fd, buffer, 0, 8192, 0);
63919
- fs43.closeSync(fd);
64217
+ const bytesRead = fs44.readSync(fd, buffer, 0, 8192, 0);
64218
+ fs44.closeSync(fd);
63920
64219
  if (bytesRead > 0) {
63921
64220
  let nullCount = 0;
63922
64221
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -63955,7 +64254,7 @@ function countBySeverity(findings) {
63955
64254
  }
63956
64255
  function scanFileWithTierA(filePath, language) {
63957
64256
  try {
63958
- const content = fs43.readFileSync(filePath, "utf-8");
64257
+ const content = fs44.readFileSync(filePath, "utf-8");
63959
64258
  const findings = executeRulesSync(filePath, content, language);
63960
64259
  return findings.map((f) => ({
63961
64260
  rule_id: f.rule_id,
@@ -64002,8 +64301,8 @@ async function sastScan(input, directory, config3) {
64002
64301
  _filesSkipped++;
64003
64302
  continue;
64004
64303
  }
64005
- const resolvedPath = path56.isAbsolute(filePath) ? filePath : path56.resolve(directory, filePath);
64006
- if (!fs43.existsSync(resolvedPath)) {
64304
+ const resolvedPath = path57.isAbsolute(filePath) ? filePath : path57.resolve(directory, filePath);
64305
+ if (!fs44.existsSync(resolvedPath)) {
64007
64306
  _filesSkipped++;
64008
64307
  continue;
64009
64308
  }
@@ -64201,18 +64500,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
64201
64500
  let resolved;
64202
64501
  const isWinAbs = isWindowsAbsolutePath(inputPath);
64203
64502
  if (isWinAbs) {
64204
- resolved = path57.win32.resolve(inputPath);
64205
- } else if (path57.isAbsolute(inputPath)) {
64206
- resolved = path57.resolve(inputPath);
64503
+ resolved = path58.win32.resolve(inputPath);
64504
+ } else if (path58.isAbsolute(inputPath)) {
64505
+ resolved = path58.resolve(inputPath);
64207
64506
  } else {
64208
- resolved = path57.resolve(baseDir, inputPath);
64507
+ resolved = path58.resolve(baseDir, inputPath);
64209
64508
  }
64210
- const workspaceResolved = path57.resolve(workspaceDir);
64509
+ const workspaceResolved = path58.resolve(workspaceDir);
64211
64510
  let relative8;
64212
64511
  if (isWinAbs) {
64213
- relative8 = path57.win32.relative(workspaceResolved, resolved);
64512
+ relative8 = path58.win32.relative(workspaceResolved, resolved);
64214
64513
  } else {
64215
- relative8 = path57.relative(workspaceResolved, resolved);
64514
+ relative8 = path58.relative(workspaceResolved, resolved);
64216
64515
  }
64217
64516
  if (relative8.startsWith("..")) {
64218
64517
  return "path traversal detected";
@@ -64273,13 +64572,13 @@ async function runLintWrapped(files, directory, _config) {
64273
64572
  }
64274
64573
  async function runLintOnFiles(linter, files, workspaceDir) {
64275
64574
  const isWindows = process.platform === "win32";
64276
- const binDir = path57.join(workspaceDir, "node_modules", ".bin");
64575
+ const binDir = path58.join(workspaceDir, "node_modules", ".bin");
64277
64576
  const validatedFiles = [];
64278
64577
  for (const file3 of files) {
64279
64578
  if (typeof file3 !== "string") {
64280
64579
  continue;
64281
64580
  }
64282
- const resolvedPath = path57.resolve(file3);
64581
+ const resolvedPath = path58.resolve(file3);
64283
64582
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
64284
64583
  if (validationError) {
64285
64584
  continue;
@@ -64297,10 +64596,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
64297
64596
  }
64298
64597
  let command;
64299
64598
  if (linter === "biome") {
64300
- const biomeBin = isWindows ? path57.join(binDir, "biome.EXE") : path57.join(binDir, "biome");
64599
+ const biomeBin = isWindows ? path58.join(binDir, "biome.EXE") : path58.join(binDir, "biome");
64301
64600
  command = [biomeBin, "check", ...validatedFiles];
64302
64601
  } else {
64303
- const eslintBin = isWindows ? path57.join(binDir, "eslint.cmd") : path57.join(binDir, "eslint");
64602
+ const eslintBin = isWindows ? path58.join(binDir, "eslint.cmd") : path58.join(binDir, "eslint");
64304
64603
  command = [eslintBin, ...validatedFiles];
64305
64604
  }
64306
64605
  try {
@@ -64437,7 +64736,7 @@ async function runSecretscanWithFiles(files, directory) {
64437
64736
  skippedFiles++;
64438
64737
  continue;
64439
64738
  }
64440
- const resolvedPath = path57.resolve(file3);
64739
+ const resolvedPath = path58.resolve(file3);
64441
64740
  const validationError = validatePath(resolvedPath, directory, directory);
64442
64741
  if (validationError) {
64443
64742
  skippedFiles++;
@@ -64455,14 +64754,14 @@ async function runSecretscanWithFiles(files, directory) {
64455
64754
  };
64456
64755
  }
64457
64756
  for (const file3 of validatedFiles) {
64458
- const ext = path57.extname(file3).toLowerCase();
64757
+ const ext = path58.extname(file3).toLowerCase();
64459
64758
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
64460
64759
  skippedFiles++;
64461
64760
  continue;
64462
64761
  }
64463
64762
  let stat2;
64464
64763
  try {
64465
- stat2 = fs44.statSync(file3);
64764
+ stat2 = fs45.statSync(file3);
64466
64765
  } catch {
64467
64766
  skippedFiles++;
64468
64767
  continue;
@@ -64473,7 +64772,7 @@ async function runSecretscanWithFiles(files, directory) {
64473
64772
  }
64474
64773
  let content;
64475
64774
  try {
64476
- const buffer = fs44.readFileSync(file3);
64775
+ const buffer = fs45.readFileSync(file3);
64477
64776
  if (buffer.includes(0)) {
64478
64777
  skippedFiles++;
64479
64778
  continue;
@@ -64661,7 +64960,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
64661
64960
  const preexistingFindings = [];
64662
64961
  for (const finding of findings) {
64663
64962
  const filePath = finding.location.file;
64664
- const normalised = path57.relative(directory, filePath).replace(/\\/g, "/");
64963
+ const normalised = path58.relative(directory, filePath).replace(/\\/g, "/");
64665
64964
  const changedLines = changedLineRanges.get(normalised);
64666
64965
  if (changedLines && changedLines.has(finding.location.line)) {
64667
64966
  newFindings.push(finding);
@@ -64712,7 +65011,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
64712
65011
  warn(`pre_check_batch: Invalid file path: ${file3}`);
64713
65012
  continue;
64714
65013
  }
64715
- changedFiles.push(path57.resolve(directory, file3));
65014
+ changedFiles.push(path58.resolve(directory, file3));
64716
65015
  }
64717
65016
  if (changedFiles.length === 0) {
64718
65017
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -64900,7 +65199,7 @@ var pre_check_batch = createSwarmTool({
64900
65199
  };
64901
65200
  return JSON.stringify(errorResult, null, 2);
64902
65201
  }
64903
- const resolvedDirectory = path57.resolve(typedArgs.directory);
65202
+ const resolvedDirectory = path58.resolve(typedArgs.directory);
64904
65203
  const workspaceAnchor = resolvedDirectory;
64905
65204
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
64906
65205
  if (dirError) {
@@ -65006,38 +65305,38 @@ ${paginatedContent}`;
65006
65305
  });
65007
65306
  // src/tools/save-plan.ts
65008
65307
  init_tool();
65009
- import * as fs46 from "fs";
65010
- import * as path59 from "path";
65308
+ import * as fs47 from "fs";
65309
+ import * as path60 from "path";
65011
65310
 
65012
65311
  // src/parallel/file-locks.ts
65013
- import * as fs45 from "fs";
65014
- import * as path58 from "path";
65312
+ import * as fs46 from "fs";
65313
+ import * as path59 from "path";
65015
65314
  var LOCKS_DIR = ".swarm/locks";
65016
65315
  var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
65017
65316
  function getLockFilePath(directory, filePath) {
65018
- const normalized = path58.resolve(directory, filePath);
65019
- if (!normalized.startsWith(path58.resolve(directory))) {
65317
+ const normalized = path59.resolve(directory, filePath);
65318
+ if (!normalized.startsWith(path59.resolve(directory))) {
65020
65319
  throw new Error("Invalid file path: path traversal not allowed");
65021
65320
  }
65022
65321
  const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
65023
- return path58.join(directory, LOCKS_DIR, `${hash3}.lock`);
65322
+ return path59.join(directory, LOCKS_DIR, `${hash3}.lock`);
65024
65323
  }
65025
65324
  function tryAcquireLock(directory, filePath, agent, taskId) {
65026
65325
  const lockPath = getLockFilePath(directory, filePath);
65027
- const locksDir = path58.dirname(lockPath);
65028
- if (!fs45.existsSync(locksDir)) {
65029
- fs45.mkdirSync(locksDir, { recursive: true });
65326
+ const locksDir = path59.dirname(lockPath);
65327
+ if (!fs46.existsSync(locksDir)) {
65328
+ fs46.mkdirSync(locksDir, { recursive: true });
65030
65329
  }
65031
- if (fs45.existsSync(lockPath)) {
65330
+ if (fs46.existsSync(lockPath)) {
65032
65331
  try {
65033
- const existingLock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
65332
+ const existingLock = JSON.parse(fs46.readFileSync(lockPath, "utf-8"));
65034
65333
  if (Date.now() > existingLock.expiresAt) {
65035
- fs45.unlinkSync(lockPath);
65334
+ fs46.unlinkSync(lockPath);
65036
65335
  } else {
65037
65336
  return { acquired: false, existing: existingLock };
65038
65337
  }
65039
65338
  } catch {
65040
- fs45.unlinkSync(lockPath);
65339
+ fs46.unlinkSync(lockPath);
65041
65340
  }
65042
65341
  }
65043
65342
  const lock = {
@@ -65048,24 +65347,24 @@ function tryAcquireLock(directory, filePath, agent, taskId) {
65048
65347
  expiresAt: Date.now() + LOCK_TIMEOUT_MS
65049
65348
  };
65050
65349
  const tempPath = `${lockPath}.tmp`;
65051
- fs45.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65052
- fs45.renameSync(tempPath, lockPath);
65350
+ fs46.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65351
+ fs46.renameSync(tempPath, lockPath);
65053
65352
  return { acquired: true, lock };
65054
65353
  }
65055
65354
  function releaseLock(directory, filePath, taskId) {
65056
65355
  const lockPath = getLockFilePath(directory, filePath);
65057
- if (!fs45.existsSync(lockPath)) {
65356
+ if (!fs46.existsSync(lockPath)) {
65058
65357
  return true;
65059
65358
  }
65060
65359
  try {
65061
- const lock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
65360
+ const lock = JSON.parse(fs46.readFileSync(lockPath, "utf-8"));
65062
65361
  if (lock.taskId === taskId) {
65063
- fs45.unlinkSync(lockPath);
65362
+ fs46.unlinkSync(lockPath);
65064
65363
  return true;
65065
65364
  }
65066
65365
  return false;
65067
65366
  } catch {
65068
- fs45.unlinkSync(lockPath);
65367
+ fs46.unlinkSync(lockPath);
65069
65368
  return true;
65070
65369
  }
65071
65370
  }
@@ -65190,14 +65489,14 @@ async function executeSavePlan(args2, fallbackDir) {
65190
65489
  try {
65191
65490
  await savePlan(dir, plan);
65192
65491
  try {
65193
- const markerPath = path59.join(dir, ".swarm", ".plan-write-marker");
65492
+ const markerPath = path60.join(dir, ".swarm", ".plan-write-marker");
65194
65493
  const marker = JSON.stringify({
65195
65494
  source: "save_plan",
65196
65495
  timestamp: new Date().toISOString(),
65197
65496
  phases_count: plan.phases.length,
65198
65497
  tasks_count: tasksCount
65199
65498
  });
65200
- await fs46.promises.writeFile(markerPath, marker, "utf8");
65499
+ await fs47.promises.writeFile(markerPath, marker, "utf8");
65201
65500
  } catch {}
65202
65501
  const warnings = [];
65203
65502
  let criticReviewFound = false;
@@ -65213,7 +65512,7 @@ async function executeSavePlan(args2, fallbackDir) {
65213
65512
  return {
65214
65513
  success: true,
65215
65514
  message: "Plan saved successfully",
65216
- plan_path: path59.join(dir, ".swarm", "plan.json"),
65515
+ plan_path: path60.join(dir, ".swarm", "plan.json"),
65217
65516
  phases_count: plan.phases.length,
65218
65517
  tasks_count: tasksCount,
65219
65518
  ...warnings.length > 0 ? { warnings } : {}
@@ -65255,8 +65554,8 @@ var save_plan = createSwarmTool({
65255
65554
  // src/tools/sbom-generate.ts
65256
65555
  init_dist();
65257
65556
  init_manager();
65258
- import * as fs47 from "fs";
65259
- import * as path60 from "path";
65557
+ import * as fs48 from "fs";
65558
+ import * as path61 from "path";
65260
65559
 
65261
65560
  // src/sbom/detectors/index.ts
65262
65561
  init_utils();
@@ -66104,9 +66403,9 @@ function findManifestFiles(rootDir) {
66104
66403
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
66105
66404
  function searchDir(dir) {
66106
66405
  try {
66107
- const entries = fs47.readdirSync(dir, { withFileTypes: true });
66406
+ const entries = fs48.readdirSync(dir, { withFileTypes: true });
66108
66407
  for (const entry of entries) {
66109
- const fullPath = path60.join(dir, entry.name);
66408
+ const fullPath = path61.join(dir, entry.name);
66110
66409
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
66111
66410
  continue;
66112
66411
  }
@@ -66115,7 +66414,7 @@ function findManifestFiles(rootDir) {
66115
66414
  } else if (entry.isFile()) {
66116
66415
  for (const pattern of patterns) {
66117
66416
  if (simpleGlobToRegex(pattern).test(entry.name)) {
66118
- manifestFiles.push(path60.relative(rootDir, fullPath));
66417
+ manifestFiles.push(path61.relative(rootDir, fullPath));
66119
66418
  break;
66120
66419
  }
66121
66420
  }
@@ -66131,13 +66430,13 @@ function findManifestFilesInDirs(directories, workingDir) {
66131
66430
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
66132
66431
  for (const dir of directories) {
66133
66432
  try {
66134
- const entries = fs47.readdirSync(dir, { withFileTypes: true });
66433
+ const entries = fs48.readdirSync(dir, { withFileTypes: true });
66135
66434
  for (const entry of entries) {
66136
- const fullPath = path60.join(dir, entry.name);
66435
+ const fullPath = path61.join(dir, entry.name);
66137
66436
  if (entry.isFile()) {
66138
66437
  for (const pattern of patterns) {
66139
66438
  if (simpleGlobToRegex(pattern).test(entry.name)) {
66140
- found.push(path60.relative(workingDir, fullPath));
66439
+ found.push(path61.relative(workingDir, fullPath));
66141
66440
  break;
66142
66441
  }
66143
66442
  }
@@ -66150,11 +66449,11 @@ function findManifestFilesInDirs(directories, workingDir) {
66150
66449
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66151
66450
  const dirs = new Set;
66152
66451
  for (const file3 of changedFiles) {
66153
- let currentDir = path60.dirname(file3);
66452
+ let currentDir = path61.dirname(file3);
66154
66453
  while (true) {
66155
- if (currentDir && currentDir !== "." && currentDir !== path60.sep) {
66156
- dirs.add(path60.join(workingDir, currentDir));
66157
- const parent = path60.dirname(currentDir);
66454
+ if (currentDir && currentDir !== "." && currentDir !== path61.sep) {
66455
+ dirs.add(path61.join(workingDir, currentDir));
66456
+ const parent = path61.dirname(currentDir);
66158
66457
  if (parent === currentDir)
66159
66458
  break;
66160
66459
  currentDir = parent;
@@ -66168,7 +66467,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66168
66467
  }
66169
66468
  function ensureOutputDir(outputDir) {
66170
66469
  try {
66171
- fs47.mkdirSync(outputDir, { recursive: true });
66470
+ fs48.mkdirSync(outputDir, { recursive: true });
66172
66471
  } catch (error93) {
66173
66472
  if (!error93 || error93.code !== "EEXIST") {
66174
66473
  throw error93;
@@ -66238,7 +66537,7 @@ var sbom_generate = createSwarmTool({
66238
66537
  const changedFiles = obj.changed_files;
66239
66538
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
66240
66539
  const workingDir = directory;
66241
- const outputDir = path60.isAbsolute(relativeOutputDir) ? relativeOutputDir : path60.join(workingDir, relativeOutputDir);
66540
+ const outputDir = path61.isAbsolute(relativeOutputDir) ? relativeOutputDir : path61.join(workingDir, relativeOutputDir);
66242
66541
  let manifestFiles = [];
66243
66542
  if (scope === "all") {
66244
66543
  manifestFiles = findManifestFiles(workingDir);
@@ -66261,11 +66560,11 @@ var sbom_generate = createSwarmTool({
66261
66560
  const processedFiles = [];
66262
66561
  for (const manifestFile of manifestFiles) {
66263
66562
  try {
66264
- const fullPath = path60.isAbsolute(manifestFile) ? manifestFile : path60.join(workingDir, manifestFile);
66265
- if (!fs47.existsSync(fullPath)) {
66563
+ const fullPath = path61.isAbsolute(manifestFile) ? manifestFile : path61.join(workingDir, manifestFile);
66564
+ if (!fs48.existsSync(fullPath)) {
66266
66565
  continue;
66267
66566
  }
66268
- const content = fs47.readFileSync(fullPath, "utf-8");
66567
+ const content = fs48.readFileSync(fullPath, "utf-8");
66269
66568
  const components = detectComponents(manifestFile, content);
66270
66569
  processedFiles.push(manifestFile);
66271
66570
  if (components.length > 0) {
@@ -66278,8 +66577,8 @@ var sbom_generate = createSwarmTool({
66278
66577
  const bom = generateCycloneDX(allComponents);
66279
66578
  const bomJson = serializeCycloneDX(bom);
66280
66579
  const filename = generateSbomFilename();
66281
- const outputPath = path60.join(outputDir, filename);
66282
- fs47.writeFileSync(outputPath, bomJson, "utf-8");
66580
+ const outputPath = path61.join(outputDir, filename);
66581
+ fs48.writeFileSync(outputPath, bomJson, "utf-8");
66283
66582
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
66284
66583
  try {
66285
66584
  const timestamp = new Date().toISOString();
@@ -66321,8 +66620,8 @@ var sbom_generate = createSwarmTool({
66321
66620
  // src/tools/schema-drift.ts
66322
66621
  init_dist();
66323
66622
  init_create_tool();
66324
- import * as fs48 from "fs";
66325
- import * as path61 from "path";
66623
+ import * as fs49 from "fs";
66624
+ import * as path62 from "path";
66326
66625
  var SPEC_CANDIDATES = [
66327
66626
  "openapi.json",
66328
66627
  "openapi.yaml",
@@ -66354,28 +66653,28 @@ function normalizePath2(p) {
66354
66653
  }
66355
66654
  function discoverSpecFile(cwd, specFileArg) {
66356
66655
  if (specFileArg) {
66357
- const resolvedPath = path61.resolve(cwd, specFileArg);
66358
- const normalizedCwd = cwd.endsWith(path61.sep) ? cwd : cwd + path61.sep;
66656
+ const resolvedPath = path62.resolve(cwd, specFileArg);
66657
+ const normalizedCwd = cwd.endsWith(path62.sep) ? cwd : cwd + path62.sep;
66359
66658
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
66360
66659
  throw new Error("Invalid spec_file: path traversal detected");
66361
66660
  }
66362
- const ext = path61.extname(resolvedPath).toLowerCase();
66661
+ const ext = path62.extname(resolvedPath).toLowerCase();
66363
66662
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
66364
66663
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
66365
66664
  }
66366
- const stats = fs48.statSync(resolvedPath);
66665
+ const stats = fs49.statSync(resolvedPath);
66367
66666
  if (stats.size > MAX_SPEC_SIZE) {
66368
66667
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
66369
66668
  }
66370
- if (!fs48.existsSync(resolvedPath)) {
66669
+ if (!fs49.existsSync(resolvedPath)) {
66371
66670
  throw new Error(`Spec file not found: ${resolvedPath}`);
66372
66671
  }
66373
66672
  return resolvedPath;
66374
66673
  }
66375
66674
  for (const candidate of SPEC_CANDIDATES) {
66376
- const candidatePath = path61.resolve(cwd, candidate);
66377
- if (fs48.existsSync(candidatePath)) {
66378
- const stats = fs48.statSync(candidatePath);
66675
+ const candidatePath = path62.resolve(cwd, candidate);
66676
+ if (fs49.existsSync(candidatePath)) {
66677
+ const stats = fs49.statSync(candidatePath);
66379
66678
  if (stats.size <= MAX_SPEC_SIZE) {
66380
66679
  return candidatePath;
66381
66680
  }
@@ -66384,8 +66683,8 @@ function discoverSpecFile(cwd, specFileArg) {
66384
66683
  return null;
66385
66684
  }
66386
66685
  function parseSpec(specFile) {
66387
- const content = fs48.readFileSync(specFile, "utf-8");
66388
- const ext = path61.extname(specFile).toLowerCase();
66686
+ const content = fs49.readFileSync(specFile, "utf-8");
66687
+ const ext = path62.extname(specFile).toLowerCase();
66389
66688
  if (ext === ".json") {
66390
66689
  return parseJsonSpec(content);
66391
66690
  }
@@ -66456,12 +66755,12 @@ function extractRoutes(cwd) {
66456
66755
  function walkDir(dir) {
66457
66756
  let entries;
66458
66757
  try {
66459
- entries = fs48.readdirSync(dir, { withFileTypes: true });
66758
+ entries = fs49.readdirSync(dir, { withFileTypes: true });
66460
66759
  } catch {
66461
66760
  return;
66462
66761
  }
66463
66762
  for (const entry of entries) {
66464
- const fullPath = path61.join(dir, entry.name);
66763
+ const fullPath = path62.join(dir, entry.name);
66465
66764
  if (entry.isSymbolicLink()) {
66466
66765
  continue;
66467
66766
  }
@@ -66471,7 +66770,7 @@ function extractRoutes(cwd) {
66471
66770
  }
66472
66771
  walkDir(fullPath);
66473
66772
  } else if (entry.isFile()) {
66474
- const ext = path61.extname(entry.name).toLowerCase();
66773
+ const ext = path62.extname(entry.name).toLowerCase();
66475
66774
  const baseName = entry.name.toLowerCase();
66476
66775
  if (![".ts", ".js", ".mjs"].includes(ext)) {
66477
66776
  continue;
@@ -66489,7 +66788,7 @@ function extractRoutes(cwd) {
66489
66788
  }
66490
66789
  function extractRoutesFromFile(filePath) {
66491
66790
  const routes = [];
66492
- const content = fs48.readFileSync(filePath, "utf-8");
66791
+ const content = fs49.readFileSync(filePath, "utf-8");
66493
66792
  const lines = content.split(/\r?\n/);
66494
66793
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
66495
66794
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -66640,8 +66939,8 @@ init_secretscan();
66640
66939
  // src/tools/symbols.ts
66641
66940
  init_tool();
66642
66941
  init_create_tool();
66643
- import * as fs49 from "fs";
66644
- import * as path62 from "path";
66942
+ import * as fs50 from "fs";
66943
+ import * as path63 from "path";
66645
66944
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
66646
66945
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
66647
66946
  function containsWindowsAttacks(str) {
@@ -66658,11 +66957,11 @@ function containsWindowsAttacks(str) {
66658
66957
  }
66659
66958
  function isPathInWorkspace(filePath, workspace) {
66660
66959
  try {
66661
- const resolvedPath = path62.resolve(workspace, filePath);
66662
- const realWorkspace = fs49.realpathSync(workspace);
66663
- const realResolvedPath = fs49.realpathSync(resolvedPath);
66664
- const relativePath = path62.relative(realWorkspace, realResolvedPath);
66665
- if (relativePath.startsWith("..") || path62.isAbsolute(relativePath)) {
66960
+ const resolvedPath = path63.resolve(workspace, filePath);
66961
+ const realWorkspace = fs50.realpathSync(workspace);
66962
+ const realResolvedPath = fs50.realpathSync(resolvedPath);
66963
+ const relativePath = path63.relative(realWorkspace, realResolvedPath);
66964
+ if (relativePath.startsWith("..") || path63.isAbsolute(relativePath)) {
66666
66965
  return false;
66667
66966
  }
66668
66967
  return true;
@@ -66674,17 +66973,17 @@ function validatePathForRead(filePath, workspace) {
66674
66973
  return isPathInWorkspace(filePath, workspace);
66675
66974
  }
66676
66975
  function extractTSSymbols(filePath, cwd) {
66677
- const fullPath = path62.join(cwd, filePath);
66976
+ const fullPath = path63.join(cwd, filePath);
66678
66977
  if (!validatePathForRead(fullPath, cwd)) {
66679
66978
  return [];
66680
66979
  }
66681
66980
  let content;
66682
66981
  try {
66683
- const stats = fs49.statSync(fullPath);
66982
+ const stats = fs50.statSync(fullPath);
66684
66983
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66685
66984
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66686
66985
  }
66687
- content = fs49.readFileSync(fullPath, "utf-8");
66986
+ content = fs50.readFileSync(fullPath, "utf-8");
66688
66987
  } catch {
66689
66988
  return [];
66690
66989
  }
@@ -66826,17 +67125,17 @@ function extractTSSymbols(filePath, cwd) {
66826
67125
  });
66827
67126
  }
66828
67127
  function extractPythonSymbols(filePath, cwd) {
66829
- const fullPath = path62.join(cwd, filePath);
67128
+ const fullPath = path63.join(cwd, filePath);
66830
67129
  if (!validatePathForRead(fullPath, cwd)) {
66831
67130
  return [];
66832
67131
  }
66833
67132
  let content;
66834
67133
  try {
66835
- const stats = fs49.statSync(fullPath);
67134
+ const stats = fs50.statSync(fullPath);
66836
67135
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66837
67136
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66838
67137
  }
66839
- content = fs49.readFileSync(fullPath, "utf-8");
67138
+ content = fs50.readFileSync(fullPath, "utf-8");
66840
67139
  } catch {
66841
67140
  return [];
66842
67141
  }
@@ -66909,7 +67208,7 @@ var symbols = createSwarmTool({
66909
67208
  }, null, 2);
66910
67209
  }
66911
67210
  const cwd = directory;
66912
- const ext = path62.extname(file3);
67211
+ const ext = path63.extname(file3);
66913
67212
  if (containsControlChars(file3)) {
66914
67213
  return JSON.stringify({
66915
67214
  file: file3,
@@ -66980,8 +67279,8 @@ init_test_runner();
66980
67279
  init_dist();
66981
67280
  init_utils();
66982
67281
  init_create_tool();
66983
- import * as fs50 from "fs";
66984
- import * as path63 from "path";
67282
+ import * as fs51 from "fs";
67283
+ import * as path64 from "path";
66985
67284
  var MAX_TEXT_LENGTH = 200;
66986
67285
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
66987
67286
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -67046,9 +67345,9 @@ function validatePathsInput(paths, cwd) {
67046
67345
  return { error: "paths contains path traversal", resolvedPath: null };
67047
67346
  }
67048
67347
  try {
67049
- const resolvedPath = path63.resolve(paths);
67050
- const normalizedCwd = path63.resolve(cwd);
67051
- const normalizedResolved = path63.resolve(resolvedPath);
67348
+ const resolvedPath = path64.resolve(paths);
67349
+ const normalizedCwd = path64.resolve(cwd);
67350
+ const normalizedResolved = path64.resolve(resolvedPath);
67052
67351
  if (!normalizedResolved.startsWith(normalizedCwd)) {
67053
67352
  return {
67054
67353
  error: "paths must be within the current working directory",
@@ -67064,13 +67363,13 @@ function validatePathsInput(paths, cwd) {
67064
67363
  }
67065
67364
  }
67066
67365
  function isSupportedExtension(filePath) {
67067
- const ext = path63.extname(filePath).toLowerCase();
67366
+ const ext = path64.extname(filePath).toLowerCase();
67068
67367
  return SUPPORTED_EXTENSIONS2.has(ext);
67069
67368
  }
67070
67369
  function findSourceFiles2(dir, files = []) {
67071
67370
  let entries;
67072
67371
  try {
67073
- entries = fs50.readdirSync(dir);
67372
+ entries = fs51.readdirSync(dir);
67074
67373
  } catch {
67075
67374
  return files;
67076
67375
  }
@@ -67079,10 +67378,10 @@ function findSourceFiles2(dir, files = []) {
67079
67378
  if (SKIP_DIRECTORIES4.has(entry)) {
67080
67379
  continue;
67081
67380
  }
67082
- const fullPath = path63.join(dir, entry);
67381
+ const fullPath = path64.join(dir, entry);
67083
67382
  let stat2;
67084
67383
  try {
67085
- stat2 = fs50.statSync(fullPath);
67384
+ stat2 = fs51.statSync(fullPath);
67086
67385
  } catch {
67087
67386
  continue;
67088
67387
  }
@@ -67175,7 +67474,7 @@ var todo_extract = createSwarmTool({
67175
67474
  return JSON.stringify(errorResult, null, 2);
67176
67475
  }
67177
67476
  const scanPath = resolvedPath;
67178
- if (!fs50.existsSync(scanPath)) {
67477
+ if (!fs51.existsSync(scanPath)) {
67179
67478
  const errorResult = {
67180
67479
  error: `path not found: ${pathsInput}`,
67181
67480
  total: 0,
@@ -67185,13 +67484,13 @@ var todo_extract = createSwarmTool({
67185
67484
  return JSON.stringify(errorResult, null, 2);
67186
67485
  }
67187
67486
  const filesToScan = [];
67188
- const stat2 = fs50.statSync(scanPath);
67487
+ const stat2 = fs51.statSync(scanPath);
67189
67488
  if (stat2.isFile()) {
67190
67489
  if (isSupportedExtension(scanPath)) {
67191
67490
  filesToScan.push(scanPath);
67192
67491
  } else {
67193
67492
  const errorResult = {
67194
- error: `unsupported file extension: ${path63.extname(scanPath)}`,
67493
+ error: `unsupported file extension: ${path64.extname(scanPath)}`,
67195
67494
  total: 0,
67196
67495
  byPriority: { high: 0, medium: 0, low: 0 },
67197
67496
  entries: []
@@ -67204,11 +67503,11 @@ var todo_extract = createSwarmTool({
67204
67503
  const allEntries = [];
67205
67504
  for (const filePath of filesToScan) {
67206
67505
  try {
67207
- const fileStat = fs50.statSync(filePath);
67506
+ const fileStat = fs51.statSync(filePath);
67208
67507
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
67209
67508
  continue;
67210
67509
  }
67211
- const content = fs50.readFileSync(filePath, "utf-8");
67510
+ const content = fs51.readFileSync(filePath, "utf-8");
67212
67511
  const entries = parseTodoComments(content, filePath, tagsSet);
67213
67512
  allEntries.push(...entries);
67214
67513
  } catch {}
@@ -67237,18 +67536,18 @@ var todo_extract = createSwarmTool({
67237
67536
  init_tool();
67238
67537
  init_schema();
67239
67538
  init_gate_evidence();
67240
- import * as fs52 from "fs";
67241
- import * as path65 from "path";
67539
+ import * as fs53 from "fs";
67540
+ import * as path66 from "path";
67242
67541
 
67243
67542
  // src/hooks/diff-scope.ts
67244
- import * as fs51 from "fs";
67245
- import * as path64 from "path";
67543
+ import * as fs52 from "fs";
67544
+ import * as path65 from "path";
67246
67545
  function getDeclaredScope(taskId, directory) {
67247
67546
  try {
67248
- const planPath = path64.join(directory, ".swarm", "plan.json");
67249
- if (!fs51.existsSync(planPath))
67547
+ const planPath = path65.join(directory, ".swarm", "plan.json");
67548
+ if (!fs52.existsSync(planPath))
67250
67549
  return null;
67251
- const raw = fs51.readFileSync(planPath, "utf-8");
67550
+ const raw = fs52.readFileSync(planPath, "utf-8");
67252
67551
  const plan = JSON.parse(raw);
67253
67552
  for (const phase of plan.phases ?? []) {
67254
67553
  for (const task of phase.tasks ?? []) {
@@ -67361,7 +67660,7 @@ var TIER_3_PATTERNS = [
67361
67660
  ];
67362
67661
  function matchesTier3Pattern(files) {
67363
67662
  for (const file3 of files) {
67364
- const fileName = path65.basename(file3);
67663
+ const fileName = path66.basename(file3);
67365
67664
  for (const pattern of TIER_3_PATTERNS) {
67366
67665
  if (pattern.test(fileName)) {
67367
67666
  return true;
@@ -67375,8 +67674,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67375
67674
  if (hasActiveTurboMode()) {
67376
67675
  const resolvedDir2 = workingDirectory;
67377
67676
  try {
67378
- const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67379
- const planRaw = fs52.readFileSync(planPath, "utf-8");
67677
+ const planPath = path66.join(resolvedDir2, ".swarm", "plan.json");
67678
+ const planRaw = fs53.readFileSync(planPath, "utf-8");
67380
67679
  const plan = JSON.parse(planRaw);
67381
67680
  for (const planPhase of plan.phases ?? []) {
67382
67681
  for (const task of planPhase.tasks ?? []) {
@@ -67442,8 +67741,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67442
67741
  }
67443
67742
  try {
67444
67743
  const resolvedDir2 = workingDirectory;
67445
- const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67446
- const planRaw = fs52.readFileSync(planPath, "utf-8");
67744
+ const planPath = path66.join(resolvedDir2, ".swarm", "plan.json");
67745
+ const planRaw = fs53.readFileSync(planPath, "utf-8");
67447
67746
  const plan = JSON.parse(planRaw);
67448
67747
  for (const planPhase of plan.phases ?? []) {
67449
67748
  for (const task of planPhase.tasks ?? []) {
@@ -67625,8 +67924,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67625
67924
  };
67626
67925
  }
67627
67926
  }
67628
- normalizedDir = path65.normalize(args2.working_directory);
67629
- const pathParts = normalizedDir.split(path65.sep);
67927
+ normalizedDir = path66.normalize(args2.working_directory);
67928
+ const pathParts = normalizedDir.split(path66.sep);
67630
67929
  if (pathParts.includes("..")) {
67631
67930
  return {
67632
67931
  success: false,
@@ -67636,11 +67935,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67636
67935
  ]
67637
67936
  };
67638
67937
  }
67639
- const resolvedDir = path65.resolve(normalizedDir);
67938
+ const resolvedDir = path66.resolve(normalizedDir);
67640
67939
  try {
67641
- const realPath = fs52.realpathSync(resolvedDir);
67642
- const planPath = path65.join(realPath, ".swarm", "plan.json");
67643
- if (!fs52.existsSync(planPath)) {
67940
+ const realPath = fs53.realpathSync(resolvedDir);
67941
+ const planPath = path66.join(realPath, ".swarm", "plan.json");
67942
+ if (!fs53.existsSync(planPath)) {
67644
67943
  return {
67645
67944
  success: false,
67646
67945
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -67673,8 +67972,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67673
67972
  recoverTaskStateFromDelegations(args2.task_id);
67674
67973
  let phaseRequiresReviewer = true;
67675
67974
  try {
67676
- const planPath = path65.join(directory, ".swarm", "plan.json");
67677
- const planRaw = fs52.readFileSync(planPath, "utf-8");
67975
+ const planPath = path66.join(directory, ".swarm", "plan.json");
67976
+ const planRaw = fs53.readFileSync(planPath, "utf-8");
67678
67977
  const plan = JSON.parse(planRaw);
67679
67978
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
67680
67979
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -67737,8 +68036,8 @@ var update_task_status = createSwarmTool({
67737
68036
  init_tool();
67738
68037
  init_utils2();
67739
68038
  init_create_tool();
67740
- import fs53 from "fs";
67741
- import path66 from "path";
68039
+ import fs54 from "fs";
68040
+ import path67 from "path";
67742
68041
  function normalizeVerdict(verdict) {
67743
68042
  switch (verdict) {
67744
68043
  case "APPROVED":
@@ -67785,7 +68084,7 @@ async function executeWriteDriftEvidence(args2, directory) {
67785
68084
  entries: [evidenceEntry]
67786
68085
  };
67787
68086
  const filename = "drift-verifier.json";
67788
- const relativePath = path66.join("evidence", String(phase), filename);
68087
+ const relativePath = path67.join("evidence", String(phase), filename);
67789
68088
  let validatedPath;
67790
68089
  try {
67791
68090
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -67796,12 +68095,12 @@ async function executeWriteDriftEvidence(args2, directory) {
67796
68095
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
67797
68096
  }, null, 2);
67798
68097
  }
67799
- const evidenceDir = path66.dirname(validatedPath);
68098
+ const evidenceDir = path67.dirname(validatedPath);
67800
68099
  try {
67801
- await fs53.promises.mkdir(evidenceDir, { recursive: true });
67802
- const tempPath = path66.join(evidenceDir, `.${filename}.tmp`);
67803
- await fs53.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
67804
- await fs53.promises.rename(tempPath, validatedPath);
68100
+ await fs54.promises.mkdir(evidenceDir, { recursive: true });
68101
+ const tempPath = path67.join(evidenceDir, `.${filename}.tmp`);
68102
+ await fs54.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
68103
+ await fs54.promises.rename(tempPath, validatedPath);
67805
68104
  return JSON.stringify({
67806
68105
  success: true,
67807
68106
  phase,
@@ -67879,6 +68178,7 @@ ${footerLines.join(`
67879
68178
  var _heartbeatTimers = new Map;
67880
68179
  var OpenCodeSwarm = async (ctx) => {
67881
68180
  const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
68181
+ swarmState.opencodeClient = ctx.client;
67882
68182
  await loadSnapshot(ctx.directory);
67883
68183
  initTelemetry(ctx.directory);
67884
68184
  const agents = getAgentConfigs(config3);
@@ -67989,7 +68289,7 @@ var OpenCodeSwarm = async (ctx) => {
67989
68289
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
67990
68290
  preflightTriggerManager = new PTM(automationConfig);
67991
68291
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
67992
- const swarmDir = path67.resolve(ctx.directory, ".swarm");
68292
+ const swarmDir = path68.resolve(ctx.directory, ".swarm");
67993
68293
  statusArtifact = new ASA(swarmDir);
67994
68294
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
67995
68295
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -68321,7 +68621,7 @@ var OpenCodeSwarm = async (ctx) => {
68321
68621
  } catch {}
68322
68622
  return Promise.resolve();
68323
68623
  },
68324
- automationConfig.capabilities?.phase_preflight === true && preflightTriggerManager ? createPhaseMonitorHook(ctx.directory, preflightTriggerManager) : knowledgeConfig.enabled ? createPhaseMonitorHook(ctx.directory) : undefined
68624
+ automationConfig.capabilities?.phase_preflight === true && preflightTriggerManager ? createPhaseMonitorHook(ctx.directory, preflightTriggerManager, undefined, createCuratorLLMDelegate(ctx.directory)) : knowledgeConfig.enabled ? createPhaseMonitorHook(ctx.directory, undefined, undefined, createCuratorLLMDelegate(ctx.directory)) : undefined
68325
68625
  ].filter(Boolean)),
68326
68626
  "experimental.session.compacting": compactionHook["experimental.session.compacting"],
68327
68627
  "command.execute.before": safeHook(commandHandler),