opencode-swarm 7.20.2 → 7.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -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.0",
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);
@@ -89523,20 +90238,20 @@ init_file_locks();
89523
90238
  init_plan_schema();
89524
90239
  init_ledger();
89525
90240
  init_manager();
89526
- import * as fs79 from "node:fs";
89527
- import * as path104 from "node:path";
90241
+ import * as fs81 from "node:fs";
90242
+ import * as path107 from "node:path";
89528
90243
  async function writeCheckpoint(directory) {
89529
90244
  try {
89530
90245
  const plan = await loadPlan(directory);
89531
90246
  if (!plan)
89532
90247
  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");
90248
+ const swarmDir = path107.join(directory, ".swarm");
90249
+ fs81.mkdirSync(swarmDir, { recursive: true });
90250
+ const jsonPath = path107.join(swarmDir, "SWARM_PLAN.json");
90251
+ const mdPath = path107.join(swarmDir, "SWARM_PLAN.md");
90252
+ fs81.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
89538
90253
  const md = derivePlanMarkdown(plan);
89539
- fs79.writeFileSync(mdPath, md, "utf8");
90254
+ fs81.writeFileSync(mdPath, md, "utf8");
89540
90255
  } catch (error93) {
89541
90256
  console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
89542
90257
  }
@@ -89551,16 +90266,16 @@ init_telemetry();
89551
90266
 
89552
90267
  // src/turbo/lean/phase-ready.ts
89553
90268
  init_file_locks();
89554
- import * as fs81 from "node:fs";
89555
- import * as path106 from "node:path";
90269
+ import * as fs83 from "node:fs";
90270
+ import * as path109 from "node:path";
89556
90271
 
89557
90272
  // src/turbo/lean/evidence.ts
89558
90273
  init_bun_compat();
89559
90274
  import { rmSync as rmSync5 } from "node:fs";
89560
- import * as fs80 from "node:fs/promises";
89561
- import * as path105 from "node:path";
90275
+ import * as fs82 from "node:fs/promises";
90276
+ import * as path108 from "node:path";
89562
90277
  function leanTurboEvidenceDir(directory, phase) {
89563
- return path105.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
90278
+ return path108.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
89564
90279
  }
89565
90280
  function validateLaneId(laneId) {
89566
90281
  if (laneId.length === 0) {
@@ -89582,21 +90297,21 @@ function validateLaneId(laneId) {
89582
90297
  function laneEvidencePath(directory, phase, laneId) {
89583
90298
  validateLaneId(laneId);
89584
90299
  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) {
90300
+ const resolvedPath = path108.resolve(path108.join(expectedDir, `${laneId}.json`));
90301
+ const resolvedDir = path108.resolve(expectedDir);
90302
+ if (!resolvedPath.startsWith(resolvedDir + path108.sep) && resolvedPath !== resolvedDir) {
89588
90303
  throw new Error(`Invalid laneId: path traversal detected (got "${laneId}")`);
89589
90304
  }
89590
90305
  return resolvedPath;
89591
90306
  }
89592
90307
  async function atomicWriteJson(filePath, data) {
89593
90308
  const content = JSON.stringify(data, null, 2);
89594
- const dir = path105.dirname(filePath);
89595
- await fs80.mkdir(dir, { recursive: true });
90309
+ const dir = path108.dirname(filePath);
90310
+ await fs82.mkdir(dir, { recursive: true });
89596
90311
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
89597
90312
  try {
89598
90313
  await bunWrite(tempPath, content);
89599
- await fs80.rename(tempPath, filePath);
90314
+ await fs82.rename(tempPath, filePath);
89600
90315
  } catch (error93) {
89601
90316
  try {
89602
90317
  rmSync5(tempPath, { force: true });
@@ -89605,7 +90320,7 @@ async function atomicWriteJson(filePath, data) {
89605
90320
  }
89606
90321
  }
89607
90322
  function phaseEvidencePath(directory, phase) {
89608
- return path105.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
90323
+ return path108.join(leanTurboEvidenceDir(directory, phase), "lean-turbo-phase.json");
89609
90324
  }
89610
90325
  async function writeLaneEvidence(directory, phase, evidence) {
89611
90326
  const targetPath = laneEvidencePath(directory, phase, evidence.laneId);
@@ -89615,7 +90330,7 @@ async function readPhaseEvidence(directory, phase) {
89615
90330
  const targetPath = phaseEvidencePath(directory, phase);
89616
90331
  let content;
89617
90332
  try {
89618
- content = await fs80.readFile(targetPath, "utf-8");
90333
+ content = await fs82.readFile(targetPath, "utf-8");
89619
90334
  } catch (error93) {
89620
90335
  const code = error93.code;
89621
90336
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -89633,7 +90348,7 @@ async function listLaneEvidence(directory, phase) {
89633
90348
  const evidenceDir = leanTurboEvidenceDir(directory, phase);
89634
90349
  let entries;
89635
90350
  try {
89636
- entries = await fs80.readdir(evidenceDir);
90351
+ entries = await fs82.readdir(evidenceDir);
89637
90352
  } catch (error93) {
89638
90353
  const code = error93.code;
89639
90354
  if (code === "ENOENT" || code === "ENOTDIR") {
@@ -89649,10 +90364,10 @@ async function listLaneEvidence(directory, phase) {
89649
90364
  if (entry === "lean-turbo-phase.json") {
89650
90365
  continue;
89651
90366
  }
89652
- const filePath = path105.join(evidenceDir, entry);
90367
+ const filePath = path108.join(evidenceDir, entry);
89653
90368
  let content;
89654
90369
  try {
89655
- content = await fs80.readFile(filePath, "utf-8");
90370
+ content = await fs82.readFile(filePath, "utf-8");
89656
90371
  } catch {
89657
90372
  continue;
89658
90373
  }
@@ -89673,10 +90388,10 @@ var DEFAULT_CONFIG2 = {
89673
90388
  };
89674
90389
  function defaultReadPlanJson(dir) {
89675
90390
  try {
89676
- const planPath = path106.join(dir, ".swarm", "plan.json");
89677
- if (!fs81.existsSync(planPath))
90391
+ const planPath = path109.join(dir, ".swarm", "plan.json");
90392
+ if (!fs83.existsSync(planPath))
89678
90393
  return null;
89679
- const raw = fs81.readFileSync(planPath, "utf-8");
90394
+ const raw = fs83.readFileSync(planPath, "utf-8");
89680
90395
  const plan = JSON.parse(raw);
89681
90396
  if (typeof plan !== "object" || plan === null || !Array.isArray(plan.phases)) {
89682
90397
  return null;
@@ -89688,11 +90403,11 @@ function defaultReadPlanJson(dir) {
89688
90403
  }
89689
90404
  function readReviewerEvidenceFromFile(directory, phase) {
89690
90405
  try {
89691
- const evidencePath = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
89692
- if (!fs81.existsSync(evidencePath)) {
90406
+ const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
90407
+ if (!fs83.existsSync(evidencePath)) {
89693
90408
  return null;
89694
90409
  }
89695
- const raw = fs81.readFileSync(evidencePath, "utf-8");
90410
+ const raw = fs83.readFileSync(evidencePath, "utf-8");
89696
90411
  const parsed = JSON.parse(raw);
89697
90412
  if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
89698
90413
  return null;
@@ -89708,11 +90423,11 @@ function readReviewerEvidenceFromFile(directory, phase) {
89708
90423
  }
89709
90424
  function readCriticEvidenceFromFile(directory, phase) {
89710
90425
  try {
89711
- const evidencePath = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
89712
- if (!fs81.existsSync(evidencePath)) {
90426
+ const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
90427
+ if (!fs83.existsSync(evidencePath)) {
89713
90428
  return null;
89714
90429
  }
89715
- const raw = fs81.readFileSync(evidencePath, "utf-8");
90430
+ const raw = fs83.readFileSync(evidencePath, "utf-8");
89716
90431
  const parsed = JSON.parse(raw);
89717
90432
  if (typeof parsed !== "object" || parsed === null || typeof parsed.verdict !== "string") {
89718
90433
  return null;
@@ -89727,10 +90442,10 @@ function readCriticEvidenceFromFile(directory, phase) {
89727
90442
  }
89728
90443
  }
89729
90444
  function listLaneEvidenceSync(directory, phase) {
89730
- const evidenceDir = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
90445
+ const evidenceDir = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
89731
90446
  let entries;
89732
90447
  try {
89733
- entries = fs81.readdirSync(evidenceDir);
90448
+ entries = fs83.readdirSync(evidenceDir);
89734
90449
  } catch {
89735
90450
  return [];
89736
90451
  }
@@ -89743,7 +90458,7 @@ function listLaneEvidenceSync(directory, phase) {
89743
90458
  }
89744
90459
  return laneIds;
89745
90460
  }
89746
- var _internals40 = {
90461
+ var _internals43 = {
89747
90462
  listActiveLocks,
89748
90463
  readPersisted: readPersisted2,
89749
90464
  readPlanJson: defaultReadPlanJson,
@@ -89797,14 +90512,14 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89797
90512
  ...DEFAULT_CONFIG2,
89798
90513
  ...actualConfig
89799
90514
  };
89800
- const statePath = path106.join(directory, ".swarm", "turbo-state.json");
89801
- if (!fs81.existsSync(statePath)) {
90515
+ const statePath = path109.join(directory, ".swarm", "turbo-state.json");
90516
+ if (!fs83.existsSync(statePath)) {
89802
90517
  return {
89803
90518
  ok: false,
89804
90519
  reason: "Lean Turbo state unreadable or missing"
89805
90520
  };
89806
90521
  }
89807
- const persisted = _internals40.readPersisted(directory);
90522
+ const persisted = _internals43.readPersisted(directory);
89808
90523
  if (!persisted) {
89809
90524
  return {
89810
90525
  ok: false,
@@ -89868,7 +90583,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89868
90583
  }
89869
90584
  }
89870
90585
  if (runState.lanes.length > 0) {
89871
- const evidenceLaneIds = new Set(_internals40.listLaneEvidenceSync(directory, phase));
90586
+ const evidenceLaneIds = new Set(_internals43.listLaneEvidenceSync(directory, phase));
89872
90587
  for (const lane of runState.lanes) {
89873
90588
  if ((lane.status === "completed" || lane.status === "failed") && !evidenceLaneIds.has(lane.laneId)) {
89874
90589
  return {
@@ -89878,7 +90593,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89878
90593
  }
89879
90594
  }
89880
90595
  }
89881
- const activeLocks = _internals40.listActiveLocks(directory);
90596
+ const activeLocks = _internals43.listActiveLocks(directory);
89882
90597
  const phaseLaneIds = new Set(laneIds);
89883
90598
  for (const lock of activeLocks) {
89884
90599
  if (lock.laneId && phaseLaneIds.has(lock.laneId)) {
@@ -89898,7 +90613,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89898
90613
  }
89899
90614
  const serialDegradedTasks = runState.degradedTasks.filter((dt) => !laneTaskIds.has(dt.taskId));
89900
90615
  if (serialDegradedTasks.length > 0) {
89901
- const plan = _internals40.readPlanJson(directory);
90616
+ const plan = _internals43.readPlanJson(directory);
89902
90617
  if (!plan) {
89903
90618
  return {
89904
90619
  ok: false,
@@ -89942,7 +90657,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89942
90657
  }
89943
90658
  const serializedTasks = runState.serializedTasks;
89944
90659
  if (Array.isArray(serializedTasks) && serializedTasks.length > 0) {
89945
- const plan = _internals40.readPlanJson(directory);
90660
+ const plan = _internals43.readPlanJson(directory);
89946
90661
  if (!plan) {
89947
90662
  return {
89948
90663
  ok: false,
@@ -89985,10 +90700,10 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
89985
90700
  }
89986
90701
  }
89987
90702
  if (mergedConfig.integrated_diff_required) {
89988
- const evidencePath = path106.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
90703
+ const evidencePath = path109.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
89989
90704
  let hasDiff = false;
89990
90705
  try {
89991
- const content = fs81.readFileSync(evidencePath, "utf-8");
90706
+ const content = fs83.readFileSync(evidencePath, "utf-8");
89992
90707
  const evidence = JSON.parse(content);
89993
90708
  hasDiff = !!evidence.integratedDiffSummary;
89994
90709
  } catch {}
@@ -90001,7 +90716,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
90001
90716
  }
90002
90717
  let reviewerVerdict = runState.lastReviewerVerdict;
90003
90718
  if (!reviewerVerdict) {
90004
- const evidence = _internals40.readReviewerEvidence(directory, phase);
90719
+ const evidence = _internals43.readReviewerEvidence(directory, phase);
90005
90720
  reviewerVerdict = evidence?.verdict ?? undefined;
90006
90721
  }
90007
90722
  if (mergedConfig.phase_reviewer) {
@@ -90014,7 +90729,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
90014
90729
  }
90015
90730
  let criticVerdict = runState.lastCriticVerdict;
90016
90731
  if (!criticVerdict) {
90017
- const evidence = _internals40.readCriticEvidence(directory, phase);
90732
+ const evidence = _internals43.readCriticEvidence(directory, phase);
90018
90733
  criticVerdict = evidence?.verdict ?? undefined;
90019
90734
  }
90020
90735
  if (mergedConfig.phase_critic) {
@@ -90259,8 +90974,8 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90259
90974
  let driftCheckEnabled = true;
90260
90975
  let driftHasSpecMd = false;
90261
90976
  try {
90262
- const specMdPath = path107.join(dir, ".swarm", "spec.md");
90263
- driftHasSpecMd = fs82.existsSync(specMdPath);
90977
+ const specMdPath = path110.join(dir, ".swarm", "spec.md");
90978
+ driftHasSpecMd = fs84.existsSync(specMdPath);
90264
90979
  const gatePlan = await loadPlan(dir);
90265
90980
  if (gatePlan) {
90266
90981
  const gatePlanId = derivePlanId(gatePlan);
@@ -90280,9 +90995,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90280
90995
  } else {
90281
90996
  let phaseType;
90282
90997
  try {
90283
- const planPath = path107.join(dir, ".swarm", "plan.json");
90284
- if (fs82.existsSync(planPath)) {
90285
- const planRaw = fs82.readFileSync(planPath, "utf-8");
90998
+ const planPath = path110.join(dir, ".swarm", "plan.json");
90999
+ if (fs84.existsSync(planPath)) {
91000
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
90286
91001
  const plan = JSON.parse(planRaw);
90287
91002
  const targetPhase = plan.phases?.find((p) => p.id === phase);
90288
91003
  phaseType = targetPhase?.type;
@@ -90292,11 +91007,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90292
91007
  warnings.push(`Phase ${phase} is annotated as 'non-code'. Drift verification was skipped per phase type annotation.`);
90293
91008
  } else {
90294
91009
  try {
90295
- const driftEvidencePath = path107.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
91010
+ const driftEvidencePath = path110.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
90296
91011
  let driftVerdictFound = false;
90297
91012
  let driftVerdictApproved = false;
90298
91013
  try {
90299
- const driftEvidenceContent = fs82.readFileSync(driftEvidencePath, "utf-8");
91014
+ const driftEvidenceContent = fs84.readFileSync(driftEvidencePath, "utf-8");
90300
91015
  const driftEvidence = JSON.parse(driftEvidenceContent);
90301
91016
  const entries = driftEvidence.entries ?? [];
90302
91017
  for (const entry of entries) {
@@ -90330,9 +91045,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90330
91045
  let incompleteTaskCount = 0;
90331
91046
  let planParseable = false;
90332
91047
  try {
90333
- const planPath = path107.join(dir, ".swarm", "plan.json");
90334
- if (fs82.existsSync(planPath)) {
90335
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91048
+ const planPath = path110.join(dir, ".swarm", "plan.json");
91049
+ if (fs84.existsSync(planPath)) {
91050
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
90336
91051
  const plan = JSON.parse(planRaw);
90337
91052
  planParseable = true;
90338
91053
  const planPhase = plan.phases?.find((p) => p.id === phase);
@@ -90397,11 +91112,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90397
91112
  const overrides = session2?.qaGateSessionOverrides ?? {};
90398
91113
  const effective = getEffectiveGates(profile, overrides);
90399
91114
  if (effective.hallucination_guard === true) {
90400
- const hgPath = path107.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
91115
+ const hgPath = path110.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
90401
91116
  let hgVerdictFound = false;
90402
91117
  let hgVerdictApproved = false;
90403
91118
  try {
90404
- const hgContent = fs82.readFileSync(hgPath, "utf-8");
91119
+ const hgContent = fs84.readFileSync(hgPath, "utf-8");
90405
91120
  const hgBundle = JSON.parse(hgContent);
90406
91121
  for (const entry of hgBundle.entries ?? []) {
90407
91122
  if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
@@ -90469,11 +91184,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90469
91184
  const overrides = session2?.qaGateSessionOverrides ?? {};
90470
91185
  const effective = getEffectiveGates(profile, overrides);
90471
91186
  if (effective.mutation_test === true) {
90472
- const mgPath = path107.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
91187
+ const mgPath = path110.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
90473
91188
  let mgVerdictFound = false;
90474
91189
  let mgVerdict;
90475
91190
  try {
90476
- const mgContent = fs82.readFileSync(mgPath, "utf-8");
91191
+ const mgContent = fs84.readFileSync(mgPath, "utf-8");
90477
91192
  const mgBundle = JSON.parse(mgContent);
90478
91193
  for (const entry of mgBundle.entries ?? []) {
90479
91194
  if (typeof entry.type === "string" && entry.type === "mutation-gate" && typeof entry.verdict === "string") {
@@ -90543,14 +91258,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
90543
91258
  const effective = getEffectiveGates(profile, overrides);
90544
91259
  if (effective.council_mode === true) {
90545
91260
  councilModeEnabled = true;
90546
- const pcPath = path107.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
91261
+ const pcPath = path110.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
90547
91262
  let pcVerdictFound = false;
90548
91263
  let _pcVerdict;
90549
91264
  let pcQuorumSize;
90550
91265
  let pcTimestamp;
90551
91266
  let pcPhaseNumber;
90552
91267
  try {
90553
- const pcContent = fs82.readFileSync(pcPath, "utf-8");
91268
+ const pcContent = fs84.readFileSync(pcPath, "utf-8");
90554
91269
  const pcBundle = JSON.parse(pcContent);
90555
91270
  for (const entry of pcBundle.entries ?? []) {
90556
91271
  if (typeof entry.type === "string" && entry.type === "phase-council" && typeof entry.verdict === "string") {
@@ -90751,11 +91466,11 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
90751
91466
  const effective = getEffectiveGates(profile, overrides);
90752
91467
  if (effective.final_council === true) {
90753
91468
  finalCouncilEnabled = true;
90754
- const fcPath = path107.join(dir, ".swarm", "evidence", "final-council.json");
91469
+ const fcPath = path110.join(dir, ".swarm", "evidence", "final-council.json");
90755
91470
  let fcVerdictFound = false;
90756
91471
  let _fcVerdict;
90757
91472
  try {
90758
- const fcContent = fs82.readFileSync(fcPath, "utf-8");
91473
+ const fcContent = fs84.readFileSync(fcPath, "utf-8");
90759
91474
  const fcBundle = JSON.parse(fcContent);
90760
91475
  for (const entry of fcBundle.entries ?? []) {
90761
91476
  if (typeof entry.type === "string" && entry.type === "final-council" && typeof entry.verdict === "string") {
@@ -90916,7 +91631,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
90916
91631
  phase_critic: leanConfig.phase_critic,
90917
91632
  integrated_diff_required: leanConfig.integrated_diff_required
90918
91633
  } : undefined;
90919
- const leanCheck = _internals40.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
91634
+ const leanCheck = _internals43.verifyLeanTurboPhaseReady(dir, phase, sessionID, leanPhaseReadyConfig);
90920
91635
  if (!leanCheck.ok) {
90921
91636
  return JSON.stringify({
90922
91637
  success: false,
@@ -90939,7 +91654,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
90939
91654
  }
90940
91655
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
90941
91656
  try {
90942
- const projectName = path107.basename(dir);
91657
+ const projectName = path110.basename(dir);
90943
91658
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
90944
91659
  if (curationResult) {
90945
91660
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -91019,7 +91734,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91019
91734
  let phaseRequiredAgents;
91020
91735
  try {
91021
91736
  const planPath = validateSwarmPath(dir, "plan.json");
91022
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91737
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91023
91738
  const plan = JSON.parse(planRaw);
91024
91739
  const phaseObj = plan.phases.find((p) => p.id === phase);
91025
91740
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -91034,7 +91749,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91034
91749
  if (agentsMissing.length > 0) {
91035
91750
  try {
91036
91751
  const planPath = validateSwarmPath(dir, "plan.json");
91037
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91752
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91038
91753
  const plan = JSON.parse(planRaw);
91039
91754
  const targetPhase = plan.phases.find((p) => p.id === phase);
91040
91755
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -91074,7 +91789,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91074
91789
  if (phaseCompleteConfig.regression_sweep?.enforce) {
91075
91790
  try {
91076
91791
  const planPath = validateSwarmPath(dir, "plan.json");
91077
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91792
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91078
91793
  const plan = JSON.parse(planRaw);
91079
91794
  const targetPhase = plan.phases.find((p) => p.id === phase);
91080
91795
  if (targetPhase) {
@@ -91128,7 +91843,7 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91128
91843
  }
91129
91844
  try {
91130
91845
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
91131
- fs82.appendFileSync(eventsPath, `${JSON.stringify(event)}
91846
+ fs84.appendFileSync(eventsPath, `${JSON.stringify(event)}
91132
91847
  `, "utf-8");
91133
91848
  } catch (writeError) {
91134
91849
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -91203,12 +91918,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91203
91918
  warnings.push(`Warning: failed to update plan.json phase status`);
91204
91919
  try {
91205
91920
  const planPath = validateSwarmPath(dir, "plan.json");
91206
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91921
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91207
91922
  const plan2 = JSON.parse(planRaw);
91208
91923
  const phaseObj = plan2.phases.find((p) => p.id === phase);
91209
91924
  if (phaseObj) {
91210
91925
  phaseObj.status = "complete";
91211
- fs82.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
91926
+ fs84.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
91212
91927
  }
91213
91928
  } catch {}
91214
91929
  } else if (plan) {
@@ -91245,12 +91960,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
91245
91960
  warnings.push(`Warning: failed to update plan.json phase status`);
91246
91961
  try {
91247
91962
  const planPath = validateSwarmPath(dir, "plan.json");
91248
- const planRaw = fs82.readFileSync(planPath, "utf-8");
91963
+ const planRaw = fs84.readFileSync(planPath, "utf-8");
91249
91964
  const plan = JSON.parse(planRaw);
91250
91965
  const phaseObj = plan.phases.find((p) => p.id === phase);
91251
91966
  if (phaseObj) {
91252
91967
  phaseObj.status = "complete";
91253
- fs82.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
91968
+ fs84.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
91254
91969
  }
91255
91970
  } catch {}
91256
91971
  }
@@ -91308,8 +92023,8 @@ init_discovery();
91308
92023
  init_utils();
91309
92024
  init_bun_compat();
91310
92025
  init_create_tool();
91311
- import * as fs83 from "node:fs";
91312
- import * as path108 from "node:path";
92026
+ import * as fs85 from "node:fs";
92027
+ import * as path111 from "node:path";
91313
92028
  var MAX_OUTPUT_BYTES5 = 52428800;
91314
92029
  var AUDIT_TIMEOUT_MS = 120000;
91315
92030
  function isValidEcosystem(value) {
@@ -91337,31 +92052,31 @@ function validateArgs3(args2) {
91337
92052
  function detectEcosystems(directory) {
91338
92053
  const ecosystems = [];
91339
92054
  const cwd = directory;
91340
- if (fs83.existsSync(path108.join(cwd, "package.json"))) {
92055
+ if (fs85.existsSync(path111.join(cwd, "package.json"))) {
91341
92056
  ecosystems.push("npm");
91342
92057
  }
91343
- if (fs83.existsSync(path108.join(cwd, "pyproject.toml")) || fs83.existsSync(path108.join(cwd, "requirements.txt"))) {
92058
+ if (fs85.existsSync(path111.join(cwd, "pyproject.toml")) || fs85.existsSync(path111.join(cwd, "requirements.txt"))) {
91344
92059
  ecosystems.push("pip");
91345
92060
  }
91346
- if (fs83.existsSync(path108.join(cwd, "Cargo.toml"))) {
92061
+ if (fs85.existsSync(path111.join(cwd, "Cargo.toml"))) {
91347
92062
  ecosystems.push("cargo");
91348
92063
  }
91349
- if (fs83.existsSync(path108.join(cwd, "go.mod"))) {
92064
+ if (fs85.existsSync(path111.join(cwd, "go.mod"))) {
91350
92065
  ecosystems.push("go");
91351
92066
  }
91352
92067
  try {
91353
- const files = fs83.readdirSync(cwd);
92068
+ const files = fs85.readdirSync(cwd);
91354
92069
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
91355
92070
  ecosystems.push("dotnet");
91356
92071
  }
91357
92072
  } catch {}
91358
- if (fs83.existsSync(path108.join(cwd, "Gemfile")) || fs83.existsSync(path108.join(cwd, "Gemfile.lock"))) {
92073
+ if (fs85.existsSync(path111.join(cwd, "Gemfile")) || fs85.existsSync(path111.join(cwd, "Gemfile.lock"))) {
91359
92074
  ecosystems.push("ruby");
91360
92075
  }
91361
- if (fs83.existsSync(path108.join(cwd, "pubspec.yaml"))) {
92076
+ if (fs85.existsSync(path111.join(cwd, "pubspec.yaml"))) {
91362
92077
  ecosystems.push("dart");
91363
92078
  }
91364
- if (fs83.existsSync(path108.join(cwd, "composer.lock"))) {
92079
+ if (fs85.existsSync(path111.join(cwd, "composer.lock"))) {
91365
92080
  ecosystems.push("composer");
91366
92081
  }
91367
92082
  return ecosystems;
@@ -92496,8 +93211,8 @@ var pkg_audit = createSwarmTool({
92496
93211
  // src/tools/placeholder-scan.ts
92497
93212
  init_zod();
92498
93213
  init_manager2();
92499
- import * as fs84 from "node:fs";
92500
- import * as path109 from "node:path";
93214
+ import * as fs86 from "node:fs";
93215
+ import * as path112 from "node:path";
92501
93216
  init_utils();
92502
93217
  init_create_tool();
92503
93218
  var MAX_FILE_SIZE = 1024 * 1024;
@@ -92620,7 +93335,7 @@ function isScaffoldFile(filePath) {
92620
93335
  if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
92621
93336
  return true;
92622
93337
  }
92623
- const filename = path109.basename(filePath);
93338
+ const filename = path112.basename(filePath);
92624
93339
  if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
92625
93340
  return true;
92626
93341
  }
@@ -92637,7 +93352,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
92637
93352
  if (regex.test(normalizedPath)) {
92638
93353
  return true;
92639
93354
  }
92640
- const filename = path109.basename(filePath);
93355
+ const filename = path112.basename(filePath);
92641
93356
  const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
92642
93357
  if (filenameRegex.test(filename)) {
92643
93358
  return true;
@@ -92646,7 +93361,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
92646
93361
  return false;
92647
93362
  }
92648
93363
  function isParserSupported(filePath) {
92649
- const ext = path109.extname(filePath).toLowerCase();
93364
+ const ext = path112.extname(filePath).toLowerCase();
92650
93365
  return SUPPORTED_PARSER_EXTENSIONS.has(ext);
92651
93366
  }
92652
93367
  function isPlanFile(filePath) {
@@ -92893,28 +93608,28 @@ async function placeholderScan(input, directory) {
92893
93608
  let filesScanned = 0;
92894
93609
  const filesWithFindings = new Set;
92895
93610
  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) {
93611
+ const fullPath = path112.isAbsolute(filePath) ? filePath : path112.resolve(directory, filePath);
93612
+ const resolvedDirectory = path112.resolve(directory);
93613
+ if (!fullPath.startsWith(resolvedDirectory + path112.sep) && fullPath !== resolvedDirectory) {
92899
93614
  continue;
92900
93615
  }
92901
- if (!fs84.existsSync(fullPath)) {
93616
+ if (!fs86.existsSync(fullPath)) {
92902
93617
  continue;
92903
93618
  }
92904
93619
  if (isAllowedByGlobs(filePath, allow_globs)) {
92905
93620
  continue;
92906
93621
  }
92907
- const relativeFilePath = path109.relative(directory, fullPath).replace(/\\/g, "/");
93622
+ const relativeFilePath = path112.relative(directory, fullPath).replace(/\\/g, "/");
92908
93623
  if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
92909
93624
  continue;
92910
93625
  }
92911
93626
  let content;
92912
93627
  try {
92913
- const stat8 = fs84.statSync(fullPath);
93628
+ const stat8 = fs86.statSync(fullPath);
92914
93629
  if (stat8.size > MAX_FILE_SIZE) {
92915
93630
  continue;
92916
93631
  }
92917
- content = fs84.readFileSync(fullPath, "utf-8");
93632
+ content = fs86.readFileSync(fullPath, "utf-8");
92918
93633
  } catch {
92919
93634
  continue;
92920
93635
  }
@@ -92975,8 +93690,8 @@ var placeholder_scan = createSwarmTool({
92975
93690
  }
92976
93691
  });
92977
93692
  // src/tools/pre-check-batch.ts
92978
- import * as fs88 from "node:fs";
92979
- import * as path113 from "node:path";
93693
+ import * as fs90 from "node:fs";
93694
+ import * as path116 from "node:path";
92980
93695
  init_zod();
92981
93696
  init_manager2();
92982
93697
  init_utils();
@@ -93104,11 +93819,11 @@ var quality_budget = createSwarmTool({
93104
93819
  }).optional().describe("Quality budget thresholds")
93105
93820
  },
93106
93821
  async execute(args2, directory) {
93107
- const result = await _internals41.qualityBudget(args2, directory);
93822
+ const result = await _internals44.qualityBudget(args2, directory);
93108
93823
  return JSON.stringify(result);
93109
93824
  }
93110
93825
  });
93111
- var _internals41 = {
93826
+ var _internals44 = {
93112
93827
  qualityBudget
93113
93828
  };
93114
93829
 
@@ -93116,9 +93831,9 @@ var _internals41 = {
93116
93831
  init_zod();
93117
93832
  init_manager2();
93118
93833
  init_detector();
93119
- import * as fs87 from "node:fs";
93120
- import * as path112 from "node:path";
93121
- import { extname as extname19 } from "node:path";
93834
+ import * as fs89 from "node:fs";
93835
+ import * as path115 from "node:path";
93836
+ import { extname as extname20 } from "node:path";
93122
93837
 
93123
93838
  // src/sast/rules/c.ts
93124
93839
  var cRules = [
@@ -93832,12 +94547,12 @@ function executeRulesSync(filePath, content, language) {
93832
94547
 
93833
94548
  // src/sast/semgrep.ts
93834
94549
  import * as child_process9 from "node:child_process";
93835
- import * as fs85 from "node:fs";
93836
- import * as path110 from "node:path";
94550
+ import * as fs87 from "node:fs";
94551
+ import * as path113 from "node:path";
93837
94552
  var semgrepAvailableCache = null;
93838
94553
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
93839
94554
  var DEFAULT_TIMEOUT_MS3 = 30000;
93840
- var _internals42 = {
94555
+ var _internals45 = {
93841
94556
  isSemgrepAvailable,
93842
94557
  checkSemgrepAvailable,
93843
94558
  resetSemgrepCache,
@@ -93862,7 +94577,7 @@ function isSemgrepAvailable() {
93862
94577
  }
93863
94578
  }
93864
94579
  async function checkSemgrepAvailable() {
93865
- return _internals42.isSemgrepAvailable();
94580
+ return _internals45.isSemgrepAvailable();
93866
94581
  }
93867
94582
  function resetSemgrepCache() {
93868
94583
  semgrepAvailableCache = null;
@@ -93959,12 +94674,12 @@ async function runSemgrep(options) {
93959
94674
  const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
93960
94675
  if (files.length === 0) {
93961
94676
  return {
93962
- available: _internals42.isSemgrepAvailable(),
94677
+ available: _internals45.isSemgrepAvailable(),
93963
94678
  findings: [],
93964
94679
  engine: "tier_a"
93965
94680
  };
93966
94681
  }
93967
- if (!_internals42.isSemgrepAvailable()) {
94682
+ if (!_internals45.isSemgrepAvailable()) {
93968
94683
  return {
93969
94684
  available: false,
93970
94685
  findings: [],
@@ -94020,14 +94735,14 @@ async function runSemgrep(options) {
94020
94735
  }
94021
94736
  function getRulesDirectory(projectRoot) {
94022
94737
  if (projectRoot) {
94023
- return path110.resolve(projectRoot, DEFAULT_RULES_DIR);
94738
+ return path113.resolve(projectRoot, DEFAULT_RULES_DIR);
94024
94739
  }
94025
94740
  return DEFAULT_RULES_DIR;
94026
94741
  }
94027
94742
  function hasBundledRules(projectRoot) {
94028
94743
  const rulesDir = getRulesDirectory(projectRoot);
94029
94744
  try {
94030
- return fs85.existsSync(rulesDir);
94745
+ return fs87.existsSync(rulesDir);
94031
94746
  } catch {
94032
94747
  return false;
94033
94748
  }
@@ -94039,26 +94754,26 @@ init_create_tool();
94039
94754
 
94040
94755
  // src/tools/sast-baseline.ts
94041
94756
  init_utils2();
94042
- import * as crypto9 from "node:crypto";
94043
- import * as fs86 from "node:fs";
94044
- import * as path111 from "node:path";
94757
+ import * as crypto10 from "node:crypto";
94758
+ import * as fs88 from "node:fs";
94759
+ import * as path114 from "node:path";
94045
94760
  var BASELINE_SCHEMA_VERSION = "1.0.0";
94046
94761
  var MAX_BASELINE_FINDINGS = 2000;
94047
94762
  var MAX_BASELINE_BYTES = 2 * 1048576;
94048
94763
  var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
94049
94764
  function normalizeFindingPath(directory, file3) {
94050
- const resolved = path111.isAbsolute(file3) ? file3 : path111.resolve(directory, file3);
94051
- const rel = path111.relative(path111.resolve(directory), resolved);
94765
+ const resolved = path114.isAbsolute(file3) ? file3 : path114.resolve(directory, file3);
94766
+ const rel = path114.relative(path114.resolve(directory), resolved);
94052
94767
  return rel.replace(/\\/g, "/");
94053
94768
  }
94054
94769
  function baselineRelPath(phase) {
94055
- return path111.join("evidence", String(phase), "sast-baseline.json");
94770
+ return path114.join("evidence", String(phase), "sast-baseline.json");
94056
94771
  }
94057
94772
  function tempRelPath(phase) {
94058
- return path111.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
94773
+ return path114.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
94059
94774
  }
94060
94775
  function lockRelPath(phase) {
94061
- return path111.join("evidence", String(phase), "sast-baseline.json.lock");
94776
+ return path114.join("evidence", String(phase), "sast-baseline.json.lock");
94062
94777
  }
94063
94778
  function getLine(lines, idx) {
94064
94779
  if (idx < 0 || idx >= lines.length)
@@ -94075,7 +94790,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
94075
94790
  }
94076
94791
  const lineNum = finding.location.line;
94077
94792
  try {
94078
- const content = fs86.readFileSync(finding.location.file, "utf-8");
94793
+ const content = fs88.readFileSync(finding.location.file, "utf-8");
94079
94794
  const lines = content.split(`
94080
94795
  `);
94081
94796
  const idx = lineNum - 1;
@@ -94085,7 +94800,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
94085
94800
  getLine(lines, idx + 1)
94086
94801
  ].join(`
94087
94802
  `);
94088
- const hash3 = crypto9.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94803
+ const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94089
94804
  return {
94090
94805
  fingerprint: `${relFile}|${finding.rule_id}|${hash3}|#${occurrenceIndex}`,
94091
94806
  stable: true
@@ -94106,7 +94821,7 @@ function assignOccurrenceIndices(findings, directory) {
94106
94821
  try {
94107
94822
  if (relFile.startsWith(".."))
94108
94823
  throw new Error("escapes workspace");
94109
- const content = fs86.readFileSync(finding.location.file, "utf-8");
94824
+ const content = fs88.readFileSync(finding.location.file, "utf-8");
94110
94825
  const lines = content.split(`
94111
94826
  `);
94112
94827
  const idx = lineNum - 1;
@@ -94116,14 +94831,14 @@ function assignOccurrenceIndices(findings, directory) {
94116
94831
  getLine(lines, idx + 1)
94117
94832
  ].join(`
94118
94833
  `);
94119
- const hash3 = crypto9.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94834
+ const hash3 = crypto10.createHash("sha256").update(window2).digest("hex").slice(0, 16);
94120
94835
  baseKey = `${relFile}|${finding.rule_id}|${hash3}`;
94121
94836
  } catch {
94122
94837
  baseKey = `${relFile}|${finding.rule_id}|L${lineNum}|UNSTABLE`;
94123
94838
  }
94124
94839
  const occIdx = countMap.get(baseKey) ?? 0;
94125
94840
  countMap.set(baseKey, occIdx + 1);
94126
- const fp = _internals43.fingerprintFinding(finding, directory, occIdx);
94841
+ const fp = _internals46.fingerprintFinding(finding, directory, occIdx);
94127
94842
  return {
94128
94843
  finding,
94129
94844
  index: occIdx,
@@ -94135,11 +94850,11 @@ function assignOccurrenceIndices(findings, directory) {
94135
94850
  async function acquireLock2(lockPath) {
94136
94851
  for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
94137
94852
  try {
94138
- const fd = fs86.openSync(lockPath, "wx");
94139
- fs86.closeSync(fd);
94853
+ const fd = fs88.openSync(lockPath, "wx");
94854
+ fs88.closeSync(fd);
94140
94855
  return () => {
94141
94856
  try {
94142
- fs86.unlinkSync(lockPath);
94857
+ fs88.unlinkSync(lockPath);
94143
94858
  } catch {}
94144
94859
  };
94145
94860
  } catch {
@@ -94179,20 +94894,20 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
94179
94894
  message: e instanceof Error ? e.message : "Path validation failed"
94180
94895
  };
94181
94896
  }
94182
- fs86.mkdirSync(path111.dirname(baselinePath), { recursive: true });
94183
- fs86.mkdirSync(path111.dirname(tempPath), { recursive: true });
94897
+ fs88.mkdirSync(path114.dirname(baselinePath), { recursive: true });
94898
+ fs88.mkdirSync(path114.dirname(tempPath), { recursive: true });
94184
94899
  const releaseLock = await acquireLock2(lockPath);
94185
94900
  try {
94186
94901
  let existing = null;
94187
94902
  try {
94188
- const raw = fs86.readFileSync(baselinePath, "utf-8");
94903
+ const raw = fs88.readFileSync(baselinePath, "utf-8");
94189
94904
  const parsed = JSON.parse(raw);
94190
94905
  if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
94191
94906
  existing = parsed;
94192
94907
  }
94193
94908
  } catch {}
94194
94909
  const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
94195
- const indexed = _internals43.assignOccurrenceIndices(findings, directory);
94910
+ const indexed = _internals46.assignOccurrenceIndices(findings, directory);
94196
94911
  if (existing && !opts?.force) {
94197
94912
  const prunedFingerprints = existing.fingerprints.filter((fp) => {
94198
94913
  const relFile = fp.slice(0, fp.indexOf("|"));
@@ -94245,8 +94960,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
94245
94960
  message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
94246
94961
  };
94247
94962
  }
94248
- fs86.writeFileSync(tempPath, json4, "utf-8");
94249
- fs86.renameSync(tempPath, baselinePath);
94963
+ fs88.writeFileSync(tempPath, json4, "utf-8");
94964
+ fs88.renameSync(tempPath, baselinePath);
94250
94965
  return {
94251
94966
  status: "merged",
94252
94967
  path: baselinePath,
@@ -94277,8 +94992,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
94277
94992
  message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
94278
94993
  };
94279
94994
  }
94280
- fs86.writeFileSync(tempPath, json3, "utf-8");
94281
- fs86.renameSync(tempPath, baselinePath);
94995
+ fs88.writeFileSync(tempPath, json3, "utf-8");
94996
+ fs88.renameSync(tempPath, baselinePath);
94282
94997
  return {
94283
94998
  status: "written",
94284
94999
  path: baselinePath,
@@ -94303,7 +95018,7 @@ function loadBaseline(directory, phase) {
94303
95018
  };
94304
95019
  }
94305
95020
  try {
94306
- const raw = fs86.readFileSync(baselinePath, "utf-8");
95021
+ const raw = fs88.readFileSync(baselinePath, "utf-8");
94307
95022
  const parsed = JSON.parse(raw);
94308
95023
  if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
94309
95024
  return {
@@ -94332,7 +95047,7 @@ function loadBaseline(directory, phase) {
94332
95047
  };
94333
95048
  }
94334
95049
  }
94335
- var _internals43 = {
95050
+ var _internals46 = {
94336
95051
  fingerprintFinding,
94337
95052
  assignOccurrenceIndices,
94338
95053
  captureOrMergeBaseline,
@@ -94351,17 +95066,17 @@ var SEVERITY_ORDER = {
94351
95066
  };
94352
95067
  function shouldSkipFile(filePath) {
94353
95068
  try {
94354
- const stats = fs87.statSync(filePath);
95069
+ const stats = fs89.statSync(filePath);
94355
95070
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
94356
95071
  return { skip: true, reason: "file too large" };
94357
95072
  }
94358
95073
  if (stats.size === 0) {
94359
95074
  return { skip: true, reason: "empty file" };
94360
95075
  }
94361
- const fd = fs87.openSync(filePath, "r");
95076
+ const fd = fs89.openSync(filePath, "r");
94362
95077
  const buffer = Buffer.alloc(8192);
94363
- const bytesRead = fs87.readSync(fd, buffer, 0, 8192, 0);
94364
- fs87.closeSync(fd);
95078
+ const bytesRead = fs89.readSync(fd, buffer, 0, 8192, 0);
95079
+ fs89.closeSync(fd);
94365
95080
  if (bytesRead > 0) {
94366
95081
  let nullCount = 0;
94367
95082
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -94400,7 +95115,7 @@ function countBySeverity(findings) {
94400
95115
  }
94401
95116
  function scanFileWithTierA(filePath, language) {
94402
95117
  try {
94403
- const content = fs87.readFileSync(filePath, "utf-8");
95118
+ const content = fs89.readFileSync(filePath, "utf-8");
94404
95119
  const findings = executeRulesSync(filePath, content, language);
94405
95120
  return findings.map((f) => ({
94406
95121
  rule_id: f.rule_id,
@@ -94453,13 +95168,13 @@ async function sastScan(input, directory, config3) {
94453
95168
  _filesSkipped++;
94454
95169
  continue;
94455
95170
  }
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) {
95171
+ const resolvedPath = path115.isAbsolute(filePath) ? filePath : path115.resolve(directory, filePath);
95172
+ const resolvedDirectory = path115.resolve(directory);
95173
+ if (!resolvedPath.startsWith(resolvedDirectory + path115.sep) && resolvedPath !== resolvedDirectory) {
94459
95174
  _filesSkipped++;
94460
95175
  continue;
94461
95176
  }
94462
- if (!fs87.existsSync(resolvedPath)) {
95177
+ if (!fs89.existsSync(resolvedPath)) {
94463
95178
  _filesSkipped++;
94464
95179
  continue;
94465
95180
  }
@@ -94468,7 +95183,7 @@ async function sastScan(input, directory, config3) {
94468
95183
  _filesSkipped++;
94469
95184
  continue;
94470
95185
  }
94471
- const ext = extname19(resolvedPath).toLowerCase();
95186
+ const ext = extname20(resolvedPath).toLowerCase();
94472
95187
  const profile = getProfileForFile(resolvedPath);
94473
95188
  const langDef = getLanguageForExtension(ext);
94474
95189
  if (!profile && !langDef) {
@@ -94742,11 +95457,11 @@ var sast_scan = createSwarmTool({
94742
95457
  capture_baseline: safeArgs.capture_baseline,
94743
95458
  phase: safeArgs.phase
94744
95459
  };
94745
- const result = await _internals44.sastScan(input, directory);
95460
+ const result = await _internals47.sastScan(input, directory);
94746
95461
  return JSON.stringify(result, null, 2);
94747
95462
  }
94748
95463
  });
94749
- var _internals44 = {
95464
+ var _internals47 = {
94750
95465
  sastScan,
94751
95466
  sast_scan
94752
95467
  };
@@ -94770,18 +95485,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
94770
95485
  let resolved;
94771
95486
  const isWinAbs = isWindowsAbsolutePath(inputPath);
94772
95487
  if (isWinAbs) {
94773
- resolved = path113.win32.resolve(inputPath);
94774
- } else if (path113.isAbsolute(inputPath)) {
94775
- resolved = path113.resolve(inputPath);
95488
+ resolved = path116.win32.resolve(inputPath);
95489
+ } else if (path116.isAbsolute(inputPath)) {
95490
+ resolved = path116.resolve(inputPath);
94776
95491
  } else {
94777
- resolved = path113.resolve(baseDir, inputPath);
95492
+ resolved = path116.resolve(baseDir, inputPath);
94778
95493
  }
94779
- const workspaceResolved = path113.resolve(workspaceDir);
95494
+ const workspaceResolved = path116.resolve(workspaceDir);
94780
95495
  let relative24;
94781
95496
  if (isWinAbs) {
94782
- relative24 = path113.win32.relative(workspaceResolved, resolved);
95497
+ relative24 = path116.win32.relative(workspaceResolved, resolved);
94783
95498
  } else {
94784
- relative24 = path113.relative(workspaceResolved, resolved);
95499
+ relative24 = path116.relative(workspaceResolved, resolved);
94785
95500
  }
94786
95501
  if (relative24.startsWith("..")) {
94787
95502
  return "path traversal detected";
@@ -94846,7 +95561,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
94846
95561
  if (typeof file3 !== "string") {
94847
95562
  continue;
94848
95563
  }
94849
- const resolvedPath = path113.resolve(file3);
95564
+ const resolvedPath = path116.resolve(file3);
94850
95565
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
94851
95566
  if (validationError) {
94852
95567
  continue;
@@ -95003,7 +95718,7 @@ async function runSecretscanWithFiles(files, directory) {
95003
95718
  skippedFiles++;
95004
95719
  continue;
95005
95720
  }
95006
- const resolvedPath = path113.resolve(file3);
95721
+ const resolvedPath = path116.resolve(file3);
95007
95722
  const validationError = validatePath(resolvedPath, directory, directory);
95008
95723
  if (validationError) {
95009
95724
  skippedFiles++;
@@ -95021,14 +95736,14 @@ async function runSecretscanWithFiles(files, directory) {
95021
95736
  };
95022
95737
  }
95023
95738
  for (const file3 of validatedFiles) {
95024
- const ext = path113.extname(file3).toLowerCase();
95739
+ const ext = path116.extname(file3).toLowerCase();
95025
95740
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
95026
95741
  skippedFiles++;
95027
95742
  continue;
95028
95743
  }
95029
95744
  let stat8;
95030
95745
  try {
95031
- stat8 = fs88.statSync(file3);
95746
+ stat8 = fs90.statSync(file3);
95032
95747
  } catch {
95033
95748
  skippedFiles++;
95034
95749
  continue;
@@ -95039,7 +95754,7 @@ async function runSecretscanWithFiles(files, directory) {
95039
95754
  }
95040
95755
  let content;
95041
95756
  try {
95042
- const buffer = fs88.readFileSync(file3);
95757
+ const buffer = fs90.readFileSync(file3);
95043
95758
  if (buffer.includes(0)) {
95044
95759
  skippedFiles++;
95045
95760
  continue;
@@ -95240,7 +95955,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
95240
95955
  const preexistingFindings = [];
95241
95956
  for (const finding of findings) {
95242
95957
  const filePath = finding.location.file;
95243
- const normalised = path113.relative(directory, filePath).replace(/\\/g, "/");
95958
+ const normalised = path116.relative(directory, filePath).replace(/\\/g, "/");
95244
95959
  const changedLines = changedLineRanges.get(normalised);
95245
95960
  if (changedLines?.has(finding.location.line)) {
95246
95961
  newFindings.push(finding);
@@ -95291,7 +96006,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
95291
96006
  warn(`pre_check_batch: Invalid file path: ${file3}`);
95292
96007
  continue;
95293
96008
  }
95294
- changedFiles.push(path113.resolve(directory, file3));
96009
+ changedFiles.push(path116.resolve(directory, file3));
95295
96010
  }
95296
96011
  if (changedFiles.length === 0) {
95297
96012
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -95492,7 +96207,7 @@ var pre_check_batch = createSwarmTool({
95492
96207
  };
95493
96208
  return JSON.stringify(errorResult, null, 2);
95494
96209
  }
95495
- const resolvedDirectory = path113.resolve(typedArgs.directory);
96210
+ const resolvedDirectory = path116.resolve(typedArgs.directory);
95496
96211
  const workspaceAnchor = resolvedDirectory;
95497
96212
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
95498
96213
  if (dirError) {
@@ -95533,7 +96248,7 @@ var pre_check_batch = createSwarmTool({
95533
96248
  });
95534
96249
  // src/tools/repo-map.ts
95535
96250
  init_zod();
95536
- import * as path114 from "node:path";
96251
+ import * as path117 from "node:path";
95537
96252
  init_path_security();
95538
96253
  init_create_tool();
95539
96254
  var VALID_ACTIONS = [
@@ -95558,7 +96273,7 @@ function validateFile(p) {
95558
96273
  return "file contains control characters";
95559
96274
  if (containsPathTraversal(p))
95560
96275
  return "file contains path traversal";
95561
- if (path114.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
96276
+ if (path117.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
95562
96277
  return "file must be a workspace-relative path, not absolute";
95563
96278
  }
95564
96279
  return null;
@@ -95581,8 +96296,8 @@ function ok(action, payload) {
95581
96296
  }
95582
96297
  function toRelativeGraphPath(input, workspaceRoot) {
95583
96298
  const normalized = input.replace(/\\/g, "/");
95584
- if (path114.isAbsolute(normalized)) {
95585
- const rel = path114.relative(workspaceRoot, normalized).replace(/\\/g, "/");
96299
+ if (path117.isAbsolute(normalized)) {
96300
+ const rel = path117.relative(workspaceRoot, normalized).replace(/\\/g, "/");
95586
96301
  return normalizeGraphPath2(rel);
95587
96302
  }
95588
96303
  return normalizeGraphPath2(normalized);
@@ -95726,8 +96441,8 @@ var repo_map = createSwarmTool({
95726
96441
  // src/tools/req-coverage.ts
95727
96442
  init_zod();
95728
96443
  init_create_tool();
95729
- import * as fs89 from "node:fs";
95730
- import * as path115 from "node:path";
96444
+ import * as fs91 from "node:fs";
96445
+ import * as path118 from "node:path";
95731
96446
  var SPEC_FILE = ".swarm/spec.md";
95732
96447
  var EVIDENCE_DIR4 = ".swarm/evidence";
95733
96448
  var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
@@ -95786,19 +96501,19 @@ function extractObligationAndText(id, lineText) {
95786
96501
  var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
95787
96502
  function readTouchedFiles(evidenceDir, phase, cwd) {
95788
96503
  const touchedFiles = new Set;
95789
- if (!fs89.existsSync(evidenceDir) || !fs89.statSync(evidenceDir).isDirectory()) {
96504
+ if (!fs91.existsSync(evidenceDir) || !fs91.statSync(evidenceDir).isDirectory()) {
95790
96505
  return [];
95791
96506
  }
95792
96507
  let entries;
95793
96508
  try {
95794
- entries = fs89.readdirSync(evidenceDir);
96509
+ entries = fs91.readdirSync(evidenceDir);
95795
96510
  } catch {
95796
96511
  return [];
95797
96512
  }
95798
96513
  for (const entry of entries) {
95799
- const entryPath = path115.join(evidenceDir, entry);
96514
+ const entryPath = path118.join(evidenceDir, entry);
95800
96515
  try {
95801
- const stat8 = fs89.statSync(entryPath);
96516
+ const stat8 = fs91.statSync(entryPath);
95802
96517
  if (!stat8.isDirectory()) {
95803
96518
  continue;
95804
96519
  }
@@ -95812,14 +96527,14 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95812
96527
  if (entryPhase !== String(phase)) {
95813
96528
  continue;
95814
96529
  }
95815
- const evidenceFilePath = path115.join(entryPath, "evidence.json");
96530
+ const evidenceFilePath = path118.join(entryPath, "evidence.json");
95816
96531
  try {
95817
- const resolvedPath = path115.resolve(evidenceFilePath);
95818
- const evidenceDirResolved = path115.resolve(evidenceDir);
95819
- if (!resolvedPath.startsWith(evidenceDirResolved + path115.sep)) {
96532
+ const resolvedPath = path118.resolve(evidenceFilePath);
96533
+ const evidenceDirResolved = path118.resolve(evidenceDir);
96534
+ if (!resolvedPath.startsWith(evidenceDirResolved + path118.sep)) {
95820
96535
  continue;
95821
96536
  }
95822
- const stat8 = fs89.lstatSync(evidenceFilePath);
96537
+ const stat8 = fs91.lstatSync(evidenceFilePath);
95823
96538
  if (!stat8.isFile()) {
95824
96539
  continue;
95825
96540
  }
@@ -95831,7 +96546,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95831
96546
  }
95832
96547
  let content;
95833
96548
  try {
95834
- content = fs89.readFileSync(evidenceFilePath, "utf-8");
96549
+ content = fs91.readFileSync(evidenceFilePath, "utf-8");
95835
96550
  } catch {
95836
96551
  continue;
95837
96552
  }
@@ -95850,7 +96565,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95850
96565
  if (Array.isArray(diffEntry.files_changed)) {
95851
96566
  for (const file3 of diffEntry.files_changed) {
95852
96567
  if (typeof file3 === "string") {
95853
- touchedFiles.add(path115.resolve(cwd, file3));
96568
+ touchedFiles.add(path118.resolve(cwd, file3));
95854
96569
  }
95855
96570
  }
95856
96571
  }
@@ -95863,12 +96578,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
95863
96578
  }
95864
96579
  function searchFileForKeywords(filePath, keywords, cwd) {
95865
96580
  try {
95866
- const resolvedPath = path115.resolve(filePath);
95867
- const cwdResolved = path115.resolve(cwd);
96581
+ const resolvedPath = path118.resolve(filePath);
96582
+ const cwdResolved = path118.resolve(cwd);
95868
96583
  if (!resolvedPath.startsWith(cwdResolved)) {
95869
96584
  return false;
95870
96585
  }
95871
- const content = fs89.readFileSync(resolvedPath, "utf-8");
96586
+ const content = fs91.readFileSync(resolvedPath, "utf-8");
95872
96587
  for (const keyword of keywords) {
95873
96588
  const regex = new RegExp(`\\b${keyword}\\b`, "i");
95874
96589
  if (regex.test(content)) {
@@ -95998,10 +96713,10 @@ var req_coverage = createSwarmTool({
95998
96713
  }, null, 2);
95999
96714
  }
96000
96715
  const cwd = inputDirectory || directory;
96001
- const specPath = path115.join(cwd, SPEC_FILE);
96716
+ const specPath = path118.join(cwd, SPEC_FILE);
96002
96717
  let specContent;
96003
96718
  try {
96004
- specContent = fs89.readFileSync(specPath, "utf-8");
96719
+ specContent = fs91.readFileSync(specPath, "utf-8");
96005
96720
  } catch (readError) {
96006
96721
  return JSON.stringify({
96007
96722
  success: false,
@@ -96025,7 +96740,7 @@ var req_coverage = createSwarmTool({
96025
96740
  message: "No FR requirements found in spec.md"
96026
96741
  }, null, 2);
96027
96742
  }
96028
- const evidenceDir = path115.join(cwd, EVIDENCE_DIR4);
96743
+ const evidenceDir = path118.join(cwd, EVIDENCE_DIR4);
96029
96744
  const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
96030
96745
  const analyzedRequirements = [];
96031
96746
  let coveredCount = 0;
@@ -96051,12 +96766,12 @@ var req_coverage = createSwarmTool({
96051
96766
  requirements: analyzedRequirements
96052
96767
  };
96053
96768
  const reportFilename = `req-coverage-phase-${phase}.json`;
96054
- const reportPath = path115.join(evidenceDir, reportFilename);
96769
+ const reportPath = path118.join(evidenceDir, reportFilename);
96055
96770
  try {
96056
- if (!fs89.existsSync(evidenceDir)) {
96057
- fs89.mkdirSync(evidenceDir, { recursive: true });
96771
+ if (!fs91.existsSync(evidenceDir)) {
96772
+ fs91.mkdirSync(evidenceDir, { recursive: true });
96058
96773
  }
96059
- fs89.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
96774
+ fs91.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
96060
96775
  } catch (writeError) {
96061
96776
  console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
96062
96777
  }
@@ -96137,9 +96852,9 @@ init_zod();
96137
96852
  init_plan_schema();
96138
96853
  init_qa_gate_profile();
96139
96854
  init_file_locks();
96140
- import * as crypto10 from "node:crypto";
96141
- import * as fs90 from "node:fs";
96142
- import * as path116 from "node:path";
96855
+ import * as crypto11 from "node:crypto";
96856
+ import * as fs92 from "node:fs";
96857
+ import * as path119 from "node:path";
96143
96858
  init_ledger();
96144
96859
  init_manager();
96145
96860
  init_state();
@@ -96217,17 +96932,17 @@ async function executeSavePlan(args2, fallbackDir) {
96217
96932
  };
96218
96933
  }
96219
96934
  if (args2.working_directory && fallbackDir) {
96220
- const resolvedTarget = path116.resolve(args2.working_directory);
96221
- const resolvedRoot = path116.resolve(fallbackDir);
96935
+ const resolvedTarget = path119.resolve(args2.working_directory);
96936
+ const resolvedRoot = path119.resolve(fallbackDir);
96222
96937
  let fallbackExists = false;
96223
96938
  try {
96224
- fs90.accessSync(resolvedRoot, fs90.constants.F_OK);
96939
+ fs92.accessSync(resolvedRoot, fs92.constants.F_OK);
96225
96940
  fallbackExists = true;
96226
96941
  } catch {
96227
96942
  fallbackExists = false;
96228
96943
  }
96229
96944
  if (fallbackExists) {
96230
- const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path116.sep);
96945
+ const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path119.sep);
96231
96946
  if (isSubdirectory) {
96232
96947
  return {
96233
96948
  success: false,
@@ -96243,12 +96958,12 @@ async function executeSavePlan(args2, fallbackDir) {
96243
96958
  let specMtime;
96244
96959
  let specHash;
96245
96960
  if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
96246
- const specPath = path116.join(targetWorkspace, ".swarm", "spec.md");
96961
+ const specPath = path119.join(targetWorkspace, ".swarm", "spec.md");
96247
96962
  try {
96248
- const stat8 = await fs90.promises.stat(specPath);
96963
+ const stat8 = await fs92.promises.stat(specPath);
96249
96964
  specMtime = stat8.mtime.toISOString();
96250
- const content = await fs90.promises.readFile(specPath, "utf8");
96251
- specHash = crypto10.createHash("sha256").update(content).digest("hex");
96965
+ const content = await fs92.promises.readFile(specPath, "utf8");
96966
+ specHash = crypto11.createHash("sha256").update(content).digest("hex");
96252
96967
  } catch {
96253
96968
  return {
96254
96969
  success: false,
@@ -96259,10 +96974,10 @@ async function executeSavePlan(args2, fallbackDir) {
96259
96974
  }
96260
96975
  }
96261
96976
  if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
96262
- const contextPath = path116.join(targetWorkspace, ".swarm", "context.md");
96977
+ const contextPath = path119.join(targetWorkspace, ".swarm", "context.md");
96263
96978
  let contextContent = "";
96264
96979
  try {
96265
- contextContent = await fs90.promises.readFile(contextPath, "utf8");
96980
+ contextContent = await fs92.promises.readFile(contextPath, "utf8");
96266
96981
  } catch {}
96267
96982
  const hasPendingSection = contextContent.includes("## Pending QA Gate Selection");
96268
96983
  if (!hasPendingSection) {
@@ -96516,14 +97231,14 @@ async function executeSavePlan(args2, fallbackDir) {
96516
97231
  }
96517
97232
  await writeCheckpoint(dir).catch(() => {});
96518
97233
  try {
96519
- const markerPath = path116.join(dir, ".swarm", ".plan-write-marker");
97234
+ const markerPath = path119.join(dir, ".swarm", ".plan-write-marker");
96520
97235
  const marker = JSON.stringify({
96521
97236
  source: "save_plan",
96522
97237
  timestamp: new Date().toISOString(),
96523
97238
  phases_count: plan.phases.length,
96524
97239
  tasks_count: tasksCount
96525
97240
  });
96526
- await fs90.promises.writeFile(markerPath, marker, "utf8");
97241
+ await fs92.promises.writeFile(markerPath, marker, "utf8");
96527
97242
  } catch {}
96528
97243
  const warnings = [];
96529
97244
  let criticReviewFound = false;
@@ -96539,7 +97254,7 @@ async function executeSavePlan(args2, fallbackDir) {
96539
97254
  return {
96540
97255
  success: true,
96541
97256
  message: "Plan saved successfully",
96542
- plan_path: path116.join(dir, ".swarm", "plan.json"),
97257
+ plan_path: path119.join(dir, ".swarm", "plan.json"),
96543
97258
  phases_count: plan.phases.length,
96544
97259
  tasks_count: tasksCount,
96545
97260
  ...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
@@ -96603,8 +97318,8 @@ var save_plan = createSwarmTool({
96603
97318
  // src/tools/sbom-generate.ts
96604
97319
  init_zod();
96605
97320
  init_manager2();
96606
- import * as fs91 from "node:fs";
96607
- import * as path117 from "node:path";
97321
+ import * as fs93 from "node:fs";
97322
+ import * as path120 from "node:path";
96608
97323
 
96609
97324
  // src/sbom/detectors/index.ts
96610
97325
  init_utils();
@@ -97452,9 +98167,9 @@ function findManifestFiles(rootDir) {
97452
98167
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
97453
98168
  function searchDir(dir) {
97454
98169
  try {
97455
- const entries = fs91.readdirSync(dir, { withFileTypes: true });
98170
+ const entries = fs93.readdirSync(dir, { withFileTypes: true });
97456
98171
  for (const entry of entries) {
97457
- const fullPath = path117.join(dir, entry.name);
98172
+ const fullPath = path120.join(dir, entry.name);
97458
98173
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
97459
98174
  continue;
97460
98175
  }
@@ -97463,7 +98178,7 @@ function findManifestFiles(rootDir) {
97463
98178
  } else if (entry.isFile()) {
97464
98179
  for (const pattern of patterns) {
97465
98180
  if (simpleGlobToRegex(pattern).test(entry.name)) {
97466
- manifestFiles.push(path117.relative(rootDir, fullPath));
98181
+ manifestFiles.push(path120.relative(rootDir, fullPath));
97467
98182
  break;
97468
98183
  }
97469
98184
  }
@@ -97479,13 +98194,13 @@ function findManifestFilesInDirs(directories, workingDir) {
97479
98194
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
97480
98195
  for (const dir of directories) {
97481
98196
  try {
97482
- const entries = fs91.readdirSync(dir, { withFileTypes: true });
98197
+ const entries = fs93.readdirSync(dir, { withFileTypes: true });
97483
98198
  for (const entry of entries) {
97484
- const fullPath = path117.join(dir, entry.name);
98199
+ const fullPath = path120.join(dir, entry.name);
97485
98200
  if (entry.isFile()) {
97486
98201
  for (const pattern of patterns) {
97487
98202
  if (simpleGlobToRegex(pattern).test(entry.name)) {
97488
- found.push(path117.relative(workingDir, fullPath));
98203
+ found.push(path120.relative(workingDir, fullPath));
97489
98204
  break;
97490
98205
  }
97491
98206
  }
@@ -97498,11 +98213,11 @@ function findManifestFilesInDirs(directories, workingDir) {
97498
98213
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
97499
98214
  const dirs = new Set;
97500
98215
  for (const file3 of changedFiles) {
97501
- let currentDir = path117.dirname(file3);
98216
+ let currentDir = path120.dirname(file3);
97502
98217
  while (true) {
97503
- if (currentDir && currentDir !== "." && currentDir !== path117.sep) {
97504
- dirs.add(path117.join(workingDir, currentDir));
97505
- const parent = path117.dirname(currentDir);
98218
+ if (currentDir && currentDir !== "." && currentDir !== path120.sep) {
98219
+ dirs.add(path120.join(workingDir, currentDir));
98220
+ const parent = path120.dirname(currentDir);
97506
98221
  if (parent === currentDir)
97507
98222
  break;
97508
98223
  currentDir = parent;
@@ -97516,7 +98231,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
97516
98231
  }
97517
98232
  function ensureOutputDir(outputDir) {
97518
98233
  try {
97519
- fs91.mkdirSync(outputDir, { recursive: true });
98234
+ fs93.mkdirSync(outputDir, { recursive: true });
97520
98235
  } catch (error93) {
97521
98236
  if (!error93 || error93.code !== "EEXIST") {
97522
98237
  throw error93;
@@ -97586,7 +98301,7 @@ var sbom_generate = createSwarmTool({
97586
98301
  const changedFiles = obj.changed_files;
97587
98302
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
97588
98303
  const workingDir = directory;
97589
- const outputDir = path117.isAbsolute(relativeOutputDir) ? relativeOutputDir : path117.join(workingDir, relativeOutputDir);
98304
+ const outputDir = path120.isAbsolute(relativeOutputDir) ? relativeOutputDir : path120.join(workingDir, relativeOutputDir);
97590
98305
  let manifestFiles = [];
97591
98306
  if (scope === "all") {
97592
98307
  manifestFiles = findManifestFiles(workingDir);
@@ -97609,11 +98324,11 @@ var sbom_generate = createSwarmTool({
97609
98324
  const processedFiles = [];
97610
98325
  for (const manifestFile of manifestFiles) {
97611
98326
  try {
97612
- const fullPath = path117.isAbsolute(manifestFile) ? manifestFile : path117.join(workingDir, manifestFile);
97613
- if (!fs91.existsSync(fullPath)) {
98327
+ const fullPath = path120.isAbsolute(manifestFile) ? manifestFile : path120.join(workingDir, manifestFile);
98328
+ if (!fs93.existsSync(fullPath)) {
97614
98329
  continue;
97615
98330
  }
97616
- const content = fs91.readFileSync(fullPath, "utf-8");
98331
+ const content = fs93.readFileSync(fullPath, "utf-8");
97617
98332
  const components = detectComponents(manifestFile, content);
97618
98333
  processedFiles.push(manifestFile);
97619
98334
  if (components.length > 0) {
@@ -97626,8 +98341,8 @@ var sbom_generate = createSwarmTool({
97626
98341
  const bom = generateCycloneDX(allComponents);
97627
98342
  const bomJson = serializeCycloneDX(bom);
97628
98343
  const filename = generateSbomFilename();
97629
- const outputPath = path117.join(outputDir, filename);
97630
- fs91.writeFileSync(outputPath, bomJson, "utf-8");
98344
+ const outputPath = path120.join(outputDir, filename);
98345
+ fs93.writeFileSync(outputPath, bomJson, "utf-8");
97631
98346
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
97632
98347
  try {
97633
98348
  const timestamp = new Date().toISOString();
@@ -97669,8 +98384,8 @@ var sbom_generate = createSwarmTool({
97669
98384
  // src/tools/schema-drift.ts
97670
98385
  init_zod();
97671
98386
  init_create_tool();
97672
- import * as fs92 from "node:fs";
97673
- import * as path118 from "node:path";
98387
+ import * as fs94 from "node:fs";
98388
+ import * as path121 from "node:path";
97674
98389
  var SPEC_CANDIDATES = [
97675
98390
  "openapi.json",
97676
98391
  "openapi.yaml",
@@ -97702,28 +98417,28 @@ function normalizePath4(p) {
97702
98417
  }
97703
98418
  function discoverSpecFile(cwd, specFileArg) {
97704
98419
  if (specFileArg) {
97705
- const resolvedPath = path118.resolve(cwd, specFileArg);
97706
- const normalizedCwd = cwd.endsWith(path118.sep) ? cwd : cwd + path118.sep;
98420
+ const resolvedPath = path121.resolve(cwd, specFileArg);
98421
+ const normalizedCwd = cwd.endsWith(path121.sep) ? cwd : cwd + path121.sep;
97707
98422
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
97708
98423
  throw new Error("Invalid spec_file: path traversal detected");
97709
98424
  }
97710
- const ext = path118.extname(resolvedPath).toLowerCase();
98425
+ const ext = path121.extname(resolvedPath).toLowerCase();
97711
98426
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
97712
98427
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
97713
98428
  }
97714
- const stats = fs92.statSync(resolvedPath);
98429
+ const stats = fs94.statSync(resolvedPath);
97715
98430
  if (stats.size > MAX_SPEC_SIZE) {
97716
98431
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
97717
98432
  }
97718
- if (!fs92.existsSync(resolvedPath)) {
98433
+ if (!fs94.existsSync(resolvedPath)) {
97719
98434
  throw new Error(`Spec file not found: ${resolvedPath}`);
97720
98435
  }
97721
98436
  return resolvedPath;
97722
98437
  }
97723
98438
  for (const candidate of SPEC_CANDIDATES) {
97724
- const candidatePath = path118.resolve(cwd, candidate);
97725
- if (fs92.existsSync(candidatePath)) {
97726
- const stats = fs92.statSync(candidatePath);
98439
+ const candidatePath = path121.resolve(cwd, candidate);
98440
+ if (fs94.existsSync(candidatePath)) {
98441
+ const stats = fs94.statSync(candidatePath);
97727
98442
  if (stats.size <= MAX_SPEC_SIZE) {
97728
98443
  return candidatePath;
97729
98444
  }
@@ -97732,8 +98447,8 @@ function discoverSpecFile(cwd, specFileArg) {
97732
98447
  return null;
97733
98448
  }
97734
98449
  function parseSpec(specFile) {
97735
- const content = fs92.readFileSync(specFile, "utf-8");
97736
- const ext = path118.extname(specFile).toLowerCase();
98450
+ const content = fs94.readFileSync(specFile, "utf-8");
98451
+ const ext = path121.extname(specFile).toLowerCase();
97737
98452
  if (ext === ".json") {
97738
98453
  return parseJsonSpec(content);
97739
98454
  }
@@ -97804,12 +98519,12 @@ function extractRoutes(cwd) {
97804
98519
  function walkDir(dir) {
97805
98520
  let entries;
97806
98521
  try {
97807
- entries = fs92.readdirSync(dir, { withFileTypes: true });
98522
+ entries = fs94.readdirSync(dir, { withFileTypes: true });
97808
98523
  } catch {
97809
98524
  return;
97810
98525
  }
97811
98526
  for (const entry of entries) {
97812
- const fullPath = path118.join(dir, entry.name);
98527
+ const fullPath = path121.join(dir, entry.name);
97813
98528
  if (entry.isSymbolicLink()) {
97814
98529
  continue;
97815
98530
  }
@@ -97819,7 +98534,7 @@ function extractRoutes(cwd) {
97819
98534
  }
97820
98535
  walkDir(fullPath);
97821
98536
  } else if (entry.isFile()) {
97822
- const ext = path118.extname(entry.name).toLowerCase();
98537
+ const ext = path121.extname(entry.name).toLowerCase();
97823
98538
  const baseName = entry.name.toLowerCase();
97824
98539
  if (![".ts", ".js", ".mjs"].includes(ext)) {
97825
98540
  continue;
@@ -97837,7 +98552,7 @@ function extractRoutes(cwd) {
97837
98552
  }
97838
98553
  function extractRoutesFromFile(filePath) {
97839
98554
  const routes = [];
97840
- const content = fs92.readFileSync(filePath, "utf-8");
98555
+ const content = fs94.readFileSync(filePath, "utf-8");
97841
98556
  const lines = content.split(/\r?\n/);
97842
98557
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
97843
98558
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -97986,8 +98701,8 @@ init_zod();
97986
98701
  init_bun_compat();
97987
98702
  init_path_security();
97988
98703
  init_create_tool();
97989
- import * as fs93 from "node:fs";
97990
- import * as path119 from "node:path";
98704
+ import * as fs95 from "node:fs";
98705
+ import * as path122 from "node:path";
97991
98706
  var DEFAULT_MAX_RESULTS = 100;
97992
98707
  var DEFAULT_MAX_LINES = 200;
97993
98708
  var REGEX_TIMEOUT_MS = 5000;
@@ -98023,11 +98738,11 @@ function containsWindowsAttacks3(str) {
98023
98738
  }
98024
98739
  function isPathInWorkspace3(filePath, workspace) {
98025
98740
  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)) {
98741
+ const resolvedPath = path122.resolve(workspace, filePath);
98742
+ const realWorkspace = fs95.realpathSync(workspace);
98743
+ const realResolvedPath = fs95.realpathSync(resolvedPath);
98744
+ const relativePath = path122.relative(realWorkspace, realResolvedPath);
98745
+ if (relativePath.startsWith("..") || path122.isAbsolute(relativePath)) {
98031
98746
  return false;
98032
98747
  }
98033
98748
  return true;
@@ -98040,12 +98755,12 @@ function validatePathForRead2(filePath, workspace) {
98040
98755
  }
98041
98756
  function findRgInEnvPath() {
98042
98757
  const searchPath = process.env.PATH ?? "";
98043
- for (const dir of searchPath.split(path119.delimiter)) {
98758
+ for (const dir of searchPath.split(path122.delimiter)) {
98044
98759
  if (!dir)
98045
98760
  continue;
98046
98761
  const isWindows = process.platform === "win32";
98047
- const candidate = path119.join(dir, isWindows ? "rg.exe" : "rg");
98048
- if (fs93.existsSync(candidate))
98762
+ const candidate = path122.join(dir, isWindows ? "rg.exe" : "rg");
98763
+ if (fs95.existsSync(candidate))
98049
98764
  return candidate;
98050
98765
  }
98051
98766
  return null;
@@ -98172,10 +98887,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
98172
98887
  return files;
98173
98888
  }
98174
98889
  try {
98175
- const entries = fs93.readdirSync(dir, { withFileTypes: true });
98890
+ const entries = fs95.readdirSync(dir, { withFileTypes: true });
98176
98891
  for (const entry of entries) {
98177
- const fullPath = path119.join(dir, entry.name);
98178
- const relativePath = path119.relative(workspace, fullPath);
98892
+ const fullPath = path122.join(dir, entry.name);
98893
+ const relativePath = path122.relative(workspace, fullPath);
98179
98894
  if (!validatePathForRead2(fullPath, workspace)) {
98180
98895
  continue;
98181
98896
  }
@@ -98216,13 +98931,13 @@ async function fallbackSearch(opts) {
98216
98931
  const matches = [];
98217
98932
  let total = 0;
98218
98933
  for (const file3 of files) {
98219
- const fullPath = path119.join(opts.workspace, file3);
98934
+ const fullPath = path122.join(opts.workspace, file3);
98220
98935
  if (!validatePathForRead2(fullPath, opts.workspace)) {
98221
98936
  continue;
98222
98937
  }
98223
98938
  let stats;
98224
98939
  try {
98225
- stats = fs93.statSync(fullPath);
98940
+ stats = fs95.statSync(fullPath);
98226
98941
  if (stats.size > MAX_FILE_SIZE_BYTES10) {
98227
98942
  continue;
98228
98943
  }
@@ -98231,7 +98946,7 @@ async function fallbackSearch(opts) {
98231
98946
  }
98232
98947
  let content;
98233
98948
  try {
98234
- content = fs93.readFileSync(fullPath, "utf-8");
98949
+ content = fs95.readFileSync(fullPath, "utf-8");
98235
98950
  } catch {
98236
98951
  continue;
98237
98952
  }
@@ -98343,7 +99058,7 @@ var search = createSwarmTool({
98343
99058
  message: "Exclude pattern contains invalid Windows-specific sequence"
98344
99059
  }, null, 2);
98345
99060
  }
98346
- if (!fs93.existsSync(directory)) {
99061
+ if (!fs95.existsSync(directory)) {
98347
99062
  return JSON.stringify({
98348
99063
  error: true,
98349
99064
  type: "unknown",
@@ -98584,7 +99299,7 @@ init_config();
98584
99299
  init_schema();
98585
99300
  init_create_tool();
98586
99301
  import { mkdir as mkdir19, rename as rename8, writeFile as writeFile15 } from "node:fs/promises";
98587
- import * as path120 from "node:path";
99302
+ import * as path123 from "node:path";
98588
99303
  var MAX_SPEC_BYTES = 256 * 1024;
98589
99304
  var spec_write = createSwarmTool({
98590
99305
  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 +99340,14 @@ var spec_write = createSwarmTool({
98625
99340
  reason: 'spec must contain at least one top-level "# Heading"'
98626
99341
  }, null, 2);
98627
99342
  }
98628
- const target = path120.join(directory, ".swarm", "spec.md");
98629
- await mkdir19(path120.dirname(target), { recursive: true });
99343
+ const target = path123.join(directory, ".swarm", "spec.md");
99344
+ await mkdir19(path123.dirname(target), { recursive: true });
98630
99345
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
98631
99346
  let finalContent = content;
98632
99347
  if (mode === "append") {
98633
99348
  try {
98634
- const fs94 = await import("node:fs/promises");
98635
- const prior = await fs94.readFile(target, "utf-8");
99349
+ const fs96 = await import("node:fs/promises");
99350
+ const prior = await fs96.readFile(target, "utf-8");
98636
99351
  finalContent = `${prior.replace(/\s+$/, "")}
98637
99352
 
98638
99353
  ${content}
@@ -98654,14 +99369,14 @@ ${content}
98654
99369
  init_zod();
98655
99370
  init_loader();
98656
99371
  import {
98657
- existsSync as existsSync70,
98658
- mkdirSync as mkdirSync29,
98659
- readFileSync as readFileSync61,
98660
- renameSync as renameSync19,
99372
+ existsSync as existsSync72,
99373
+ mkdirSync as mkdirSync31,
99374
+ readFileSync as readFileSync62,
99375
+ renameSync as renameSync20,
98661
99376
  unlinkSync as unlinkSync15,
98662
- writeFileSync as writeFileSync23
99377
+ writeFileSync as writeFileSync24
98663
99378
  } from "node:fs";
98664
- import path121 from "node:path";
99379
+ import path124 from "node:path";
98665
99380
  init_create_tool();
98666
99381
  init_resolve_working_directory();
98667
99382
  var VerdictSchema2 = exports_external.object({
@@ -98791,9 +99506,9 @@ var submit_phase_council_verdicts = createSwarmTool({
98791
99506
  }
98792
99507
  });
98793
99508
  function getPhaseMutationGapFinding(phaseNumber, workingDir) {
98794
- const mutationGatePath = path121.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
99509
+ const mutationGatePath = path124.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
98795
99510
  try {
98796
- const raw = readFileSync61(mutationGatePath, "utf-8");
99511
+ const raw = readFileSync62(mutationGatePath, "utf-8");
98797
99512
  const parsed = JSON.parse(raw);
98798
99513
  const gateEntry = (parsed.entries ?? []).find((entry) => entry?.type === "mutation-gate");
98799
99514
  if (!gateEntry) {
@@ -98853,9 +99568,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
98853
99568
  }
98854
99569
  }
98855
99570
  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");
99571
+ const evidenceDir = path124.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
99572
+ mkdirSync31(evidenceDir, { recursive: true });
99573
+ const evidenceFile = path124.join(evidenceDir, "phase-council.json");
98859
99574
  const evidenceBundle = {
98860
99575
  entries: [
98861
99576
  {
@@ -98888,10 +99603,10 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
98888
99603
  };
98889
99604
  const tempFile = `${evidenceFile}.tmp-${Date.now()}`;
98890
99605
  try {
98891
- writeFileSync23(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
98892
- renameSync19(tempFile, evidenceFile);
99606
+ writeFileSync24(tempFile, JSON.stringify(evidenceBundle, null, 2), "utf-8");
99607
+ renameSync20(tempFile, evidenceFile);
98893
99608
  } finally {
98894
- if (existsSync70(tempFile)) {
99609
+ if (existsSync72(tempFile)) {
98895
99610
  unlinkSync15(tempFile);
98896
99611
  }
98897
99612
  }
@@ -98940,8 +99655,8 @@ function createSwarmCommandTool(agents) {
98940
99655
  init_zod();
98941
99656
  init_path_security();
98942
99657
  init_create_tool();
98943
- import * as fs94 from "node:fs";
98944
- import * as path122 from "node:path";
99658
+ import * as fs96 from "node:fs";
99659
+ import * as path125 from "node:path";
98945
99660
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
98946
99661
  function containsWindowsAttacks4(str) {
98947
99662
  if (/:[^\\/]/.test(str))
@@ -98955,14 +99670,14 @@ function containsWindowsAttacks4(str) {
98955
99670
  }
98956
99671
  function isPathInWorkspace4(filePath, workspace) {
98957
99672
  try {
98958
- const resolvedPath = path122.resolve(workspace, filePath);
98959
- if (!fs94.existsSync(resolvedPath)) {
99673
+ const resolvedPath = path125.resolve(workspace, filePath);
99674
+ if (!fs96.existsSync(resolvedPath)) {
98960
99675
  return true;
98961
99676
  }
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)) {
99677
+ const realWorkspace = fs96.realpathSync(workspace);
99678
+ const realResolvedPath = fs96.realpathSync(resolvedPath);
99679
+ const relativePath = path125.relative(realWorkspace, realResolvedPath);
99680
+ if (relativePath.startsWith("..") || path125.isAbsolute(relativePath)) {
98966
99681
  return false;
98967
99682
  }
98968
99683
  return true;
@@ -99134,7 +99849,7 @@ var suggestPatch = createSwarmTool({
99134
99849
  message: "changes cannot be empty"
99135
99850
  }, null, 2);
99136
99851
  }
99137
- if (!fs94.existsSync(directory)) {
99852
+ if (!fs96.existsSync(directory)) {
99138
99853
  return JSON.stringify({
99139
99854
  success: false,
99140
99855
  error: true,
@@ -99170,8 +99885,8 @@ var suggestPatch = createSwarmTool({
99170
99885
  });
99171
99886
  continue;
99172
99887
  }
99173
- const fullPath = path122.resolve(directory, change.file);
99174
- if (!fs94.existsSync(fullPath)) {
99888
+ const fullPath = path125.resolve(directory, change.file);
99889
+ if (!fs96.existsSync(fullPath)) {
99175
99890
  errors5.push({
99176
99891
  success: false,
99177
99892
  error: true,
@@ -99185,7 +99900,7 @@ var suggestPatch = createSwarmTool({
99185
99900
  }
99186
99901
  let content;
99187
99902
  try {
99188
- content = fs94.readFileSync(fullPath, "utf-8");
99903
+ content = fs96.readFileSync(fullPath, "utf-8");
99189
99904
  } catch (err3) {
99190
99905
  errors5.push({
99191
99906
  success: false,
@@ -99473,12 +100188,12 @@ var lean_turbo_acquire_locks = createSwarmTool({
99473
100188
  // src/tools/lean-turbo-plan-lanes.ts
99474
100189
  init_zod();
99475
100190
  init_constants();
99476
- import * as fs96 from "node:fs";
99477
- import * as path124 from "node:path";
100191
+ import * as fs98 from "node:fs";
100192
+ import * as path127 from "node:path";
99478
100193
 
99479
100194
  // src/turbo/lean/conflicts.ts
99480
- import * as fs95 from "node:fs";
99481
- import * as path123 from "node:path";
100195
+ import * as fs97 from "node:fs";
100196
+ import * as path126 from "node:path";
99482
100197
  var DEFAULT_GLOBAL_FILES = [
99483
100198
  "package.json",
99484
100199
  "package-lock.json",
@@ -99605,12 +100320,12 @@ function isProtectedPath2(normalizedPath) {
99605
100320
  return false;
99606
100321
  }
99607
100322
  function readTaskScopes(directory, taskId) {
99608
- const scopePath = path123.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
100323
+ const scopePath = path126.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
99609
100324
  try {
99610
- if (!fs95.existsSync(scopePath)) {
100325
+ if (!fs97.existsSync(scopePath)) {
99611
100326
  return null;
99612
100327
  }
99613
- const raw = fs95.readFileSync(scopePath, "utf-8");
100328
+ const raw = fs97.readFileSync(scopePath, "utf-8");
99614
100329
  const parsed = JSON.parse(raw);
99615
100330
  if (!parsed || !Array.isArray(parsed.files)) {
99616
100331
  return null;
@@ -99993,12 +100708,12 @@ function createEmptyPlan(phaseNumber, planId) {
99993
100708
  // src/tools/lean-turbo-plan-lanes.ts
99994
100709
  init_create_tool();
99995
100710
  function readPlanJson(directory) {
99996
- const planPath = path124.join(directory, ".swarm", "plan.json");
99997
- if (!fs96.existsSync(planPath)) {
100711
+ const planPath = path127.join(directory, ".swarm", "plan.json");
100712
+ if (!fs98.existsSync(planPath)) {
99998
100713
  return null;
99999
100714
  }
100000
100715
  try {
100001
- return JSON.parse(fs96.readFileSync(planPath, "utf-8"));
100716
+ return JSON.parse(fs98.readFileSync(planPath, "utf-8"));
100002
100717
  } catch {
100003
100718
  return null;
100004
100719
  }
@@ -100047,8 +100762,8 @@ init_config();
100047
100762
 
100048
100763
  // src/turbo/lean/reviewer.ts
100049
100764
  init_state();
100050
- import * as fs97 from "node:fs/promises";
100051
- import * as path125 from "node:path";
100765
+ import * as fs99 from "node:fs/promises";
100766
+ import * as path128 from "node:path";
100052
100767
  init_state3();
100053
100768
  var DEFAULT_CONFIG3 = {
100054
100769
  reviewerAgent: "",
@@ -100070,7 +100785,7 @@ function resolveDefaultReviewerAgent(generatedAgentNames) {
100070
100785
  }
100071
100786
  async function compileReviewPackage(directory, phase, sessionID, requireDiffSummary) {
100072
100787
  const lanes = await listLaneEvidence(directory, phase);
100073
- const persisted = _internals45.readPersisted?.(directory) ?? null;
100788
+ const persisted = _internals48.readPersisted?.(directory) ?? null;
100074
100789
  if (persisted) {
100075
100790
  let matchingRunState = null;
100076
100791
  for (const sessionState of Object.values(persisted.sessions)) {
@@ -100164,9 +100879,9 @@ function parseReviewerVerdict(responseText) {
100164
100879
  return { verdict, reason };
100165
100880
  }
100166
100881
  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");
100882
+ const evidenceDir = path128.join(directory, ".swarm", "evidence", String(phase));
100883
+ await fs99.mkdir(evidenceDir, { recursive: true });
100884
+ const evidencePath = path128.join(evidenceDir, "lean-turbo-reviewer.json");
100170
100885
  const content = JSON.stringify({
100171
100886
  phase,
100172
100887
  verdict,
@@ -100175,11 +100890,11 @@ async function writeReviewerEvidence(directory, phase, verdict, reason) {
100175
100890
  }, null, 2);
100176
100891
  const tempPath = `${evidencePath}.tmp.${process.pid}.${Date.now()}`;
100177
100892
  try {
100178
- await fs97.writeFile(tempPath, content, "utf-8");
100179
- await fs97.rename(tempPath, evidencePath);
100893
+ await fs99.writeFile(tempPath, content, "utf-8");
100894
+ await fs99.rename(tempPath, evidencePath);
100180
100895
  } catch (error93) {
100181
100896
  try {
100182
- await fs97.unlink(tempPath);
100897
+ await fs99.unlink(tempPath);
100183
100898
  } catch {}
100184
100899
  throw error93;
100185
100900
  }
@@ -100262,7 +100977,7 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
100262
100977
  client.session.delete({ path: { id: sessionId } }).catch(() => {});
100263
100978
  }
100264
100979
  }
100265
- var _internals45 = {
100980
+ var _internals48 = {
100266
100981
  compileReviewPackage,
100267
100982
  parseReviewerVerdict,
100268
100983
  writeReviewerEvidence,
@@ -100279,28 +100994,28 @@ async function dispatchPhaseReviewer(directory, phase, sessionID, config3) {
100279
100994
  };
100280
100995
  const generatedAgentNames = swarmState.generatedAgentNames;
100281
100996
  const agentName = mergedConfig.reviewerAgent || resolveDefaultReviewerAgent(generatedAgentNames);
100282
- const pkg = await _internals45.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
100997
+ const pkg = await _internals48.compileReviewPackage(directory, phase, sessionID, mergedConfig.requireDiffSummary);
100283
100998
  let responseText;
100284
100999
  try {
100285
- responseText = await _internals45.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
101000
+ responseText = await _internals48.dispatchReviewerAgent(directory, pkg, agentName, mergedConfig.timeoutMs);
100286
101001
  } catch (error93) {
100287
- const evidencePath2 = await _internals45.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
101002
+ const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", error93 instanceof Error ? error93.message : String(error93));
100288
101003
  return {
100289
101004
  verdict: "REJECTED",
100290
101005
  reason: `Reviewer dispatch failed: ${error93 instanceof Error ? error93.message : String(error93)}`,
100291
101006
  evidencePath: evidencePath2
100292
101007
  };
100293
101008
  }
100294
- const parsed = _internals45.parseReviewerVerdict(responseText);
101009
+ const parsed = _internals48.parseReviewerVerdict(responseText);
100295
101010
  if (!parsed) {
100296
- const evidencePath2 = await _internals45.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
101011
+ const evidencePath2 = await _internals48.writeReviewerEvidence(directory, phase, "REJECTED", "Reviewer response could not be parsed");
100297
101012
  return {
100298
101013
  verdict: "REJECTED",
100299
101014
  reason: "Reviewer response could not be parsed",
100300
101015
  evidencePath: evidencePath2
100301
101016
  };
100302
101017
  }
100303
- const evidencePath = await _internals45.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
101018
+ const evidencePath = await _internals48.writeReviewerEvidence(directory, phase, parsed.verdict, parsed.reason);
100304
101019
  return {
100305
101020
  verdict: parsed.verdict,
100306
101021
  reason: parsed.reason,
@@ -100806,7 +101521,7 @@ ${fileList}
100806
101521
 
100807
101522
  // src/tools/lean-turbo-run-phase.ts
100808
101523
  init_create_tool();
100809
- var _internals46 = {
101524
+ var _internals49 = {
100810
101525
  LeanTurboRunner,
100811
101526
  loadPluginConfigWithMeta
100812
101527
  };
@@ -100816,9 +101531,9 @@ async function executeLeanTurboRunPhase(args2) {
100816
101531
  let runError = null;
100817
101532
  let runner = null;
100818
101533
  try {
100819
- const { config: config3 } = _internals46.loadPluginConfigWithMeta(directory);
101534
+ const { config: config3 } = _internals49.loadPluginConfigWithMeta(directory);
100820
101535
  const leanConfig = config3.turbo?.strategy === "lean" ? config3.turbo.lean : undefined;
100821
- runner = new _internals46.LeanTurboRunner({
101536
+ runner = new _internals49.LeanTurboRunner({
100822
101537
  directory,
100823
101538
  sessionID,
100824
101539
  opencodeClient: swarmState.opencodeClient ?? null,
@@ -100970,8 +101685,8 @@ var lean_turbo_status = createSwarmTool({
100970
101685
  // src/tools/lint-spec.ts
100971
101686
  init_spec_schema();
100972
101687
  init_create_tool();
100973
- import * as fs98 from "node:fs";
100974
- import * as path126 from "node:path";
101688
+ import * as fs100 from "node:fs";
101689
+ import * as path129 from "node:path";
100975
101690
  var SPEC_FILE_NAME = "spec.md";
100976
101691
  var SWARM_DIR2 = ".swarm";
100977
101692
  var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
@@ -101024,8 +101739,8 @@ var lint_spec = createSwarmTool({
101024
101739
  async execute(_args, directory) {
101025
101740
  const errors5 = [];
101026
101741
  const warnings = [];
101027
- const specPath = path126.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
101028
- if (!fs98.existsSync(specPath)) {
101742
+ const specPath = path129.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
101743
+ if (!fs100.existsSync(specPath)) {
101029
101744
  const result2 = {
101030
101745
  valid: false,
101031
101746
  specMtime: null,
@@ -101044,12 +101759,12 @@ var lint_spec = createSwarmTool({
101044
101759
  }
101045
101760
  let specMtime = null;
101046
101761
  try {
101047
- const stats = fs98.statSync(specPath);
101762
+ const stats = fs100.statSync(specPath);
101048
101763
  specMtime = stats.mtime.toISOString();
101049
101764
  } catch {}
101050
101765
  let content;
101051
101766
  try {
101052
- content = fs98.readFileSync(specPath, "utf-8");
101767
+ content = fs100.readFileSync(specPath, "utf-8");
101053
101768
  } catch (e) {
101054
101769
  const result2 = {
101055
101770
  valid: false,
@@ -101094,13 +101809,13 @@ var lint_spec = createSwarmTool({
101094
101809
  });
101095
101810
  // src/tools/mutation-test.ts
101096
101811
  init_zod();
101097
- import * as fs99 from "node:fs";
101098
- import * as path128 from "node:path";
101812
+ import * as fs101 from "node:fs";
101813
+ import * as path131 from "node:path";
101099
101814
 
101100
101815
  // src/mutation/engine.ts
101101
101816
  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";
101817
+ import { unlinkSync as unlinkSync16, writeFileSync as writeFileSync25 } from "node:fs";
101818
+ import * as path130 from "node:path";
101104
101819
 
101105
101820
  // src/mutation/equivalence.ts
101106
101821
  function isStaticallyEquivalent(originalCode, mutatedCode) {
@@ -101172,7 +101887,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
101172
101887
  const strippedMutated = stripCode(mutatedCode);
101173
101888
  return strippedOriginal === strippedMutated;
101174
101889
  }
101175
- var _internals47 = {
101890
+ var _internals50 = {
101176
101891
  isStaticallyEquivalent,
101177
101892
  checkEquivalence,
101178
101893
  batchCheckEquivalence
@@ -101212,7 +101927,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
101212
101927
  const results = [];
101213
101928
  for (const { patch, originalCode, mutatedCode } of patches) {
101214
101929
  try {
101215
- const result = await _internals47.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
101930
+ const result = await _internals50.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
101216
101931
  results.push(result);
101217
101932
  } catch (err3) {
101218
101933
  results.push({
@@ -101240,9 +101955,9 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
101240
101955
  let patchFile;
101241
101956
  try {
101242
101957
  const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
101243
- patchFile = path127.join(workingDir, `.mutation_patch_${safeId2}.diff`);
101958
+ patchFile = path130.join(workingDir, `.mutation_patch_${safeId2}.diff`);
101244
101959
  try {
101245
- writeFileSync24(patchFile, patch.patch);
101960
+ writeFileSync25(patchFile, patch.patch);
101246
101961
  } catch (writeErr) {
101247
101962
  error93 = `Failed to write patch file: ${writeErr}`;
101248
101963
  outcome = "error";
@@ -101512,7 +102227,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
101512
102227
  }
101513
102228
 
101514
102229
  // src/mutation/gate.ts
101515
- var _internals48 = {
102230
+ var _internals51 = {
101516
102231
  evaluateMutationGate,
101517
102232
  buildTestImprovementPrompt,
101518
102233
  buildMessage
@@ -101533,8 +102248,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
101533
102248
  } else {
101534
102249
  verdict = "fail";
101535
102250
  }
101536
- const testImprovementPrompt = _internals48.buildTestImprovementPrompt(report, passThreshold, verdict);
101537
- const message = _internals48.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
102251
+ const testImprovementPrompt = _internals51.buildTestImprovementPrompt(report, passThreshold, verdict);
102252
+ const message = _internals51.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
101538
102253
  return {
101539
102254
  verdict,
101540
102255
  killRate: report.killRate,
@@ -101639,8 +102354,8 @@ var mutation_test = createSwarmTool({
101639
102354
  ];
101640
102355
  for (const filePath of uniquePaths) {
101641
102356
  try {
101642
- const resolvedPath = path128.resolve(cwd, filePath);
101643
- sourceFiles.set(filePath, fs99.readFileSync(resolvedPath, "utf-8"));
102357
+ const resolvedPath = path131.resolve(cwd, filePath);
102358
+ sourceFiles.set(filePath, fs101.readFileSync(resolvedPath, "utf-8"));
101644
102359
  } catch {}
101645
102360
  }
101646
102361
  const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
@@ -101658,8 +102373,8 @@ var mutation_test = createSwarmTool({
101658
102373
  init_zod();
101659
102374
  init_manager2();
101660
102375
  init_detector();
101661
- import * as fs100 from "node:fs";
101662
- import * as path129 from "node:path";
102376
+ import * as fs102 from "node:fs";
102377
+ import * as path132 from "node:path";
101663
102378
  init_create_tool();
101664
102379
  var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
101665
102380
  var BINARY_CHECK_BYTES = 8192;
@@ -101725,7 +102440,7 @@ async function syntaxCheck(input, directory, config3) {
101725
102440
  if (languages?.length) {
101726
102441
  const lowerLangs = languages.map((l) => l.toLowerCase());
101727
102442
  filesToCheck = filesToCheck.filter((file3) => {
101728
- const ext = path129.extname(file3.path).toLowerCase();
102443
+ const ext = path132.extname(file3.path).toLowerCase();
101729
102444
  const langDef = getLanguageForExtension(ext);
101730
102445
  const fileProfile = getProfileForFile(file3.path);
101731
102446
  const langId = fileProfile?.id || langDef?.id;
@@ -101738,7 +102453,7 @@ async function syntaxCheck(input, directory, config3) {
101738
102453
  let skippedCount = 0;
101739
102454
  for (const fileInfo of filesToCheck) {
101740
102455
  const { path: filePath } = fileInfo;
101741
- const fullPath = path129.isAbsolute(filePath) ? filePath : path129.join(directory, filePath);
102456
+ const fullPath = path132.isAbsolute(filePath) ? filePath : path132.join(directory, filePath);
101742
102457
  const result = {
101743
102458
  path: filePath,
101744
102459
  language: "",
@@ -101768,7 +102483,7 @@ async function syntaxCheck(input, directory, config3) {
101768
102483
  }
101769
102484
  let content;
101770
102485
  try {
101771
- content = fs100.readFileSync(fullPath, "utf8");
102486
+ content = fs102.readFileSync(fullPath, "utf8");
101772
102487
  } catch {
101773
102488
  result.skipped_reason = "file_read_error";
101774
102489
  skippedCount++;
@@ -101787,7 +102502,7 @@ async function syntaxCheck(input, directory, config3) {
101787
102502
  results.push(result);
101788
102503
  continue;
101789
102504
  }
101790
- const ext = path129.extname(filePath).toLowerCase();
102505
+ const ext = path132.extname(filePath).toLowerCase();
101791
102506
  const langDef = getLanguageForExtension(ext);
101792
102507
  result.language = profile?.id || langDef?.id || "unknown";
101793
102508
  const errors5 = extractSyntaxErrors(parser, content);
@@ -101879,8 +102594,8 @@ init_zod();
101879
102594
  init_utils();
101880
102595
  init_create_tool();
101881
102596
  init_path_security();
101882
- import * as fs101 from "node:fs";
101883
- import * as path130 from "node:path";
102597
+ import * as fs103 from "node:fs";
102598
+ import * as path133 from "node:path";
101884
102599
  var MAX_TEXT_LENGTH = 200;
101885
102600
  var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
101886
102601
  var SUPPORTED_EXTENSIONS4 = new Set([
@@ -101946,9 +102661,9 @@ function validatePathsInput(paths, cwd) {
101946
102661
  return { error: "paths contains path traversal", resolvedPath: null };
101947
102662
  }
101948
102663
  try {
101949
- const resolvedPath = path130.resolve(paths);
101950
- const normalizedCwd = path130.resolve(cwd);
101951
- const normalizedResolved = path130.resolve(resolvedPath);
102664
+ const resolvedPath = path133.resolve(paths);
102665
+ const normalizedCwd = path133.resolve(cwd);
102666
+ const normalizedResolved = path133.resolve(resolvedPath);
101952
102667
  if (!normalizedResolved.startsWith(normalizedCwd)) {
101953
102668
  return {
101954
102669
  error: "paths must be within the current working directory",
@@ -101964,13 +102679,13 @@ function validatePathsInput(paths, cwd) {
101964
102679
  }
101965
102680
  }
101966
102681
  function isSupportedExtension(filePath) {
101967
- const ext = path130.extname(filePath).toLowerCase();
102682
+ const ext = path133.extname(filePath).toLowerCase();
101968
102683
  return SUPPORTED_EXTENSIONS4.has(ext);
101969
102684
  }
101970
102685
  function findSourceFiles3(dir, files = []) {
101971
102686
  let entries;
101972
102687
  try {
101973
- entries = fs101.readdirSync(dir);
102688
+ entries = fs103.readdirSync(dir);
101974
102689
  } catch {
101975
102690
  return files;
101976
102691
  }
@@ -101979,10 +102694,10 @@ function findSourceFiles3(dir, files = []) {
101979
102694
  if (SKIP_DIRECTORIES5.has(entry)) {
101980
102695
  continue;
101981
102696
  }
101982
- const fullPath = path130.join(dir, entry);
102697
+ const fullPath = path133.join(dir, entry);
101983
102698
  let stat8;
101984
102699
  try {
101985
- stat8 = fs101.statSync(fullPath);
102700
+ stat8 = fs103.statSync(fullPath);
101986
102701
  } catch {
101987
102702
  continue;
101988
102703
  }
@@ -102075,7 +102790,7 @@ var todo_extract = createSwarmTool({
102075
102790
  return JSON.stringify(errorResult, null, 2);
102076
102791
  }
102077
102792
  const scanPath = resolvedPath;
102078
- if (!fs101.existsSync(scanPath)) {
102793
+ if (!fs103.existsSync(scanPath)) {
102079
102794
  const errorResult = {
102080
102795
  error: `path not found: ${pathsInput}`,
102081
102796
  total: 0,
@@ -102085,13 +102800,13 @@ var todo_extract = createSwarmTool({
102085
102800
  return JSON.stringify(errorResult, null, 2);
102086
102801
  }
102087
102802
  const filesToScan = [];
102088
- const stat8 = fs101.statSync(scanPath);
102803
+ const stat8 = fs103.statSync(scanPath);
102089
102804
  if (stat8.isFile()) {
102090
102805
  if (isSupportedExtension(scanPath)) {
102091
102806
  filesToScan.push(scanPath);
102092
102807
  } else {
102093
102808
  const errorResult = {
102094
- error: `unsupported file extension: ${path130.extname(scanPath)}`,
102809
+ error: `unsupported file extension: ${path133.extname(scanPath)}`,
102095
102810
  total: 0,
102096
102811
  byPriority: { high: 0, medium: 0, low: 0 },
102097
102812
  entries: []
@@ -102104,11 +102819,11 @@ var todo_extract = createSwarmTool({
102104
102819
  const allEntries = [];
102105
102820
  for (const filePath of filesToScan) {
102106
102821
  try {
102107
- const fileStat = fs101.statSync(filePath);
102822
+ const fileStat = fs103.statSync(filePath);
102108
102823
  if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
102109
102824
  continue;
102110
102825
  }
102111
- const content = fs101.readFileSync(filePath, "utf-8");
102826
+ const content = fs103.readFileSync(filePath, "utf-8");
102112
102827
  const entries = parseTodoComments(content, filePath, tagsSet);
102113
102828
  allEntries.push(...entries);
102114
102829
  } catch {}
@@ -102139,19 +102854,19 @@ init_loader();
102139
102854
  init_schema();
102140
102855
  init_qa_gate_profile();
102141
102856
  init_gate_evidence();
102142
- import * as fs105 from "node:fs";
102143
- import * as path134 from "node:path";
102857
+ import * as fs107 from "node:fs";
102858
+ import * as path137 from "node:path";
102144
102859
 
102145
102860
  // src/hooks/diff-scope.ts
102146
102861
  init_bun_compat();
102147
- import * as fs103 from "node:fs";
102148
- import * as path132 from "node:path";
102862
+ import * as fs105 from "node:fs";
102863
+ import * as path135 from "node:path";
102149
102864
 
102150
102865
  // src/utils/gitignore-warning.ts
102151
102866
  init_bun_compat();
102152
- import * as fs102 from "node:fs";
102153
- import * as path131 from "node:path";
102154
- var _internals49 = { bunSpawn };
102867
+ import * as fs104 from "node:fs";
102868
+ import * as path134 from "node:path";
102869
+ var _internals52 = { bunSpawn };
102155
102870
  var _swarmGitExcludedChecked = false;
102156
102871
  function fileCoversSwarm(content) {
102157
102872
  for (const rawLine of content.split(`
@@ -102184,7 +102899,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102184
102899
  checkIgnoreExitCode
102185
102900
  ] = await Promise.all([
102186
102901
  (async () => {
102187
- const proc = _internals49.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
102902
+ const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
102188
102903
  try {
102189
102904
  return await Promise.all([proc.exited, proc.stdout.text()]);
102190
102905
  } finally {
@@ -102194,7 +102909,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102194
102909
  }
102195
102910
  })(),
102196
102911
  (async () => {
102197
- const proc = _internals49.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
102912
+ const proc = _internals52.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
102198
102913
  try {
102199
102914
  return await Promise.all([proc.exited, proc.stdout.text()]);
102200
102915
  } finally {
@@ -102204,7 +102919,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102204
102919
  }
102205
102920
  })(),
102206
102921
  (async () => {
102207
- const proc = _internals49.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
102922
+ const proc = _internals52.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
102208
102923
  try {
102209
102924
  return await proc.exited;
102210
102925
  } finally {
@@ -102224,16 +102939,16 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102224
102939
  const excludeRelPath = excludePathRaw.trim();
102225
102940
  if (!excludeRelPath)
102226
102941
  return;
102227
- const excludePath = path131.isAbsolute(excludeRelPath) ? excludeRelPath : path131.join(directory, excludeRelPath);
102942
+ const excludePath = path134.isAbsolute(excludeRelPath) ? excludeRelPath : path134.join(directory, excludeRelPath);
102228
102943
  if (checkIgnoreExitCode !== 0) {
102229
102944
  try {
102230
- fs102.mkdirSync(path131.dirname(excludePath), { recursive: true });
102945
+ fs104.mkdirSync(path134.dirname(excludePath), { recursive: true });
102231
102946
  let existing = "";
102232
102947
  try {
102233
- existing = fs102.readFileSync(excludePath, "utf8");
102948
+ existing = fs104.readFileSync(excludePath, "utf8");
102234
102949
  } catch {}
102235
102950
  if (!fileCoversSwarm(existing)) {
102236
- fs102.appendFileSync(excludePath, `
102951
+ fs104.appendFileSync(excludePath, `
102237
102952
  # opencode-swarm local runtime state
102238
102953
  .swarm/
102239
102954
  `, "utf8");
@@ -102243,7 +102958,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102243
102958
  }
102244
102959
  } catch {}
102245
102960
  }
102246
- const trackedProc = _internals49.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
102961
+ const trackedProc = _internals52.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
102247
102962
  let trackedExitCode;
102248
102963
  let trackedOutput;
102249
102964
  try {
@@ -102268,13 +102983,13 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
102268
102983
  }
102269
102984
 
102270
102985
  // src/hooks/diff-scope.ts
102271
- var _internals50 = { bunSpawn };
102986
+ var _internals53 = { bunSpawn };
102272
102987
  function getDeclaredScope(taskId, directory) {
102273
102988
  try {
102274
- const planPath = path132.join(directory, ".swarm", "plan.json");
102275
- if (!fs103.existsSync(planPath))
102989
+ const planPath = path135.join(directory, ".swarm", "plan.json");
102990
+ if (!fs105.existsSync(planPath))
102276
102991
  return null;
102277
- const raw = fs103.readFileSync(planPath, "utf-8");
102992
+ const raw = fs105.readFileSync(planPath, "utf-8");
102278
102993
  const plan = JSON.parse(raw);
102279
102994
  for (const phase of plan.phases ?? []) {
102280
102995
  for (const task of phase.tasks ?? []) {
@@ -102303,7 +103018,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
102303
103018
  };
102304
103019
  async function getChangedFiles(directory) {
102305
103020
  try {
102306
- const proc = _internals50.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
103021
+ const proc = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
102307
103022
  cwd: directory,
102308
103023
  ...GIT_DIFF_SPAWN_OPTIONS
102309
103024
  });
@@ -102320,7 +103035,7 @@ async function getChangedFiles(directory) {
102320
103035
  return stdout.trim().split(`
102321
103036
  `).map((f) => f.trim()).filter((f) => f.length > 0);
102322
103037
  }
102323
- const proc2 = _internals50.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
103038
+ const proc2 = _internals53.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
102324
103039
  cwd: directory,
102325
103040
  ...GIT_DIFF_SPAWN_OPTIONS
102326
103041
  });
@@ -102376,9 +103091,9 @@ init_telemetry();
102376
103091
 
102377
103092
  // src/turbo/lean/task-completion.ts
102378
103093
  init_file_locks();
102379
- import * as fs104 from "node:fs";
102380
- import * as path133 from "node:path";
102381
- var _internals51 = {
103094
+ import * as fs106 from "node:fs";
103095
+ import * as path136 from "node:path";
103096
+ var _internals54 = {
102382
103097
  listActiveLocks,
102383
103098
  verifyLeanTurboTaskCompletion
102384
103099
  };
@@ -102396,7 +103111,7 @@ var TIER_3_PATTERNS = [
102396
103111
  ];
102397
103112
  function matchesTier3Pattern(files) {
102398
103113
  for (const file3 of files) {
102399
- const fileName = path133.basename(file3);
103114
+ const fileName = path136.basename(file3);
102400
103115
  for (const pattern of TIER_3_PATTERNS) {
102401
103116
  if (pattern.test(fileName)) {
102402
103117
  return true;
@@ -102408,14 +103123,14 @@ function matchesTier3Pattern(files) {
102408
103123
  function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102409
103124
  let persisted = null;
102410
103125
  try {
102411
- const statePath = path133.join(directory, ".swarm", "turbo-state.json");
102412
- if (!fs104.existsSync(statePath)) {
103126
+ const statePath = path136.join(directory, ".swarm", "turbo-state.json");
103127
+ if (!fs106.existsSync(statePath)) {
102413
103128
  return {
102414
103129
  ok: false,
102415
103130
  reason: "Lean Turbo state file not found"
102416
103131
  };
102417
103132
  }
102418
- const raw = fs104.readFileSync(statePath, "utf-8");
103133
+ const raw = fs106.readFileSync(statePath, "utf-8");
102419
103134
  persisted = JSON.parse(raw);
102420
103135
  } catch {
102421
103136
  return {
@@ -102492,11 +103207,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102492
103207
  };
102493
103208
  }
102494
103209
  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) {
103210
+ const evidencePath = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
103211
+ const expectedDir = path136.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
103212
+ const resolvedPath = path136.resolve(evidencePath);
103213
+ const resolvedDir = path136.resolve(expectedDir);
103214
+ if (!resolvedPath.startsWith(resolvedDir + path136.sep) && resolvedPath !== resolvedDir) {
102500
103215
  return {
102501
103216
  ok: false,
102502
103217
  reason: `Lane ID causes path traversal: ${lane.laneId}`,
@@ -102508,7 +103223,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102508
103223
  }
102509
103224
  };
102510
103225
  }
102511
- if (!fs104.existsSync(evidencePath)) {
103226
+ if (!fs106.existsSync(evidencePath)) {
102512
103227
  return {
102513
103228
  ok: false,
102514
103229
  reason: `Lane ${lane.laneId} evidence file not found: ${evidencePath}`,
@@ -102520,7 +103235,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102520
103235
  }
102521
103236
  };
102522
103237
  }
102523
- const activeLocks = _internals51.listActiveLocks(directory);
103238
+ const activeLocks = _internals54.listActiveLocks(directory);
102524
103239
  const laneLocks = activeLocks.filter((lock) => lock.laneId === lane.laneId);
102525
103240
  if (laneLocks.length > 0) {
102526
103241
  return {
@@ -102536,8 +103251,8 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
102536
103251
  }
102537
103252
  let filesTouched = [];
102538
103253
  try {
102539
- const planPath = path133.join(directory, ".swarm", "plan.json");
102540
- const planRaw = fs104.readFileSync(planPath, "utf-8");
103254
+ const planPath = path136.join(directory, ".swarm", "plan.json");
103255
+ const planRaw = fs106.readFileSync(planPath, "utf-8");
102541
103256
  const plan = JSON.parse(planRaw);
102542
103257
  for (const planPhase of plan.phases ?? []) {
102543
103258
  for (const task of planPhase.tasks ?? []) {
@@ -102619,7 +103334,7 @@ var TIER_3_PATTERNS2 = [
102619
103334
  ];
102620
103335
  function matchesTier3Pattern2(files) {
102621
103336
  for (const file3 of files) {
102622
- const fileName = path134.basename(file3);
103337
+ const fileName = path137.basename(file3);
102623
103338
  for (const pattern of TIER_3_PATTERNS2) {
102624
103339
  if (pattern.test(fileName)) {
102625
103340
  return true;
@@ -102651,8 +103366,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102651
103366
  if (!skipStandardTurboBypass && hasActiveTurboMode()) {
102652
103367
  const resolvedDir2 = workingDirectory;
102653
103368
  try {
102654
- const planPath = path134.join(resolvedDir2, ".swarm", "plan.json");
102655
- const planRaw = fs105.readFileSync(planPath, "utf-8");
103369
+ const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
103370
+ const planRaw = fs107.readFileSync(planPath, "utf-8");
102656
103371
  const plan = JSON.parse(planRaw);
102657
103372
  for (const planPhase of plan.phases ?? []) {
102658
103373
  for (const task of planPhase.tasks ?? []) {
@@ -102718,8 +103433,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
102718
103433
  }
102719
103434
  try {
102720
103435
  const resolvedDir2 = workingDirectory;
102721
- const planPath = path134.join(resolvedDir2, ".swarm", "plan.json");
102722
- const planRaw = fs105.readFileSync(planPath, "utf-8");
103436
+ const planPath = path137.join(resolvedDir2, ".swarm", "plan.json");
103437
+ const planRaw = fs107.readFileSync(planPath, "utf-8");
102723
103438
  const plan = JSON.parse(planRaw);
102724
103439
  for (const planPhase of plan.phases ?? []) {
102725
103440
  for (const task of planPhase.tasks ?? []) {
@@ -102903,8 +103618,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102903
103618
  };
102904
103619
  }
102905
103620
  }
102906
- normalizedDir = path134.normalize(args2.working_directory);
102907
- const pathParts = normalizedDir.split(path134.sep);
103621
+ normalizedDir = path137.normalize(args2.working_directory);
103622
+ const pathParts = normalizedDir.split(path137.sep);
102908
103623
  if (pathParts.includes("..")) {
102909
103624
  return {
102910
103625
  success: false,
@@ -102914,11 +103629,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102914
103629
  ]
102915
103630
  };
102916
103631
  }
102917
- const resolvedDir = path134.resolve(normalizedDir);
103632
+ const resolvedDir = path137.resolve(normalizedDir);
102918
103633
  try {
102919
- const realPath = fs105.realpathSync(resolvedDir);
102920
- const planPath = path134.join(realPath, ".swarm", "plan.json");
102921
- if (!fs105.existsSync(planPath)) {
103634
+ const realPath = fs107.realpathSync(resolvedDir);
103635
+ const planPath = path137.join(realPath, ".swarm", "plan.json");
103636
+ if (!fs107.existsSync(planPath)) {
102922
103637
  return {
102923
103638
  success: false,
102924
103639
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -102949,22 +103664,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102949
103664
  }
102950
103665
  if (args2.status === "in_progress") {
102951
103666
  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");
103667
+ const evidencePath = path137.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
103668
+ fs107.mkdirSync(path137.dirname(evidencePath), { recursive: true });
103669
+ const fd = fs107.openSync(evidencePath, "wx");
102955
103670
  let writeOk = false;
102956
103671
  try {
102957
- fs105.writeSync(fd, JSON.stringify({
103672
+ fs107.writeSync(fd, JSON.stringify({
102958
103673
  taskId: args2.task_id,
102959
103674
  required_gates: ["reviewer", "test_engineer"],
102960
103675
  gates: {}
102961
103676
  }, null, 2));
102962
103677
  writeOk = true;
102963
103678
  } finally {
102964
- fs105.closeSync(fd);
103679
+ fs107.closeSync(fd);
102965
103680
  if (!writeOk) {
102966
103681
  try {
102967
- fs105.unlinkSync(evidencePath);
103682
+ fs107.unlinkSync(evidencePath);
102968
103683
  } catch {}
102969
103684
  }
102970
103685
  }
@@ -102974,8 +103689,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
102974
103689
  recoverTaskStateFromDelegations(args2.task_id);
102975
103690
  let phaseRequiresReviewer = true;
102976
103691
  try {
102977
- const planPath = path134.join(directory, ".swarm", "plan.json");
102978
- const planRaw = fs105.readFileSync(planPath, "utf-8");
103692
+ const planPath = path137.join(directory, ".swarm", "plan.json");
103693
+ const planRaw = fs107.readFileSync(planPath, "utf-8");
102979
103694
  const plan = JSON.parse(planRaw);
102980
103695
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
102981
103696
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -103285,8 +104000,8 @@ init_utils2();
103285
104000
  init_ledger();
103286
104001
  init_manager();
103287
104002
  init_create_tool();
103288
- import fs106 from "node:fs";
103289
- import path135 from "node:path";
104003
+ import fs108 from "node:fs";
104004
+ import path138 from "node:path";
103290
104005
  function normalizeVerdict(verdict) {
103291
104006
  switch (verdict) {
103292
104007
  case "APPROVED":
@@ -103334,7 +104049,7 @@ async function executeWriteDriftEvidence(args2, directory) {
103334
104049
  entries: [evidenceEntry]
103335
104050
  };
103336
104051
  const filename = "drift-verifier.json";
103337
- const relativePath = path135.join("evidence", String(phase), filename);
104052
+ const relativePath = path138.join("evidence", String(phase), filename);
103338
104053
  let validatedPath;
103339
104054
  try {
103340
104055
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103345,12 +104060,12 @@ async function executeWriteDriftEvidence(args2, directory) {
103345
104060
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
103346
104061
  }, null, 2);
103347
104062
  }
103348
- const evidenceDir = path135.dirname(validatedPath);
104063
+ const evidenceDir = path138.dirname(validatedPath);
103349
104064
  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);
104065
+ await fs108.promises.mkdir(evidenceDir, { recursive: true });
104066
+ const tempPath = path138.join(evidenceDir, `.${filename}.tmp`);
104067
+ await fs108.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104068
+ await fs108.promises.rename(tempPath, validatedPath);
103354
104069
  let snapshotInfo;
103355
104070
  let snapshotError;
103356
104071
  let qaProfileLocked;
@@ -103443,8 +104158,8 @@ var write_drift_evidence = createSwarmTool({
103443
104158
  // src/tools/write-final-council-evidence.ts
103444
104159
  init_zod();
103445
104160
  init_loader();
103446
- import fs107 from "node:fs";
103447
- import path136 from "node:path";
104161
+ import fs109 from "node:fs";
104162
+ import path139 from "node:path";
103448
104163
  init_utils2();
103449
104164
  init_manager();
103450
104165
  init_create_tool();
@@ -103532,7 +104247,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
103532
104247
  timestamp: synthesis.timestamp
103533
104248
  };
103534
104249
  const filename = "final-council.json";
103535
- const relativePath = path136.join("evidence", filename);
104250
+ const relativePath = path139.join("evidence", filename);
103536
104251
  let validatedPath;
103537
104252
  try {
103538
104253
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103546,12 +104261,12 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
103546
104261
  const evidenceContent = {
103547
104262
  entries: [evidenceEntry]
103548
104263
  };
103549
- const evidenceDir = path136.dirname(validatedPath);
104264
+ const evidenceDir = path139.dirname(validatedPath);
103550
104265
  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);
104266
+ await fs109.promises.mkdir(evidenceDir, { recursive: true });
104267
+ const tempPath = path139.join(evidenceDir, `.${filename}.tmp`);
104268
+ await fs109.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104269
+ await fs109.promises.rename(tempPath, validatedPath);
103555
104270
  return JSON.stringify({
103556
104271
  success: true,
103557
104272
  phase: input.phase,
@@ -103607,8 +104322,8 @@ var write_final_council_evidence = createSwarmTool({
103607
104322
  init_zod();
103608
104323
  init_utils2();
103609
104324
  init_create_tool();
103610
- import fs108 from "node:fs";
103611
- import path137 from "node:path";
104325
+ import fs110 from "node:fs";
104326
+ import path140 from "node:path";
103612
104327
  function normalizeVerdict2(verdict) {
103613
104328
  switch (verdict) {
103614
104329
  case "APPROVED":
@@ -103656,7 +104371,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
103656
104371
  entries: [evidenceEntry]
103657
104372
  };
103658
104373
  const filename = "hallucination-guard.json";
103659
- const relativePath = path137.join("evidence", String(phase), filename);
104374
+ const relativePath = path140.join("evidence", String(phase), filename);
103660
104375
  let validatedPath;
103661
104376
  try {
103662
104377
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103667,12 +104382,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
103667
104382
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
103668
104383
  }, null, 2);
103669
104384
  }
103670
- const evidenceDir = path137.dirname(validatedPath);
104385
+ const evidenceDir = path140.dirname(validatedPath);
103671
104386
  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);
104387
+ await fs110.promises.mkdir(evidenceDir, { recursive: true });
104388
+ const tempPath = path140.join(evidenceDir, `.${filename}.tmp`);
104389
+ await fs110.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104390
+ await fs110.promises.rename(tempPath, validatedPath);
103676
104391
  return JSON.stringify({
103677
104392
  success: true,
103678
104393
  phase,
@@ -103718,8 +104433,8 @@ var write_hallucination_evidence = createSwarmTool({
103718
104433
  init_zod();
103719
104434
  init_utils2();
103720
104435
  init_create_tool();
103721
- import fs109 from "node:fs";
103722
- import path138 from "node:path";
104436
+ import fs111 from "node:fs";
104437
+ import path141 from "node:path";
103723
104438
  function normalizeVerdict3(verdict) {
103724
104439
  switch (verdict) {
103725
104440
  case "PASS":
@@ -103793,7 +104508,7 @@ async function executeWriteMutationEvidence(args2, directory) {
103793
104508
  entries: [evidenceEntry]
103794
104509
  };
103795
104510
  const filename = "mutation-gate.json";
103796
- const relativePath = path138.join("evidence", String(phase), filename);
104511
+ const relativePath = path141.join("evidence", String(phase), filename);
103797
104512
  let validatedPath;
103798
104513
  try {
103799
104514
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -103804,12 +104519,12 @@ async function executeWriteMutationEvidence(args2, directory) {
103804
104519
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
103805
104520
  }, null, 2);
103806
104521
  }
103807
- const evidenceDir = path138.dirname(validatedPath);
104522
+ const evidenceDir = path141.dirname(validatedPath);
103808
104523
  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);
104524
+ await fs111.promises.mkdir(evidenceDir, { recursive: true });
104525
+ const tempPath = path141.join(evidenceDir, `.${filename}.tmp`);
104526
+ await fs111.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
104527
+ await fs111.promises.rename(tempPath, validatedPath);
103813
104528
  return JSON.stringify({
103814
104529
  success: true,
103815
104530
  phase,
@@ -104152,7 +104867,7 @@ async function initializeOpenCodeSwarm(ctx) {
104152
104867
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
104153
104868
  preflightTriggerManager = new PTM(automationConfig);
104154
104869
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
104155
- const swarmDir = path140.resolve(ctx.directory, ".swarm");
104870
+ const swarmDir = path143.resolve(ctx.directory, ".swarm");
104156
104871
  statusArtifact = new ASA(swarmDir);
104157
104872
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
104158
104873
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -104551,6 +105266,14 @@ async function initializeOpenCodeSwarm(ctx) {
104551
105266
  return Promise.resolve();
104552
105267
  }
104553
105268
  },
105269
+ (input, output) => {
105270
+ try {
105271
+ const p = input;
105272
+ return skillPropagationTransformScan(ctx.directory, output, p.sessionID);
105273
+ } catch {
105274
+ return Promise.resolve();
105275
+ }
105276
+ },
104554
105277
  (_input, output) => {
104555
105278
  if (output.messages) {
104556
105279
  output.messages = consolidateSystemMessages(output.messages);
@@ -104624,6 +105347,12 @@ async function initializeOpenCodeSwarm(ctx) {
104624
105347
  agent: input.agent,
104625
105348
  sessionID: input.sessionID
104626
105349
  }, KnowledgeApplicationConfigSchema.parse(config3.knowledge_application ?? {}));
105350
+ await skillPropagationGateBefore(ctx.directory, {
105351
+ tool: input.tool,
105352
+ agent: input.agent,
105353
+ sessionID: input.sessionID,
105354
+ args: input.args
105355
+ }, { enabled: true });
104627
105356
  if (swarmState.lastBudgetPct >= 50) {
104628
105357
  const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
104629
105358
  if (!pressureSession.contextPressureWarningSent) {