opencode-swarm 7.20.2 → 7.21.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
@@ -33,7 +33,7 @@ var package_default;
33
33
  var init_package = __esm(() => {
34
34
  package_default = {
35
35
  name: "opencode-swarm",
36
- version: "7.20.2",
36
+ version: "7.21.1",
37
37
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
38
38
  main: "dist/index.js",
39
39
  types: "dist/index.d.ts",
@@ -62852,9 +62852,14 @@ At session start, before your first delegation:
62852
62852
  1. Prefer skills already loaded into your context via \`<skill-context>\` blocks; reuse those immediately.
62853
62853
  2. When you need to inspect on-disk skills, use the \`search\` tool with \`include\` patterns like \`.opencode/skills/*/SKILL.md,.claude/skills/*/SKILL.md\` and frontmatter queries such as \`^name:\` / \`^description:\` so you only read the YAML lines you need.
62854
62854
  3. Write a brief skill index to \`.swarm/context.md\` under \`## Available Skills\`:
62855
- - writing-tests: Guidelines for writing tests (bun:test, mock isolation, CI) → test_engineer, coder
62856
- - engineering-conventions: Engineering invariants for this repo → coder, reviewer, test_engineer
62857
- - [name]: [description] → [applicable agents]
62855
+ - writing-tests: Guidelines for writing tests (used: 12, compliance: 95%) → test_engineer, coder
62856
+ - engineering-conventions: Engineering invariants (used: 8, compliance: 100%) → coder, reviewer, test_engineer
62857
+ - [name]: [description] (used: N, compliance: N%) → [applicable agents]
62858
+
62859
+ If \`.swarm/skill-usage.jsonl\` exists, read it at session start to inform skill prioritization. Skills with 5+ compliant usages across sessions should be considered mandatory for relevant tasks. Read \`.swarm/skill-usage.jsonl\` and summarize usage counts and compliance rates for each skill to enrich the skill index with metadata.
62860
+
62861
+ If skill-usage.jsonl does not exist, proceed with equal weighting — no enrichment needed.
62862
+
62858
62863
  4. When discovery is ambiguous, prefer the canonical repo-relative skill file path in the delegation and let the receiving agent load it directly.
62859
62864
 
62860
62865
  ### Step 2 — Route skills to agents
@@ -62892,6 +62897,12 @@ Default to repo-relative \`file:\` references for coder, reviewer, test_engineer
62892
62897
 
62893
62898
  **Mandatory for coding tasks:** Always provide \`writing-tests\` to test_engineer and \`engineering-conventions\` to coder + reviewer when those skills are present in the project. Prefer \`file:\` references when the files exist.
62894
62899
 
62900
+ ### Step 4 — Forward skills to reviewer
62901
+
62902
+ When delegating to the reviewer after a coder task, include a \`SKILLS_USED_BY_CODER: [comma-separated list of skill paths from the coder delegation]\` field. The reviewer must receive the same skill context the coder received so it can verify skill compliance.
62903
+
62904
+ Example: If the coder received \`SKILLS: file:.claude/skills/writing-tests/SKILL.md\`, the reviewer delegation must include \`SKILLS_USED_BY_CODER: file:.claude/skills/writing-tests/SKILL.md\` in addition to the reviewer's own \`SKILLS:\` field.
62905
+
62895
62906
  ## SWARM KNOWLEDGE DIRECTIVES (v2 acknowledgment contract)
62896
62907
 
62897
62908
  If a \`<swarm_knowledge_directives>\` block is present in your context, treat each
@@ -62942,6 +62953,7 @@ Continue handling small touch-ups (typos, cross-references) inline.
62942
62953
  - ✗ "I don't know which skill is relevant" → When uncertain, pass ALL discovered skills. Subagents discard inapplicable content.
62943
62954
  - ✗ "The skill was loaded earlier so the agent knows it" → Each subagent Task call is a fresh context. Skills do NOT persist across Task boundaries.
62944
62955
  - ✗ "I'll paste the whole skill body every time just to be safe" → Inline bodies are fallback only. Prefer \`file:\` references to avoid unnecessary context bloat.
62956
+ - ✗ "The reviewer doesn't need the coder's skills" → WRONG. The reviewer cannot verify skill compliance without knowing what skills the coder received. Always forward via SKILLS_USED_BY_CODER.
62945
62957
 
62946
62958
  ## SLASH COMMANDS
62947
62959
  {{SLASH_COMMANDS}}
@@ -63002,6 +63014,7 @@ TASK: Review login validation
63002
63014
  FILE: src/auth/login.ts
63003
63015
  CHECK: [security, correctness, edge-cases]
63004
63016
  GATES: lint=PASS, sast_scan=PASS, secretscan=PASS
63017
+ SKILLS_USED_BY_CODER: file:.claude/skills/engineering-conventions/SKILL.md
63005
63018
  OUTPUT: VERDICT + RISK + ISSUES
63006
63019
  SKILLS: file:.claude/skills/engineering-conventions/SKILL.md
63007
63020
 
@@ -65696,6 +65709,7 @@ AFFECTS: [callers/consumers/dependents to inspect, or "infer from diff"]
65696
65709
  CHECK: [list of dimensions to evaluate]
65697
65710
  GATES: [pre-completed gate results (lint, SAST, secretscan, etc.), or "none" if unavailable]
65698
65711
  SKILLS: [optional — either "none", repo-relative file: references (preferred), or inline skill content pasted by architect]
65712
+ SKILLS_USED_BY_CODER: [list of skill paths that were passed to the coder for this task, or "none" if no skills were used]
65699
65713
 
65700
65714
  SKILLS HANDLING: If SKILLS is present and not "none", load EVERY referenced skill before beginning your review.
65701
65715
  - For \`file:\` entries, use the search tool to read the referenced \`SKILL.md\` file with \`include\` set to that exact repo-relative path, \`mode: regex\`, \`query: .*\`, \`max_results: 1000\`, and \`max_lines: 1000\`.
@@ -65704,6 +65718,13 @@ SKILLS HANDLING: If SKILLS is present and not "none", load EVERY referenced skil
65704
65718
  - If inline \`--- skill-name ---\` sections are present, read them directly.
65705
65719
  - Skills contain project-specific constraints (coding standards, architectural invariants, security requirements) that supplement and may extend your normal review dimensions. Flag any violation of a skill rule at the same severity as a logic error.
65706
65720
 
65721
+ SKILL COMPLIANCE REVIEW: When SKILLS_USED_BY_CODER is provided and not "none":
65722
+ - Load each skill the coder received using the same SKILLS HANDLING procedure above
65723
+ - For each skill rule, verify the coder's changes comply
65724
+ - Flag violations at the same severity as logic errors
65725
+ - Report the overall compliance verdict in SKILL_COMPLIANCE field of your output
65726
+ - If you cannot load a skill (SKILL_LOAD_FAILED), report SKILL_COMPLIANCE: PARTIAL — [skill path] could not be loaded
65727
+
65707
65728
  PROCESSING: If GATES is provided and includes passing results for lint, SAST, placeholder-scan, or secret-scan: skip the corresponding Tier 2 checks that those gates already cover. Focus Tier 2 time on checks NOT covered by automated gates.
65708
65729
 
65709
65730
  ## OUTPUT FORMAT (MANDATORY — deviations will be rejected)
@@ -65713,6 +65734,7 @@ VERDICT: APPROVED | REJECTED
65713
65734
  REUSE_RE_VERIFICATION: [VERIFIED | DUPLICATION_DETECTED | SKIPPED] — DUPLICATION_DETECTED is only valid when VERDICT is REJECTED
65714
65735
  RISK: LOW | MEDIUM | HIGH | CRITICAL
65715
65736
  ISSUES: list with line numbers, grouped by CHECK dimension
65737
+ SKILL_COMPLIANCE: COMPLIANT | PARTIAL | VIOLATED — [list of violations or "all rules followed"]
65716
65738
  FIXES: required changes if rejected
65717
65739
  Use INFO only inside ISSUES for non-blocking suggestions. RISK reflects the highest blocking severity, so it never uses INFO.
65718
65740
 
@@ -71634,15 +71656,15 @@ var init_curator_drift = __esm(() => {
71634
71656
  var exports_project_context = {};
71635
71657
  __export(exports_project_context, {
71636
71658
  buildProjectContext: () => buildProjectContext,
71637
- _internals: () => _internals52,
71659
+ _internals: () => _internals55,
71638
71660
  LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
71639
71661
  });
71640
- import * as fs110 from "node:fs";
71641
- import * as path139 from "node:path";
71662
+ import * as fs112 from "node:fs";
71663
+ import * as path142 from "node:path";
71642
71664
  function detectFileExists2(directory, pattern) {
71643
71665
  if (pattern.includes("*") || pattern.includes("?")) {
71644
71666
  try {
71645
- const files = fs110.readdirSync(directory);
71667
+ const files = fs112.readdirSync(directory);
71646
71668
  const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
71647
71669
  return files.some((f) => regex.test(f));
71648
71670
  } catch {
@@ -71650,7 +71672,7 @@ function detectFileExists2(directory, pattern) {
71650
71672
  }
71651
71673
  }
71652
71674
  try {
71653
- fs110.accessSync(path139.join(directory, pattern));
71675
+ fs112.accessSync(path142.join(directory, pattern));
71654
71676
  return true;
71655
71677
  } catch {
71656
71678
  return false;
@@ -71659,7 +71681,7 @@ function detectFileExists2(directory, pattern) {
71659
71681
  function selectTestCommandFromScriptsTest(backend, directory) {
71660
71682
  let pkgRaw;
71661
71683
  try {
71662
- pkgRaw = fs110.readFileSync(path139.join(directory, "package.json"), "utf-8");
71684
+ pkgRaw = fs112.readFileSync(path142.join(directory, "package.json"), "utf-8");
71663
71685
  } catch {
71664
71686
  return null;
71665
71687
  }
@@ -71718,7 +71740,7 @@ function selectLintCommand(backend, directory) {
71718
71740
  return null;
71719
71741
  }
71720
71742
  async function buildProjectContext(directory) {
71721
- const backend = await _internals52.pickBackend(directory);
71743
+ const backend = await _internals55.pickBackend(directory);
71722
71744
  if (!backend)
71723
71745
  return null;
71724
71746
  const ctx = emptyProjectContext();
@@ -71749,16 +71771,16 @@ async function buildProjectContext(directory) {
71749
71771
  if (backend.prompts.reviewerChecklist.length > 0) {
71750
71772
  ctx.REVIEWER_CHECKLIST = bulletList(backend.prompts.reviewerChecklist);
71751
71773
  }
71752
- const profiles = _internals52.pickedProfiles(directory);
71774
+ const profiles = _internals55.pickedProfiles(directory);
71753
71775
  if (profiles.length > 1) {
71754
71776
  ctx.PROJECT_CONTEXT_SECONDARY_LANGUAGES = profiles.slice(1).map((p) => p.id).join(", ");
71755
71777
  }
71756
71778
  return ctx;
71757
71779
  }
71758
- var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals52;
71780
+ var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals55;
71759
71781
  var init_project_context = __esm(() => {
71760
71782
  init_dispatch();
71761
- _internals52 = {
71783
+ _internals55 = {
71762
71784
  pickBackend,
71763
71785
  pickedProfiles
71764
71786
  };
@@ -71768,7 +71790,7 @@ var init_project_context = __esm(() => {
71768
71790
  init_package();
71769
71791
  init_agents2();
71770
71792
  init_critic();
71771
- import * as path140 from "node:path";
71793
+ import * as path143 from "node:path";
71772
71794
 
71773
71795
  // src/background/index.ts
71774
71796
  init_event_bus();
@@ -82651,9 +82673,702 @@ function createSelfReviewHook(config3, injectAdvisory) {
82651
82673
  };
82652
82674
  }
82653
82675
 
82654
- // src/hooks/slop-detector.ts
82676
+ // src/hooks/skill-propagation-gate.ts
82677
+ init_schema();
82678
+ init_logger();
82679
+ import * as fs62 from "node:fs";
82680
+ import * as path89 from "node:path";
82681
+
82682
+ // src/hooks/skill-scoring.ts
82683
+ import * as path88 from "node:path";
82684
+
82685
+ // src/hooks/skill-usage-log.ts
82686
+ init_utils2();
82687
+ import * as crypto9 from "node:crypto";
82655
82688
  import * as fs61 from "node:fs";
82656
82689
  import * as path87 from "node:path";
82690
+ function resolveLogPath(directory) {
82691
+ return validateSwarmPath(directory, "skill-usage.jsonl");
82692
+ }
82693
+ var _internals40 = {
82694
+ generateId: () => crypto9.randomUUID(),
82695
+ appendFileSync: fs61.appendFileSync.bind(fs61),
82696
+ readFileSync: fs61.readFileSync.bind(fs61),
82697
+ writeFileSync: fs61.writeFileSync.bind(fs61),
82698
+ renameSync: fs61.renameSync.bind(fs61),
82699
+ mkdirSync: fs61.mkdirSync.bind(fs61),
82700
+ existsSync: fs61.existsSync.bind(fs61),
82701
+ statSync: fs61.statSync.bind(fs61),
82702
+ openSync: fs61.openSync.bind(fs61),
82703
+ readSync: fs61.readSync.bind(fs61),
82704
+ closeSync: fs61.closeSync.bind(fs61)
82705
+ };
82706
+ function appendSkillUsageEntry(directory, entry) {
82707
+ const {
82708
+ skillPath,
82709
+ agentName,
82710
+ taskID,
82711
+ timestamp,
82712
+ complianceVerdict,
82713
+ sessionID,
82714
+ reviewerNotes
82715
+ } = entry;
82716
+ if (!skillPath || typeof skillPath !== "string") {
82717
+ throw new Error("skillPath is required and must be a non-empty string");
82718
+ }
82719
+ if (/\.\.[/\\]/.test(skillPath)) {
82720
+ throw new Error("skillPath contains path traversal sequence");
82721
+ }
82722
+ if (!agentName || typeof agentName !== "string") {
82723
+ throw new Error("agentName is required and must be a non-empty string");
82724
+ }
82725
+ if (!taskID || typeof taskID !== "string") {
82726
+ throw new Error("taskID is required and must be a non-empty string");
82727
+ }
82728
+ if (!timestamp || typeof timestamp !== "string") {
82729
+ throw new Error("timestamp is required and must be a non-empty string");
82730
+ }
82731
+ if (!complianceVerdict || typeof complianceVerdict !== "string") {
82732
+ throw new Error("complianceVerdict is required and must be a non-empty string");
82733
+ }
82734
+ if (!sessionID || typeof sessionID !== "string") {
82735
+ throw new Error("sessionID is required and must be a non-empty string");
82736
+ }
82737
+ const resolved = validateSwarmPath(directory, "skill-usage.jsonl");
82738
+ const dir = path87.dirname(resolved);
82739
+ if (!_internals40.existsSync(dir)) {
82740
+ _internals40.mkdirSync(dir, { recursive: true });
82741
+ }
82742
+ const fullEntry = {
82743
+ id: _internals40.generateId(),
82744
+ skillPath,
82745
+ agentName,
82746
+ taskID,
82747
+ timestamp,
82748
+ complianceVerdict,
82749
+ sessionID,
82750
+ ...reviewerNotes !== undefined && { reviewerNotes }
82751
+ };
82752
+ _internals40.appendFileSync(resolved, `${JSON.stringify(fullEntry)}
82753
+ `, "utf-8");
82754
+ }
82755
+ function readSkillUsageEntries(directory, options) {
82756
+ const resolved = resolveLogPath(directory);
82757
+ if (!_internals40.existsSync(resolved)) {
82758
+ return [];
82759
+ }
82760
+ const raw = _internals40.readFileSync(resolved, "utf-8");
82761
+ const entries = [];
82762
+ for (const line of raw.split(`
82763
+ `)) {
82764
+ const trimmed = line.trim();
82765
+ if (!trimmed)
82766
+ continue;
82767
+ try {
82768
+ entries.push(JSON.parse(trimmed));
82769
+ } catch {}
82770
+ }
82771
+ if (!options)
82772
+ return entries;
82773
+ return entries.filter((e) => {
82774
+ if (options.sessionID !== undefined && e.sessionID !== options.sessionID) {
82775
+ return false;
82776
+ }
82777
+ if (options.skillPath !== undefined && e.skillPath !== options.skillPath) {
82778
+ return false;
82779
+ }
82780
+ if (options.agentName !== undefined && e.agentName !== options.agentName) {
82781
+ return false;
82782
+ }
82783
+ if (options.taskID !== undefined && e.taskID !== options.taskID) {
82784
+ return false;
82785
+ }
82786
+ if (options.dateRange !== undefined) {
82787
+ if (e.timestamp < options.dateRange.start)
82788
+ return false;
82789
+ if (e.timestamp > options.dateRange.end)
82790
+ return false;
82791
+ }
82792
+ return true;
82793
+ });
82794
+ }
82795
+ var TAIL_BYTES_DEFAULT = 64 * 1024;
82796
+ function readSkillUsageEntriesTail(directory, filters, maxBytes = TAIL_BYTES_DEFAULT) {
82797
+ const logPath = resolveLogPath(directory);
82798
+ if (!_internals40.existsSync(logPath))
82799
+ return [];
82800
+ try {
82801
+ const stat7 = _internals40.statSync(logPath);
82802
+ const start2 = Math.max(0, stat7.size - maxBytes);
82803
+ const fd = _internals40.openSync(logPath, "r");
82804
+ try {
82805
+ const readLen = stat7.size - start2;
82806
+ if (readLen === 0)
82807
+ return [];
82808
+ const buf = Buffer.alloc(readLen);
82809
+ _internals40.readSync(fd, buf, 0, buf.length, start2);
82810
+ const content = buf.toString("utf-8");
82811
+ let usable;
82812
+ if (start2 > 0) {
82813
+ const firstNewline = content.indexOf(`
82814
+ `);
82815
+ usable = firstNewline >= 0 ? content.slice(firstNewline + 1) : "";
82816
+ } else {
82817
+ usable = content;
82818
+ }
82819
+ const entries = [];
82820
+ for (const line of usable.split(`
82821
+ `)) {
82822
+ if (!line.trim())
82823
+ continue;
82824
+ try {
82825
+ const entry = JSON.parse(line);
82826
+ if (filters.sessionID !== undefined && entry.sessionID !== filters.sessionID) {
82827
+ continue;
82828
+ }
82829
+ entries.push(entry);
82830
+ } catch {}
82831
+ }
82832
+ return entries;
82833
+ } finally {
82834
+ _internals40.closeSync(fd);
82835
+ }
82836
+ } catch {
82837
+ return [];
82838
+ }
82839
+ }
82840
+
82841
+ // src/hooks/skill-scoring.ts
82842
+ var FREQUENCY_CAP = 10;
82843
+ var FREQUENCY_WEIGHT = 0.3;
82844
+ var COMPLIANCE_WEIGHT = 0.3;
82845
+ var RECENCY_WEIGHT = 0.15;
82846
+ var TASK_DIVERSITY_WEIGHT = 0.05;
82847
+ var CONTEXT_WEIGHT = 0.2;
82848
+ var RECENCY_DECAY_MS = 30 * 24 * 60 * 60 * 1000;
82849
+ var _internals41 = {
82850
+ computeSkillRelevanceScore: null,
82851
+ rankSkillsForContext: null,
82852
+ getSkillStats: null,
82853
+ formatSkillIndexWithContext: null,
82854
+ extractSkillName: null,
82855
+ computeRecencyScore: null,
82856
+ computeContextMatchScore: null
82857
+ };
82858
+ function extractSkillName(skillPath) {
82859
+ const base = path88.basename(skillPath, path88.extname(skillPath));
82860
+ if (base !== "SKILL")
82861
+ return base;
82862
+ const parent = path88.basename(path88.dirname(skillPath));
82863
+ return parent;
82864
+ }
82865
+ function computeRecencyScore(lastUsedTimestamp) {
82866
+ if (!lastUsedTimestamp)
82867
+ return 0;
82868
+ const lastUsed = new Date(lastUsedTimestamp).getTime();
82869
+ if (Number.isNaN(lastUsed))
82870
+ return 0;
82871
+ const ageMs = Date.now() - lastUsed;
82872
+ if (ageMs <= 0)
82873
+ return 1;
82874
+ if (ageMs >= RECENCY_DECAY_MS)
82875
+ return 0;
82876
+ return 1 - ageMs / RECENCY_DECAY_MS;
82877
+ }
82878
+ var MIN_KEYWORD_LENGTH = 3;
82879
+ function extractKeywords(text) {
82880
+ const words = text.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= MIN_KEYWORD_LENGTH);
82881
+ return new Set(words);
82882
+ }
82883
+ function computeContextMatchScore(taskDescription, skillPath) {
82884
+ const taskKeywords = extractKeywords(taskDescription);
82885
+ if (taskKeywords.size === 0)
82886
+ return 0;
82887
+ const skillName = extractSkillName(skillPath);
82888
+ const skillText = `${skillPath} ${skillName}`;
82889
+ const skillKeywords = extractKeywords(skillText);
82890
+ let matchCount = 0;
82891
+ for (const kw of taskKeywords) {
82892
+ if (skillKeywords.has(kw)) {
82893
+ matchCount++;
82894
+ }
82895
+ }
82896
+ return matchCount / taskKeywords.size;
82897
+ }
82898
+ function computeSkillRelevanceScore(skillPath, taskDescription, usageHistory) {
82899
+ const contextScore = computeContextMatchScore(taskDescription, skillPath) * CONTEXT_WEIGHT;
82900
+ if (usageHistory.length === 0)
82901
+ return contextScore;
82902
+ const usageCount = usageHistory.length;
82903
+ const frequencyScore = Math.min(1, usageCount / FREQUENCY_CAP) * FREQUENCY_WEIGHT;
82904
+ const entriesWithVerdict = usageHistory.filter((e) => e.complianceVerdict !== undefined && e.complianceVerdict !== "not_checked");
82905
+ const compliantCount = entriesWithVerdict.filter((e) => e.complianceVerdict === "compliant").length;
82906
+ const denominator = Math.max(1, entriesWithVerdict.length);
82907
+ const complianceScore = compliantCount / denominator * COMPLIANCE_WEIGHT;
82908
+ const sortedByTime = [...usageHistory].sort((a, b) => b.timestamp > a.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0);
82909
+ const lastUsedTimestamp = sortedByTime[0]?.timestamp ?? "";
82910
+ const recencyScore = computeRecencyScore(lastUsedTimestamp) * RECENCY_WEIGHT;
82911
+ const distinctTaskIDs = new Set(usageHistory.map((e) => e.taskID).filter(Boolean)).size;
82912
+ const taskDiversityScore = distinctTaskIDs / Math.max(1, usageHistory.length) * TASK_DIVERSITY_WEIGHT;
82913
+ return frequencyScore + complianceScore + recencyScore + taskDiversityScore + contextScore;
82914
+ }
82915
+ function rankSkillsForContext(skills, taskContext, directory) {
82916
+ const allEntries = readSkillUsageEntries(directory);
82917
+ const results = [];
82918
+ for (const skillPath of skills) {
82919
+ const skillEntries = allEntries.filter((e) => e.skillPath === skillPath);
82920
+ const score = computeSkillRelevanceScore(skillPath, taskContext, skillEntries);
82921
+ const entriesWithVerdict = skillEntries.filter((e) => e.complianceVerdict !== undefined && e.complianceVerdict !== "not_checked");
82922
+ const compliantCount = entriesWithVerdict.filter((e) => e.complianceVerdict === "compliant").length;
82923
+ const complianceRate = entriesWithVerdict.length > 0 ? compliantCount / entriesWithVerdict.length : 0;
82924
+ results.push({
82925
+ skillPath,
82926
+ score,
82927
+ usageCount: skillEntries.length,
82928
+ complianceRate
82929
+ });
82930
+ }
82931
+ results.sort((a, b) => {
82932
+ if (b.score !== a.score)
82933
+ return b.score - a.score;
82934
+ return b.usageCount - a.usageCount;
82935
+ });
82936
+ return results;
82937
+ }
82938
+ function getSkillStats(skillPath, directory) {
82939
+ const entries = readSkillUsageEntries(directory, { skillPath });
82940
+ if (entries.length === 0) {
82941
+ return {
82942
+ totalUsage: 0,
82943
+ complianceRate: 0,
82944
+ lastUsed: "",
82945
+ topAgents: []
82946
+ };
82947
+ }
82948
+ const entriesWithVerdict = entries.filter((e) => e.complianceVerdict !== undefined && e.complianceVerdict !== "not_checked");
82949
+ const compliantCount = entriesWithVerdict.filter((e) => e.complianceVerdict === "compliant").length;
82950
+ const complianceRate = entriesWithVerdict.length > 0 ? compliantCount / entriesWithVerdict.length : 0;
82951
+ const sortedByTime = [...entries].sort((a, b) => b.timestamp > a.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0);
82952
+ const lastUsed = sortedByTime[0]?.timestamp ?? "";
82953
+ const agentCounts = new Map;
82954
+ for (const entry of entries) {
82955
+ agentCounts.set(entry.agentName, (agentCounts.get(entry.agentName) ?? 0) + 1);
82956
+ }
82957
+ const topAgents = Array.from(agentCounts.entries()).sort((a, b) => b[1] - a[1]).map(([agent, count]) => ({ agent, count }));
82958
+ return {
82959
+ totalUsage: entries.length,
82960
+ complianceRate,
82961
+ lastUsed,
82962
+ topAgents
82963
+ };
82964
+ }
82965
+ function formatSkillIndexWithContext(skills, directory) {
82966
+ const allEntries = readSkillUsageEntries(directory);
82967
+ const hasHistory = allEntries.length > 0;
82968
+ if (!hasHistory) {
82969
+ return skills.map((sp) => ` - ${extractSkillName(sp)}`).join(`
82970
+ `);
82971
+ }
82972
+ const lines = [];
82973
+ for (const skillPath of skills) {
82974
+ const stats = getSkillStats(skillPath, directory);
82975
+ const name2 = extractSkillName(skillPath);
82976
+ const compliancePct = Math.round(stats.complianceRate * 100);
82977
+ const topAgentNames = stats.topAgents.slice(0, 3).map((a) => a.agent).join(", ");
82978
+ lines.push(` ${name2}: ${skillPath} (used: ${stats.totalUsage}, compliance: ${compliancePct}%)` + (stats.topAgents.length > 0 ? ` → ${topAgentNames}` : ""));
82979
+ }
82980
+ return lines.join(`
82981
+ `);
82982
+ }
82983
+ _internals41.computeSkillRelevanceScore = computeSkillRelevanceScore;
82984
+ _internals41.rankSkillsForContext = rankSkillsForContext;
82985
+ _internals41.getSkillStats = getSkillStats;
82986
+ _internals41.formatSkillIndexWithContext = formatSkillIndexWithContext;
82987
+ _internals41.extractSkillName = extractSkillName;
82988
+ _internals41.computeRecencyScore = computeRecencyScore;
82989
+ _internals41.computeContextMatchScore = computeContextMatchScore;
82990
+
82991
+ // src/hooks/skill-propagation-gate.ts
82992
+ var SKILL_CAPABLE_AGENTS = new Set([
82993
+ "coder",
82994
+ "reviewer",
82995
+ "test_engineer",
82996
+ "sme",
82997
+ "docs",
82998
+ "designer"
82999
+ ]);
83000
+ var SKILL_SEARCH_ROOTS = [
83001
+ ".opencode/skills",
83002
+ ".opencode/skills/generated",
83003
+ ".claude/skills"
83004
+ ];
83005
+ var MAX_SCORING_SESSION_ENTRIES = 500;
83006
+ var _internals42 = {
83007
+ readdirSync: fs62.readdirSync.bind(fs62),
83008
+ existsSync: fs62.existsSync.bind(fs62),
83009
+ statSync: fs62.statSync.bind(fs62),
83010
+ mkdirSync: fs62.mkdirSync.bind(fs62),
83011
+ appendFileSync: fs62.appendFileSync.bind(fs62),
83012
+ skillPropagationGateBefore: null,
83013
+ skillPropagationTransformScan: null,
83014
+ SKILL_CAPABLE_AGENTS,
83015
+ MAX_SCORING_SESSION_ENTRIES,
83016
+ writeWarnEvent: null,
83017
+ discoverAvailableSkills: null,
83018
+ parseDelegationArgs: null,
83019
+ appendSkillUsageEntry,
83020
+ readSkillUsageEntries,
83021
+ readSkillUsageEntriesTail,
83022
+ parseSkillPaths: null,
83023
+ extractTaskIdFromPrompt: null,
83024
+ computeSkillRelevanceScore
83025
+ };
83026
+ function discoverAvailableSkills(directory) {
83027
+ const results = [];
83028
+ for (const root of SKILL_SEARCH_ROOTS) {
83029
+ const rootPath = path89.join(directory, root);
83030
+ if (!_internals42.existsSync(rootPath))
83031
+ continue;
83032
+ let entries;
83033
+ try {
83034
+ entries = _internals42.readdirSync(rootPath);
83035
+ } catch {
83036
+ continue;
83037
+ }
83038
+ for (const entry of entries) {
83039
+ if (entry.startsWith("."))
83040
+ continue;
83041
+ const skillDir = path89.join(rootPath, entry);
83042
+ const skillFile = path89.join(skillDir, "SKILL.md");
83043
+ try {
83044
+ if (_internals42.statSync(skillDir).isDirectory() && _internals42.existsSync(skillFile)) {
83045
+ results.push(path89.join(root, entry, "SKILL.md"));
83046
+ }
83047
+ } catch (err2) {
83048
+ warn(`[skill-propagation-gate] failed to stat skill directory ${entry}: ${err2 instanceof Error ? err2.message : String(err2)}`);
83049
+ }
83050
+ }
83051
+ }
83052
+ return [...new Set(results)];
83053
+ }
83054
+ function parseDelegationArgs(args2) {
83055
+ if (!args2 || typeof args2 !== "object")
83056
+ return null;
83057
+ const record3 = args2;
83058
+ const subagentType = typeof record3.subagent_type === "string" ? record3.subagent_type : "";
83059
+ const prompt = typeof record3.prompt === "string" ? record3.prompt : "";
83060
+ if (!subagentType && !prompt)
83061
+ return null;
83062
+ let targetAgent = subagentType;
83063
+ if (!targetAgent && prompt) {
83064
+ const lines = prompt.split(`
83065
+ `);
83066
+ for (const line of lines) {
83067
+ const trimmed = line.trim();
83068
+ if (trimmed) {
83069
+ targetAgent = trimmed;
83070
+ break;
83071
+ }
83072
+ }
83073
+ }
83074
+ if (!targetAgent)
83075
+ return null;
83076
+ let skillsField = "";
83077
+ if (prompt) {
83078
+ const lines = prompt.split(`
83079
+ `);
83080
+ for (const line of lines) {
83081
+ const trimmed = line.trim();
83082
+ if (trimmed.startsWith("SKILLS:")) {
83083
+ skillsField = trimmed.slice("SKILLS:".length).trim();
83084
+ break;
83085
+ }
83086
+ }
83087
+ }
83088
+ return { targetAgent, skillsField };
83089
+ }
83090
+ function writeWarnEvent2(directory, record3) {
83091
+ const filePath = path89.join(directory, ".swarm", "events.jsonl");
83092
+ try {
83093
+ const dir = path89.dirname(filePath);
83094
+ if (!_internals42.existsSync(dir)) {
83095
+ _internals42.mkdirSync(dir, { recursive: true });
83096
+ }
83097
+ _internals42.appendFileSync(filePath, `${JSON.stringify(record3)}
83098
+ `, "utf-8");
83099
+ } catch (err2) {
83100
+ warn(`[skill-propagation-gate] failed to write warning event: ${err2 instanceof Error ? err2.message : String(err2)}`);
83101
+ }
83102
+ }
83103
+ function parseSkillPaths(fieldValue) {
83104
+ if (!fieldValue || typeof fieldValue !== "string")
83105
+ return [];
83106
+ const trimmed = fieldValue.trim();
83107
+ if (trimmed.toLowerCase() === "none" || trimmed === "")
83108
+ return [];
83109
+ return trimmed.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
83110
+ }
83111
+ function extractTaskIdFromPrompt(prompt) {
83112
+ if (!prompt || typeof prompt !== "string")
83113
+ return "unknown";
83114
+ const taskIdMatch = prompt.match(/\btaskId\s*[:=]\s*(\S+)/i);
83115
+ if (taskIdMatch)
83116
+ return taskIdMatch[1];
83117
+ const taskMatch = prompt.match(/\bTASK\s*[:=]\s*(\S+)/i);
83118
+ if (taskMatch)
83119
+ return taskMatch[1];
83120
+ return "unknown";
83121
+ }
83122
+ async function skillPropagationGateBefore(directory, input, config3) {
83123
+ if (!config3.enabled)
83124
+ return;
83125
+ const toolName = typeof input.tool === "string" ? input.tool : "";
83126
+ if (toolName !== "task" && toolName !== "Task")
83127
+ return;
83128
+ const agentRaw = typeof input.agent === "string" ? input.agent : "";
83129
+ if (!agentRaw)
83130
+ return;
83131
+ const baseAgent = stripKnownSwarmPrefix(agentRaw);
83132
+ if (baseAgent !== "architect")
83133
+ return;
83134
+ const parsed = _internals42.parseDelegationArgs(input.args);
83135
+ if (!parsed)
83136
+ return;
83137
+ const targetBase = stripKnownSwarmPrefix(parsed.targetAgent);
83138
+ if (!_internals42.SKILL_CAPABLE_AGENTS.has(targetBase))
83139
+ return;
83140
+ const sessionID = typeof input.sessionID === "string" ? input.sessionID : "unknown";
83141
+ const availableSkills = _internals42.discoverAvailableSkills(directory);
83142
+ const skillsValue = parsed.skillsField.trim();
83143
+ if (skillsValue && skillsValue.toLowerCase() !== "none") {
83144
+ const prompt = typeof input.args?.prompt === "string" ? String(input.args.prompt) : "";
83145
+ const taskId = _internals42.extractTaskIdFromPrompt(prompt);
83146
+ const skillPaths = _internals42.parseSkillPaths(skillsValue);
83147
+ let coderSkillPaths = [];
83148
+ if (prompt) {
83149
+ for (const line of prompt.split(`
83150
+ `)) {
83151
+ const trimmed = line.trim();
83152
+ if (trimmed.startsWith("SKILLS_USED_BY_CODER:")) {
83153
+ const fieldVal = trimmed.slice("SKILLS_USED_BY_CODER:".length).trim();
83154
+ coderSkillPaths = _internals42.parseSkillPaths(fieldVal);
83155
+ break;
83156
+ }
83157
+ }
83158
+ }
83159
+ const allPaths = [...new Set([...skillPaths, ...coderSkillPaths])];
83160
+ for (const skillPath of allPaths) {
83161
+ try {
83162
+ _internals42.appendSkillUsageEntry(directory, {
83163
+ skillPath,
83164
+ agentName: targetBase,
83165
+ taskID: taskId,
83166
+ complianceVerdict: "not_checked",
83167
+ sessionID,
83168
+ timestamp: new Date().toISOString()
83169
+ });
83170
+ } catch (err2) {
83171
+ warn(`[skill-propagation-gate] failed to record skill usage entry: ${err2 instanceof Error ? err2.message : String(err2)}`);
83172
+ }
83173
+ }
83174
+ }
83175
+ if (skillsValue && skillsValue.toLowerCase() !== "none" && availableSkills.length > 0) {
83176
+ try {
83177
+ const sessionEntries = _internals42.readSkillUsageEntriesTail(directory, {
83178
+ sessionID
83179
+ });
83180
+ if (sessionEntries.length > _internals42.MAX_SCORING_SESSION_ENTRIES) {
83181
+ warn(`[skill-propagation-gate] skipping scoring — session has ${sessionEntries.length} entries (limit: ${_internals42.MAX_SCORING_SESSION_ENTRIES})`);
83182
+ } else {
83183
+ const prompt = typeof input.args?.prompt === "string" ? String(input.args.prompt) : "";
83184
+ const scored = availableSkills.map((skillPath) => {
83185
+ const skillEntries = sessionEntries.filter((e) => e.skillPath === skillPath);
83186
+ const score = _internals42.computeSkillRelevanceScore(skillPath, prompt, skillEntries);
83187
+ return { skillPath, score, usageCount: skillEntries.length };
83188
+ }).sort((a, b) => b.score - a.score || b.usageCount - a.usageCount);
83189
+ if (scored.length > 0) {
83190
+ const topSkills = scored.slice(0, 5).map((r) => ` ${r.skillPath} (score: ${r.score.toFixed(3)}, used: ${r.usageCount})`).join(`
83191
+ `);
83192
+ warn(`[skill-propagation-gate] Skill recommendations for task: ${topSkills}`);
83193
+ }
83194
+ }
83195
+ } catch (err2) {
83196
+ warn(`[skill-propagation-gate] skill scoring failed (non-blocking): ${err2 instanceof Error ? err2.message : String(err2)}`);
83197
+ }
83198
+ }
83199
+ if (availableSkills.length === 0)
83200
+ return;
83201
+ const skillsLower = skillsValue.toLowerCase();
83202
+ if (skillsValue && skillsLower !== "none")
83203
+ return;
83204
+ try {
83205
+ _internals42.writeWarnEvent(directory, {
83206
+ type: "skill_propagation_warn",
83207
+ timestamp: new Date().toISOString(),
83208
+ tool: toolName,
83209
+ agent: agentRaw,
83210
+ target_agent: parsed.targetAgent,
83211
+ sessionID,
83212
+ skills_missing: true,
83213
+ available_skills: availableSkills
83214
+ });
83215
+ } catch {}
83216
+ }
83217
+ var COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:—|-)\s*(.*))?\s*$/i;
83218
+ var CODER_SKILLS_PATTERN = /SKILLS_USED_BY_CODER\s*:\s*(.+)/i;
83219
+ async function skillPropagationTransformScan(directory, output, sessionID) {
83220
+ if (!output?.messages)
83221
+ return;
83222
+ if (!sessionID)
83223
+ return;
83224
+ const messages = output.messages;
83225
+ let hadRecordingError = false;
83226
+ let dedupKeys = new Set;
83227
+ let existingEntries = [];
83228
+ try {
83229
+ existingEntries = _internals42.readSkillUsageEntries(directory, {
83230
+ sessionID
83231
+ });
83232
+ dedupKeys = new Set(existingEntries.map((e) => `${e.skillPath}|${e.agentName}|${e.taskID}`));
83233
+ } catch (err2) {
83234
+ warn(`[skill-propagation-gate] dedup preload failed, continuing without dedup: ${err2 instanceof Error ? err2.message : String(err2)}`);
83235
+ }
83236
+ function isDuplicate(skillPath, agentName, taskID) {
83237
+ const key = `${skillPath}|${agentName}|${taskID}`;
83238
+ if (dedupKeys.has(key))
83239
+ return true;
83240
+ dedupKeys.add(key);
83241
+ return false;
83242
+ }
83243
+ for (let i2 = messages.length - 1;i2 >= 0; i2--) {
83244
+ const m = messages[i2];
83245
+ const agent = m.info?.agent;
83246
+ if (typeof agent !== "string" || stripKnownSwarmPrefix(agent) !== "reviewer") {
83247
+ continue;
83248
+ }
83249
+ const text = (m.parts ?? []).map((p) => typeof p.text === "string" ? p.text : "").join(`
83250
+ `);
83251
+ if (!text)
83252
+ continue;
83253
+ const skillPaths = [];
83254
+ for (const line of text.split(`
83255
+ `)) {
83256
+ const coderMatch = line.trim().match(CODER_SKILLS_PATTERN);
83257
+ if (coderMatch) {
83258
+ const parsed = _internals42.parseSkillPaths(coderMatch[1]);
83259
+ skillPaths.push(...parsed);
83260
+ }
83261
+ }
83262
+ let resolvedTaskID = "unknown";
83263
+ if (existingEntries.length > 0) {
83264
+ const latestDelegation = [...existingEntries].reverse().find((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__");
83265
+ if (latestDelegation) {
83266
+ resolvedTaskID = latestDelegation.taskID;
83267
+ if (skillPaths.length === 0) {
83268
+ const delegatedPaths = existingEntries.filter((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__" && e.taskID === resolvedTaskID).map((e) => e.skillPath);
83269
+ if (delegatedPaths.length > 0) {
83270
+ skillPaths.push(...new Set(delegatedPaths));
83271
+ }
83272
+ }
83273
+ }
83274
+ }
83275
+ for (const line of text.split(`
83276
+ `)) {
83277
+ const complianceMatch = line.trim().match(COMPLIANCE_PATTERN);
83278
+ if (!complianceMatch)
83279
+ continue;
83280
+ const verdict = complianceMatch[1].toLowerCase();
83281
+ const notes = (complianceMatch[2] ?? "").trim();
83282
+ const paths = skillPaths.length > 0 ? skillPaths : ["__overall__"];
83283
+ for (const skillPath of paths) {
83284
+ if (hadRecordingError)
83285
+ break;
83286
+ if (isDuplicate(skillPath, "reviewer", resolvedTaskID))
83287
+ continue;
83288
+ try {
83289
+ _internals42.appendSkillUsageEntry(directory, {
83290
+ skillPath,
83291
+ agentName: "reviewer",
83292
+ taskID: resolvedTaskID,
83293
+ complianceVerdict: verdict,
83294
+ reviewerNotes: notes || undefined,
83295
+ sessionID,
83296
+ timestamp: new Date().toISOString()
83297
+ });
83298
+ } catch (err2) {
83299
+ hadRecordingError = true;
83300
+ warn(`[skill-propagation-gate] transform-scan compliance recording failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
83301
+ }
83302
+ }
83303
+ break;
83304
+ }
83305
+ break;
83306
+ }
83307
+ if (hadRecordingError)
83308
+ return;
83309
+ for (let i2 = messages.length - 1;i2 >= 0; i2--) {
83310
+ const m = messages[i2];
83311
+ const agent = m.info?.agent;
83312
+ if (typeof agent !== "string" || stripKnownSwarmPrefix(agent) !== "architect") {
83313
+ continue;
83314
+ }
83315
+ const text = (m.parts ?? []).map((p) => typeof p.text === "string" ? p.text : "").join(`
83316
+ `);
83317
+ if (!text)
83318
+ continue;
83319
+ let currentTargetAgent = "";
83320
+ let skillsField = "";
83321
+ for (const line of text.split(`
83322
+ `)) {
83323
+ const trimmed = line.trim();
83324
+ if (trimmed.match(/TO\s+(coder|reviewer|test_engineer|sme|docs|designer)/i)) {
83325
+ const agentMatch = trimmed.match(/TO\s+(coder|reviewer|test_engineer|sme|docs|designer)/i);
83326
+ if (agentMatch)
83327
+ currentTargetAgent = agentMatch[1].toLowerCase();
83328
+ }
83329
+ if (trimmed.startsWith("SKILLS:")) {
83330
+ skillsField = trimmed.slice("SKILLS:".length).trim();
83331
+ }
83332
+ if (currentTargetAgent && skillsField && skillsField.toLowerCase() !== "none") {
83333
+ const skillPaths = _internals42.parseSkillPaths(skillsField);
83334
+ const taskId = _internals42.extractTaskIdFromPrompt(text);
83335
+ for (const skillPath of skillPaths) {
83336
+ if (hadRecordingError)
83337
+ break;
83338
+ if (isDuplicate(skillPath, currentTargetAgent, taskId))
83339
+ continue;
83340
+ try {
83341
+ _internals42.appendSkillUsageEntry(directory, {
83342
+ skillPath,
83343
+ agentName: currentTargetAgent,
83344
+ taskID: taskId,
83345
+ complianceVerdict: "not_checked",
83346
+ sessionID,
83347
+ timestamp: new Date().toISOString()
83348
+ });
83349
+ } catch (err2) {
83350
+ hadRecordingError = true;
83351
+ warn(`[skill-propagation-gate] transform-scan delegation recording failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
83352
+ }
83353
+ }
83354
+ currentTargetAgent = "";
83355
+ skillsField = "";
83356
+ }
83357
+ }
83358
+ break;
83359
+ }
83360
+ }
83361
+ _internals42.skillPropagationGateBefore = skillPropagationGateBefore;
83362
+ _internals42.skillPropagationTransformScan = skillPropagationTransformScan;
83363
+ _internals42.writeWarnEvent = writeWarnEvent2;
83364
+ _internals42.discoverAvailableSkills = discoverAvailableSkills;
83365
+ _internals42.parseDelegationArgs = parseDelegationArgs;
83366
+ _internals42.parseSkillPaths = parseSkillPaths;
83367
+ _internals42.extractTaskIdFromPrompt = extractTaskIdFromPrompt;
83368
+
83369
+ // src/hooks/slop-detector.ts
83370
+ import * as fs63 from "node:fs";
83371
+ import * as path90 from "node:path";
82657
83372
  var WRITE_EDIT_TOOLS = new Set([
82658
83373
  "write",
82659
83374
  "edit",
@@ -82698,12 +83413,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
82698
83413
  function walkFiles(dir, exts, deadline) {
82699
83414
  const results = [];
82700
83415
  try {
82701
- for (const entry of fs61.readdirSync(dir, { withFileTypes: true })) {
83416
+ for (const entry of fs63.readdirSync(dir, { withFileTypes: true })) {
82702
83417
  if (deadline !== undefined && Date.now() > deadline)
82703
83418
  break;
82704
83419
  if (entry.isSymbolicLink())
82705
83420
  continue;
82706
- const full = path87.join(dir, entry.name);
83421
+ const full = path90.join(dir, entry.name);
82707
83422
  if (entry.isDirectory()) {
82708
83423
  if (entry.name === "node_modules" || entry.name === ".git")
82709
83424
  continue;
@@ -82718,7 +83433,7 @@ function walkFiles(dir, exts, deadline) {
82718
83433
  return results;
82719
83434
  }
82720
83435
  function checkDeadExports(content, projectDir, startTime) {
82721
- const hasPackageJson = fs61.existsSync(path87.join(projectDir, "package.json"));
83436
+ const hasPackageJson = fs63.existsSync(path90.join(projectDir, "package.json"));
82722
83437
  if (!hasPackageJson)
82723
83438
  return null;
82724
83439
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -82741,7 +83456,7 @@ function checkDeadExports(content, projectDir, startTime) {
82741
83456
  if (found || Date.now() - startTime > 480)
82742
83457
  break;
82743
83458
  try {
82744
- const text = fs61.readFileSync(file3, "utf-8");
83459
+ const text = fs63.readFileSync(file3, "utf-8");
82745
83460
  if (importPattern.test(text))
82746
83461
  found = true;
82747
83462
  importPattern.lastIndex = 0;
@@ -82832,17 +83547,17 @@ function checkDuplicateUtility(content, projectDir, startTime, targetFile) {
82832
83547
  for (const utilDir of utilityDirs) {
82833
83548
  if (Date.now() > deadline)
82834
83549
  break;
82835
- const utilPath = path87.join(projectDir, utilDir);
82836
- if (!fs61.existsSync(utilPath))
83550
+ const utilPath = path90.join(projectDir, utilDir);
83551
+ if (!fs63.existsSync(utilPath))
82837
83552
  continue;
82838
83553
  const files = walkFiles(utilPath, [".ts", ".tsx", ".js", ".jsx"], deadline);
82839
83554
  for (const file3 of files) {
82840
83555
  if (Date.now() > deadline)
82841
83556
  break;
82842
- if (targetFile && path87.resolve(file3) === path87.resolve(targetFile))
83557
+ if (targetFile && path90.resolve(file3) === path90.resolve(targetFile))
82843
83558
  continue;
82844
83559
  try {
82845
- const text = fs61.readFileSync(file3, "utf-8");
83560
+ const text = fs63.readFileSync(file3, "utf-8");
82846
83561
  for (const name2 of newExports) {
82847
83562
  const exportPattern = new RegExp(`\\bexport\\s+(?:function|class|const|type|interface)\\s+${name2}\\b`);
82848
83563
  if (exportPattern.test(text)) {
@@ -82925,7 +83640,7 @@ Review before proceeding.`;
82925
83640
  // src/hooks/steering-consumed.ts
82926
83641
  init_bun_compat();
82927
83642
  init_utils2();
82928
- import * as fs62 from "node:fs";
83643
+ import * as fs64 from "node:fs";
82929
83644
  function recordSteeringConsumed(directory, directiveId) {
82930
83645
  try {
82931
83646
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -82934,7 +83649,7 @@ function recordSteeringConsumed(directory, directiveId) {
82934
83649
  directiveId,
82935
83650
  timestamp: new Date().toISOString()
82936
83651
  };
82937
- fs62.appendFileSync(eventsPath, `${JSON.stringify(event)}
83652
+ fs64.appendFileSync(eventsPath, `${JSON.stringify(event)}
82938
83653
  `, "utf-8");
82939
83654
  } catch {}
82940
83655
  }
@@ -82976,15 +83691,15 @@ function createSteeringConsumedHook(directory) {
82976
83691
 
82977
83692
  // src/hooks/trajectory-logger.ts
82978
83693
  init_manager2();
82979
- import * as fs64 from "node:fs/promises";
82980
- import * as path89 from "node:path";
83694
+ import * as fs66 from "node:fs/promises";
83695
+ import * as path92 from "node:path";
82981
83696
 
82982
83697
  // src/prm/trajectory-store.ts
82983
83698
  init_utils2();
82984
- import * as fs63 from "node:fs/promises";
82985
- import * as path88 from "node:path";
83699
+ import * as fs65 from "node:fs/promises";
83700
+ import * as path91 from "node:path";
82986
83701
  function getTrajectoryPath(sessionId, directory) {
82987
- const relativePath = path88.join("trajectories", `${sessionId}.jsonl`);
83702
+ const relativePath = path91.join("trajectories", `${sessionId}.jsonl`);
82988
83703
  return validateSwarmPath(directory, relativePath);
82989
83704
  }
82990
83705
  var _inMemoryTrajectoryCache = new Map;
@@ -83003,10 +83718,10 @@ async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 100
83003
83718
  _inMemoryTrajectoryCache.set(sessionId, cached3);
83004
83719
  }
83005
83720
  const trajectoryPath = getTrajectoryPath(sessionId, directory);
83006
- await fs63.mkdir(path88.dirname(trajectoryPath), { recursive: true });
83721
+ await fs65.mkdir(path91.dirname(trajectoryPath), { recursive: true });
83007
83722
  const line = `${JSON.stringify(entry)}
83008
83723
  `;
83009
- await fs63.appendFile(trajectoryPath, line, "utf-8");
83724
+ await fs65.appendFile(trajectoryPath, line, "utf-8");
83010
83725
  } catch (err2) {
83011
83726
  console.warn(`[trajectory-store] Failed to append trajectory entry: ${err2}`);
83012
83727
  }
@@ -83014,7 +83729,7 @@ async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 100
83014
83729
  async function readTrajectory(sessionId, directory) {
83015
83730
  try {
83016
83731
  const trajectoryPath = getTrajectoryPath(sessionId, directory);
83017
- const content = await fs63.readFile(trajectoryPath, "utf-8");
83732
+ const content = await fs65.readFile(trajectoryPath, "utf-8");
83018
83733
  const lines = content.split(`
83019
83734
  `).filter((line) => line.trim().length > 0);
83020
83735
  const entries = [];
@@ -83038,15 +83753,15 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
83038
83753
  for (const subdir of ["trajectories", "replays"]) {
83039
83754
  try {
83040
83755
  const dirPath = validateSwarmPath(directory, subdir);
83041
- const entries = await fs63.readdir(dirPath, { withFileTypes: true });
83756
+ const entries = await fs65.readdir(dirPath, { withFileTypes: true });
83042
83757
  for (const entry of entries) {
83043
83758
  if (!entry.isFile())
83044
83759
  continue;
83045
- const filePath = path88.join(dirPath, entry.name);
83760
+ const filePath = path91.join(dirPath, entry.name);
83046
83761
  try {
83047
- const stat8 = await fs63.stat(filePath);
83762
+ const stat8 = await fs65.stat(filePath);
83048
83763
  if (now - stat8.mtimeMs > cutoffMs) {
83049
- await fs63.unlink(filePath);
83764
+ await fs65.unlink(filePath);
83050
83765
  }
83051
83766
  } catch {}
83052
83767
  }
@@ -83096,7 +83811,7 @@ function isSensitiveKey(key) {
83096
83811
  }
83097
83812
  async function truncateTrajectoryFile(filePath, maxLines) {
83098
83813
  try {
83099
- const content = await fs64.readFile(filePath, "utf-8");
83814
+ const content = await fs66.readFile(filePath, "utf-8");
83100
83815
  const lines = content.split(`
83101
83816
  `).filter((line) => line.trim().length > 0);
83102
83817
  if (lines.length <= maxLines) {
@@ -83104,7 +83819,7 @@ async function truncateTrajectoryFile(filePath, maxLines) {
83104
83819
  }
83105
83820
  const keepCount = Math.floor(maxLines / 2);
83106
83821
  const keptLines = lines.slice(-keepCount);
83107
- await fs64.writeFile(filePath, `${keptLines.join(`
83822
+ await fs66.writeFile(filePath, `${keptLines.join(`
83108
83823
  `)}
83109
83824
  `, "utf-8");
83110
83825
  } catch {}
@@ -83234,13 +83949,13 @@ function createTrajectoryLoggerHook(config3, _directory) {
83234
83949
  elapsed_ms
83235
83950
  };
83236
83951
  const sanitized = sanitizeTaskId2(taskId);
83237
- const relativePath = path89.join("evidence", sanitized, "trajectory.jsonl");
83952
+ const relativePath = path92.join("evidence", sanitized, "trajectory.jsonl");
83238
83953
  const trajectoryPath = validateSwarmPath(_directory, relativePath);
83239
83954
  try {
83240
- await fs64.mkdir(path89.dirname(trajectoryPath), { recursive: true });
83955
+ await fs66.mkdir(path92.dirname(trajectoryPath), { recursive: true });
83241
83956
  const line = `${JSON.stringify(entry)}
83242
83957
  `;
83243
- await fs64.appendFile(trajectoryPath, line, "utf-8");
83958
+ await fs66.appendFile(trajectoryPath, line, "utf-8");
83244
83959
  await truncateTrajectoryFile(trajectoryPath, maxLines);
83245
83960
  } catch {}
83246
83961
  try {
@@ -83787,17 +84502,17 @@ init_state();
83787
84502
  init_telemetry();
83788
84503
 
83789
84504
  // src/prm/replay.ts
83790
- import { promises as fs65 } from "node:fs";
83791
- import path90 from "node:path";
84505
+ import { promises as fs67 } from "node:fs";
84506
+ import path93 from "node:path";
83792
84507
  function isPathSafe2(targetPath, basePath) {
83793
- const resolvedTarget = path90.resolve(targetPath);
83794
- const resolvedBase = path90.resolve(basePath);
83795
- const rel = path90.relative(resolvedBase, resolvedTarget);
83796
- return !rel.startsWith("..") && !path90.isAbsolute(rel);
84508
+ const resolvedTarget = path93.resolve(targetPath);
84509
+ const resolvedBase = path93.resolve(basePath);
84510
+ const rel = path93.relative(resolvedBase, resolvedTarget);
84511
+ return !rel.startsWith("..") && !path93.isAbsolute(rel);
83797
84512
  }
83798
84513
  function isWithinReplaysDir(targetPath) {
83799
- const resolved = path90.resolve(targetPath);
83800
- const parts2 = resolved.split(path90.sep);
84514
+ const resolved = path93.resolve(targetPath);
84515
+ const parts2 = resolved.split(path93.sep);
83801
84516
  for (let i2 = 0;i2 < parts2.length - 1; i2++) {
83802
84517
  if (parts2[i2] === ".swarm" && parts2[i2 + 1] === "replays") {
83803
84518
  return true;
@@ -83810,15 +84525,15 @@ function sanitizeFilename(input) {
83810
84525
  }
83811
84526
  async function startReplayRecording(sessionID, directory) {
83812
84527
  try {
83813
- const replayDir = path90.join(directory, ".swarm", "replays");
84528
+ const replayDir = path93.join(directory, ".swarm", "replays");
83814
84529
  const safeSessionID = sanitizeFilename(sessionID);
83815
84530
  const filename = `${safeSessionID}-${Date.now()}.jsonl`;
83816
- const filepath = path90.join(replayDir, filename);
84531
+ const filepath = path93.join(replayDir, filename);
83817
84532
  if (!isPathSafe2(filepath, replayDir)) {
83818
84533
  console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
83819
84534
  return null;
83820
84535
  }
83821
- await fs65.mkdir(replayDir, { recursive: true });
84536
+ await fs67.mkdir(replayDir, { recursive: true });
83822
84537
  return filepath;
83823
84538
  } catch (err2) {
83824
84539
  console.warn(`[replay] Failed to start recording for session ${sessionID}: ${err2}`);
@@ -83838,7 +84553,7 @@ async function recordReplayEntry(artifactPath, sessionID, entry) {
83838
84553
  };
83839
84554
  const line = `${JSON.stringify(fullEntry)}
83840
84555
  `;
83841
- await fs65.appendFile(artifactPath, line, "utf-8");
84556
+ await fs67.appendFile(artifactPath, line, "utf-8");
83842
84557
  } catch (err2) {
83843
84558
  console.warn(`[replay] Failed to record entry: ${err2}`);
83844
84559
  }
@@ -83973,7 +84688,7 @@ init_version_check();
83973
84688
  init_utils2();
83974
84689
  init_state();
83975
84690
  init_bun_compat();
83976
- import { renameSync as renameSync17 } from "node:fs";
84691
+ import { renameSync as renameSync18 } from "node:fs";
83977
84692
  var TRANSIENT_SESSION_FIELDS = [
83978
84693
  { name: "revisionLimitHit", resetValue: false },
83979
84694
  { name: "coderRevisions", resetValue: 0 },
@@ -84100,7 +84815,7 @@ async function readSnapshot(directory) {
84100
84815
  if (parsed.version !== 1 && parsed.version !== 2) {
84101
84816
  try {
84102
84817
  const quarantinePath = validateSwarmPath(directory, "session/state.json.quarantine");
84103
- renameSync17(resolvedPath, quarantinePath);
84818
+ renameSync18(resolvedPath, quarantinePath);
84104
84819
  } catch {}
84105
84820
  return null;
84106
84821
  }
@@ -84186,8 +84901,8 @@ init_telemetry();
84186
84901
  // src/tools/batch-symbols.ts
84187
84902
  init_dist();
84188
84903
  init_create_tool();
84189
- import * as fs66 from "node:fs";
84190
- import * as path91 from "node:path";
84904
+ import * as fs68 from "node:fs";
84905
+ import * as path94 from "node:path";
84191
84906
  init_path_security();
84192
84907
  var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
84193
84908
  function containsWindowsAttacks2(str) {
@@ -84204,14 +84919,14 @@ function containsWindowsAttacks2(str) {
84204
84919
  }
84205
84920
  function isPathInWorkspace2(filePath, workspace) {
84206
84921
  try {
84207
- const resolvedPath = path91.resolve(workspace, filePath);
84208
- if (!fs66.existsSync(resolvedPath)) {
84922
+ const resolvedPath = path94.resolve(workspace, filePath);
84923
+ if (!fs68.existsSync(resolvedPath)) {
84209
84924
  return true;
84210
84925
  }
84211
- const realWorkspace = fs66.realpathSync(workspace);
84212
- const realResolvedPath = fs66.realpathSync(resolvedPath);
84213
- const relativePath = path91.relative(realWorkspace, realResolvedPath);
84214
- if (relativePath.startsWith("..") || path91.isAbsolute(relativePath)) {
84926
+ const realWorkspace = fs68.realpathSync(workspace);
84927
+ const realResolvedPath = fs68.realpathSync(resolvedPath);
84928
+ const relativePath = path94.relative(realWorkspace, realResolvedPath);
84929
+ if (relativePath.startsWith("..") || path94.isAbsolute(relativePath)) {
84215
84930
  return false;
84216
84931
  }
84217
84932
  return true;
@@ -84220,7 +84935,7 @@ function isPathInWorkspace2(filePath, workspace) {
84220
84935
  }
84221
84936
  }
84222
84937
  function processFile2(file3, cwd, exportedOnly) {
84223
- const ext = path91.extname(file3);
84938
+ const ext = path94.extname(file3);
84224
84939
  if (containsControlChars(file3)) {
84225
84940
  return {
84226
84941
  file: file3,
@@ -84253,8 +84968,8 @@ function processFile2(file3, cwd, exportedOnly) {
84253
84968
  errorType: "path-outside-workspace"
84254
84969
  };
84255
84970
  }
84256
- const fullPath = path91.join(cwd, file3);
84257
- if (!fs66.existsSync(fullPath)) {
84971
+ const fullPath = path94.join(cwd, file3);
84972
+ if (!fs68.existsSync(fullPath)) {
84258
84973
  return {
84259
84974
  file: file3,
84260
84975
  success: false,
@@ -84285,14 +85000,14 @@ function processFile2(file3, cwd, exportedOnly) {
84285
85000
  }
84286
85001
  let isEmptyFile = false;
84287
85002
  try {
84288
- const stats = fs66.statSync(fullPath);
85003
+ const stats = fs68.statSync(fullPath);
84289
85004
  if (stats.size === 0) {
84290
85005
  isEmptyFile = true;
84291
85006
  }
84292
85007
  } catch {}
84293
85008
  if (syms.length === 0) {
84294
85009
  try {
84295
- const content = fs66.readFileSync(fullPath, "utf-8");
85010
+ const content = fs68.readFileSync(fullPath, "utf-8");
84296
85011
  if (content.trim().length === 0) {
84297
85012
  isEmptyFile = true;
84298
85013
  }
@@ -84544,25 +85259,25 @@ init_manager2();
84544
85259
  init_task_id();
84545
85260
  init_create_tool();
84546
85261
  init_resolve_working_directory();
84547
- import * as fs67 from "node:fs";
84548
- import * as path92 from "node:path";
85262
+ import * as fs69 from "node:fs";
85263
+ import * as path95 from "node:path";
84549
85264
  var EVIDENCE_DIR = ".swarm/evidence";
84550
85265
  function isValidTaskId3(taskId) {
84551
85266
  return isStrictTaskId(taskId);
84552
85267
  }
84553
85268
  function isPathWithinSwarm(filePath, workspaceRoot) {
84554
- const normalizedWorkspace = path92.resolve(workspaceRoot);
84555
- const swarmPath = path92.join(normalizedWorkspace, ".swarm", "evidence");
84556
- const normalizedPath = path92.resolve(filePath);
85269
+ const normalizedWorkspace = path95.resolve(workspaceRoot);
85270
+ const swarmPath = path95.join(normalizedWorkspace, ".swarm", "evidence");
85271
+ const normalizedPath = path95.resolve(filePath);
84557
85272
  return normalizedPath.startsWith(swarmPath);
84558
85273
  }
84559
85274
  function readEvidenceFile(evidencePath) {
84560
- if (!fs67.existsSync(evidencePath)) {
85275
+ if (!fs69.existsSync(evidencePath)) {
84561
85276
  return null;
84562
85277
  }
84563
85278
  let content;
84564
85279
  try {
84565
- content = fs67.readFileSync(evidencePath, "utf-8");
85280
+ content = fs69.readFileSync(evidencePath, "utf-8");
84566
85281
  } catch {
84567
85282
  return null;
84568
85283
  }
@@ -84634,7 +85349,7 @@ var check_gate_status = createSwarmTool({
84634
85349
  };
84635
85350
  return JSON.stringify(errorResult, null, 2);
84636
85351
  }
84637
- const evidencePath = path92.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
85352
+ const evidencePath = path95.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
84638
85353
  if (!isPathWithinSwarm(evidencePath, directory)) {
84639
85354
  const errorResult = {
84640
85355
  taskId: taskIdInput,
@@ -84730,8 +85445,8 @@ init_utils2();
84730
85445
  init_state();
84731
85446
  init_create_tool();
84732
85447
  init_resolve_working_directory();
84733
- import * as fs68 from "node:fs";
84734
- import * as path93 from "node:path";
85448
+ import * as fs70 from "node:fs";
85449
+ import * as path96 from "node:path";
84735
85450
  function extractMatches(regex, text) {
84736
85451
  return Array.from(text.matchAll(regex));
84737
85452
  }
@@ -84825,7 +85540,7 @@ async function executeCompletionVerify(args2, directory) {
84825
85540
  let plan;
84826
85541
  try {
84827
85542
  const planPath = validateSwarmPath(directory, "plan.json");
84828
- const planRaw = fs68.readFileSync(planPath, "utf-8");
85543
+ const planRaw = fs70.readFileSync(planPath, "utf-8");
84829
85544
  plan = JSON.parse(planRaw);
84830
85545
  } catch {
84831
85546
  const result2 = {
@@ -84883,10 +85598,10 @@ async function executeCompletionVerify(args2, directory) {
84883
85598
  let hasFileReadFailure = false;
84884
85599
  for (const filePath of fileTargets) {
84885
85600
  const normalizedPath = filePath.replace(/\\/g, "/");
84886
- const resolvedPath = path93.resolve(directory, normalizedPath);
84887
- const projectRoot = path93.resolve(directory);
84888
- const relative20 = path93.relative(projectRoot, resolvedPath);
84889
- const withinProject = relative20 === "" || !relative20.startsWith("..") && !path93.isAbsolute(relative20);
85601
+ const resolvedPath = path96.resolve(directory, normalizedPath);
85602
+ const projectRoot = path96.resolve(directory);
85603
+ const relative20 = path96.relative(projectRoot, resolvedPath);
85604
+ const withinProject = relative20 === "" || !relative20.startsWith("..") && !path96.isAbsolute(relative20);
84890
85605
  if (!withinProject) {
84891
85606
  blockedTasks.push({
84892
85607
  task_id: task.id,
@@ -84899,7 +85614,7 @@ async function executeCompletionVerify(args2, directory) {
84899
85614
  }
84900
85615
  let fileContent;
84901
85616
  try {
84902
- fileContent = fs68.readFileSync(resolvedPath, "utf-8");
85617
+ fileContent = fs70.readFileSync(resolvedPath, "utf-8");
84903
85618
  } catch {
84904
85619
  blockedTasks.push({
84905
85620
  task_id: task.id,
@@ -84941,9 +85656,9 @@ async function executeCompletionVerify(args2, directory) {
84941
85656
  blockedTasks
84942
85657
  };
84943
85658
  try {
84944
- const evidenceDir = path93.join(directory, ".swarm", "evidence", `${phase}`);
84945
- const evidencePath = path93.join(evidenceDir, "completion-verify.json");
84946
- fs68.mkdirSync(evidenceDir, { recursive: true });
85659
+ const evidenceDir = path96.join(directory, ".swarm", "evidence", `${phase}`);
85660
+ const evidencePath = path96.join(evidenceDir, "completion-verify.json");
85661
+ fs70.mkdirSync(evidenceDir, { recursive: true });
84947
85662
  const evidenceBundle = {
84948
85663
  schema_version: "1.0.0",
84949
85664
  task_id: "completion-verify",
@@ -84964,7 +85679,7 @@ async function executeCompletionVerify(args2, directory) {
84964
85679
  }
84965
85680
  ]
84966
85681
  };
84967
- fs68.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
85682
+ fs70.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
84968
85683
  } catch {}
84969
85684
  return JSON.stringify(result, null, 2);
84970
85685
  }
@@ -85018,12 +85733,12 @@ var completion_verify = createSwarmTool({
85018
85733
  });
85019
85734
  // src/tools/complexity-hotspots.ts
85020
85735
  init_zod();
85021
- import * as fs70 from "node:fs";
85022
- import * as path95 from "node:path";
85736
+ import * as fs72 from "node:fs";
85737
+ import * as path98 from "node:path";
85023
85738
 
85024
85739
  // src/quality/metrics.ts
85025
- import * as fs69 from "node:fs";
85026
- import * as path94 from "node:path";
85740
+ import * as fs71 from "node:fs";
85741
+ import * as path97 from "node:path";
85027
85742
  var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
85028
85743
  var MIN_DUPLICATION_LINES = 10;
85029
85744
  function estimateCyclomaticComplexity(content) {
@@ -85061,11 +85776,11 @@ function estimateCyclomaticComplexity(content) {
85061
85776
  }
85062
85777
  function getComplexityForFile(filePath) {
85063
85778
  try {
85064
- const stat8 = fs69.statSync(filePath);
85779
+ const stat8 = fs71.statSync(filePath);
85065
85780
  if (stat8.size > MAX_FILE_SIZE_BYTES4) {
85066
85781
  return null;
85067
85782
  }
85068
- const content = fs69.readFileSync(filePath, "utf-8");
85783
+ const content = fs71.readFileSync(filePath, "utf-8");
85069
85784
  return estimateCyclomaticComplexity(content);
85070
85785
  } catch {
85071
85786
  return null;
@@ -85075,8 +85790,8 @@ async function computeComplexityDelta(files, workingDir) {
85075
85790
  let totalComplexity = 0;
85076
85791
  const analyzedFiles = [];
85077
85792
  for (const file3 of files) {
85078
- const fullPath = path94.isAbsolute(file3) ? file3 : path94.join(workingDir, file3);
85079
- if (!fs69.existsSync(fullPath)) {
85793
+ const fullPath = path97.isAbsolute(file3) ? file3 : path97.join(workingDir, file3);
85794
+ if (!fs71.existsSync(fullPath)) {
85080
85795
  continue;
85081
85796
  }
85082
85797
  const complexity = getComplexityForFile(fullPath);
@@ -85197,8 +85912,8 @@ function countGoExports(content) {
85197
85912
  }
85198
85913
  function getExportCountForFile(filePath) {
85199
85914
  try {
85200
- const content = fs69.readFileSync(filePath, "utf-8");
85201
- const ext = path94.extname(filePath).toLowerCase();
85915
+ const content = fs71.readFileSync(filePath, "utf-8");
85916
+ const ext = path97.extname(filePath).toLowerCase();
85202
85917
  switch (ext) {
85203
85918
  case ".ts":
85204
85919
  case ".tsx":
@@ -85224,8 +85939,8 @@ async function computePublicApiDelta(files, workingDir) {
85224
85939
  let totalExports = 0;
85225
85940
  const analyzedFiles = [];
85226
85941
  for (const file3 of files) {
85227
- const fullPath = path94.isAbsolute(file3) ? file3 : path94.join(workingDir, file3);
85228
- if (!fs69.existsSync(fullPath)) {
85942
+ const fullPath = path97.isAbsolute(file3) ? file3 : path97.join(workingDir, file3);
85943
+ if (!fs71.existsSync(fullPath)) {
85229
85944
  continue;
85230
85945
  }
85231
85946
  const exports = getExportCountForFile(fullPath);
@@ -85258,16 +85973,16 @@ async function computeDuplicationRatio(files, workingDir) {
85258
85973
  let duplicateLines = 0;
85259
85974
  const analyzedFiles = [];
85260
85975
  for (const file3 of files) {
85261
- const fullPath = path94.isAbsolute(file3) ? file3 : path94.join(workingDir, file3);
85262
- if (!fs69.existsSync(fullPath)) {
85976
+ const fullPath = path97.isAbsolute(file3) ? file3 : path97.join(workingDir, file3);
85977
+ if (!fs71.existsSync(fullPath)) {
85263
85978
  continue;
85264
85979
  }
85265
85980
  try {
85266
- const stat8 = fs69.statSync(fullPath);
85981
+ const stat8 = fs71.statSync(fullPath);
85267
85982
  if (stat8.size > MAX_FILE_SIZE_BYTES4) {
85268
85983
  continue;
85269
85984
  }
85270
- const content = fs69.readFileSync(fullPath, "utf-8");
85985
+ const content = fs71.readFileSync(fullPath, "utf-8");
85271
85986
  const lines = content.split(`
85272
85987
  `).filter((line) => line.trim().length > 0);
85273
85988
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -85291,8 +86006,8 @@ function countCodeLines(content) {
85291
86006
  return lines.length;
85292
86007
  }
85293
86008
  function isTestFile(filePath) {
85294
- const basename12 = path94.basename(filePath);
85295
- const _ext = path94.extname(filePath).toLowerCase();
86009
+ const basename13 = path97.basename(filePath);
86010
+ const _ext = path97.extname(filePath).toLowerCase();
85296
86011
  const testPatterns = [
85297
86012
  ".test.",
85298
86013
  ".spec.",
@@ -85307,7 +86022,7 @@ function isTestFile(filePath) {
85307
86022
  ".spec.jsx"
85308
86023
  ];
85309
86024
  for (const pattern of testPatterns) {
85310
- if (basename12.includes(pattern)) {
86025
+ if (basename13.includes(pattern)) {
85311
86026
  return true;
85312
86027
  }
85313
86028
  }
@@ -85373,8 +86088,8 @@ function matchGlobSegment(globSegments, pathSegments) {
85373
86088
  }
85374
86089
  return gIndex === globSegments.length && pIndex === pathSegments.length;
85375
86090
  }
85376
- function matchesGlobSegment(path95, glob) {
85377
- const normalizedPath = path95.replace(/\\/g, "/");
86091
+ function matchesGlobSegment(path98, glob) {
86092
+ const normalizedPath = path98.replace(/\\/g, "/");
85378
86093
  const normalizedGlob = glob.replace(/\\/g, "/");
85379
86094
  if (normalizedPath.includes("//")) {
85380
86095
  return false;
@@ -85405,8 +86120,8 @@ function simpleGlobToRegex2(glob) {
85405
86120
  function hasGlobstar(glob) {
85406
86121
  return glob.includes("**");
85407
86122
  }
85408
- function globMatches(path95, glob) {
85409
- const normalizedPath = path95.replace(/\\/g, "/");
86123
+ function globMatches(path98, glob) {
86124
+ const normalizedPath = path98.replace(/\\/g, "/");
85410
86125
  if (!glob || glob === "") {
85411
86126
  if (normalizedPath.includes("//")) {
85412
86127
  return false;
@@ -85442,31 +86157,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
85442
86157
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
85443
86158
  let testLines = 0;
85444
86159
  let codeLines = 0;
85445
- const srcDir = path94.join(workingDir, "src");
85446
- if (fs69.existsSync(srcDir)) {
86160
+ const srcDir = path97.join(workingDir, "src");
86161
+ if (fs71.existsSync(srcDir)) {
85447
86162
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
85448
86163
  codeLines += lines;
85449
86164
  });
85450
86165
  }
85451
86166
  const possibleSrcDirs = ["lib", "app", "source", "core"];
85452
86167
  for (const dir of possibleSrcDirs) {
85453
- const dirPath = path94.join(workingDir, dir);
85454
- if (fs69.existsSync(dirPath)) {
86168
+ const dirPath = path97.join(workingDir, dir);
86169
+ if (fs71.existsSync(dirPath)) {
85455
86170
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
85456
86171
  codeLines += lines;
85457
86172
  });
85458
86173
  }
85459
86174
  }
85460
- const testsDir = path94.join(workingDir, "tests");
85461
- if (fs69.existsSync(testsDir)) {
86175
+ const testsDir = path97.join(workingDir, "tests");
86176
+ if (fs71.existsSync(testsDir)) {
85462
86177
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
85463
86178
  testLines += lines;
85464
86179
  });
85465
86180
  }
85466
86181
  const possibleTestDirs = ["test", "__tests__", "specs"];
85467
86182
  for (const dir of possibleTestDirs) {
85468
- const dirPath = path94.join(workingDir, dir);
85469
- if (fs69.existsSync(dirPath) && dirPath !== testsDir) {
86183
+ const dirPath = path97.join(workingDir, dir);
86184
+ if (fs71.existsSync(dirPath) && dirPath !== testsDir) {
85470
86185
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
85471
86186
  testLines += lines;
85472
86187
  });
@@ -85478,9 +86193,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
85478
86193
  }
85479
86194
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
85480
86195
  try {
85481
- const entries = fs69.readdirSync(dirPath, { withFileTypes: true });
86196
+ const entries = fs71.readdirSync(dirPath, { withFileTypes: true });
85482
86197
  for (const entry of entries) {
85483
- const fullPath = path94.join(dirPath, entry.name);
86198
+ const fullPath = path97.join(dirPath, entry.name);
85484
86199
  if (entry.isDirectory()) {
85485
86200
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
85486
86201
  continue;
@@ -85488,7 +86203,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
85488
86203
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
85489
86204
  } else if (entry.isFile()) {
85490
86205
  const relativePath = fullPath.replace(`${dirPath}/`, "");
85491
- const ext = path94.extname(entry.name).toLowerCase();
86206
+ const ext = path97.extname(entry.name).toLowerCase();
85492
86207
  const validExts = [
85493
86208
  ".ts",
85494
86209
  ".tsx",
@@ -85524,7 +86239,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
85524
86239
  continue;
85525
86240
  }
85526
86241
  try {
85527
- const content = fs69.readFileSync(fullPath, "utf-8");
86242
+ const content = fs71.readFileSync(fullPath, "utf-8");
85528
86243
  const lines = countCodeLines(content);
85529
86244
  callback(lines);
85530
86245
  } catch {}
@@ -85724,11 +86439,11 @@ async function getGitChurn(days, directory) {
85724
86439
  }
85725
86440
  function getComplexityForFile2(filePath) {
85726
86441
  try {
85727
- const stat8 = fs70.statSync(filePath);
86442
+ const stat8 = fs72.statSync(filePath);
85728
86443
  if (stat8.size > MAX_FILE_SIZE_BYTES5) {
85729
86444
  return null;
85730
86445
  }
85731
- const content = fs70.readFileSync(filePath, "utf-8");
86446
+ const content = fs72.readFileSync(filePath, "utf-8");
85732
86447
  return estimateCyclomaticComplexity(content);
85733
86448
  } catch {
85734
86449
  return null;
@@ -85739,7 +86454,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
85739
86454
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
85740
86455
  const filteredChurn = new Map;
85741
86456
  for (const [file3, count] of churnMap) {
85742
- const ext = path95.extname(file3).toLowerCase();
86457
+ const ext = path98.extname(file3).toLowerCase();
85743
86458
  if (extSet.has(ext)) {
85744
86459
  filteredChurn.set(file3, count);
85745
86460
  }
@@ -85749,8 +86464,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
85749
86464
  let analyzedFiles = 0;
85750
86465
  for (const [file3, churnCount] of filteredChurn) {
85751
86466
  let fullPath = file3;
85752
- if (!fs70.existsSync(fullPath)) {
85753
- fullPath = path95.join(cwd, file3);
86467
+ if (!fs72.existsSync(fullPath)) {
86468
+ fullPath = path98.join(cwd, file3);
85754
86469
  }
85755
86470
  const complexity = getComplexityForFile2(fullPath);
85756
86471
  if (complexity !== null) {
@@ -85918,13 +86633,13 @@ ${body2}`);
85918
86633
 
85919
86634
  // src/council/council-evidence-writer.ts
85920
86635
  import {
85921
- appendFileSync as appendFileSync9,
85922
- existsSync as existsSync51,
85923
- mkdirSync as mkdirSync22,
85924
- readFileSync as readFileSync42,
85925
- writeFileSync as writeFileSync15
86636
+ appendFileSync as appendFileSync11,
86637
+ existsSync as existsSync53,
86638
+ mkdirSync as mkdirSync24,
86639
+ readFileSync as readFileSync43,
86640
+ writeFileSync as writeFileSync16
85926
86641
  } from "node:fs";
85927
- import { join as join81 } from "node:path";
86642
+ import { join as join83 } from "node:path";
85928
86643
  var EVIDENCE_DIR2 = ".swarm/evidence";
85929
86644
  var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
85930
86645
  var COUNCIL_GATE_NAME = "council";
@@ -85958,13 +86673,13 @@ function writeCouncilEvidence(workingDir, synthesis) {
85958
86673
  if (!VALID_TASK_ID.test(synthesis.taskId)) {
85959
86674
  throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
85960
86675
  }
85961
- const dir = join81(workingDir, EVIDENCE_DIR2);
85962
- mkdirSync22(dir, { recursive: true });
85963
- const filePath = join81(dir, `${synthesis.taskId}.json`);
86676
+ const dir = join83(workingDir, EVIDENCE_DIR2);
86677
+ mkdirSync24(dir, { recursive: true });
86678
+ const filePath = join83(dir, `${synthesis.taskId}.json`);
85964
86679
  const existingRoot = Object.create(null);
85965
- if (existsSync51(filePath)) {
86680
+ if (existsSync53(filePath)) {
85966
86681
  try {
85967
- const parsed = JSON.parse(readFileSync42(filePath, "utf-8"));
86682
+ const parsed = JSON.parse(readFileSync43(filePath, "utf-8"));
85968
86683
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
85969
86684
  safeAssignOwnProps(existingRoot, parsed);
85970
86685
  }
@@ -85992,17 +86707,17 @@ function writeCouncilEvidence(workingDir, synthesis) {
85992
86707
  updated.taskId = synthesis.taskId;
85993
86708
  if (!Array.isArray(updated.required_gates))
85994
86709
  updated.required_gates = [];
85995
- writeFileSync15(filePath, JSON.stringify(updated, null, 2));
86710
+ writeFileSync16(filePath, JSON.stringify(updated, null, 2));
85996
86711
  try {
85997
- const councilDir = join81(workingDir, ".swarm", "council");
85998
- mkdirSync22(councilDir, { recursive: true });
86712
+ const councilDir = join83(workingDir, ".swarm", "council");
86713
+ mkdirSync24(councilDir, { recursive: true });
85999
86714
  const auditLine = JSON.stringify({
86000
86715
  round: synthesis.roundNumber,
86001
86716
  verdict: synthesis.overallVerdict,
86002
86717
  timestamp: synthesis.timestamp,
86003
86718
  vetoedBy: synthesis.vetoedBy
86004
86719
  });
86005
- appendFileSync9(join81(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
86720
+ appendFileSync11(join83(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
86006
86721
  `);
86007
86722
  } catch (auditError) {
86008
86723
  console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
@@ -86324,25 +87039,25 @@ function buildFinalCouncilFeedback(projectSummary, verdict, vetoedBy, requiredFi
86324
87039
  }
86325
87040
 
86326
87041
  // src/council/criteria-store.ts
86327
- import { existsSync as existsSync52, mkdirSync as mkdirSync23, readFileSync as readFileSync43, writeFileSync as writeFileSync16 } from "node:fs";
86328
- import { join as join82 } from "node:path";
87042
+ import { existsSync as existsSync54, mkdirSync as mkdirSync25, readFileSync as readFileSync44, writeFileSync as writeFileSync17 } from "node:fs";
87043
+ import { join as join84 } from "node:path";
86329
87044
  var COUNCIL_DIR = ".swarm/council";
86330
87045
  function writeCriteria(workingDir, taskId, criteria) {
86331
- const dir = join82(workingDir, COUNCIL_DIR);
86332
- mkdirSync23(dir, { recursive: true });
87046
+ const dir = join84(workingDir, COUNCIL_DIR);
87047
+ mkdirSync25(dir, { recursive: true });
86333
87048
  const payload = {
86334
87049
  taskId,
86335
87050
  criteria,
86336
87051
  declaredAt: new Date().toISOString()
86337
87052
  };
86338
- writeFileSync16(join82(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
87053
+ writeFileSync17(join84(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
86339
87054
  }
86340
87055
  function readCriteria(workingDir, taskId) {
86341
- const filePath = join82(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
86342
- if (!existsSync52(filePath))
87056
+ const filePath = join84(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
87057
+ if (!existsSync54(filePath))
86343
87058
  return null;
86344
87059
  try {
86345
- const parsed = JSON.parse(readFileSync43(filePath, "utf-8"));
87060
+ const parsed = JSON.parse(readFileSync44(filePath, "utf-8"));
86346
87061
  if (parsed && typeof parsed === "object" && typeof parsed.taskId === "string" && Array.isArray(parsed.criteria)) {
86347
87062
  return parsed;
86348
87063
  }
@@ -86490,8 +87205,8 @@ var submit_council_verdicts = createSwarmTool({
86490
87205
  // src/tools/convene-general-council.ts
86491
87206
  init_zod();
86492
87207
  init_loader();
86493
- import * as fs71 from "node:fs";
86494
- import * as path96 from "node:path";
87208
+ import * as fs73 from "node:fs";
87209
+ import * as path99 from "node:path";
86495
87210
 
86496
87211
  // src/council/general-council-advisory.ts
86497
87212
  var ADVISORY_HEADER = "[general_council] (advisory; not blocking)";
@@ -86919,13 +87634,13 @@ var convene_general_council = createSwarmTool({
86919
87634
  const round1 = input.round1Responses;
86920
87635
  const round2 = input.round2Responses ?? [];
86921
87636
  const result = synthesizeGeneralCouncil(input.question, input.mode, round1, round2);
86922
- const evidenceDir = path96.join(workingDir, ".swarm", "council", "general");
87637
+ const evidenceDir = path99.join(workingDir, ".swarm", "council", "general");
86923
87638
  const safeTimestamp = result.timestamp.replace(/[:.]/g, "-");
86924
87639
  const evidenceFile = `${safeTimestamp}-${input.mode}.json`;
86925
- const evidencePath = path96.join(evidenceDir, evidenceFile);
87640
+ const evidencePath = path99.join(evidenceDir, evidenceFile);
86926
87641
  try {
86927
- await fs71.promises.mkdir(evidenceDir, { recursive: true });
86928
- await fs71.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
87642
+ await fs73.promises.mkdir(evidenceDir, { recursive: true });
87643
+ await fs73.promises.writeFile(evidencePath, JSON.stringify(result, null, 2));
86929
87644
  } catch (err2) {
86930
87645
  const message = err2 instanceof Error ? err2.message : String(err2);
86931
87646
  console.warn(`[convene_general_council] Failed to write evidence to ${evidencePath}: ${message}`);
@@ -87166,8 +87881,8 @@ init_scope_persistence();
87166
87881
  init_state();
87167
87882
  init_task_id();
87168
87883
  init_create_tool();
87169
- import * as fs72 from "node:fs";
87170
- import * as path97 from "node:path";
87884
+ import * as fs74 from "node:fs";
87885
+ import * as path100 from "node:path";
87171
87886
  function validateTaskIdFormat2(taskId) {
87172
87887
  return validateTaskIdFormat(taskId);
87173
87888
  }
@@ -87241,8 +87956,8 @@ async function executeDeclareScope(args2, fallbackDir) {
87241
87956
  };
87242
87957
  }
87243
87958
  }
87244
- normalizedDir = path97.normalize(args2.working_directory);
87245
- const pathParts = normalizedDir.split(path97.sep);
87959
+ normalizedDir = path100.normalize(args2.working_directory);
87960
+ const pathParts = normalizedDir.split(path100.sep);
87246
87961
  if (pathParts.includes("..")) {
87247
87962
  return {
87248
87963
  success: false,
@@ -87252,11 +87967,11 @@ async function executeDeclareScope(args2, fallbackDir) {
87252
87967
  ]
87253
87968
  };
87254
87969
  }
87255
- const resolvedDir = path97.resolve(normalizedDir);
87970
+ const resolvedDir = path100.resolve(normalizedDir);
87256
87971
  try {
87257
- const realPath = fs72.realpathSync(resolvedDir);
87258
- const planPath2 = path97.join(realPath, ".swarm", "plan.json");
87259
- if (!fs72.existsSync(planPath2)) {
87972
+ const realPath = fs74.realpathSync(resolvedDir);
87973
+ const planPath2 = path100.join(realPath, ".swarm", "plan.json");
87974
+ if (!fs74.existsSync(planPath2)) {
87260
87975
  return {
87261
87976
  success: false,
87262
87977
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -87279,8 +87994,8 @@ async function executeDeclareScope(args2, fallbackDir) {
87279
87994
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
87280
87995
  }
87281
87996
  const directory = normalizedDir || fallbackDir;
87282
- const planPath = path97.resolve(directory, ".swarm", "plan.json");
87283
- if (!fs72.existsSync(planPath)) {
87997
+ const planPath = path100.resolve(directory, ".swarm", "plan.json");
87998
+ if (!fs74.existsSync(planPath)) {
87284
87999
  return {
87285
88000
  success: false,
87286
88001
  message: "No plan found",
@@ -87289,7 +88004,7 @@ async function executeDeclareScope(args2, fallbackDir) {
87289
88004
  }
87290
88005
  let planContent;
87291
88006
  try {
87292
- planContent = JSON.parse(fs72.readFileSync(planPath, "utf-8"));
88007
+ planContent = JSON.parse(fs74.readFileSync(planPath, "utf-8"));
87293
88008
  } catch {
87294
88009
  return {
87295
88010
  success: false,
@@ -87319,8 +88034,8 @@ async function executeDeclareScope(args2, fallbackDir) {
87319
88034
  const normalizeErrors = [];
87320
88035
  const dir = normalizedDir || fallbackDir || process.cwd();
87321
88036
  const mergedFiles = rawMergedFiles.map((file3) => {
87322
- if (path97.isAbsolute(file3)) {
87323
- const relativePath = path97.relative(dir, file3).replace(/\\/g, "/");
88037
+ if (path100.isAbsolute(file3)) {
88038
+ const relativePath = path100.relative(dir, file3).replace(/\\/g, "/");
87324
88039
  if (relativePath.startsWith("..")) {
87325
88040
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
87326
88041
  return file3;
@@ -87380,8 +88095,8 @@ var declare_scope = createSwarmTool({
87380
88095
  // src/tools/diff.ts
87381
88096
  init_zod();
87382
88097
  import * as child_process7 from "node:child_process";
87383
- import * as fs73 from "node:fs";
87384
- import * as path98 from "node:path";
88098
+ import * as fs75 from "node:fs";
88099
+ import * as path101 from "node:path";
87385
88100
  init_create_tool();
87386
88101
  var MAX_DIFF_LINES = 500;
87387
88102
  var DIFF_TIMEOUT_MS = 30000;
@@ -87410,20 +88125,20 @@ function validateBase(base) {
87410
88125
  function validatePaths(paths) {
87411
88126
  if (!paths)
87412
88127
  return null;
87413
- for (const path99 of paths) {
87414
- if (!path99 || path99.length === 0) {
88128
+ for (const path102 of paths) {
88129
+ if (!path102 || path102.length === 0) {
87415
88130
  return "empty path not allowed";
87416
88131
  }
87417
- if (path99.length > MAX_PATH_LENGTH) {
88132
+ if (path102.length > MAX_PATH_LENGTH) {
87418
88133
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
87419
88134
  }
87420
- if (SHELL_METACHARACTERS2.test(path99)) {
88135
+ if (SHELL_METACHARACTERS2.test(path102)) {
87421
88136
  return "path contains shell metacharacters";
87422
88137
  }
87423
- if (path99.startsWith("-")) {
88138
+ if (path102.startsWith("-")) {
87424
88139
  return 'path cannot start with "-" (option-like arguments not allowed)';
87425
88140
  }
87426
- if (CONTROL_CHAR_PATTERN2.test(path99)) {
88141
+ if (CONTROL_CHAR_PATTERN2.test(path102)) {
87427
88142
  return "path contains control characters";
87428
88143
  }
87429
88144
  }
@@ -87531,8 +88246,8 @@ var diff = createSwarmTool({
87531
88246
  if (parts2.length >= 3) {
87532
88247
  const additions = parseInt(parts2[0], 10) || 0;
87533
88248
  const deletions = parseInt(parts2[1], 10) || 0;
87534
- const path99 = parts2[2];
87535
- files.push({ path: path99, additions, deletions });
88249
+ const path102 = parts2[2];
88250
+ files.push({ path: path102, additions, deletions });
87536
88251
  }
87537
88252
  }
87538
88253
  const contractChanges = [];
@@ -87572,7 +88287,7 @@ var diff = createSwarmTool({
87572
88287
  } else if (base === "unstaged") {
87573
88288
  const oldRef = `:${file3.path}`;
87574
88289
  oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
87575
- newContent = fs73.readFileSync(path98.join(directory, file3.path), "utf-8");
88290
+ newContent = fs75.readFileSync(path101.join(directory, file3.path), "utf-8");
87576
88291
  } else {
87577
88292
  const oldRef = `${base}:${file3.path}`;
87578
88293
  oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
@@ -87646,8 +88361,8 @@ var diff = createSwarmTool({
87646
88361
  // src/tools/diff-summary.ts
87647
88362
  init_zod();
87648
88363
  import * as child_process8 from "node:child_process";
87649
- import * as fs74 from "node:fs";
87650
- import * as path99 from "node:path";
88364
+ import * as fs76 from "node:fs";
88365
+ import * as path102 from "node:path";
87651
88366
  init_create_tool();
87652
88367
  var diff_summary = createSwarmTool({
87653
88368
  description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
@@ -87695,7 +88410,7 @@ var diff_summary = createSwarmTool({
87695
88410
  }
87696
88411
  try {
87697
88412
  let oldContent;
87698
- const newContent = fs74.readFileSync(path99.join(workingDir, filePath), "utf-8");
88413
+ const newContent = fs76.readFileSync(path102.join(workingDir, filePath), "utf-8");
87699
88414
  if (fileExistsInHead) {
87700
88415
  oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
87701
88416
  encoding: "utf-8",
@@ -87923,8 +88638,8 @@ Use these as DOMAIN values when delegating to @sme.`;
87923
88638
  init_zod();
87924
88639
  init_create_tool();
87925
88640
  init_path_security();
87926
- import * as fs75 from "node:fs";
87927
- import * as path100 from "node:path";
88641
+ import * as fs77 from "node:fs";
88642
+ import * as path103 from "node:path";
87928
88643
  var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
87929
88644
  var MAX_EVIDENCE_FILES = 1000;
87930
88645
  var EVIDENCE_DIR3 = ".swarm/evidence";
@@ -87951,9 +88666,9 @@ function validateRequiredTypes(input) {
87951
88666
  return null;
87952
88667
  }
87953
88668
  function isPathWithinSwarm2(filePath, cwd) {
87954
- const normalizedCwd = path100.resolve(cwd);
87955
- const swarmPath = path100.join(normalizedCwd, ".swarm");
87956
- const normalizedPath = path100.resolve(filePath);
88669
+ const normalizedCwd = path103.resolve(cwd);
88670
+ const swarmPath = path103.join(normalizedCwd, ".swarm");
88671
+ const normalizedPath = path103.resolve(filePath);
87957
88672
  return normalizedPath.startsWith(swarmPath);
87958
88673
  }
87959
88674
  function parseCompletedTasks(planContent) {
@@ -87969,12 +88684,12 @@ function parseCompletedTasks(planContent) {
87969
88684
  }
87970
88685
  function readEvidenceFiles(evidenceDir, _cwd) {
87971
88686
  const evidence = [];
87972
- if (!fs75.existsSync(evidenceDir) || !fs75.statSync(evidenceDir).isDirectory()) {
88687
+ if (!fs77.existsSync(evidenceDir) || !fs77.statSync(evidenceDir).isDirectory()) {
87973
88688
  return evidence;
87974
88689
  }
87975
88690
  let files;
87976
88691
  try {
87977
- files = fs75.readdirSync(evidenceDir);
88692
+ files = fs77.readdirSync(evidenceDir);
87978
88693
  } catch {
87979
88694
  return evidence;
87980
88695
  }
@@ -87983,14 +88698,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
87983
88698
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
87984
88699
  continue;
87985
88700
  }
87986
- const filePath = path100.join(evidenceDir, filename);
88701
+ const filePath = path103.join(evidenceDir, filename);
87987
88702
  try {
87988
- const resolvedPath = path100.resolve(filePath);
87989
- const evidenceDirResolved = path100.resolve(evidenceDir);
88703
+ const resolvedPath = path103.resolve(filePath);
88704
+ const evidenceDirResolved = path103.resolve(evidenceDir);
87990
88705
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
87991
88706
  continue;
87992
88707
  }
87993
- const stat8 = fs75.lstatSync(filePath);
88708
+ const stat8 = fs77.lstatSync(filePath);
87994
88709
  if (!stat8.isFile()) {
87995
88710
  continue;
87996
88711
  }
@@ -87999,7 +88714,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
87999
88714
  }
88000
88715
  let fileStat;
88001
88716
  try {
88002
- fileStat = fs75.statSync(filePath);
88717
+ fileStat = fs77.statSync(filePath);
88003
88718
  if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
88004
88719
  continue;
88005
88720
  }
@@ -88008,7 +88723,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
88008
88723
  }
88009
88724
  let content;
88010
88725
  try {
88011
- content = fs75.readFileSync(filePath, "utf-8");
88726
+ content = fs77.readFileSync(filePath, "utf-8");
88012
88727
  } catch {
88013
88728
  continue;
88014
88729
  }
@@ -88104,7 +88819,7 @@ var evidence_check = createSwarmTool({
88104
88819
  return JSON.stringify(errorResult, null, 2);
88105
88820
  }
88106
88821
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
88107
- const planPath = path100.join(cwd, PLAN_FILE);
88822
+ const planPath = path103.join(cwd, PLAN_FILE);
88108
88823
  if (!isPathWithinSwarm2(planPath, cwd)) {
88109
88824
  const errorResult = {
88110
88825
  error: "plan file path validation failed",
@@ -88118,7 +88833,7 @@ var evidence_check = createSwarmTool({
88118
88833
  }
88119
88834
  let planContent;
88120
88835
  try {
88121
- planContent = fs75.readFileSync(planPath, "utf-8");
88836
+ planContent = fs77.readFileSync(planPath, "utf-8");
88122
88837
  } catch {
88123
88838
  const result2 = {
88124
88839
  message: "No completed tasks found in plan.",
@@ -88136,7 +88851,7 @@ var evidence_check = createSwarmTool({
88136
88851
  };
88137
88852
  return JSON.stringify(result2, null, 2);
88138
88853
  }
88139
- const evidenceDir = path100.join(cwd, EVIDENCE_DIR3);
88854
+ const evidenceDir = path103.join(cwd, EVIDENCE_DIR3);
88140
88855
  const evidence = readEvidenceFiles(evidenceDir, cwd);
88141
88856
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
88142
88857
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -88153,8 +88868,8 @@ var evidence_check = createSwarmTool({
88153
88868
  // src/tools/file-extractor.ts
88154
88869
  init_zod();
88155
88870
  init_create_tool();
88156
- import * as fs76 from "node:fs";
88157
- import * as path101 from "node:path";
88871
+ import * as fs78 from "node:fs";
88872
+ import * as path104 from "node:path";
88158
88873
  var EXT_MAP = {
88159
88874
  python: ".py",
88160
88875
  py: ".py",
@@ -88216,8 +88931,8 @@ var extract_code_blocks = createSwarmTool({
88216
88931
  execute: async (args2, directory) => {
88217
88932
  const { content, output_dir, prefix } = args2;
88218
88933
  const targetDir = output_dir || directory;
88219
- if (!fs76.existsSync(targetDir)) {
88220
- fs76.mkdirSync(targetDir, { recursive: true });
88934
+ if (!fs78.existsSync(targetDir)) {
88935
+ fs78.mkdirSync(targetDir, { recursive: true });
88221
88936
  }
88222
88937
  if (!content) {
88223
88938
  return "Error: content is required";
@@ -88235,16 +88950,16 @@ var extract_code_blocks = createSwarmTool({
88235
88950
  if (prefix) {
88236
88951
  filename = `${prefix}_${filename}`;
88237
88952
  }
88238
- let filepath = path101.join(targetDir, filename);
88239
- const base = path101.basename(filepath, path101.extname(filepath));
88240
- const ext = path101.extname(filepath);
88953
+ let filepath = path104.join(targetDir, filename);
88954
+ const base = path104.basename(filepath, path104.extname(filepath));
88955
+ const ext = path104.extname(filepath);
88241
88956
  let counter = 1;
88242
- while (fs76.existsSync(filepath)) {
88243
- filepath = path101.join(targetDir, `${base}_${counter}${ext}`);
88957
+ while (fs78.existsSync(filepath)) {
88958
+ filepath = path104.join(targetDir, `${base}_${counter}${ext}`);
88244
88959
  counter++;
88245
88960
  }
88246
88961
  try {
88247
- fs76.writeFileSync(filepath, code.trim(), "utf-8");
88962
+ fs78.writeFileSync(filepath, code.trim(), "utf-8");
88248
88963
  savedFiles.push(filepath);
88249
88964
  } catch (error93) {
88250
88965
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -88497,8 +89212,8 @@ var gitingest = createSwarmTool({
88497
89212
  init_zod();
88498
89213
  init_create_tool();
88499
89214
  init_path_security();
88500
- import * as fs77 from "node:fs";
88501
- import * as path102 from "node:path";
89215
+ import * as fs79 from "node:fs";
89216
+ import * as path105 from "node:path";
88502
89217
  var MAX_FILE_PATH_LENGTH2 = 500;
88503
89218
  var MAX_SYMBOL_LENGTH = 256;
88504
89219
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
@@ -88546,7 +89261,7 @@ function validateSymbolInput(symbol3) {
88546
89261
  return null;
88547
89262
  }
88548
89263
  function isBinaryFile2(filePath, buffer) {
88549
- const ext = path102.extname(filePath).toLowerCase();
89264
+ const ext = path105.extname(filePath).toLowerCase();
88550
89265
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
88551
89266
  return false;
88552
89267
  }
@@ -88570,15 +89285,15 @@ function parseImports(content, targetFile, targetSymbol) {
88570
89285
  const imports = [];
88571
89286
  let _resolvedTarget;
88572
89287
  try {
88573
- _resolvedTarget = path102.resolve(targetFile);
89288
+ _resolvedTarget = path105.resolve(targetFile);
88574
89289
  } catch {
88575
89290
  _resolvedTarget = targetFile;
88576
89291
  }
88577
- const targetBasename = path102.basename(targetFile, path102.extname(targetFile));
89292
+ const targetBasename = path105.basename(targetFile, path105.extname(targetFile));
88578
89293
  const targetWithExt = targetFile;
88579
89294
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
88580
- const normalizedTargetWithExt = path102.normalize(targetWithExt).replace(/\\/g, "/");
88581
- const normalizedTargetWithoutExt = path102.normalize(targetWithoutExt).replace(/\\/g, "/");
89295
+ const normalizedTargetWithExt = path105.normalize(targetWithExt).replace(/\\/g, "/");
89296
+ const normalizedTargetWithoutExt = path105.normalize(targetWithoutExt).replace(/\\/g, "/");
88582
89297
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
88583
89298
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
88584
89299
  const modulePath = match[1] || match[2] || match[3];
@@ -88601,9 +89316,9 @@ function parseImports(content, targetFile, targetSymbol) {
88601
89316
  }
88602
89317
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
88603
89318
  let isMatch = false;
88604
- const _targetDir = path102.dirname(targetFile);
88605
- const targetExt = path102.extname(targetFile);
88606
- const targetBasenameNoExt = path102.basename(targetFile, targetExt);
89319
+ const _targetDir = path105.dirname(targetFile);
89320
+ const targetExt = path105.extname(targetFile);
89321
+ const targetBasenameNoExt = path105.basename(targetFile, targetExt);
88607
89322
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
88608
89323
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
88609
89324
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -88660,7 +89375,7 @@ var SKIP_DIRECTORIES4 = new Set([
88660
89375
  function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
88661
89376
  let entries;
88662
89377
  try {
88663
- entries = fs77.readdirSync(dir);
89378
+ entries = fs79.readdirSync(dir);
88664
89379
  } catch (e) {
88665
89380
  stats.fileErrors.push({
88666
89381
  path: dir,
@@ -88671,13 +89386,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
88671
89386
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
88672
89387
  for (const entry of entries) {
88673
89388
  if (SKIP_DIRECTORIES4.has(entry)) {
88674
- stats.skippedDirs.push(path102.join(dir, entry));
89389
+ stats.skippedDirs.push(path105.join(dir, entry));
88675
89390
  continue;
88676
89391
  }
88677
- const fullPath = path102.join(dir, entry);
89392
+ const fullPath = path105.join(dir, entry);
88678
89393
  let stat8;
88679
89394
  try {
88680
- stat8 = fs77.statSync(fullPath);
89395
+ stat8 = fs79.statSync(fullPath);
88681
89396
  } catch (e) {
88682
89397
  stats.fileErrors.push({
88683
89398
  path: fullPath,
@@ -88688,7 +89403,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
88688
89403
  if (stat8.isDirectory()) {
88689
89404
  findSourceFiles2(fullPath, files, stats);
88690
89405
  } else if (stat8.isFile()) {
88691
- const ext = path102.extname(fullPath).toLowerCase();
89406
+ const ext = path105.extname(fullPath).toLowerCase();
88692
89407
  if (SUPPORTED_EXTENSIONS3.includes(ext)) {
88693
89408
  files.push(fullPath);
88694
89409
  }
@@ -88745,8 +89460,8 @@ var imports = createSwarmTool({
88745
89460
  return JSON.stringify(errorResult, null, 2);
88746
89461
  }
88747
89462
  try {
88748
- const targetFile = path102.resolve(file3);
88749
- if (!fs77.existsSync(targetFile)) {
89463
+ const targetFile = path105.resolve(file3);
89464
+ if (!fs79.existsSync(targetFile)) {
88750
89465
  const errorResult = {
88751
89466
  error: `target file not found: ${file3}`,
88752
89467
  target: file3,
@@ -88756,7 +89471,7 @@ var imports = createSwarmTool({
88756
89471
  };
88757
89472
  return JSON.stringify(errorResult, null, 2);
88758
89473
  }
88759
- const targetStat = fs77.statSync(targetFile);
89474
+ const targetStat = fs79.statSync(targetFile);
88760
89475
  if (!targetStat.isFile()) {
88761
89476
  const errorResult = {
88762
89477
  error: "target must be a file, not a directory",
@@ -88767,7 +89482,7 @@ var imports = createSwarmTool({
88767
89482
  };
88768
89483
  return JSON.stringify(errorResult, null, 2);
88769
89484
  }
88770
- const baseDir = path102.dirname(targetFile);
89485
+ const baseDir = path105.dirname(targetFile);
88771
89486
  const scanStats = {
88772
89487
  skippedDirs: [],
88773
89488
  skippedFiles: 0,
@@ -88782,12 +89497,12 @@ var imports = createSwarmTool({
88782
89497
  if (consumers.length >= MAX_CONSUMERS)
88783
89498
  break;
88784
89499
  try {
88785
- const stat8 = fs77.statSync(filePath);
89500
+ const stat8 = fs79.statSync(filePath);
88786
89501
  if (stat8.size > MAX_FILE_SIZE_BYTES7) {
88787
89502
  skippedFileCount++;
88788
89503
  continue;
88789
89504
  }
88790
- const buffer = fs77.readFileSync(filePath);
89505
+ const buffer = fs79.readFileSync(filePath);
88791
89506
  if (isBinaryFile2(filePath, buffer)) {
88792
89507
  skippedFileCount++;
88793
89508
  continue;
@@ -88852,7 +89567,7 @@ var imports = createSwarmTool({
88852
89567
  });
88853
89568
  // src/tools/knowledge-ack.ts
88854
89569
  init_zod();
88855
- import { randomUUID as randomUUID7 } from "node:crypto";
89570
+ import { randomUUID as randomUUID8 } from "node:crypto";
88856
89571
  init_state();
88857
89572
  init_logger();
88858
89573
  init_create_tool();
@@ -88885,7 +89600,7 @@ var knowledge_ack = createSwarmTool({
88885
89600
  let sessionId = ctx?.sessionID;
88886
89601
  if (!sessionId) {
88887
89602
  warn("[knowledge-ack] No sessionID in tool context — dedup disabled for this acknowledgment");
88888
- sessionId = randomUUID7();
89603
+ sessionId = randomUUID8();
88889
89604
  }
88890
89605
  const dedupKey = buildAckDedupKey(sessionId, a.id, a.result);
88891
89606
  if (swarmState.knowledgeAckDedup.has(dedupKey)) {
@@ -88915,7 +89630,7 @@ init_knowledge_store();
88915
89630
  init_knowledge_validator();
88916
89631
  init_manager();
88917
89632
  init_create_tool();
88918
- import { randomUUID as randomUUID8 } from "node:crypto";
89633
+ import { randomUUID as randomUUID9 } from "node:crypto";
88919
89634
  var VALID_CATEGORIES2 = [
88920
89635
  "process",
88921
89636
  "architecture",
@@ -88989,7 +89704,7 @@ var knowledge_add = createSwarmTool({
88989
89704
  project_name = plan?.title ?? "";
88990
89705
  } catch {}
88991
89706
  const entry = {
88992
- id: randomUUID8(),
89707
+ id: randomUUID9(),
88993
89708
  tier: "swarm",
88994
89709
  lesson,
88995
89710
  category,
@@ -89058,7 +89773,7 @@ init_zod();
89058
89773
  init_config();
89059
89774
  init_knowledge_store();
89060
89775
  init_create_tool();
89061
- import { existsSync as existsSync57 } from "node:fs";
89776
+ import { existsSync as existsSync59 } from "node:fs";
89062
89777
  var DEFAULT_LIMIT = 10;
89063
89778
  var MAX_LESSON_LENGTH = 200;
89064
89779
  var VALID_CATEGORIES3 = [
@@ -89128,14 +89843,14 @@ function validateLimit(limit) {
89128
89843
  }
89129
89844
  async function readSwarmKnowledge(directory) {
89130
89845
  const swarmPath = resolveSwarmKnowledgePath(directory);
89131
- if (!existsSync57(swarmPath)) {
89846
+ if (!existsSync59(swarmPath)) {
89132
89847
  return [];
89133
89848
  }
89134
89849
  return readKnowledge(swarmPath);
89135
89850
  }
89136
89851
  async function readHiveKnowledge() {
89137
89852
  const hivePath = resolveHiveKnowledgePath();
89138
- if (!existsSync57(hivePath)) {
89853
+ if (!existsSync59(hivePath)) {
89139
89854
  return [];
89140
89855
  }
89141
89856
  return readKnowledge(hivePath);
@@ -89369,30 +90084,30 @@ init_config();
89369
90084
  init_schema();
89370
90085
  init_qa_gate_profile();
89371
90086
  init_manager2();
89372
- import * as fs82 from "node:fs";
89373
- import * as path107 from "node:path";
90087
+ import * as fs84 from "node:fs";
90088
+ import * as path110 from "node:path";
89374
90089
 
89375
90090
  // src/full-auto/phase-approval.ts
89376
90091
  init_utils2();
89377
90092
  init_logger();
89378
90093
  init_state2();
89379
- import * as fs78 from "node:fs";
89380
- import * as path103 from "node:path";
90094
+ import * as fs80 from "node:fs";
90095
+ import * as path106 from "node:path";
89381
90096
  var APPROVAL_TTL_MS = 24 * 60 * 60 * 1000;
89382
90097
  function readEvidenceDir(directory, phase) {
89383
90098
  try {
89384
- const dirPath = validateSwarmPath(directory, path103.posix.join("evidence", String(phase)));
89385
- if (!fs78.existsSync(dirPath))
90099
+ const dirPath = validateSwarmPath(directory, path106.posix.join("evidence", String(phase)));
90100
+ if (!fs80.existsSync(dirPath))
89386
90101
  return [];
89387
- const entries = fs78.readdirSync(dirPath);
89388
- return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path103.join(dirPath, e));
90102
+ const entries = fs80.readdirSync(dirPath);
90103
+ return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path106.join(dirPath, e));
89389
90104
  } catch {
89390
90105
  return [];
89391
90106
  }
89392
90107
  }
89393
90108
  function parseEvidence(filePath) {
89394
90109
  try {
89395
- const raw = fs78.readFileSync(filePath, "utf-8");
90110
+ const raw = fs80.readFileSync(filePath, "utf-8");
89396
90111
  const parsed = JSON.parse(raw);
89397
90112
  return parsed;
89398
90113
  } catch (error93) {
@@ -89481,9 +90196,9 @@ function verifyFullAutoPhaseApproval(directory, sessionID, phase, config3) {
89481
90196
  function phaseIsExplicitlyNonCode(directory, phase) {
89482
90197
  try {
89483
90198
  const planPath = validateSwarmPath(directory, "plan.json");
89484
- if (!fs78.existsSync(planPath))
90199
+ if (!fs80.existsSync(planPath))
89485
90200
  return false;
89486
- const raw = fs78.readFileSync(planPath, "utf-8");
90201
+ const raw = fs80.readFileSync(planPath, "utf-8");
89487
90202
  const plan = JSON.parse(raw);
89488
90203
  const phases = Array.isArray(plan.phases) ? plan.phases : [];
89489
90204
  const entry = phases.find((p) => p.id === phase || p.phase === phase);
@@ -89511,6 +90226,7 @@ function phaseIsExplicitlyNonCode(directory, phase) {
89511
90226
  }
89512
90227
 
89513
90228
  // src/tools/phase-complete.ts
90229
+ init_gate_evidence();
89514
90230
  init_curator();
89515
90231
  init_knowledge_curator();
89516
90232
  init_knowledge_reader();
@@ -89523,20 +90239,20 @@ init_file_locks();
89523
90239
  init_plan_schema();
89524
90240
  init_ledger();
89525
90241
  init_manager();
89526
- import * as fs79 from "node:fs";
89527
- import * as path104 from "node:path";
90242
+ import * as fs81 from "node:fs";
90243
+ import * as path107 from "node:path";
89528
90244
  async function writeCheckpoint(directory) {
89529
90245
  try {
89530
90246
  const plan = await loadPlan(directory);
89531
90247
  if (!plan)
89532
90248
  return;
89533
- const swarmDir = path104.join(directory, ".swarm");
89534
- fs79.mkdirSync(swarmDir, { recursive: true });
89535
- const jsonPath = path104.join(swarmDir, "SWARM_PLAN.json");
89536
- const mdPath = path104.join(swarmDir, "SWARM_PLAN.md");
89537
- fs79.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
90249
+ const swarmDir = path107.join(directory, ".swarm");
90250
+ fs81.mkdirSync(swarmDir, { recursive: true });
90251
+ const jsonPath = path107.join(swarmDir, "SWARM_PLAN.json");
90252
+ const mdPath = path107.join(swarmDir, "SWARM_PLAN.md");
90253
+ fs81.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
89538
90254
  const md = derivePlanMarkdown(plan);
89539
- fs79.writeFileSync(mdPath, md, "utf8");
90255
+ fs81.writeFileSync(mdPath, md, "utf8");
89540
90256
  } catch (error93) {
89541
90257
  console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
89542
90258
  }
@@ -89551,16 +90267,16 @@ init_telemetry();
89551
90267
 
89552
90268
  // src/turbo/lean/phase-ready.ts
89553
90269
  init_file_locks();
89554
- import * as fs81 from "node:fs";
89555
- import * as path106 from "node:path";
90270
+ import * as fs83 from "node:fs";
90271
+ import * as path109 from "node:path";
89556
90272
 
89557
90273
  // src/turbo/lean/evidence.ts
89558
90274
  init_bun_compat();
89559
90275
  import { rmSync as rmSync5 } from "node:fs";
89560
- import * as fs80 from "node:fs/promises";
89561
- import * as path105 from "node:path";
90276
+ import * as fs82 from "node:fs/promises";
90277
+ import * as path108 from "node:path";
89562
90278
  function leanTurboEvidenceDir(directory, phase) {
89563
- return path105.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
90279
+ return path108.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
89564
90280
  }
89565
90281
  function validateLaneId(laneId) {
89566
90282
  if (laneId.length === 0) {
@@ -89582,21 +90298,21 @@ function validateLaneId(laneId) {
89582
90298
  function laneEvidencePath(directory, phase, laneId) {
89583
90299
  validateLaneId(laneId);
89584
90300
  const expectedDir = leanTurboEvidenceDir(directory, phase);
89585
- const resolvedPath = path105.resolve(path105.join(expectedDir, `${laneId}.json`));
89586
- const resolvedDir = path105.resolve(expectedDir);
89587
- if (!resolvedPath.startsWith(resolvedDir + path105.sep) && resolvedPath !== resolvedDir) {
90301
+ const resolvedPath = path108.resolve(path108.join(expectedDir, `${laneId}.json`));
90302
+ const resolvedDir = path108.resolve(expectedDir);
90303
+ if (!resolvedPath.startsWith(resolvedDir + path108.sep) && resolvedPath !== resolvedDir) {
89588
90304
  throw new Error(`Invalid laneId: path traversal detected (got "${laneId}")`);
89589
90305
  }
89590
90306
  return resolvedPath;
89591
90307
  }
89592
90308
  async function atomicWriteJson(filePath, data) {
89593
90309
  const content = JSON.stringify(data, null, 2);
89594
- const dir = path105.dirname(filePath);
89595
- await fs80.mkdir(dir, { recursive: true });
90310
+ const dir = path108.dirname(filePath);
90311
+ await fs82.mkdir(dir, { recursive: true });
89596
90312
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
89597
90313
  try {
89598
90314
  await bunWrite(tempPath, content);
89599
- await fs80.rename(tempPath, filePath);
90315
+ await fs82.rename(tempPath, filePath);
89600
90316
  } catch (error93) {
89601
90317
  try {
89602
90318
  rmSync5(tempPath, { force: true });
@@ -89605,7 +90321,7 @@ async function atomicWriteJson(filePath, data) {
89605
90321
  }
89606
90322
  }
89607
90323
  function phaseEvidencePath(directory, phase) {
89608
- return path105.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
90324
+ return path108.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
89609
90325
  }
89610
90326
  async function writeLaneEvidence(directory, phase, evidence) {
89611
90327
  const targetPath = laneEvidencePath(directory, phase, evidence.laneId);
@@ -89615,7 +90331,7 @@ async function readPhaseEvidence(directory, phase) {
89615
90331
  const targetPath = phaseEvidencePath(directory, phase);
89616
90332
  let content;
89617
90333
  try {
89618
- content = await fs80.readFile(targetPath, "utf-8");
90334
+ content = await fs82.readFile(targetPath, "utf-8");
89619
90335
  } catch (error93) {
89620
90336
  const code = error93.code;
89621
90337
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -89633,7 +90349,7 @@ async function listLaneEvidence(directory, phase) {
89633
90349
  const evidenceDir = leanTurboEvidenceDir(directory, phase);
89634
90350
  let entries;
89635
90351
  try {
89636
- entries = await fs80.readdir(evidenceDir);
90352
+ entries = await fs82.readdir(evidenceDir);
89637
90353
  } catch (error93) {
89638
90354
  const code = error93.code;
89639
90355
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -89649,10 +90365,10 @@ async function listLaneEvidence(directory, phase) {
89649
90365
  if (entry === "lean-turbo-phase.json") {
89650
90366
  continue;
89651
90367
  }
89652
- const filePath = path105.join(evidenceDir, entry);
90368
+ const filePath = path108.join(evidenceDir, entry);
89653
90369
  let content;
89654
90370
  try {
89655
- content = await fs80.readFile(filePath, "utf-8");
90371
+ content = await fs82.readFile(filePath, "utf-8");
89656
90372
  } catch {
89657
90373
  continue;
89658
90374
  }
@@ -89673,10 +90389,10 @@ var DEFAULT_CONFIG2 = {
89673
90389
  };
89674
90390
  function defaultReadPlanJson(dir) {
89675
90391
  try {
89676
- const planPath = path106.join(dir, ".swarm", "plan.json");
89677
- if (!fs81.existsSync(planPath))
90392
+ const planPath = path109.join(dir, ".swarm", "plan.json");
90393
+ if (!fs83.existsSync(planPath))
89678
90394
  return null;
89679
- const raw = fs81.readFileSync(planPath, "utf-8");
90395
+ const raw = fs83.readFileSync(planPath, "utf-8");
89680
90396
  const plan = JSON.parse(raw);
89681
90397
  if (typeof plan !== "object" || plan === null || !Array.isArray(plan.phases)) {
89682
90398
  return null;
@@ -89688,11 +90404,11 @@ function defaultReadPlanJson(dir) {
89688
90404
  }
89689
90405
  function readReviewerEvidenceFromFile(directory, phase) {
89690
90406
  try {
89691
- const evidencePath = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
89692
- if (!fs81.existsSync(evidencePath)) {
90407
+ const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
90408
+ if (!fs83.existsSync(evidencePath)) {
89693
90409
  return null;
89694
90410
  }
89695
- const raw = fs81.readFileSync(evidencePath, "utf-8");
90411
+ const raw = fs83.readFileSync(evidencePath, "utf-8");
89696
90412
  const parsed = JSON.parse(raw);
89697
90413
  if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
89698
90414
  return null;
@@ -89708,11 +90424,11 @@ function readReviewerEvidenceFromFile(directory, phase) {
89708
90424
  }
89709
90425
  function readCriticEvidenceFromFile(directory, phase) {
89710
90426
  try {
89711
- const evidencePath = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
89712
- if (!fs81.existsSync(evidencePath)) {
90427
+ const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
90428
+ if (!fs83.existsSync(evidencePath)) {
89713
90429
  return null;
89714
90430
  }
89715
- const raw = fs81.readFileSync(evidencePath, "utf-8");
90431
+ const raw = fs83.readFileSync(evidencePath, "utf-8");
89716
90432
  const parsed = JSON.parse(raw);
89717
90433
  if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
89718
90434
  return null;
@@ -89727,10 +90443,10 @@ function readCriticEvidenceFromFile(directory, phase) {
89727
90443
  }
89728
90444
  }
89729
90445
  function listLaneEvidenceSync(directory, phase) {
89730
- const evidenceDir = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
90446
+ const evidenceDir = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
89731
90447
  let entries;
89732
90448
  try {
89733
- entries = fs81.readdirSync(evidenceDir);
90449
+ entries = fs83.readdirSync(evidenceDir);
89734
90450
  } catch {
89735
90451
  return [];
89736
90452
  }
@@ -89743,7 +90459,7 @@ function listLaneEvidenceSync(directory, phase) {
89743
90459
  }
89744
90460
  return laneIds;
89745
90461
  }
89746
- var _internals40 = {
90462
+ var _internals43 = {
89747
90463
  listActiveLocks,
89748
90464
  readPersisted: readPersisted2,
89749
90465
  readPlanJson: defaultReadPlanJson,
@@ -89797,14 +90513,14 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89797
90513
  ...DEFAULT_CONFIG2,
89798
90514
  ...actualConfig
89799
90515
  };
89800
- const statePath = path106.join(directory, ".swarm", "turbo-state.json");
89801
- if (!fs81.existsSync(statePath)) {
90516
+ const statePath = path109.join(directory, ".swarm", "turbo-state.json");
90517
+ if (!fs83.existsSync(statePath)) {
89802
90518
  return {
89803
90519
  ok: false,
89804
90520
  reason: "Lean Turbo state unreadable or missing"
89805
90521
  };
89806
90522
  }
89807
- const persisted = _internals40.readPersisted(directory);
90523
+ const persisted = _internals43.readPersisted(directory);
89808
90524
  if (!persisted) {
89809
90525
  return {
89810
90526
  ok: false,
@@ -89868,7 +90584,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89868
90584
  }
89869
90585
  }
89870
90586
  if (runState.lanes.length > 0) {
89871
- const evidenceLaneIds = new Set(_internals40.listLaneEvidenceSync(directory, phase));
90587
+ const evidenceLaneIds = new Set(_internals43.listLaneEvidenceSync(directory, phase));
89872
90588
  for (const lane of runState.lanes) {
89873
90589
  if ((lane.status === "completed" || lane.status === "failed") && !evidenceLaneIds.has(lane.laneId)) {
89874
90590
  return {
@@ -89878,7 +90594,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89878
90594
  }
89879
90595
  }
89880
90596
  }
89881
- const activeLocks = _internals40.listActiveLocks(directory);
90597
+ const activeLocks = _internals43.listActiveLocks(directory);
89882
90598
  const phaseLaneIds = new Set(laneIds);
89883
90599
  for (const lock of activeLocks) {
89884
90600
  if (lock.laneId && phaseLaneIds.has(lock.laneId)) {
@@ -89898,7 +90614,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89898
90614
  }
89899
90615
  const serialDegradedTasks = runState.degradedTasks.filter((dt) => !laneTaskIds.has(dt.taskId));
89900
90616
  if (serialDegradedTasks.length > 0) {
89901
- const plan = _internals40.readPlanJson(directory);
90617
+ const plan = _internals43.readPlanJson(directory);
89902
90618
  if (!plan) {
89903
90619
  return {
89904
90620
  ok: false,
@@ -89942,7 +90658,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89942
90658
  }
89943
90659
  const serializedTasks = runState.serializedTasks;
89944
90660
  if (Array.isArray(serializedTasks) && serializedTasks.length > 0) {
89945
- const plan = _internals40.readPlanJson(directory);
90661
+ const plan = _internals43.readPlanJson(directory);
89946
90662
  if (!plan) {
89947
90663
  return {
89948
90664
  ok: false,
@@ -89985,10 +90701,10 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89985
90701
  }
89986
90702
  }
89987
90703
  if (mergedConfig.integrated_diff_required) {
89988
- const evidencePath = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
90704
+ const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
89989
90705
  let hasDiff = false;
89990
90706
  try {
89991
- const content = fs81.readFileSync(evidencePath, "utf-8");
90707
+ const content = fs83.readFileSync(evidencePath, "utf-8");
89992
90708
  const evidence = JSON.parse(content);
89993
90709
  hasDiff = !!evidence.integratedDiffSummary;
89994
90710
  } catch {}
@@ -90001,7 +90717,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
90001
90717
  }
90002
90718
  let reviewerVerdict = runState.lastReviewerVerdict;
90003
90719
  if (!reviewerVerdict) {
90004
- const evidence = _internals40.readReviewerEvidence(directory, phase);
90720
+ const evidence = _internals43.readReviewerEvidence(directory, phase);
90005
90721
  reviewerVerdict = evidence?.verdict ?? undefined;
90006
90722
  }
90007
90723
  if (mergedConfig.phase_reviewer) {
@@ -90014,7 +90730,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
90014
90730
  }
90015
90731
  let criticVerdict = runState.lastCriticVerdict;
90016
90732
  if (!criticVerdict) {
90017
- const evidence = _internals40.readCriticEvidence(directory, phase);
90733
+ const evidence = _internals43.readCriticEvidence(directory, phase);
90018
90734
  criticVerdict = evidence?.verdict ?? undefined;
90019
90735
  }
90020
90736
  if (mergedConfig.phase_critic) {
@@ -90046,6 +90762,23 @@ function safeWarn(message, error93) {
90046
90762
  warn(message, error93 instanceof Error ? error93.message : String(error93));
90047
90763
  } catch {}
90048
90764
  }
90765
+ var TASK_GATE_INFERABLE_AGENTS = new Set([
90766
+ "coder",
90767
+ "reviewer",
90768
+ "test_engineer"
90769
+ ]);
90770
+ function canInferMissingAgentsFromTaskGates(agentsMissing) {
90771
+ return agentsMissing.every((agent) => TASK_GATE_INFERABLE_AGENTS.has(agent));
90772
+ }
90773
+ async function allCompletedTasksHavePassedGateEvidence(directory, tasks) {
90774
+ for (const task of tasks) {
90775
+ if (task.status !== "completed")
90776
+ return false;
90777
+ if (!await hasPassedAllGates(directory, task.id))
90778
+ return false;
90779
+ }
90780
+ return tasks.length > 0;
90781
+ }
90049
90782
  function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSessionId) {
90050
90783
  const agents = new Set;
90051
90784
  const contributorSessionIds = [];
@@ -90057,12 +90790,9 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
90057
90790
  agents.add(agent);
90058
90791
  }
90059
90792
  }
90060
- const callerDelegations = swarmState.delegationChains.get(callerSessionId);
90061
- if (callerDelegations) {
90062
- for (const delegation of callerDelegations) {
90063
- agents.add(stripKnownSwarmPrefix(delegation.from));
90064
- agents.add(stripKnownSwarmPrefix(delegation.to));
90065
- }
90793
+ for (const delegation of _getDelegationsSince(callerSessionId, phaseReferenceTimestamp)) {
90794
+ agents.add(stripKnownSwarmPrefix(delegation.from));
90795
+ agents.add(stripKnownSwarmPrefix(delegation.to));
90066
90796
  }
90067
90797
  }
90068
90798
  for (const [sessionId, session] of swarmState.agentSessions) {
@@ -90081,17 +90811,24 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
90081
90811
  agents.add(agent);
90082
90812
  }
90083
90813
  }
90084
- const delegations2 = swarmState.delegationChains.get(sessionId);
90085
- if (delegations2) {
90086
- for (const delegation of delegations2) {
90087
- agents.add(stripKnownSwarmPrefix(delegation.from));
90088
- agents.add(stripKnownSwarmPrefix(delegation.to));
90089
- }
90814
+ for (const delegation of _getDelegationsSince(sessionId, phaseReferenceTimestamp)) {
90815
+ agents.add(stripKnownSwarmPrefix(delegation.from));
90816
+ agents.add(stripKnownSwarmPrefix(delegation.to));
90090
90817
  }
90091
90818
  }
90092
90819
  }
90093
90820
  return { agents, contributorSessionIds };
90094
90821
  }
90822
+ function _getDelegationsSince(sessionID, sinceTimestamp) {
90823
+ const chain = swarmState.delegationChains.get(sessionID);
90824
+ if (!chain) {
90825
+ return [];
90826
+ }
90827
+ if (sinceTimestamp === 0) {
90828
+ return chain;
90829
+ }
90830
+ return chain.filter((entry) => entry.timestamp > sinceTimestamp);
90831
+ }
90095
90832
  function isValidRetroEntry(entry, phase) {
90096
90833
  return entry.type === "retrospective" && "phase_number" in entry && entry.phase_number === phase && "verdict" in entry && entry.verdict === "pass";
90097
90834
  }
@@ -90259,8 +90996,8 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90259
90996
  let driftCheckEnabled = true;
90260
90997
  let driftHasSpecMd = false;
90261
90998
  try {
90262
- const specMdPath = path107.join(dir, ".swarm", "spec.md");
90263
- driftHasSpecMd = fs82.existsSync(specMdPath);
90999
+ const specMdPath = path110.join(dir, ".swarm", "spec.md");
91000
+ driftHasSpecMd = fs84.existsSync(specMdPath);
90264
91001
  const gatePlan = await loadPlan(dir);
90265
91002
  if (gatePlan) {
90266
91003
  const gatePlanId = derivePlanId(gatePlan);
@@ -90280,9 +91017,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90280
91017
  } else {
90281
91018
  let phaseType;
90282
91019
  try {
90283
- const planPath = path107.join(dir, ".swarm", "plan.json");
90284
- if (fs82.existsSync(planPath)) {
90285
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91020
+ const planPath = path110.join(dir, ".swarm", "plan.json");
91021
+ if (fs84.existsSync(planPath)) {
91022
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
90286
91023
  const plan = JSON.parse(planRaw);
90287
91024
  const targetPhase = plan.phases?.find((p) => p.id === phase);
90288
91025
  phaseType = targetPhase?.type;
@@ -90292,11 +91029,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90292
91029
  warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
90293
91030
  } else {
90294
91031
  try {
90295
- const driftEvidencePath = path107.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
91032
+ const driftEvidencePath = path110.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
90296
91033
  let driftVerdictFound = false;
90297
91034
  let driftVerdictApproved = false;
90298
91035
  try {
90299
- const driftEvidenceContent = fs82.readFileSync(driftEvidencePath, "utf-8");
91036
+ const driftEvidenceContent = fs84.readFileSync(driftEvidencePath, "utf-8");
90300
91037
  const driftEvidence = JSON.parse(driftEvidenceContent);
90301
91038
  const entries = driftEvidence.entries ?? [];
90302
91039
  for (const entry of entries) {
@@ -90330,9 +91067,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90330
91067
  let incompleteTaskCount = 0;
90331
91068
  let planParseable = false;
90332
91069
  try {
90333
- const planPath = path107.join(dir, ".swarm", "plan.json");
90334
- if (fs82.existsSync(planPath)) {
90335
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91070
+ const planPath = path110.join(dir, ".swarm", "plan.json");
91071
+ if (fs84.existsSync(planPath)) {
91072
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
90336
91073
  const plan = JSON.parse(planRaw);
90337
91074
  planParseable = true;
90338
91075
  const planPhase = plan.phases?.find((p) => p.id === phase);
@@ -90397,11 +91134,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90397
91134
  const overrides = session2?.qaGateSessionOverrides ?? {};
90398
91135
  const effective = getEffectiveGates(profile, overrides);
90399
91136
  if (effective.hallucination_guard === true) {
90400
- const hgPath = path107.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
91137
+ const hgPath = path110.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
90401
91138
  let hgVerdictFound = false;
90402
91139
  let hgVerdictApproved = false;
90403
91140
  try {
90404
- const hgContent = fs82.readFileSync(hgPath, "utf-8");
91141
+ const hgContent = fs84.readFileSync(hgPath, "utf-8");
90405
91142
  const hgBundle = JSON.parse(hgContent);
90406
91143
  for (const entry of hgBundle.entries ?? []) {
90407
91144
  if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
@@ -90469,11 +91206,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90469
91206
  const overrides = session2?.qaGateSessionOverrides ?? {};
90470
91207
  const effective = getEffectiveGates(profile, overrides);
90471
91208
  if (effective.mutation_test === true) {
90472
- const mgPath = path107.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
91209
+ const mgPath = path110.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
90473
91210
  let mgVerdictFound = false;
90474
91211
  let mgVerdict;
90475
91212
  try {
90476
- const mgContent = fs82.readFileSync(mgPath, "utf-8");
91213
+ const mgContent = fs84.readFileSync(mgPath, "utf-8");
90477
91214
  const mgBundle = JSON.parse(mgContent);
90478
91215
  for (const entry of mgBundle.entries ?? []) {
90479
91216
  if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
@@ -90543,14 +91280,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90543
91280
  const effective = getEffectiveGates(profile, overrides);
90544
91281
  if (effective.council_mode === true) {
90545
91282
  councilModeEnabled = true;
90546
- const pcPath = path107.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
91283
+ const pcPath = path110.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
90547
91284
  let pcVerdictFound = false;
90548
91285
  let _pcVerdict;
90549
91286
  let pcQuorumSize;
90550
91287
  let pcTimestamp;
90551
91288
  let pcPhaseNumber;
90552
91289
  try {
90553
- const pcContent = fs82.readFileSync(pcPath, "utf-8");
91290
+ const pcContent = fs84.readFileSync(pcPath, "utf-8");
90554
91291
  const pcBundle = JSON.parse(pcContent);
90555
91292
  for (const entry of pcBundle.entries ?? []) {
90556
91293
  if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
@@ -90751,11 +91488,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
90751
91488
  const effective = getEffectiveGates(profile, overrides);
90752
91489
  if (effective.final_council === true) {
90753
91490
  finalCouncilEnabled = true;
90754
- const fcPath = path107.join(dir, ".swarm", "evidence", "final-council.json");
91491
+ const fcPath = path110.join(dir, ".swarm", "evidence", "final-council.json");
90755
91492
  let fcVerdictFound = false;
90756
91493
  let _fcVerdict;
90757
91494
  try {
90758
- const fcContent = fs82.readFileSync(fcPath, "utf-8");
91495
+ const fcContent = fs84.readFileSync(fcPath, "utf-8");
90759
91496
  const fcBundle = JSON.parse(fcContent);
90760
91497
  for (const entry of fcBundle.entries ?? []) {
90761
91498
  if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
@@ -90916,7 +91653,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
90916
91653
  phase_critic: leanConfig.phase_critic,
90917
91654
  integrated_diff_required: leanConfig.integrated_diff_required
90918
91655
  } : undefined;
90919
- const leanCheck = _internals40.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
91656
+ const leanCheck = _internals43.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
90920
91657
  if (!leanCheck.ok) {
90921
91658
  return JSON.stringify({
90922
91659
  success: false,
@@ -90939,7 +91676,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
90939
91676
  }
90940
91677
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
90941
91678
  try {
90942
- const projectName = path107.basename(dir);
91679
+ const projectName = path110.basename(dir);
90943
91680
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
90944
91681
  if (curationResult) {
90945
91682
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -91019,7 +91756,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91019
91756
  let phaseRequiredAgents;
91020
91757
  try {
91021
91758
  const planPath = validateSwarmPath(dir, "plan.json");
91022
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91759
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91023
91760
  const plan = JSON.parse(planRaw);
91024
91761
  const phaseObj = plan.phases.find((p) => p.id === phase);
91025
91762
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -91034,11 +91771,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91034
91771
  if (agentsMissing.length > 0) {
91035
91772
  try {
91036
91773
  const planPath = validateSwarmPath(dir, "plan.json");
91037
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91774
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91038
91775
  const plan = JSON.parse(planRaw);
91039
91776
  const targetPhase = plan.phases.find((p) => p.id === phase);
91040
- if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
91041
- warnings.push(`Agent dispatch fallback: all ${targetPhase.tasks.length} tasks in phase ${phase} are completed in plan.json. Clearing missing agents: ${agentsMissing.join(", ")}.`);
91777
+ if (targetPhase && targetPhase.tasks.length > 0 && canInferMissingAgentsFromTaskGates(agentsMissing) && await allCompletedTasksHavePassedGateEvidence(dir, targetPhase.tasks)) {
91778
+ warnings.push(`Agent dispatch fallback: all ${targetPhase.tasks.length} tasks in phase ${phase} are completed in plan.json and durable gate evidence passed. Clearing missing agents: ${agentsMissing.join(", ")}.`);
91042
91779
  agentsMissing = [];
91043
91780
  }
91044
91781
  } catch {}
@@ -91074,7 +91811,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91074
91811
  if (phaseCompleteConfig.regression_sweep?.enforce) {
91075
91812
  try {
91076
91813
  const planPath = validateSwarmPath(dir, "plan.json");
91077
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91814
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91078
91815
  const plan = JSON.parse(planRaw);
91079
91816
  const targetPhase = plan.phases.find((p) => p.id === phase);
91080
91817
  if (targetPhase) {
@@ -91128,7 +91865,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91128
91865
  }
91129
91866
  try {
91130
91867
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
91131
- fs82.appendFileSync(eventsPath, `${JSON.stringify(event)}
91868
+ fs84.appendFileSync(eventsPath, `${JSON.stringify(event)}
91132
91869
  `, "utf-8");
91133
91870
  } catch (writeError) {
91134
91871
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -91203,12 +91940,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91203
91940
  warnings.push(`Warning: failed to update plan.json phase status`);
91204
91941
  try {
91205
91942
  const planPath = validateSwarmPath(dir, "plan.json");
91206
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91943
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91207
91944
  const plan2 = JSON.parse(planRaw);
91208
91945
  const phaseObj = plan2.phases.find((p) => p.id === phase);
91209
91946
  if (phaseObj) {
91210
91947
  phaseObj.status = "complete";
91211
- fs82.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
91948
+ fs84.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
91212
91949
  }
91213
91950
  } catch {}
91214
91951
  } else if (plan) {
@@ -91245,12 +91982,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91245
91982
  warnings.push(`Warning: failed to update plan.json phase status`);
91246
91983
  try {
91247
91984
  const planPath = validateSwarmPath(dir, "plan.json");
91248
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91985
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91249
91986
  const plan = JSON.parse(planRaw);
91250
91987
  const phaseObj = plan.phases.find((p) => p.id === phase);
91251
91988
  if (phaseObj) {
91252
91989
  phaseObj.status = "complete";
91253
- fs82.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
91990
+ fs84.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
91254
91991
  }
91255
91992
  } catch {}
91256
91993
  }
@@ -91308,8 +92045,8 @@ init_discovery();
91308
92045
  init_utils();
91309
92046
  init_bun_compat();
91310
92047
  init_create_tool();
91311
- import * as fs83 from "node:fs";
91312
- import * as path108 from "node:path";
92048
+ import * as fs85 from "node:fs";
92049
+ import * as path111 from "node:path";
91313
92050
  var MAX_OUTPUT_BYTES5 = 52428800;
91314
92051
  var AUDIT_TIMEOUT_MS = 120000;
91315
92052
  function isValidEcosystem(value) {
@@ -91337,31 +92074,31 @@ function validateArgs3(args2) {
91337
92074
  function detectEcosystems(directory) {
91338
92075
  const ecosystems = [];
91339
92076
  const cwd = directory;
91340
- if (fs83.existsSync(path108.join(cwd, "package.json"))) {
92077
+ if (fs85.existsSync(path111.join(cwd, "package.json"))) {
91341
92078
  ecosystems.push("npm");
91342
92079
  }
91343
- if (fs83.existsSync(path108.join(cwd, "pyproject.toml")) || fs83.existsSync(path108.join(cwd, "requirements.txt"))) {
92080
+ if (fs85.existsSync(path111.join(cwd, "pyproject.toml")) || fs85.existsSync(path111.join(cwd, "requirements.txt"))) {
91344
92081
  ecosystems.push("pip");
91345
92082
  }
91346
- if (fs83.existsSync(path108.join(cwd, "Cargo.toml"))) {
92083
+ if (fs85.existsSync(path111.join(cwd, "Cargo.toml"))) {
91347
92084
  ecosystems.push("cargo");
91348
92085
  }
91349
- if (fs83.existsSync(path108.join(cwd, "go.mod"))) {
92086
+ if (fs85.existsSync(path111.join(cwd, "go.mod"))) {
91350
92087
  ecosystems.push("go");
91351
92088
  }
91352
92089
  try {
91353
- const files = fs83.readdirSync(cwd);
92090
+ const files = fs85.readdirSync(cwd);
91354
92091
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
91355
92092
  ecosystems.push("dotnet");
91356
92093
  }
91357
92094
  } catch {}
91358
- if (fs83.existsSync(path108.join(cwd, "Gemfile")) || fs83.existsSync(path108.join(cwd, "Gemfile.lock"))) {
92095
+ if (fs85.existsSync(path111.join(cwd, "Gemfile")) || fs85.existsSync(path111.join(cwd, "Gemfile.lock"))) {
91359
92096
  ecosystems.push("ruby");
91360
92097
  }
91361
- if (fs83.existsSync(path108.join(cwd, "pubspec.yaml"))) {
92098
+ if (fs85.existsSync(path111.join(cwd, "pubspec.yaml"))) {
91362
92099
  ecosystems.push("dart");
91363
92100
  }
91364
- if (fs83.existsSync(path108.join(cwd, "composer.lock"))) {
92101
+ if (fs85.existsSync(path111.join(cwd, "composer.lock"))) {
91365
92102
  ecosystems.push("composer");
91366
92103
  }
91367
92104
  return ecosystems;
@@ -92496,8 +93233,8 @@ var pkg_audit = createSwarmTool({
92496
93233
  // src/tools/placeholder-scan.ts
92497
93234
  init_zod();
92498
93235
  init_manager2();
92499
- import * as fs84 from "node:fs";
92500
- import * as path109 from "node:path";
93236
+ import * as fs86 from "node:fs";
93237
+ import * as path112 from "node:path";
92501
93238
  init_utils();
92502
93239
  init_create_tool();
92503
93240
  var MAX_FILE_SIZE = 1024 * 1024;
@@ -92620,7 +93357,7 @@ function isScaffoldFile(filePath) {
92620
93357
  if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
92621
93358
  return true;
92622
93359
  }
92623
- const filename = path109.basename(filePath);
93360
+ const filename = path112.basename(filePath);
92624
93361
  if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
92625
93362
  return true;
92626
93363
  }
@@ -92637,7 +93374,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
92637
93374
  if (regex.test(normalizedPath)) {
92638
93375
  return true;
92639
93376
  }
92640
- const filename = path109.basename(filePath);
93377
+ const filename = path112.basename(filePath);
92641
93378
  const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
92642
93379
  if (filenameRegex.test(filename)) {
92643
93380
  return true;
@@ -92646,7 +93383,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
92646
93383
  return false;
92647
93384
  }
92648
93385
  function isParserSupported(filePath) {
92649
- const ext = path109.extname(filePath).toLowerCase();
93386
+ const ext = path112.extname(filePath).toLowerCase();
92650
93387
  return SUPPORTED_PARSER_EXTENSIONS.has(ext);
92651
93388
  }
92652
93389
  function isPlanFile(filePath) {
@@ -92893,28 +93630,28 @@ async function placeholderScan(input, directory) {
92893
93630
  let filesScanned = 0;
92894
93631
  const filesWithFindings = new Set;
92895
93632
  for (const filePath of changed_files) {
92896
- const fullPath = path109.isAbsolute(filePath) ? filePath : path109.resolve(directory, filePath);
92897
- const resolvedDirectory = path109.resolve(directory);
92898
- if (!fullPath.startsWith(resolvedDirectory + path109.sep) && fullPath !== resolvedDirectory) {
93633
+ const fullPath = path112.isAbsolute(filePath) ? filePath : path112.resolve(directory, filePath);
93634
+ const resolvedDirectory = path112.resolve(directory);
93635
+ if (!fullPath.startsWith(resolvedDirectory + path112.sep) && fullPath !== resolvedDirectory) {
92899
93636
  continue;
92900
93637
  }
92901
- if (!fs84.existsSync(fullPath)) {
93638
+ if (!fs86.existsSync(fullPath)) {
92902
93639
  continue;
92903
93640
  }
92904
93641
  if (isAllowedByGlobs(filePath, allow_globs)) {
92905
93642
  continue;
92906
93643
  }
92907
- const relativeFilePath = path109.relative(directory, fullPath).replace(/\\/g, "/");
93644
+ const relativeFilePath = path112.relative(directory, fullPath).replace(/\\/g, "/");
92908
93645
  if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
92909
93646
  continue;
92910
93647
  }
92911
93648
  let content;
92912
93649
  try {
92913
- const stat8 = fs84.statSync(fullPath);
93650
+ const stat8 = fs86.statSync(fullPath);
92914
93651
  if (stat8.size > MAX_FILE_SIZE) {
92915
93652
  continue;
92916
93653
  }
92917
- content = fs84.readFileSync(fullPath, "utf-8");
93654
+ content = fs86.readFileSync(fullPath, "utf-8");
92918
93655
  } catch {
92919
93656
  continue;
92920
93657
  }
@@ -92975,8 +93712,8 @@ var placeholder_scan = createSwarmTool({
92975
93712
  }
92976
93713
  });
92977
93714
  // src/tools/pre-check-batch.ts
92978
- import * as fs88 from "node:fs";
92979
- import * as path113 from "node:path";
93715
+ import * as fs90 from "node:fs";
93716
+ import * as path116 from "node:path";
92980
93717
  init_zod();
92981
93718
  init_manager2();
92982
93719
  init_utils();
@@ -93104,11 +93841,11 @@ var quality_budget = createSwarmTool({
93104
93841
  }).optional().describe("Quality budget thresholds")
93105
93842
  },
93106
93843
  async execute(args2, directory) {
93107
- const result = await _internals41.qualityBudget(args2, directory);
93844
+ const result = await _internals44.qualityBudget(args2, directory);
93108
93845
  return JSON.stringify(result);
93109
93846
  }
93110
93847
  });
93111
- var _internals41 = {
93848
+ var _internals44 = {
93112
93849
  qualityBudget
93113
93850
  };
93114
93851
 
@@ -93116,9 +93853,9 @@ var _internals41 = {
93116
93853
  init_zod();
93117
93854
  init_manager2();
93118
93855
  init_detector();
93119
- import * as fs87 from "node:fs";
93120
- import * as path112 from "node:path";
93121
- import { extname as extname19 } from "node:path";
93856
+ import * as fs89 from "node:fs";
93857
+ import * as path115 from "node:path";
93858
+ import { extname as extname20 } from "node:path";
93122
93859
 
93123
93860
  // src/sast/rules/c.ts
93124
93861
  var cRules = [
@@ -93832,12 +94569,12 @@ function executeRulesSync(filePath, content, language) {
93832
94569
 
93833
94570
  // src/sast/semgrep.ts
93834
94571
  import * as child_process9 from "node:child_process";
93835
- import * as fs85 from "node:fs";
93836
- import * as path110 from "node:path";
94572
+ import * as fs87 from "node:fs";
94573
+ import * as path113 from "node:path";
93837
94574
  var semgrepAvailableCache = null;
93838
94575
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
93839
94576
  var DEFAULT_TIMEOUT_MS3 = 30000;
93840
- var _internals42 = {
94577
+ var _internals45 = {
93841
94578
  isSemgrepAvailable,
93842
94579
  checkSemgrepAvailable,
93843
94580
  resetSemgrepCache,
@@ -93862,7 +94599,7 @@ function isSemgrepAvailable() {
93862
94599
  }
93863
94600
  }
93864
94601
  async function checkSemgrepAvailable() {
93865
- return _internals42.isSemgrepAvailable();
94602
+ return _internals45.isSemgrepAvailable();
93866
94603
  }
93867
94604
  function resetSemgrepCache() {
93868
94605
  semgrepAvailableCache = null;
@@ -93959,12 +94696,12 @@ async function runSemgrep(options) {
93959
94696
  const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
93960
94697
  if (files.length === 0) {
93961
94698
  return {
93962
- available: _internals42.isSemgrepAvailable(),
94699
+ available: _internals45.isSemgrepAvailable(),
93963
94700
  findings: [],
93964
94701
  engine: "tier_a"
93965
94702
  };
93966
94703
  }
93967
- if (!_internals42.isSemgrepAvailable()) {
94704
+ if (!_internals45.isSemgrepAvailable()) {
93968
94705
  return {
93969
94706
  available: false,
93970
94707
  findings: [],
@@ -94020,14 +94757,14 @@ async function runSemgrep(options) {
94020
94757
  }
94021
94758
  function getRulesDirectory(projectRoot) {
94022
94759
  if (projectRoot) {
94023
- return path110.resolve(projectRoot, DEFAULT_RULES_DIR);
94760
+ return path113.resolve(projectRoot, DEFAULT_RULES_DIR);
94024
94761
  }
94025
94762
  return DEFAULT_RULES_DIR;
94026
94763
  }
94027
94764
  function hasBundledRules(projectRoot) {
94028
94765
  const rulesDir = getRulesDirectory(projectRoot);
94029
94766
  try {
94030
- return fs85.existsSync(rulesDir);
94767
+ return fs87.existsSync(rulesDir);
94031
94768
  } catch {
94032
94769
  return false;
94033
94770
  }
@@ -94039,26 +94776,26 @@ init_create_tool();
94039
94776
 
94040
94777
  // src/tools/sast-baseline.ts
94041
94778
  init_utils2();
94042
- import * as crypto9 from "node:crypto";
94043
- import * as fs86 from "node:fs";
94044
- import * as path111 from "node:path";
94779
+ import * as crypto10 from "node:crypto";
94780
+ import * as fs88 from "node:fs";
94781
+ import * as path114 from "node:path";
94045
94782
  var BASELINE_SCHEMA_VERSION = "1.0.0";
94046
94783
  var MAX_BASELINE_FINDINGS = 2000;
94047
94784
  var MAX_BASELINE_BYTES = 2 * 1048576;
94048
94785
  var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
94049
94786
  function normalizeFindingPath(directory, file3) {
94050
- const resolved = path111.isAbsolute(file3) ? file3 : path111.resolve(directory, file3);
94051
- const rel = path111.relative(path111.resolve(directory), resolved);
94787
+ const resolved = path114.isAbsolute(file3) ? file3 : path114.resolve(directory, file3);
94788
+ const rel = path114.relative(path114.resolve(directory), resolved);
94052
94789
  return rel.replace(/\\/g, "/");
94053
94790
  }
94054
94791
  function baselineRelPath(phase) {
94055
- return path111.join("evidence", String(phase), "sast-baseline.json");
94792
+ return path114.join("evidence", String(phase), "sast-baseline.json");
94056
94793
  }
94057
94794
  function tempRelPath(phase) {
94058
- return path111.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
94795
+ return path114.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
94059
94796
  }
94060
94797
  function lockRelPath(phase) {
94061
- return path111.join("evidence", String(phase), "sast-baseline.json.lock");
94798
+ return path114.join("evidence", String(phase), "sast-baseline.json.lock");
94062
94799
  }
94063
94800
  function getLine(lines, idx) {
94064
94801
  if (idx < 0 || idx >= lines.length)
@@ -94075,7 +94812,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
94075
94812
  }
94076
94813
  const lineNum = finding.location.line;
94077
94814
  try {
94078
- const content = fs86.readFileSync(finding.location.file, "utf-8");
94815
+ const content = fs88.readFileSync(finding.location.file, "utf-8");
94079
94816
  const lines = content.split(`
94080
94817
  `);
94081
94818
  const idx = lineNum - 1;
@@ -94085,7 +94822,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
94085
94822
  getLine(lines, idx + 1)
94086
94823
  ].join(`
94087
94824
  `);
94088
- const hash3 = crypto9.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94825
+ const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94089
94826
  return {
94090
94827
  fingerprint: `${relFile}|${finding.rule_id}|${hash3}|#${occurrenceIndex}`,
94091
94828
  stable: true
@@ -94106,7 +94843,7 @@ function assignOccurrenceIndices(findings, directory) {
94106
94843
  try {
94107
94844
  if (relFile.startsWith(".."))
94108
94845
  throw new Error("escapes workspace");
94109
- const content = fs86.readFileSync(finding.location.file, "utf-8");
94846
+ const content = fs88.readFileSync(finding.location.file, "utf-8");
94110
94847
  const lines = content.split(`
94111
94848
  `);
94112
94849
  const idx = lineNum - 1;
@@ -94116,14 +94853,14 @@ function assignOccurrenceIndices(findings, directory) {
94116
94853
  getLine(lines, idx + 1)
94117
94854
  ].join(`
94118
94855
  `);
94119
- const hash3 = crypto9.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94856
+ const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94120
94857
  baseKey = `${relFile}|${finding.rule_id}|${hash3}`;
94121
94858
  } catch {
94122
94859
  baseKey = `${relFile}|${finding.rule_id}|L${lineNum}|UNSTABLE`;
94123
94860
  }
94124
94861
  const occIdx = countMap.get(baseKey) ?? 0;
94125
94862
  countMap.set(baseKey, occIdx + 1);
94126
- const fp = _internals43.fingerprintFinding(finding, directory, occIdx);
94863
+ const fp = _internals46.fingerprintFinding(finding, directory, occIdx);
94127
94864
  return {
94128
94865
  finding,
94129
94866
  index: occIdx,
@@ -94135,11 +94872,11 @@ function assignOccurrenceIndices(findings, directory) {
94135
94872
  async function acquireLock2(lockPath) {
94136
94873
  for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
94137
94874
  try {
94138
- const fd = fs86.openSync(lockPath, "wx");
94139
- fs86.closeSync(fd);
94875
+ const fd = fs88.openSync(lockPath, "wx");
94876
+ fs88.closeSync(fd);
94140
94877
  return () => {
94141
94878
  try {
94142
- fs86.unlinkSync(lockPath);
94879
+ fs88.unlinkSync(lockPath);
94143
94880
  } catch {}
94144
94881
  };
94145
94882
  } catch {
@@ -94179,20 +94916,20 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
94179
94916
  message: e instanceof Error ? e.message : "Path validation failed"
94180
94917
  };
94181
94918
  }
94182
- fs86.mkdirSync(path111.dirname(baselinePath), { recursive: true });
94183
- fs86.mkdirSync(path111.dirname(tempPath), { recursive: true });
94919
+ fs88.mkdirSync(path114.dirname(baselinePath), { recursive: true });
94920
+ fs88.mkdirSync(path114.dirname(tempPath), { recursive: true });
94184
94921
  const releaseLock = await acquireLock2(lockPath);
94185
94922
  try {
94186
94923
  let existing = null;
94187
94924
  try {
94188
- const raw = fs86.readFileSync(baselinePath, "utf-8");
94925
+ const raw = fs88.readFileSync(baselinePath, "utf-8");
94189
94926
  const parsed = JSON.parse(raw);
94190
94927
  if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
94191
94928
  existing = parsed;
94192
94929
  }
94193
94930
  } catch {}
94194
94931
  const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
94195
- const indexed = _internals43.assignOccurrenceIndices(findings, directory);
94932
+ const indexed = _internals46.assignOccurrenceIndices(findings, directory);
94196
94933
  if (existing && !opts?.force) {
94197
94934
  const prunedFingerprints = existing.fingerprints.filter((fp) => {
94198
94935
  const relFile = fp.slice(0, fp.indexOf("|"));
@@ -94245,8 +94982,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
94245
94982
  message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
94246
94983
  };
94247
94984
  }
94248
- fs86.writeFileSync(tempPath, json4, "utf-8");
94249
- fs86.renameSync(tempPath, baselinePath);
94985
+ fs88.writeFileSync(tempPath, json4, "utf-8");
94986
+ fs88.renameSync(tempPath, baselinePath);
94250
94987
  return {
94251
94988
  status: "merged",
94252
94989
  path: baselinePath,
@@ -94277,8 +95014,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
94277
95014
  message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
94278
95015
  };
94279
95016
  }
94280
- fs86.writeFileSync(tempPath, json3, "utf-8");
94281
- fs86.renameSync(tempPath, baselinePath);
95017
+ fs88.writeFileSync(tempPath, json3, "utf-8");
95018
+ fs88.renameSync(tempPath, baselinePath);
94282
95019
  return {
94283
95020
  status: "written",
94284
95021
  path: baselinePath,
@@ -94303,7 +95040,7 @@ function loadBaseline(directory, phase) {
94303
95040
  };
94304
95041
  }
94305
95042
  try {
94306
- const raw = fs86.readFileSync(baselinePath, "utf-8");
95043
+ const raw = fs88.readFileSync(baselinePath, "utf-8");
94307
95044
  const parsed = JSON.parse(raw);
94308
95045
  if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
94309
95046
  return {
@@ -94332,7 +95069,7 @@ function loadBaseline(directory, phase) {
94332
95069
  };
94333
95070
  }
94334
95071
  }
94335
- var _internals43 = {
95072
+ var _internals46 = {
94336
95073
  fingerprintFinding,
94337
95074
  assignOccurrenceIndices,
94338
95075
  captureOrMergeBaseline,
@@ -94351,17 +95088,17 @@ var SEVERITY_ORDER = {
94351
95088
  };
94352
95089
  function shouldSkipFile(filePath) {
94353
95090
  try {
94354
- const stats = fs87.statSync(filePath);
95091
+ const stats = fs89.statSync(filePath);
94355
95092
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
94356
95093
  return { skip: true, reason: "file too large" };
94357
95094
  }
94358
95095
  if (stats.size === 0) {
94359
95096
  return { skip: true, reason: "empty file" };
94360
95097
  }
94361
- const fd = fs87.openSync(filePath, "r");
95098
+ const fd = fs89.openSync(filePath, "r");
94362
95099
  const buffer = Buffer.alloc(8192);
94363
- const bytesRead = fs87.readSync(fd, buffer, 0, 8192, 0);
94364
- fs87.closeSync(fd);
95100
+ const bytesRead = fs89.readSync(fd, buffer, 0, 8192, 0);
95101
+ fs89.closeSync(fd);
94365
95102
  if (bytesRead > 0) {
94366
95103
  let nullCount = 0;
94367
95104
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -94400,7 +95137,7 @@ function countBySeverity(findings) {
94400
95137
  }
94401
95138
  function scanFileWithTierA(filePath, language) {
94402
95139
  try {
94403
- const content = fs87.readFileSync(filePath, "utf-8");
95140
+ const content = fs89.readFileSync(filePath, "utf-8");
94404
95141
  const findings = executeRulesSync(filePath, content, language);
94405
95142
  return findings.map((f) => ({
94406
95143
  rule_id: f.rule_id,
@@ -94453,13 +95190,13 @@ async function sastScan(input, directory, config3) {
94453
95190
  _filesSkipped++;
94454
95191
  continue;
94455
95192
  }
94456
- const resolvedPath = path112.isAbsolute(filePath) ? filePath : path112.resolve(directory, filePath);
94457
- const resolvedDirectory = path112.resolve(directory);
94458
- if (!resolvedPath.startsWith(resolvedDirectory + path112.sep) && resolvedPath !== resolvedDirectory) {
95193
+ const resolvedPath = path115.isAbsolute(filePath) ? filePath : path115.resolve(directory, filePath);
95194
+ const resolvedDirectory = path115.resolve(directory);
95195
+ if (!resolvedPath.startsWith(resolvedDirectory + path115.sep) && resolvedPath !== resolvedDirectory) {
94459
95196
  _filesSkipped++;
94460
95197
  continue;
94461
95198
  }
94462
- if (!fs87.existsSync(resolvedPath)) {
95199
+ if (!fs89.existsSync(resolvedPath)) {
94463
95200
  _filesSkipped++;
94464
95201
  continue;
94465
95202
  }
@@ -94468,7 +95205,7 @@ async function sastScan(input, directory, config3) {
94468
95205
  _filesSkipped++;
94469
95206
  continue;
94470
95207
  }
94471
- const ext = extname19(resolvedPath).toLowerCase();
95208
+ const ext = extname20(resolvedPath).toLowerCase();
94472
95209
  const profile = getProfileForFile(resolvedPath);
94473
95210
  const langDef = getLanguageForExtension(ext);
94474
95211
  if (!profile && !langDef) {
@@ -94742,11 +95479,11 @@ var sast_scan = createSwarmTool({
94742
95479
  capture_baseline: safeArgs.capture_baseline,
94743
95480
  phase: safeArgs.phase
94744
95481
  };
94745
- const result = await _internals44.sastScan(input, directory);
95482
+ const result = await _internals47.sastScan(input, directory);
94746
95483
  return JSON.stringify(result, null, 2);
94747
95484
  }
94748
95485
  });
94749
- var _internals44 = {
95486
+ var _internals47 = {
94750
95487
  sastScan,
94751
95488
  sast_scan
94752
95489
  };
@@ -94770,18 +95507,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
94770
95507
  let resolved;
94771
95508
  const isWinAbs = isWindowsAbsolutePath(inputPath);
94772
95509
  if (isWinAbs) {
94773
- resolved = path113.win32.resolve(inputPath);
94774
- } else if (path113.isAbsolute(inputPath)) {
94775
- resolved = path113.resolve(inputPath);
95510
+ resolved = path116.win32.resolve(inputPath);
95511
+ } else if (path116.isAbsolute(inputPath)) {
95512
+ resolved = path116.resolve(inputPath);
94776
95513
  } else {
94777
- resolved = path113.resolve(baseDir, inputPath);
95514
+ resolved = path116.resolve(baseDir, inputPath);
94778
95515
  }
94779
- const workspaceResolved = path113.resolve(workspaceDir);
95516
+ const workspaceResolved = path116.resolve(workspaceDir);
94780
95517
  let relative24;
94781
95518
  if (isWinAbs) {
94782
- relative24 = path113.win32.relative(workspaceResolved, resolved);
95519
+ relative24 = path116.win32.relative(workspaceResolved, resolved);
94783
95520
  } else {
94784
- relative24 = path113.relative(workspaceResolved, resolved);
95521
+ relative24 = path116.relative(workspaceResolved, resolved);
94785
95522
  }
94786
95523
  if (relative24.startsWith("..")) {
94787
95524
  return "path traversal detected";
@@ -94846,7 +95583,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
94846
95583
  if (typeof file3 !== "string") {
94847
95584
  continue;
94848
95585
  }
94849
- const resolvedPath = path113.resolve(file3);
95586
+ const resolvedPath = path116.resolve(file3);
94850
95587
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
94851
95588
  if (validationError) {
94852
95589
  continue;
@@ -95003,7 +95740,7 @@ async function runSecretscanWithFiles(files, directory) {
95003
95740
  skippedFiles++;
95004
95741
  continue;
95005
95742
  }
95006
- const resolvedPath = path113.resolve(file3);
95743
+ const resolvedPath = path116.resolve(file3);
95007
95744
  const validationError = validatePath(resolvedPath, directory, directory);
95008
95745
  if (validationError) {
95009
95746
  skippedFiles++;
@@ -95021,14 +95758,14 @@ async function runSecretscanWithFiles(files, directory) {
95021
95758
  };
95022
95759
  }
95023
95760
  for (const file3 of validatedFiles) {
95024
- const ext = path113.extname(file3).toLowerCase();
95761
+ const ext = path116.extname(file3).toLowerCase();
95025
95762
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
95026
95763
  skippedFiles++;
95027
95764
  continue;
95028
95765
  }
95029
95766
  let stat8;
95030
95767
  try {
95031
- stat8 = fs88.statSync(file3);
95768
+ stat8 = fs90.statSync(file3);
95032
95769
  } catch {
95033
95770
  skippedFiles++;
95034
95771
  continue;
@@ -95039,7 +95776,7 @@ async function runSecretscanWithFiles(files, directory) {
95039
95776
  }
95040
95777
  let content;
95041
95778
  try {
95042
- const buffer = fs88.readFileSync(file3);
95779
+ const buffer = fs90.readFileSync(file3);
95043
95780
  if (buffer.includes(0)) {
95044
95781
  skippedFiles++;
95045
95782
  continue;
@@ -95240,7 +95977,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
95240
95977
  const preexistingFindings = [];
95241
95978
  for (const finding of findings) {
95242
95979
  const filePath = finding.location.file;
95243
- const normalised = path113.relative(directory, filePath).replace(/\\/g, "/");
95980
+ const normalised = path116.relative(directory, filePath).replace(/\\/g, "/");
95244
95981
  const changedLines = changedLineRanges.get(normalised);
95245
95982
  if (changedLines?.has(finding.location.line)) {
95246
95983
  newFindings.push(finding);
@@ -95291,7 +96028,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
95291
96028
  warn(`pre_check_batch: Invalid file path: ${file3}`);
95292
96029
  continue;
95293
96030
  }
95294
- changedFiles.push(path113.resolve(directory, file3));
96031
+ changedFiles.push(path116.resolve(directory, file3));
95295
96032
  }
95296
96033
  if (changedFiles.length === 0) {
95297
96034
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -95492,7 +96229,7 @@ var pre_check_batch = createSwarmTool({
95492
96229
  };
95493
96230
  return JSON.stringify(errorResult, null, 2);
95494
96231
  }
95495
- const resolvedDirectory = path113.resolve(typedArgs.directory);
96232
+ const resolvedDirectory = path116.resolve(typedArgs.directory);
95496
96233
  const workspaceAnchor = resolvedDirectory;
95497
96234
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
95498
96235
  if (dirError) {
@@ -95533,7 +96270,7 @@ var pre_check_batch = createSwarmTool({
95533
96270
  });
95534
96271
  // src/tools/repo-map.ts
95535
96272
  init_zod();
95536
- import * as path114 from "node:path";
96273
+ import * as path117 from "node:path";
95537
96274
  init_path_security();
95538
96275
  init_create_tool();
95539
96276
  var VALID_ACTIONS = [
@@ -95558,7 +96295,7 @@ function validateFile(p) {
95558
96295
  return "file contains control characters";
95559
96296
  if (containsPathTraversal(p))
95560
96297
  return "file contains path traversal";
95561
- if (path114.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
96298
+ if (path117.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
95562
96299
  return "file must be a workspace-relative path, not absolute";
95563
96300
  }
95564
96301
  return null;
@@ -95581,8 +96318,8 @@ function ok(action, payload) {
95581
96318
  }
95582
96319
  function toRelativeGraphPath(input, workspaceRoot) {
95583
96320
  const normalized = input.replace(/\\/g, "/");
95584
- if (path114.isAbsolute(normalized)) {
95585
- const rel = path114.relative(workspaceRoot, normalized).replace(/\\/g, "/");
96321
+ if (path117.isAbsolute(normalized)) {
96322
+ const rel = path117.relative(workspaceRoot, normalized).replace(/\\/g, "/");
95586
96323
  return normalizeGraphPath2(rel);
95587
96324
  }
95588
96325
  return normalizeGraphPath2(normalized);
@@ -95726,8 +96463,8 @@ var repo_map = createSwarmTool({
95726
96463
  // src/tools/req-coverage.ts
95727
96464
  init_zod();
95728
96465
  init_create_tool();
95729
- import * as fs89 from "node:fs";
95730
- import * as path115 from "node:path";
96466
+ import * as fs91 from "node:fs";
96467
+ import * as path118 from "node:path";
95731
96468
  var SPEC_FILE = ".swarm/spec.md";
95732
96469
  var EVIDENCE_DIR4 = ".swarm/evidence";
95733
96470
  var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
@@ -95786,19 +96523,19 @@ function extractObligationAndText(id, lineText) {
95786
96523
  var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
95787
96524
  function readTouchedFiles(evidenceDir, phase, cwd) {
95788
96525
  const touchedFiles = new Set;
95789
- if (!fs89.existsSync(evidenceDir) || !fs89.statSync(evidenceDir).isDirectory()) {
96526
+ if (!fs91.existsSync(evidenceDir) || !fs91.statSync(evidenceDir).isDirectory()) {
95790
96527
  return [];
95791
96528
  }
95792
96529
  let entries;
95793
96530
  try {
95794
- entries = fs89.readdirSync(evidenceDir);
96531
+ entries = fs91.readdirSync(evidenceDir);
95795
96532
  } catch {
95796
96533
  return [];
95797
96534
  }
95798
96535
  for (const entry of entries) {
95799
- const entryPath = path115.join(evidenceDir, entry);
96536
+ const entryPath = path118.join(evidenceDir, entry);
95800
96537
  try {
95801
- const stat8 = fs89.statSync(entryPath);
96538
+ const stat8 = fs91.statSync(entryPath);
95802
96539
  if (!stat8.isDirectory()) {
95803
96540
  continue;
95804
96541
  }
@@ -95812,14 +96549,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95812
96549
  if (entryPhase !== String(phase)) {
95813
96550
  continue;
95814
96551
  }
95815
- const evidenceFilePath = path115.join(entryPath, "evidence.json");
96552
+ const evidenceFilePath = path118.join(entryPath, "evidence.json");
95816
96553
  try {
95817
- const resolvedPath = path115.resolve(evidenceFilePath);
95818
- const evidenceDirResolved = path115.resolve(evidenceDir);
95819
- if (!resolvedPath.startsWith(evidenceDirResolved + path115.sep)) {
96554
+ const resolvedPath = path118.resolve(evidenceFilePath);
96555
+ const evidenceDirResolved = path118.resolve(evidenceDir);
96556
+ if (!resolvedPath.startsWith(evidenceDirResolved + path118.sep)) {
95820
96557
  continue;
95821
96558
  }
95822
- const stat8 = fs89.lstatSync(evidenceFilePath);
96559
+ const stat8 = fs91.lstatSync(evidenceFilePath);
95823
96560
  if (!stat8.isFile()) {
95824
96561
  continue;
95825
96562
  }
@@ -95831,7 +96568,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95831
96568
  }
95832
96569
  let content;
95833
96570
  try {
95834
- content = fs89.readFileSync(evidenceFilePath, "utf-8");
96571
+ content = fs91.readFileSync(evidenceFilePath, "utf-8");
95835
96572
  } catch {
95836
96573
  continue;
95837
96574
  }
@@ -95850,7 +96587,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95850
96587
  if (Array.isArray(diffEntry.files_changed)) {
95851
96588
  for (const file3 of diffEntry.files_changed) {
95852
96589
  if (typeof file3 === "string") {
95853
- touchedFiles.add(path115.resolve(cwd, file3));
96590
+ touchedFiles.add(path118.resolve(cwd, file3));
95854
96591
  }
95855
96592
  }
95856
96593
  }
@@ -95863,12 +96600,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95863
96600
  }
95864
96601
  function searchFileForKeywords(filePath, keywords, cwd) {
95865
96602
  try {
95866
- const resolvedPath = path115.resolve(filePath);
95867
- const cwdResolved = path115.resolve(cwd);
96603
+ const resolvedPath = path118.resolve(filePath);
96604
+ const cwdResolved = path118.resolve(cwd);
95868
96605
  if (!resolvedPath.startsWith(cwdResolved)) {
95869
96606
  return false;
95870
96607
  }
95871
- const content = fs89.readFileSync(resolvedPath, "utf-8");
96608
+ const content = fs91.readFileSync(resolvedPath, "utf-8");
95872
96609
  for (const keyword of keywords) {
95873
96610
  const regex = new RegExp(`\\b${keyword}\\b`, "i");
95874
96611
  if (regex.test(content)) {
@@ -95998,10 +96735,10 @@ var req_coverage = createSwarmTool({
95998
96735
  }, null, 2);
95999
96736
  }
96000
96737
  const cwd = inputDirectory || directory;
96001
- const specPath = path115.join(cwd, SPEC_FILE);
96738
+ const specPath = path118.join(cwd, SPEC_FILE);
96002
96739
  let specContent;
96003
96740
  try {
96004
- specContent = fs89.readFileSync(specPath, "utf-8");
96741
+ specContent = fs91.readFileSync(specPath, "utf-8");
96005
96742
  } catch (readError) {
96006
96743
  return JSON.stringify({
96007
96744
  success: false,
@@ -96025,7 +96762,7 @@ var req_coverage = createSwarmTool({
96025
96762
  message: "No FR requirements found in spec.md"
96026
96763
  }, null, 2);
96027
96764
  }
96028
- const evidenceDir = path115.join(cwd, EVIDENCE_DIR4);
96765
+ const evidenceDir = path118.join(cwd, EVIDENCE_DIR4);
96029
96766
  const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
96030
96767
  const analyzedRequirements = [];
96031
96768
  let coveredCount = 0;
@@ -96051,12 +96788,12 @@ var req_coverage = createSwarmTool({
96051
96788
  requirements: analyzedRequirements
96052
96789
  };
96053
96790
  const reportFilename = `req-coverage-phase-${phase}.json`;
96054
- const reportPath = path115.join(evidenceDir, reportFilename);
96791
+ const reportPath = path118.join(evidenceDir, reportFilename);
96055
96792
  try {
96056
- if (!fs89.existsSync(evidenceDir)) {
96057
- fs89.mkdirSync(evidenceDir, { recursive: true });
96793
+ if (!fs91.existsSync(evidenceDir)) {
96794
+ fs91.mkdirSync(evidenceDir, { recursive: true });
96058
96795
  }
96059
- fs89.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
96796
+ fs91.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
96060
96797
  } catch (writeError) {
96061
96798
  console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
96062
96799
  }
@@ -96137,9 +96874,9 @@ init_zod();
96137
96874
  init_plan_schema();
96138
96875
  init_qa_gate_profile();
96139
96876
  init_file_locks();
96140
- import * as crypto10 from "node:crypto";
96141
- import * as fs90 from "node:fs";
96142
- import * as path116 from "node:path";
96877
+ import * as crypto11 from "node:crypto";
96878
+ import * as fs92 from "node:fs";
96879
+ import * as path119 from "node:path";
96143
96880
  init_ledger();
96144
96881
  init_manager();
96145
96882
  init_state();
@@ -96217,17 +96954,17 @@ async function executeSavePlan(args2, fallbackDir) {
96217
96954
  };
96218
96955
  }
96219
96956
  if (args2.working_directory && fallbackDir) {
96220
- const resolvedTarget = path116.resolve(args2.working_directory);
96221
- const resolvedRoot = path116.resolve(fallbackDir);
96957
+ const resolvedTarget = path119.resolve(args2.working_directory);
96958
+ const resolvedRoot = path119.resolve(fallbackDir);
96222
96959
  let fallbackExists = false;
96223
96960
  try {
96224
- fs90.accessSync(resolvedRoot, fs90.constants.F_OK);
96961
+ fs92.accessSync(resolvedRoot, fs92.constants.F_OK);
96225
96962
  fallbackExists = true;
96226
96963
  } catch {
96227
96964
  fallbackExists = false;
96228
96965
  }
96229
96966
  if (fallbackExists) {
96230
- const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path116.sep);
96967
+ const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path119.sep);
96231
96968
  if (isSubdirectory) {
96232
96969
  return {
96233
96970
  success: false,
@@ -96243,12 +96980,12 @@ async function executeSavePlan(args2, fallbackDir) {
96243
96980
  let specMtime;
96244
96981
  let specHash;
96245
96982
  if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
96246
- const specPath = path116.join(targetWorkspace, ".swarm", "spec.md");
96983
+ const specPath = path119.join(targetWorkspace, ".swarm", "spec.md");
96247
96984
  try {
96248
- const stat8 = await fs90.promises.stat(specPath);
96985
+ const stat8 = await fs92.promises.stat(specPath);
96249
96986
  specMtime = stat8.mtime.toISOString();
96250
- const content = await fs90.promises.readFile(specPath, "utf8");
96251
- specHash = crypto10.createHash("sha256").update(content).digest("hex");
96987
+ const content = await fs92.promises.readFile(specPath, "utf8");
96988
+ specHash = crypto11.createHash("sha256").update(content).digest("hex");
96252
96989
  } catch {
96253
96990
  return {
96254
96991
  success: false,
@@ -96259,10 +96996,10 @@ async function executeSavePlan(args2, fallbackDir) {
96259
96996
  }
96260
96997
  }
96261
96998
  if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
96262
- const contextPath = path116.join(targetWorkspace, ".swarm", "context.md");
96999
+ const contextPath = path119.join(targetWorkspace, ".swarm", "context.md");
96263
97000
  let contextContent = "";
96264
97001
  try {
96265
- contextContent = await fs90.promises.readFile(contextPath, "utf8");
97002
+ contextContent = await fs92.promises.readFile(contextPath, "utf8");
96266
97003
  } catch {}
96267
97004
  const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
96268
97005
  if (!hasPendingSection) {
@@ -96516,14 +97253,14 @@ async function executeSavePlan(args2, fallbackDir) {
96516
97253
  }
96517
97254
  await writeCheckpoint(dir).catch(() => {});
96518
97255
  try {
96519
- const markerPath = path116.join(dir, ".swarm", ".plan-write-marker");
97256
+ const markerPath = path119.join(dir, ".swarm", ".plan-write-marker");
96520
97257
  const marker = JSON.stringify({
96521
97258
  source: "save_plan",
96522
97259
  timestamp: new Date().toISOString(),
96523
97260
  phases_count: plan.phases.length,
96524
97261
  tasks_count: tasksCount
96525
97262
  });
96526
- await fs90.promises.writeFile(markerPath, marker, "utf8");
97263
+ await fs92.promises.writeFile(markerPath, marker, "utf8");
96527
97264
  } catch {}
96528
97265
  const warnings = [];
96529
97266
  let criticReviewFound = false;
@@ -96539,7 +97276,7 @@ async function executeSavePlan(args2, fallbackDir) {
96539
97276
  return {
96540
97277
  success: true,
96541
97278
  message: "Plan saved successfully",
96542
- plan_path: path116.join(dir, ".swarm", "plan.json"),
97279
+ plan_path: path119.join(dir, ".swarm", "plan.json"),
96543
97280
  phases_count: plan.phases.length,
96544
97281
  tasks_count: tasksCount,
96545
97282
  ...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
@@ -96603,8 +97340,8 @@ var save_plan = createSwarmTool({
96603
97340
  // src/tools/sbom-generate.ts
96604
97341
  init_zod();
96605
97342
  init_manager2();
96606
- import * as fs91 from "node:fs";
96607
- import * as path117 from "node:path";
97343
+ import * as fs93 from "node:fs";
97344
+ import * as path120 from "node:path";
96608
97345
 
96609
97346
  // src/sbom/detectors/index.ts
96610
97347
  init_utils();
@@ -97452,9 +98189,9 @@ function findManifestFiles(rootDir) {
97452
98189
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
97453
98190
  function searchDir(dir) {
97454
98191
  try {
97455
- const entries = fs91.readdirSync(dir, { withFileTypes: true });
98192
+ const entries = fs93.readdirSync(dir, { withFileTypes: true });
97456
98193
  for (const entry of entries) {
97457
- const fullPath = path117.join(dir, entry.name);
98194
+ const fullPath = path120.join(dir, entry.name);
97458
98195
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
97459
98196
  continue;
97460
98197
  }
@@ -97463,7 +98200,7 @@ function findManifestFiles(rootDir) {
97463
98200
  } else if (entry.isFile()) {
97464
98201
  for (const pattern of patterns) {
97465
98202
  if (simpleGlobToRegex(pattern).test(entry.name)) {
97466
- manifestFiles.push(path117.relative(rootDir, fullPath));
98203
+ manifestFiles.push(path120.relative(rootDir, fullPath));
97467
98204
  break;
97468
98205
  }
97469
98206
  }
@@ -97479,13 +98216,13 @@ function findManifestFilesInDirs(directories, workingDir) {
97479
98216
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
97480
98217
  for (const dir of directories) {
97481
98218
  try {
97482
- const entries = fs91.readdirSync(dir, { withFileTypes: true });
98219
+ const entries = fs93.readdirSync(dir, { withFileTypes: true });
97483
98220
  for (const entry of entries) {
97484
- const fullPath = path117.join(dir, entry.name);
98221
+ const fullPath = path120.join(dir, entry.name);
97485
98222
  if (entry.isFile()) {
97486
98223
  for (const pattern of patterns) {
97487
98224
  if (simpleGlobToRegex(pattern).test(entry.name)) {
97488
- found.push(path117.relative(workingDir, fullPath));
98225
+ found.push(path120.relative(workingDir, fullPath));
97489
98226
  break;
97490
98227
  }
97491
98228
  }
@@ -97498,11 +98235,11 @@ function findManifestFilesInDirs(directories, workingDir) {
97498
98235
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
97499
98236
  const dirs = new Set;
97500
98237
  for (const file3 of changedFiles) {
97501
- let currentDir = path117.dirname(file3);
98238
+ let currentDir = path120.dirname(file3);
97502
98239
  while (true) {
97503
- if (currentDir && currentDir !== "." && currentDir !== path117.sep) {
97504
- dirs.add(path117.join(workingDir, currentDir));
97505
- const parent = path117.dirname(currentDir);
98240
+ if (currentDir && currentDir !== "." && currentDir !== path120.sep) {
98241
+ dirs.add(path120.join(workingDir, currentDir));
98242
+ const parent = path120.dirname(currentDir);
97506
98243
  if (parent === currentDir)
97507
98244
  break;
97508
98245
  currentDir = parent;
@@ -97516,7 +98253,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
97516
98253
  }
97517
98254
  function ensureOutputDir(outputDir) {
97518
98255
  try {
97519
- fs91.mkdirSync(outputDir, { recursive: true });
98256
+ fs93.mkdirSync(outputDir, { recursive: true });
97520
98257
  } catch (error93) {
97521
98258
  if (!error93 || error93.code !== "EEXIST") {
97522
98259
  throw error93;
@@ -97586,7 +98323,7 @@ var sbom_generate = createSwarmTool({
97586
98323
  const changedFiles = obj.changed_files;
97587
98324
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
97588
98325
  const workingDir = directory;
97589
- const outputDir = path117.isAbsolute(relativeOutputDir) ? relativeOutputDir : path117.join(workingDir, relativeOutputDir);
98326
+ const outputDir = path120.isAbsolute(relativeOutputDir) ? relativeOutputDir : path120.join(workingDir, relativeOutputDir);
97590
98327
  let manifestFiles = [];
97591
98328
  if (scope === "all") {
97592
98329
  manifestFiles = findManifestFiles(workingDir);
@@ -97609,11 +98346,11 @@ var sbom_generate = createSwarmTool({
97609
98346
  const processedFiles = [];
97610
98347
  for (const manifestFile of manifestFiles) {
97611
98348
  try {
97612
- const fullPath = path117.isAbsolute(manifestFile) ? manifestFile : path117.join(workingDir, manifestFile);
97613
- if (!fs91.existsSync(fullPath)) {
98349
+ const fullPath = path120.isAbsolute(manifestFile) ? manifestFile : path120.join(workingDir, manifestFile);
98350
+ if (!fs93.existsSync(fullPath)) {
97614
98351
  continue;
97615
98352
  }
97616
- const content = fs91.readFileSync(fullPath, "utf-8");
98353
+ const content = fs93.readFileSync(fullPath, "utf-8");
97617
98354
  const components = detectComponents(manifestFile, content);
97618
98355
  processedFiles.push(manifestFile);
97619
98356
  if (components.length > 0) {
@@ -97626,8 +98363,8 @@ var sbom_generate = createSwarmTool({
97626
98363
  const bom = generateCycloneDX(allComponents);
97627
98364
  const bomJson = serializeCycloneDX(bom);
97628
98365
  const filename = generateSbomFilename();
97629
- const outputPath = path117.join(outputDir, filename);
97630
- fs91.writeFileSync(outputPath, bomJson, "utf-8");
98366
+ const outputPath = path120.join(outputDir, filename);
98367
+ fs93.writeFileSync(outputPath, bomJson, "utf-8");
97631
98368
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
97632
98369
  try {
97633
98370
  const timestamp = new Date().toISOString();
@@ -97669,8 +98406,8 @@ var sbom_generate = createSwarmTool({
97669
98406
  // src/tools/schema-drift.ts
97670
98407
  init_zod();
97671
98408
  init_create_tool();
97672
- import * as fs92 from "node:fs";
97673
- import * as path118 from "node:path";
98409
+ import * as fs94 from "node:fs";
98410
+ import * as path121 from "node:path";
97674
98411
  var SPEC_CANDIDATES = [
97675
98412
  "openapi.json",
97676
98413
  "openapi.yaml",
@@ -97702,28 +98439,28 @@ function normalizePath4(p) {
97702
98439
  }
97703
98440
  function discoverSpecFile(cwd, specFileArg) {
97704
98441
  if (specFileArg) {
97705
- const resolvedPath = path118.resolve(cwd, specFileArg);
97706
- const normalizedCwd = cwd.endsWith(path118.sep) ? cwd : cwd + path118.sep;
98442
+ const resolvedPath = path121.resolve(cwd, specFileArg);
98443
+ const normalizedCwd = cwd.endsWith(path121.sep) ? cwd : cwd + path121.sep;
97707
98444
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
97708
98445
  throw new Error("Invalid spec_file: path traversal detected");
97709
98446
  }
97710
- const ext = path118.extname(resolvedPath).toLowerCase();
98447
+ const ext = path121.extname(resolvedPath).toLowerCase();
97711
98448
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
97712
98449
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
97713
98450
  }
97714
- const stats = fs92.statSync(resolvedPath);
98451
+ const stats = fs94.statSync(resolvedPath);
97715
98452
  if (stats.size > MAX_SPEC_SIZE) {
97716
98453
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
97717
98454
  }
97718
- if (!fs92.existsSync(resolvedPath)) {
98455
+ if (!fs94.existsSync(resolvedPath)) {
97719
98456
  throw new Error(`Spec file not found: ${resolvedPath}`);
97720
98457
  }
97721
98458
  return resolvedPath;
97722
98459
  }
97723
98460
  for (const candidate of SPEC_CANDIDATES) {
97724
- const candidatePath = path118.resolve(cwd, candidate);
97725
- if (fs92.existsSync(candidatePath)) {
97726
- const stats = fs92.statSync(candidatePath);
98461
+ const candidatePath = path121.resolve(cwd, candidate);
98462
+ if (fs94.existsSync(candidatePath)) {
98463
+ const stats = fs94.statSync(candidatePath);
97727
98464
  if (stats.size <= MAX_SPEC_SIZE) {
97728
98465
  return candidatePath;
97729
98466
  }
@@ -97732,8 +98469,8 @@ function discoverSpecFile(cwd, specFileArg) {
97732
98469
  return null;
97733
98470
  }
97734
98471
  function parseSpec(specFile) {
97735
- const content = fs92.readFileSync(specFile, "utf-8");
97736
- const ext = path118.extname(specFile).toLowerCase();
98472
+ const content = fs94.readFileSync(specFile, "utf-8");
98473
+ const ext = path121.extname(specFile).toLowerCase();
97737
98474
  if (ext === ".json") {
97738
98475
  return parseJsonSpec(content);
97739
98476
  }
@@ -97804,12 +98541,12 @@ function extractRoutes(cwd) {
97804
98541
  function walkDir(dir) {
97805
98542
  let entries;
97806
98543
  try {
97807
- entries = fs92.readdirSync(dir, { withFileTypes: true });
98544
+ entries = fs94.readdirSync(dir, { withFileTypes: true });
97808
98545
  } catch {
97809
98546
  return;
97810
98547
  }
97811
98548
  for (const entry of entries) {
97812
- const fullPath = path118.join(dir, entry.name);
98549
+ const fullPath = path121.join(dir, entry.name);
97813
98550
  if (entry.isSymbolicLink()) {
97814
98551
  continue;
97815
98552
  }
@@ -97819,7 +98556,7 @@ function extractRoutes(cwd) {
97819
98556
  }
97820
98557
  walkDir(fullPath);
97821
98558
  } else if (entry.isFile()) {
97822
- const ext = path118.extname(entry.name).toLowerCase();
98559
+ const ext = path121.extname(entry.name).toLowerCase();
97823
98560
  const baseName = entry.name.toLowerCase();
97824
98561
  if (![".ts", ".js", ".mjs"].includes(ext)) {
97825
98562
  continue;
@@ -97837,7 +98574,7 @@ function extractRoutes(cwd) {
97837
98574
  }
97838
98575
  function extractRoutesFromFile(filePath) {
97839
98576
  const routes = [];
97840
- const content = fs92.readFileSync(filePath, "utf-8");
98577
+ const content = fs94.readFileSync(filePath, "utf-8");
97841
98578
  const lines = content.split(/\r?\n/);
97842
98579
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
97843
98580
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -97986,8 +98723,8 @@ init_zod();
97986
98723
  init_bun_compat();
97987
98724
  init_path_security();
97988
98725
  init_create_tool();
97989
- import * as fs93 from "node:fs";
97990
- import * as path119 from "node:path";
98726
+ import * as fs95 from "node:fs";
98727
+ import * as path122 from "node:path";
97991
98728
  var DEFAULT_MAX_RESULTS = 100;
97992
98729
  var DEFAULT_MAX_LINES = 200;
97993
98730
  var REGEX_TIMEOUT_MS = 5000;
@@ -98023,11 +98760,11 @@ function containsWindowsAttacks3(str) {
98023
98760
  }
98024
98761
  function isPathInWorkspace3(filePath, workspace) {
98025
98762
  try {
98026
- const resolvedPath = path119.resolve(workspace, filePath);
98027
- const realWorkspace = fs93.realpathSync(workspace);
98028
- const realResolvedPath = fs93.realpathSync(resolvedPath);
98029
- const relativePath = path119.relative(realWorkspace, realResolvedPath);
98030
- if (relativePath.startsWith("..") || path119.isAbsolute(relativePath)) {
98763
+ const resolvedPath = path122.resolve(workspace, filePath);
98764
+ const realWorkspace = fs95.realpathSync(workspace);
98765
+ const realResolvedPath = fs95.realpathSync(resolvedPath);
98766
+ const relativePath = path122.relative(realWorkspace, realResolvedPath);
98767
+ if (relativePath.startsWith("..") || path122.isAbsolute(relativePath)) {
98031
98768
  return false;
98032
98769
  }
98033
98770
  return true;
@@ -98040,12 +98777,12 @@ function validatePathForRead2(filePath, workspace) {
98040
98777
  }
98041
98778
  function findRgInEnvPath() {
98042
98779
  const searchPath = process.env.PATH ?? "";
98043
- for (const dir of searchPath.split(path119.delimiter)) {
98780
+ for (const dir of searchPath.split(path122.delimiter)) {
98044
98781
  if (!dir)
98045
98782
  continue;
98046
98783
  const isWindows = process.platform === "win32";
98047
- const candidate = path119.join(dir, isWindows ? "rg.exe" : "rg");
98048
- if (fs93.existsSync(candidate))
98784
+ const candidate = path122.join(dir, isWindows ? "rg.exe" : "rg");
98785
+ if (fs95.existsSync(candidate))
98049
98786
  return candidate;
98050
98787
  }
98051
98788
  return null;
@@ -98172,10 +98909,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
98172
98909
  return files;
98173
98910
  }
98174
98911
  try {
98175
- const entries = fs93.readdirSync(dir, { withFileTypes: true });
98912
+ const entries = fs95.readdirSync(dir, { withFileTypes: true });
98176
98913
  for (const entry of entries) {
98177
- const fullPath = path119.join(dir, entry.name);
98178
- const relativePath = path119.relative(workspace, fullPath);
98914
+ const fullPath = path122.join(dir, entry.name);
98915
+ const relativePath = path122.relative(workspace, fullPath);
98179
98916
  if (!validatePathForRead2(fullPath, workspace)) {
98180
98917
  continue;
98181
98918
  }
@@ -98216,13 +98953,13 @@ async function fallbackSearch(opts) {
98216
98953
  const matches = [];
98217
98954
  let total = 0;
98218
98955
  for (const file3 of files) {
98219
- const fullPath = path119.join(opts.workspace, file3);
98956
+ const fullPath = path122.join(opts.workspace, file3);
98220
98957
  if (!validatePathForRead2(fullPath, opts.workspace)) {
98221
98958
  continue;
98222
98959
  }
98223
98960
  let stats;
98224
98961
  try {
98225
- stats = fs93.statSync(fullPath);
98962
+ stats = fs95.statSync(fullPath);
98226
98963
  if (stats.size > MAX_FILE_SIZE_BYTES10) {
98227
98964
  continue;
98228
98965
  }
@@ -98231,7 +98968,7 @@ async function fallbackSearch(opts) {
98231
98968
  }
98232
98969
  let content;
98233
98970
  try {
98234
- content = fs93.readFileSync(fullPath, "utf-8");
98971
+ content = fs95.readFileSync(fullPath, "utf-8");
98235
98972
  } catch {
98236
98973
  continue;
98237
98974
  }
@@ -98343,7 +99080,7 @@ var search = createSwarmTool({
98343
99080
  message: "Exclude pattern contains invalid Windows-specific sequence"
98344
99081
  }, null, 2);
98345
99082
  }
98346
- if (!fs93.existsSync(directory)) {
99083
+ if (!fs95.existsSync(directory)) {
98347
99084
  return JSON.stringify({
98348
99085
  error: true,
98349
99086
  type: "unknown",
@@ -98584,7 +99321,7 @@ init_config();
98584
99321
  init_schema();
98585
99322
  init_create_tool();
98586
99323
  import { mkdir as mkdir19, rename as rename8, writeFile as writeFile15 } from "node:fs/promises";
98587
- import * as path120 from "node:path";
99324
+ import * as path123 from "node:path";
98588
99325
  var MAX_SPEC_BYTES = 256 * 1024;
98589
99326
  var spec_write = createSwarmTool({
98590
99327
  description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
@@ -98625,14 +99362,14 @@ var spec_write = createSwarmTool({
98625
99362
  reason: 'spec must contain at least one top-level "# Heading"'
98626
99363
  }, null, 2);
98627
99364
  }
98628
- const target = path120.join(directory, ".swarm", "spec.md");
98629
- await mkdir19(path120.dirname(target), { recursive: true });
99365
+ const target = path123.join(directory, ".swarm", "spec.md");
99366
+ await mkdir19(path123.dirname(target), { recursive: true });
98630
99367
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
98631
99368
  let finalContent = content;
98632
99369
  if (mode === "append") {
98633
99370
  try {
98634
- const fs94 = await import("node:fs/promises");
98635
- const prior = await fs94.readFile(target, "utf-8");
99371
+ const fs96 = await import("node:fs/promises");
99372
+ const prior = await fs96.readFile(target, "utf-8");
98636
99373
  finalContent = `${prior.replace(/\s+$/, "")}
98637
99374
 
98638
99375
  ${content}
@@ -98654,14 +99391,14 @@ ${content}
98654
99391
  init_zod();
98655
99392
  init_loader();
98656
99393
  import {
98657
- existsSync as existsSync70,
98658
- mkdirSync as mkdirSync29,
98659
- readFileSync as readFileSync61,
98660
- renameSync as renameSync19,
99394
+ existsSync as existsSync72,
99395
+ mkdirSync as mkdirSync31,
99396
+ readFileSync as readFileSync62,
99397
+ renameSync as renameSync20,
98661
99398
  unlinkSync as unlinkSync15,
98662
- writeFileSync as writeFileSync23
99399
+ writeFileSync as writeFileSync24
98663
99400
  } from "node:fs";
98664
- import path121 from "node:path";
99401
+ import path124 from "node:path";
98665
99402
  init_create_tool();
98666
99403
  init_resolve_working_directory();
98667
99404
  var VerdictSchema2 = exports_external.object({
@@ -98791,9 +99528,9 @@ var submit_phase_council_verdicts = createSwarmTool({
98791
99528
  }
98792
99529
  });
98793
99530
  function getPhaseMutationGapFinding(phaseNumber, workingDir) {
98794
- const mutationGatePath = path121.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
99531
+ const mutationGatePath = path124.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
98795
99532
  try {
98796
- const raw = readFileSync61(mutationGatePath, "utf-8");
99533
+ const raw = readFileSync62(mutationGatePath, "utf-8");
98797
99534
  const parsed = JSON.parse(raw);
98798
99535
  const gateEntry = (parsed.entries ?? []).find((entry) => entry?.type === "mutation-gate");
98799
99536
  if (!gateEntry) {
@@ -98853,9 +99590,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
98853
99590
  }
98854
99591
  }
98855
99592
  function writePhaseCouncilEvidence(workingDir, synthesis) {
98856
- const evidenceDir = path121.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
98857
- mkdirSync29(evidenceDir, { recursive: true });
98858
- const evidenceFile = path121.join(evidenceDir, "phase-council.json");
99593
+ const evidenceDir = path124.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
99594
+ mkdirSync31(evidenceDir, { recursive: true });
99595
+ const evidenceFile = path124.join(evidenceDir, "phase-council.json");
98859
99596
  const evidenceBundle = {
98860
99597
  entries: [
98861
99598
  {
@@ -98888,10 +99625,10 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
98888
99625
  };
98889
99626
  const tempFile = `${evidenceFile}.tmp-${Date.now()}`;
98890
99627
  try {
98891
- writeFileSync23(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
98892
- renameSync19(tempFile, evidenceFile);
99628
+ writeFileSync24(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
99629
+ renameSync20(tempFile, evidenceFile);
98893
99630
  } finally {
98894
- if (existsSync70(tempFile)) {
99631
+ if (existsSync72(tempFile)) {
98895
99632
  unlinkSync15(tempFile);
98896
99633
  }
98897
99634
  }
@@ -98940,8 +99677,8 @@ function createSwarmCommandTool(agents) {
98940
99677
  init_zod();
98941
99678
  init_path_security();
98942
99679
  init_create_tool();
98943
- import * as fs94 from "node:fs";
98944
- import * as path122 from "node:path";
99680
+ import * as fs96 from "node:fs";
99681
+ import * as path125 from "node:path";
98945
99682
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
98946
99683
  function containsWindowsAttacks4(str) {
98947
99684
  if (/:[^\\/]/.test(str))
@@ -98955,14 +99692,14 @@ function containsWindowsAttacks4(str) {
98955
99692
  }
98956
99693
  function isPathInWorkspace4(filePath, workspace) {
98957
99694
  try {
98958
- const resolvedPath = path122.resolve(workspace, filePath);
98959
- if (!fs94.existsSync(resolvedPath)) {
99695
+ const resolvedPath = path125.resolve(workspace, filePath);
99696
+ if (!fs96.existsSync(resolvedPath)) {
98960
99697
  return true;
98961
99698
  }
98962
- const realWorkspace = fs94.realpathSync(workspace);
98963
- const realResolvedPath = fs94.realpathSync(resolvedPath);
98964
- const relativePath = path122.relative(realWorkspace, realResolvedPath);
98965
- if (relativePath.startsWith("..") || path122.isAbsolute(relativePath)) {
99699
+ const realWorkspace = fs96.realpathSync(workspace);
99700
+ const realResolvedPath = fs96.realpathSync(resolvedPath);
99701
+ const relativePath = path125.relative(realWorkspace, realResolvedPath);
99702
+ if (relativePath.startsWith("..") || path125.isAbsolute(relativePath)) {
98966
99703
  return false;
98967
99704
  }
98968
99705
  return true;
@@ -99134,7 +99871,7 @@ var suggestPatch = createSwarmTool({
99134
99871
  message: "changes cannot be empty"
99135
99872
  }, null, 2);
99136
99873
  }
99137
- if (!fs94.existsSync(directory)) {
99874
+ if (!fs96.existsSync(directory)) {
99138
99875
  return JSON.stringify({
99139
99876
  success: false,
99140
99877
  error: true,
@@ -99170,8 +99907,8 @@ var suggestPatch = createSwarmTool({
99170
99907
  });
99171
99908
  continue;
99172
99909
  }
99173
- const fullPath = path122.resolve(directory, change.file);
99174
- if (!fs94.existsSync(fullPath)) {
99910
+ const fullPath = path125.resolve(directory, change.file);
99911
+ if (!fs96.existsSync(fullPath)) {
99175
99912
  errors5.push({
99176
99913
  success: false,
99177
99914
  error: true,
@@ -99185,7 +99922,7 @@ var suggestPatch = createSwarmTool({
99185
99922
  }
99186
99923
  let content;
99187
99924
  try {
99188
- content = fs94.readFileSync(fullPath, "utf-8");
99925
+ content = fs96.readFileSync(fullPath, "utf-8");
99189
99926
  } catch (err3) {
99190
99927
  errors5.push({
99191
99928
  success: false,
@@ -99473,12 +100210,12 @@ var lean_turbo_acquire_locks = createSwarmTool({
99473
100210
  // src/tools/lean-turbo-plan-lanes.ts
99474
100211
  init_zod();
99475
100212
  init_constants();
99476
- import * as fs96 from "node:fs";
99477
- import * as path124 from "node:path";
100213
+ import * as fs98 from "node:fs";
100214
+ import * as path127 from "node:path";
99478
100215
 
99479
100216
  // src/turbo/lean/conflicts.ts
99480
- import * as fs95 from "node:fs";
99481
- import * as path123 from "node:path";
100217
+ import * as fs97 from "node:fs";
100218
+ import * as path126 from "node:path";
99482
100219
  var DEFAULT_GLOBAL_FILES = [
99483
100220
  "package.json",
99484
100221
  "package-lock.json",
@@ -99605,12 +100342,12 @@ function isProtectedPath2(normalizedPath) {
99605
100342
  return false;
99606
100343
  }
99607
100344
  function readTaskScopes(directory, taskId) {
99608
- const scopePath = path123.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
100345
+ const scopePath = path126.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
99609
100346
  try {
99610
- if (!fs95.existsSync(scopePath)) {
100347
+ if (!fs97.existsSync(scopePath)) {
99611
100348
  return null;
99612
100349
  }
99613
- const raw = fs95.readFileSync(scopePath, "utf-8");
100350
+ const raw = fs97.readFileSync(scopePath, "utf-8");
99614
100351
  const parsed = JSON.parse(raw);
99615
100352
  if (!parsed || !Array.isArray(parsed.files)) {
99616
100353
  return null;
@@ -99993,12 +100730,12 @@ function createEmptyPlan(phaseNumber, planId) {
99993
100730
  // src/tools/lean-turbo-plan-lanes.ts
99994
100731
  init_create_tool();
99995
100732
  function readPlanJson(directory) {
99996
- const planPath = path124.join(directory, ".swarm", "plan.json");
99997
- if (!fs96.existsSync(planPath)) {
100733
+ const planPath = path127.join(directory, ".swarm", "plan.json");
100734
+ if (!fs98.existsSync(planPath)) {
99998
100735
  return null;
99999
100736
  }
100000
100737
  try {
100001
- return JSON.parse(fs96.readFileSync(planPath, "utf-8"));
100738
+ return JSON.parse(fs98.readFileSync(planPath, "utf-8"));
100002
100739
  } catch {
100003
100740
  return null;
100004
100741
  }
@@ -100047,8 +100784,8 @@ init_config();
100047
100784
 
100048
100785
  // src/turbo/lean/reviewer.ts
100049
100786
  init_state();
100050
- import * as fs97 from "node:fs/promises";
100051
- import * as path125 from "node:path";
100787
+ import * as fs99 from "node:fs/promises";
100788
+ import * as path128 from "node:path";
100052
100789
  init_state3();
100053
100790
  var DEFAULT_CONFIG3 = {
100054
100791
  reviewerAgent: "",
@@ -100070,7 +100807,7 @@ function resolveDefaultReviewerAgent(generatedAgentNames) {
100070
100807
  }
100071
100808
  async function compileReviewPackage(directory, phase, sessionID, requireDiffSummary) {
100072
100809
  const lanes = await listLaneEvidence(directory, phase);
100073
- const persisted = _internals45.readPersisted?.(directory) ?? null;
100810
+ const persisted = _internals48.readPersisted?.(directory) ?? null;
100074
100811
  if (persisted) {
100075
100812
  let matchingRunState = null;
100076
100813
  for (const sessionState of Object.values(persisted.sessions)) {
@@ -100164,9 +100901,9 @@ function parseReviewerVerdict(responseText) {
100164
100901
  return { verdict, reason };
100165
100902
  }
100166
100903
  async function writeReviewerEvidence(directory, phase, verdict, reason) {
100167
- const evidenceDir = path125.join(directory, ".swarm", "evidence", String(phase));
100168
- await fs97.mkdir(evidenceDir, { recursive: true });
100169
- const evidencePath = path125.join(evidenceDir, "lean-turbo-reviewer.json");
100904
+ const evidenceDir = path128.join(directory, ".swarm", "evidence", String(phase));
100905
+ await fs99.mkdir(evidenceDir, { recursive: true });
100906
+ const evidencePath = path128.join(evidenceDir, "lean-turbo-reviewer.json");
100170
100907
  const content = JSON.stringify({
100171
100908
  phase,
100172
100909
  verdict,
@@ -100175,11 +100912,11 @@ async function writeReviewerEvidence(directory, phase, verdict, reason) {
100175
100912
  }, null, 2);
100176
100913
  const tempPath = `${evidencePath}.tmp.${process.pid}.${Date.now()}`;
100177
100914
  try {
100178
- await fs97.writeFile(tempPath, content, "utf-8");
100179
- await fs97.rename(tempPath, evidencePath);
100915
+ await fs99.writeFile(tempPath, content, "utf-8");
100916
+ await fs99.rename(tempPath, evidencePath);
100180
100917
  } catch (error93) {
100181
100918
  try {
100182
- await fs97.unlink(tempPath);
100919
+ await fs99.unlink(tempPath);
100183
100920
  } catch {}
100184
100921
  throw error93;
100185
100922
  }
@@ -100262,7 +100999,7 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
100262
100999
  client.session.delete({ path: { id: sessionId } }).catch(() => {});
100263
101000
  }
100264
101001
  }
100265
- var _internals45 = {
101002
+ var _internals48 = {
100266
101003
  compileReviewPackage,
100267
101004
  parseReviewerVerdict,
100268
101005
  writeReviewerEvidence,
@@ -100279,28 +101016,28 @@ async function dispatchPhaseReviewer(directory, phase, sessionID, config3) {
100279
101016
  };
100280
101017
  const generatedAgentNames = swarmState.generatedAgentNames;
100281
101018
  const agentName = mergedConfig.reviewerAgent || resolveDefaultReviewerAgent(generatedAgentNames);
100282
- const pkg = await _internals45.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
101019
+ const pkg = await _internals48.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
100283
101020
  let responseText;
100284
101021
  try {
100285
- responseText = await _internals45.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
101022
+ responseText = await _internals48.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
100286
101023
  } catch (error93) {
100287
- const evidencePath2 = await _internals45.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
101024
+ const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
100288
101025
  return {
100289
101026
  verdict: "REJECTED",
100290
101027
  reason: `Reviewer dispatch failed: ${error93 instanceof Error ? error93.message : String(error93)}`,
100291
101028
  evidencePath: evidencePath2
100292
101029
  };
100293
101030
  }
100294
- const parsed = _internals45.parseReviewerVerdict(responseText);
101031
+ const parsed = _internals48.parseReviewerVerdict(responseText);
100295
101032
  if (!parsed) {
100296
- const evidencePath2 = await _internals45.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
101033
+ const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
100297
101034
  return {
100298
101035
  verdict: "REJECTED",
100299
101036
  reason: "Reviewer response could not be parsed",
100300
101037
  evidencePath: evidencePath2
100301
101038
  };
100302
101039
  }
100303
- const evidencePath = await _internals45.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
101040
+ const evidencePath = await _internals48.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
100304
101041
  return {
100305
101042
  verdict: parsed.verdict,
100306
101043
  reason: parsed.reason,
@@ -100806,7 +101543,7 @@ ${fileList}
100806
101543
 
100807
101544
  // src/tools/lean-turbo-run-phase.ts
100808
101545
  init_create_tool();
100809
- var _internals46 = {
101546
+ var _internals49 = {
100810
101547
  LeanTurboRunner,
100811
101548
  loadPluginConfigWithMeta
100812
101549
  };
@@ -100816,9 +101553,9 @@ async function executeLeanTurboRunPhase(args2) {
100816
101553
  let runError = null;
100817
101554
  let runner = null;
100818
101555
  try {
100819
- const { config: config3 } = _internals46.loadPluginConfigWithMeta(directory);
101556
+ const { config: config3 } = _internals49.loadPluginConfigWithMeta(directory);
100820
101557
  const leanConfig = config3.turbo?.strategy === "lean" ? config3.turbo.lean : undefined;
100821
- runner = new _internals46.LeanTurboRunner({
101558
+ runner = new _internals49.LeanTurboRunner({
100822
101559
  directory,
100823
101560
  sessionID,
100824
101561
  opencodeClient: swarmState.opencodeClient ?? null,
@@ -100970,8 +101707,8 @@ var lean_turbo_status = createSwarmTool({
100970
101707
  // src/tools/lint-spec.ts
100971
101708
  init_spec_schema();
100972
101709
  init_create_tool();
100973
- import * as fs98 from "node:fs";
100974
- import * as path126 from "node:path";
101710
+ import * as fs100 from "node:fs";
101711
+ import * as path129 from "node:path";
100975
101712
  var SPEC_FILE_NAME = "spec.md";
100976
101713
  var SWARM_DIR2 = ".swarm";
100977
101714
  var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
@@ -101024,8 +101761,8 @@ var lint_spec = createSwarmTool({
101024
101761
  async execute(_args, directory) {
101025
101762
  const errors5 = [];
101026
101763
  const warnings = [];
101027
- const specPath = path126.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
101028
- if (!fs98.existsSync(specPath)) {
101764
+ const specPath = path129.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
101765
+ if (!fs100.existsSync(specPath)) {
101029
101766
  const result2 = {
101030
101767
  valid: false,
101031
101768
  specMtime: null,
@@ -101044,12 +101781,12 @@ var lint_spec = createSwarmTool({
101044
101781
  }
101045
101782
  let specMtime = null;
101046
101783
  try {
101047
- const stats = fs98.statSync(specPath);
101784
+ const stats = fs100.statSync(specPath);
101048
101785
  specMtime = stats.mtime.toISOString();
101049
101786
  } catch {}
101050
101787
  let content;
101051
101788
  try {
101052
- content = fs98.readFileSync(specPath, "utf-8");
101789
+ content = fs100.readFileSync(specPath, "utf-8");
101053
101790
  } catch (e) {
101054
101791
  const result2 = {
101055
101792
  valid: false,
@@ -101094,13 +101831,13 @@ var lint_spec = createSwarmTool({
101094
101831
  });
101095
101832
  // src/tools/mutation-test.ts
101096
101833
  init_zod();
101097
- import * as fs99 from "node:fs";
101098
- import * as path128 from "node:path";
101834
+ import * as fs101 from "node:fs";
101835
+ import * as path131 from "node:path";
101099
101836
 
101100
101837
  // src/mutation/engine.ts
101101
101838
  import { spawnSync as spawnSync3 } from "node:child_process";
101102
- import { unlinkSync as unlinkSync16, writeFileSync as writeFileSync24 } from "node:fs";
101103
- import * as path127 from "node:path";
101839
+ import { unlinkSync as unlinkSync16, writeFileSync as writeFileSync25 } from "node:fs";
101840
+ import * as path130 from "node:path";
101104
101841
 
101105
101842
  // src/mutation/equivalence.ts
101106
101843
  function isStaticallyEquivalent(originalCode, mutatedCode) {
@@ -101172,7 +101909,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
101172
101909
  const strippedMutated = stripCode(mutatedCode);
101173
101910
  return strippedOriginal === strippedMutated;
101174
101911
  }
101175
- var _internals47 = {
101912
+ var _internals50 = {
101176
101913
  isStaticallyEquivalent,
101177
101914
  checkEquivalence,
101178
101915
  batchCheckEquivalence
@@ -101212,7 +101949,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
101212
101949
  const results = [];
101213
101950
  for (const { patch, originalCode, mutatedCode } of patches) {
101214
101951
  try {
101215
- const result = await _internals47.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
101952
+ const result = await _internals50.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
101216
101953
  results.push(result);
101217
101954
  } catch (err3) {
101218
101955
  results.push({
@@ -101240,9 +101977,9 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
101240
101977
  let patchFile;
101241
101978
  try {
101242
101979
  const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
101243
- patchFile = path127.join(workingDir, `.mutation_patch_${safeId2}.diff`);
101980
+ patchFile = path130.join(workingDir, `.mutation_patch_${safeId2}.diff`);
101244
101981
  try {
101245
- writeFileSync24(patchFile, patch.patch);
101982
+ writeFileSync25(patchFile, patch.patch);
101246
101983
  } catch (writeErr) {
101247
101984
  error93 = `Failed to write patch file: ${writeErr}`;
101248
101985
  outcome = "error";
@@ -101512,7 +102249,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
101512
102249
  }
101513
102250
 
101514
102251
  // src/mutation/gate.ts
101515
- var _internals48 = {
102252
+ var _internals51 = {
101516
102253
  evaluateMutationGate,
101517
102254
  buildTestImprovementPrompt,
101518
102255
  buildMessage
@@ -101533,8 +102270,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
101533
102270
  } else {
101534
102271
  verdict = "fail";
101535
102272
  }
101536
- const testImprovementPrompt = _internals48.buildTestImprovementPrompt(report, passThreshold, verdict);
101537
- const message = _internals48.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
102273
+ const testImprovementPrompt = _internals51.buildTestImprovementPrompt(report, passThreshold, verdict);
102274
+ const message = _internals51.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
101538
102275
  return {
101539
102276
  verdict,
101540
102277
  killRate: report.killRate,
@@ -101639,8 +102376,8 @@ var mutation_test = createSwarmTool({
101639
102376
  ];
101640
102377
  for (const filePath of uniquePaths) {
101641
102378
  try {
101642
- const resolvedPath = path128.resolve(cwd, filePath);
101643
- sourceFiles.set(filePath, fs99.readFileSync(resolvedPath, "utf-8"));
102379
+ const resolvedPath = path131.resolve(cwd, filePath);
102380
+ sourceFiles.set(filePath, fs101.readFileSync(resolvedPath, "utf-8"));
101644
102381
  } catch {}
101645
102382
  }
101646
102383
  const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
@@ -101658,8 +102395,8 @@ var mutation_test = createSwarmTool({
101658
102395
  init_zod();
101659
102396
  init_manager2();
101660
102397
  init_detector();
101661
- import * as fs100 from "node:fs";
101662
- import * as path129 from "node:path";
102398
+ import * as fs102 from "node:fs";
102399
+ import * as path132 from "node:path";
101663
102400
  init_create_tool();
101664
102401
  var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
101665
102402
  var BINARY_CHECK_BYTES = 8192;
@@ -101725,7 +102462,7 @@ async function syntaxCheck(input, directory, config3) {
101725
102462
  if (languages?.length) {
101726
102463
  const lowerLangs = languages.map((l) => l.toLowerCase());
101727
102464
  filesToCheck = filesToCheck.filter((file3) => {
101728
- const ext = path129.extname(file3.path).toLowerCase();
102465
+ const ext = path132.extname(file3.path).toLowerCase();
101729
102466
  const langDef = getLanguageForExtension(ext);
101730
102467
  const fileProfile = getProfileForFile(file3.path);
101731
102468
  const langId = fileProfile?.id || langDef?.id;
@@ -101738,7 +102475,7 @@ async function syntaxCheck(input, directory, config3) {
101738
102475
  let skippedCount = 0;
101739
102476
  for (const fileInfo of filesToCheck) {
101740
102477
  const { path: filePath } = fileInfo;
101741
- const fullPath = path129.isAbsolute(filePath) ? filePath : path129.join(directory, filePath);
102478
+ const fullPath = path132.isAbsolute(filePath) ? filePath : path132.join(directory, filePath);
101742
102479
  const result = {
101743
102480
  path: filePath,
101744
102481
  language: "",
@@ -101768,7 +102505,7 @@ async function syntaxCheck(input, directory, config3) {
101768
102505
  }
101769
102506
  let content;
101770
102507
  try {
101771
- content = fs100.readFileSync(fullPath, "utf8");
102508
+ content = fs102.readFileSync(fullPath, "utf8");
101772
102509
  } catch {
101773
102510
  result.skipped_reason = "file_read_error";
101774
102511
  skippedCount++;
@@ -101787,7 +102524,7 @@ async function syntaxCheck(input, directory, config3) {
101787
102524
  results.push(result);
101788
102525
  continue;
101789
102526
  }
101790
- const ext = path129.extname(filePath).toLowerCase();
102527
+ const ext = path132.extname(filePath).toLowerCase();
101791
102528
  const langDef = getLanguageForExtension(ext);
101792
102529
  result.language = profile?.id || langDef?.id || "unknown";
101793
102530
  const errors5 = extractSyntaxErrors(parser, content);
@@ -101879,8 +102616,8 @@ init_zod();
101879
102616
  init_utils();
101880
102617
  init_create_tool();
101881
102618
  init_path_security();
101882
- import * as fs101 from "node:fs";
101883
- import * as path130 from "node:path";
102619
+ import * as fs103 from "node:fs";
102620
+ import * as path133 from "node:path";
101884
102621
  var MAX_TEXT_LENGTH = 200;
101885
102622
  var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
101886
102623
  var SUPPORTED_EXTENSIONS4 = new Set([
@@ -101946,9 +102683,9 @@ function validatePathsInput(paths, cwd) {
101946
102683
  return { error: "paths contains path traversal", resolvedPath: null };
101947
102684
  }
101948
102685
  try {
101949
- const resolvedPath = path130.resolve(paths);
101950
- const normalizedCwd = path130.resolve(cwd);
101951
- const normalizedResolved = path130.resolve(resolvedPath);
102686
+ const resolvedPath = path133.resolve(paths);
102687
+ const normalizedCwd = path133.resolve(cwd);
102688
+ const normalizedResolved = path133.resolve(resolvedPath);
101952
102689
  if (!normalizedResolved.startsWith(normalizedCwd)) {
101953
102690
  return {
101954
102691
  error: "paths must be within the current working directory",
@@ -101964,13 +102701,13 @@ function validatePathsInput(paths, cwd) {
101964
102701
  }
101965
102702
  }
101966
102703
  function isSupportedExtension(filePath) {
101967
- const ext = path130.extname(filePath).toLowerCase();
102704
+ const ext = path133.extname(filePath).toLowerCase();
101968
102705
  return SUPPORTED_EXTENSIONS4.has(ext);
101969
102706
  }
101970
102707
  function findSourceFiles3(dir, files = []) {
101971
102708
  let entries;
101972
102709
  try {
101973
- entries = fs101.readdirSync(dir);
102710
+ entries = fs103.readdirSync(dir);
101974
102711
  } catch {
101975
102712
  return files;
101976
102713
  }
@@ -101979,10 +102716,10 @@ function findSourceFiles3(dir, files = []) {
101979
102716
  if (SKIP_DIRECTORIES5.has(entry)) {
101980
102717
  continue;
101981
102718
  }
101982
- const fullPath = path130.join(dir, entry);
102719
+ const fullPath = path133.join(dir, entry);
101983
102720
  let stat8;
101984
102721
  try {
101985
- stat8 = fs101.statSync(fullPath);
102722
+ stat8 = fs103.statSync(fullPath);
101986
102723
  } catch {
101987
102724
  continue;
101988
102725
  }
@@ -102075,7 +102812,7 @@ var todo_extract = createSwarmTool({
102075
102812
  return JSON.stringify(errorResult, null, 2);
102076
102813
  }
102077
102814
  const scanPath = resolvedPath;
102078
- if (!fs101.existsSync(scanPath)) {
102815
+ if (!fs103.existsSync(scanPath)) {
102079
102816
  const errorResult = {
102080
102817
  error: `path not found: ${pathsInput}`,
102081
102818
  total: 0,
@@ -102085,13 +102822,13 @@ var todo_extract = createSwarmTool({
102085
102822
  return JSON.stringify(errorResult, null, 2);
102086
102823
  }
102087
102824
  const filesToScan = [];
102088
- const stat8 = fs101.statSync(scanPath);
102825
+ const stat8 = fs103.statSync(scanPath);
102089
102826
  if (stat8.isFile()) {
102090
102827
  if (isSupportedExtension(scanPath)) {
102091
102828
  filesToScan.push(scanPath);
102092
102829
  } else {
102093
102830
  const errorResult = {
102094
- error: `unsupported file extension: ${path130.extname(scanPath)}`,
102831
+ error: `unsupported file extension: ${path133.extname(scanPath)}`,
102095
102832
  total: 0,
102096
102833
  byPriority: { high: 0, medium: 0, low: 0 },
102097
102834
  entries: []
@@ -102104,11 +102841,11 @@ var todo_extract = createSwarmTool({
102104
102841
  const allEntries = [];
102105
102842
  for (const filePath of filesToScan) {
102106
102843
  try {
102107
- const fileStat = fs101.statSync(filePath);
102844
+ const fileStat = fs103.statSync(filePath);
102108
102845
  if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
102109
102846
  continue;
102110
102847
  }
102111
- const content = fs101.readFileSync(filePath, "utf-8");
102848
+ const content = fs103.readFileSync(filePath, "utf-8");
102112
102849
  const entries = parseTodoComments(content, filePath, tagsSet);
102113
102850
  allEntries.push(...entries);
102114
102851
  } catch {}
@@ -102139,19 +102876,19 @@ init_loader();
102139
102876
  init_schema();
102140
102877
  init_qa_gate_profile();
102141
102878
  init_gate_evidence();
102142
- import * as fs105 from "node:fs";
102143
- import * as path134 from "node:path";
102879
+ import * as fs107 from "node:fs";
102880
+ import * as path137 from "node:path";
102144
102881
 
102145
102882
  // src/hooks/diff-scope.ts
102146
102883
  init_bun_compat();
102147
- import * as fs103 from "node:fs";
102148
- import * as path132 from "node:path";
102884
+ import * as fs105 from "node:fs";
102885
+ import * as path135 from "node:path";
102149
102886
 
102150
102887
  // src/utils/gitignore-warning.ts
102151
102888
  init_bun_compat();
102152
- import * as fs102 from "node:fs";
102153
- import * as path131 from "node:path";
102154
- var _internals49 = { bunSpawn };
102889
+ import * as fs104 from "node:fs";
102890
+ import * as path134 from "node:path";
102891
+ var _internals52 = { bunSpawn };
102155
102892
  var _swarmGitExcludedChecked = false;
102156
102893
  function fileCoversSwarm(content) {
102157
102894
  for (const rawLine of content.split(`
@@ -102184,7 +102921,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102184
102921
  checkIgnoreExitCode
102185
102922
  ] = await Promise.all([
102186
102923
  (async () => {
102187
- const proc = _internals49.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
102924
+ const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
102188
102925
  try {
102189
102926
  return await Promise.all([proc.exited, proc.stdout.text()]);
102190
102927
  } finally {
@@ -102194,7 +102931,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102194
102931
  }
102195
102932
  })(),
102196
102933
  (async () => {
102197
- const proc = _internals49.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
102934
+ const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
102198
102935
  try {
102199
102936
  return await Promise.all([proc.exited, proc.stdout.text()]);
102200
102937
  } finally {
@@ -102204,7 +102941,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102204
102941
  }
102205
102942
  })(),
102206
102943
  (async () => {
102207
- const proc = _internals49.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
102944
+ const proc = _internals52.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
102208
102945
  try {
102209
102946
  return await proc.exited;
102210
102947
  } finally {
@@ -102224,16 +102961,16 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102224
102961
  const excludeRelPath = excludePathRaw.trim();
102225
102962
  if (!excludeRelPath)
102226
102963
  return;
102227
- const excludePath = path131.isAbsolute(excludeRelPath) ? excludeRelPath : path131.join(directory, excludeRelPath);
102964
+ const excludePath = path134.isAbsolute(excludeRelPath) ? excludeRelPath : path134.join(directory, excludeRelPath);
102228
102965
  if (checkIgnoreExitCode !== 0) {
102229
102966
  try {
102230
- fs102.mkdirSync(path131.dirname(excludePath), { recursive: true });
102967
+ fs104.mkdirSync(path134.dirname(excludePath), { recursive: true });
102231
102968
  let existing = "";
102232
102969
  try {
102233
- existing = fs102.readFileSync(excludePath, "utf8");
102970
+ existing = fs104.readFileSync(excludePath, "utf8");
102234
102971
  } catch {}
102235
102972
  if (!fileCoversSwarm(existing)) {
102236
- fs102.appendFileSync(excludePath, `
102973
+ fs104.appendFileSync(excludePath, `
102237
102974
  # opencode-swarm local runtime state
102238
102975
  .swarm/
102239
102976
  `, "utf8");
@@ -102243,7 +102980,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102243
102980
  }
102244
102981
  } catch {}
102245
102982
  }
102246
- const trackedProc = _internals49.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
102983
+ const trackedProc = _internals52.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
102247
102984
  let trackedExitCode;
102248
102985
  let trackedOutput;
102249
102986
  try {
@@ -102268,13 +103005,13 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102268
103005
  }
102269
103006
 
102270
103007
  // src/hooks/diff-scope.ts
102271
- var _internals50 = { bunSpawn };
103008
+ var _internals53 = { bunSpawn };
102272
103009
  function getDeclaredScope(taskId, directory) {
102273
103010
  try {
102274
- const planPath = path132.join(directory, ".swarm", "plan.json");
102275
- if (!fs103.existsSync(planPath))
103011
+ const planPath = path135.join(directory, ".swarm", "plan.json");
103012
+ if (!fs105.existsSync(planPath))
102276
103013
  return null;
102277
- const raw = fs103.readFileSync(planPath, "utf-8");
103014
+ const raw = fs105.readFileSync(planPath, "utf-8");
102278
103015
  const plan = JSON.parse(raw);
102279
103016
  for (const phase of plan.phases ?? []) {
102280
103017
  for (const task of phase.tasks ?? []) {
@@ -102303,7 +103040,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
102303
103040
  };
102304
103041
  async function getChangedFiles(directory) {
102305
103042
  try {
102306
- const proc = _internals50.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
103043
+ const proc = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
102307
103044
  cwd: directory,
102308
103045
  ...GIT_DIFF_SPAWN_OPTIONS
102309
103046
  });
@@ -102320,7 +103057,7 @@ async function getChangedFiles(directory) {
102320
103057
  return stdout.trim().split(`
102321
103058
  `).map((f) => f.trim()).filter((f) => f.length > 0);
102322
103059
  }
102323
- const proc2 = _internals50.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
103060
+ const proc2 = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
102324
103061
  cwd: directory,
102325
103062
  ...GIT_DIFF_SPAWN_OPTIONS
102326
103063
  });
@@ -102376,9 +103113,9 @@ init_telemetry();
102376
103113
 
102377
103114
  // src/turbo/lean/task-completion.ts
102378
103115
  init_file_locks();
102379
- import * as fs104 from "node:fs";
102380
- import * as path133 from "node:path";
102381
- var _internals51 = {
103116
+ import * as fs106 from "node:fs";
103117
+ import * as path136 from "node:path";
103118
+ var _internals54 = {
102382
103119
  listActiveLocks,
102383
103120
  verifyLeanTurboTaskCompletion
102384
103121
  };
@@ -102396,7 +103133,7 @@ var TIER_3_PATTERNS = [
102396
103133
  ];
102397
103134
  function matchesTier3Pattern(files) {
102398
103135
  for (const file3 of files) {
102399
- const fileName = path133.basename(file3);
103136
+ const fileName = path136.basename(file3);
102400
103137
  for (const pattern of TIER_3_PATTERNS) {
102401
103138
  if (pattern.test(fileName)) {
102402
103139
  return true;
@@ -102408,14 +103145,14 @@ function matchesTier3Pattern(files) {
102408
103145
  function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102409
103146
  let persisted = null;
102410
103147
  try {
102411
- const statePath = path133.join(directory, ".swarm", "turbo-state.json");
102412
- if (!fs104.existsSync(statePath)) {
103148
+ const statePath = path136.join(directory, ".swarm", "turbo-state.json");
103149
+ if (!fs106.existsSync(statePath)) {
102413
103150
  return {
102414
103151
  ok: false,
102415
103152
  reason: "Lean Turbo state file not found"
102416
103153
  };
102417
103154
  }
102418
- const raw = fs104.readFileSync(statePath, "utf-8");
103155
+ const raw = fs106.readFileSync(statePath, "utf-8");
102419
103156
  persisted = JSON.parse(raw);
102420
103157
  } catch {
102421
103158
  return {
@@ -102492,11 +103229,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102492
103229
  };
102493
103230
  }
102494
103231
  const phase = runState.phase ?? 0;
102495
- const evidencePath = path133.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
102496
- const expectedDir = path133.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
102497
- const resolvedPath = path133.resolve(evidencePath);
102498
- const resolvedDir = path133.resolve(expectedDir);
102499
- if (!resolvedPath.startsWith(resolvedDir + path133.sep) && resolvedPath !== resolvedDir) {
103232
+ const evidencePath = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
103233
+ const expectedDir = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
103234
+ const resolvedPath = path136.resolve(evidencePath);
103235
+ const resolvedDir = path136.resolve(expectedDir);
103236
+ if (!resolvedPath.startsWith(resolvedDir + path136.sep) && resolvedPath !== resolvedDir) {
102500
103237
  return {
102501
103238
  ok: false,
102502
103239
  reason: `Lane ID causes path traversal: ${lane.laneId}`,
@@ -102508,7 +103245,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102508
103245
  }
102509
103246
  };
102510
103247
  }
102511
- if (!fs104.existsSync(evidencePath)) {
103248
+ if (!fs106.existsSync(evidencePath)) {
102512
103249
  return {
102513
103250
  ok: false,
102514
103251
  reason: `Lane ${lane.laneId} evidence file not found: ${evidencePath}`,
@@ -102520,7 +103257,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102520
103257
  }
102521
103258
  };
102522
103259
  }
102523
- const activeLocks = _internals51.listActiveLocks(directory);
103260
+ const activeLocks = _internals54.listActiveLocks(directory);
102524
103261
  const laneLocks = activeLocks.filter((lock) => lock.laneId === lane.laneId);
102525
103262
  if (laneLocks.length > 0) {
102526
103263
  return {
@@ -102536,8 +103273,8 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102536
103273
  }
102537
103274
  let filesTouched = [];
102538
103275
  try {
102539
- const planPath = path133.join(directory, ".swarm", "plan.json");
102540
- const planRaw = fs104.readFileSync(planPath, "utf-8");
103276
+ const planPath = path136.join(directory, ".swarm", "plan.json");
103277
+ const planRaw = fs106.readFileSync(planPath, "utf-8");
102541
103278
  const plan = JSON.parse(planRaw);
102542
103279
  for (const planPhase of plan.phases ?? []) {
102543
103280
  for (const task of planPhase.tasks ?? []) {
@@ -102619,7 +103356,7 @@ var TIER_3_PATTERNS2 = [
102619
103356
  ];
102620
103357
  function matchesTier3Pattern2(files) {
102621
103358
  for (const file3 of files) {
102622
- const fileName = path134.basename(file3);
103359
+ const fileName = path137.basename(file3);
102623
103360
  for (const pattern of TIER_3_PATTERNS2) {
102624
103361
  if (pattern.test(fileName)) {
102625
103362
  return true;
@@ -102628,6 +103365,13 @@ function matchesTier3Pattern2(files) {
102628
103365
  }
102629
103366
  return false;
102630
103367
  }
103368
+ function hasPassedDurableGateEvidence(workingDirectory, taskId) {
103369
+ const evidence = readTaskEvidenceRaw(workingDirectory, taskId);
103370
+ if (!evidence || !Array.isArray(evidence.required_gates) || evidence.required_gates.length === 0) {
103371
+ return false;
103372
+ }
103373
+ return evidence.required_gates.every((gate) => evidence.gates?.[gate] != null);
103374
+ }
102631
103375
  function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = false, sessionID) {
102632
103376
  try {
102633
103377
  let skipStandardTurboBypass = false;
@@ -102651,8 +103395,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102651
103395
  if (!skipStandardTurboBypass && hasActiveTurboMode()) {
102652
103396
  const resolvedDir2 = workingDirectory;
102653
103397
  try {
102654
- const planPath = path134.join(resolvedDir2, ".swarm", "plan.json");
102655
- const planRaw = fs105.readFileSync(planPath, "utf-8");
103398
+ const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
103399
+ const planRaw = fs107.readFileSync(planPath, "utf-8");
102656
103400
  const plan = JSON.parse(planRaw);
102657
103401
  for (const planPhase of plan.phases ?? []) {
102658
103402
  for (const task of planPhase.tasks ?? []) {
@@ -102674,12 +103418,11 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102674
103418
  try {
102675
103419
  const evidence = readTaskEvidenceRaw(resolvedDir, taskId);
102676
103420
  if (evidence === null) {} else if (evidence.required_gates && Array.isArray(evidence.required_gates) && evidence.gates) {
102677
- const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
102678
- if (allGatesMet) {
103421
+ if (evidence.required_gates.length > 0 && evidence.required_gates.every((gate) => evidence.gates[gate] != null)) {
102679
103422
  return { blocked: false, reason: "" };
102680
103423
  }
102681
103424
  const missingGates = evidence.required_gates.filter((gate) => evidence.gates[gate] == null);
102682
- evidenceIncompleteReason = `Task ${taskId} is missing required gates: [${missingGates.join(", ")}]. ` + `Required: [${evidence.required_gates.join(", ")}]. ` + `Completed: [${Object.keys(evidence.gates).join(", ")}]. ` + `Delegate the missing gate agents before marking task as completed.`;
103425
+ evidenceIncompleteReason = evidence.required_gates.length === 0 ? `Task ${taskId} has an evidence file with no required gates. Delegate reviewer and test_engineer before marking task as completed.` : `Task ${taskId} is missing required gates: [${missingGates.join(", ")}]. ` + `Required: [${evidence.required_gates.join(", ")}]. ` + `Completed: [${Object.keys(evidence.gates).join(", ")}]. ` + `Delegate the missing gate agents before marking task as completed.`;
102683
103426
  }
102684
103427
  } catch (error93) {
102685
103428
  console.warn(`[gate-evidence] Evidence file for task ${taskId} is corrupt or unreadable:`, error93 instanceof Error ? error93.message : String(error93));
@@ -102689,7 +103432,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102689
103432
  reason: `Evidence file for task ${taskId} is corrupt or unreadable. ` + `Fix the file at .swarm/evidence/${taskId}.json or delete it to fall through to session state.`
102690
103433
  };
102691
103434
  }
102692
- if (swarmState.agentSessions.size === 0) {
103435
+ if (swarmState.agentSessions.size === 0 && !evidenceIncompleteReason) {
102693
103436
  return { blocked: false, reason: "" };
102694
103437
  }
102695
103438
  let validSessionCount = 0;
@@ -102706,7 +103449,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102706
103449
  return { blocked: false, reason: "" };
102707
103450
  }
102708
103451
  }
102709
- if (validSessionCount === 0) {
103452
+ if (validSessionCount === 0 && !evidenceIncompleteReason) {
102710
103453
  return { blocked: false, reason: "" };
102711
103454
  }
102712
103455
  const stateEntries = [];
@@ -102718,12 +103461,12 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102718
103461
  }
102719
103462
  try {
102720
103463
  const resolvedDir2 = workingDirectory;
102721
- const planPath = path134.join(resolvedDir2, ".swarm", "plan.json");
102722
- const planRaw = fs105.readFileSync(planPath, "utf-8");
103464
+ const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
103465
+ const planRaw = fs107.readFileSync(planPath, "utf-8");
102723
103466
  const plan = JSON.parse(planRaw);
102724
103467
  for (const planPhase of plan.phases ?? []) {
102725
103468
  for (const task of planPhase.tasks ?? []) {
102726
- if (task.id === taskId && task.status === "completed") {
103469
+ if (task.id === taskId && task.status === "completed" && hasPassedDurableGateEvidence(resolvedDir2, taskId)) {
102727
103470
  return { blocked: false, reason: "" };
102728
103471
  }
102729
103472
  }
@@ -102744,26 +103487,6 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102744
103487
  }
102745
103488
  }
102746
103489
  }
102747
- if (!hasReviewer && !hasTestEngineer) {
102748
- for (const [, chain] of swarmState.delegationChains) {
102749
- let lastCoderIndex = -1;
102750
- for (let i2 = chain.length - 1;i2 >= 0; i2--) {
102751
- const target = stripKnownSwarmPrefix(chain[i2].to);
102752
- if (target === "coder") {
102753
- lastCoderIndex = i2;
102754
- break;
102755
- }
102756
- }
102757
- const searchStart = lastCoderIndex === -1 ? 0 : lastCoderIndex + 1;
102758
- for (let i2 = searchStart;i2 < chain.length; i2++) {
102759
- const target = stripKnownSwarmPrefix(chain[i2].to);
102760
- if (target === "reviewer")
102761
- hasReviewer = true;
102762
- if (target === "test_engineer")
102763
- hasTestEngineer = true;
102764
- }
102765
- }
102766
- }
102767
103490
  if (hasReviewer && hasTestEngineer) {
102768
103491
  return { blocked: false, reason: "" };
102769
103492
  }
@@ -102806,26 +103529,6 @@ function recoverTaskStateFromDelegations(taskId) {
102806
103529
  }
102807
103530
  }
102808
103531
  }
102809
- if (!hasReviewer && !hasTestEngineer) {
102810
- for (const [, chain] of swarmState.delegationChains) {
102811
- let lastCoderIndex = -1;
102812
- for (let i2 = chain.length - 1;i2 >= 0; i2--) {
102813
- const target = stripKnownSwarmPrefix(chain[i2].to);
102814
- if (target === "coder") {
102815
- lastCoderIndex = i2;
102816
- break;
102817
- }
102818
- }
102819
- const searchStart = lastCoderIndex === -1 ? 0 : lastCoderIndex + 1;
102820
- for (let i2 = searchStart;i2 < chain.length; i2++) {
102821
- const target = stripKnownSwarmPrefix(chain[i2].to);
102822
- if (target === "reviewer")
102823
- hasReviewer = true;
102824
- if (target === "test_engineer")
102825
- hasTestEngineer = true;
102826
- }
102827
- }
102828
- }
102829
103532
  if (!hasReviewer && !hasTestEngineer)
102830
103533
  return;
102831
103534
  for (const [, session] of swarmState.agentSessions) {
@@ -102903,8 +103606,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102903
103606
  };
102904
103607
  }
102905
103608
  }
102906
- normalizedDir = path134.normalize(args2.working_directory);
102907
- const pathParts = normalizedDir.split(path134.sep);
103609
+ normalizedDir = path137.normalize(args2.working_directory);
103610
+ const pathParts = normalizedDir.split(path137.sep);
102908
103611
  if (pathParts.includes("..")) {
102909
103612
  return {
102910
103613
  success: false,
@@ -102914,11 +103617,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102914
103617
  ]
102915
103618
  };
102916
103619
  }
102917
- const resolvedDir = path134.resolve(normalizedDir);
103620
+ const resolvedDir = path137.resolve(normalizedDir);
102918
103621
  try {
102919
- const realPath = fs105.realpathSync(resolvedDir);
102920
- const planPath = path134.join(realPath, ".swarm", "plan.json");
102921
- if (!fs105.existsSync(planPath)) {
103622
+ const realPath = fs107.realpathSync(resolvedDir);
103623
+ const planPath = path137.join(realPath, ".swarm", "plan.json");
103624
+ if (!fs107.existsSync(planPath)) {
102922
103625
  return {
102923
103626
  success: false,
102924
103627
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -102949,22 +103652,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102949
103652
  }
102950
103653
  if (args2.status === "in_progress") {
102951
103654
  try {
102952
- const evidencePath = path134.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
102953
- fs105.mkdirSync(path134.dirname(evidencePath), { recursive: true });
102954
- const fd = fs105.openSync(evidencePath, "wx");
103655
+ const evidencePath = path137.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
103656
+ fs107.mkdirSync(path137.dirname(evidencePath), { recursive: true });
103657
+ const fd = fs107.openSync(evidencePath, "wx");
102955
103658
  let writeOk = false;
102956
103659
  try {
102957
- fs105.writeSync(fd, JSON.stringify({
103660
+ fs107.writeSync(fd, JSON.stringify({
102958
103661
  taskId: args2.task_id,
102959
103662
  required_gates: ["reviewer", "test_engineer"],
102960
103663
  gates: {}
102961
103664
  }, null, 2));
102962
103665
  writeOk = true;
102963
103666
  } finally {
102964
- fs105.closeSync(fd);
103667
+ fs107.closeSync(fd);
102965
103668
  if (!writeOk) {
102966
103669
  try {
102967
- fs105.unlinkSync(evidencePath);
103670
+ fs107.unlinkSync(evidencePath);
102968
103671
  } catch {}
102969
103672
  }
102970
103673
  }
@@ -102974,8 +103677,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102974
103677
  recoverTaskStateFromDelegations(args2.task_id);
102975
103678
  let phaseRequiresReviewer = true;
102976
103679
  try {
102977
- const planPath = path134.join(directory, ".swarm", "plan.json");
102978
- const planRaw = fs105.readFileSync(planPath, "utf-8");
103680
+ const planPath = path137.join(directory, ".swarm", "plan.json");
103681
+ const planRaw = fs107.readFileSync(planPath, "utf-8");
102979
103682
  const plan = JSON.parse(planRaw);
102980
103683
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
102981
103684
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -103285,8 +103988,8 @@ init_utils2();
103285
103988
  init_ledger();
103286
103989
  init_manager();
103287
103990
  init_create_tool();
103288
- import fs106 from "node:fs";
103289
- import path135 from "node:path";
103991
+ import fs108 from "node:fs";
103992
+ import path138 from "node:path";
103290
103993
  function normalizeVerdict(verdict) {
103291
103994
  switch (verdict) {
103292
103995
  case "APPROVED":
@@ -103334,7 +104037,7 @@ async function executeWriteDriftEvidence(args2, directory) {
103334
104037
  entries: [evidenceEntry]
103335
104038
  };
103336
104039
  const filename = "drift-verifier.json";
103337
- const relativePath = path135.join("evidence", String(phase), filename);
104040
+ const relativePath = path138.join("evidence", String(phase), filename);
103338
104041
  let validatedPath;
103339
104042
  try {
103340
104043
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103345,12 +104048,12 @@ async function executeWriteDriftEvidence(args2, directory) {
103345
104048
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
103346
104049
  }, null, 2);
103347
104050
  }
103348
- const evidenceDir = path135.dirname(validatedPath);
104051
+ const evidenceDir = path138.dirname(validatedPath);
103349
104052
  try {
103350
- await fs106.promises.mkdir(evidenceDir, { recursive: true });
103351
- const tempPath = path135.join(evidenceDir, `.${filename}.tmp`);
103352
- await fs106.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
103353
- await fs106.promises.rename(tempPath, validatedPath);
104053
+ await fs108.promises.mkdir(evidenceDir, { recursive: true });
104054
+ const tempPath = path138.join(evidenceDir, `.${filename}.tmp`);
104055
+ await fs108.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104056
+ await fs108.promises.rename(tempPath, validatedPath);
103354
104057
  let snapshotInfo;
103355
104058
  let snapshotError;
103356
104059
  let qaProfileLocked;
@@ -103443,8 +104146,8 @@ var write_drift_evidence = createSwarmTool({
103443
104146
  // src/tools/write-final-council-evidence.ts
103444
104147
  init_zod();
103445
104148
  init_loader();
103446
- import fs107 from "node:fs";
103447
- import path136 from "node:path";
104149
+ import fs109 from "node:fs";
104150
+ import path139 from "node:path";
103448
104151
  init_utils2();
103449
104152
  init_manager();
103450
104153
  init_create_tool();
@@ -103532,7 +104235,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
103532
104235
  timestamp: synthesis.timestamp
103533
104236
  };
103534
104237
  const filename = "final-council.json";
103535
- const relativePath = path136.join("evidence", filename);
104238
+ const relativePath = path139.join("evidence", filename);
103536
104239
  let validatedPath;
103537
104240
  try {
103538
104241
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103546,12 +104249,12 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
103546
104249
  const evidenceContent = {
103547
104250
  entries: [evidenceEntry]
103548
104251
  };
103549
- const evidenceDir = path136.dirname(validatedPath);
104252
+ const evidenceDir = path139.dirname(validatedPath);
103550
104253
  try {
103551
- await fs107.promises.mkdir(evidenceDir, { recursive: true });
103552
- const tempPath = path136.join(evidenceDir, `.${filename}.tmp`);
103553
- await fs107.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
103554
- await fs107.promises.rename(tempPath, validatedPath);
104254
+ await fs109.promises.mkdir(evidenceDir, { recursive: true });
104255
+ const tempPath = path139.join(evidenceDir, `.${filename}.tmp`);
104256
+ await fs109.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104257
+ await fs109.promises.rename(tempPath, validatedPath);
103555
104258
  return JSON.stringify({
103556
104259
  success: true,
103557
104260
  phase: input.phase,
@@ -103607,8 +104310,8 @@ var write_final_council_evidence = createSwarmTool({
103607
104310
  init_zod();
103608
104311
  init_utils2();
103609
104312
  init_create_tool();
103610
- import fs108 from "node:fs";
103611
- import path137 from "node:path";
104313
+ import fs110 from "node:fs";
104314
+ import path140 from "node:path";
103612
104315
  function normalizeVerdict2(verdict) {
103613
104316
  switch (verdict) {
103614
104317
  case "APPROVED":
@@ -103656,7 +104359,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
103656
104359
  entries: [evidenceEntry]
103657
104360
  };
103658
104361
  const filename = "hallucination-guard.json";
103659
- const relativePath = path137.join("evidence", String(phase), filename);
104362
+ const relativePath = path140.join("evidence", String(phase), filename);
103660
104363
  let validatedPath;
103661
104364
  try {
103662
104365
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103667,12 +104370,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
103667
104370
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
103668
104371
  }, null, 2);
103669
104372
  }
103670
- const evidenceDir = path137.dirname(validatedPath);
104373
+ const evidenceDir = path140.dirname(validatedPath);
103671
104374
  try {
103672
- await fs108.promises.mkdir(evidenceDir, { recursive: true });
103673
- const tempPath = path137.join(evidenceDir, `.${filename}.tmp`);
103674
- await fs108.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
103675
- await fs108.promises.rename(tempPath, validatedPath);
104375
+ await fs110.promises.mkdir(evidenceDir, { recursive: true });
104376
+ const tempPath = path140.join(evidenceDir, `.${filename}.tmp`);
104377
+ await fs110.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104378
+ await fs110.promises.rename(tempPath, validatedPath);
103676
104379
  return JSON.stringify({
103677
104380
  success: true,
103678
104381
  phase,
@@ -103718,8 +104421,8 @@ var write_hallucination_evidence = createSwarmTool({
103718
104421
  init_zod();
103719
104422
  init_utils2();
103720
104423
  init_create_tool();
103721
- import fs109 from "node:fs";
103722
- import path138 from "node:path";
104424
+ import fs111 from "node:fs";
104425
+ import path141 from "node:path";
103723
104426
  function normalizeVerdict3(verdict) {
103724
104427
  switch (verdict) {
103725
104428
  case "PASS":
@@ -103793,7 +104496,7 @@ async function executeWriteMutationEvidence(args2, directory) {
103793
104496
  entries: [evidenceEntry]
103794
104497
  };
103795
104498
  const filename = "mutation-gate.json";
103796
- const relativePath = path138.join("evidence", String(phase), filename);
104499
+ const relativePath = path141.join("evidence", String(phase), filename);
103797
104500
  let validatedPath;
103798
104501
  try {
103799
104502
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103804,12 +104507,12 @@ async function executeWriteMutationEvidence(args2, directory) {
103804
104507
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
103805
104508
  }, null, 2);
103806
104509
  }
103807
- const evidenceDir = path138.dirname(validatedPath);
104510
+ const evidenceDir = path141.dirname(validatedPath);
103808
104511
  try {
103809
- await fs109.promises.mkdir(evidenceDir, { recursive: true });
103810
- const tempPath = path138.join(evidenceDir, `.${filename}.tmp`);
103811
- await fs109.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
103812
- await fs109.promises.rename(tempPath, validatedPath);
104512
+ await fs111.promises.mkdir(evidenceDir, { recursive: true });
104513
+ const tempPath = path141.join(evidenceDir, `.${filename}.tmp`);
104514
+ await fs111.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104515
+ await fs111.promises.rename(tempPath, validatedPath);
103813
104516
  return JSON.stringify({
103814
104517
  success: true,
103815
104518
  phase,
@@ -104152,7 +104855,7 @@ async function initializeOpenCodeSwarm(ctx) {
104152
104855
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
104153
104856
  preflightTriggerManager = new PTM(automationConfig);
104154
104857
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
104155
- const swarmDir = path140.resolve(ctx.directory, ".swarm");
104858
+ const swarmDir = path143.resolve(ctx.directory, ".swarm");
104156
104859
  statusArtifact = new ASA(swarmDir);
104157
104860
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
104158
104861
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -104551,6 +105254,14 @@ async function initializeOpenCodeSwarm(ctx) {
104551
105254
  return Promise.resolve();
104552
105255
  }
104553
105256
  },
105257
+ (input, output) => {
105258
+ try {
105259
+ const p = input;
105260
+ return skillPropagationTransformScan(ctx.directory, output, p.sessionID);
105261
+ } catch {
105262
+ return Promise.resolve();
105263
+ }
105264
+ },
104554
105265
  (_input, output) => {
104555
105266
  if (output.messages) {
104556
105267
  output.messages = consolidateSystemMessages(output.messages);
@@ -104624,6 +105335,12 @@ async function initializeOpenCodeSwarm(ctx) {
104624
105335
  agent: input.agent,
104625
105336
  sessionID: input.sessionID
104626
105337
  }, KnowledgeApplicationConfigSchema.parse(config3.knowledge_application ?? {}));
105338
+ await skillPropagationGateBefore(ctx.directory, {
105339
+ tool: input.tool,
105340
+ agent: input.agent,
105341
+ sessionID: input.sessionID,
105342
+ args: input.args
105343
+ }, { enabled: true });
104627
105344
  if (swarmState.lastBudgetPct >= 50) {
104628
105345
  const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
104629
105346
  if (!pressureSession.contextPressureWarningSent) {