opencode-swarm 6.41.4 → 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);
@@ -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,
@@ -55232,10 +55483,10 @@ function createSystemEnhancerHook(config3, directory) {
55232
55483
  });
55233
55484
  if (darkMatter && darkMatter.length > 0) {
55234
55485
  const darkMatterReport = formatDarkMatterOutput2(darkMatter);
55235
- await fs28.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55486
+ await fs29.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
55236
55487
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
55237
55488
  try {
55238
- const projectName = path40.basename(path40.resolve(directory));
55489
+ const projectName = path41.basename(path41.resolve(directory));
55239
55490
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
55240
55491
  const knowledgePath = resolveSwarmKnowledgePath(directory);
55241
55492
  const existingEntries = await readKnowledge(knowledgePath);
@@ -55299,11 +55550,11 @@ function createSystemEnhancerHook(config3, directory) {
55299
55550
  if (handoffContent) {
55300
55551
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55301
55552
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55302
- if (fs28.existsSync(consumedPath)) {
55553
+ if (fs29.existsSync(consumedPath)) {
55303
55554
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55304
- fs28.unlinkSync(consumedPath);
55555
+ fs29.unlinkSync(consumedPath);
55305
55556
  }
55306
- fs28.renameSync(handoffPath, consumedPath);
55557
+ fs29.renameSync(handoffPath, consumedPath);
55307
55558
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55308
55559
  The previous model's session ended. Here is your starting context:
55309
55560
 
@@ -55584,11 +55835,11 @@ ${budgetWarning}`);
55584
55835
  if (handoffContent) {
55585
55836
  const handoffPath = validateSwarmPath(directory, "handoff.md");
55586
55837
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
55587
- if (fs28.existsSync(consumedPath)) {
55838
+ if (fs29.existsSync(consumedPath)) {
55588
55839
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
55589
- fs28.unlinkSync(consumedPath);
55840
+ fs29.unlinkSync(consumedPath);
55590
55841
  }
55591
- fs28.renameSync(handoffPath, consumedPath);
55842
+ fs29.renameSync(handoffPath, consumedPath);
55592
55843
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
55593
55844
  The previous model's session ended. Here is your starting context:
55594
55845
 
@@ -56358,8 +56609,8 @@ function isReadTool(toolName) {
56358
56609
  }
56359
56610
 
56360
56611
  // src/hooks/incremental-verify.ts
56361
- import * as fs29 from "fs";
56362
- import * as path41 from "path";
56612
+ import * as fs30 from "fs";
56613
+ import * as path42 from "path";
56363
56614
 
56364
56615
  // src/hooks/spawn-helper.ts
56365
56616
  import { spawn } from "child_process";
@@ -56434,21 +56685,21 @@ function spawnAsync(command, cwd, timeoutMs) {
56434
56685
  // src/hooks/incremental-verify.ts
56435
56686
  var emittedSkipAdvisories = new Set;
56436
56687
  function detectPackageManager(projectDir) {
56437
- if (fs29.existsSync(path41.join(projectDir, "bun.lockb")))
56688
+ if (fs30.existsSync(path42.join(projectDir, "bun.lockb")))
56438
56689
  return "bun";
56439
- if (fs29.existsSync(path41.join(projectDir, "pnpm-lock.yaml")))
56690
+ if (fs30.existsSync(path42.join(projectDir, "pnpm-lock.yaml")))
56440
56691
  return "pnpm";
56441
- if (fs29.existsSync(path41.join(projectDir, "yarn.lock")))
56692
+ if (fs30.existsSync(path42.join(projectDir, "yarn.lock")))
56442
56693
  return "yarn";
56443
- if (fs29.existsSync(path41.join(projectDir, "package-lock.json")))
56694
+ if (fs30.existsSync(path42.join(projectDir, "package-lock.json")))
56444
56695
  return "npm";
56445
56696
  return "bun";
56446
56697
  }
56447
56698
  function detectTypecheckCommand(projectDir) {
56448
- const pkgPath = path41.join(projectDir, "package.json");
56449
- if (fs29.existsSync(pkgPath)) {
56699
+ const pkgPath = path42.join(projectDir, "package.json");
56700
+ if (fs30.existsSync(pkgPath)) {
56450
56701
  try {
56451
- const pkg = JSON.parse(fs29.readFileSync(pkgPath, "utf8"));
56702
+ const pkg = JSON.parse(fs30.readFileSync(pkgPath, "utf8"));
56452
56703
  const scripts = pkg.scripts;
56453
56704
  if (scripts?.typecheck) {
56454
56705
  const pm = detectPackageManager(projectDir);
@@ -56462,8 +56713,8 @@ function detectTypecheckCommand(projectDir) {
56462
56713
  ...pkg.dependencies,
56463
56714
  ...pkg.devDependencies
56464
56715
  };
56465
- if (!deps?.typescript && !fs29.existsSync(path41.join(projectDir, "tsconfig.json"))) {}
56466
- 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"));
56467
56718
  if (hasTSMarkers) {
56468
56719
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
56469
56720
  }
@@ -56471,17 +56722,17 @@ function detectTypecheckCommand(projectDir) {
56471
56722
  return null;
56472
56723
  }
56473
56724
  }
56474
- if (fs29.existsSync(path41.join(projectDir, "go.mod"))) {
56725
+ if (fs30.existsSync(path42.join(projectDir, "go.mod"))) {
56475
56726
  return { command: ["go", "vet", "./..."], language: "go" };
56476
56727
  }
56477
- if (fs29.existsSync(path41.join(projectDir, "Cargo.toml"))) {
56728
+ if (fs30.existsSync(path42.join(projectDir, "Cargo.toml"))) {
56478
56729
  return { command: ["cargo", "check"], language: "rust" };
56479
56730
  }
56480
- 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"))) {
56481
56732
  return { command: null, language: "python" };
56482
56733
  }
56483
56734
  try {
56484
- const entries = fs29.readdirSync(projectDir);
56735
+ const entries = fs30.readdirSync(projectDir);
56485
56736
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
56486
56737
  return {
56487
56738
  command: ["dotnet", "build", "--no-restore"],
@@ -56661,19 +56912,7 @@ function sanitizeLessonForContext(text) {
56661
56912
  }
56662
56913
  function isOrchestratorAgent(agentName) {
56663
56914
  const stripped = stripKnownSwarmPrefix(agentName);
56664
- const nonOrchestratorAgents = new Set([
56665
- "coder",
56666
- "reviewer",
56667
- "test_engineer",
56668
- "security_reviewer",
56669
- "integration_analyst",
56670
- "docs_writer",
56671
- "designer",
56672
- "critic",
56673
- "docs",
56674
- "explorer"
56675
- ]);
56676
- return !nonOrchestratorAgents.has(stripped.toLowerCase());
56915
+ return stripped.toLowerCase() === "architect";
56677
56916
  }
56678
56917
  function injectKnowledgeMessage(output, text) {
56679
56918
  if (!output.messages)
@@ -56790,7 +57029,7 @@ ${injectionText}`;
56790
57029
  // src/hooks/scope-guard.ts
56791
57030
  init_constants();
56792
57031
  init_schema();
56793
- import * as path43 from "path";
57032
+ import * as path44 from "path";
56794
57033
  var WRITE_TOOLS = new Set([
56795
57034
  "write",
56796
57035
  "edit",
@@ -56852,13 +57091,13 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
56852
57091
  }
56853
57092
  function isFileInScope(filePath, scopeEntries, directory) {
56854
57093
  const dir = directory ?? process.cwd();
56855
- const resolvedFile = path43.resolve(dir, filePath);
57094
+ const resolvedFile = path44.resolve(dir, filePath);
56856
57095
  return scopeEntries.some((scope) => {
56857
- const resolvedScope = path43.resolve(dir, scope);
57096
+ const resolvedScope = path44.resolve(dir, scope);
56858
57097
  if (resolvedFile === resolvedScope)
56859
57098
  return true;
56860
- const rel = path43.relative(resolvedScope, resolvedFile);
56861
- 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);
56862
57101
  });
56863
57102
  }
56864
57103
 
@@ -56907,8 +57146,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
56907
57146
  }
56908
57147
 
56909
57148
  // src/hooks/slop-detector.ts
56910
- import * as fs31 from "fs";
56911
- import * as path44 from "path";
57149
+ import * as fs32 from "fs";
57150
+ import * as path45 from "path";
56912
57151
  var WRITE_EDIT_TOOLS = new Set([
56913
57152
  "write",
56914
57153
  "edit",
@@ -56953,12 +57192,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
56953
57192
  function walkFiles(dir, exts, deadline) {
56954
57193
  const results = [];
56955
57194
  try {
56956
- for (const entry of fs31.readdirSync(dir, { withFileTypes: true })) {
57195
+ for (const entry of fs32.readdirSync(dir, { withFileTypes: true })) {
56957
57196
  if (deadline !== undefined && Date.now() > deadline)
56958
57197
  break;
56959
57198
  if (entry.isSymbolicLink())
56960
57199
  continue;
56961
- const full = path44.join(dir, entry.name);
57200
+ const full = path45.join(dir, entry.name);
56962
57201
  if (entry.isDirectory()) {
56963
57202
  if (entry.name === "node_modules" || entry.name === ".git")
56964
57203
  continue;
@@ -56973,7 +57212,7 @@ function walkFiles(dir, exts, deadline) {
56973
57212
  return results;
56974
57213
  }
56975
57214
  function checkDeadExports(content, projectDir, startTime) {
56976
- const hasPackageJson = fs31.existsSync(path44.join(projectDir, "package.json"));
57215
+ const hasPackageJson = fs32.existsSync(path45.join(projectDir, "package.json"));
56977
57216
  if (!hasPackageJson)
56978
57217
  return null;
56979
57218
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -56996,7 +57235,7 @@ function checkDeadExports(content, projectDir, startTime) {
56996
57235
  if (found || Date.now() - startTime > 480)
56997
57236
  break;
56998
57237
  try {
56999
- const text = fs31.readFileSync(file3, "utf-8");
57238
+ const text = fs32.readFileSync(file3, "utf-8");
57000
57239
  if (importPattern.test(text))
57001
57240
  found = true;
57002
57241
  importPattern.lastIndex = 0;
@@ -57129,7 +57368,7 @@ Review before proceeding.`;
57129
57368
 
57130
57369
  // src/hooks/steering-consumed.ts
57131
57370
  init_utils2();
57132
- import * as fs32 from "fs";
57371
+ import * as fs33 from "fs";
57133
57372
  function recordSteeringConsumed(directory, directiveId) {
57134
57373
  try {
57135
57374
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -57138,7 +57377,7 @@ function recordSteeringConsumed(directory, directiveId) {
57138
57377
  directiveId,
57139
57378
  timestamp: new Date().toISOString()
57140
57379
  };
57141
- fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
57380
+ fs33.appendFileSync(eventsPath, `${JSON.stringify(event)}
57142
57381
  `, "utf-8");
57143
57382
  } catch {}
57144
57383
  }
@@ -57183,7 +57422,7 @@ init_config_doctor();
57183
57422
 
57184
57423
  // src/session/snapshot-reader.ts
57185
57424
  init_utils2();
57186
- import { renameSync as renameSync11 } from "fs";
57425
+ import { renameSync as renameSync12 } from "fs";
57187
57426
  var TRANSIENT_SESSION_FIELDS = [
57188
57427
  { name: "revisionLimitHit", resetValue: false },
57189
57428
  { name: "coderRevisions", resetValue: 0 },
@@ -57294,7 +57533,7 @@ async function readSnapshot(directory) {
57294
57533
  if (parsed.version !== 1 && parsed.version !== 2) {
57295
57534
  try {
57296
57535
  const quarantinePath = validateSwarmPath(directory, "session/state.json.quarantine");
57297
- renameSync11(resolvedPath, quarantinePath);
57536
+ renameSync12(resolvedPath, quarantinePath);
57298
57537
  } catch {}
57299
57538
  return null;
57300
57539
  }
@@ -57551,8 +57790,8 @@ init_dist();
57551
57790
  init_manager();
57552
57791
  init_create_tool();
57553
57792
  init_resolve_working_directory();
57554
- import * as fs33 from "fs";
57555
- import * as path45 from "path";
57793
+ import * as fs34 from "fs";
57794
+ import * as path46 from "path";
57556
57795
  var EVIDENCE_DIR = ".swarm/evidence";
57557
57796
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
57558
57797
  function isValidTaskId3(taskId) {
@@ -57569,18 +57808,18 @@ function isValidTaskId3(taskId) {
57569
57808
  return TASK_ID_PATTERN2.test(taskId);
57570
57809
  }
57571
57810
  function isPathWithinSwarm(filePath, workspaceRoot) {
57572
- const normalizedWorkspace = path45.resolve(workspaceRoot);
57573
- const swarmPath = path45.join(normalizedWorkspace, ".swarm", "evidence");
57574
- 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);
57575
57814
  return normalizedPath.startsWith(swarmPath);
57576
57815
  }
57577
57816
  function readEvidenceFile(evidencePath) {
57578
- if (!fs33.existsSync(evidencePath)) {
57817
+ if (!fs34.existsSync(evidencePath)) {
57579
57818
  return null;
57580
57819
  }
57581
57820
  let content;
57582
57821
  try {
57583
- content = fs33.readFileSync(evidencePath, "utf-8");
57822
+ content = fs34.readFileSync(evidencePath, "utf-8");
57584
57823
  } catch {
57585
57824
  return null;
57586
57825
  }
@@ -57652,7 +57891,7 @@ var check_gate_status = createSwarmTool({
57652
57891
  };
57653
57892
  return JSON.stringify(errorResult, null, 2);
57654
57893
  }
57655
- const evidencePath = path45.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57894
+ const evidencePath = path46.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
57656
57895
  if (!isPathWithinSwarm(evidencePath, directory)) {
57657
57896
  const errorResult = {
57658
57897
  taskId: taskIdInput,
@@ -57745,8 +57984,8 @@ init_co_change_analyzer();
57745
57984
  // src/tools/completion-verify.ts
57746
57985
  init_dist();
57747
57986
  init_utils2();
57748
- import * as fs34 from "fs";
57749
- import * as path46 from "path";
57987
+ import * as fs35 from "fs";
57988
+ import * as path47 from "path";
57750
57989
  init_create_tool();
57751
57990
  init_resolve_working_directory();
57752
57991
  function extractMatches(regex, text) {
@@ -57842,7 +58081,7 @@ async function executeCompletionVerify(args2, directory) {
57842
58081
  let plan;
57843
58082
  try {
57844
58083
  const planPath = validateSwarmPath(directory, "plan.json");
57845
- const planRaw = fs34.readFileSync(planPath, "utf-8");
58084
+ const planRaw = fs35.readFileSync(planPath, "utf-8");
57846
58085
  plan = JSON.parse(planRaw);
57847
58086
  } catch {
57848
58087
  const result2 = {
@@ -57900,10 +58139,10 @@ async function executeCompletionVerify(args2, directory) {
57900
58139
  let hasFileReadFailure = false;
57901
58140
  for (const filePath of fileTargets) {
57902
58141
  const normalizedPath = filePath.replace(/\\/g, "/");
57903
- const resolvedPath = path46.resolve(directory, normalizedPath);
57904
- const projectRoot = path46.resolve(directory);
57905
- const relative6 = path46.relative(projectRoot, resolvedPath);
57906
- 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);
57907
58146
  if (!withinProject) {
57908
58147
  blockedTasks.push({
57909
58148
  task_id: task.id,
@@ -57916,7 +58155,7 @@ async function executeCompletionVerify(args2, directory) {
57916
58155
  }
57917
58156
  let fileContent;
57918
58157
  try {
57919
- fileContent = fs34.readFileSync(resolvedPath, "utf-8");
58158
+ fileContent = fs35.readFileSync(resolvedPath, "utf-8");
57920
58159
  } catch {
57921
58160
  blockedTasks.push({
57922
58161
  task_id: task.id,
@@ -57958,9 +58197,9 @@ async function executeCompletionVerify(args2, directory) {
57958
58197
  blockedTasks
57959
58198
  };
57960
58199
  try {
57961
- const evidenceDir = path46.join(directory, ".swarm", "evidence", `${phase}`);
57962
- const evidencePath = path46.join(evidenceDir, "completion-verify.json");
57963
- 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 });
57964
58203
  const evidenceBundle = {
57965
58204
  schema_version: "1.0.0",
57966
58205
  task_id: "completion-verify",
@@ -57981,7 +58220,7 @@ async function executeCompletionVerify(args2, directory) {
57981
58220
  }
57982
58221
  ]
57983
58222
  };
57984
- fs34.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
58223
+ fs35.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
57985
58224
  } catch {}
57986
58225
  return JSON.stringify(result, null, 2);
57987
58226
  }
@@ -58035,12 +58274,12 @@ var completion_verify = createSwarmTool({
58035
58274
  });
58036
58275
  // src/tools/complexity-hotspots.ts
58037
58276
  init_dist();
58038
- import * as fs36 from "fs";
58039
- import * as path48 from "path";
58277
+ import * as fs37 from "fs";
58278
+ import * as path49 from "path";
58040
58279
 
58041
58280
  // src/quality/metrics.ts
58042
- import * as fs35 from "fs";
58043
- import * as path47 from "path";
58281
+ import * as fs36 from "fs";
58282
+ import * as path48 from "path";
58044
58283
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
58045
58284
  var MIN_DUPLICATION_LINES = 10;
58046
58285
  function estimateCyclomaticComplexity(content) {
@@ -58078,11 +58317,11 @@ function estimateCyclomaticComplexity(content) {
58078
58317
  }
58079
58318
  function getComplexityForFile(filePath) {
58080
58319
  try {
58081
- const stat2 = fs35.statSync(filePath);
58320
+ const stat2 = fs36.statSync(filePath);
58082
58321
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58083
58322
  return null;
58084
58323
  }
58085
- const content = fs35.readFileSync(filePath, "utf-8");
58324
+ const content = fs36.readFileSync(filePath, "utf-8");
58086
58325
  return estimateCyclomaticComplexity(content);
58087
58326
  } catch {
58088
58327
  return null;
@@ -58092,8 +58331,8 @@ async function computeComplexityDelta(files, workingDir) {
58092
58331
  let totalComplexity = 0;
58093
58332
  const analyzedFiles = [];
58094
58333
  for (const file3 of files) {
58095
- const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58096
- if (!fs35.existsSync(fullPath)) {
58334
+ const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
58335
+ if (!fs36.existsSync(fullPath)) {
58097
58336
  continue;
58098
58337
  }
58099
58338
  const complexity = getComplexityForFile(fullPath);
@@ -58214,8 +58453,8 @@ function countGoExports(content) {
58214
58453
  }
58215
58454
  function getExportCountForFile(filePath) {
58216
58455
  try {
58217
- const content = fs35.readFileSync(filePath, "utf-8");
58218
- const ext = path47.extname(filePath).toLowerCase();
58456
+ const content = fs36.readFileSync(filePath, "utf-8");
58457
+ const ext = path48.extname(filePath).toLowerCase();
58219
58458
  switch (ext) {
58220
58459
  case ".ts":
58221
58460
  case ".tsx":
@@ -58241,8 +58480,8 @@ async function computePublicApiDelta(files, workingDir) {
58241
58480
  let totalExports = 0;
58242
58481
  const analyzedFiles = [];
58243
58482
  for (const file3 of files) {
58244
- const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58245
- if (!fs35.existsSync(fullPath)) {
58483
+ const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
58484
+ if (!fs36.existsSync(fullPath)) {
58246
58485
  continue;
58247
58486
  }
58248
58487
  const exports = getExportCountForFile(fullPath);
@@ -58275,16 +58514,16 @@ async function computeDuplicationRatio(files, workingDir) {
58275
58514
  let duplicateLines = 0;
58276
58515
  const analyzedFiles = [];
58277
58516
  for (const file3 of files) {
58278
- const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
58279
- if (!fs35.existsSync(fullPath)) {
58517
+ const fullPath = path48.isAbsolute(file3) ? file3 : path48.join(workingDir, file3);
58518
+ if (!fs36.existsSync(fullPath)) {
58280
58519
  continue;
58281
58520
  }
58282
58521
  try {
58283
- const stat2 = fs35.statSync(fullPath);
58522
+ const stat2 = fs36.statSync(fullPath);
58284
58523
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
58285
58524
  continue;
58286
58525
  }
58287
- const content = fs35.readFileSync(fullPath, "utf-8");
58526
+ const content = fs36.readFileSync(fullPath, "utf-8");
58288
58527
  const lines = content.split(`
58289
58528
  `).filter((line) => line.trim().length > 0);
58290
58529
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -58308,8 +58547,8 @@ function countCodeLines(content) {
58308
58547
  return lines.length;
58309
58548
  }
58310
58549
  function isTestFile(filePath) {
58311
- const basename7 = path47.basename(filePath);
58312
- const _ext = path47.extname(filePath).toLowerCase();
58550
+ const basename7 = path48.basename(filePath);
58551
+ const _ext = path48.extname(filePath).toLowerCase();
58313
58552
  const testPatterns = [
58314
58553
  ".test.",
58315
58554
  ".spec.",
@@ -58390,8 +58629,8 @@ function matchGlobSegment(globSegments, pathSegments) {
58390
58629
  }
58391
58630
  return gIndex === globSegments.length && pIndex === pathSegments.length;
58392
58631
  }
58393
- function matchesGlobSegment(path48, glob) {
58394
- const normalizedPath = path48.replace(/\\/g, "/");
58632
+ function matchesGlobSegment(path49, glob) {
58633
+ const normalizedPath = path49.replace(/\\/g, "/");
58395
58634
  const normalizedGlob = glob.replace(/\\/g, "/");
58396
58635
  if (normalizedPath.includes("//")) {
58397
58636
  return false;
@@ -58422,8 +58661,8 @@ function simpleGlobToRegex2(glob) {
58422
58661
  function hasGlobstar(glob) {
58423
58662
  return glob.includes("**");
58424
58663
  }
58425
- function globMatches(path48, glob) {
58426
- const normalizedPath = path48.replace(/\\/g, "/");
58664
+ function globMatches(path49, glob) {
58665
+ const normalizedPath = path49.replace(/\\/g, "/");
58427
58666
  if (!glob || glob === "") {
58428
58667
  if (normalizedPath.includes("//")) {
58429
58668
  return false;
@@ -58459,31 +58698,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
58459
58698
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58460
58699
  let testLines = 0;
58461
58700
  let codeLines = 0;
58462
- const srcDir = path47.join(workingDir, "src");
58463
- if (fs35.existsSync(srcDir)) {
58701
+ const srcDir = path48.join(workingDir, "src");
58702
+ if (fs36.existsSync(srcDir)) {
58464
58703
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
58465
58704
  codeLines += lines;
58466
58705
  });
58467
58706
  }
58468
58707
  const possibleSrcDirs = ["lib", "app", "source", "core"];
58469
58708
  for (const dir of possibleSrcDirs) {
58470
- const dirPath = path47.join(workingDir, dir);
58471
- if (fs35.existsSync(dirPath)) {
58709
+ const dirPath = path48.join(workingDir, dir);
58710
+ if (fs36.existsSync(dirPath)) {
58472
58711
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
58473
58712
  codeLines += lines;
58474
58713
  });
58475
58714
  }
58476
58715
  }
58477
- const testsDir = path47.join(workingDir, "tests");
58478
- if (fs35.existsSync(testsDir)) {
58716
+ const testsDir = path48.join(workingDir, "tests");
58717
+ if (fs36.existsSync(testsDir)) {
58479
58718
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
58480
58719
  testLines += lines;
58481
58720
  });
58482
58721
  }
58483
58722
  const possibleTestDirs = ["test", "__tests__", "specs"];
58484
58723
  for (const dir of possibleTestDirs) {
58485
- const dirPath = path47.join(workingDir, dir);
58486
- if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
58724
+ const dirPath = path48.join(workingDir, dir);
58725
+ if (fs36.existsSync(dirPath) && dirPath !== testsDir) {
58487
58726
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
58488
58727
  testLines += lines;
58489
58728
  });
@@ -58495,9 +58734,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
58495
58734
  }
58496
58735
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
58497
58736
  try {
58498
- const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
58737
+ const entries = fs36.readdirSync(dirPath, { withFileTypes: true });
58499
58738
  for (const entry of entries) {
58500
- const fullPath = path47.join(dirPath, entry.name);
58739
+ const fullPath = path48.join(dirPath, entry.name);
58501
58740
  if (entry.isDirectory()) {
58502
58741
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
58503
58742
  continue;
@@ -58505,7 +58744,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58505
58744
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
58506
58745
  } else if (entry.isFile()) {
58507
58746
  const relativePath = fullPath.replace(`${dirPath}/`, "");
58508
- const ext = path47.extname(entry.name).toLowerCase();
58747
+ const ext = path48.extname(entry.name).toLowerCase();
58509
58748
  const validExts = [
58510
58749
  ".ts",
58511
58750
  ".tsx",
@@ -58541,7 +58780,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
58541
58780
  continue;
58542
58781
  }
58543
58782
  try {
58544
- const content = fs35.readFileSync(fullPath, "utf-8");
58783
+ const content = fs36.readFileSync(fullPath, "utf-8");
58545
58784
  const lines = countCodeLines(content);
58546
58785
  callback(lines);
58547
58786
  } catch {}
@@ -58742,11 +58981,11 @@ async function getGitChurn(days, directory) {
58742
58981
  }
58743
58982
  function getComplexityForFile2(filePath) {
58744
58983
  try {
58745
- const stat2 = fs36.statSync(filePath);
58984
+ const stat2 = fs37.statSync(filePath);
58746
58985
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
58747
58986
  return null;
58748
58987
  }
58749
- const content = fs36.readFileSync(filePath, "utf-8");
58988
+ const content = fs37.readFileSync(filePath, "utf-8");
58750
58989
  return estimateCyclomaticComplexity(content);
58751
58990
  } catch {
58752
58991
  return null;
@@ -58757,7 +58996,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58757
58996
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
58758
58997
  const filteredChurn = new Map;
58759
58998
  for (const [file3, count] of churnMap) {
58760
- const ext = path48.extname(file3).toLowerCase();
58999
+ const ext = path49.extname(file3).toLowerCase();
58761
59000
  if (extSet.has(ext)) {
58762
59001
  filteredChurn.set(file3, count);
58763
59002
  }
@@ -58767,8 +59006,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
58767
59006
  let analyzedFiles = 0;
58768
59007
  for (const [file3, churnCount] of filteredChurn) {
58769
59008
  let fullPath = file3;
58770
- if (!fs36.existsSync(fullPath)) {
58771
- fullPath = path48.join(cwd, file3);
59009
+ if (!fs37.existsSync(fullPath)) {
59010
+ fullPath = path49.join(cwd, file3);
58772
59011
  }
58773
59012
  const complexity = getComplexityForFile2(fullPath);
58774
59013
  if (complexity !== null) {
@@ -58917,6 +59156,7 @@ var complexity_hotspots = createSwarmTool({
58917
59156
  init_dist();
58918
59157
  init_config();
58919
59158
  init_schema();
59159
+ init_review_receipt();
58920
59160
  init_create_tool();
58921
59161
  var curator_analyze = createSwarmTool({
58922
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.",
@@ -58952,7 +59192,40 @@ var curator_analyze = createSwarmTool({
58952
59192
  const { config: config3 } = loadPluginConfigWithMeta(directory);
58953
59193
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
58954
59194
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
58955
- 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
+ }
58956
59229
  let applied = 0;
58957
59230
  let skipped = 0;
58958
59231
  if (typedArgs.recommendations && typedArgs.recommendations.length > 0) {
@@ -58976,8 +59249,8 @@ var curator_analyze = createSwarmTool({
58976
59249
  });
58977
59250
  // src/tools/declare-scope.ts
58978
59251
  init_tool();
58979
- import * as fs37 from "fs";
58980
- import * as path49 from "path";
59252
+ import * as fs38 from "fs";
59253
+ import * as path50 from "path";
58981
59254
  init_create_tool();
58982
59255
  function validateTaskIdFormat(taskId) {
58983
59256
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -59056,8 +59329,8 @@ async function executeDeclareScope(args2, fallbackDir) {
59056
59329
  };
59057
59330
  }
59058
59331
  }
59059
- normalizedDir = path49.normalize(args2.working_directory);
59060
- const pathParts = normalizedDir.split(path49.sep);
59332
+ normalizedDir = path50.normalize(args2.working_directory);
59333
+ const pathParts = normalizedDir.split(path50.sep);
59061
59334
  if (pathParts.includes("..")) {
59062
59335
  return {
59063
59336
  success: false,
@@ -59067,11 +59340,11 @@ async function executeDeclareScope(args2, fallbackDir) {
59067
59340
  ]
59068
59341
  };
59069
59342
  }
59070
- const resolvedDir = path49.resolve(normalizedDir);
59343
+ const resolvedDir = path50.resolve(normalizedDir);
59071
59344
  try {
59072
- const realPath = fs37.realpathSync(resolvedDir);
59073
- const planPath2 = path49.join(realPath, ".swarm", "plan.json");
59074
- if (!fs37.existsSync(planPath2)) {
59345
+ const realPath = fs38.realpathSync(resolvedDir);
59346
+ const planPath2 = path50.join(realPath, ".swarm", "plan.json");
59347
+ if (!fs38.existsSync(planPath2)) {
59075
59348
  return {
59076
59349
  success: false,
59077
59350
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -59094,8 +59367,8 @@ async function executeDeclareScope(args2, fallbackDir) {
59094
59367
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
59095
59368
  }
59096
59369
  const directory = normalizedDir || fallbackDir;
59097
- const planPath = path49.resolve(directory, ".swarm", "plan.json");
59098
- if (!fs37.existsSync(planPath)) {
59370
+ const planPath = path50.resolve(directory, ".swarm", "plan.json");
59371
+ if (!fs38.existsSync(planPath)) {
59099
59372
  return {
59100
59373
  success: false,
59101
59374
  message: "No plan found",
@@ -59104,7 +59377,7 @@ async function executeDeclareScope(args2, fallbackDir) {
59104
59377
  }
59105
59378
  let planContent;
59106
59379
  try {
59107
- planContent = JSON.parse(fs37.readFileSync(planPath, "utf-8"));
59380
+ planContent = JSON.parse(fs38.readFileSync(planPath, "utf-8"));
59108
59381
  } catch {
59109
59382
  return {
59110
59383
  success: false,
@@ -59136,8 +59409,8 @@ async function executeDeclareScope(args2, fallbackDir) {
59136
59409
  const normalizeErrors = [];
59137
59410
  const dir = normalizedDir || fallbackDir || process.cwd();
59138
59411
  const mergedFiles = rawMergedFiles.map((file3) => {
59139
- if (path49.isAbsolute(file3)) {
59140
- const relativePath = path49.relative(dir, file3).replace(/\\/g, "/");
59412
+ if (path50.isAbsolute(file3)) {
59413
+ const relativePath = path50.relative(dir, file3).replace(/\\/g, "/");
59141
59414
  if (relativePath.startsWith("..")) {
59142
59415
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
59143
59416
  return file3;
@@ -59463,20 +59736,20 @@ function validateBase(base) {
59463
59736
  function validatePaths(paths) {
59464
59737
  if (!paths)
59465
59738
  return null;
59466
- for (const path51 of paths) {
59467
- if (!path51 || path51.length === 0) {
59739
+ for (const path52 of paths) {
59740
+ if (!path52 || path52.length === 0) {
59468
59741
  return "empty path not allowed";
59469
59742
  }
59470
- if (path51.length > MAX_PATH_LENGTH) {
59743
+ if (path52.length > MAX_PATH_LENGTH) {
59471
59744
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
59472
59745
  }
59473
- if (SHELL_METACHARACTERS2.test(path51)) {
59746
+ if (SHELL_METACHARACTERS2.test(path52)) {
59474
59747
  return "path contains shell metacharacters";
59475
59748
  }
59476
- if (path51.startsWith("-")) {
59749
+ if (path52.startsWith("-")) {
59477
59750
  return 'path cannot start with "-" (option-like arguments not allowed)';
59478
59751
  }
59479
- if (CONTROL_CHAR_PATTERN2.test(path51)) {
59752
+ if (CONTROL_CHAR_PATTERN2.test(path52)) {
59480
59753
  return "path contains control characters";
59481
59754
  }
59482
59755
  }
@@ -59557,8 +59830,8 @@ var diff = createSwarmTool({
59557
59830
  if (parts2.length >= 3) {
59558
59831
  const additions = parseInt(parts2[0], 10) || 0;
59559
59832
  const deletions = parseInt(parts2[1], 10) || 0;
59560
- const path51 = parts2[2];
59561
- files.push({ path: path51, additions, deletions });
59833
+ const path52 = parts2[2];
59834
+ files.push({ path: path52, additions, deletions });
59562
59835
  }
59563
59836
  }
59564
59837
  const contractChanges = [];
@@ -59840,8 +60113,8 @@ Use these as DOMAIN values when delegating to @sme.`;
59840
60113
  // src/tools/evidence-check.ts
59841
60114
  init_dist();
59842
60115
  init_create_tool();
59843
- import * as fs38 from "fs";
59844
- import * as path51 from "path";
60116
+ import * as fs39 from "fs";
60117
+ import * as path52 from "path";
59845
60118
  var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
59846
60119
  var MAX_EVIDENCE_FILES = 1000;
59847
60120
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -59868,9 +60141,9 @@ function validateRequiredTypes(input) {
59868
60141
  return null;
59869
60142
  }
59870
60143
  function isPathWithinSwarm2(filePath, cwd) {
59871
- const normalizedCwd = path51.resolve(cwd);
59872
- const swarmPath = path51.join(normalizedCwd, ".swarm");
59873
- const normalizedPath = path51.resolve(filePath);
60144
+ const normalizedCwd = path52.resolve(cwd);
60145
+ const swarmPath = path52.join(normalizedCwd, ".swarm");
60146
+ const normalizedPath = path52.resolve(filePath);
59874
60147
  return normalizedPath.startsWith(swarmPath);
59875
60148
  }
59876
60149
  function parseCompletedTasks(planContent) {
@@ -59886,12 +60159,12 @@ function parseCompletedTasks(planContent) {
59886
60159
  }
59887
60160
  function readEvidenceFiles(evidenceDir, _cwd) {
59888
60161
  const evidence = [];
59889
- if (!fs38.existsSync(evidenceDir) || !fs38.statSync(evidenceDir).isDirectory()) {
60162
+ if (!fs39.existsSync(evidenceDir) || !fs39.statSync(evidenceDir).isDirectory()) {
59890
60163
  return evidence;
59891
60164
  }
59892
60165
  let files;
59893
60166
  try {
59894
- files = fs38.readdirSync(evidenceDir);
60167
+ files = fs39.readdirSync(evidenceDir);
59895
60168
  } catch {
59896
60169
  return evidence;
59897
60170
  }
@@ -59900,14 +60173,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59900
60173
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
59901
60174
  continue;
59902
60175
  }
59903
- const filePath = path51.join(evidenceDir, filename);
60176
+ const filePath = path52.join(evidenceDir, filename);
59904
60177
  try {
59905
- const resolvedPath = path51.resolve(filePath);
59906
- const evidenceDirResolved = path51.resolve(evidenceDir);
60178
+ const resolvedPath = path52.resolve(filePath);
60179
+ const evidenceDirResolved = path52.resolve(evidenceDir);
59907
60180
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
59908
60181
  continue;
59909
60182
  }
59910
- const stat2 = fs38.lstatSync(filePath);
60183
+ const stat2 = fs39.lstatSync(filePath);
59911
60184
  if (!stat2.isFile()) {
59912
60185
  continue;
59913
60186
  }
@@ -59916,7 +60189,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59916
60189
  }
59917
60190
  let fileStat;
59918
60191
  try {
59919
- fileStat = fs38.statSync(filePath);
60192
+ fileStat = fs39.statSync(filePath);
59920
60193
  if (fileStat.size > MAX_FILE_SIZE_BYTES4) {
59921
60194
  continue;
59922
60195
  }
@@ -59925,7 +60198,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
59925
60198
  }
59926
60199
  let content;
59927
60200
  try {
59928
- content = fs38.readFileSync(filePath, "utf-8");
60201
+ content = fs39.readFileSync(filePath, "utf-8");
59929
60202
  } catch {
59930
60203
  continue;
59931
60204
  }
@@ -60021,7 +60294,7 @@ var evidence_check = createSwarmTool({
60021
60294
  return JSON.stringify(errorResult, null, 2);
60022
60295
  }
60023
60296
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
60024
- const planPath = path51.join(cwd, PLAN_FILE);
60297
+ const planPath = path52.join(cwd, PLAN_FILE);
60025
60298
  if (!isPathWithinSwarm2(planPath, cwd)) {
60026
60299
  const errorResult = {
60027
60300
  error: "plan file path validation failed",
@@ -60035,7 +60308,7 @@ var evidence_check = createSwarmTool({
60035
60308
  }
60036
60309
  let planContent;
60037
60310
  try {
60038
- planContent = fs38.readFileSync(planPath, "utf-8");
60311
+ planContent = fs39.readFileSync(planPath, "utf-8");
60039
60312
  } catch {
60040
60313
  const result2 = {
60041
60314
  message: "No completed tasks found in plan.",
@@ -60053,7 +60326,7 @@ var evidence_check = createSwarmTool({
60053
60326
  };
60054
60327
  return JSON.stringify(result2, null, 2);
60055
60328
  }
60056
- const evidenceDir = path51.join(cwd, EVIDENCE_DIR2);
60329
+ const evidenceDir = path52.join(cwd, EVIDENCE_DIR2);
60057
60330
  const evidence = readEvidenceFiles(evidenceDir, cwd);
60058
60331
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
60059
60332
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -60070,8 +60343,8 @@ var evidence_check = createSwarmTool({
60070
60343
  // src/tools/file-extractor.ts
60071
60344
  init_tool();
60072
60345
  init_create_tool();
60073
- import * as fs39 from "fs";
60074
- import * as path52 from "path";
60346
+ import * as fs40 from "fs";
60347
+ import * as path53 from "path";
60075
60348
  var EXT_MAP = {
60076
60349
  python: ".py",
60077
60350
  py: ".py",
@@ -60133,8 +60406,8 @@ var extract_code_blocks = createSwarmTool({
60133
60406
  execute: async (args2, directory) => {
60134
60407
  const { content, output_dir, prefix } = args2;
60135
60408
  const targetDir = output_dir || directory;
60136
- if (!fs39.existsSync(targetDir)) {
60137
- fs39.mkdirSync(targetDir, { recursive: true });
60409
+ if (!fs40.existsSync(targetDir)) {
60410
+ fs40.mkdirSync(targetDir, { recursive: true });
60138
60411
  }
60139
60412
  if (!content) {
60140
60413
  return "Error: content is required";
@@ -60152,16 +60425,16 @@ var extract_code_blocks = createSwarmTool({
60152
60425
  if (prefix) {
60153
60426
  filename = `${prefix}_${filename}`;
60154
60427
  }
60155
- let filepath = path52.join(targetDir, filename);
60156
- const base = path52.basename(filepath, path52.extname(filepath));
60157
- 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);
60158
60431
  let counter = 1;
60159
- while (fs39.existsSync(filepath)) {
60160
- filepath = path52.join(targetDir, `${base}_${counter}${ext}`);
60432
+ while (fs40.existsSync(filepath)) {
60433
+ filepath = path53.join(targetDir, `${base}_${counter}${ext}`);
60161
60434
  counter++;
60162
60435
  }
60163
60436
  try {
60164
- fs39.writeFileSync(filepath, code.trim(), "utf-8");
60437
+ fs40.writeFileSync(filepath, code.trim(), "utf-8");
60165
60438
  savedFiles.push(filepath);
60166
60439
  } catch (error93) {
60167
60440
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -60277,8 +60550,8 @@ var gitingest = createSwarmTool({
60277
60550
  // src/tools/imports.ts
60278
60551
  init_dist();
60279
60552
  init_create_tool();
60280
- import * as fs40 from "fs";
60281
- import * as path53 from "path";
60553
+ import * as fs41 from "fs";
60554
+ import * as path54 from "path";
60282
60555
  var MAX_FILE_PATH_LENGTH2 = 500;
60283
60556
  var MAX_SYMBOL_LENGTH = 256;
60284
60557
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
@@ -60326,7 +60599,7 @@ function validateSymbolInput(symbol3) {
60326
60599
  return null;
60327
60600
  }
60328
60601
  function isBinaryFile2(filePath, buffer) {
60329
- const ext = path53.extname(filePath).toLowerCase();
60602
+ const ext = path54.extname(filePath).toLowerCase();
60330
60603
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
60331
60604
  return false;
60332
60605
  }
@@ -60350,15 +60623,15 @@ function parseImports(content, targetFile, targetSymbol) {
60350
60623
  const imports = [];
60351
60624
  let _resolvedTarget;
60352
60625
  try {
60353
- _resolvedTarget = path53.resolve(targetFile);
60626
+ _resolvedTarget = path54.resolve(targetFile);
60354
60627
  } catch {
60355
60628
  _resolvedTarget = targetFile;
60356
60629
  }
60357
- const targetBasename = path53.basename(targetFile, path53.extname(targetFile));
60630
+ const targetBasename = path54.basename(targetFile, path54.extname(targetFile));
60358
60631
  const targetWithExt = targetFile;
60359
60632
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
60360
- const normalizedTargetWithExt = path53.normalize(targetWithExt).replace(/\\/g, "/");
60361
- const normalizedTargetWithoutExt = path53.normalize(targetWithoutExt).replace(/\\/g, "/");
60633
+ const normalizedTargetWithExt = path54.normalize(targetWithExt).replace(/\\/g, "/");
60634
+ const normalizedTargetWithoutExt = path54.normalize(targetWithoutExt).replace(/\\/g, "/");
60362
60635
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
60363
60636
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
60364
60637
  const modulePath = match[1] || match[2] || match[3];
@@ -60381,9 +60654,9 @@ function parseImports(content, targetFile, targetSymbol) {
60381
60654
  }
60382
60655
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
60383
60656
  let isMatch = false;
60384
- const _targetDir = path53.dirname(targetFile);
60385
- const targetExt = path53.extname(targetFile);
60386
- 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);
60387
60660
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
60388
60661
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
60389
60662
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -60440,7 +60713,7 @@ var SKIP_DIRECTORIES3 = new Set([
60440
60713
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
60441
60714
  let entries;
60442
60715
  try {
60443
- entries = fs40.readdirSync(dir);
60716
+ entries = fs41.readdirSync(dir);
60444
60717
  } catch (e) {
60445
60718
  stats.fileErrors.push({
60446
60719
  path: dir,
@@ -60451,13 +60724,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60451
60724
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
60452
60725
  for (const entry of entries) {
60453
60726
  if (SKIP_DIRECTORIES3.has(entry)) {
60454
- stats.skippedDirs.push(path53.join(dir, entry));
60727
+ stats.skippedDirs.push(path54.join(dir, entry));
60455
60728
  continue;
60456
60729
  }
60457
- const fullPath = path53.join(dir, entry);
60730
+ const fullPath = path54.join(dir, entry);
60458
60731
  let stat2;
60459
60732
  try {
60460
- stat2 = fs40.statSync(fullPath);
60733
+ stat2 = fs41.statSync(fullPath);
60461
60734
  } catch (e) {
60462
60735
  stats.fileErrors.push({
60463
60736
  path: fullPath,
@@ -60468,7 +60741,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
60468
60741
  if (stat2.isDirectory()) {
60469
60742
  findSourceFiles(fullPath, files, stats);
60470
60743
  } else if (stat2.isFile()) {
60471
- const ext = path53.extname(fullPath).toLowerCase();
60744
+ const ext = path54.extname(fullPath).toLowerCase();
60472
60745
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
60473
60746
  files.push(fullPath);
60474
60747
  }
@@ -60525,8 +60798,8 @@ var imports = createSwarmTool({
60525
60798
  return JSON.stringify(errorResult, null, 2);
60526
60799
  }
60527
60800
  try {
60528
- const targetFile = path53.resolve(file3);
60529
- if (!fs40.existsSync(targetFile)) {
60801
+ const targetFile = path54.resolve(file3);
60802
+ if (!fs41.existsSync(targetFile)) {
60530
60803
  const errorResult = {
60531
60804
  error: `target file not found: ${file3}`,
60532
60805
  target: file3,
@@ -60536,7 +60809,7 @@ var imports = createSwarmTool({
60536
60809
  };
60537
60810
  return JSON.stringify(errorResult, null, 2);
60538
60811
  }
60539
- const targetStat = fs40.statSync(targetFile);
60812
+ const targetStat = fs41.statSync(targetFile);
60540
60813
  if (!targetStat.isFile()) {
60541
60814
  const errorResult = {
60542
60815
  error: "target must be a file, not a directory",
@@ -60547,7 +60820,7 @@ var imports = createSwarmTool({
60547
60820
  };
60548
60821
  return JSON.stringify(errorResult, null, 2);
60549
60822
  }
60550
- const baseDir = path53.dirname(targetFile);
60823
+ const baseDir = path54.dirname(targetFile);
60551
60824
  const scanStats = {
60552
60825
  skippedDirs: [],
60553
60826
  skippedFiles: 0,
@@ -60562,12 +60835,12 @@ var imports = createSwarmTool({
60562
60835
  if (consumers.length >= MAX_CONSUMERS)
60563
60836
  break;
60564
60837
  try {
60565
- const stat2 = fs40.statSync(filePath);
60838
+ const stat2 = fs41.statSync(filePath);
60566
60839
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
60567
60840
  skippedFileCount++;
60568
60841
  continue;
60569
60842
  }
60570
- const buffer = fs40.readFileSync(filePath);
60843
+ const buffer = fs41.readFileSync(filePath);
60571
60844
  if (isBinaryFile2(filePath, buffer)) {
60572
60845
  skippedFileCount++;
60573
60846
  continue;
@@ -60634,7 +60907,7 @@ var imports = createSwarmTool({
60634
60907
  init_dist();
60635
60908
  init_config();
60636
60909
  init_knowledge_store();
60637
- import { randomUUID as randomUUID4 } from "crypto";
60910
+ import { randomUUID as randomUUID5 } from "crypto";
60638
60911
  init_manager2();
60639
60912
  init_create_tool();
60640
60913
  var VALID_CATEGORIES2 = [
@@ -60709,7 +60982,7 @@ var knowledgeAdd = createSwarmTool({
60709
60982
  project_name = plan?.title ?? "";
60710
60983
  } catch {}
60711
60984
  const entry = {
60712
- id: randomUUID4(),
60985
+ id: randomUUID5(),
60713
60986
  tier: "swarm",
60714
60987
  lesson,
60715
60988
  category,
@@ -60767,7 +61040,7 @@ init_dist();
60767
61040
  init_config();
60768
61041
  init_knowledge_store();
60769
61042
  init_create_tool();
60770
- import { existsSync as existsSync32 } from "fs";
61043
+ import { existsSync as existsSync33 } from "fs";
60771
61044
  var DEFAULT_LIMIT = 10;
60772
61045
  var MAX_LESSON_LENGTH = 200;
60773
61046
  var VALID_CATEGORIES3 = [
@@ -60836,14 +61109,14 @@ function validateLimit(limit) {
60836
61109
  }
60837
61110
  async function readSwarmKnowledge(directory) {
60838
61111
  const swarmPath = resolveSwarmKnowledgePath(directory);
60839
- if (!existsSync32(swarmPath)) {
61112
+ if (!existsSync33(swarmPath)) {
60840
61113
  return [];
60841
61114
  }
60842
61115
  return readKnowledge(swarmPath);
60843
61116
  }
60844
61117
  async function readHiveKnowledge() {
60845
61118
  const hivePath = resolveHiveKnowledgePath();
60846
- if (!existsSync32(hivePath)) {
61119
+ if (!existsSync33(hivePath)) {
60847
61120
  return [];
60848
61121
  }
60849
61122
  return readKnowledge(hivePath);
@@ -61156,8 +61429,9 @@ init_dist();
61156
61429
  init_config();
61157
61430
  init_schema();
61158
61431
  init_manager();
61159
- import * as fs41 from "fs";
61160
- import * as path54 from "path";
61432
+ import * as fs42 from "fs";
61433
+ import * as path55 from "path";
61434
+ init_review_receipt();
61161
61435
  init_utils2();
61162
61436
  init_telemetry();
61163
61437
  init_create_tool();
@@ -61378,11 +61652,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61378
61652
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
61379
61653
  }
61380
61654
  try {
61381
- 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");
61382
61656
  let driftVerdictFound = false;
61383
61657
  let driftVerdictApproved = false;
61384
61658
  try {
61385
- const driftEvidenceContent = fs41.readFileSync(driftEvidencePath, "utf-8");
61659
+ const driftEvidenceContent = fs42.readFileSync(driftEvidencePath, "utf-8");
61386
61660
  const driftEvidence = JSON.parse(driftEvidenceContent);
61387
61661
  const entries = driftEvidence.entries ?? [];
61388
61662
  for (const entry of entries) {
@@ -61412,14 +61686,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61412
61686
  driftVerdictFound = false;
61413
61687
  }
61414
61688
  if (!driftVerdictFound) {
61415
- const specPath = path54.join(dir, ".swarm", "spec.md");
61416
- const specExists = fs41.existsSync(specPath);
61689
+ const specPath = path55.join(dir, ".swarm", "spec.md");
61690
+ const specExists = fs42.existsSync(specPath);
61417
61691
  if (!specExists) {
61418
61692
  let incompleteTaskCount = 0;
61419
61693
  let planPhaseFound = false;
61420
61694
  try {
61421
61695
  const planPath = validateSwarmPath(dir, "plan.json");
61422
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61696
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61423
61697
  const plan = JSON.parse(planRaw);
61424
61698
  const targetPhase = plan.phases.find((p) => p.id === phase);
61425
61699
  if (targetPhase) {
@@ -61461,32 +61735,10 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61461
61735
  safeWarn(`[phase_complete] Drift verifier error (non-blocking):`, driftError);
61462
61736
  }
61463
61737
  }
61464
- const knowledgeConfig = {
61465
- enabled: true,
61466
- swarm_max_entries: 100,
61467
- hive_max_entries: 200,
61468
- auto_promote_days: 90,
61469
- max_inject_count: 5,
61470
- dedup_threshold: 0.6,
61471
- scope_filter: ["global"],
61472
- hive_enabled: true,
61473
- rejected_max_entries: 20,
61474
- validation_enabled: true,
61475
- evergreen_confidence: 0.9,
61476
- evergreen_utility: 0.8,
61477
- low_utility_threshold: 0.3,
61478
- min_retrievals_for_utility: 3,
61479
- schema_version: 1,
61480
- same_project_weight: 1,
61481
- cross_project_weight: 0.5,
61482
- min_encounter_score: 0.1,
61483
- initial_encounter_score: 1,
61484
- encounter_increment: 0.1,
61485
- max_encounter_score: 10
61486
- };
61738
+ const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
61487
61739
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
61488
61740
  try {
61489
- const projectName = path54.basename(dir);
61741
+ const projectName = path55.basename(dir);
61490
61742
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
61491
61743
  if (curationResult) {
61492
61744
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -61495,6 +61747,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61495
61747
  sessionState.pendingAdvisoryMessages.push(`[CURATOR] Knowledge curation: ${curationResult.stored} stored, ${curationResult.skipped} skipped, ${curationResult.rejected} rejected.`);
61496
61748
  }
61497
61749
  }
61750
+ await updateRetrievalOutcome(dir, `Phase ${phase}`, true);
61498
61751
  } catch (error93) {
61499
61752
  safeWarn("[phase_complete] Failed to curate lessons from retrospective:", error93);
61500
61753
  }
@@ -61503,7 +61756,41 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61503
61756
  try {
61504
61757
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
61505
61758
  if (curatorConfig.enabled && curatorConfig.phase_enabled) {
61506
- 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
+ }
61507
61794
  const knowledgeResult = await applyCuratorKnowledgeUpdates(dir, curatorResult.knowledge_recommendations, knowledgeConfig);
61508
61795
  const callerSessionState = swarmState.agentSessions.get(sessionID);
61509
61796
  if (callerSessionState) {
@@ -61531,7 +61818,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61531
61818
  let phaseRequiredAgents;
61532
61819
  try {
61533
61820
  const planPath = validateSwarmPath(dir, "plan.json");
61534
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61821
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61535
61822
  const plan = JSON.parse(planRaw);
61536
61823
  const phaseObj = plan.phases.find((p) => p.id === phase);
61537
61824
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -61546,7 +61833,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61546
61833
  if (agentsMissing.length > 0) {
61547
61834
  try {
61548
61835
  const planPath = validateSwarmPath(dir, "plan.json");
61549
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61836
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61550
61837
  const plan = JSON.parse(planRaw);
61551
61838
  const targetPhase = plan.phases.find((p) => p.id === phase);
61552
61839
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -61577,7 +61864,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61577
61864
  if (phaseCompleteConfig.regression_sweep?.enforce) {
61578
61865
  try {
61579
61866
  const planPath = validateSwarmPath(dir, "plan.json");
61580
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61867
+ const planRaw = fs42.readFileSync(planPath, "utf-8");
61581
61868
  const plan = JSON.parse(planRaw);
61582
61869
  const targetPhase = plan.phases.find((p) => p.id === phase);
61583
61870
  if (targetPhase) {
@@ -61615,7 +61902,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61615
61902
  };
61616
61903
  try {
61617
61904
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
61618
- fs41.appendFileSync(eventsPath, `${JSON.stringify(event)}
61905
+ fs42.appendFileSync(eventsPath, `${JSON.stringify(event)}
61619
61906
  `, "utf-8");
61620
61907
  } catch (writeError) {
61621
61908
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -61639,12 +61926,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61639
61926
  }
61640
61927
  try {
61641
61928
  const planPath = validateSwarmPath(dir, "plan.json");
61642
- const planJson = fs41.readFileSync(planPath, "utf-8");
61929
+ const planJson = fs42.readFileSync(planPath, "utf-8");
61643
61930
  const plan = JSON.parse(planJson);
61644
61931
  const phaseObj = plan.phases.find((p) => p.id === phase);
61645
61932
  if (phaseObj) {
61646
61933
  phaseObj.status = "completed";
61647
- fs41.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61934
+ fs42.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
61648
61935
  `, "utf-8");
61649
61936
  }
61650
61937
  } catch (error93) {
@@ -61711,8 +61998,8 @@ init_dist();
61711
61998
  init_discovery();
61712
61999
  init_utils();
61713
62000
  init_create_tool();
61714
- import * as fs42 from "fs";
61715
- import * as path55 from "path";
62001
+ import * as fs43 from "fs";
62002
+ import * as path56 from "path";
61716
62003
  var MAX_OUTPUT_BYTES5 = 52428800;
61717
62004
  var AUDIT_TIMEOUT_MS = 120000;
61718
62005
  function isValidEcosystem(value) {
@@ -61730,28 +62017,28 @@ function validateArgs3(args2) {
61730
62017
  function detectEcosystems(directory) {
61731
62018
  const ecosystems = [];
61732
62019
  const cwd = directory;
61733
- if (fs42.existsSync(path55.join(cwd, "package.json"))) {
62020
+ if (fs43.existsSync(path56.join(cwd, "package.json"))) {
61734
62021
  ecosystems.push("npm");
61735
62022
  }
61736
- 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"))) {
61737
62024
  ecosystems.push("pip");
61738
62025
  }
61739
- if (fs42.existsSync(path55.join(cwd, "Cargo.toml"))) {
62026
+ if (fs43.existsSync(path56.join(cwd, "Cargo.toml"))) {
61740
62027
  ecosystems.push("cargo");
61741
62028
  }
61742
- if (fs42.existsSync(path55.join(cwd, "go.mod"))) {
62029
+ if (fs43.existsSync(path56.join(cwd, "go.mod"))) {
61743
62030
  ecosystems.push("go");
61744
62031
  }
61745
62032
  try {
61746
- const files = fs42.readdirSync(cwd);
62033
+ const files = fs43.readdirSync(cwd);
61747
62034
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
61748
62035
  ecosystems.push("dotnet");
61749
62036
  }
61750
62037
  } catch {}
61751
- 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"))) {
61752
62039
  ecosystems.push("ruby");
61753
62040
  }
61754
- if (fs42.existsSync(path55.join(cwd, "pubspec.yaml"))) {
62041
+ if (fs43.existsSync(path56.join(cwd, "pubspec.yaml"))) {
61755
62042
  ecosystems.push("dart");
61756
62043
  }
61757
62044
  return ecosystems;
@@ -62772,8 +63059,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
62772
63059
  ]);
62773
63060
  // src/tools/pre-check-batch.ts
62774
63061
  init_dist();
62775
- import * as fs44 from "fs";
62776
- import * as path57 from "path";
63062
+ import * as fs45 from "fs";
63063
+ import * as path58 from "path";
62777
63064
 
62778
63065
  // node_modules/yocto-queue/index.js
62779
63066
  class Node2 {
@@ -62918,8 +63205,8 @@ function pLimit(concurrency) {
62918
63205
  },
62919
63206
  map: {
62920
63207
  async value(iterable, function_) {
62921
- const promises5 = Array.from(iterable, (value, index) => this(function_, value, index));
62922
- return Promise.all(promises5);
63208
+ const promises6 = Array.from(iterable, (value, index) => this(function_, value, index));
63209
+ return Promise.all(promises6);
62923
63210
  }
62924
63211
  }
62925
63212
  });
@@ -63047,8 +63334,8 @@ async function qualityBudget(input, directory) {
63047
63334
  init_dist();
63048
63335
  init_manager();
63049
63336
  init_detector();
63050
- import * as fs43 from "fs";
63051
- import * as path56 from "path";
63337
+ import * as fs44 from "fs";
63338
+ import * as path57 from "path";
63052
63339
  import { extname as extname10 } from "path";
63053
63340
 
63054
63341
  // src/sast/rules/c.ts
@@ -63918,17 +64205,17 @@ var SEVERITY_ORDER = {
63918
64205
  };
63919
64206
  function shouldSkipFile(filePath) {
63920
64207
  try {
63921
- const stats = fs43.statSync(filePath);
64208
+ const stats = fs44.statSync(filePath);
63922
64209
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
63923
64210
  return { skip: true, reason: "file too large" };
63924
64211
  }
63925
64212
  if (stats.size === 0) {
63926
64213
  return { skip: true, reason: "empty file" };
63927
64214
  }
63928
- const fd = fs43.openSync(filePath, "r");
64215
+ const fd = fs44.openSync(filePath, "r");
63929
64216
  const buffer = Buffer.alloc(8192);
63930
- const bytesRead = fs43.readSync(fd, buffer, 0, 8192, 0);
63931
- fs43.closeSync(fd);
64217
+ const bytesRead = fs44.readSync(fd, buffer, 0, 8192, 0);
64218
+ fs44.closeSync(fd);
63932
64219
  if (bytesRead > 0) {
63933
64220
  let nullCount = 0;
63934
64221
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -63967,7 +64254,7 @@ function countBySeverity(findings) {
63967
64254
  }
63968
64255
  function scanFileWithTierA(filePath, language) {
63969
64256
  try {
63970
- const content = fs43.readFileSync(filePath, "utf-8");
64257
+ const content = fs44.readFileSync(filePath, "utf-8");
63971
64258
  const findings = executeRulesSync(filePath, content, language);
63972
64259
  return findings.map((f) => ({
63973
64260
  rule_id: f.rule_id,
@@ -64014,8 +64301,8 @@ async function sastScan(input, directory, config3) {
64014
64301
  _filesSkipped++;
64015
64302
  continue;
64016
64303
  }
64017
- const resolvedPath = path56.isAbsolute(filePath) ? filePath : path56.resolve(directory, filePath);
64018
- if (!fs43.existsSync(resolvedPath)) {
64304
+ const resolvedPath = path57.isAbsolute(filePath) ? filePath : path57.resolve(directory, filePath);
64305
+ if (!fs44.existsSync(resolvedPath)) {
64019
64306
  _filesSkipped++;
64020
64307
  continue;
64021
64308
  }
@@ -64213,18 +64500,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
64213
64500
  let resolved;
64214
64501
  const isWinAbs = isWindowsAbsolutePath(inputPath);
64215
64502
  if (isWinAbs) {
64216
- resolved = path57.win32.resolve(inputPath);
64217
- } else if (path57.isAbsolute(inputPath)) {
64218
- resolved = path57.resolve(inputPath);
64503
+ resolved = path58.win32.resolve(inputPath);
64504
+ } else if (path58.isAbsolute(inputPath)) {
64505
+ resolved = path58.resolve(inputPath);
64219
64506
  } else {
64220
- resolved = path57.resolve(baseDir, inputPath);
64507
+ resolved = path58.resolve(baseDir, inputPath);
64221
64508
  }
64222
- const workspaceResolved = path57.resolve(workspaceDir);
64509
+ const workspaceResolved = path58.resolve(workspaceDir);
64223
64510
  let relative8;
64224
64511
  if (isWinAbs) {
64225
- relative8 = path57.win32.relative(workspaceResolved, resolved);
64512
+ relative8 = path58.win32.relative(workspaceResolved, resolved);
64226
64513
  } else {
64227
- relative8 = path57.relative(workspaceResolved, resolved);
64514
+ relative8 = path58.relative(workspaceResolved, resolved);
64228
64515
  }
64229
64516
  if (relative8.startsWith("..")) {
64230
64517
  return "path traversal detected";
@@ -64285,13 +64572,13 @@ async function runLintWrapped(files, directory, _config) {
64285
64572
  }
64286
64573
  async function runLintOnFiles(linter, files, workspaceDir) {
64287
64574
  const isWindows = process.platform === "win32";
64288
- const binDir = path57.join(workspaceDir, "node_modules", ".bin");
64575
+ const binDir = path58.join(workspaceDir, "node_modules", ".bin");
64289
64576
  const validatedFiles = [];
64290
64577
  for (const file3 of files) {
64291
64578
  if (typeof file3 !== "string") {
64292
64579
  continue;
64293
64580
  }
64294
- const resolvedPath = path57.resolve(file3);
64581
+ const resolvedPath = path58.resolve(file3);
64295
64582
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
64296
64583
  if (validationError) {
64297
64584
  continue;
@@ -64309,10 +64596,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
64309
64596
  }
64310
64597
  let command;
64311
64598
  if (linter === "biome") {
64312
- 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");
64313
64600
  command = [biomeBin, "check", ...validatedFiles];
64314
64601
  } else {
64315
- 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");
64316
64603
  command = [eslintBin, ...validatedFiles];
64317
64604
  }
64318
64605
  try {
@@ -64449,7 +64736,7 @@ async function runSecretscanWithFiles(files, directory) {
64449
64736
  skippedFiles++;
64450
64737
  continue;
64451
64738
  }
64452
- const resolvedPath = path57.resolve(file3);
64739
+ const resolvedPath = path58.resolve(file3);
64453
64740
  const validationError = validatePath(resolvedPath, directory, directory);
64454
64741
  if (validationError) {
64455
64742
  skippedFiles++;
@@ -64467,14 +64754,14 @@ async function runSecretscanWithFiles(files, directory) {
64467
64754
  };
64468
64755
  }
64469
64756
  for (const file3 of validatedFiles) {
64470
- const ext = path57.extname(file3).toLowerCase();
64757
+ const ext = path58.extname(file3).toLowerCase();
64471
64758
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
64472
64759
  skippedFiles++;
64473
64760
  continue;
64474
64761
  }
64475
64762
  let stat2;
64476
64763
  try {
64477
- stat2 = fs44.statSync(file3);
64764
+ stat2 = fs45.statSync(file3);
64478
64765
  } catch {
64479
64766
  skippedFiles++;
64480
64767
  continue;
@@ -64485,7 +64772,7 @@ async function runSecretscanWithFiles(files, directory) {
64485
64772
  }
64486
64773
  let content;
64487
64774
  try {
64488
- const buffer = fs44.readFileSync(file3);
64775
+ const buffer = fs45.readFileSync(file3);
64489
64776
  if (buffer.includes(0)) {
64490
64777
  skippedFiles++;
64491
64778
  continue;
@@ -64673,7 +64960,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
64673
64960
  const preexistingFindings = [];
64674
64961
  for (const finding of findings) {
64675
64962
  const filePath = finding.location.file;
64676
- const normalised = path57.relative(directory, filePath).replace(/\\/g, "/");
64963
+ const normalised = path58.relative(directory, filePath).replace(/\\/g, "/");
64677
64964
  const changedLines = changedLineRanges.get(normalised);
64678
64965
  if (changedLines && changedLines.has(finding.location.line)) {
64679
64966
  newFindings.push(finding);
@@ -64724,7 +65011,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
64724
65011
  warn(`pre_check_batch: Invalid file path: ${file3}`);
64725
65012
  continue;
64726
65013
  }
64727
- changedFiles.push(path57.resolve(directory, file3));
65014
+ changedFiles.push(path58.resolve(directory, file3));
64728
65015
  }
64729
65016
  if (changedFiles.length === 0) {
64730
65017
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -64912,7 +65199,7 @@ var pre_check_batch = createSwarmTool({
64912
65199
  };
64913
65200
  return JSON.stringify(errorResult, null, 2);
64914
65201
  }
64915
- const resolvedDirectory = path57.resolve(typedArgs.directory);
65202
+ const resolvedDirectory = path58.resolve(typedArgs.directory);
64916
65203
  const workspaceAnchor = resolvedDirectory;
64917
65204
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
64918
65205
  if (dirError) {
@@ -65018,38 +65305,38 @@ ${paginatedContent}`;
65018
65305
  });
65019
65306
  // src/tools/save-plan.ts
65020
65307
  init_tool();
65021
- import * as fs46 from "fs";
65022
- import * as path59 from "path";
65308
+ import * as fs47 from "fs";
65309
+ import * as path60 from "path";
65023
65310
 
65024
65311
  // src/parallel/file-locks.ts
65025
- import * as fs45 from "fs";
65026
- import * as path58 from "path";
65312
+ import * as fs46 from "fs";
65313
+ import * as path59 from "path";
65027
65314
  var LOCKS_DIR = ".swarm/locks";
65028
65315
  var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
65029
65316
  function getLockFilePath(directory, filePath) {
65030
- const normalized = path58.resolve(directory, filePath);
65031
- if (!normalized.startsWith(path58.resolve(directory))) {
65317
+ const normalized = path59.resolve(directory, filePath);
65318
+ if (!normalized.startsWith(path59.resolve(directory))) {
65032
65319
  throw new Error("Invalid file path: path traversal not allowed");
65033
65320
  }
65034
65321
  const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
65035
- return path58.join(directory, LOCKS_DIR, `${hash3}.lock`);
65322
+ return path59.join(directory, LOCKS_DIR, `${hash3}.lock`);
65036
65323
  }
65037
65324
  function tryAcquireLock(directory, filePath, agent, taskId) {
65038
65325
  const lockPath = getLockFilePath(directory, filePath);
65039
- const locksDir = path58.dirname(lockPath);
65040
- if (!fs45.existsSync(locksDir)) {
65041
- fs45.mkdirSync(locksDir, { recursive: true });
65326
+ const locksDir = path59.dirname(lockPath);
65327
+ if (!fs46.existsSync(locksDir)) {
65328
+ fs46.mkdirSync(locksDir, { recursive: true });
65042
65329
  }
65043
- if (fs45.existsSync(lockPath)) {
65330
+ if (fs46.existsSync(lockPath)) {
65044
65331
  try {
65045
- const existingLock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
65332
+ const existingLock = JSON.parse(fs46.readFileSync(lockPath, "utf-8"));
65046
65333
  if (Date.now() > existingLock.expiresAt) {
65047
- fs45.unlinkSync(lockPath);
65334
+ fs46.unlinkSync(lockPath);
65048
65335
  } else {
65049
65336
  return { acquired: false, existing: existingLock };
65050
65337
  }
65051
65338
  } catch {
65052
- fs45.unlinkSync(lockPath);
65339
+ fs46.unlinkSync(lockPath);
65053
65340
  }
65054
65341
  }
65055
65342
  const lock = {
@@ -65060,24 +65347,24 @@ function tryAcquireLock(directory, filePath, agent, taskId) {
65060
65347
  expiresAt: Date.now() + LOCK_TIMEOUT_MS
65061
65348
  };
65062
65349
  const tempPath = `${lockPath}.tmp`;
65063
- fs45.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65064
- fs45.renameSync(tempPath, lockPath);
65350
+ fs46.writeFileSync(tempPath, JSON.stringify(lock, null, 2), "utf-8");
65351
+ fs46.renameSync(tempPath, lockPath);
65065
65352
  return { acquired: true, lock };
65066
65353
  }
65067
65354
  function releaseLock(directory, filePath, taskId) {
65068
65355
  const lockPath = getLockFilePath(directory, filePath);
65069
- if (!fs45.existsSync(lockPath)) {
65356
+ if (!fs46.existsSync(lockPath)) {
65070
65357
  return true;
65071
65358
  }
65072
65359
  try {
65073
- const lock = JSON.parse(fs45.readFileSync(lockPath, "utf-8"));
65360
+ const lock = JSON.parse(fs46.readFileSync(lockPath, "utf-8"));
65074
65361
  if (lock.taskId === taskId) {
65075
- fs45.unlinkSync(lockPath);
65362
+ fs46.unlinkSync(lockPath);
65076
65363
  return true;
65077
65364
  }
65078
65365
  return false;
65079
65366
  } catch {
65080
- fs45.unlinkSync(lockPath);
65367
+ fs46.unlinkSync(lockPath);
65081
65368
  return true;
65082
65369
  }
65083
65370
  }
@@ -65202,14 +65489,14 @@ async function executeSavePlan(args2, fallbackDir) {
65202
65489
  try {
65203
65490
  await savePlan(dir, plan);
65204
65491
  try {
65205
- const markerPath = path59.join(dir, ".swarm", ".plan-write-marker");
65492
+ const markerPath = path60.join(dir, ".swarm", ".plan-write-marker");
65206
65493
  const marker = JSON.stringify({
65207
65494
  source: "save_plan",
65208
65495
  timestamp: new Date().toISOString(),
65209
65496
  phases_count: plan.phases.length,
65210
65497
  tasks_count: tasksCount
65211
65498
  });
65212
- await fs46.promises.writeFile(markerPath, marker, "utf8");
65499
+ await fs47.promises.writeFile(markerPath, marker, "utf8");
65213
65500
  } catch {}
65214
65501
  const warnings = [];
65215
65502
  let criticReviewFound = false;
@@ -65225,7 +65512,7 @@ async function executeSavePlan(args2, fallbackDir) {
65225
65512
  return {
65226
65513
  success: true,
65227
65514
  message: "Plan saved successfully",
65228
- plan_path: path59.join(dir, ".swarm", "plan.json"),
65515
+ plan_path: path60.join(dir, ".swarm", "plan.json"),
65229
65516
  phases_count: plan.phases.length,
65230
65517
  tasks_count: tasksCount,
65231
65518
  ...warnings.length > 0 ? { warnings } : {}
@@ -65267,8 +65554,8 @@ var save_plan = createSwarmTool({
65267
65554
  // src/tools/sbom-generate.ts
65268
65555
  init_dist();
65269
65556
  init_manager();
65270
- import * as fs47 from "fs";
65271
- import * as path60 from "path";
65557
+ import * as fs48 from "fs";
65558
+ import * as path61 from "path";
65272
65559
 
65273
65560
  // src/sbom/detectors/index.ts
65274
65561
  init_utils();
@@ -66116,9 +66403,9 @@ function findManifestFiles(rootDir) {
66116
66403
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
66117
66404
  function searchDir(dir) {
66118
66405
  try {
66119
- const entries = fs47.readdirSync(dir, { withFileTypes: true });
66406
+ const entries = fs48.readdirSync(dir, { withFileTypes: true });
66120
66407
  for (const entry of entries) {
66121
- const fullPath = path60.join(dir, entry.name);
66408
+ const fullPath = path61.join(dir, entry.name);
66122
66409
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
66123
66410
  continue;
66124
66411
  }
@@ -66127,7 +66414,7 @@ function findManifestFiles(rootDir) {
66127
66414
  } else if (entry.isFile()) {
66128
66415
  for (const pattern of patterns) {
66129
66416
  if (simpleGlobToRegex(pattern).test(entry.name)) {
66130
- manifestFiles.push(path60.relative(rootDir, fullPath));
66417
+ manifestFiles.push(path61.relative(rootDir, fullPath));
66131
66418
  break;
66132
66419
  }
66133
66420
  }
@@ -66143,13 +66430,13 @@ function findManifestFilesInDirs(directories, workingDir) {
66143
66430
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
66144
66431
  for (const dir of directories) {
66145
66432
  try {
66146
- const entries = fs47.readdirSync(dir, { withFileTypes: true });
66433
+ const entries = fs48.readdirSync(dir, { withFileTypes: true });
66147
66434
  for (const entry of entries) {
66148
- const fullPath = path60.join(dir, entry.name);
66435
+ const fullPath = path61.join(dir, entry.name);
66149
66436
  if (entry.isFile()) {
66150
66437
  for (const pattern of patterns) {
66151
66438
  if (simpleGlobToRegex(pattern).test(entry.name)) {
66152
- found.push(path60.relative(workingDir, fullPath));
66439
+ found.push(path61.relative(workingDir, fullPath));
66153
66440
  break;
66154
66441
  }
66155
66442
  }
@@ -66162,11 +66449,11 @@ function findManifestFilesInDirs(directories, workingDir) {
66162
66449
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66163
66450
  const dirs = new Set;
66164
66451
  for (const file3 of changedFiles) {
66165
- let currentDir = path60.dirname(file3);
66452
+ let currentDir = path61.dirname(file3);
66166
66453
  while (true) {
66167
- if (currentDir && currentDir !== "." && currentDir !== path60.sep) {
66168
- dirs.add(path60.join(workingDir, currentDir));
66169
- 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);
66170
66457
  if (parent === currentDir)
66171
66458
  break;
66172
66459
  currentDir = parent;
@@ -66180,7 +66467,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
66180
66467
  }
66181
66468
  function ensureOutputDir(outputDir) {
66182
66469
  try {
66183
- fs47.mkdirSync(outputDir, { recursive: true });
66470
+ fs48.mkdirSync(outputDir, { recursive: true });
66184
66471
  } catch (error93) {
66185
66472
  if (!error93 || error93.code !== "EEXIST") {
66186
66473
  throw error93;
@@ -66250,7 +66537,7 @@ var sbom_generate = createSwarmTool({
66250
66537
  const changedFiles = obj.changed_files;
66251
66538
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
66252
66539
  const workingDir = directory;
66253
- const outputDir = path60.isAbsolute(relativeOutputDir) ? relativeOutputDir : path60.join(workingDir, relativeOutputDir);
66540
+ const outputDir = path61.isAbsolute(relativeOutputDir) ? relativeOutputDir : path61.join(workingDir, relativeOutputDir);
66254
66541
  let manifestFiles = [];
66255
66542
  if (scope === "all") {
66256
66543
  manifestFiles = findManifestFiles(workingDir);
@@ -66273,11 +66560,11 @@ var sbom_generate = createSwarmTool({
66273
66560
  const processedFiles = [];
66274
66561
  for (const manifestFile of manifestFiles) {
66275
66562
  try {
66276
- const fullPath = path60.isAbsolute(manifestFile) ? manifestFile : path60.join(workingDir, manifestFile);
66277
- if (!fs47.existsSync(fullPath)) {
66563
+ const fullPath = path61.isAbsolute(manifestFile) ? manifestFile : path61.join(workingDir, manifestFile);
66564
+ if (!fs48.existsSync(fullPath)) {
66278
66565
  continue;
66279
66566
  }
66280
- const content = fs47.readFileSync(fullPath, "utf-8");
66567
+ const content = fs48.readFileSync(fullPath, "utf-8");
66281
66568
  const components = detectComponents(manifestFile, content);
66282
66569
  processedFiles.push(manifestFile);
66283
66570
  if (components.length > 0) {
@@ -66290,8 +66577,8 @@ var sbom_generate = createSwarmTool({
66290
66577
  const bom = generateCycloneDX(allComponents);
66291
66578
  const bomJson = serializeCycloneDX(bom);
66292
66579
  const filename = generateSbomFilename();
66293
- const outputPath = path60.join(outputDir, filename);
66294
- fs47.writeFileSync(outputPath, bomJson, "utf-8");
66580
+ const outputPath = path61.join(outputDir, filename);
66581
+ fs48.writeFileSync(outputPath, bomJson, "utf-8");
66295
66582
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
66296
66583
  try {
66297
66584
  const timestamp = new Date().toISOString();
@@ -66333,8 +66620,8 @@ var sbom_generate = createSwarmTool({
66333
66620
  // src/tools/schema-drift.ts
66334
66621
  init_dist();
66335
66622
  init_create_tool();
66336
- import * as fs48 from "fs";
66337
- import * as path61 from "path";
66623
+ import * as fs49 from "fs";
66624
+ import * as path62 from "path";
66338
66625
  var SPEC_CANDIDATES = [
66339
66626
  "openapi.json",
66340
66627
  "openapi.yaml",
@@ -66366,28 +66653,28 @@ function normalizePath2(p) {
66366
66653
  }
66367
66654
  function discoverSpecFile(cwd, specFileArg) {
66368
66655
  if (specFileArg) {
66369
- const resolvedPath = path61.resolve(cwd, specFileArg);
66370
- 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;
66371
66658
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
66372
66659
  throw new Error("Invalid spec_file: path traversal detected");
66373
66660
  }
66374
- const ext = path61.extname(resolvedPath).toLowerCase();
66661
+ const ext = path62.extname(resolvedPath).toLowerCase();
66375
66662
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
66376
66663
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
66377
66664
  }
66378
- const stats = fs48.statSync(resolvedPath);
66665
+ const stats = fs49.statSync(resolvedPath);
66379
66666
  if (stats.size > MAX_SPEC_SIZE) {
66380
66667
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
66381
66668
  }
66382
- if (!fs48.existsSync(resolvedPath)) {
66669
+ if (!fs49.existsSync(resolvedPath)) {
66383
66670
  throw new Error(`Spec file not found: ${resolvedPath}`);
66384
66671
  }
66385
66672
  return resolvedPath;
66386
66673
  }
66387
66674
  for (const candidate of SPEC_CANDIDATES) {
66388
- const candidatePath = path61.resolve(cwd, candidate);
66389
- if (fs48.existsSync(candidatePath)) {
66390
- const stats = fs48.statSync(candidatePath);
66675
+ const candidatePath = path62.resolve(cwd, candidate);
66676
+ if (fs49.existsSync(candidatePath)) {
66677
+ const stats = fs49.statSync(candidatePath);
66391
66678
  if (stats.size <= MAX_SPEC_SIZE) {
66392
66679
  return candidatePath;
66393
66680
  }
@@ -66396,8 +66683,8 @@ function discoverSpecFile(cwd, specFileArg) {
66396
66683
  return null;
66397
66684
  }
66398
66685
  function parseSpec(specFile) {
66399
- const content = fs48.readFileSync(specFile, "utf-8");
66400
- const ext = path61.extname(specFile).toLowerCase();
66686
+ const content = fs49.readFileSync(specFile, "utf-8");
66687
+ const ext = path62.extname(specFile).toLowerCase();
66401
66688
  if (ext === ".json") {
66402
66689
  return parseJsonSpec(content);
66403
66690
  }
@@ -66468,12 +66755,12 @@ function extractRoutes(cwd) {
66468
66755
  function walkDir(dir) {
66469
66756
  let entries;
66470
66757
  try {
66471
- entries = fs48.readdirSync(dir, { withFileTypes: true });
66758
+ entries = fs49.readdirSync(dir, { withFileTypes: true });
66472
66759
  } catch {
66473
66760
  return;
66474
66761
  }
66475
66762
  for (const entry of entries) {
66476
- const fullPath = path61.join(dir, entry.name);
66763
+ const fullPath = path62.join(dir, entry.name);
66477
66764
  if (entry.isSymbolicLink()) {
66478
66765
  continue;
66479
66766
  }
@@ -66483,7 +66770,7 @@ function extractRoutes(cwd) {
66483
66770
  }
66484
66771
  walkDir(fullPath);
66485
66772
  } else if (entry.isFile()) {
66486
- const ext = path61.extname(entry.name).toLowerCase();
66773
+ const ext = path62.extname(entry.name).toLowerCase();
66487
66774
  const baseName = entry.name.toLowerCase();
66488
66775
  if (![".ts", ".js", ".mjs"].includes(ext)) {
66489
66776
  continue;
@@ -66501,7 +66788,7 @@ function extractRoutes(cwd) {
66501
66788
  }
66502
66789
  function extractRoutesFromFile(filePath) {
66503
66790
  const routes = [];
66504
- const content = fs48.readFileSync(filePath, "utf-8");
66791
+ const content = fs49.readFileSync(filePath, "utf-8");
66505
66792
  const lines = content.split(/\r?\n/);
66506
66793
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
66507
66794
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -66652,8 +66939,8 @@ init_secretscan();
66652
66939
  // src/tools/symbols.ts
66653
66940
  init_tool();
66654
66941
  init_create_tool();
66655
- import * as fs49 from "fs";
66656
- import * as path62 from "path";
66942
+ import * as fs50 from "fs";
66943
+ import * as path63 from "path";
66657
66944
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
66658
66945
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
66659
66946
  function containsWindowsAttacks(str) {
@@ -66670,11 +66957,11 @@ function containsWindowsAttacks(str) {
66670
66957
  }
66671
66958
  function isPathInWorkspace(filePath, workspace) {
66672
66959
  try {
66673
- const resolvedPath = path62.resolve(workspace, filePath);
66674
- const realWorkspace = fs49.realpathSync(workspace);
66675
- const realResolvedPath = fs49.realpathSync(resolvedPath);
66676
- const relativePath = path62.relative(realWorkspace, realResolvedPath);
66677
- 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)) {
66678
66965
  return false;
66679
66966
  }
66680
66967
  return true;
@@ -66686,17 +66973,17 @@ function validatePathForRead(filePath, workspace) {
66686
66973
  return isPathInWorkspace(filePath, workspace);
66687
66974
  }
66688
66975
  function extractTSSymbols(filePath, cwd) {
66689
- const fullPath = path62.join(cwd, filePath);
66976
+ const fullPath = path63.join(cwd, filePath);
66690
66977
  if (!validatePathForRead(fullPath, cwd)) {
66691
66978
  return [];
66692
66979
  }
66693
66980
  let content;
66694
66981
  try {
66695
- const stats = fs49.statSync(fullPath);
66982
+ const stats = fs50.statSync(fullPath);
66696
66983
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66697
66984
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66698
66985
  }
66699
- content = fs49.readFileSync(fullPath, "utf-8");
66986
+ content = fs50.readFileSync(fullPath, "utf-8");
66700
66987
  } catch {
66701
66988
  return [];
66702
66989
  }
@@ -66838,17 +67125,17 @@ function extractTSSymbols(filePath, cwd) {
66838
67125
  });
66839
67126
  }
66840
67127
  function extractPythonSymbols(filePath, cwd) {
66841
- const fullPath = path62.join(cwd, filePath);
67128
+ const fullPath = path63.join(cwd, filePath);
66842
67129
  if (!validatePathForRead(fullPath, cwd)) {
66843
67130
  return [];
66844
67131
  }
66845
67132
  let content;
66846
67133
  try {
66847
- const stats = fs49.statSync(fullPath);
67134
+ const stats = fs50.statSync(fullPath);
66848
67135
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
66849
67136
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
66850
67137
  }
66851
- content = fs49.readFileSync(fullPath, "utf-8");
67138
+ content = fs50.readFileSync(fullPath, "utf-8");
66852
67139
  } catch {
66853
67140
  return [];
66854
67141
  }
@@ -66921,7 +67208,7 @@ var symbols = createSwarmTool({
66921
67208
  }, null, 2);
66922
67209
  }
66923
67210
  const cwd = directory;
66924
- const ext = path62.extname(file3);
67211
+ const ext = path63.extname(file3);
66925
67212
  if (containsControlChars(file3)) {
66926
67213
  return JSON.stringify({
66927
67214
  file: file3,
@@ -66992,8 +67279,8 @@ init_test_runner();
66992
67279
  init_dist();
66993
67280
  init_utils();
66994
67281
  init_create_tool();
66995
- import * as fs50 from "fs";
66996
- import * as path63 from "path";
67282
+ import * as fs51 from "fs";
67283
+ import * as path64 from "path";
66997
67284
  var MAX_TEXT_LENGTH = 200;
66998
67285
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
66999
67286
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -67058,9 +67345,9 @@ function validatePathsInput(paths, cwd) {
67058
67345
  return { error: "paths contains path traversal", resolvedPath: null };
67059
67346
  }
67060
67347
  try {
67061
- const resolvedPath = path63.resolve(paths);
67062
- const normalizedCwd = path63.resolve(cwd);
67063
- const normalizedResolved = path63.resolve(resolvedPath);
67348
+ const resolvedPath = path64.resolve(paths);
67349
+ const normalizedCwd = path64.resolve(cwd);
67350
+ const normalizedResolved = path64.resolve(resolvedPath);
67064
67351
  if (!normalizedResolved.startsWith(normalizedCwd)) {
67065
67352
  return {
67066
67353
  error: "paths must be within the current working directory",
@@ -67076,13 +67363,13 @@ function validatePathsInput(paths, cwd) {
67076
67363
  }
67077
67364
  }
67078
67365
  function isSupportedExtension(filePath) {
67079
- const ext = path63.extname(filePath).toLowerCase();
67366
+ const ext = path64.extname(filePath).toLowerCase();
67080
67367
  return SUPPORTED_EXTENSIONS2.has(ext);
67081
67368
  }
67082
67369
  function findSourceFiles2(dir, files = []) {
67083
67370
  let entries;
67084
67371
  try {
67085
- entries = fs50.readdirSync(dir);
67372
+ entries = fs51.readdirSync(dir);
67086
67373
  } catch {
67087
67374
  return files;
67088
67375
  }
@@ -67091,10 +67378,10 @@ function findSourceFiles2(dir, files = []) {
67091
67378
  if (SKIP_DIRECTORIES4.has(entry)) {
67092
67379
  continue;
67093
67380
  }
67094
- const fullPath = path63.join(dir, entry);
67381
+ const fullPath = path64.join(dir, entry);
67095
67382
  let stat2;
67096
67383
  try {
67097
- stat2 = fs50.statSync(fullPath);
67384
+ stat2 = fs51.statSync(fullPath);
67098
67385
  } catch {
67099
67386
  continue;
67100
67387
  }
@@ -67187,7 +67474,7 @@ var todo_extract = createSwarmTool({
67187
67474
  return JSON.stringify(errorResult, null, 2);
67188
67475
  }
67189
67476
  const scanPath = resolvedPath;
67190
- if (!fs50.existsSync(scanPath)) {
67477
+ if (!fs51.existsSync(scanPath)) {
67191
67478
  const errorResult = {
67192
67479
  error: `path not found: ${pathsInput}`,
67193
67480
  total: 0,
@@ -67197,13 +67484,13 @@ var todo_extract = createSwarmTool({
67197
67484
  return JSON.stringify(errorResult, null, 2);
67198
67485
  }
67199
67486
  const filesToScan = [];
67200
- const stat2 = fs50.statSync(scanPath);
67487
+ const stat2 = fs51.statSync(scanPath);
67201
67488
  if (stat2.isFile()) {
67202
67489
  if (isSupportedExtension(scanPath)) {
67203
67490
  filesToScan.push(scanPath);
67204
67491
  } else {
67205
67492
  const errorResult = {
67206
- error: `unsupported file extension: ${path63.extname(scanPath)}`,
67493
+ error: `unsupported file extension: ${path64.extname(scanPath)}`,
67207
67494
  total: 0,
67208
67495
  byPriority: { high: 0, medium: 0, low: 0 },
67209
67496
  entries: []
@@ -67216,11 +67503,11 @@ var todo_extract = createSwarmTool({
67216
67503
  const allEntries = [];
67217
67504
  for (const filePath of filesToScan) {
67218
67505
  try {
67219
- const fileStat = fs50.statSync(filePath);
67506
+ const fileStat = fs51.statSync(filePath);
67220
67507
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
67221
67508
  continue;
67222
67509
  }
67223
- const content = fs50.readFileSync(filePath, "utf-8");
67510
+ const content = fs51.readFileSync(filePath, "utf-8");
67224
67511
  const entries = parseTodoComments(content, filePath, tagsSet);
67225
67512
  allEntries.push(...entries);
67226
67513
  } catch {}
@@ -67249,18 +67536,18 @@ var todo_extract = createSwarmTool({
67249
67536
  init_tool();
67250
67537
  init_schema();
67251
67538
  init_gate_evidence();
67252
- import * as fs52 from "fs";
67253
- import * as path65 from "path";
67539
+ import * as fs53 from "fs";
67540
+ import * as path66 from "path";
67254
67541
 
67255
67542
  // src/hooks/diff-scope.ts
67256
- import * as fs51 from "fs";
67257
- import * as path64 from "path";
67543
+ import * as fs52 from "fs";
67544
+ import * as path65 from "path";
67258
67545
  function getDeclaredScope(taskId, directory) {
67259
67546
  try {
67260
- const planPath = path64.join(directory, ".swarm", "plan.json");
67261
- if (!fs51.existsSync(planPath))
67547
+ const planPath = path65.join(directory, ".swarm", "plan.json");
67548
+ if (!fs52.existsSync(planPath))
67262
67549
  return null;
67263
- const raw = fs51.readFileSync(planPath, "utf-8");
67550
+ const raw = fs52.readFileSync(planPath, "utf-8");
67264
67551
  const plan = JSON.parse(raw);
67265
67552
  for (const phase of plan.phases ?? []) {
67266
67553
  for (const task of phase.tasks ?? []) {
@@ -67373,7 +67660,7 @@ var TIER_3_PATTERNS = [
67373
67660
  ];
67374
67661
  function matchesTier3Pattern(files) {
67375
67662
  for (const file3 of files) {
67376
- const fileName = path65.basename(file3);
67663
+ const fileName = path66.basename(file3);
67377
67664
  for (const pattern of TIER_3_PATTERNS) {
67378
67665
  if (pattern.test(fileName)) {
67379
67666
  return true;
@@ -67387,8 +67674,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67387
67674
  if (hasActiveTurboMode()) {
67388
67675
  const resolvedDir2 = workingDirectory;
67389
67676
  try {
67390
- const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67391
- const planRaw = fs52.readFileSync(planPath, "utf-8");
67677
+ const planPath = path66.join(resolvedDir2, ".swarm", "plan.json");
67678
+ const planRaw = fs53.readFileSync(planPath, "utf-8");
67392
67679
  const plan = JSON.parse(planRaw);
67393
67680
  for (const planPhase of plan.phases ?? []) {
67394
67681
  for (const task of planPhase.tasks ?? []) {
@@ -67454,8 +67741,8 @@ function checkReviewerGate(taskId, workingDirectory) {
67454
67741
  }
67455
67742
  try {
67456
67743
  const resolvedDir2 = workingDirectory;
67457
- const planPath = path65.join(resolvedDir2, ".swarm", "plan.json");
67458
- const planRaw = fs52.readFileSync(planPath, "utf-8");
67744
+ const planPath = path66.join(resolvedDir2, ".swarm", "plan.json");
67745
+ const planRaw = fs53.readFileSync(planPath, "utf-8");
67459
67746
  const plan = JSON.parse(planRaw);
67460
67747
  for (const planPhase of plan.phases ?? []) {
67461
67748
  for (const task of planPhase.tasks ?? []) {
@@ -67637,8 +67924,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67637
67924
  };
67638
67925
  }
67639
67926
  }
67640
- normalizedDir = path65.normalize(args2.working_directory);
67641
- const pathParts = normalizedDir.split(path65.sep);
67927
+ normalizedDir = path66.normalize(args2.working_directory);
67928
+ const pathParts = normalizedDir.split(path66.sep);
67642
67929
  if (pathParts.includes("..")) {
67643
67930
  return {
67644
67931
  success: false,
@@ -67648,11 +67935,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67648
67935
  ]
67649
67936
  };
67650
67937
  }
67651
- const resolvedDir = path65.resolve(normalizedDir);
67938
+ const resolvedDir = path66.resolve(normalizedDir);
67652
67939
  try {
67653
- const realPath = fs52.realpathSync(resolvedDir);
67654
- const planPath = path65.join(realPath, ".swarm", "plan.json");
67655
- if (!fs52.existsSync(planPath)) {
67940
+ const realPath = fs53.realpathSync(resolvedDir);
67941
+ const planPath = path66.join(realPath, ".swarm", "plan.json");
67942
+ if (!fs53.existsSync(planPath)) {
67656
67943
  return {
67657
67944
  success: false,
67658
67945
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -67685,8 +67972,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
67685
67972
  recoverTaskStateFromDelegations(args2.task_id);
67686
67973
  let phaseRequiresReviewer = true;
67687
67974
  try {
67688
- const planPath = path65.join(directory, ".swarm", "plan.json");
67689
- const planRaw = fs52.readFileSync(planPath, "utf-8");
67975
+ const planPath = path66.join(directory, ".swarm", "plan.json");
67976
+ const planRaw = fs53.readFileSync(planPath, "utf-8");
67690
67977
  const plan = JSON.parse(planRaw);
67691
67978
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
67692
67979
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -67749,8 +68036,8 @@ var update_task_status = createSwarmTool({
67749
68036
  init_tool();
67750
68037
  init_utils2();
67751
68038
  init_create_tool();
67752
- import fs53 from "fs";
67753
- import path66 from "path";
68039
+ import fs54 from "fs";
68040
+ import path67 from "path";
67754
68041
  function normalizeVerdict(verdict) {
67755
68042
  switch (verdict) {
67756
68043
  case "APPROVED":
@@ -67797,7 +68084,7 @@ async function executeWriteDriftEvidence(args2, directory) {
67797
68084
  entries: [evidenceEntry]
67798
68085
  };
67799
68086
  const filename = "drift-verifier.json";
67800
- const relativePath = path66.join("evidence", String(phase), filename);
68087
+ const relativePath = path67.join("evidence", String(phase), filename);
67801
68088
  let validatedPath;
67802
68089
  try {
67803
68090
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -67808,12 +68095,12 @@ async function executeWriteDriftEvidence(args2, directory) {
67808
68095
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
67809
68096
  }, null, 2);
67810
68097
  }
67811
- const evidenceDir = path66.dirname(validatedPath);
68098
+ const evidenceDir = path67.dirname(validatedPath);
67812
68099
  try {
67813
- await fs53.promises.mkdir(evidenceDir, { recursive: true });
67814
- const tempPath = path66.join(evidenceDir, `.${filename}.tmp`);
67815
- await fs53.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
67816
- 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);
67817
68104
  return JSON.stringify({
67818
68105
  success: true,
67819
68106
  phase,
@@ -67891,6 +68178,7 @@ ${footerLines.join(`
67891
68178
  var _heartbeatTimers = new Map;
67892
68179
  var OpenCodeSwarm = async (ctx) => {
67893
68180
  const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
68181
+ swarmState.opencodeClient = ctx.client;
67894
68182
  await loadSnapshot(ctx.directory);
67895
68183
  initTelemetry(ctx.directory);
67896
68184
  const agents = getAgentConfigs(config3);
@@ -68001,7 +68289,7 @@ var OpenCodeSwarm = async (ctx) => {
68001
68289
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
68002
68290
  preflightTriggerManager = new PTM(automationConfig);
68003
68291
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
68004
- const swarmDir = path67.resolve(ctx.directory, ".swarm");
68292
+ const swarmDir = path68.resolve(ctx.directory, ".swarm");
68005
68293
  statusArtifact = new ASA(swarmDir);
68006
68294
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
68007
68295
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -68333,7 +68621,7 @@ var OpenCodeSwarm = async (ctx) => {
68333
68621
  } catch {}
68334
68622
  return Promise.resolve();
68335
68623
  },
68336
- 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
68337
68625
  ].filter(Boolean)),
68338
68626
  "experimental.session.compacting": compactionHook["experimental.session.compacting"],
68339
68627
  "command.execute.before": safeHook(commandHandler),