opencode-swarm 6.41.4 → 6.42.1

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