opencode-swarm 7.93.1 → 7.94.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/.opencode/skills/plan/SKILL.md +2 -2
  2. package/dist/agents/council-prompts.d.ts +3 -3
  3. package/dist/agents/critic.d.ts +6 -6
  4. package/dist/agents/explorer.d.ts +2 -2
  5. package/dist/agents/read-only-lane-guidance.d.ts +1 -0
  6. package/dist/cli/{config-doctor-fkwyrtpq.js → config-doctor-ecmx9scq.js} +2 -2
  7. package/dist/cli/{explorer-4ttwy7jd.js → explorer-jc46negv.js} +1 -1
  8. package/dist/cli/{guardrail-explain-bjsc2ydm.js → guardrail-explain-we8mhb6y.js} +8 -8
  9. package/dist/cli/{guardrail-log-x3w800x5.js → guardrail-log-0q6pvbpx.js} +3 -3
  10. package/dist/cli/{index-1x2608ga.js → index-2a6ppa65.js} +14 -2
  11. package/dist/cli/{index-xsbtbffr.js → index-79dcqsg9.js} +4 -0
  12. package/dist/cli/{index-mv27v975.js → index-a59fjg9v.js} +1141 -15
  13. package/dist/cli/{index-ne4g3mk1.js → index-dgjsa6hy.js} +1 -1
  14. package/dist/cli/{index-5hrexm02.js → index-fjxjb66n.js} +166 -5
  15. package/dist/cli/{index-w7gkpmq8.js → index-hb10a2g8.js} +35 -2
  16. package/dist/cli/{index-dy6zs70b.js → index-jv0bz96v.js} +9 -9
  17. package/dist/cli/{index-9j1xvd8m.js → index-q8qx8p47.js} +2 -2
  18. package/dist/cli/{index-yykcmn6m.js → index-tx5czwpd.js} +1 -1
  19. package/dist/cli/{index-2jpbaedv.js → index-vqg905es.js} +1 -1
  20. package/dist/cli/index.js +7 -7
  21. package/dist/cli/{knowledge-store-eqans52j.js → knowledge-store-pa58msy5.js} +3 -1
  22. package/dist/cli/{schema-1kndsf0c.js → schema-jy18ftky.js} +1 -1
  23. package/dist/cli/{skill-generator-d0jzw6n2.js → skill-generator-3tkwcg4x.js} +12 -2
  24. package/dist/hooks/curator.d.ts +8 -3
  25. package/dist/hooks/knowledge-events.d.ts +12 -1
  26. package/dist/hooks/knowledge-store.d.ts +2 -0
  27. package/dist/index.js +1114 -621
  28. package/dist/services/skill-generator.d.ts +46 -0
  29. package/dist/tools/index.d.ts +1 -0
  30. package/dist/tools/manifest.d.ts +1 -0
  31. package/dist/tools/stale-reconciliation.d.ts +23 -0
  32. package/dist/tools/tool-metadata.d.ts +7 -2
  33. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.93.1",
72
+ version: "7.94.1",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -645,6 +645,10 @@ var init_tool_metadata = __esm(() => {
645
645
  description: "inspect the content and source entries of a skill file",
646
646
  agents: ["architect", "skill_improver"]
647
647
  },
648
+ run_stale_reconciliation: {
649
+ description: "reconcile skills against the knowledge store: mark skills stale when source knowledge is archived or deleted, or clear stale markers",
650
+ agents: ["architect"]
651
+ },
648
652
  skill_regenerate: {
649
653
  description: "regenerate an active skill by re-clustering its source knowledge entries and updating the SKILL.md in place",
650
654
  agents: ["architect"]
@@ -61550,6 +61554,7 @@ __export(exports_knowledge_store, {
61550
61554
  jaccardBigram: () => jaccardBigram,
61551
61555
  inferTags: () => inferTags,
61552
61556
  getPlatformConfigDir: () => getPlatformConfigDir,
61557
+ getArchivedKnowledgeIds: () => getArchivedKnowledgeIds,
61553
61558
  findNearDuplicate: () => findNearDuplicate,
61554
61559
  enforceKnowledgeCap: () => enforceKnowledgeCap,
61555
61560
  computeOutcomeSignal: () => computeOutcomeSignal,
@@ -61790,6 +61795,38 @@ async function transactKnowledge(filePath, mutate) {
61790
61795
  await atomicWriteFile(fp, content);
61791
61796
  }, mutate);
61792
61797
  }
61798
+ async function getArchivedKnowledgeIds(directory) {
61799
+ const archived = new Set;
61800
+ const swarmPath = resolveSwarmKnowledgePath(directory);
61801
+ try {
61802
+ const content = await readFile5(swarmPath, "utf-8");
61803
+ const lines = content.split(`
61804
+ `).filter((l) => l.trim());
61805
+ for (const line of lines) {
61806
+ try {
61807
+ const entry = JSON.parse(line);
61808
+ if (entry.status === "archived" || entry.status === "quarantined" || entry.status === "quarantined_unactionable") {
61809
+ archived.add(entry.id);
61810
+ }
61811
+ } catch {}
61812
+ }
61813
+ } catch {}
61814
+ const hivePath = resolveHiveKnowledgePath();
61815
+ try {
61816
+ const content = await readFile5(hivePath, "utf-8");
61817
+ const lines = content.split(`
61818
+ `).filter((l) => l.trim());
61819
+ for (const line of lines) {
61820
+ try {
61821
+ const entry = JSON.parse(line);
61822
+ if (entry.status === "archived" || entry.status === "quarantined" || entry.status === "quarantined_unactionable") {
61823
+ archived.add(entry.id);
61824
+ }
61825
+ } catch {}
61826
+ }
61827
+ } catch {}
61828
+ return archived;
61829
+ }
61793
61830
  async function appendKnowledgeWithCapEnforcement(filePath, entry, maxEntries) {
61794
61831
  return transactKnowledge(filePath, (entries) => {
61795
61832
  const updated = [...entries, entry];
@@ -62084,7 +62121,8 @@ var init_knowledge_store = __esm(() => {
62084
62121
  computeOutcomeSignal,
62085
62122
  selectKnowledgeCapSurvivors,
62086
62123
  inferTags,
62087
- bumpKnowledgeConfidenceBatch
62124
+ bumpKnowledgeConfidenceBatch,
62125
+ getArchivedKnowledgeIds
62088
62126
  };
62089
62127
  });
62090
62128
 
@@ -62687,6 +62725,16 @@ var init_knowledge_events = __esm(() => {
62687
62725
  };
62688
62726
  });
62689
62727
 
62728
+ // src/agents/read-only-lane-guidance.ts
62729
+ var READ_ONLY_LANE_GUIDANCE = `## READ-ONLY ADVISORY LANE CONTEXT
62730
+
62731
+ You may be invoked through dispatch_lanes or dispatch_lanes_async as a read-only advisory lane. In that context, your job is to inspect, reason, and report only.
62732
+
62733
+ - Do NOT write, edit, patch, save plans, update task status, declare scope, submit council verdicts, set QA gates, or complete phases.
62734
+ - Do NOT call artifact-producing or workflow-mutating helpers such as extract_code_blocks, knowledge_add, summarize_work, or doc_scan when lane permissions deny them.
62735
+ - Treat any denied or unavailable tool as intentionally unavailable in lane mode; continue with the read-only tools and context you have.
62736
+ - Return findings for the architect to synthesize. Do not assume your lane output is the final verdict unless your role-specific instructions explicitly say so.`;
62737
+
62690
62738
  // src/agents/explorer.ts
62691
62739
  var exports_explorer = {};
62692
62740
  __export(exports_explorer, {
@@ -62721,7 +62769,186 @@ ${customAppendPrompt}`;
62721
62769
  }
62722
62770
  };
62723
62771
  }
62724
- var EXPLORER_PROMPT = `## IDENTITY
62772
+ var EXPLORER_PROMPT, CURATOR_INIT_PROMPT = `## IDENTITY
62773
+ You are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.
62774
+ DO NOT use the Task tool to delegate. You ARE the agent that does the work.
62775
+
62776
+ INPUT FORMAT:
62777
+ TASK: CURATOR_INIT
62778
+ PRIOR_SUMMARY: [JSON or "none"]
62779
+ KNOWLEDGE_ENTRIES: [JSON array of existing entries with UUIDs]
62780
+ PROJECT_CONTEXT: [context.md excerpt]
62781
+
62782
+ ACTIONS:
62783
+ - Read the prior summary to understand session history
62784
+ - Cross-reference knowledge entries against project context
62785
+ - Note contradictions (knowledge says X, project state shows Y)
62786
+ - Observe where lessons could be tighter or stale
62787
+ - Produce a concise briefing for the architect
62788
+
62789
+ RULES:
62790
+ - Output under 2000 chars
62791
+ - No code modifications
62792
+ - Flag contradictions explicitly with CONTRADICTION: prefix
62793
+ - Memory proposals are for concise durable facts only. Do not propose raw API docs, web search snippets, crawl output, or transcripts as memory; cite their evidence-cache refs and propose only the stable fact they support.
62794
+ - If no prior summary exists, state "First session — no prior context"
62795
+
62796
+ OUTPUT FORMAT:
62797
+ BRIEFING:
62798
+ [concise summary of prior session state, key decisions, active blockers]
62799
+
62800
+ CONTRADICTIONS:
62801
+ - [entry_id]: [description] (or "None detected")
62802
+
62803
+ OBSERVATIONS:
62804
+ - entry <uuid> appears high-confidence: [observable evidence] (suggests boost confidence, mark hive_eligible)
62805
+ - entry <uuid> appears stale: [observable evidence] (suggests archive — no longer injected)
62806
+ - entry <uuid> could be tighter: [what's verbose or duplicate] (suggests rewrite with tighter version, max 280 chars)
62807
+ - entry <uuid> contradicts project state: [observable conflict] (suggests tag as contradicted)
62808
+ - new candidate: [concise lesson text from observed patterns] (suggests new entry)
62809
+ Use the UUID from KNOWLEDGE_ENTRIES when observing about existing entries. Use "new candidate" only when observing a potential new entry.
62810
+
62811
+ KNOWLEDGE_STATS:
62812
+ - Entries reviewed: [N]
62813
+ - Prior phases covered: [N]
62814
+ `, CURATOR_PHASE_PROMPT = `## IDENTITY
62815
+ You are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.
62816
+ DO NOT use the Task tool to delegate. You ARE the agent that does the work.
62817
+
62818
+ INPUT FORMAT:
62819
+ TASK: CURATOR_PHASE [phase_number]
62820
+ PRIOR_DIGEST: [running summary or "none"]
62821
+ PHASE_EVENTS: [JSON array from events.jsonl for this phase]
62822
+ PHASE_EVIDENCE: [summary of evidence bundles]
62823
+ PHASE_DECISIONS: [decisions from context.md]
62824
+ AGENTS_DISPATCHED: [list]
62825
+ AGENTS_EXPECTED: [list from config]
62826
+ KNOWLEDGE_ENTRIES: [JSON array of existing entries with UUIDs]
62827
+
62828
+ ACTIONS:
62829
+ - Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)
62830
+ - Observe workflow deviations: missing reviewer, missing retro, skipped test_engineer
62831
+ - Report knowledge update candidates with observable evidence: entries that appear promoted, archived, rewritten, or contradicted
62832
+ - Summarize key decisions and blockers resolved
62833
+
62834
+ RULES:
62835
+ - Output under 2000 chars
62836
+ - No code modifications
62837
+ - Compliance observations are READ-ONLY — report, do not enforce
62838
+ - OBSERVATIONS should not contain directives — report what is observed, do not instruct the architect what to do
62839
+ - Extend the digest, never replace it
62840
+ - Memory proposals are for concise durable facts only. Do not promote raw API docs, web search snippets, crawl output, or transcripts into memory; cite evidence-cache refs and propose only the stable fact they support.
62841
+
62842
+ OUTPUT FORMAT:
62843
+ PHASE_DIGEST:
62844
+ phase: [N]
62845
+ summary: [what was accomplished]
62846
+ agents_used: [list]
62847
+ tasks_completed: [N]/[total]
62848
+ key_decisions: [list]
62849
+ blockers_resolved: [list]
62850
+
62851
+ COMPLIANCE:
62852
+ - [type] observed: [description] (or "No deviations observed")
62853
+
62854
+ OBSERVATIONS:
62855
+ - entry <uuid> appears high-confidence: [observable evidence] (suggests boost confidence, mark hive_eligible)
62856
+ - entry <uuid> appears stale: [observable evidence] (suggests archive — no longer injected)
62857
+ - entry <uuid> could be tighter: [what's verbose or duplicate] (suggests rewrite with tighter version, max 280 chars)
62858
+ - entry <uuid> contradicts project state: [observable conflict] (suggests tag as contradicted)
62859
+ - new candidate: [concise lesson text from observed patterns] (suggests new entry)
62860
+ Use the UUID from KNOWLEDGE_ENTRIES when observing about existing entries. Use "new candidate" only when observing a potential new entry.
62861
+
62862
+ EXTENDED_DIGEST:
62863
+ [the full running digest with this phase appended]
62864
+
62865
+ ## ACTIONABILITY ENRICHMENT (V3 compatibility label; overrides the format above when triggered)
62866
+ When the input asks you to "Convert this prose lesson into an actionable knowledge directive", ignore the PHASE_DIGEST output format entirely and output ONLY a single JSON object — no fences, no commentary, no digest.
62867
+ MANDATORY fields (the directive is rejected without them):
62868
+ - at least one non-empty scope field: "applies_to_agents" (roles: architect, coder, reviewer, test_engineer, sme, docs, designer, critic, curator) or "applies_to_tools" (edit, write, patch, bash, read, grep, glob)
62869
+ - at least one non-empty predicate field: "forbidden_actions", "required_actions", or "verification_checks"
62870
+ Optional: "triggers" (short surfacing phrases), "directive_priority" (low|medium|high|critical).
62871
+ Example output:
62872
+ {"applies_to_agents":["coder"],"forbidden_actions":["use async iterators in hot paths"],"required_actions":["use a plain for loop in hot paths"],"triggers":["hot path","async iterator"],"directive_priority":"high"}
62873
+ `, CURATOR_POSTMORTEM_PROMPT = `## IDENTITY
62874
+ You are Explorer in CURATOR_POSTMORTEM mode. You synthesize a project-end post-mortem from structured .swarm/ evidence.
62875
+ DO NOT use the Task tool to delegate. You ARE the agent that does the work.
62876
+ DO NOT scan raw source code — work only from the recorded evidence provided below.
62877
+
62878
+ INPUT FORMAT:
62879
+ TASK: CURATOR_POSTMORTEM [plan_id]
62880
+ PLAN_SUMMARY: [plan phases, task counts, completion status]
62881
+ CURATOR_DIGESTS: [running digest from curator_phase across all phases]
62882
+ KNOWLEDGE_ENTRIES: [JSON array of existing entries with UUIDs]
62883
+ KNOWLEDGE_EVENTS_SUMMARY: [aggregated violation/applied/ignored counts per entry]
62884
+ PENDING_PROPOSALS: [skill/motif proposals awaiting triage]
62885
+ UNACTIONABLE_QUARANTINE: [entries flagged unactionable with retry status]
62886
+ DRIFT_REPORTS: [per-phase alignment/drift scores if available]
62887
+ RETROSPECTIVES: [any session retrospectives found]
62888
+
62889
+ ACTIONS:
62890
+ 1. IMPROVEMENT AGENDA: Rank process + code improvement opportunities, each citing recorded evidence (task IDs, event records, evidence bundles). Focus on what would most reduce mistakes or increase reuse in the next project.
62891
+ 2. FINAL CURATION PASS: Consolidate knowledge across phases — identify near-duplicate lessons that accumulated under different IDs, recommend hive promotion for project-proven entries (high confidence, multiple phases confirmed), flag never-applied entries past 3+ phases for review.
62892
+ 3. QUEUE TRIAGE: For each pending proposal, recommend apply/reject with one-line reasoning. Surface unactionable-quarantine counts and retry candidates.
62893
+ 4. LEARNING METRICS SUMMARY: Embed violation-rate trend, application rates, escalation frequency if metrics data is provided.
62894
+
62895
+ RULES:
62896
+ - Output under 4000 chars
62897
+ - No code modifications — read-only synthesis
62898
+ - Every improvement item must cite a specific evidence artifact or event record
62899
+ - Do not invent evidence — if an artifact is missing, note the gap
62900
+ - Proposals route through existing gated paths (knowledge_add, skill proposals, hive promotion) — recommend the path, do not bypass it
62901
+ - HIGH-severity items that should become critical directives must be flagged for critic gate validation
62902
+
62903
+ OUTPUT FORMAT:
62904
+ POST_MORTEM_REPORT:
62905
+ plan_id: [plan identifier]
62906
+ generated_at: [ISO timestamp]
62907
+
62908
+ IMPROVEMENT_AGENDA:
62909
+ 1. [priority] [description] — evidence: [artifact/event ref]
62910
+ 2. ...
62911
+
62912
+ CURATION_RECOMMENDATIONS:
62913
+ - merge: [entry_a UUID] + [entry_b UUID] — [reason]
62914
+ - promote_to_hive: [entry UUID] — [evidence of cross-phase confirmation]
62915
+ - flag_stale: [entry UUID] — [never applied in N phases]
62916
+ - rewrite: [entry UUID] — [what's verbose/outdated]
62917
+
62918
+ QUEUE_TRIAGE:
62919
+ - [proposal_id]: APPLY|REJECT — [one-line reasoning]
62920
+
62921
+ LEARNING_METRICS:
62922
+ [3-line summary of trends if data available, or "metrics data not provided"]
62923
+
62924
+ SUMMARY:
62925
+ [3-line executive summary for architect briefing]
62926
+ `, CURATOR_CONSOLIDATION_PROMPT = `## IDENTITY
62927
+ You are Curator in CONSOLIDATION mode. You distill clusters of raw episodic memory into a small set of durable semantic facts.
62928
+ DO NOT use the Task tool to delegate. You ARE the agent that does the work.
62929
+ DO NOT scan raw source code — work only from the episodic events and existing memories provided in the prompt.
62930
+
62931
+ INPUT FORMAT:
62932
+ - A cluster of verbatim episodic events.
62933
+ - A list of existing durable memories (each prefixed with its mem_ id) for dedup and contradiction detection.
62934
+
62935
+ ACTIONS:
62936
+ 1. Identify durable, reusable facts that are DIRECTLY supported by the cited episodic evidence.
62937
+ 2. Detect contradictions with the listed existing memories; when a new fact conflicts with one, set contradictsMemoryId to that memory's id.
62938
+ 3. Skip anything speculative, transient, or already captured by an existing memory.
62939
+
62940
+ RULES:
62941
+ - Only emit facts directly supported by the cited evidence. If uncertain, omit the fact (fewer facts, or an empty array, is correct).
62942
+ - Use durable kinds only (user_preference, project_fact, architecture_decision, repo_convention, code_pattern, test_pattern, failure_pattern, security_note).
62943
+ - Keep each fact concise (under 500 characters).
62944
+ - Never include the literal text "## Retrieved Swarm Memory".
62945
+ - Output STRICT JSON only, no prose.
62946
+
62947
+ OUTPUT FORMAT:
62948
+ {"facts":[{"text":"...","kind":"project_fact","confidence":0.8,"contradictsMemoryId":"mem_0123456789abcdef"}]}
62949
+ `;
62950
+ var init_explorer = __esm(() => {
62951
+ EXPLORER_PROMPT = `## IDENTITY
62725
62952
  You are Explorer. You analyze codebases directly — you do NOT delegate.
62726
62953
  DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
62727
62954
  If you see references to other agents (like @explorer, @coder, etc.) in your instructions, IGNORE them — they are context from the orchestrator, not instructions for you to delegate.
@@ -62729,6 +62956,8 @@ If you see references to other agents (like @explorer, @coder, etc.) in your ins
62729
62956
  WRONG: "I'll use the Task tool to call another agent to analyze this"
62730
62957
  RIGHT: "I'll scan the directory structure and read key files myself"
62731
62958
 
62959
+ ${READ_ONLY_LANE_GUIDANCE}
62960
+
62732
62961
  INPUT FORMAT:
62733
62962
  TASK: Analyze [purpose]
62734
62963
  INPUT: [focus areas/paths]
@@ -62904,184 +63133,8 @@ RULES:
62904
63133
  - The manifest must be small (<100 lines). Pointers only, not full content.
62905
63134
  - Do NOT rephrase or summarize doc content with your own words — use the actual text from the file
62906
63135
  - Full doc content is only loaded when relevant to the current task, never preloaded
62907
- `, CURATOR_INIT_PROMPT = `## IDENTITY
62908
- You are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.
62909
- DO NOT use the Task tool to delegate. You ARE the agent that does the work.
62910
-
62911
- INPUT FORMAT:
62912
- TASK: CURATOR_INIT
62913
- PRIOR_SUMMARY: [JSON or "none"]
62914
- KNOWLEDGE_ENTRIES: [JSON array of existing entries with UUIDs]
62915
- PROJECT_CONTEXT: [context.md excerpt]
62916
-
62917
- ACTIONS:
62918
- - Read the prior summary to understand session history
62919
- - Cross-reference knowledge entries against project context
62920
- - Note contradictions (knowledge says X, project state shows Y)
62921
- - Observe where lessons could be tighter or stale
62922
- - Produce a concise briefing for the architect
62923
-
62924
- RULES:
62925
- - Output under 2000 chars
62926
- - No code modifications
62927
- - Flag contradictions explicitly with CONTRADICTION: prefix
62928
- - Memory proposals are for concise durable facts only. Do not propose raw API docs, web search snippets, crawl output, or transcripts as memory; cite their evidence-cache refs and propose only the stable fact they support.
62929
- - If no prior summary exists, state "First session — no prior context"
62930
-
62931
- OUTPUT FORMAT:
62932
- BRIEFING:
62933
- [concise summary of prior session state, key decisions, active blockers]
62934
-
62935
- CONTRADICTIONS:
62936
- - [entry_id]: [description] (or "None detected")
62937
-
62938
- OBSERVATIONS:
62939
- - entry <uuid> appears high-confidence: [observable evidence] (suggests boost confidence, mark hive_eligible)
62940
- - entry <uuid> appears stale: [observable evidence] (suggests archive — no longer injected)
62941
- - entry <uuid> could be tighter: [what's verbose or duplicate] (suggests rewrite with tighter version, max 280 chars)
62942
- - entry <uuid> contradicts project state: [observable conflict] (suggests tag as contradicted)
62943
- - new candidate: [concise lesson text from observed patterns] (suggests new entry)
62944
- Use the UUID from KNOWLEDGE_ENTRIES when observing about existing entries. Use "new candidate" only when observing a potential new entry.
62945
-
62946
- KNOWLEDGE_STATS:
62947
- - Entries reviewed: [N]
62948
- - Prior phases covered: [N]
62949
- `, CURATOR_PHASE_PROMPT = `## IDENTITY
62950
- You are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.
62951
- DO NOT use the Task tool to delegate. You ARE the agent that does the work.
62952
-
62953
- INPUT FORMAT:
62954
- TASK: CURATOR_PHASE [phase_number]
62955
- PRIOR_DIGEST: [running summary or "none"]
62956
- PHASE_EVENTS: [JSON array from events.jsonl for this phase]
62957
- PHASE_EVIDENCE: [summary of evidence bundles]
62958
- PHASE_DECISIONS: [decisions from context.md]
62959
- AGENTS_DISPATCHED: [list]
62960
- AGENTS_EXPECTED: [list from config]
62961
- KNOWLEDGE_ENTRIES: [JSON array of existing entries with UUIDs]
62962
-
62963
- ACTIONS:
62964
- - Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)
62965
- - Observe workflow deviations: missing reviewer, missing retro, skipped test_engineer
62966
- - Report knowledge update candidates with observable evidence: entries that appear promoted, archived, rewritten, or contradicted
62967
- - Summarize key decisions and blockers resolved
62968
-
62969
- RULES:
62970
- - Output under 2000 chars
62971
- - No code modifications
62972
- - Compliance observations are READ-ONLY — report, do not enforce
62973
- - OBSERVATIONS should not contain directives — report what is observed, do not instruct the architect what to do
62974
- - Extend the digest, never replace it
62975
- - Memory proposals are for concise durable facts only. Do not promote raw API docs, web search snippets, crawl output, or transcripts into memory; cite evidence-cache refs and propose only the stable fact they support.
62976
-
62977
- OUTPUT FORMAT:
62978
- PHASE_DIGEST:
62979
- phase: [N]
62980
- summary: [what was accomplished]
62981
- agents_used: [list]
62982
- tasks_completed: [N]/[total]
62983
- key_decisions: [list]
62984
- blockers_resolved: [list]
62985
-
62986
- COMPLIANCE:
62987
- - [type] observed: [description] (or "No deviations observed")
62988
-
62989
- OBSERVATIONS:
62990
- - entry <uuid> appears high-confidence: [observable evidence] (suggests boost confidence, mark hive_eligible)
62991
- - entry <uuid> appears stale: [observable evidence] (suggests archive — no longer injected)
62992
- - entry <uuid> could be tighter: [what's verbose or duplicate] (suggests rewrite with tighter version, max 280 chars)
62993
- - entry <uuid> contradicts project state: [observable conflict] (suggests tag as contradicted)
62994
- - new candidate: [concise lesson text from observed patterns] (suggests new entry)
62995
- Use the UUID from KNOWLEDGE_ENTRIES when observing about existing entries. Use "new candidate" only when observing a potential new entry.
62996
-
62997
- EXTENDED_DIGEST:
62998
- [the full running digest with this phase appended]
62999
-
63000
- ## V3 ACTIONABILITY ENRICHMENT (overrides the format above when triggered)
63001
- When the input asks you to "Convert this prose lesson into an actionable knowledge directive", ignore the PHASE_DIGEST output format entirely and output ONLY a single JSON object — no fences, no commentary, no digest.
63002
- MANDATORY fields (the directive is rejected without them):
63003
- - at least one non-empty scope field: "applies_to_agents" (roles: architect, coder, reviewer, test_engineer, sme, docs, designer, critic, curator) or "applies_to_tools" (edit, write, patch, bash, read, grep, glob)
63004
- - at least one non-empty predicate field: "forbidden_actions", "required_actions", or "verification_checks"
63005
- Optional: "triggers" (short surfacing phrases), "directive_priority" (low|medium|high|critical).
63006
- Example output:
63007
- {"applies_to_agents":["coder"],"forbidden_actions":["use async iterators in hot paths"],"required_actions":["use a plain for loop in hot paths"],"triggers":["hot path","async iterator"],"directive_priority":"high"}
63008
- `, CURATOR_POSTMORTEM_PROMPT = `## IDENTITY
63009
- You are Explorer in CURATOR_POSTMORTEM mode. You synthesize a project-end post-mortem from structured .swarm/ evidence.
63010
- DO NOT use the Task tool to delegate. You ARE the agent that does the work.
63011
- DO NOT scan raw source code — work only from the recorded evidence provided below.
63012
-
63013
- INPUT FORMAT:
63014
- TASK: CURATOR_POSTMORTEM [plan_id]
63015
- PLAN_SUMMARY: [plan phases, task counts, completion status]
63016
- CURATOR_DIGESTS: [running digest from curator_phase across all phases]
63017
- KNOWLEDGE_ENTRIES: [JSON array of existing entries with UUIDs]
63018
- KNOWLEDGE_EVENTS_SUMMARY: [aggregated violation/applied/ignored counts per entry]
63019
- PENDING_PROPOSALS: [skill/motif proposals awaiting triage]
63020
- UNACTIONABLE_QUARANTINE: [entries flagged unactionable with retry status]
63021
- DRIFT_REPORTS: [per-phase alignment/drift scores if available]
63022
- RETROSPECTIVES: [any session retrospectives found]
63023
-
63024
- ACTIONS:
63025
- 1. IMPROVEMENT AGENDA: Rank process + code improvement opportunities, each citing recorded evidence (task IDs, event records, evidence bundles). Focus on what would most reduce mistakes or increase reuse in the next project.
63026
- 2. FINAL CURATION PASS: Consolidate knowledge across phases — identify near-duplicate lessons that accumulated under different IDs, recommend hive promotion for project-proven entries (high confidence, multiple phases confirmed), flag never-applied entries past 3+ phases for review.
63027
- 3. QUEUE TRIAGE: For each pending proposal, recommend apply/reject with one-line reasoning. Surface unactionable-quarantine counts and retry candidates.
63028
- 4. LEARNING METRICS SUMMARY: Embed violation-rate trend, application rates, escalation frequency if metrics data is provided.
63029
-
63030
- RULES:
63031
- - Output under 4000 chars
63032
- - No code modifications — read-only synthesis
63033
- - Every improvement item must cite a specific evidence artifact or event record
63034
- - Do not invent evidence — if an artifact is missing, note the gap
63035
- - Proposals route through existing gated paths (knowledge_add, skill proposals, hive promotion) — recommend the path, do not bypass it
63036
- - HIGH-severity items that should become critical directives must be flagged for critic gate validation
63037
-
63038
- OUTPUT FORMAT:
63039
- POST_MORTEM_REPORT:
63040
- plan_id: [plan identifier]
63041
- generated_at: [ISO timestamp]
63042
-
63043
- IMPROVEMENT_AGENDA:
63044
- 1. [priority] [description] — evidence: [artifact/event ref]
63045
- 2. ...
63046
-
63047
- CURATION_RECOMMENDATIONS:
63048
- - merge: [entry_a UUID] + [entry_b UUID] — [reason]
63049
- - promote_to_hive: [entry UUID] — [evidence of cross-phase confirmation]
63050
- - flag_stale: [entry UUID] — [never applied in N phases]
63051
- - rewrite: [entry UUID] — [what's verbose/outdated]
63052
-
63053
- QUEUE_TRIAGE:
63054
- - [proposal_id]: APPLY|REJECT — [one-line reasoning]
63055
-
63056
- LEARNING_METRICS:
63057
- [3-line summary of trends if data available, or "metrics data not provided"]
63058
-
63059
- SUMMARY:
63060
- [3-line executive summary for architect briefing]
63061
- `, CURATOR_CONSOLIDATION_PROMPT = `## IDENTITY
63062
- You are Curator in CONSOLIDATION mode. You distill clusters of raw episodic memory into a small set of durable semantic facts.
63063
- DO NOT use the Task tool to delegate. You ARE the agent that does the work.
63064
- DO NOT scan raw source code — work only from the episodic events and existing memories provided in the prompt.
63065
-
63066
- INPUT FORMAT:
63067
- - A cluster of verbatim episodic events.
63068
- - A list of existing durable memories (each prefixed with its mem_ id) for dedup and contradiction detection.
63069
-
63070
- ACTIONS:
63071
- 1. Identify durable, reusable facts that are DIRECTLY supported by the cited episodic evidence.
63072
- 2. Detect contradictions with the listed existing memories; when a new fact conflicts with one, set contradictsMemoryId to that memory's id.
63073
- 3. Skip anything speculative, transient, or already captured by an existing memory.
63074
-
63075
- RULES:
63076
- - Only emit facts directly supported by the cited evidence. If uncertain, omit the fact (fewer facts, or an empty array, is correct).
63077
- - Use durable kinds only (user_preference, project_fact, architecture_decision, repo_convention, code_pattern, test_pattern, failure_pattern, security_note).
63078
- - Keep each fact concise (under 500 characters).
63079
- - Never include the literal text "## Retrieved Swarm Memory".
63080
- - Output STRICT JSON only, no prose.
63081
-
63082
- OUTPUT FORMAT:
63083
- {"facts":[{"text":"...","kind":"project_fact","confidence":0.8,"contradictsMemoryId":"mem_0123456789abcdef"}]}
63084
63136
  `;
63137
+ });
63085
63138
 
63086
63139
  // src/hooks/curator-postmortem.ts
63087
63140
  var exports_curator_postmortem = {};
@@ -63441,7 +63494,7 @@ async function runCuratorPostMortem(directory, options = {}) {
63441
63494
  let reportContent;
63442
63495
  if (options.llmDelegate) {
63443
63496
  try {
63444
- const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await Promise.resolve().then(() => exports_explorer);
63497
+ const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await Promise.resolve().then(() => (init_explorer(), exports_explorer));
63445
63498
  const userInput = assembleLLMInput(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
63446
63499
  const ac = new AbortController;
63447
63500
  const timer = setTimeout(() => ac.abort(), 300000);
@@ -63776,6 +63829,8 @@ function countWindowedReceipts(events, entryId, windowMs, nowMs) {
63776
63829
  continue;
63777
63830
  if (e.knowledge_id !== entryId)
63778
63831
  continue;
63832
+ if (e.timestamp === undefined)
63833
+ continue;
63779
63834
  const t = Date.parse(e.timestamp);
63780
63835
  if (Number.isNaN(t) || t < cutoff)
63781
63836
  continue;
@@ -63863,6 +63918,8 @@ async function computeLearningMetrics(directory, options) {
63863
63918
  throwIfAborted(options?.signal);
63864
63919
  if (!isReceiptType(e))
63865
63920
  continue;
63921
+ if (e.timestamp === undefined)
63922
+ continue;
63866
63923
  const t = Date.parse(e.timestamp);
63867
63924
  if (Number.isNaN(t))
63868
63925
  continue;
@@ -65183,16 +65240,21 @@ __export(exports_skill_generator, {
65183
65240
  selectCandidateEntries: () => selectCandidateEntries,
65184
65241
  sanitizeSlug: () => sanitizeSlug,
65185
65242
  retireSkill: () => retireSkill,
65243
+ retireOrMarkStale: () => retireOrMarkStale,
65186
65244
  renderSkillMarkdown: () => renderSkillMarkdown,
65187
65245
  regenerateSkill: () => regenerateSkill,
65188
65246
  proposalPath: () => proposalPath,
65189
65247
  parseDraftFrontmatter: () => parseDraftFrontmatter,
65248
+ markSkillStale: () => markSkillStale,
65190
65249
  listSkills: () => listSkills,
65191
65250
  isValidSlug: () => isValidSlug2,
65192
65251
  isSkillMaturityEligible: () => isSkillMaturityEligible,
65193
65252
  inspectSkill: () => inspectSkill,
65194
65253
  generateSkills: () => generateSkills,
65254
+ findStaleSkillsBySourceKnowledgeId: () => findStaleSkillsBySourceKnowledgeId,
65255
+ findSkillsBySourceKnowledgeId: () => findSkillsBySourceKnowledgeId,
65195
65256
  clusterEntries: () => clusterEntries,
65257
+ clearSkillStale: () => clearSkillStale,
65196
65258
  autoApplyProposals: () => autoApplyProposals,
65197
65259
  activeRepoRelativePath: () => activeRepoRelativePath,
65198
65260
  activePath: () => activePath,
@@ -65204,7 +65266,7 @@ __export(exports_skill_generator, {
65204
65266
  DEFAULT_SKILL_MIN_CONFIDENCE: () => DEFAULT_SKILL_MIN_CONFIDENCE
65205
65267
  });
65206
65268
  import { existsSync as existsSync23, unlinkSync as unlinkSync7 } from "node:fs";
65207
- import { mkdir as mkdir10, readFile as readFile9, rename as rename4, writeFile as writeFile6 } from "node:fs/promises";
65269
+ import { mkdir as mkdir10, readFile as readFile9, rename as rename4, unlink as unlink3, writeFile as writeFile6 } from "node:fs/promises";
65208
65270
  import * as path47 from "node:path";
65209
65271
  function sanitizeSlug(input) {
65210
65272
  const lc = input.toLowerCase().trim();
@@ -65895,10 +65957,81 @@ async function activateProposal(directory, slug, force = false, options = {}) {
65895
65957
  };
65896
65958
  }
65897
65959
  }
65960
+ async function findSkillsBySourceKnowledgeId(directory, sourceId) {
65961
+ const activeDir = path47.join(directory, ".opencode", "skills", "generated");
65962
+ const fs23 = await import("node:fs/promises");
65963
+ if (!existsSync23(activeDir))
65964
+ return [];
65965
+ const entries = await fs23.readdir(activeDir, { withFileTypes: true });
65966
+ const matches = [];
65967
+ for (const e of entries) {
65968
+ if (!e.isDirectory())
65969
+ continue;
65970
+ const skillDir = path47.join(activeDir, e.name);
65971
+ const retiredMarker = path47.join(skillDir, "retired.marker");
65972
+ if (existsSync23(retiredMarker))
65973
+ continue;
65974
+ const staleMarker = path47.join(skillDir, "stale.marker");
65975
+ if (existsSync23(staleMarker))
65976
+ continue;
65977
+ const skillPath = path47.join(skillDir, "SKILL.md");
65978
+ if (!existsSync23(skillPath))
65979
+ continue;
65980
+ let content;
65981
+ try {
65982
+ content = await fs23.readFile(skillPath, "utf-8");
65983
+ } catch {
65984
+ continue;
65985
+ }
65986
+ const fm = parseDraftFrontmatter(content);
65987
+ if (fm?.sourceKnowledgeIds.includes(sourceId)) {
65988
+ matches.push(skillDir);
65989
+ }
65990
+ }
65991
+ return matches;
65992
+ }
65993
+ async function findStaleSkillsBySourceKnowledgeId(directory, archivedIds) {
65994
+ const activeDir = path47.join(directory, ".opencode", "skills", "generated");
65995
+ if (!existsSync23(activeDir))
65996
+ return [];
65997
+ const fs23 = await import("node:fs/promises");
65998
+ const entries = await fs23.readdir(activeDir, { withFileTypes: true });
65999
+ const matches = [];
66000
+ for (const e of entries) {
66001
+ if (!e.isDirectory())
66002
+ continue;
66003
+ const skillDir = path47.join(activeDir, e.name);
66004
+ const retiredMarker = path47.join(skillDir, "retired.marker");
66005
+ if (existsSync23(retiredMarker))
66006
+ continue;
66007
+ const staleMarker = path47.join(skillDir, "stale.marker");
66008
+ if (!existsSync23(staleMarker))
66009
+ continue;
66010
+ const skillPath = path47.join(skillDir, "SKILL.md");
66011
+ if (!existsSync23(skillPath))
66012
+ continue;
66013
+ let content;
66014
+ try {
66015
+ content = await fs23.readFile(skillPath, "utf-8");
66016
+ } catch {
66017
+ continue;
66018
+ }
66019
+ const fm = parseDraftFrontmatter(content);
66020
+ const sourceIds = fm?.sourceKnowledgeIds ?? [];
66021
+ if (sourceIds.length === 0)
66022
+ continue;
66023
+ const allArchived = sourceIds.every((id) => archivedIds.has(id));
66024
+ if (allArchived) {
66025
+ matches.push(skillDir);
66026
+ }
66027
+ }
66028
+ return matches;
66029
+ }
65898
66030
  async function listSkills(directory) {
65899
66031
  const result = {
65900
66032
  proposals: [],
65901
- active: []
66033
+ active: [],
66034
+ stale: []
65902
66035
  };
65903
66036
  const proposalsDir = path47.join(directory, ".swarm", "skills", "proposals");
65904
66037
  const activeDir = path47.join(directory, ".opencode", "skills", "generated");
@@ -65923,6 +66056,16 @@ async function listSkills(directory) {
65923
66056
  const retiredMarker = path47.join(activeDir, e.name, "retired.marker");
65924
66057
  if (existsSync23(retiredMarker))
65925
66058
  continue;
66059
+ const staleMarker = path47.join(activeDir, e.name, "stale.marker");
66060
+ if (existsSync23(staleMarker)) {
66061
+ let reason = "stale";
66062
+ try {
66063
+ const content = await fs23.readFile(staleMarker, "utf-8");
66064
+ reason = content.trim() || "stale";
66065
+ } catch {}
66066
+ result.stale.push({ slug: e.name, reason });
66067
+ continue;
66068
+ }
65926
66069
  const skillPath = path47.join(activeDir, e.name, "SKILL.md");
65927
66070
  if (existsSync23(skillPath)) {
65928
66071
  result.active.push({
@@ -66008,7 +66151,34 @@ async function inspectSkill(directory, slug, prefer = "auto") {
66008
66151
  for (const c of candidates) {
66009
66152
  if (existsSync23(c.p)) {
66010
66153
  const content = await readFile9(c.p, "utf-8");
66011
- return { found: true, path: c.p, content, mode: c.m };
66154
+ const result = { found: true, path: c.p, content, mode: c.m };
66155
+ const fm = parseDraftFrontmatter(content);
66156
+ if (fm && fm.sourceKnowledgeIds.length > 0) {
66157
+ const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
66158
+ const hivePath = resolveHiveKnowledgePath();
66159
+ const hive = existsSync23(hivePath) ? await readKnowledge(hivePath) : [];
66160
+ const allEntries = [...swarm, ...hive];
66161
+ const entryMap = new Map(allEntries.map((e) => [e.id, e]));
66162
+ result.source_knowledge_status = fm.sourceKnowledgeIds.map((id) => {
66163
+ const entry = entryMap.get(id);
66164
+ if (!entry)
66165
+ return { id, status: "deleted" };
66166
+ if (entry.status === "archived" || entry.status === "quarantined") {
66167
+ return { id, status: "archived" };
66168
+ }
66169
+ return { id, status: "active" };
66170
+ });
66171
+ }
66172
+ if (c.m === "active") {
66173
+ const skillDir = path47.join(directory, ".opencode", "skills", "generated", cleanSlug);
66174
+ const staleMarker = path47.join(skillDir, "stale.marker");
66175
+ if (existsSync23(staleMarker)) {
66176
+ try {
66177
+ result.stale_reason = await readFile9(staleMarker, "utf-8");
66178
+ } catch {}
66179
+ }
66180
+ }
66181
+ return result;
66012
66182
  }
66013
66183
  }
66014
66184
  return { found: false };
@@ -66047,6 +66217,54 @@ async function retireSkill(directory, slug, reason) {
66047
66217
  reason
66048
66218
  };
66049
66219
  }
66220
+ async function markSkillStale(skillDir, reason) {
66221
+ await mkdir10(skillDir, { recursive: true });
66222
+ await writeFile6(path47.join(skillDir, "stale.marker"), reason, "utf-8");
66223
+ }
66224
+ async function clearSkillStale(skillDir) {
66225
+ const markerPath = path47.join(skillDir, "stale.marker");
66226
+ try {
66227
+ await unlink3(markerPath);
66228
+ } catch (err) {
66229
+ if (err instanceof Error && "code" in err && err.code === "ENOENT") {
66230
+ return;
66231
+ }
66232
+ warn(`[skill-generator] failed to remove stale.marker at ${markerPath}: ${err instanceof Error ? err.message : String(err)}`);
66233
+ }
66234
+ }
66235
+ async function retireOrMarkStale(directory, skillDir, archivedKnowledgeIds) {
66236
+ const fs23 = await import("node:fs/promises");
66237
+ const skillPath = path47.join(skillDir, "SKILL.md");
66238
+ if (!existsSync23(skillPath)) {
66239
+ await markSkillStale(skillDir, "source knowledge archived, SKILL.md missing");
66240
+ const slug2 = path47.basename(skillDir);
66241
+ return { action: "stale", slug: slug2, skillDir };
66242
+ }
66243
+ let content;
66244
+ try {
66245
+ content = await fs23.readFile(skillPath, "utf-8");
66246
+ } catch {
66247
+ await markSkillStale(skillDir, "source knowledge archived, SKILL.md unreadable");
66248
+ const slug2 = path47.basename(skillDir);
66249
+ return { action: "stale", slug: slug2, skillDir };
66250
+ }
66251
+ const fm = parseDraftFrontmatter(content);
66252
+ const sourceIds = fm?.sourceKnowledgeIds ?? [];
66253
+ if (sourceIds.length === 0) {
66254
+ await markSkillStale(skillDir, "source knowledge archived, no source_knowledge_ids in frontmatter");
66255
+ const slug2 = path47.basename(skillDir);
66256
+ return { action: "stale", slug: slug2, skillDir };
66257
+ }
66258
+ const allArchived = sourceIds.every((id) => archivedKnowledgeIds.has(id));
66259
+ const slug = path47.basename(skillDir);
66260
+ if (allArchived) {
66261
+ await retireSkill(directory, slug, "all source knowledge entries archived or deleted");
66262
+ return { action: "retire", slug, skillDir };
66263
+ } else {
66264
+ await markSkillStale(skillDir, "one or more source knowledge entries archived");
66265
+ return { action: "stale", slug, skillDir };
66266
+ }
66267
+ }
66050
66268
  async function regenerateSkill(directory, slug, options = {}) {
66051
66269
  const cleanSlug = sanitizeSlug(slug);
66052
66270
  if (!isValidSlug2(cleanSlug)) {
@@ -66206,6 +66424,7 @@ async function regenerateSkill(directory, slug, options = {}) {
66206
66424
  try {
66207
66425
  await atomicWrite3(skillPath, content);
66208
66426
  await stampSourceEntries(directory, cleanSlug, matchedEntries.map((e) => e.id));
66427
+ await clearSkillStale(path47.dirname(activePath(directory, cleanSlug)));
66209
66428
  } catch (writeErr) {
66210
66429
  return {
66211
66430
  regenerated: false,
@@ -66249,11 +66468,15 @@ var init_skill_generator = __esm(() => {
66249
66468
  generateSkills,
66250
66469
  activateProposal,
66251
66470
  listSkills,
66471
+ findSkillsBySourceKnowledgeId,
66472
+ findStaleSkillsBySourceKnowledgeId,
66252
66473
  inspectSkill,
66253
66474
  stampSourceEntries,
66254
66475
  parseDraftFrontmatter,
66255
66476
  retireSkill,
66477
+ retireOrMarkStale,
66256
66478
  regenerateSkill,
66479
+ clearSkillStale,
66257
66480
  autoApplyProposals,
66258
66481
  unlinkSync: unlinkSync7
66259
66482
  };
@@ -67199,11 +67422,12 @@ ${digest2.summary}`).join(`
67199
67422
 
67200
67423
  `);
67201
67424
  }
67202
- async function autoRetireSkills(directory, curatorKnowledgePath, excludeSlugs) {
67425
+ async function autoRetireSkills(directory, _curatorKnowledgePath, excludeSlugs) {
67203
67426
  const observations = [];
67204
67427
  try {
67205
67428
  const skillListResult = await _internals32.listSkills(directory);
67206
67429
  const usageEntries = _internals32.readSkillUsageEntries(directory);
67430
+ const allArchivedIds = await _internals32.getArchivedKnowledgeIds(directory);
67207
67431
  for (const active of skillListResult.active) {
67208
67432
  if (excludeSlugs?.has(active.slug))
67209
67433
  continue;
@@ -67223,30 +67447,20 @@ async function autoRetireSkills(directory, curatorKnowledgePath, excludeSlugs) {
67223
67447
  });
67224
67448
  const violations = skillUsage.filter((e) => e.complianceVerdict === "violated").length;
67225
67449
  const violationRate = skillUsage.length > 0 ? violations / skillUsage.length : 0;
67226
- let allArchived = false;
67227
- try {
67228
- const content = await _internals32.readFileAsync(active.path, "utf-8");
67229
- const fm = _internals32.parseDraftFrontmatter(content);
67230
- if (fm && fm.sourceKnowledgeIds.length > 0) {
67231
- const swarmKnowledge = await _internals32.readKnowledge(curatorKnowledgePath);
67232
- let hiveKnowledge = [];
67233
- try {
67234
- const hivePath = resolveHiveKnowledgePath();
67235
- if (fs24.existsSync(hivePath)) {
67236
- hiveKnowledge = await _internals32.readKnowledge(hivePath);
67237
- }
67238
- } catch {}
67239
- const allKnowledge = [...swarmKnowledge, ...hiveKnowledge];
67240
- const sourceIds = new Set(fm.sourceKnowledgeIds);
67241
- const sources = allKnowledge.filter((e) => sourceIds.has(e.id));
67242
- allArchived = sources.length === sourceIds.size && sources.every((e) => e.status === "archived");
67243
- }
67244
- } catch {}
67245
- if (violationRate > 0.3 || allArchived) {
67246
- const reason = violationRate > 0.3 ? `auto-retire: violation rate ${(violationRate * 100).toFixed(0)}% exceeds 30% threshold` : "auto-retire: all source knowledge entries archived";
67450
+ if (violationRate > 0.3) {
67451
+ const reason = `auto-retire: violation rate ${(violationRate * 100).toFixed(0)}% exceeds 30% threshold`;
67247
67452
  await _internals32.retireSkill(directory, active.slug, reason);
67248
67453
  observations.push(`Skill '${active.slug}' auto-retired: ${reason}`);
67249
67454
  warn(`[curator] ${observations[observations.length - 1]}`);
67455
+ continue;
67456
+ }
67457
+ const result = await _internals32.retireOrMarkStale(directory, path50.dirname(active.path), allArchivedIds);
67458
+ if (result.action === "retire") {
67459
+ observations.push(`Skill '${active.slug}' auto-retired: all source knowledge entries archived`);
67460
+ warn(`[curator] ${observations[observations.length - 1]}`);
67461
+ } else if (result.action === "stale") {
67462
+ observations.push(`Skill '${active.slug}' marked stale: some source knowledge entries archived`);
67463
+ warn(`[curator] ${observations[observations.length - 1]}`);
67250
67464
  }
67251
67465
  }
67252
67466
  } catch (autoRetireErr) {
@@ -68015,6 +68229,29 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config3, know
68015
68229
  const retireNote = ` [${autoRetireObservations.length} skill(s) auto-retired]`;
68016
68230
  phaseDigest.summary += retireNote;
68017
68231
  }
68232
+ try {
68233
+ const eventsContent = await readSwarmFileAsync(directory, "knowledge-events.jsonl");
68234
+ if (eventsContent) {
68235
+ const lines = eventsContent.split(`
68236
+ `).filter((l) => l.trim());
68237
+ const batchEvents = [];
68238
+ for (const line of lines) {
68239
+ try {
68240
+ const event = JSON.parse(line);
68241
+ if (event.type === "skill-stale-batch") {
68242
+ batchEvents.push({
68243
+ skillIds: event.skillIds ?? [],
68244
+ retiredCount: event.retiredCount ?? 0,
68245
+ staleCount: event.staleCount ?? 0
68246
+ });
68247
+ }
68248
+ } catch {}
68249
+ }
68250
+ for (const batch of batchEvents) {
68251
+ warn(`[curator] skill-stale-batch: ${batch.skillIds.length} skills affected (${batch.retiredCount} retired, ${batch.staleCount} stale)`);
68252
+ }
68253
+ }
68254
+ } catch {}
68018
68255
  try {
68019
68256
  const metrics = await computeLearningMetrics(directory, {
68020
68257
  currentPhase: phase
@@ -68220,6 +68457,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
68220
68457
  }
68221
68458
  var DEFAULT_CURATOR_LLM_TIMEOUT_MS = 300000, MAX_CURATOR_PHASE_DIGESTS = 50, MAX_CURATOR_COMPLIANCE_OBSERVATIONS = 200, MAX_CURATOR_RECOMMENDATIONS = 200, _internals32;
68222
68459
  var init_curator = __esm(() => {
68460
+ init_explorer();
68223
68461
  init_event_bus();
68224
68462
  init_schema();
68225
68463
  init_manager();
@@ -68245,7 +68483,9 @@ var init_curator = __esm(() => {
68245
68483
  readSkillUsageEntries,
68246
68484
  listSkills,
68247
68485
  parseDraftFrontmatter,
68486
+ retireOrMarkStale,
68248
68487
  retireSkill,
68488
+ getArchivedKnowledgeIds,
68249
68489
  readFileAsync: (filePath, encoding) => import("node:fs/promises").then((fs25) => fs25.readFile(filePath, encoding)),
68250
68490
  readKnowledge,
68251
68491
  reviseSkill,
@@ -68546,7 +68786,7 @@ import {
68546
68786
  readFile as readFile12,
68547
68787
  rename as rename7,
68548
68788
  stat as stat8,
68549
- unlink as unlink3,
68789
+ unlink as unlink4,
68550
68790
  writeFile as writeFile9
68551
68791
  } from "node:fs/promises";
68552
68792
  import * as path52 from "node:path";
@@ -68751,7 +68991,7 @@ async function writeSynonymMapAtomic(filePath, map3) {
68751
68991
  await rename7(tmp, filePath);
68752
68992
  } finally {
68753
68993
  try {
68754
- await unlink3(tmp);
68994
+ await unlink4(tmp);
68755
68995
  } catch {}
68756
68996
  }
68757
68997
  }
@@ -69314,7 +69554,7 @@ function discoverAvailableSkills(directory) {
69314
69554
  if (entry.startsWith("."))
69315
69555
  continue;
69316
69556
  const skillDir = path54.join(rootPath, entry);
69317
- if (_internals34.existsSync(path54.join(skillDir, "retired.marker")))
69557
+ if (_internals34.existsSync(path54.join(skillDir, "retired.marker")) || _internals34.existsSync(path54.join(skillDir, "stale.marker")))
69318
69558
  continue;
69319
69559
  const skillFile = path54.join(skillDir, "SKILL.md");
69320
69560
  try {
@@ -69520,7 +69760,7 @@ async function skillPropagationGateBefore(directory, input, config3) {
69520
69760
  const existingPaths = new Set(scored.map((s) => s.skillPath));
69521
69761
  for (const routingPath of routingPaths) {
69522
69762
  const routedSkillDir = path54.dirname(path54.join(directory, routingPath));
69523
- if (_internals34.existsSync(path54.join(routedSkillDir, "retired.marker")))
69763
+ if (_internals34.existsSync(path54.join(routedSkillDir, "retired.marker")) || _internals34.existsSync(path54.join(routedSkillDir, "stale.marker")))
69524
69764
  continue;
69525
69765
  if (!existingPaths.has(routingPath)) {
69526
69766
  scored.push({
@@ -69831,7 +70071,7 @@ var init_skill_propagation_gate = __esm(() => {
69831
70071
  });
69832
70072
 
69833
70073
  // src/hooks/micro-reflector.ts
69834
- import { existsSync as existsSync28 } from "node:fs";
70074
+ import { existsSync as existsSync27 } from "node:fs";
69835
70075
  import { readFile as readFile13, writeFile as writeFile10 } from "node:fs/promises";
69836
70076
  import * as path55 from "node:path";
69837
70077
  function resolveInsightCandidatesPath(directory) {
@@ -69866,7 +70106,7 @@ async function readTaskTrajectory(directory, taskId) {
69866
70106
  try {
69867
70107
  const rel = path55.join("evidence", sanitizeTaskId2(taskId), "trajectory.jsonl");
69868
70108
  const filePath = validateSwarmPath(directory, rel);
69869
- if (!existsSync28(filePath))
70109
+ if (!existsSync27(filePath))
69870
70110
  return [];
69871
70111
  const content = await readFile13(filePath, "utf-8");
69872
70112
  const out = [];
@@ -70110,7 +70350,7 @@ var init_micro_reflector = __esm(() => {
70110
70350
 
70111
70351
  // src/hooks/knowledge-curator.ts
70112
70352
  import { createHash as createHash9 } from "node:crypto";
70113
- import { existsSync as existsSync29 } from "node:fs";
70353
+ import { existsSync as existsSync28 } from "node:fs";
70114
70354
  import { appendFile as appendFile8, mkdir as mkdir13, readFile as readFile14, writeFile as writeFile11 } from "node:fs/promises";
70115
70355
  import * as path56 from "node:path";
70116
70356
  function pruneSeenRetroSections() {
@@ -70535,7 +70775,7 @@ function readInsightJsonl2(content) {
70535
70775
  async function consumeInsightCandidates(directory, batchLimit = MESO_INSIGHT_BATCH_LIMIT) {
70536
70776
  try {
70537
70777
  const filePath = resolveInsightCandidatesPath(directory);
70538
- if (!existsSync29(filePath))
70778
+ if (!existsSync28(filePath))
70539
70779
  return [];
70540
70780
  const consumed = [];
70541
70781
  await transactFile(filePath, async (p) => readInsightJsonl2(await readFile14(p, "utf-8").catch(() => "")), async (p, data) => {
@@ -71676,12 +71916,12 @@ var init_trajectory_cluster = __esm(() => {
71676
71916
  });
71677
71917
 
71678
71918
  // src/services/unactionable-hardening.ts
71679
- import { existsSync as existsSync30 } from "node:fs";
71919
+ import { existsSync as existsSync29 } from "node:fs";
71680
71920
  async function hardenUnactionableEntries(params) {
71681
71921
  const result = { hardened: 0, retired: 0, remaining: 0 };
71682
71922
  try {
71683
71923
  const queuePath = resolveUnactionablePath(params.directory);
71684
- if (!existsSync30(queuePath))
71924
+ if (!existsSync29(queuePath))
71685
71925
  return result;
71686
71926
  const limit = params.batchLimit ?? HARDENING_BATCH_LIMIT;
71687
71927
  const dedupThreshold = params.dedupThreshold ?? 0.6;
@@ -71788,7 +72028,7 @@ var init_unactionable_hardening = __esm(() => {
71788
72028
  });
71789
72029
 
71790
72030
  // src/services/skill-improver.ts
71791
- import { existsSync as existsSync31 } from "node:fs";
72031
+ import { existsSync as existsSync30 } from "node:fs";
71792
72032
  import { mkdir as mkdir15, readFile as readFile15, rename as rename8, writeFile as writeFile13 } from "node:fs/promises";
71793
72033
  import * as path59 from "node:path";
71794
72034
  function timestampSlug(d) {
@@ -71803,7 +72043,7 @@ async function atomicWrite4(p, content) {
71803
72043
  async function gatherInventory(directory) {
71804
72044
  const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
71805
72045
  const hivePath = resolveHiveKnowledgePath();
71806
- const hive = existsSync31(hivePath) ? await readKnowledge(hivePath) : [];
72046
+ const hive = existsSync30(hivePath) ? await readKnowledge(hivePath) : [];
71807
72047
  const archived = [...swarm, ...hive].filter((e) => e.status === "archived").length;
71808
72048
  const skills = await listSkills(directory);
71809
72049
  const knowledgeById = new Map([...swarm, ...hive].map((entry) => [entry.id, entry]));
@@ -74042,7 +74282,7 @@ __export(exports_skill_consolidation, {
74042
74282
  consolidationStatePath: () => consolidationStatePath,
74043
74283
  _internals: () => _internals39
74044
74284
  });
74045
- import { existsSync as existsSync33 } from "node:fs";
74285
+ import { existsSync as existsSync32 } from "node:fs";
74046
74286
  import { mkdir as mkdir16, readFile as readFile16, rename as rename9, writeFile as writeFile14 } from "node:fs/promises";
74047
74287
  import * as path62 from "node:path";
74048
74288
  function consolidationStatePath(directory) {
@@ -74050,7 +74290,7 @@ function consolidationStatePath(directory) {
74050
74290
  }
74051
74291
  async function readState2(directory) {
74052
74292
  const filePath = consolidationStatePath(directory);
74053
- if (!existsSync33(filePath))
74293
+ if (!existsSync32(filePath))
74054
74294
  return {};
74055
74295
  try {
74056
74296
  const parsed = JSON.parse(await readFile16(filePath, "utf-8"));
@@ -75679,7 +75919,7 @@ var init_gate_bridge = __esm(() => {
75679
75919
  });
75680
75920
 
75681
75921
  // src/services/version-check.ts
75682
- import { existsSync as existsSync34, mkdirSync as mkdirSync21, readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "node:fs";
75922
+ import { existsSync as existsSync33, mkdirSync as mkdirSync21, readFileSync as readFileSync18, writeFileSync as writeFileSync13 } from "node:fs";
75683
75923
  import { homedir as homedir8 } from "node:os";
75684
75924
  import { join as join51 } from "node:path";
75685
75925
  function cacheDir() {
@@ -75693,7 +75933,7 @@ function cacheFile() {
75693
75933
  function readVersionCache() {
75694
75934
  try {
75695
75935
  const path67 = cacheFile();
75696
- if (!existsSync34(path67))
75936
+ if (!existsSync33(path67))
75697
75937
  return null;
75698
75938
  const raw = readFileSync18(path67, "utf-8");
75699
75939
  const parsed = JSON.parse(raw);
@@ -75791,10 +76031,10 @@ var init_version_check = __esm(() => {
75791
76031
  });
75792
76032
 
75793
76033
  // src/services/knowledge-diagnostics.ts
75794
- import { existsSync as existsSync35 } from "node:fs";
76034
+ import { existsSync as existsSync34 } from "node:fs";
75795
76035
  import { readFile as readFile18 } from "node:fs/promises";
75796
76036
  async function readRawLines(filePath) {
75797
- if (!existsSync35(filePath))
76037
+ if (!existsSync34(filePath))
75798
76038
  return { entries: [], corrupt: 0 };
75799
76039
  const content = await readFile18(filePath, "utf-8");
75800
76040
  const entries = [];
@@ -75919,7 +76159,7 @@ async function computeKnowledgeDebug(directory) {
75919
76159
  };
75920
76160
  }
75921
76161
  async function safeJsonlCount(filePath) {
75922
- if (!filePath || !existsSync35(filePath))
76162
+ if (!filePath || !existsSync34(filePath))
75923
76163
  return 0;
75924
76164
  try {
75925
76165
  const content = await readFile18(filePath, "utf-8");
@@ -76002,7 +76242,7 @@ var init_knowledge_diagnostics = __esm(() => {
76002
76242
 
76003
76243
  // src/services/diagnose-service.ts
76004
76244
  import * as child_process6 from "node:child_process";
76005
- import { existsSync as existsSync36, readdirSync as readdirSync7, readFileSync as readFileSync19, statSync as statSync11 } from "node:fs";
76245
+ import { existsSync as existsSync35, readdirSync as readdirSync7, readFileSync as readFileSync19, statSync as statSync11 } from "node:fs";
76006
76246
  import path67 from "node:path";
76007
76247
  import { fileURLToPath as fileURLToPath2 } from "node:url";
76008
76248
  function validateTaskDag(plan) {
@@ -76250,7 +76490,7 @@ async function checkConfigBackups(directory) {
76250
76490
  }
76251
76491
  async function checkGitRepository(directory) {
76252
76492
  try {
76253
- if (!existsSync36(directory) || !statSync11(directory).isDirectory()) {
76493
+ if (!existsSync35(directory) || !statSync11(directory).isDirectory()) {
76254
76494
  return {
76255
76495
  name: "Git Repository",
76256
76496
  status: "❌",
@@ -76315,7 +76555,7 @@ async function checkSpecStaleness(directory, plan) {
76315
76555
  }
76316
76556
  async function checkConfigParseability(directory) {
76317
76557
  const configPath = path67.join(directory, ".opencode/opencode-swarm.json");
76318
- if (!existsSync36(configPath)) {
76558
+ if (!existsSync35(configPath)) {
76319
76559
  return {
76320
76560
  name: "Config Parseability",
76321
76561
  status: "✅",
@@ -76370,11 +76610,11 @@ async function checkGrammarWasmFiles() {
76370
76610
  const thisDir = path67.dirname(fileURLToPath2(import.meta.url));
76371
76611
  const grammarDir = resolveGrammarDir(thisDir);
76372
76612
  const missing = [];
76373
- if (!existsSync36(path67.join(grammarDir, "tree-sitter.wasm"))) {
76613
+ if (!existsSync35(path67.join(grammarDir, "tree-sitter.wasm"))) {
76374
76614
  missing.push("tree-sitter.wasm (core runtime)");
76375
76615
  }
76376
76616
  for (const file3 of grammarFiles) {
76377
- if (!existsSync36(path67.join(grammarDir, file3))) {
76617
+ if (!existsSync35(path67.join(grammarDir, file3))) {
76378
76618
  missing.push(file3);
76379
76619
  }
76380
76620
  }
@@ -76393,7 +76633,7 @@ async function checkGrammarWasmFiles() {
76393
76633
  }
76394
76634
  async function checkCheckpointManifest(directory) {
76395
76635
  const manifestPath = path67.join(directory, ".swarm/checkpoints.json");
76396
- if (!existsSync36(manifestPath)) {
76636
+ if (!existsSync35(manifestPath)) {
76397
76637
  return {
76398
76638
  name: "Checkpoint Manifest",
76399
76639
  status: "✅",
@@ -76445,7 +76685,7 @@ async function checkCheckpointManifest(directory) {
76445
76685
  }
76446
76686
  async function checkEventStreamIntegrity(directory) {
76447
76687
  const eventsPath = path67.join(directory, ".swarm/events.jsonl");
76448
- if (!existsSync36(eventsPath)) {
76688
+ if (!existsSync35(eventsPath)) {
76449
76689
  return {
76450
76690
  name: "Event Stream",
76451
76691
  status: "✅",
@@ -76486,7 +76726,7 @@ async function checkEventStreamIntegrity(directory) {
76486
76726
  }
76487
76727
  async function checkSteeringDirectives(directory) {
76488
76728
  const eventsPath = path67.join(directory, ".swarm/events.jsonl");
76489
- if (!existsSync36(eventsPath)) {
76729
+ if (!existsSync35(eventsPath)) {
76490
76730
  return {
76491
76731
  name: "Steering Directives",
76492
76732
  status: "✅",
@@ -76542,7 +76782,7 @@ async function checkCurator(directory) {
76542
76782
  };
76543
76783
  }
76544
76784
  const summaryPath = path67.join(directory, ".swarm/curator-summary.json");
76545
- if (!existsSync36(summaryPath)) {
76785
+ if (!existsSync35(summaryPath)) {
76546
76786
  return {
76547
76787
  name: "Curator",
76548
76788
  status: "✅",
@@ -76744,7 +76984,7 @@ async function getDiagnoseData(directory) {
76744
76984
  checks5.push(await checkKnowledgeHealth(directory));
76745
76985
  try {
76746
76986
  const evidenceDir = path67.join(directory, ".swarm", "evidence");
76747
- const snapshotFiles = existsSync36(evidenceDir) ? readdirSync7(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
76987
+ const snapshotFiles = existsSync35(evidenceDir) ? readdirSync7(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
76748
76988
  if (snapshotFiles.length > 0) {
76749
76989
  const latest = snapshotFiles.sort().pop();
76750
76990
  checks5.push({
@@ -76777,7 +77017,7 @@ async function getDiagnoseData(directory) {
76777
77017
  const cacheRows = [];
76778
77018
  for (const cachePath of cachePaths) {
76779
77019
  try {
76780
- if (!existsSync36(cachePath)) {
77020
+ if (!existsSync35(cachePath)) {
76781
77021
  cacheRows.push(`⬜ ${cachePath} — absent`);
76782
77022
  continue;
76783
77023
  }
@@ -82711,7 +82951,7 @@ var KNOWLEDGE_SCHEMA_VERSION = 2;
82711
82951
 
82712
82952
  // src/hooks/knowledge-migrator.ts
82713
82953
  import { randomUUID as randomUUID6 } from "node:crypto";
82714
- import { existsSync as existsSync43, readFileSync as readFileSync26 } from "node:fs";
82954
+ import { existsSync as existsSync42, readFileSync as readFileSync26 } from "node:fs";
82715
82955
  import { mkdir as mkdir17, readFile as readFile19, writeFile as writeFile15 } from "node:fs/promises";
82716
82956
  import * as os15 from "node:os";
82717
82957
  import * as path75 from "node:path";
@@ -82728,7 +82968,7 @@ async function migrateContextToKnowledge(directory, config3) {
82728
82968
  const sentinelPath = path75.join(directory, ".swarm", ".knowledge-migrated");
82729
82969
  const contextPath = path75.join(directory, ".swarm", "context.md");
82730
82970
  const knowledgePath = resolveSwarmKnowledgePath(directory);
82731
- if (existsSync43(sentinelPath)) {
82971
+ if (existsSync42(sentinelPath)) {
82732
82972
  return {
82733
82973
  migrated: false,
82734
82974
  entriesMigrated: 0,
@@ -82737,7 +82977,7 @@ async function migrateContextToKnowledge(directory, config3) {
82737
82977
  skippedReason: "sentinel-exists"
82738
82978
  };
82739
82979
  }
82740
- if (!existsSync43(contextPath)) {
82980
+ if (!existsSync42(contextPath)) {
82741
82981
  return {
82742
82982
  migrated: false,
82743
82983
  entriesMigrated: 0,
@@ -82829,7 +83069,7 @@ async function migrateHiveKnowledgeLegacy(config3) {
82829
83069
  const legacyHivePath = _internals51.resolveLegacyHiveKnowledgePath();
82830
83070
  const canonicalHivePath = resolveHiveKnowledgePath();
82831
83071
  const sentinelPath = path75.join(path75.dirname(canonicalHivePath), ".hive-knowledge-migrated");
82832
- if (existsSync43(sentinelPath)) {
83072
+ if (existsSync42(sentinelPath)) {
82833
83073
  return {
82834
83074
  migrated: false,
82835
83075
  entriesMigrated: 0,
@@ -82838,7 +83078,7 @@ async function migrateHiveKnowledgeLegacy(config3) {
82838
83078
  skippedReason: "sentinel-exists"
82839
83079
  };
82840
83080
  }
82841
- if (!existsSync43(legacyHivePath)) {
83081
+ if (!existsSync42(legacyHivePath)) {
82842
83082
  return {
82843
83083
  migrated: false,
82844
83084
  entriesMigrated: 0,
@@ -83040,7 +83280,7 @@ function truncateLesson2(text) {
83040
83280
  }
83041
83281
  function inferProjectName(directory) {
83042
83282
  const packageJsonPath = path75.join(directory, "package.json");
83043
- if (existsSync43(packageJsonPath)) {
83283
+ if (existsSync42(packageJsonPath)) {
83044
83284
  try {
83045
83285
  const pkg = JSON.parse(readFileSync26(packageJsonPath, "utf-8"));
83046
83286
  if (pkg.name && typeof pkg.name === "string") {
@@ -83433,12 +83673,12 @@ var init_identity = __esm(() => {
83433
83673
  });
83434
83674
 
83435
83675
  // src/commands/link.ts
83436
- import { existsSync as existsSync44 } from "node:fs";
83676
+ import { existsSync as existsSync43 } from "node:fs";
83437
83677
  import * as path77 from "node:path";
83438
83678
  async function mergeLocalKnowledgeIntoLink(localSwarmDir, linkDir) {
83439
83679
  const localPath = path77.join(localSwarmDir, "knowledge.jsonl");
83440
83680
  const sharedPath = path77.join(linkDir, "knowledge.jsonl");
83441
- if (!existsSync44(localPath))
83681
+ if (!existsSync43(localPath))
83442
83682
  return { merged: 0, skipped: 0 };
83443
83683
  let merged = 0;
83444
83684
  let skipped = 0;
@@ -84754,7 +84994,7 @@ var init_maintenance = __esm(() => {
84754
84994
 
84755
84995
  // src/memory/local-jsonl-provider.ts
84756
84996
  import { randomUUID as randomUUID7 } from "node:crypto";
84757
- import { existsSync as existsSync45 } from "node:fs";
84997
+ import { existsSync as existsSync44 } from "node:fs";
84758
84998
  import {
84759
84999
  appendFile as appendFile9,
84760
85000
  mkdir as mkdir18,
@@ -85105,7 +85345,7 @@ function validateLoadedProposals(values, config3) {
85105
85345
  return { records, invalidCount };
85106
85346
  }
85107
85347
  async function readJsonl(filePath) {
85108
- if (!existsSync45(filePath))
85348
+ if (!existsSync44(filePath))
85109
85349
  return [];
85110
85350
  const content = await readFile20(filePath, "utf-8");
85111
85351
  const records = [];
@@ -85265,7 +85505,7 @@ var init_prompt_block = __esm(() => {
85265
85505
  });
85266
85506
 
85267
85507
  // src/memory/jsonl-migration.ts
85268
- import { existsSync as existsSync46, renameSync as renameSync18, unlinkSync as unlinkSync13 } from "node:fs";
85508
+ import { existsSync as existsSync45, renameSync as renameSync18, unlinkSync as unlinkSync13 } from "node:fs";
85269
85509
  import { copyFile as copyFile2, mkdir as mkdir19, readFile as readFile21, stat as stat10, writeFile as writeFile17 } from "node:fs/promises";
85270
85510
  import * as path79 from "node:path";
85271
85511
  function resolveMemoryStorageDir(rootDirectory, config3 = {}) {
@@ -85297,10 +85537,10 @@ async function backupLegacyJsonl(rootDirectory, config3 = {}) {
85297
85537
  const results = [];
85298
85538
  for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
85299
85539
  const source = path79.join(storageDir, filename);
85300
- if (!existsSync46(source))
85540
+ if (!existsSync45(source))
85301
85541
  continue;
85302
85542
  const backup = path79.join(backupDir, `${filename}.pre-sqlite-migration`);
85303
- if (existsSync46(backup)) {
85543
+ if (existsSync45(backup)) {
85304
85544
  results.push({ source, backup, created: false });
85305
85545
  continue;
85306
85546
  }
@@ -85354,7 +85594,7 @@ async function writeMigrationReport(rootDirectory, report, config3 = {}) {
85354
85594
  }
85355
85595
  async function readMigrationReport(rootDirectory, config3 = {}) {
85356
85596
  const reportPath = path79.join(resolveMemoryStorageDir(rootDirectory, config3), "migration-report.json");
85357
- if (!existsSync46(reportPath))
85597
+ if (!existsSync45(reportPath))
85358
85598
  return null;
85359
85599
  try {
85360
85600
  return JSON.parse(await readFile21(reportPath, "utf-8"));
@@ -85368,13 +85608,13 @@ async function getLegacyJsonlFileStatus(rootDirectory, config3 = {}) {
85368
85608
  for (const file3 of ["memories.jsonl", "proposals.jsonl"]) {
85369
85609
  const filePath = path79.join(storageDir, file3);
85370
85610
  let sizeBytes = 0;
85371
- if (existsSync46(filePath)) {
85611
+ if (existsSync45(filePath)) {
85372
85612
  sizeBytes = (await stat10(filePath)).size;
85373
85613
  }
85374
85614
  statuses.push({
85375
85615
  file: file3,
85376
85616
  path: filePath,
85377
- exists: existsSync46(filePath),
85617
+ exists: existsSync45(filePath),
85378
85618
  sizeBytes
85379
85619
  });
85380
85620
  }
@@ -85455,7 +85695,7 @@ async function readProposalJsonl(filePath, config3) {
85455
85695
  return { records, invalidRows, totalRows: rows.totalRows };
85456
85696
  }
85457
85697
  async function readJsonlRows(filePath) {
85458
- if (!existsSync46(filePath)) {
85698
+ if (!existsSync45(filePath)) {
85459
85699
  return { rows: [], invalidRows: [], totalRows: 0 };
85460
85700
  }
85461
85701
  const content = await readFile21(filePath, "utf-8");
@@ -86729,7 +86969,7 @@ var init_provider_pool = __esm(() => {
86729
86969
 
86730
86970
  // src/memory/gateway.ts
86731
86971
  import { createHash as createHash13 } from "node:crypto";
86732
- import { existsSync as existsSync47, readFileSync as readFileSync27 } from "node:fs";
86972
+ import { existsSync as existsSync46, readFileSync as readFileSync27 } from "node:fs";
86733
86973
  import * as path82 from "node:path";
86734
86974
 
86735
86975
  class MemoryGateway {
@@ -87090,7 +87330,7 @@ function readGitRemoteUrl(directory) {
87090
87330
  if (gitRemoteUrlCache.has(directory))
87091
87331
  return gitRemoteUrlCache.get(directory);
87092
87332
  const gitConfigPath = path82.join(directory, ".git", "config");
87093
- if (!existsSync47(gitConfigPath)) {
87333
+ if (!existsSync46(gitConfigPath)) {
87094
87334
  gitRemoteUrlCache.set(directory, undefined);
87095
87335
  return;
87096
87336
  }
@@ -88194,7 +88434,7 @@ var init_consolidation_log = __esm(() => {
88194
88434
  });
88195
88435
 
88196
88436
  // src/commands/memory.ts
88197
- import { existsSync as existsSync48 } from "node:fs";
88437
+ import { existsSync as existsSync47 } from "node:fs";
88198
88438
  import * as path86 from "node:path";
88199
88439
  import { fileURLToPath as fileURLToPath3 } from "node:url";
88200
88440
  async function handleMemoryCommand(_directory, _args) {
@@ -88254,7 +88494,7 @@ async function handleMemoryStatusCommand(directory, _args) {
88254
88494
  `- Provider: \`${config3.provider}\``,
88255
88495
  `- Storage: \`${storageDir}\``,
88256
88496
  `- SQLite path: \`${sqlitePath}\``,
88257
- `- SQLite database exists: \`${existsSync48(sqlitePath)}\``,
88497
+ `- SQLite database exists: \`${existsSync47(sqlitePath)}\``,
88258
88498
  `- Automatic destructive cleanup: \`disabled\``,
88259
88499
  "",
88260
88500
  "### Legacy JSONL"
@@ -93116,19 +93356,19 @@ function hasCompoundTestExtension(filename) {
93116
93356
  const lower = filename.toLowerCase();
93117
93357
  return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
93118
93358
  }
93119
- function isLanguageSpecificTestFile(basename13) {
93120
- const lower = basename13.toLowerCase();
93359
+ function isLanguageSpecificTestFile(basename14) {
93360
+ const lower = basename14.toLowerCase();
93121
93361
  if (lower.endsWith("_test.go"))
93122
93362
  return true;
93123
93363
  if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
93124
93364
  return true;
93125
93365
  if (lower.endsWith("_spec.rb"))
93126
93366
  return true;
93127
- if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename13) || basename13.endsWith("Test.java") || basename13.endsWith("Tests.java") || lower.endsWith("it.java")))
93367
+ if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename14) || basename14.endsWith("Test.java") || basename14.endsWith("Tests.java") || lower.endsWith("it.java")))
93128
93368
  return true;
93129
93369
  if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
93130
93370
  return true;
93131
- if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename13) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
93371
+ if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename14) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
93132
93372
  return true;
93133
93373
  if (lower.endsWith(".tests.ps1"))
93134
93374
  return true;
@@ -93136,23 +93376,23 @@ function isLanguageSpecificTestFile(basename13) {
93136
93376
  }
93137
93377
  function isConventionTestFilePath(filePath) {
93138
93378
  const normalizedPath = filePath.replace(/\\/g, "/");
93139
- const basename13 = path99.basename(filePath);
93140
- return hasCompoundTestExtension(basename13) || basename13.includes(".spec.") || basename13.includes(".test.") || isLanguageSpecificTestFile(basename13) || isTestDirectoryPath(normalizedPath);
93379
+ const basename14 = path99.basename(filePath);
93380
+ return hasCompoundTestExtension(basename14) || basename14.includes(".spec.") || basename14.includes(".test.") || isLanguageSpecificTestFile(basename14) || isTestDirectoryPath(normalizedPath);
93141
93381
  }
93142
93382
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
93143
93383
  const testFiles = [];
93144
93384
  for (const file3 of sourceFiles) {
93145
93385
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
93146
93386
  const relativeFile = path99.relative(workingDir, absoluteFile);
93147
- const basename13 = path99.basename(absoluteFile);
93387
+ const basename14 = path99.basename(absoluteFile);
93148
93388
  const dirname45 = path99.dirname(absoluteFile);
93149
93389
  const preferRelativeOutput = !path99.isAbsolute(file3);
93150
93390
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
93151
93391
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
93152
93392
  continue;
93153
93393
  }
93154
- const nameWithoutExt = basename13.replace(/\.[^.]+$/, "");
93155
- const ext = path99.extname(basename13);
93394
+ const nameWithoutExt = basename14.replace(/\.[^.]+$/, "");
93395
+ const ext = path99.extname(basename14);
93156
93396
  const genericTestNames = [
93157
93397
  `${nameWithoutExt}.spec${ext}`,
93158
93398
  `${nameWithoutExt}.test${ext}`
@@ -93163,7 +93403,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
93163
93403
  ...languageSpecificTestNames
93164
93404
  ].map((candidateName) => path99.join(dirname45, candidateName));
93165
93405
  const testDirectoryNames = [
93166
- basename13,
93406
+ basename14,
93167
93407
  ...genericTestNames,
93168
93408
  ...languageSpecificTestNames
93169
93409
  ];
@@ -98740,12 +98980,12 @@ var init_turbo = __esm(() => {
98740
98980
  });
98741
98981
 
98742
98982
  // src/commands/unlink.ts
98743
- import { existsSync as existsSync60 } from "node:fs";
98983
+ import { existsSync as existsSync59 } from "node:fs";
98744
98984
  import * as path110 from "node:path";
98745
98985
  async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
98746
98986
  const sharedPath = path110.join(linkDir, "knowledge.jsonl");
98747
98987
  const localPath = path110.join(localSwarmDir, "knowledge.jsonl");
98748
- if (!existsSync60(sharedPath))
98988
+ if (!existsSync59(sharedPath))
98749
98989
  return 0;
98750
98990
  const sharedEntries = await readKnowledge(sharedPath);
98751
98991
  if (sharedEntries.length === 0)
@@ -101959,7 +102199,7 @@ Example: If the coder received \`SKILLS: file:.claude/skills/writing-tests/SKILL
101959
102199
 
101960
102200
  **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.
101961
102201
 
101962
- ## SWARM KNOWLEDGE DIRECTIVES (v2 acknowledgment contract)
102202
+ ## SWARM KNOWLEDGE DIRECTIVES (v2 acknowledgment contract; retained compatibility label)
101963
102203
 
101964
102204
  If a \`<swarm_knowledge_directives>\` block is present in your context, treat each
101965
102205
  record inside as a structured directive you MUST inspect before:
@@ -102180,7 +102420,7 @@ ACTION: Load skill file:.opencode/skills/brainstorm/SKILL.md immediately. Follow
102180
102420
 
102181
102421
  HARD CONSTRAINTS:
102182
102422
  - Complete the loaded skill's QA gate dialogue before save_plan.
102183
- - Preserve the legacy behavioral guidance markers below for prompt post-processing.
102423
+ - Preserve the behavioral guidance marker comments below for prompt post-processing. "Legacy" describes the marker format, not stale guidance.
102184
102424
 
102185
102425
  <!-- BEHAVIORAL_GUIDANCE_START -->
102186
102426
  - Treat brainstorm output as discovery material until the loaded skill transitions to SPECIFY or PLAN.
@@ -102197,7 +102437,7 @@ ACTION: Load skill file:.opencode/skills/specify/SKILL.md immediately. Follow th
102197
102437
  HARD CONSTRAINTS:
102198
102438
  - Complete the loaded skill's QA gate dialogue before save_plan.
102199
102439
  - Requirements must use independently testable FR-### and SC-### numbering.
102200
- - Preserve the legacy behavioral guidance markers below for prompt post-processing.
102440
+ - Preserve the behavioral guidance marker comments below for prompt post-processing. "Legacy" describes the marker format, not stale guidance.
102201
102441
 
102202
102442
  <!-- BEHAVIORAL_GUIDANCE_START -->
102203
102443
  - Follow the loaded skill's spec creation, clarification, and transition rules.
@@ -102321,7 +102561,7 @@ HARD CONSTRAINTS (apply regardless of skill load success):
102321
102561
  - Do NOT delegate to coder
102322
102562
  - Do NOT call declare_scope
102323
102563
  - Do NOT mutate source code or write any files outside .swarm/
102324
- - You (architect) own \`web_search\` and \`web_fetch\`; sme workers receive gathered evidence in their dispatch message — do NOT expect sme to fetch
102564
+ - In MODE: DEEP_RESEARCH, you (architect) coordinate \`web_search\` and own \`web_fetch\`; sme synthesis workers receive gathered evidence in their dispatch message — do NOT expect sme to fetch in this mode. Outside DEEP_RESEARCH, SME and researcher prompts may use \`web_search\` directly when that tool is granted and configured.
102325
102565
  - Every claim in the final report MUST cite a source from the gathered evidence; reviewers verify claim↔citation before a claim is reported
102326
102566
  - Critics challenge only high-stakes / contested claims — do NOT waste cycles on well-supported ones
102327
102567
  - If council.general.enabled is false or no search API key is configured, surface that and STOP — do not produce ungrounded research
@@ -102853,15 +103093,19 @@ Reply with a single fenced JSON block. No prose outside the block.
102853
103093
  Notes:
102854
103094
  - \`searchQueries\` is optional — list queries you would have run if you had web access (the architect uses these for audit), or omit / leave empty if none.
102855
103095
  - \`sources\` MUST come from the RESEARCH CONTEXT only. Copy title/url/snippet/query verbatim. Never invent sources.
102856
- - For Round 1: leave \`disagreementTopics\` as []. For Round 2: list the specific disagreement topics this response addresses.`, HARD_RULES = `================================================================
103096
+ - For Round 1: leave \`disagreementTopics\` as []. For Round 2: list the specific disagreement topics this response addresses.`, HARD_RULES, GENERALIST_COUNCIL_PROMPT, SKEPTIC_COUNCIL_PROMPT, DOMAIN_EXPERT_COUNCIL_PROMPT;
103097
+ var init_council_prompts = __esm(() => {
103098
+ HARD_RULES = `================================================================
102857
103099
  HARD RULES
102858
103100
  ================================================================
102859
103101
  - You have no tools. Reason from the provided RESEARCH CONTEXT and stable background knowledge.
103102
+ - If invoked through dispatch_lanes as a read-only advisory lane, the same no-tools rule applies.
102860
103103
  - Training knowledge may provide stable background only; it must not support current facts, rankings, prices, release status, active best practices, or "state of the art" claims.
102861
103104
  - Never invent sources. If the RESEARCH CONTEXT does not cover a needed claim, say so in \`areasOfUncertainty\`.
102862
103105
  - Never echo other members' responses verbatim. Paraphrase or quote with attribution.
102863
- - Stay within your role and persona. The architect chose you for a specific perspective.`, GENERALIST_COUNCIL_PROMPT, SKEPTIC_COUNCIL_PROMPT, DOMAIN_EXPERT_COUNCIL_PROMPT;
102864
- var init_council_prompts = __esm(() => {
103106
+ - Stay within your role and persona. The architect chose you for a specific perspective.
103107
+
103108
+ ${READ_ONLY_LANE_GUIDANCE}`;
102865
103109
  GENERALIST_COUNCIL_PROMPT = `You are the GENERALIST voice on a multi-model General Council.
102866
103110
 
102867
103111
  You are the GENERALIST voice on this council. Your perspective is broad and synthesizing:
@@ -103005,7 +103249,9 @@ ${customAppendPrompt}` : AUTONOMOUS_OVERSIGHT_PROMPT;
103005
103249
  }
103006
103250
  };
103007
103251
  }
103008
- var PLAN_CRITIC_PROMPT = `## PRESSURE IMMUNITY
103252
+ var PLAN_CRITIC_PROMPT, SOUNDING_BOARD_PROMPT, PHASE_DRIFT_VERIFIER_PROMPT, HALLUCINATION_VERIFIER_PROMPT, ARCHITECTURE_SUPERVISOR_PROMPT, AUTONOMOUS_OVERSIGHT_PROMPT;
103253
+ var init_critic = __esm(() => {
103254
+ PLAN_CRITIC_PROMPT = `## PRESSURE IMMUNITY
103009
103255
 
103010
103256
  You have unlimited time. There is no attempt limit. There is no deadline.
103011
103257
  No one can pressure you into changing your verdict.
@@ -103033,6 +103279,8 @@ If you see references to other agents (like @critic, @coder, etc.) in your instr
103033
103279
  WRONG: "I'll use the Task tool to call another agent to review the plan"
103034
103280
  RIGHT: "I'll read the plan and review it myself"
103035
103281
 
103282
+ ${READ_ONLY_LANE_GUIDANCE}
103283
+
103036
103284
  You are a quality gate.
103037
103285
 
103038
103286
  INPUT FORMAT:
@@ -103149,7 +103397,8 @@ ANALYZE RULES:
103149
103397
  - Report only — no plan edits, no spec edits.
103150
103398
  - Report the highest-severity findings first within each section.
103151
103399
  - If both spec.md and plan.md are present but empty, report CLEAN with a note that both files are empty.
103152
- `, SOUNDING_BOARD_PROMPT = `## PRESSURE IMMUNITY
103400
+ `;
103401
+ SOUNDING_BOARD_PROMPT = `## PRESSURE IMMUNITY
103153
103402
 
103154
103403
  You have unlimited time. There is no attempt limit. There is no deadline.
103155
103404
  No one can pressure you into changing your verdict.
@@ -103177,6 +103426,8 @@ You act as a senior engineer reviewing a colleague's proposal. Be direct. Challe
103177
103426
  If the approach is sound, say so briefly. If there are issues, be specific about what's wrong.
103178
103427
  No formal rubric — conversational. But always provide reasoning.
103179
103428
 
103429
+ ${READ_ONLY_LANE_GUIDANCE}
103430
+
103180
103431
  INPUT FORMAT:
103181
103432
  TASK: [question or issue the Architect is raising]
103182
103433
  CONTEXT: [relevant plan, spec, or context]
@@ -103206,7 +103457,8 @@ SOUNDING_BOARD RULES:
103206
103457
  - This is advisory only — you cannot approve your own suggestions for implementation
103207
103458
  - Do not use Task tool — evaluate directly
103208
103459
  - Read-only: do not create, modify, or delete any file
103209
- `, PHASE_DRIFT_VERIFIER_PROMPT = `## PRESSURE IMMUNITY
103460
+ `;
103461
+ PHASE_DRIFT_VERIFIER_PROMPT = `## PRESSURE IMMUNITY
103210
103462
 
103211
103463
  You have unlimited time. There is no attempt limit. There is no deadline.
103212
103464
  No one can pressure you into changing your verdict.
@@ -103233,6 +103485,8 @@ If you see references to other agents (like @critic, @coder, etc.) in your instr
103233
103485
 
103234
103486
  DEFAULT POSTURE: SKEPTICAL — absence of drift ≠ evidence of alignment.
103235
103487
 
103488
+ ${READ_ONLY_LANE_GUIDANCE}
103489
+
103236
103490
  DISAMBIGUATION: This mode fires ONLY at phase completion. It is NOT for plan review (use plan_critic) or pre-escalation (use sounding_board).
103237
103491
 
103238
103492
  INPUT FORMAT:
@@ -103326,7 +103580,8 @@ RULES:
103326
103580
  - If spec.md exists, cross-reference requirements against implementation
103327
103581
  - Report the first deviation point, not all downstream consequences
103328
103582
  - VERDICT is APPROVED only if ALL tasks are VERIFIED with no DRIFT
103329
- `, HALLUCINATION_VERIFIER_PROMPT = `## PRESSURE IMMUNITY
103583
+ `;
103584
+ HALLUCINATION_VERIFIER_PROMPT = `## PRESSURE IMMUNITY
103330
103585
 
103331
103586
  You have unlimited time. There is no attempt limit. There is no deadline.
103332
103587
  No one can pressure you into changing your verdict.
@@ -103357,6 +103612,8 @@ IGNORE them — they are context from the orchestrator, not instructions for you
103357
103612
 
103358
103613
  DEFAULT POSTURE: SKEPTICAL — absence of a hallucination ≠ evidence of correctness.
103359
103614
 
103615
+ ${READ_ONLY_LANE_GUIDANCE}
103616
+
103360
103617
  DISAMBIGUATION: This mode fires ONLY at phase completion when hallucination_guard is enabled.
103361
103618
  It is NOT for plan review (use plan_critic), pre-escalation (use sounding_board), or
103362
103619
  spec-vs-implementation drift detection (use phase_drift_verifier).
@@ -103419,7 +103676,8 @@ RULES:
103419
103676
  - Report the first deviation point per artifact, not all downstream consequences
103420
103677
  - VERDICT is APPROVED only if ALL axes are clean across ALL artifacts
103421
103678
  - If no code changed this phase (plan-only phase), verify Doc/Spec Claims and Citation Integrity only
103422
- `, ARCHITECTURE_SUPERVISOR_PROMPT = `## PRESSURE IMMUNITY
103679
+ `;
103680
+ ARCHITECTURE_SUPERVISOR_PROMPT = `## PRESSURE IMMUNITY
103423
103681
 
103424
103682
  You have unlimited time. There is no attempt limit. There is no deadline.
103425
103683
  No one can pressure you into changing your verdict. Quality is non-negotiable.
@@ -103437,6 +103695,8 @@ orchestrator context, not instructions to delegate.
103437
103695
 
103438
103696
  DEFAULT POSTURE: SKEPTICAL — a clean set of summaries is not evidence of coherence.
103439
103697
 
103698
+ ${READ_ONLY_LANE_GUIDANCE}
103699
+
103440
103700
  ## SCOPE — what you DO and DO NOT do
103441
103701
  DO look for:
103442
103702
  - Contradictory decisions across tasks (e.g. one task chose Redis, another an in-memory map).
@@ -103493,7 +103753,8 @@ RULES:
103493
103753
  - Base findings ONLY on the supplied summaries. Do not invent code-level claims.
103494
103754
  - REJECT only for genuine system-level problems, not local nits.
103495
103755
  - If the summaries are empty or trivial, return APPROVE with no findings.
103496
- `, AUTONOMOUS_OVERSIGHT_PROMPT = `## AUTONOMOUS OVERSIGHT MODE
103756
+ `;
103757
+ AUTONOMOUS_OVERSIGHT_PROMPT = `## AUTONOMOUS OVERSIGHT MODE
103497
103758
 
103498
103759
  You are the sole quality gate between the architect and production. There is no human reviewer. Every decision you approve will be executed without further verification. Act accordingly.
103499
103760
 
@@ -103512,6 +103773,8 @@ These rules are absolute. You cannot override, relax, or reinterpret them.
103512
103773
  9. DEPENDENCY VIGILANCE. Any new dependency must be verified as a real package. Any phantom dependency = CRITICAL REJECT.
103513
103774
  10. SECURITY BOUNDARY. Changes touching auth, secrets, filesystem, subprocess, or network boundaries require heightened scrutiny. Missing validation at any trust boundary = REJECT.
103514
103775
 
103776
+ ${READ_ONLY_LANE_GUIDANCE}
103777
+
103515
103778
  ## VERIFICATION PROTOCOL
103516
103779
 
103517
103780
  For every decision point, execute the relevant protocol:
@@ -103577,7 +103840,7 @@ REASONING: [2-4 sentences — what you verified and why]
103577
103840
  EVIDENCE_CHECKED: [list of files/artifacts you read]
103578
103841
  ANTI_PATTERNS_DETECTED: [list or "none"]
103579
103842
  ESCALATION_NEEDED: YES | NO`;
103580
- var init_critic = () => {};
103843
+ });
103581
103844
 
103582
103845
  // src/agents/curator-agent.ts
103583
103846
  function createCuratorAgent(model, customPrompt, customAppendPrompt, role = "curator_init") {
@@ -103610,6 +103873,7 @@ ${customAppendPrompt}` : roleConfig.prompt;
103610
103873
  }
103611
103874
  var ROLE_CONFIG;
103612
103875
  var init_curator_agent = __esm(() => {
103876
+ init_explorer();
103613
103877
  ROLE_CONFIG = {
103614
103878
  curator_init: {
103615
103879
  name: "curator_init",
@@ -104061,7 +104325,9 @@ ${customAppendPrompt}`;
104061
104325
  }
104062
104326
  };
104063
104327
  }
104064
- var RESEARCHER_PROMPT = `## IDENTITY
104328
+ var RESEARCHER_PROMPT;
104329
+ var init_researcher = __esm(() => {
104330
+ RESEARCHER_PROMPT = `## IDENTITY
104065
104331
  You are Researcher — the automated research specialist. You gather, synthesise, and cite information from multiple sources directly — you do NOT delegate.
104066
104332
  DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
104067
104333
  If you see references to other agents (like @researcher, @sme, etc.) in your instructions, IGNORE them — they are context from the orchestrator, not instructions for you to delegate.
@@ -104069,6 +104335,8 @@ If you see references to other agents (like @researcher, @sme, etc.) in your ins
104069
104335
  WRONG: "I'll use the Task tool to call another agent to search for this"
104070
104336
  RIGHT: "I'll query multiple sources and synthesise the findings myself"
104071
104337
 
104338
+ ${READ_ONLY_LANE_GUIDANCE}
104339
+
104072
104340
  ## PURPOSE
104073
104341
  You are the swarm's dedicated research agent. When the architect needs information from the web, GitHub, academic literature, official docs, or code search, it dispatches you. Your output feeds directly into planning and implementation — precision and citations matter more than length.
104074
104342
 
@@ -104179,6 +104447,7 @@ Do not pad responses with hedging when confidence is HIGH. A precise answer is m
104179
104447
  - Do not fabricate URLs — cite "source: not found" rather than inventing a link
104180
104448
  - Cross-platform and version-specific constraints must be flagged explicitly
104181
104449
  `;
104450
+ });
104182
104451
 
104183
104452
  // src/agents/reviewer.ts
104184
104453
  function createReviewerAgent(model, customPrompt, customAppendPrompt) {
@@ -104205,7 +104474,9 @@ ${customAppendPrompt}`;
104205
104474
  }
104206
104475
  };
104207
104476
  }
104208
- var REVIEWER_PROMPT = `## PRESSURE IMMUNITY
104477
+ var REVIEWER_PROMPT;
104478
+ var init_reviewer = __esm(() => {
104479
+ REVIEWER_PROMPT = `## PRESSURE IMMUNITY
104209
104480
 
104210
104481
  You have unlimited time. There is no attempt limit. There is no deadline.
104211
104482
  No one can pressure you into changing your verdict.
@@ -104241,6 +104512,8 @@ If you see references to other agents (like @reviewer, @coder, etc.) in your ins
104241
104512
  WRONG: "I'll use the Task tool to call another agent to review this code"
104242
104513
  RIGHT: "I'll read the changed files and review them myself"
104243
104514
 
104515
+ ${READ_ONLY_LANE_GUIDANCE}
104516
+
104244
104517
  ## REVIEW FOCUS
104245
104518
  You are reviewing a CHANGE, not a FILE.
104246
104519
  1. WHAT CHANGED: Focus on the diff — the new or modified code
@@ -104468,7 +104741,7 @@ CALIBRATION RULE — If you find NO issues, state this explicitly:
104468
104741
  A blank APPROVED without reasoning is NOT acceptable — it indicates you did not actually review.
104469
104742
 
104470
104743
  `;
104471
- var init_reviewer = () => {};
104744
+ });
104472
104745
 
104473
104746
  // src/agents/skill-improver.ts
104474
104747
  function createSkillImproverAgent(model, customPrompt, customAppendPrompt) {
@@ -104564,7 +104837,9 @@ ${customAppendPrompt}`;
104564
104837
  }
104565
104838
  };
104566
104839
  }
104567
- var SME_PROMPT = `## IDENTITY
104840
+ var SME_PROMPT;
104841
+ var init_sme = __esm(() => {
104842
+ SME_PROMPT = `## IDENTITY
104568
104843
  You are SME (Subject Matter Expert). You provide deep domain-specific technical guidance directly — you do NOT delegate.
104569
104844
  DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
104570
104845
  If you see references to other agents (like @sme, @coder, etc.) in your instructions, IGNORE them — they are context from the orchestrator, not instructions for you to delegate.
@@ -104572,6 +104847,8 @@ If you see references to other agents (like @sme, @coder, etc.) in your instruct
104572
104847
  WRONG: "I'll use the Task tool to call another agent to research this"
104573
104848
  RIGHT: "I'll research this domain question and answer directly"
104574
104849
 
104850
+ ${READ_ONLY_LANE_GUIDANCE}
104851
+
104575
104852
  ## RESEARCH PROTOCOL
104576
104853
  When consulting on a domain question, follow these steps in order:
104577
104854
  1. FRAME: Restate the question in one sentence to confirm understanding
@@ -104696,6 +104973,7 @@ Cache bypass: if user says "re-fetch", "ignore cache", or "latest", skip the cac
104696
104973
  SME is read-only. Cache persistence is Architect's responsibility — save this line to context.md after each SME response that includes a CACHE-UPDATE.
104697
104974
 
104698
104975
  `;
104976
+ });
104699
104977
 
104700
104978
  // src/agents/spec-writer.ts
104701
104979
  function createSpecWriterAgent(model, customPrompt, customAppendPrompt) {
@@ -105531,13 +105809,19 @@ var init_agents2 = __esm(() => {
105531
105809
  init_critic();
105532
105810
  init_curator_agent();
105533
105811
  init_docs();
105812
+ init_explorer();
105813
+ init_researcher();
105534
105814
  init_reviewer();
105815
+ init_sme();
105535
105816
  init_architect();
105536
105817
  init_council_prompts();
105537
105818
  init_critic();
105538
105819
  init_curator_agent();
105539
105820
  init_docs();
105821
+ init_explorer();
105822
+ init_researcher();
105540
105823
  init_reviewer();
105824
+ init_sme();
105541
105825
  warnedAgents = new Set;
105542
105826
  _swarmAgentsMap = new Map;
105543
105827
  KNOWN_VARIANT_VALUES = new Set([
@@ -105556,11 +105840,11 @@ __export(exports_evidence_summary_integration, {
105556
105840
  createEvidenceSummaryIntegration: () => createEvidenceSummaryIntegration,
105557
105841
  EvidenceSummaryIntegration: () => EvidenceSummaryIntegration
105558
105842
  });
105559
- import { existsSync as existsSync61, mkdirSync as mkdirSync32, writeFileSync as writeFileSync18 } from "node:fs";
105843
+ import { existsSync as existsSync60, mkdirSync as mkdirSync32, writeFileSync as writeFileSync18 } from "node:fs";
105560
105844
  import * as path114 from "node:path";
105561
105845
  function persistSummary(projectDir, artifact, filename) {
105562
105846
  const swarmPath = path114.join(projectDir, ".swarm");
105563
- if (!existsSync61(swarmPath)) {
105847
+ if (!existsSync60(swarmPath)) {
105564
105848
  mkdirSync32(swarmPath, { recursive: true });
105565
105849
  }
105566
105850
  const artifactPath = path114.join(swarmPath, filename);
@@ -106572,7 +106856,7 @@ var init_schema3 = __esm(() => {
106572
106856
 
106573
106857
  // src/summaries/store.ts
106574
106858
  import {
106575
- existsSync as existsSync73,
106859
+ existsSync as existsSync72,
106576
106860
  mkdirSync as mkdirSync39,
106577
106861
  readFileSync as readFileSync49,
106578
106862
  renameSync as renameSync26,
@@ -106587,7 +106871,7 @@ function writeRawSidecar(absPath, bundle) {
106587
106871
  writeFileSync25(tempFile, JSON.stringify(bundle, null, 2), "utf-8");
106588
106872
  renameSync26(tempFile, absPath);
106589
106873
  } finally {
106590
- if (existsSync73(tempFile)) {
106874
+ if (existsSync72(tempFile)) {
106591
106875
  try {
106592
106876
  unlinkSync22(tempFile);
106593
106877
  } catch {}
@@ -106674,7 +106958,7 @@ function readSupervisorReportRaw(directory, phase) {
106674
106958
  } catch {
106675
106959
  return null;
106676
106960
  }
106677
- if (!existsSync73(abs))
106961
+ if (!existsSync72(abs))
106678
106962
  return null;
106679
106963
  try {
106680
106964
  const parsed = JSON.parse(readFileSync49(abs, "utf-8"));
@@ -106773,7 +107057,7 @@ __export(exports_runtime, {
106773
107057
  clearParserCache: () => clearParserCache,
106774
107058
  _internals: () => _internals79
106775
107059
  });
106776
- import { existsSync as existsSync74, statSync as statSync24 } from "node:fs";
107060
+ import { existsSync as existsSync73, statSync as statSync24 } from "node:fs";
106777
107061
  import * as path129 from "node:path";
106778
107062
  import { fileURLToPath as fileURLToPath4 } from "node:url";
106779
107063
  import { Language, Parser as TreeSitterParser } from "web-tree-sitter";
@@ -106842,7 +107126,7 @@ async function loadGrammar(languageId) {
106842
107126
  const parser = new TreeSitterParser;
106843
107127
  const wasmFileName = getWasmFileName(normalizedId);
106844
107128
  const wasmPath = path129.join(getGrammarsDirAbsolute(), wasmFileName);
106845
- if (!existsSync74(wasmPath)) {
107129
+ if (!existsSync73(wasmPath)) {
106846
107130
  throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
106847
107131
  ` + `Make sure to run 'bun run build' to copy grammar files to dist/lang/grammars/`);
106848
107132
  }
@@ -107025,17 +107309,17 @@ function normalizeSeparators(filePath) {
107025
107309
  }
107026
107310
  function matchesDocPattern(filePath, patterns) {
107027
107311
  const normalizedPath = normalizeSeparators(filePath);
107028
- const basename16 = path142.basename(filePath);
107312
+ const basename17 = path142.basename(filePath);
107029
107313
  for (const pattern of patterns) {
107030
107314
  if (!pattern.includes("/") && !pattern.includes("\\")) {
107031
- if (basename16 === pattern) {
107315
+ if (basename17 === pattern) {
107032
107316
  return true;
107033
107317
  }
107034
107318
  continue;
107035
107319
  }
107036
107320
  if (pattern.startsWith("**/")) {
107037
107321
  const filenamePattern = pattern.slice(3);
107038
- if (basename16 === filenamePattern) {
107322
+ if (basename17 === filenamePattern) {
107039
107323
  return true;
107040
107324
  }
107041
107325
  continue;
@@ -107428,7 +107712,7 @@ var init_doc_scan = __esm(() => {
107428
107712
  });
107429
107713
 
107430
107714
  // src/hooks/knowledge-reader.ts
107431
- import { existsSync as existsSync79 } from "node:fs";
107715
+ import { existsSync as existsSync78 } from "node:fs";
107432
107716
  import { readFile as readFile29 } from "node:fs/promises";
107433
107717
  import * as path143 from "node:path";
107434
107718
  function inferCategoriesFromPhase(phaseDescription) {
@@ -107476,7 +107760,7 @@ function inferCategoriesFromPhase(phaseDescription) {
107476
107760
  }
107477
107761
  async function transactShownFile(shownFile, mutate) {
107478
107762
  return transactFile(shownFile, async (filePath) => {
107479
- if (!existsSync79(filePath))
107763
+ if (!existsSync78(filePath))
107480
107764
  return {};
107481
107765
  try {
107482
107766
  const content = await readFile29(filePath, "utf-8");
@@ -107606,7 +107890,7 @@ async function readMergedKnowledge(directory, config3, context, opts) {
107606
107890
  async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
107607
107891
  const shownFile = path143.join(directory, ".swarm", ".knowledge-shown.json");
107608
107892
  try {
107609
- if (!existsSync79(shownFile)) {
107893
+ if (!existsSync78(shownFile)) {
107610
107894
  return;
107611
107895
  }
107612
107896
  let shownIds;
@@ -108336,7 +108620,7 @@ __export(exports_design_doc_drift, {
108336
108620
  _internals: () => _internals111
108337
108621
  });
108338
108622
  import * as fs118 from "node:fs";
108339
- import * as path188 from "node:path";
108623
+ import * as path190 from "node:path";
108340
108624
  function mtimeMsOrNull(absPath) {
108341
108625
  try {
108342
108626
  return fs118.statSync(absPath).mtimeMs;
@@ -108347,35 +108631,35 @@ function mtimeMsOrNull(absPath) {
108347
108631
  function resolveAnchorWithin(directory, anchor) {
108348
108632
  if (!anchor || typeof anchor !== "string")
108349
108633
  return null;
108350
- const root = path188.resolve(directory);
108351
- const resolved = path188.resolve(root, anchor);
108352
- const rel = path188.relative(root, resolved);
108353
- if (rel.startsWith("..") || path188.isAbsolute(rel))
108634
+ const root = path190.resolve(directory);
108635
+ const resolved = path190.resolve(root, anchor);
108636
+ const rel = path190.relative(root, resolved);
108637
+ if (rel.startsWith("..") || path190.isAbsolute(rel))
108354
108638
  return null;
108355
108639
  return resolved;
108356
108640
  }
108357
108641
  async function runDesignDocDriftCheck(directory, phase, outDir) {
108358
108642
  try {
108359
- const root = path188.resolve(directory);
108360
- const outAbs = path188.resolve(root, outDir);
108361
- const outRel = path188.relative(root, outAbs);
108362
- if (outRel.startsWith("..") || path188.isAbsolute(outRel)) {
108643
+ const root = path190.resolve(directory);
108644
+ const outAbs = path190.resolve(root, outDir);
108645
+ const outRel = path190.relative(root, outAbs);
108646
+ if (outRel.startsWith("..") || path190.isAbsolute(outRel)) {
108363
108647
  return null;
108364
108648
  }
108365
108649
  const docMtimes = new Map;
108366
108650
  const checkedDocs = [];
108367
108651
  const missingDocs = [];
108368
108652
  for (const [docName, relFile] of Object.entries(DESIGN_DOC_FILES)) {
108369
- const abs = path188.join(outAbs, relFile);
108653
+ const abs = path190.join(outAbs, relFile);
108370
108654
  const mtime = mtimeMsOrNull(abs);
108371
108655
  docMtimes.set(docName, mtime);
108372
108656
  if (mtime === null) {
108373
- missingDocs.push(path188.join(outDir, relFile));
108657
+ missingDocs.push(path190.join(outDir, relFile));
108374
108658
  } else {
108375
- checkedDocs.push(path188.join(outDir, relFile));
108659
+ checkedDocs.push(path190.join(outDir, relFile));
108376
108660
  }
108377
108661
  }
108378
- const traceabilityAbs = path188.join(outAbs, TRACEABILITY_REL);
108662
+ const traceabilityAbs = path190.join(outAbs, TRACEABILITY_REL);
108379
108663
  let registry3 = null;
108380
108664
  try {
108381
108665
  const stat14 = await fs118.promises.stat(traceabilityAbs);
@@ -108445,7 +108729,7 @@ async function runDesignDocDriftCheck(directory, phase, outDir) {
108445
108729
  };
108446
108730
  const filename = `${DOC_DRIFT_REPORT_PREFIX}${phase}.json`;
108447
108731
  const filePath = validateSwarmPath(directory, filename);
108448
- await fs118.promises.mkdir(path188.dirname(filePath), { recursive: true });
108732
+ await fs118.promises.mkdir(path190.dirname(filePath), { recursive: true });
108449
108733
  await fs118.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
108450
108734
  getGlobalEventBus().publish("curator.docdrift.completed", {
108451
108735
  phase,
@@ -108477,10 +108761,10 @@ var init_design_doc_drift = __esm(() => {
108477
108761
  domain: "domain.md",
108478
108762
  "technical-spec": "technical-spec.md",
108479
108763
  "behavior-spec": "behavior-spec.md",
108480
- "reference-impl": path188.join("reference", "reference-impl.md"),
108481
- "idiom-notes": path188.join("reference", "idiom-notes.md")
108764
+ "reference-impl": path190.join("reference", "reference-impl.md"),
108765
+ "idiom-notes": path190.join("reference", "idiom-notes.md")
108482
108766
  };
108483
- TRACEABILITY_REL = path188.join("reference", "traceability.json");
108767
+ TRACEABILITY_REL = path190.join("reference", "traceability.json");
108484
108768
  _internals111 = {
108485
108769
  mtimeMsOrNull,
108486
108770
  resolveAnchorWithin,
@@ -108492,11 +108776,11 @@ var init_design_doc_drift = __esm(() => {
108492
108776
  var exports_project_context = {};
108493
108777
  __export(exports_project_context, {
108494
108778
  buildProjectContext: () => buildProjectContext,
108495
- _internals: () => _internals124,
108779
+ _internals: () => _internals125,
108496
108780
  LANG_BACKEND_DETECTION_TIMEOUT_MS: () => LANG_BACKEND_DETECTION_TIMEOUT_MS
108497
108781
  });
108498
108782
  import * as fs142 from "node:fs";
108499
- import * as path217 from "node:path";
108783
+ import * as path219 from "node:path";
108500
108784
  function detectFileExists2(directory, pattern) {
108501
108785
  if (pattern.includes("*") || pattern.includes("?")) {
108502
108786
  try {
@@ -108508,7 +108792,7 @@ function detectFileExists2(directory, pattern) {
108508
108792
  }
108509
108793
  }
108510
108794
  try {
108511
- fs142.accessSync(path217.join(directory, pattern));
108795
+ fs142.accessSync(path219.join(directory, pattern));
108512
108796
  return true;
108513
108797
  } catch {
108514
108798
  return false;
@@ -108517,7 +108801,7 @@ function detectFileExists2(directory, pattern) {
108517
108801
  function selectTestCommandFromScriptsTest(backend, directory) {
108518
108802
  let pkgRaw;
108519
108803
  try {
108520
- pkgRaw = fs142.readFileSync(path217.join(directory, "package.json"), "utf-8");
108804
+ pkgRaw = fs142.readFileSync(path219.join(directory, "package.json"), "utf-8");
108521
108805
  } catch {
108522
108806
  return null;
108523
108807
  }
@@ -108576,7 +108860,7 @@ function selectLintCommand(backend, directory) {
108576
108860
  return null;
108577
108861
  }
108578
108862
  async function buildProjectContext(directory) {
108579
- const backend = await _internals124.pickBackend(directory);
108863
+ const backend = await _internals125.pickBackend(directory);
108580
108864
  if (!backend)
108581
108865
  return null;
108582
108866
  const ctx = emptyProjectContext();
@@ -108615,17 +108899,17 @@ async function buildProjectContext(directory) {
108615
108899
  if (backend.prompts.reviewerChecklist.length > 0) {
108616
108900
  ctx.REVIEWER_CHECKLIST = bulletList(backend.prompts.reviewerChecklist);
108617
108901
  }
108618
- const profiles = _internals124.pickedProfiles(directory);
108902
+ const profiles = _internals125.pickedProfiles(directory);
108619
108903
  if (profiles.length > 1) {
108620
108904
  ctx.PROJECT_CONTEXT_SECONDARY_LANGUAGES = profiles.slice(1).map((p) => p.id).join(", ");
108621
108905
  }
108622
108906
  return ctx;
108623
108907
  }
108624
- var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals124;
108908
+ var LANG_BACKEND_DETECTION_TIMEOUT_MS = 300, _internals125;
108625
108909
  var init_project_context = __esm(() => {
108626
108910
  init_dispatch();
108627
108911
  init_framework_detector();
108628
- _internals124 = {
108912
+ _internals125 = {
108629
108913
  pickBackend,
108630
108914
  pickedProfiles
108631
108915
  };
@@ -108635,7 +108919,7 @@ var init_project_context = __esm(() => {
108635
108919
  init_package();
108636
108920
  init_agents2();
108637
108921
  init_critic();
108638
- import * as path218 from "node:path";
108922
+ import * as path220 from "node:path";
108639
108923
  import { fileURLToPath as fileURLToPath5 } from "node:url";
108640
108924
 
108641
108925
  // src/background/index.ts
@@ -113337,7 +113621,7 @@ import * as path138 from "node:path";
113337
113621
  // src/tools/repo-graph/builder.ts
113338
113622
  init_profiles();
113339
113623
  import * as fsSync8 from "node:fs";
113340
- import { existsSync as existsSync75, realpathSync as realpathSync14 } from "node:fs";
113624
+ import { existsSync as existsSync74, realpathSync as realpathSync14 } from "node:fs";
113341
113625
  import * as fsPromises5 from "node:fs/promises";
113342
113626
  import * as os17 from "node:os";
113343
113627
  import * as path133 from "node:path";
@@ -115549,7 +115833,7 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
115549
115833
  if (realRoot === null) {
115550
115834
  return null;
115551
115835
  }
115552
- if (!existsSync75(resolved)) {
115836
+ if (!existsSync74(resolved)) {
115553
115837
  const EXTENSIONS = [
115554
115838
  ".ts",
115555
115839
  ".tsx",
@@ -115563,7 +115847,7 @@ function resolveModuleSpecifier(workspaceRoot, sourceFile, specifier) {
115563
115847
  let found = null;
115564
115848
  for (const ext of EXTENSIONS) {
115565
115849
  const candidate = resolved + ext;
115566
- if (existsSync75(candidate)) {
115850
+ if (existsSync74(candidate)) {
115567
115851
  found = candidate;
115568
115852
  break;
115569
115853
  }
@@ -116061,7 +116345,7 @@ async function buildWorkspaceGraphAsync(workspaceRoot, options) {
116061
116345
  const walkBudgetMs = options?.walkBudgetMs ?? DEFAULT_WALK_BUDGET_MS;
116062
116346
  const followSymlinks = options?.followSymlinks ?? false;
116063
116347
  const absoluteRoot = path133.resolve(workspaceRoot);
116064
- if (!existsSync75(absoluteRoot)) {
116348
+ if (!existsSync74(absoluteRoot)) {
116065
116349
  throw new Error(`Workspace directory does not exist: ${workspaceRoot}`);
116066
116350
  }
116067
116351
  if (isRefusedWorkspaceRoot(absoluteRoot)) {
@@ -116170,7 +116454,7 @@ function getCachedMtime(workspace) {
116170
116454
  // src/tools/repo-graph/incremental.ts
116171
116455
  init_logger();
116172
116456
  init_path_security();
116173
- import { existsSync as existsSync77 } from "node:fs";
116457
+ import { existsSync as existsSync76 } from "node:fs";
116174
116458
  import * as fsPromises7 from "node:fs/promises";
116175
116459
  import * as path137 from "node:path";
116176
116460
 
@@ -116862,7 +117146,7 @@ function buildOntologyPreflightPacket(graph, filePaths = [], options = {}) {
116862
117146
  init_utils2();
116863
117147
  init_logger();
116864
117148
  init_path_security();
116865
- import { constants as constants5, existsSync as existsSync76, readFileSync as readFileSync52, statSync as statSync27 } from "node:fs";
117149
+ import { constants as constants5, existsSync as existsSync75, readFileSync as readFileSync52, statSync as statSync27 } from "node:fs";
116866
117150
  import * as fsPromises6 from "node:fs/promises";
116867
117151
  import * as path136 from "node:path";
116868
117152
  var WINDOWS_RENAME_MAX_RETRIES2 = 5;
@@ -116934,7 +117218,7 @@ async function loadGraph(workspace) {
116934
117218
  if (cached3 && !isDirty(normalized)) {
116935
117219
  try {
116936
117220
  const graphPath = getGraphPath(workspace);
116937
- if (existsSync76(graphPath)) {
117221
+ if (existsSync75(graphPath)) {
116938
117222
  const stats2 = await fsPromises6.stat(graphPath);
116939
117223
  const cachedMtime = getCachedMtime(normalized);
116940
117224
  if (cachedMtime !== undefined && stats2.mtimeMs !== cachedMtime) {
@@ -116951,7 +117235,7 @@ async function loadGraph(workspace) {
116951
117235
  }
116952
117236
  try {
116953
117237
  const graphPath = getGraphPath(workspace);
116954
- if (!existsSync76(graphPath)) {
117238
+ if (!existsSync75(graphPath)) {
116955
117239
  return null;
116956
117240
  }
116957
117241
  const stats2 = await fsPromises6.stat(graphPath);
@@ -116985,7 +117269,7 @@ function loadGraphSync(workspace) {
116985
117269
  const normalized = path136.normalize(workspace);
116986
117270
  try {
116987
117271
  const graphPath = getGraphPath(workspace);
116988
- if (!existsSync76(graphPath))
117272
+ if (!existsSync75(graphPath))
116989
117273
  return null;
116990
117274
  const stats2 = statSync27(graphPath);
116991
117275
  const content = readFileSync52(graphPath, "utf-8");
@@ -117115,7 +117399,7 @@ async function updateGraphForFiles(workspaceRoot, filePaths, options) {
117115
117399
  const updatedPaths = new Set;
117116
117400
  for (const rawFilePath of filePaths) {
117117
117401
  const normalizedPath = normalizeGraphPath(rawFilePath);
117118
- const fileExists = existsSync77(rawFilePath);
117402
+ const fileExists = existsSync76(rawFilePath);
117119
117403
  if (fileExists) {
117120
117404
  graph.edges = graph.edges.filter((e) => normalizeGraphPath(e.source) !== normalizedPath);
117121
117405
  if (graph.symbolEdges) {
@@ -117190,7 +117474,7 @@ async function updateGraphForFiles(workspaceRoot, filePaths, options) {
117190
117474
  if (loadedMtime !== undefined) {
117191
117475
  try {
117192
117476
  const graphPath = getGraphPath(workspaceRoot);
117193
- if (existsSync77(graphPath)) {
117477
+ if (existsSync76(graphPath)) {
117194
117478
  const currentStats = await fsPromises7.stat(graphPath);
117195
117479
  if (currentStats.mtimeMs !== loadedMtime) {
117196
117480
  warn(`[repo-graph] Concurrent modification detected — falling back to full rebuild`);
@@ -121362,7 +121646,7 @@ init_logger();
121362
121646
  init_knowledge_link();
121363
121647
  init_knowledge_store();
121364
121648
  var import_proper_lockfile9 = __toESM(require_proper_lockfile(), 1);
121365
- import { existsSync as existsSync81 } from "node:fs";
121649
+ import { existsSync as existsSync80 } from "node:fs";
121366
121650
  import { appendFile as appendFile14, mkdir as mkdir29, readFile as readFile31 } from "node:fs/promises";
121367
121651
  import * as path147 from "node:path";
121368
121652
  function resolveApplicationLogPath(directory) {
@@ -121451,7 +121735,7 @@ async function bumpCountersBatch(directory, bumps) {
121451
121735
  const swarmPath = resolveSwarmKnowledgePath(directory);
121452
121736
  await transactKnowledge(swarmPath, applyOne);
121453
121737
  const hivePath = resolveHiveKnowledgePath();
121454
- if (existsSync81(hivePath)) {
121738
+ if (existsSync80(hivePath)) {
121455
121739
  await transactKnowledge(hivePath, applyOne);
121456
121740
  }
121457
121741
  }
@@ -122425,7 +122709,7 @@ init_extractors();
122425
122709
  // src/hooks/phase-directives.ts
122426
122710
  init_knowledge_events();
122427
122711
  init_knowledge_store();
122428
- import { existsSync as existsSync82 } from "node:fs";
122712
+ import { existsSync as existsSync81 } from "node:fs";
122429
122713
  async function collectPhaseDirectiveIds(directory, phaseLabel) {
122430
122714
  const events = await readKnowledgeEvents(directory);
122431
122715
  const ids = new Set;
@@ -122445,7 +122729,7 @@ async function readEntriesById(directory) {
122445
122729
  for (const e of swarm)
122446
122730
  map3.set(e.id, e);
122447
122731
  const hivePath = resolveHiveKnowledgePath();
122448
- if (existsSync82(hivePath)) {
122732
+ if (existsSync81(hivePath)) {
122449
122733
  const hive = await readKnowledge(hivePath);
122450
122734
  for (const e of hive)
122451
122735
  if (!map3.has(e.id))
@@ -124337,7 +124621,7 @@ init_schema();
124337
124621
  // src/services/directive-predicate-runner.ts
124338
124622
  init_bun_compat();
124339
124623
  init_logger();
124340
- import { existsSync as existsSync85 } from "node:fs";
124624
+ import { existsSync as existsSync84 } from "node:fs";
124341
124625
  import * as path153 from "node:path";
124342
124626
  var PREDICATE_TIMEOUT_MS = 15000;
124343
124627
  var TOOL_BINARY_ALLOWLIST = new Set([
@@ -124379,7 +124663,7 @@ function findBinaryInPath(binary) {
124379
124663
  if (!dir)
124380
124664
  continue;
124381
124665
  const candidate = path153.join(dir, exeName);
124382
- if (existsSync85(candidate))
124666
+ if (existsSync84(candidate))
124383
124667
  return candidate;
124384
124668
  }
124385
124669
  return null;
@@ -125454,7 +125738,7 @@ init_zod();
125454
125738
  init_path_security();
125455
125739
  init_create_tool();
125456
125740
  import {
125457
- existsSync as existsSync87,
125741
+ existsSync as existsSync86,
125458
125742
  mkdirSync as mkdirSync40,
125459
125743
  mkdtempSync as mkdtempSync2,
125460
125744
  readFileSync as readFileSync57,
@@ -125817,13 +126101,13 @@ function atomicWriteFileSync2(targetPath, content) {
125817
126101
  writeFileSync26(tempPath, content, "utf-8");
125818
126102
  renameSync29(tempPath, targetPath);
125819
126103
  } finally {
125820
- if (existsSync87(tempPath)) {
126104
+ if (existsSync86(tempPath)) {
125821
126105
  try {
125822
126106
  unlinkSync25(tempPath);
125823
126107
  } catch {}
125824
126108
  }
125825
126109
  const tempDir = path156.dirname(tempPath);
125826
- if (tempDir !== dir && existsSync87(tempDir)) {
126110
+ if (tempDir !== dir && existsSync86(tempDir)) {
125827
126111
  try {
125828
126112
  rmdirSync(tempDir);
125829
126113
  } catch {}
@@ -125900,7 +126184,7 @@ function processFileDiff(fileDiff, targetPath, fullPath, workspace, dryRun, allo
125900
126184
  };
125901
126185
  }
125902
126186
  const parentDir = path156.dirname(fullPath);
125903
- if (!existsSync87(parentDir)) {
126187
+ if (!existsSync86(parentDir)) {
125904
126188
  return {
125905
126189
  file: targetPath,
125906
126190
  status: "error",
@@ -125916,7 +126200,7 @@ function processFileDiff(fileDiff, targetPath, fullPath, workspace, dryRun, allo
125916
126200
  ]
125917
126201
  };
125918
126202
  }
125919
- if (existsSync87(fullPath)) {
126203
+ if (existsSync86(fullPath)) {
125920
126204
  return {
125921
126205
  file: targetPath,
125922
126206
  status: "error",
@@ -125991,7 +126275,7 @@ function processFileDiff(fileDiff, targetPath, fullPath, workspace, dryRun, allo
125991
126275
  ]
125992
126276
  };
125993
126277
  }
125994
- if (!existsSync87(fullPath)) {
126278
+ if (!existsSync86(fullPath)) {
125995
126279
  return {
125996
126280
  file: targetPath,
125997
126281
  status: "error",
@@ -126035,7 +126319,7 @@ function processFileDiff(fileDiff, targetPath, fullPath, workspace, dryRun, allo
126035
126319
  hunksFailed: 0
126036
126320
  };
126037
126321
  }
126038
- if (!existsSync87(fullPath)) {
126322
+ if (!existsSync86(fullPath)) {
126039
126323
  return {
126040
126324
  file: targetPath,
126041
126325
  status: "error",
@@ -126190,7 +126474,7 @@ var swarmApplyPatch = createSwarmTool({
126190
126474
  const dryRun = obj.dryRun ?? false;
126191
126475
  const allowCreates = obj.allowCreates ?? false;
126192
126476
  const allowDeletes = obj.allowDeletes ?? false;
126193
- if (!existsSync87(directory)) {
126477
+ if (!existsSync86(directory)) {
126194
126478
  return JSON.stringify(buildErrorResult("Workspace directory does not exist"), null, 2);
126195
126479
  }
126196
126480
  if (files.length === 0) {
@@ -127383,7 +127667,7 @@ function countCodeLines(content) {
127383
127667
  return lines.length;
127384
127668
  }
127385
127669
  function isTestFile(filePath) {
127386
- const basename18 = path160.basename(filePath);
127670
+ const basename19 = path160.basename(filePath);
127387
127671
  const _ext = path160.extname(filePath).toLowerCase();
127388
127672
  const testPatterns = [
127389
127673
  ".test.",
@@ -127399,7 +127683,7 @@ function isTestFile(filePath) {
127399
127683
  ".spec.jsx"
127400
127684
  ];
127401
127685
  for (const pattern of testPatterns) {
127402
- if (basename18.includes(pattern)) {
127686
+ if (basename19.includes(pattern)) {
127403
127687
  return true;
127404
127688
  }
127405
127689
  }
@@ -128012,7 +128296,7 @@ ${body}`);
128012
128296
  // src/council/council-evidence-writer.ts
128013
128297
  init_zod();
128014
128298
  init_task_file();
128015
- import { appendFileSync as appendFileSync18, existsSync as existsSync92, mkdirSync as mkdirSync42, readFileSync as readFileSync63 } from "node:fs";
128299
+ import { appendFileSync as appendFileSync18, existsSync as existsSync91, mkdirSync as mkdirSync42, readFileSync as readFileSync63 } from "node:fs";
128016
128300
  import { join as join128 } from "node:path";
128017
128301
  var EVIDENCE_DIR2 = ".swarm/evidence";
128018
128302
  var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
@@ -128056,7 +128340,7 @@ async function writeCouncilEvidence(workingDir, synthesis) {
128056
128340
  const filePath = taskEvidencePath(workingDir, synthesis.taskId);
128057
128341
  await _internals90.withTaskEvidenceLock(workingDir, synthesis.taskId, COUNCIL_AGENT_ID, async () => {
128058
128342
  const existingRoot = Object.create(null);
128059
- if (existsSync92(filePath)) {
128343
+ if (existsSync91(filePath)) {
128060
128344
  try {
128061
128345
  const parsed = EvidenceFileSchema.parse(JSON.parse(readFileSync63(filePath, "utf-8")));
128062
128346
  safeAssignOwnProps(existingRoot, parsed);
@@ -128451,7 +128735,7 @@ function buildFinalCouncilFeedback(projectSummary, verdict, vetoedBy, requiredFi
128451
128735
  // src/council/criteria-store.ts
128452
128736
  init_zod();
128453
128737
  init_task_file();
128454
- import { existsSync as existsSync93, mkdirSync as mkdirSync43, readFileSync as readFileSync64 } from "node:fs";
128738
+ import { existsSync as existsSync92, mkdirSync as mkdirSync43, readFileSync as readFileSync64 } from "node:fs";
128455
128739
  import { join as join129 } from "node:path";
128456
128740
  var COUNCIL_DIR = ".swarm/council";
128457
128741
  var CouncilCriteriaSchema = exports_external.object({
@@ -128475,7 +128759,7 @@ async function writeCriteria(workingDir, taskId, criteria) {
128475
128759
  }
128476
128760
  function readCriteria(workingDir, taskId) {
128477
128761
  const filePath = join129(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
128478
- if (!existsSync93(filePath))
128762
+ if (!existsSync92(filePath))
128479
128763
  return null;
128480
128764
  try {
128481
128765
  return CouncilCriteriaSchema.parse(JSON.parse(readFileSync64(filePath, "utf-8")));
@@ -130199,7 +130483,7 @@ init_zod();
130199
130483
  init_utils2();
130200
130484
  import { createHash as createHash19 } from "node:crypto";
130201
130485
  import {
130202
- existsSync as existsSync95,
130486
+ existsSync as existsSync94,
130203
130487
  mkdirSync as mkdirSync44,
130204
130488
  readFileSync as readFileSync67,
130205
130489
  renameSync as renameSync30,
@@ -130250,7 +130534,7 @@ function storeLaneOutput(directory, input, now = Date.now) {
130250
130534
  const absPath = validateSwarmPath(directory, relPath);
130251
130535
  const timestamp = new Date(now()).toISOString();
130252
130536
  try {
130253
- if (existsSync95(absPath)) {
130537
+ if (existsSync94(absPath)) {
130254
130538
  const existing = LaneOutputArtifactSchema.safeParse(JSON.parse(readFileSync67(absPath, "utf-8")));
130255
130539
  if (existing.success && existing.data.digest === digest3) {
130256
130540
  return {
@@ -130304,7 +130588,7 @@ function readLaneOutput(directory, ref) {
130304
130588
  if (!REF_RE.test(ref))
130305
130589
  return null;
130306
130590
  const absPath = validateSwarmPath(directory, laneOutputRelativePath(ref));
130307
- if (!existsSync95(absPath))
130591
+ if (!existsSync94(absPath))
130308
130592
  return null;
130309
130593
  let parsed;
130310
130594
  try {
@@ -130406,7 +130690,7 @@ function writeAtomicJson(absPath, value) {
130406
130690
  if (lastRenameError)
130407
130691
  throw lastRenameError;
130408
130692
  } finally {
130409
- if (existsSync95(tempFile)) {
130693
+ if (existsSync94(tempFile)) {
130410
130694
  try {
130411
130695
  unlinkSync26(tempFile);
130412
130696
  } catch {}
@@ -135442,9 +135726,9 @@ var _internals105 = {
135442
135726
  },
135443
135727
  getTimestamp: () => new Date().toISOString(),
135444
135728
  retireSkillFile: async (filePath) => {
135445
- const { unlink: unlink7 } = await import("node:fs/promises");
135729
+ const { unlink: unlink8 } = await import("node:fs/promises");
135446
135730
  try {
135447
- await unlink7(filePath);
135731
+ await unlink8(filePath);
135448
135732
  return true;
135449
135733
  } catch (err) {
135450
135734
  const error93 = err;
@@ -137188,8 +137472,10 @@ var knowledge_add = createSwarmTool({
137188
137472
  init_zod();
137189
137473
  init_knowledge_events();
137190
137474
  init_knowledge_store();
137475
+ init_skill_generator();
137191
137476
  init_logger();
137192
137477
  init_create_tool();
137478
+ import * as path175 from "node:path";
137193
137479
  var MODES2 = ["archive", "quarantine", "purge"];
137194
137480
  var TIERS = ["swarm", "hive"];
137195
137481
  var knowledge_archive = createSwarmTool({
@@ -137272,6 +137558,44 @@ var knowledge_archive = createSwarmTool({
137272
137558
  } else {
137273
137559
  await recordKnowledgeEvent(directory, tombstone);
137274
137560
  }
137561
+ const allArchivedIds = await getArchivedKnowledgeIds(directory);
137562
+ allArchivedIds.add(id);
137563
+ queueMicrotask(async () => {
137564
+ try {
137565
+ const affectedSkillDirs = await findSkillsBySourceKnowledgeId(directory, id);
137566
+ const staleSkillDirs = await findStaleSkillsBySourceKnowledgeId(directory, allArchivedIds);
137567
+ const allSkillDirs = new Set([
137568
+ ...affectedSkillDirs,
137569
+ ...staleSkillDirs
137570
+ ]);
137571
+ if (allSkillDirs.size === 0)
137572
+ return;
137573
+ const slugSet = new Set;
137574
+ let retiredCount = 0;
137575
+ let staleCount = 0;
137576
+ for (const skillDir of allSkillDirs) {
137577
+ const slug = path175.basename(skillDir);
137578
+ if (slugSet.has(slug))
137579
+ continue;
137580
+ slugSet.add(slug);
137581
+ const result = await retireOrMarkStale(directory, skillDir, allArchivedIds);
137582
+ if (result.action === "retire")
137583
+ retiredCount++;
137584
+ else
137585
+ staleCount++;
137586
+ }
137587
+ const batchEvent = {
137588
+ type: "skill-stale-batch",
137589
+ skillIds: Array.from(slugSet),
137590
+ archivedIds: Array.from(allArchivedIds),
137591
+ retiredCount,
137592
+ staleCount
137593
+ };
137594
+ await recordKnowledgeEvent(directory, batchEvent);
137595
+ } catch (err) {
137596
+ warn(`[knowledge-archive] post-archive skill invalidation failed: ${err instanceof Error ? err.message : String(err)}`);
137597
+ }
137598
+ });
137275
137599
  return JSON.stringify({
137276
137600
  success: true,
137277
137601
  id,
@@ -137288,7 +137612,7 @@ init_zod();
137288
137612
  init_config();
137289
137613
  init_knowledge_store();
137290
137614
  init_create_tool();
137291
- import { existsSync as existsSync101 } from "node:fs";
137615
+ import { existsSync as existsSync100 } from "node:fs";
137292
137616
  var DEFAULT_LIMIT = 10;
137293
137617
  var MAX_LESSON_LENGTH = 200;
137294
137618
  var VALID_CATEGORIES3 = [
@@ -137364,14 +137688,14 @@ function validateLimit(limit) {
137364
137688
  }
137365
137689
  async function readSwarmKnowledge(directory) {
137366
137690
  const swarmPath = resolveSwarmKnowledgePath(directory);
137367
- if (!existsSync101(swarmPath)) {
137691
+ if (!existsSync100(swarmPath)) {
137368
137692
  return [];
137369
137693
  }
137370
137694
  return readKnowledge(swarmPath);
137371
137695
  }
137372
137696
  async function readHiveKnowledge() {
137373
137697
  const hivePath = resolveHiveKnowledgePath();
137374
- if (!existsSync101(hivePath)) {
137698
+ if (!existsSync100(hivePath)) {
137375
137699
  return [];
137376
137700
  }
137377
137701
  return readKnowledge(hivePath);
@@ -137640,7 +137964,7 @@ var knowledge_receipt = createSwarmTool({
137640
137964
  const recordedEventIds = [];
137641
137965
  const emit2 = async (event) => {
137642
137966
  const written = await recordKnowledgeEvent(directory, event);
137643
- if (written)
137967
+ if (written && written.event_id !== undefined)
137644
137968
  recordedEventIds.push(written.event_id);
137645
137969
  };
137646
137970
  for (const item of applied) {
@@ -137706,8 +138030,12 @@ var knowledge_receipt = createSwarmTool({
137706
138030
 
137707
138031
  // src/tools/knowledge-remove.ts
137708
138032
  init_zod();
138033
+ init_knowledge_events();
137709
138034
  init_knowledge_store();
138035
+ init_skill_generator();
138036
+ init_logger();
137710
138037
  init_create_tool();
138038
+ import * as path176 from "node:path";
137711
138039
  var knowledge_remove = createSwarmTool({
137712
138040
  description: "Delete an outdated swarm knowledge entry by ID (swarm tier only — does not affect hive). Promoted entries cannot be deleted. Double-deletion is idempotent — removing a non-existent entry returns a clear message without error.",
137713
138041
  args: {
@@ -137767,6 +138095,44 @@ var knowledge_remove = createSwarmTool({
137767
138095
  message: "entry not found"
137768
138096
  });
137769
138097
  }
138098
+ const allArchivedIds = await getArchivedKnowledgeIds(directory);
138099
+ allArchivedIds.add(id);
138100
+ queueMicrotask(async () => {
138101
+ try {
138102
+ const affectedSkillDirs = await findSkillsBySourceKnowledgeId(directory, id);
138103
+ const staleSkillDirs = await findStaleSkillsBySourceKnowledgeId(directory, allArchivedIds);
138104
+ const allSkillDirs = new Set([
138105
+ ...affectedSkillDirs,
138106
+ ...staleSkillDirs
138107
+ ]);
138108
+ if (allSkillDirs.size === 0)
138109
+ return;
138110
+ const slugSet = new Set;
138111
+ let retiredCount = 0;
138112
+ let staleCount = 0;
138113
+ for (const skillDir of allSkillDirs) {
138114
+ const slug = path176.basename(skillDir);
138115
+ if (slugSet.has(slug))
138116
+ continue;
138117
+ slugSet.add(slug);
138118
+ const result = await retireOrMarkStale(directory, skillDir, allArchivedIds);
138119
+ if (result.action === "retire")
138120
+ retiredCount++;
138121
+ else
138122
+ staleCount++;
138123
+ }
138124
+ const batchEvent = {
138125
+ type: "skill-stale-batch",
138126
+ skillIds: Array.from(slugSet),
138127
+ archivedIds: Array.from(allArchivedIds),
138128
+ retiredCount,
138129
+ staleCount
138130
+ };
138131
+ await recordKnowledgeEvent(directory, batchEvent);
138132
+ } catch (err) {
138133
+ warn(`[knowledge-remove] post-purge skill invalidation failed: ${err instanceof Error ? err.message : String(err)}`);
138134
+ }
138135
+ });
137770
138136
  return JSON.stringify({
137771
138137
  success: true,
137772
138138
  removed: 1,
@@ -137821,10 +138187,10 @@ var lean_turbo_acquire_locks = createSwarmTool({
137821
138187
  init_zod();
137822
138188
  init_constants();
137823
138189
  import * as fs108 from "node:fs";
137824
- import * as path175 from "node:path";
138190
+ import * as path177 from "node:path";
137825
138191
  init_create_tool();
137826
138192
  function readPlanJson2(directory) {
137827
- const planPath = path175.join(directory, ".swarm", "plan.json");
138193
+ const planPath = path177.join(directory, ".swarm", "plan.json");
137828
138194
  if (!fs108.existsSync(planPath)) {
137829
138195
  return null;
137830
138196
  }
@@ -138192,12 +138558,12 @@ var lint_spec = createSwarmTool({
138192
138558
  // src/tools/mutation-test.ts
138193
138559
  init_zod();
138194
138560
  import * as fs109 from "node:fs";
138195
- import * as path177 from "node:path";
138561
+ import * as path179 from "node:path";
138196
138562
 
138197
138563
  // src/mutation/engine.ts
138198
138564
  import { spawnSync as spawnSync13 } from "node:child_process";
138199
138565
  import { unlinkSync as unlinkSync27, writeFileSync as writeFileSync30 } from "node:fs";
138200
- import * as path176 from "node:path";
138566
+ import * as path178 from "node:path";
138201
138567
 
138202
138568
  // src/mutation/equivalence.ts
138203
138569
  function isStaticallyEquivalent(originalCode, mutatedCode) {
@@ -138360,7 +138726,7 @@ function validateTestCommand(testCommand) {
138360
138726
  return "testCommand must not be empty";
138361
138727
  }
138362
138728
  const exe = testCommand[0];
138363
- const base = path176.basename(exe).replace(/\.(exe|cmd|bat)$/i, "");
138729
+ const base = path178.basename(exe).replace(/\.(exe|cmd|bat)$/i, "");
138364
138730
  if (!ALLOWED_TEST_RUNNERS.has(base)) {
138365
138731
  return `testCommand executable '${exe}' is not in the allowed test runner list. Permitted runners: ${[...ALLOWED_TEST_RUNNERS].join(", ")}`;
138366
138732
  }
@@ -138384,7 +138750,7 @@ async function executeMutation(patch, testCommand, testFiles, workingDir) {
138384
138750
  let patchFile;
138385
138751
  try {
138386
138752
  const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
138387
- patchFile = path176.join(workingDir, `.mutation_patch_${safeId2}.diff`);
138753
+ patchFile = path178.join(workingDir, `.mutation_patch_${safeId2}.diff`);
138388
138754
  try {
138389
138755
  writeFileSync30(patchFile, patch.patch);
138390
138756
  } catch (writeErr) {
@@ -138801,7 +139167,7 @@ var mutation_test = createSwarmTool({
138801
139167
  ];
138802
139168
  for (const filePath of uniquePaths) {
138803
139169
  try {
138804
- const resolvedPath = path177.resolve(cwd, filePath);
139170
+ const resolvedPath = path179.resolve(cwd, filePath);
138805
139171
  sourceFiles.set(filePath, fs109.readFileSync(resolvedPath, "utf-8"));
138806
139172
  } catch {}
138807
139173
  }
@@ -138819,8 +139185,8 @@ var mutation_test = createSwarmTool({
138819
139185
 
138820
139186
  // src/tools/parse-lane-candidates.ts
138821
139187
  init_zod();
138822
- import { existsSync as existsSync103 } from "node:fs";
138823
- import * as path179 from "node:path";
139188
+ import { existsSync as existsSync102 } from "node:fs";
139189
+ import * as path181 from "node:path";
138824
139190
 
138825
139191
  // src/background/candidate-parser.ts
138826
139192
  init_zod();
@@ -138831,7 +139197,7 @@ init_utils2();
138831
139197
  var import_proper_lockfile10 = __toESM(require_proper_lockfile(), 1);
138832
139198
  import { createHash as createHash24 } from "node:crypto";
138833
139199
  import { appendFileSync as appendFileSync19, mkdirSync as mkdirSync46 } from "node:fs";
138834
- import * as path178 from "node:path";
139200
+ import * as path180 from "node:path";
138835
139201
  var BATCH_DIGEST_ALGORITHM = "sha256";
138836
139202
  var SidecarEnvelopeSchema = exports_external.object({
138837
139203
  record_type: exports_external.literal("invocation"),
@@ -138986,7 +139352,7 @@ function computeBatchDigest(batchId) {
138986
139352
  return createHash24(BATCH_DIGEST_ALGORITHM).update(batchId).digest("hex");
138987
139353
  }
138988
139354
  function sidecarRelativePath(batchDigest) {
138989
- return path178.join("lane-results", batchDigest, "candidates.jsonl");
139355
+ return path180.join("lane-results", batchDigest, "candidates.jsonl");
138990
139356
  }
138991
139357
  function validateRecord(record3, schema, label) {
138992
139358
  const result = schema.safeParse(record3);
@@ -138995,7 +139361,7 @@ function validateRecord(record3, schema, label) {
138995
139361
  }
138996
139362
  }
138997
139363
  function withLockfile(lockDir, write) {
138998
- const lockPath = path178.join(lockDir, ".lock");
139364
+ const lockPath = path180.join(lockDir, ".lock");
138999
139365
  const lf = import_proper_lockfile10.default;
139000
139366
  const release = lf.lockSync(lockPath, {
139001
139367
  realpath: false
@@ -139014,7 +139380,7 @@ function appendToSidecar(options, batchId, envelope, candidates) {
139014
139380
  for (let i = 0;i < candidates.length; i++) {
139015
139381
  validateRecord(candidates[i], SidecarCandidateSchema, `candidate[${i}]`);
139016
139382
  }
139017
- mkdirSync46(path178.dirname(absPath), { recursive: true });
139383
+ mkdirSync46(path180.dirname(absPath), { recursive: true });
139018
139384
  const sanitizedEnvelope = sanitizeRecord(structuredClone(envelope));
139019
139385
  const sanitizedCandidates = candidates.map((c) => sanitizeRecord(structuredClone(c)));
139020
139386
  const lines = [JSON.stringify(sanitizedEnvelope)];
@@ -139028,7 +139394,7 @@ function appendToSidecar(options, batchId, envelope, candidates) {
139028
139394
  appendFileSync19(absPath, payload, "utf-8");
139029
139395
  };
139030
139396
  if (options.useLockfile) {
139031
- withLockfile(path178.dirname(absPath), doWrite);
139397
+ withLockfile(path180.dirname(absPath), doWrite);
139032
139398
  } else {
139033
139399
  doWrite();
139034
139400
  }
@@ -139487,7 +139853,7 @@ function laneOutputRelativePath2(ref) {
139487
139853
  if (parts.length !== 4)
139488
139854
  return "";
139489
139855
  const [, batchDigest, laneDigest, outputDigest] = parts;
139490
- return path179.join("lane-results", batchDigest, laneDigest, `${outputDigest}.json`);
139856
+ return path181.join("lane-results", batchDigest, laneDigest, `${outputDigest}.json`);
139491
139857
  }
139492
139858
  var parse_lane_candidates = createSwarmTool({
139493
139859
  description: "Parse [CANDIDATE] rows from a dispatch_lanes or collect_lane_results artifact (by output_ref), produce structured records with provenance, optionally persist to a per-batch sidecar JSONL. Pure-parser variant exists as internal module.",
@@ -139522,10 +139888,10 @@ var parse_lane_candidates = createSwarmTool({
139522
139888
  project_root
139523
139889
  } = parsed.data;
139524
139890
  if (project_root !== undefined) {
139525
- const absRoot = path179.resolve(project_root);
139526
- const absDir = path179.resolve(directory);
139527
- const rel = path179.relative(absDir, absRoot);
139528
- if (rel === ".." || rel.startsWith(`..${path179.sep}`) || path179.isAbsolute(rel)) {
139891
+ const absRoot = path181.resolve(project_root);
139892
+ const absDir = path181.resolve(directory);
139893
+ const rel = path181.relative(absDir, absRoot);
139894
+ if (rel === ".." || rel.startsWith(`..${path181.sep}`) || path181.isAbsolute(rel)) {
139529
139895
  return JSON.stringify({
139530
139896
  success: false,
139531
139897
  failure_class: "invalid_args",
@@ -139545,7 +139911,7 @@ var parse_lane_candidates = createSwarmTool({
139545
139911
  if (!loaded) {
139546
139912
  const relPath = REF_RE2.test(output_ref) ? laneOutputRelativePath2(output_ref) : "";
139547
139913
  const absPath = relPath ? validateSwarmPath(directory, relPath) : "";
139548
- const fileExists = absPath ? existsSync103(absPath) : false;
139914
+ const fileExists = absPath ? existsSync102(absPath) : false;
139549
139915
  const artifactStatus = fileExists ? "artifact-corrupted" : "ref-not-found";
139550
139916
  const refParts = output_ref.split(":");
139551
139917
  const hasValidRef = REF_RE2.test(output_ref) && refParts.length === 4;
@@ -139618,22 +139984,22 @@ init_schema();
139618
139984
  init_manager2();
139619
139985
  init_task_file();
139620
139986
  import * as fs119 from "node:fs";
139621
- import * as path189 from "node:path";
139987
+ import * as path191 from "node:path";
139622
139988
 
139623
139989
  // src/full-auto/phase-approval.ts
139624
139990
  init_utils2();
139625
139991
  init_logger();
139626
139992
  init_state3();
139627
139993
  import * as fs110 from "node:fs";
139628
- import * as path180 from "node:path";
139994
+ import * as path182 from "node:path";
139629
139995
  var APPROVAL_TTL_MS = 24 * 60 * 60 * 1000;
139630
139996
  function readEvidenceDir(directory, phase) {
139631
139997
  try {
139632
- const dirPath = validateSwarmPath(directory, path180.posix.join("evidence", String(phase)));
139998
+ const dirPath = validateSwarmPath(directory, path182.posix.join("evidence", String(phase)));
139633
139999
  if (!fs110.existsSync(dirPath))
139634
140000
  return [];
139635
140001
  const entries = fs110.readdirSync(dirPath);
139636
- return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path180.join(dirPath, e));
140002
+ return entries.filter((e) => e.startsWith("full-auto-") && e.endsWith(".json")).map((e) => path182.join(dirPath, e));
139637
140003
  } catch {
139638
140004
  return [];
139639
140005
  }
@@ -139792,7 +140158,13 @@ async function evaluatePhaseCriticalDirectives(params) {
139792
140158
  try {
139793
140159
  const events = await readKnowledgeEvents(params.directory);
139794
140160
  const retrievedThisPhase = events.filter((e) => e.type === "retrieved" && (!params.phaseLabel || e.phase === params.phaseLabel));
139795
- const phaseStart = retrievedThisPhase.length > 0 ? retrievedThisPhase.map((e) => e.timestamp).reduce((a, b) => a < b ? a : b) : null;
140161
+ const phaseStart = retrievedThisPhase.length > 0 ? retrievedThisPhase.map((e) => e.timestamp).reduce((a, b) => {
140162
+ if (b === undefined)
140163
+ return a;
140164
+ if (a === undefined)
140165
+ return b;
140166
+ return a < b ? a : b;
140167
+ }, undefined) : null;
139796
140168
  const criticalIds = await readCriticalIdsForPhase(params.directory, params.phaseLabel);
139797
140169
  if (criticalIds.length === 0) {
139798
140170
  return {
@@ -139802,7 +140174,13 @@ async function evaluatePhaseCriticalDirectives(params) {
139802
140174
  failedClosed: false
139803
140175
  };
139804
140176
  }
139805
- const receipts = events.filter(isReceipt).filter((r) => phaseStart === null || r.timestamp >= phaseStart).map((r) => ({
140177
+ const receipts = events.filter(isReceipt).filter((r) => {
140178
+ if (phaseStart === null || phaseStart === undefined)
140179
+ return true;
140180
+ if (r.timestamp === undefined)
140181
+ return false;
140182
+ return r.timestamp >= phaseStart;
140183
+ }).map((r) => ({
139806
140184
  type: r.type,
139807
140185
  knowledge_id: r.knowledge_id,
139808
140186
  timestamp: r.timestamp,
@@ -139888,16 +140266,16 @@ init_plan_schema();
139888
140266
  init_ledger();
139889
140267
  init_manager();
139890
140268
  import * as fs111 from "node:fs";
139891
- import * as path181 from "node:path";
140269
+ import * as path183 from "node:path";
139892
140270
  async function writeCheckpoint(directory) {
139893
140271
  try {
139894
140272
  const plan = await loadPlan(directory);
139895
140273
  if (!plan)
139896
140274
  return;
139897
- const swarmDir = path181.join(directory, ".swarm");
140275
+ const swarmDir = path183.join(directory, ".swarm");
139898
140276
  fs111.mkdirSync(swarmDir, { recursive: true });
139899
- const jsonPath = path181.join(swarmDir, "SWARM_PLAN.json");
139900
- const mdPath = path181.join(swarmDir, "SWARM_PLAN.md");
140277
+ const jsonPath = path183.join(swarmDir, "SWARM_PLAN.json");
140278
+ const mdPath = path183.join(swarmDir, "SWARM_PLAN.md");
139901
140279
  fs111.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
139902
140280
  const md = derivePlanMarkdown(plan);
139903
140281
  fs111.writeFileSync(mdPath, md, "utf8");
@@ -140402,7 +140780,7 @@ init_state();
140402
140780
  // src/turbo/lean/phase-ready.ts
140403
140781
  init_file_locks();
140404
140782
  import * as fs112 from "node:fs";
140405
- import * as path182 from "node:path";
140783
+ import * as path184 from "node:path";
140406
140784
  init_state4();
140407
140785
  var DEFAULT_CONFIG3 = {
140408
140786
  phase_reviewer: true,
@@ -140411,7 +140789,7 @@ var DEFAULT_CONFIG3 = {
140411
140789
  };
140412
140790
  function defaultReadPlanJson(dir) {
140413
140791
  try {
140414
- const planPath = path182.join(dir, ".swarm", "plan.json");
140792
+ const planPath = path184.join(dir, ".swarm", "plan.json");
140415
140793
  if (!fs112.existsSync(planPath))
140416
140794
  return null;
140417
140795
  const raw = fs112.readFileSync(planPath, "utf-8");
@@ -140426,7 +140804,7 @@ function defaultReadPlanJson(dir) {
140426
140804
  }
140427
140805
  function readReviewerEvidenceFromFile(directory, phase) {
140428
140806
  try {
140429
- const evidencePath = path182.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
140807
+ const evidencePath = path184.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-reviewer.json");
140430
140808
  if (!fs112.existsSync(evidencePath)) {
140431
140809
  return null;
140432
140810
  }
@@ -140446,7 +140824,7 @@ function readReviewerEvidenceFromFile(directory, phase) {
140446
140824
  }
140447
140825
  function readCriticEvidenceFromFile(directory, phase) {
140448
140826
  try {
140449
- const evidencePath = path182.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
140827
+ const evidencePath = path184.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-critic.json");
140450
140828
  if (!fs112.existsSync(evidencePath)) {
140451
140829
  return null;
140452
140830
  }
@@ -140465,7 +140843,7 @@ function readCriticEvidenceFromFile(directory, phase) {
140465
140843
  }
140466
140844
  }
140467
140845
  function listLaneEvidenceSync(directory, phase) {
140468
- const evidenceDir = path182.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
140846
+ const evidenceDir = path184.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
140469
140847
  let entries;
140470
140848
  try {
140471
140849
  entries = fs112.readdirSync(evidenceDir);
@@ -140535,7 +140913,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
140535
140913
  ...DEFAULT_CONFIG3,
140536
140914
  ...actualConfig
140537
140915
  };
140538
- const statePath = path182.join(directory, ".swarm", "turbo-state.json");
140916
+ const statePath = path184.join(directory, ".swarm", "turbo-state.json");
140539
140917
  if (!fs112.existsSync(statePath)) {
140540
140918
  return {
140541
140919
  ok: false,
@@ -140723,7 +141101,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
140723
141101
  }
140724
141102
  }
140725
141103
  if (mergedConfig.integrated_diff_required) {
140726
- const evidencePath = path182.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
141104
+ const evidencePath = path184.join(directory, ".swarm", "evidence", String(phase), "lean-turbo-phase.json");
140727
141105
  let hasDiff = false;
140728
141106
  try {
140729
141107
  const content = fs112.readFileSync(evidencePath, "utf-8");
@@ -140889,7 +141267,7 @@ async function runCompletionVerifyGate(ctx) {
140889
141267
  // src/tools/phase-complete/gates/drift-gate.ts
140890
141268
  init_effective_spec();
140891
141269
  import * as fs113 from "node:fs";
140892
- import * as path183 from "node:path";
141270
+ import * as path185 from "node:path";
140893
141271
 
140894
141272
  // src/tools/phase-complete/gates/gate-helpers.ts
140895
141273
  init_qa_gate_profile();
@@ -140938,7 +141316,7 @@ async function runDriftGate(ctx) {
140938
141316
  }
140939
141317
  let phaseType;
140940
141318
  try {
140941
- const planPath = path183.join(dir, ".swarm", "plan.json");
141319
+ const planPath = path185.join(dir, ".swarm", "plan.json");
140942
141320
  if (fs113.existsSync(planPath)) {
140943
141321
  const planRaw = fs113.readFileSync(planPath, "utf-8");
140944
141322
  const plan = JSON.parse(planRaw);
@@ -140957,7 +141335,7 @@ async function runDriftGate(ctx) {
140957
141335
  };
140958
141336
  }
140959
141337
  try {
140960
- const driftEvidencePath = path183.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
141338
+ const driftEvidencePath = path185.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
140961
141339
  let driftVerdictFound = false;
140962
141340
  let driftVerdictApproved = false;
140963
141341
  try {
@@ -140998,7 +141376,7 @@ async function runDriftGate(ctx) {
140998
141376
  let incompleteTaskCount = 0;
140999
141377
  let planParseable = false;
141000
141378
  try {
141001
- const planPath = path183.join(dir, ".swarm", "plan.json");
141379
+ const planPath = path185.join(dir, ".swarm", "plan.json");
141002
141380
  if (fs113.existsSync(planPath)) {
141003
141381
  const planRaw = fs113.readFileSync(planPath, "utf-8");
141004
141382
  const plan = JSON.parse(planRaw);
@@ -141077,7 +141455,7 @@ async function runDriftGate(ctx) {
141077
141455
  }
141078
141456
  // src/tools/phase-complete/gates/final-council-gate.ts
141079
141457
  import * as fs114 from "node:fs";
141080
- import * as path184 from "node:path";
141458
+ import * as path186 from "node:path";
141081
141459
  async function runFinalCouncilGate(ctx) {
141082
141460
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
141083
141461
  let finalCouncilEnabled = false;
@@ -141100,7 +141478,7 @@ async function runFinalCouncilGate(ctx) {
141100
141478
  if (lastPhaseId !== undefined && phase === lastPhaseId) {
141101
141479
  if (preamble.effectiveGates?.final_council === true) {
141102
141480
  finalCouncilEnabled = true;
141103
- const fcPath = path184.join(dir, ".swarm", "evidence", "final-council.json");
141481
+ const fcPath = path186.join(dir, ".swarm", "evidence", "final-council.json");
141104
141482
  let fcVerdictFound = false;
141105
141483
  let _fcVerdict;
141106
141484
  try {
@@ -141254,13 +141632,13 @@ async function runFinalCouncilGate(ctx) {
141254
141632
  }
141255
141633
  // src/tools/phase-complete/gates/hallucination-gate.ts
141256
141634
  import * as fs115 from "node:fs";
141257
- import * as path185 from "node:path";
141635
+ import * as path187 from "node:path";
141258
141636
  async function runHallucinationGate(ctx) {
141259
141637
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
141260
141638
  try {
141261
141639
  const preamble = await resolveGatePreamble(dir, sessionID);
141262
141640
  if (preamble.resolved && preamble.effectiveGates?.hallucination_guard === true) {
141263
- const hgPath = path185.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
141641
+ const hgPath = path187.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
141264
141642
  let hgVerdictFound = false;
141265
141643
  let hgVerdictApproved = false;
141266
141644
  try {
@@ -141318,13 +141696,13 @@ async function runHallucinationGate(ctx) {
141318
141696
  }
141319
141697
  // src/tools/phase-complete/gates/mutation-gate.ts
141320
141698
  import * as fs116 from "node:fs";
141321
- import * as path186 from "node:path";
141699
+ import * as path188 from "node:path";
141322
141700
  async function runMutationGate(ctx) {
141323
141701
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
141324
141702
  try {
141325
141703
  const preamble = await resolveGatePreamble(dir, sessionID);
141326
141704
  if (preamble.resolved && preamble.effectiveGates?.mutation_test === true) {
141327
- const mgPath = path186.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
141705
+ const mgPath = path188.join(dir, ".swarm", "evidence", String(phase), "mutation-gate.json");
141328
141706
  let mgVerdictFound = false;
141329
141707
  let mgVerdict;
141330
141708
  try {
@@ -141382,7 +141760,7 @@ async function runMutationGate(ctx) {
141382
141760
  }
141383
141761
  // src/tools/phase-complete/gates/phase-council-gate.ts
141384
141762
  import * as fs117 from "node:fs";
141385
- import * as path187 from "node:path";
141763
+ import * as path189 from "node:path";
141386
141764
  async function runPhaseCouncilGate(ctx) {
141387
141765
  const { phase, dir, sessionID, pluginConfig, agentsDispatched, safeWarn } = ctx;
141388
141766
  const gateWarnings = [];
@@ -141391,7 +141769,7 @@ async function runPhaseCouncilGate(ctx) {
141391
141769
  const preamble = await resolveGatePreamble(dir, sessionID);
141392
141770
  if (preamble.resolved && preamble.effectiveGates?.phase_council === true && pluginConfig.council?.enabled === true) {
141393
141771
  councilModeEnabled = true;
141394
- const pcPath = path187.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
141772
+ const pcPath = path189.join(dir, ".swarm", "evidence", String(phase), "phase-council.json");
141395
141773
  let pcVerdictFound = false;
141396
141774
  let _pcVerdict;
141397
141775
  let pcQuorumSize;
@@ -141959,7 +142337,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
141959
142337
  }
141960
142338
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
141961
142339
  try {
141962
- const projectName = path189.basename(dir);
142340
+ const projectName = path191.basename(dir);
141963
142341
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig, {
141964
142342
  llmDelegate: createCuratorLLMDelegate(dir, "phase", sessionID),
141965
142343
  enrichmentQuota: {
@@ -142536,7 +142914,7 @@ init_utils();
142536
142914
  init_bun_compat();
142537
142915
  init_create_tool();
142538
142916
  import * as fs120 from "node:fs";
142539
- import * as path190 from "node:path";
142917
+ import * as path192 from "node:path";
142540
142918
  var MAX_OUTPUT_BYTES7 = 52428800;
142541
142919
  var AUDIT_TIMEOUT_MS = 120000;
142542
142920
  function isValidEcosystem(value) {
@@ -142564,16 +142942,16 @@ function validateArgs3(args2) {
142564
142942
  function detectEcosystems(directory) {
142565
142943
  const ecosystems = [];
142566
142944
  const cwd = directory;
142567
- if (fs120.existsSync(path190.join(cwd, "package.json"))) {
142945
+ if (fs120.existsSync(path192.join(cwd, "package.json"))) {
142568
142946
  ecosystems.push("npm");
142569
142947
  }
142570
- if (fs120.existsSync(path190.join(cwd, "pyproject.toml")) || fs120.existsSync(path190.join(cwd, "requirements.txt"))) {
142948
+ if (fs120.existsSync(path192.join(cwd, "pyproject.toml")) || fs120.existsSync(path192.join(cwd, "requirements.txt"))) {
142571
142949
  ecosystems.push("pip");
142572
142950
  }
142573
- if (fs120.existsSync(path190.join(cwd, "Cargo.toml"))) {
142951
+ if (fs120.existsSync(path192.join(cwd, "Cargo.toml"))) {
142574
142952
  ecosystems.push("cargo");
142575
142953
  }
142576
- if (fs120.existsSync(path190.join(cwd, "go.mod"))) {
142954
+ if (fs120.existsSync(path192.join(cwd, "go.mod"))) {
142577
142955
  ecosystems.push("go");
142578
142956
  }
142579
142957
  try {
@@ -142582,13 +142960,13 @@ function detectEcosystems(directory) {
142582
142960
  ecosystems.push("dotnet");
142583
142961
  }
142584
142962
  } catch {}
142585
- if (fs120.existsSync(path190.join(cwd, "Gemfile")) || fs120.existsSync(path190.join(cwd, "Gemfile.lock"))) {
142963
+ if (fs120.existsSync(path192.join(cwd, "Gemfile")) || fs120.existsSync(path192.join(cwd, "Gemfile.lock"))) {
142586
142964
  ecosystems.push("ruby");
142587
142965
  }
142588
- if (fs120.existsSync(path190.join(cwd, "pubspec.yaml"))) {
142966
+ if (fs120.existsSync(path192.join(cwd, "pubspec.yaml"))) {
142589
142967
  ecosystems.push("dart");
142590
142968
  }
142591
- if (fs120.existsSync(path190.join(cwd, "composer.lock"))) {
142969
+ if (fs120.existsSync(path192.join(cwd, "composer.lock"))) {
142592
142970
  ecosystems.push("composer");
142593
142971
  }
142594
142972
  return ecosystems;
@@ -143725,7 +144103,7 @@ var pkg_audit = createSwarmTool({
143725
144103
  init_zod();
143726
144104
  init_manager2();
143727
144105
  import * as fs121 from "node:fs";
143728
- import * as path191 from "node:path";
144106
+ import * as path193 from "node:path";
143729
144107
  init_utils();
143730
144108
  init_create_tool();
143731
144109
  var MAX_FILE_SIZE = 1024 * 1024;
@@ -143848,7 +144226,7 @@ function isScaffoldFile(filePath) {
143848
144226
  if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
143849
144227
  return true;
143850
144228
  }
143851
- const filename = path191.basename(filePath);
144229
+ const filename = path193.basename(filePath);
143852
144230
  if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
143853
144231
  return true;
143854
144232
  }
@@ -143865,7 +144243,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
143865
144243
  if (regex.test(normalizedPath)) {
143866
144244
  return true;
143867
144245
  }
143868
- const filename = path191.basename(filePath);
144246
+ const filename = path193.basename(filePath);
143869
144247
  const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
143870
144248
  if (filenameRegex.test(filename)) {
143871
144249
  return true;
@@ -143874,7 +144252,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
143874
144252
  return false;
143875
144253
  }
143876
144254
  function isParserSupported(filePath) {
143877
- const ext = path191.extname(filePath).toLowerCase();
144255
+ const ext = path193.extname(filePath).toLowerCase();
143878
144256
  return SUPPORTED_PARSER_EXTENSIONS.has(ext);
143879
144257
  }
143880
144258
  function isPlanFile(filePath) {
@@ -144121,9 +144499,9 @@ async function placeholderScan(input, directory) {
144121
144499
  let filesScanned = 0;
144122
144500
  const filesWithFindings = new Set;
144123
144501
  for (const filePath of changed_files) {
144124
- const fullPath = path191.isAbsolute(filePath) ? filePath : path191.resolve(directory, filePath);
144125
- const resolvedDirectory = path191.resolve(directory);
144126
- if (!fullPath.startsWith(resolvedDirectory + path191.sep) && fullPath !== resolvedDirectory) {
144502
+ const fullPath = path193.isAbsolute(filePath) ? filePath : path193.resolve(directory, filePath);
144503
+ const resolvedDirectory = path193.resolve(directory);
144504
+ if (!fullPath.startsWith(resolvedDirectory + path193.sep) && fullPath !== resolvedDirectory) {
144127
144505
  continue;
144128
144506
  }
144129
144507
  if (!fs121.existsSync(fullPath)) {
@@ -144132,7 +144510,7 @@ async function placeholderScan(input, directory) {
144132
144510
  if (isAllowedByGlobs(filePath, allow_globs)) {
144133
144511
  continue;
144134
144512
  }
144135
- const relativeFilePath = path191.relative(directory, fullPath).replace(/\\/g, "/");
144513
+ const relativeFilePath = path193.relative(directory, fullPath).replace(/\\/g, "/");
144136
144514
  if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
144137
144515
  continue;
144138
144516
  }
@@ -144205,7 +144583,7 @@ var placeholder_scan = createSwarmTool({
144205
144583
 
144206
144584
  // src/tools/pre-check-batch.ts
144207
144585
  import * as fs125 from "node:fs";
144208
- import * as path195 from "node:path";
144586
+ import * as path197 from "node:path";
144209
144587
  init_zod();
144210
144588
  init_manager2();
144211
144589
  init_utils();
@@ -144346,7 +144724,7 @@ init_zod();
144346
144724
  init_manager2();
144347
144725
  init_detector();
144348
144726
  import * as fs124 from "node:fs";
144349
- import * as path194 from "node:path";
144727
+ import * as path196 from "node:path";
144350
144728
  import { extname as extname19 } from "node:path";
144351
144729
 
144352
144730
  // src/sast/rules/c.ts
@@ -145056,7 +145434,7 @@ function executeRulesSync(filePath, content, language) {
145056
145434
  // src/sast/semgrep.ts
145057
145435
  import * as child_process15 from "node:child_process";
145058
145436
  import * as fs122 from "node:fs";
145059
- import * as path192 from "node:path";
145437
+ import * as path194 from "node:path";
145060
145438
  var semgrepAvailableCache = null;
145061
145439
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
145062
145440
  var DEFAULT_TIMEOUT_MS4 = 30000;
@@ -145343,7 +145721,7 @@ async function runSemgrep(options) {
145343
145721
  }
145344
145722
  function getRulesDirectory(projectRoot) {
145345
145723
  if (projectRoot) {
145346
- return path192.resolve(projectRoot, DEFAULT_RULES_DIR);
145724
+ return path194.resolve(projectRoot, DEFAULT_RULES_DIR);
145347
145725
  }
145348
145726
  return DEFAULT_RULES_DIR;
145349
145727
  }
@@ -145364,24 +145742,24 @@ init_create_tool();
145364
145742
  init_utils2();
145365
145743
  import * as crypto13 from "node:crypto";
145366
145744
  import * as fs123 from "node:fs";
145367
- import * as path193 from "node:path";
145745
+ import * as path195 from "node:path";
145368
145746
  var BASELINE_SCHEMA_VERSION = "1.0.0";
145369
145747
  var MAX_BASELINE_FINDINGS = 2000;
145370
145748
  var MAX_BASELINE_BYTES = 2 * 1048576;
145371
145749
  var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
145372
145750
  function normalizeFindingPath(directory, file3) {
145373
- const resolved = path193.isAbsolute(file3) ? file3 : path193.resolve(directory, file3);
145374
- const rel = path193.relative(path193.resolve(directory), resolved);
145751
+ const resolved = path195.isAbsolute(file3) ? file3 : path195.resolve(directory, file3);
145752
+ const rel = path195.relative(path195.resolve(directory), resolved);
145375
145753
  return rel.replace(/\\/g, "/");
145376
145754
  }
145377
145755
  function baselineRelPath(phase) {
145378
- return path193.join("evidence", String(phase), "sast-baseline.json");
145756
+ return path195.join("evidence", String(phase), "sast-baseline.json");
145379
145757
  }
145380
145758
  function tempRelPath(phase) {
145381
- return path193.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
145759
+ return path195.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
145382
145760
  }
145383
145761
  function lockRelPath(phase) {
145384
- return path193.join("evidence", String(phase), "sast-baseline.json.lock");
145762
+ return path195.join("evidence", String(phase), "sast-baseline.json.lock");
145385
145763
  }
145386
145764
  function getLine(lines, idx) {
145387
145765
  if (idx < 0 || idx >= lines.length)
@@ -145502,8 +145880,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
145502
145880
  message: e instanceof Error ? e.message : "Path validation failed"
145503
145881
  };
145504
145882
  }
145505
- fs123.mkdirSync(path193.dirname(baselinePath), { recursive: true });
145506
- fs123.mkdirSync(path193.dirname(tempPath), { recursive: true });
145883
+ fs123.mkdirSync(path195.dirname(baselinePath), { recursive: true });
145884
+ fs123.mkdirSync(path195.dirname(tempPath), { recursive: true });
145507
145885
  const releaseLock = await acquireLock2(lockPath);
145508
145886
  try {
145509
145887
  let existing = null;
@@ -145776,9 +146154,9 @@ async function sastScan(input, directory, config3) {
145776
146154
  _filesSkipped++;
145777
146155
  continue;
145778
146156
  }
145779
- const resolvedPath = path194.isAbsolute(filePath) ? filePath : path194.resolve(directory, filePath);
145780
- const resolvedDirectory = path194.resolve(directory);
145781
- if (!resolvedPath.startsWith(resolvedDirectory + path194.sep) && resolvedPath !== resolvedDirectory) {
146157
+ const resolvedPath = path196.isAbsolute(filePath) ? filePath : path196.resolve(directory, filePath);
146158
+ const resolvedDirectory = path196.resolve(directory);
146159
+ if (!resolvedPath.startsWith(resolvedDirectory + path196.sep) && resolvedPath !== resolvedDirectory) {
145782
146160
  _filesSkipped++;
145783
146161
  continue;
145784
146162
  }
@@ -146093,18 +146471,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
146093
146471
  let resolved;
146094
146472
  const isWinAbs = isWindowsAbsolutePath(inputPath);
146095
146473
  if (isWinAbs) {
146096
- resolved = path195.win32.resolve(inputPath);
146097
- } else if (path195.isAbsolute(inputPath)) {
146098
- resolved = path195.resolve(inputPath);
146474
+ resolved = path197.win32.resolve(inputPath);
146475
+ } else if (path197.isAbsolute(inputPath)) {
146476
+ resolved = path197.resolve(inputPath);
146099
146477
  } else {
146100
- resolved = path195.resolve(baseDir, inputPath);
146478
+ resolved = path197.resolve(baseDir, inputPath);
146101
146479
  }
146102
- const workspaceResolved = path195.resolve(workspaceDir);
146480
+ const workspaceResolved = path197.resolve(workspaceDir);
146103
146481
  let relative38;
146104
146482
  if (isWinAbs) {
146105
- relative38 = path195.win32.relative(workspaceResolved, resolved);
146483
+ relative38 = path197.win32.relative(workspaceResolved, resolved);
146106
146484
  } else {
146107
- relative38 = path195.relative(workspaceResolved, resolved);
146485
+ relative38 = path197.relative(workspaceResolved, resolved);
146108
146486
  }
146109
146487
  if (relative38.startsWith("..")) {
146110
146488
  return "path traversal detected";
@@ -146169,7 +146547,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
146169
146547
  if (typeof file3 !== "string") {
146170
146548
  continue;
146171
146549
  }
146172
- const resolvedPath = path195.resolve(file3);
146550
+ const resolvedPath = path197.resolve(file3);
146173
146551
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
146174
146552
  if (validationError) {
146175
146553
  continue;
@@ -146326,7 +146704,7 @@ async function runSecretscanWithFiles(files, directory) {
146326
146704
  skippedFiles++;
146327
146705
  continue;
146328
146706
  }
146329
- const resolvedPath = path195.resolve(file3);
146707
+ const resolvedPath = path197.resolve(file3);
146330
146708
  const validationError = validatePath(resolvedPath, directory, directory);
146331
146709
  if (validationError) {
146332
146710
  skippedFiles++;
@@ -146344,7 +146722,7 @@ async function runSecretscanWithFiles(files, directory) {
146344
146722
  };
146345
146723
  }
146346
146724
  for (const file3 of validatedFiles) {
146347
- const ext = path195.extname(file3).toLowerCase();
146725
+ const ext = path197.extname(file3).toLowerCase();
146348
146726
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
146349
146727
  skippedFiles++;
146350
146728
  continue;
@@ -146563,7 +146941,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
146563
146941
  const preexistingFindings = [];
146564
146942
  for (const finding of findings) {
146565
146943
  const filePath = finding.location.file;
146566
- const normalised = path195.relative(directory, filePath).replace(/\\/g, "/");
146944
+ const normalised = path197.relative(directory, filePath).replace(/\\/g, "/");
146567
146945
  const changedLines = changedLineRanges.get(normalised);
146568
146946
  if (changedLines?.has(finding.location.line)) {
146569
146947
  newFindings.push(finding);
@@ -146614,7 +146992,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
146614
146992
  warn(`pre_check_batch: Invalid file path: ${file3}`);
146615
146993
  continue;
146616
146994
  }
146617
- changedFiles.push(path195.resolve(directory, file3));
146995
+ changedFiles.push(path197.resolve(directory, file3));
146618
146996
  }
146619
146997
  if (changedFiles.length === 0) {
146620
146998
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -146815,9 +147193,9 @@ var pre_check_batch = createSwarmTool({
146815
147193
  };
146816
147194
  return JSON.stringify(errorResult, null, 2);
146817
147195
  }
146818
- const resolvedDirectory = path195.resolve(typedArgs.directory);
146819
- const workspaceAnchor = path195.resolve(directory);
146820
- if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor + path195.sep)) {
147196
+ const resolvedDirectory = path197.resolve(typedArgs.directory);
147197
+ const workspaceAnchor = path197.resolve(directory);
147198
+ if (resolvedDirectory !== workspaceAnchor && resolvedDirectory.startsWith(workspaceAnchor + path197.sep)) {
146821
147199
  const subDirError = `directory "${typedArgs.directory}" is a subdirectory of the project root — pre_check_batch requires the project root directory "${workspaceAnchor}"`;
146822
147200
  const subDirResult = {
146823
147201
  gates_passed: false,
@@ -146871,7 +147249,7 @@ var pre_check_batch = createSwarmTool({
146871
147249
  init_zod();
146872
147250
  init_path_security();
146873
147251
  init_create_tool();
146874
- import * as path196 from "node:path";
147252
+ import * as path198 from "node:path";
146875
147253
  var VALID_ACTIONS = [
146876
147254
  "build",
146877
147255
  "importers",
@@ -146900,7 +147278,7 @@ function validateFile(p) {
146900
147278
  return "file contains control characters";
146901
147279
  if (containsPathTraversal(p))
146902
147280
  return "file contains path traversal";
146903
- if (path196.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
147281
+ if (path198.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
146904
147282
  return "file must be a workspace-relative path, not absolute";
146905
147283
  }
146906
147284
  return null;
@@ -146923,8 +147301,8 @@ function ok(action, payload) {
146923
147301
  }
146924
147302
  function toRelativeGraphPath(input, workspaceRoot) {
146925
147303
  const normalized = input.replace(/\\/g, "/");
146926
- if (path196.isAbsolute(normalized)) {
146927
- const rel = path196.relative(workspaceRoot, normalized).replace(/\\/g, "/");
147304
+ if (path198.isAbsolute(normalized)) {
147305
+ const rel = path198.relative(workspaceRoot, normalized).replace(/\\/g, "/");
146928
147306
  return normalizeGraphPath(rel);
146929
147307
  }
146930
147308
  return normalizeGraphPath(normalized);
@@ -147120,10 +147498,10 @@ var repo_map = createSwarmTool({
147120
147498
  maxTokens: 4000
147121
147499
  });
147122
147500
  const toRel = (p) => {
147123
- if (!path196.isAbsolute(p))
147501
+ if (!path198.isAbsolute(p))
147124
147502
  return p.replace(/\\/g, "/");
147125
147503
  try {
147126
- return path196.relative(directory, p).replace(/\\/g, "/");
147504
+ return path198.relative(directory, p).replace(/\\/g, "/");
147127
147505
  } catch {
147128
147506
  return p;
147129
147507
  }
@@ -147173,7 +147551,7 @@ init_zod();
147173
147551
  init_effective_spec();
147174
147552
  init_create_tool();
147175
147553
  import * as fs126 from "node:fs";
147176
- import * as path197 from "node:path";
147554
+ import * as path199 from "node:path";
147177
147555
  var EVIDENCE_DIR4 = ".swarm/evidence";
147178
147556
  var OBLIGATION_KEYWORDS2 = ["MUST", "SHOULD", "SHALL"];
147179
147557
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
@@ -147241,7 +147619,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
147241
147619
  return [];
147242
147620
  }
147243
147621
  for (const entry of entries) {
147244
- const entryPath = path197.join(evidenceDir, entry);
147622
+ const entryPath = path199.join(evidenceDir, entry);
147245
147623
  try {
147246
147624
  const stat14 = fs126.statSync(entryPath);
147247
147625
  if (!stat14.isDirectory()) {
@@ -147257,11 +147635,11 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
147257
147635
  if (entryPhase !== String(phase)) {
147258
147636
  continue;
147259
147637
  }
147260
- const evidenceFilePath = path197.join(entryPath, "evidence.json");
147638
+ const evidenceFilePath = path199.join(entryPath, "evidence.json");
147261
147639
  try {
147262
- const resolvedPath = path197.resolve(evidenceFilePath);
147263
- const evidenceDirResolved = path197.resolve(evidenceDir);
147264
- if (!resolvedPath.startsWith(evidenceDirResolved + path197.sep)) {
147640
+ const resolvedPath = path199.resolve(evidenceFilePath);
147641
+ const evidenceDirResolved = path199.resolve(evidenceDir);
147642
+ if (!resolvedPath.startsWith(evidenceDirResolved + path199.sep)) {
147265
147643
  continue;
147266
147644
  }
147267
147645
  const stat14 = fs126.lstatSync(evidenceFilePath);
@@ -147295,7 +147673,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
147295
147673
  if (Array.isArray(diffEntry.files_changed)) {
147296
147674
  for (const file3 of diffEntry.files_changed) {
147297
147675
  if (typeof file3 === "string") {
147298
- touchedFiles.add(path197.resolve(cwd, file3));
147676
+ touchedFiles.add(path199.resolve(cwd, file3));
147299
147677
  }
147300
147678
  }
147301
147679
  }
@@ -147308,8 +147686,8 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
147308
147686
  }
147309
147687
  function searchFileForKeywords(filePath, keywords, cwd) {
147310
147688
  try {
147311
- const resolvedPath = path197.resolve(filePath);
147312
- const cwdResolved = path197.resolve(cwd);
147689
+ const resolvedPath = path199.resolve(filePath);
147690
+ const cwdResolved = path199.resolve(cwd);
147313
147691
  if (!resolvedPath.startsWith(cwdResolved)) {
147314
147692
  return false;
147315
147693
  }
@@ -147468,7 +147846,7 @@ var req_coverage = createSwarmTool({
147468
147846
  message: "No FR requirements found in spec.md"
147469
147847
  }, null, 2);
147470
147848
  }
147471
- const evidenceDir = path197.join(cwd, EVIDENCE_DIR4);
147849
+ const evidenceDir = path199.join(cwd, EVIDENCE_DIR4);
147472
147850
  const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
147473
147851
  const analyzedRequirements = [];
147474
147852
  let coveredCount = 0;
@@ -147494,7 +147872,7 @@ var req_coverage = createSwarmTool({
147494
147872
  requirements: analyzedRequirements
147495
147873
  };
147496
147874
  const reportFilename = `req-coverage-phase-${phase}.json`;
147497
- const reportPath = path197.join(evidenceDir, reportFilename);
147875
+ const reportPath = path199.join(evidenceDir, reportFilename);
147498
147876
  try {
147499
147877
  if (!fs126.existsSync(evidenceDir)) {
147500
147878
  fs126.mkdirSync(evidenceDir, { recursive: true });
@@ -147649,7 +148027,7 @@ init_plan_schema();
147649
148027
  init_qa_gate_profile();
147650
148028
  init_file_locks();
147651
148029
  import * as fs127 from "node:fs";
147652
- import * as path198 from "node:path";
148030
+ import * as path200 from "node:path";
147653
148031
  init_ledger();
147654
148032
  init_manager();
147655
148033
  init_effective_spec();
@@ -147731,8 +148109,8 @@ async function executeSavePlan(args2, fallbackDir) {
147731
148109
  };
147732
148110
  }
147733
148111
  if (args2.working_directory && fallbackDir) {
147734
- const resolvedTarget = path198.resolve(args2.working_directory);
147735
- const resolvedRoot = path198.resolve(fallbackDir);
148112
+ const resolvedTarget = path200.resolve(args2.working_directory);
148113
+ const resolvedRoot = path200.resolve(fallbackDir);
147736
148114
  let fallbackExists = false;
147737
148115
  try {
147738
148116
  fs127.accessSync(resolvedRoot, fs127.constants.F_OK);
@@ -147741,7 +148119,7 @@ async function executeSavePlan(args2, fallbackDir) {
147741
148119
  fallbackExists = false;
147742
148120
  }
147743
148121
  if (fallbackExists) {
147744
- const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path198.sep);
148122
+ const isSubdirectory = resolvedTarget.startsWith(resolvedRoot + path200.sep);
147745
148123
  if (isSubdirectory) {
147746
148124
  return {
147747
148125
  success: false,
@@ -147772,7 +148150,7 @@ async function executeSavePlan(args2, fallbackDir) {
147772
148150
  specHash = spec.hash;
147773
148151
  }
147774
148152
  if (process.env.SWARM_SKIP_GATE_SELECTION !== "1") {
147775
- const contextPath = path198.join(targetWorkspace, ".swarm", "context.md");
148153
+ const contextPath = path200.join(targetWorkspace, ".swarm", "context.md");
147776
148154
  let contextContent = "";
147777
148155
  try {
147778
148156
  contextContent = await fs127.promises.readFile(contextPath, "utf8");
@@ -148062,7 +148440,7 @@ async function executeSavePlan(args2, fallbackDir) {
148062
148440
  }
148063
148441
  await writeCheckpoint(dir).catch(() => {});
148064
148442
  try {
148065
- const markerPath = path198.join(dir, ".swarm", ".plan-write-marker");
148443
+ const markerPath = path200.join(dir, ".swarm", ".plan-write-marker");
148066
148444
  const marker = JSON.stringify({
148067
148445
  source: "save_plan",
148068
148446
  timestamp: new Date().toISOString(),
@@ -148085,7 +148463,7 @@ async function executeSavePlan(args2, fallbackDir) {
148085
148463
  return {
148086
148464
  success: true,
148087
148465
  message: "Plan saved successfully",
148088
- plan_path: path198.join(dir, ".swarm", "plan.json"),
148466
+ plan_path: path200.join(dir, ".swarm", "plan.json"),
148089
148467
  phases_count: plan.phases.length,
148090
148468
  tasks_count: tasksCount,
148091
148469
  ...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
@@ -148138,8 +148516,8 @@ var save_plan = createSwarmTool({
148138
148516
  confirm_identity_change: exports_external.boolean().optional().describe("When true, allows overwriting an existing plan that has a different " + "identity (swarm_id + title). Without this flag, save_plan rejects " + "with PLAN_IDENTITY_MISMATCH if the identity differs."),
148139
148517
  execution_profile: exports_external.object({
148140
148518
  parallelization_enabled: exports_external.boolean().optional().describe("When true, enables parallel task dispatch for this plan. Default false (serial)."),
148141
- max_concurrent_tasks: exports_external.number().int().min(1).max(64).optional().describe("Maximum tasks that may run concurrently when parallelization is enabled. Default 1."),
148142
- council_parallel: exports_external.boolean().optional().describe("When true, council review phases may run in parallel. Default false."),
148519
+ max_concurrent_tasks: exports_external.number().int().min(1).max(64).optional().describe("Maximum tasks that may run concurrently when parallelization is enabled. Default 10."),
148520
+ council_parallel: exports_external.boolean().optional().describe("When true, council review phases may run in parallel. Default true."),
148143
148521
  locked: exports_external.boolean().optional().describe("When true, locks the profile — future save_plan calls that include " + "execution_profile will be rejected (fail-closed). " + "Unlock by resetting the plan (reset_statuses: true)."),
148144
148522
  auto_proceed: exports_external.boolean().optional().describe("When true, the architect advances to the next phase automatically without asking for confirmation. Default false.")
148145
148523
  }).optional().describe("Architect-facing concurrency controls. Once locked, cannot be changed without resetting. " + "Omit to preserve the existing profile.")
@@ -148153,7 +148531,7 @@ var save_plan = createSwarmTool({
148153
148531
  init_zod();
148154
148532
  init_manager2();
148155
148533
  import * as fs128 from "node:fs";
148156
- import * as path199 from "node:path";
148534
+ import * as path201 from "node:path";
148157
148535
 
148158
148536
  // src/sbom/detectors/index.ts
148159
148537
  init_utils();
@@ -149003,7 +149381,7 @@ function findManifestFiles(rootDir) {
149003
149381
  try {
149004
149382
  const entries = fs128.readdirSync(dir, { withFileTypes: true });
149005
149383
  for (const entry of entries) {
149006
- const fullPath = path199.join(dir, entry.name);
149384
+ const fullPath = path201.join(dir, entry.name);
149007
149385
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
149008
149386
  continue;
149009
149387
  }
@@ -149012,7 +149390,7 @@ function findManifestFiles(rootDir) {
149012
149390
  } else if (entry.isFile()) {
149013
149391
  for (const pattern of patterns) {
149014
149392
  if (simpleGlobToRegex(pattern).test(entry.name)) {
149015
- manifestFiles.push(path199.relative(rootDir, fullPath));
149393
+ manifestFiles.push(path201.relative(rootDir, fullPath));
149016
149394
  break;
149017
149395
  }
149018
149396
  }
@@ -149030,11 +149408,11 @@ function findManifestFilesInDirs(directories, workingDir) {
149030
149408
  try {
149031
149409
  const entries = fs128.readdirSync(dir, { withFileTypes: true });
149032
149410
  for (const entry of entries) {
149033
- const fullPath = path199.join(dir, entry.name);
149411
+ const fullPath = path201.join(dir, entry.name);
149034
149412
  if (entry.isFile()) {
149035
149413
  for (const pattern of patterns) {
149036
149414
  if (simpleGlobToRegex(pattern).test(entry.name)) {
149037
- found.push(path199.relative(workingDir, fullPath));
149415
+ found.push(path201.relative(workingDir, fullPath));
149038
149416
  break;
149039
149417
  }
149040
149418
  }
@@ -149047,11 +149425,11 @@ function findManifestFilesInDirs(directories, workingDir) {
149047
149425
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
149048
149426
  const dirs = new Set;
149049
149427
  for (const file3 of changedFiles) {
149050
- let currentDir = path199.dirname(file3);
149428
+ let currentDir = path201.dirname(file3);
149051
149429
  while (true) {
149052
- if (currentDir && currentDir !== "." && currentDir !== path199.sep) {
149053
- dirs.add(path199.join(workingDir, currentDir));
149054
- const parent = path199.dirname(currentDir);
149430
+ if (currentDir && currentDir !== "." && currentDir !== path201.sep) {
149431
+ dirs.add(path201.join(workingDir, currentDir));
149432
+ const parent = path201.dirname(currentDir);
149055
149433
  if (parent === currentDir)
149056
149434
  break;
149057
149435
  currentDir = parent;
@@ -149135,7 +149513,7 @@ var sbom_generate = createSwarmTool({
149135
149513
  const changedFiles = obj.changed_files;
149136
149514
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
149137
149515
  const workingDir = directory;
149138
- const outputDir = path199.isAbsolute(relativeOutputDir) ? relativeOutputDir : path199.join(workingDir, relativeOutputDir);
149516
+ const outputDir = path201.isAbsolute(relativeOutputDir) ? relativeOutputDir : path201.join(workingDir, relativeOutputDir);
149139
149517
  let manifestFiles = [];
149140
149518
  if (scope === "all") {
149141
149519
  manifestFiles = findManifestFiles(workingDir);
@@ -149158,7 +149536,7 @@ var sbom_generate = createSwarmTool({
149158
149536
  const processedFiles = [];
149159
149537
  for (const manifestFile of manifestFiles) {
149160
149538
  try {
149161
- const fullPath = path199.isAbsolute(manifestFile) ? manifestFile : path199.join(workingDir, manifestFile);
149539
+ const fullPath = path201.isAbsolute(manifestFile) ? manifestFile : path201.join(workingDir, manifestFile);
149162
149540
  if (!fs128.existsSync(fullPath)) {
149163
149541
  continue;
149164
149542
  }
@@ -149175,7 +149553,7 @@ var sbom_generate = createSwarmTool({
149175
149553
  const bom = generateCycloneDX(allComponents);
149176
149554
  const bomJson = serializeCycloneDX(bom);
149177
149555
  const filename = generateSbomFilename();
149178
- const outputPath = path199.join(outputDir, filename);
149556
+ const outputPath = path201.join(outputDir, filename);
149179
149557
  fs128.writeFileSync(outputPath, bomJson, "utf-8");
149180
149558
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
149181
149559
  try {
@@ -149220,7 +149598,7 @@ var sbom_generate = createSwarmTool({
149220
149598
  init_zod();
149221
149599
  init_create_tool();
149222
149600
  import * as fs129 from "node:fs";
149223
- import * as path200 from "node:path";
149601
+ import * as path202 from "node:path";
149224
149602
  var SPEC_CANDIDATES = [
149225
149603
  "openapi.json",
149226
149604
  "openapi.yaml",
@@ -149252,12 +149630,12 @@ function normalizePath5(p) {
149252
149630
  }
149253
149631
  function discoverSpecFile(cwd, specFileArg) {
149254
149632
  if (specFileArg) {
149255
- const resolvedPath = path200.resolve(cwd, specFileArg);
149256
- const normalizedCwd = cwd.endsWith(path200.sep) ? cwd : cwd + path200.sep;
149633
+ const resolvedPath = path202.resolve(cwd, specFileArg);
149634
+ const normalizedCwd = cwd.endsWith(path202.sep) ? cwd : cwd + path202.sep;
149257
149635
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
149258
149636
  throw new Error("Invalid spec_file: path traversal detected");
149259
149637
  }
149260
- const ext = path200.extname(resolvedPath).toLowerCase();
149638
+ const ext = path202.extname(resolvedPath).toLowerCase();
149261
149639
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
149262
149640
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
149263
149641
  }
@@ -149271,7 +149649,7 @@ function discoverSpecFile(cwd, specFileArg) {
149271
149649
  return resolvedPath;
149272
149650
  }
149273
149651
  for (const candidate of SPEC_CANDIDATES) {
149274
- const candidatePath = path200.resolve(cwd, candidate);
149652
+ const candidatePath = path202.resolve(cwd, candidate);
149275
149653
  if (fs129.existsSync(candidatePath)) {
149276
149654
  const stats2 = fs129.statSync(candidatePath);
149277
149655
  if (stats2.size <= MAX_SPEC_SIZE) {
@@ -149283,7 +149661,7 @@ function discoverSpecFile(cwd, specFileArg) {
149283
149661
  }
149284
149662
  function parseSpec(specFile) {
149285
149663
  const content = fs129.readFileSync(specFile, "utf-8");
149286
- const ext = path200.extname(specFile).toLowerCase();
149664
+ const ext = path202.extname(specFile).toLowerCase();
149287
149665
  if (ext === ".json") {
149288
149666
  return parseJsonSpec(content);
149289
149667
  }
@@ -149359,7 +149737,7 @@ function extractRoutes2(cwd) {
149359
149737
  return;
149360
149738
  }
149361
149739
  for (const entry of entries) {
149362
- const fullPath = path200.join(dir, entry.name);
149740
+ const fullPath = path202.join(dir, entry.name);
149363
149741
  if (entry.isSymbolicLink()) {
149364
149742
  continue;
149365
149743
  }
@@ -149369,7 +149747,7 @@ function extractRoutes2(cwd) {
149369
149747
  }
149370
149748
  walkDir2(fullPath);
149371
149749
  } else if (entry.isFile()) {
149372
- const ext = path200.extname(entry.name).toLowerCase();
149750
+ const ext = path202.extname(entry.name).toLowerCase();
149373
149751
  const baseName = entry.name.toLowerCase();
149374
149752
  if (![".ts", ".js", ".mjs"].includes(ext)) {
149375
149753
  continue;
@@ -149538,7 +149916,7 @@ init_bun_compat();
149538
149916
  init_path_security();
149539
149917
  init_create_tool();
149540
149918
  import * as fs130 from "node:fs";
149541
- import * as path201 from "node:path";
149919
+ import * as path203 from "node:path";
149542
149920
  var DEFAULT_MAX_RESULTS = 100;
149543
149921
  var DEFAULT_MAX_LINES = 200;
149544
149922
  var REGEX_TIMEOUT_MS = 5000;
@@ -149574,11 +149952,11 @@ function containsWindowsAttacks4(str) {
149574
149952
  }
149575
149953
  function isPathInWorkspace3(filePath, workspace) {
149576
149954
  try {
149577
- const resolvedPath = path201.resolve(workspace, filePath);
149955
+ const resolvedPath = path203.resolve(workspace, filePath);
149578
149956
  const realWorkspace = fs130.realpathSync(workspace);
149579
149957
  const realResolvedPath = fs130.realpathSync(resolvedPath);
149580
- const relativePath = path201.relative(realWorkspace, realResolvedPath);
149581
- if (relativePath.startsWith("..") || path201.isAbsolute(relativePath)) {
149958
+ const relativePath = path203.relative(realWorkspace, realResolvedPath);
149959
+ if (relativePath.startsWith("..") || path203.isAbsolute(relativePath)) {
149582
149960
  return false;
149583
149961
  }
149584
149962
  return true;
@@ -149591,11 +149969,11 @@ function validatePathForRead2(filePath, workspace) {
149591
149969
  }
149592
149970
  function findRgInEnvPath() {
149593
149971
  const searchPath = process.env.PATH ?? "";
149594
- for (const dir of searchPath.split(path201.delimiter)) {
149972
+ for (const dir of searchPath.split(path203.delimiter)) {
149595
149973
  if (!dir)
149596
149974
  continue;
149597
149975
  const isWindows = process.platform === "win32";
149598
- const candidate = path201.join(dir, isWindows ? "rg.exe" : "rg");
149976
+ const candidate = path203.join(dir, isWindows ? "rg.exe" : "rg");
149599
149977
  if (fs130.existsSync(candidate))
149600
149978
  return candidate;
149601
149979
  }
@@ -149725,8 +150103,8 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
149725
150103
  try {
149726
150104
  const entries = fs130.readdirSync(dir, { withFileTypes: true });
149727
150105
  for (const entry of entries) {
149728
- const fullPath = path201.join(dir, entry.name);
149729
- const relativePath = path201.relative(workspace, fullPath);
150106
+ const fullPath = path203.join(dir, entry.name);
150107
+ const relativePath = path203.relative(workspace, fullPath);
149730
150108
  if (!validatePathForRead2(fullPath, workspace)) {
149731
150109
  continue;
149732
150110
  }
@@ -149767,7 +150145,7 @@ async function fallbackSearch(opts) {
149767
150145
  const matches = [];
149768
150146
  let total = 0;
149769
150147
  for (const file3 of files) {
149770
- const fullPath = path201.join(opts.workspace, file3);
150148
+ const fullPath = path203.join(opts.workspace, file3);
149771
150149
  if (!validatePathForRead2(fullPath, opts.workspace)) {
149772
150150
  continue;
149773
150151
  }
@@ -150199,7 +150577,7 @@ init_config();
150199
150577
  init_schema();
150200
150578
  init_create_tool();
150201
150579
  import { mkdir as mkdir34, rename as rename14, writeFile as writeFile23 } from "node:fs/promises";
150202
- import * as path202 from "node:path";
150580
+ import * as path204 from "node:path";
150203
150581
  var MAX_SPEC_BYTES2 = 256 * 1024;
150204
150582
  var spec_write = createSwarmTool({
150205
150583
  description: "Write the canonical project spec to .swarm/spec.md. Atomic write, size-bounded (256 KiB), heading-required. Honors spec_writer.allow_spec_write.",
@@ -150240,8 +150618,8 @@ var spec_write = createSwarmTool({
150240
150618
  reason: 'spec must contain at least one top-level "# Heading"'
150241
150619
  }, null, 2);
150242
150620
  }
150243
- const target = path202.join(directory, ".swarm", "spec.md");
150244
- await mkdir34(path202.dirname(target), { recursive: true });
150621
+ const target = path204.join(directory, ".swarm", "spec.md");
150622
+ await mkdir34(path204.dirname(target), { recursive: true });
150245
150623
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
150246
150624
  let finalContent = content;
150247
150625
  if (mode === "append") {
@@ -150266,6 +150644,120 @@ ${content}
150266
150644
  }
150267
150645
  });
150268
150646
 
150647
+ // src/tools/stale-reconciliation.ts
150648
+ init_zod();
150649
+ init_knowledge_store();
150650
+ init_skill_generator();
150651
+ init_create_tool();
150652
+ import { existsSync as existsSync115 } from "node:fs";
150653
+ import { readdir as readdir12, readFile as readFile33 } from "node:fs/promises";
150654
+ import { join as join163 } from "node:path";
150655
+ var run_stale_reconciliation = createSwarmTool({
150656
+ description: "Reconcile skills against the knowledge store. clear=false: mark skills stale when source knowledge is archived or deleted. clear=true: clear stale.marker on affected active skills (proposal files under .swarm/skills/proposals are scanned but not modified — they are drafts, not yet active skills).",
150657
+ args: {
150658
+ clear: exports_external.boolean().optional().default(false).describe("If true, clear stale markers for affected skills. If false (default), mark affected skills stale.")
150659
+ },
150660
+ execute: async (args2, directory) => {
150661
+ if (typeof directory !== "string" || !directory) {
150662
+ return JSON.stringify({ found: 0, skills: [] }, null, 2);
150663
+ }
150664
+ const archivedIds = await _internals116.getArchivedKnowledgeIds(directory);
150665
+ const archivedSet = new Set(archivedIds);
150666
+ const allKnownIds = new Set;
150667
+ const swarmPath = _internals116.resolveSwarmKnowledgePath(directory);
150668
+ const hivePath = _internals116.resolveHiveKnowledgePath();
150669
+ try {
150670
+ const swarmEntries = await _internals116.readKnowledge(swarmPath);
150671
+ for (const e of swarmEntries)
150672
+ allKnownIds.add(e.id);
150673
+ } catch {}
150674
+ try {
150675
+ const hiveEntries = await _internals116.readKnowledge(hivePath);
150676
+ for (const e of hiveEntries)
150677
+ allKnownIds.add(e.id);
150678
+ } catch {}
150679
+ const skillEntries = [];
150680
+ for (const dir of [
150681
+ join163(directory, ".opencode", "skills", "generated"),
150682
+ join163(directory, ".swarm", "skills", "proposals")
150683
+ ]) {
150684
+ if (!_internals116.existsSync(dir))
150685
+ continue;
150686
+ const entries = await _internals116.readdir(dir, { withFileTypes: true });
150687
+ for (const entry of entries) {
150688
+ if (entry.isDirectory()) {
150689
+ skillEntries.push({
150690
+ slug: entry.name,
150691
+ path: join163(dir, entry.name),
150692
+ isProposal: false
150693
+ });
150694
+ } else if (entry.name.endsWith(".md")) {
150695
+ const slug = entry.name.replace(/\.md$/, "");
150696
+ skillEntries.push({
150697
+ slug,
150698
+ path: join163(dir, entry.name),
150699
+ isProposal: true
150700
+ });
150701
+ }
150702
+ }
150703
+ }
150704
+ const results = [];
150705
+ for (const { slug, path: path205, isProposal } of skillEntries) {
150706
+ const skillMdPath = isProposal ? path205 : join163(path205, "SKILL.md");
150707
+ if (!_internals116.existsSync(skillMdPath))
150708
+ continue;
150709
+ const content = await _internals116.readFile(skillMdPath, "utf-8");
150710
+ const fm = _internals116.parseDraftFrontmatter(content);
150711
+ const sourceIds = fm?.sourceKnowledgeIds ?? [];
150712
+ if (sourceIds.length === 0)
150713
+ continue;
150714
+ const affected = sourceIds.filter((id) => archivedSet.has(id) || !allKnownIds.has(id));
150715
+ if (affected.length === 0)
150716
+ continue;
150717
+ if (args2.clear) {
150718
+ if (!isProposal) {
150719
+ const markerPath = join163(path205, "stale.marker");
150720
+ if (_internals116.existsSync(markerPath)) {
150721
+ try {
150722
+ await _internals116.clearSkillStale(path205);
150723
+ results.push({
150724
+ slug,
150725
+ reason: affected.join(", "),
150726
+ action: "cleared"
150727
+ });
150728
+ } catch {}
150729
+ }
150730
+ }
150731
+ } else {
150732
+ if (!isProposal) {
150733
+ try {
150734
+ await _internals116.retireOrMarkStale(directory, path205, archivedSet);
150735
+ results.push({
150736
+ slug,
150737
+ reason: affected.join(", "),
150738
+ action: "marked_stale"
150739
+ });
150740
+ } catch {}
150741
+ }
150742
+ }
150743
+ }
150744
+ return JSON.stringify({ found: results.length, skills: results }, null, 2);
150745
+ }
150746
+ });
150747
+ var _internals116 = {
150748
+ run_stale_reconciliation,
150749
+ clearSkillStale,
150750
+ retireOrMarkStale,
150751
+ parseDraftFrontmatter,
150752
+ getArchivedKnowledgeIds,
150753
+ readKnowledge,
150754
+ resolveSwarmKnowledgePath,
150755
+ resolveHiveKnowledgePath,
150756
+ readdir: readdir12,
150757
+ readFile: readFile33,
150758
+ existsSync: existsSync115
150759
+ };
150760
+
150269
150761
  // src/tools/submit-phase-council-verdicts.ts
150270
150762
  init_zod();
150271
150763
  init_loader();
@@ -150277,7 +150769,7 @@ import {
150277
150769
  unlinkSync as unlinkSync29,
150278
150770
  writeFileSync as writeFileSync36
150279
150771
  } from "node:fs";
150280
- import path203 from "node:path";
150772
+ import path205 from "node:path";
150281
150773
  init_create_tool();
150282
150774
  init_resolve_working_directory();
150283
150775
  var VerdictSchema2 = exports_external.object({
@@ -150444,7 +150936,7 @@ var submit_phase_council_verdicts = createSwarmTool({
150444
150936
  }
150445
150937
  });
150446
150938
  function getPhaseMutationGapFinding(phaseNumber, workingDir) {
150447
- const mutationGatePath = path203.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
150939
+ const mutationGatePath = path205.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
150448
150940
  try {
150449
150941
  const raw = readFileSync90(mutationGatePath, "utf-8");
150450
150942
  const parsed = JSON.parse(raw);
@@ -150506,9 +150998,9 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
150506
150998
  }
150507
150999
  }
150508
151000
  function writePhaseCouncilEvidence(workingDir, synthesis, provenance) {
150509
- const evidenceDir = path203.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
151001
+ const evidenceDir = path205.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
150510
151002
  mkdirSync51(evidenceDir, { recursive: true });
150511
- const evidenceFile = path203.join(evidenceDir, "phase-council.json");
151003
+ const evidenceFile = path205.join(evidenceDir, "phase-council.json");
150512
151004
  const evidenceBundle = {
150513
151005
  entries: [
150514
151006
  {
@@ -150571,7 +151063,7 @@ init_zod();
150571
151063
  init_path_security();
150572
151064
  init_create_tool();
150573
151065
  import * as fs131 from "node:fs";
150574
- import * as path204 from "node:path";
151066
+ import * as path206 from "node:path";
150575
151067
  var BINARY_EXTENSIONS2 = new Set([
150576
151068
  ".png",
150577
151069
  ".jpg",
@@ -150607,14 +151099,14 @@ function containsWindowsAttacks5(str) {
150607
151099
  }
150608
151100
  function isPathInWorkspace4(filePath, workspace) {
150609
151101
  try {
150610
- const resolvedPath = path204.resolve(workspace, filePath);
151102
+ const resolvedPath = path206.resolve(workspace, filePath);
150611
151103
  if (!fs131.existsSync(resolvedPath)) {
150612
151104
  return true;
150613
151105
  }
150614
151106
  const realWorkspace = fs131.realpathSync(workspace);
150615
151107
  const realResolvedPath = fs131.realpathSync(resolvedPath);
150616
- const relativePath = path204.relative(realWorkspace, realResolvedPath);
150617
- if (relativePath.startsWith("..") || path204.isAbsolute(relativePath)) {
151108
+ const relativePath = path206.relative(realWorkspace, realResolvedPath);
151109
+ if (relativePath.startsWith("..") || path206.isAbsolute(relativePath)) {
150618
151110
  return false;
150619
151111
  }
150620
151112
  return true;
@@ -150729,7 +151221,7 @@ function arraysEqual2(a, b) {
150729
151221
  return true;
150730
151222
  }
150731
151223
  function isBinaryFile4(filePath) {
150732
- const ext = path204.extname(filePath).toLowerCase();
151224
+ const ext = path206.extname(filePath).toLowerCase();
150733
151225
  return BINARY_EXTENSIONS2.has(ext);
150734
151226
  }
150735
151227
  function splitDiffLines(content) {
@@ -150934,7 +151426,7 @@ var suggestPatch = createSwarmTool({
150934
151426
  });
150935
151427
  continue;
150936
151428
  }
150937
- const fullPath = path204.resolve(directory, change.file);
151429
+ const fullPath = path206.resolve(directory, change.file);
150938
151430
  if (!fs131.existsSync(fullPath)) {
150939
151431
  errors5.push({
150940
151432
  success: false,
@@ -151029,7 +151521,7 @@ var suggestPatch = createSwarmTool({
151029
151521
  const unifiedParts = [];
151030
151522
  for (const [file3, entries] of fileGroups) {
151031
151523
  entries.sort((a, b) => a.contextMatch.startLineIndex - b.contextMatch.startLineIndex);
151032
- const entryFullPath = path204.resolve(directory, file3);
151524
+ const entryFullPath = path206.resolve(directory, file3);
151033
151525
  let entryContent;
151034
151526
  try {
151035
151527
  entryContent = fs131.readFileSync(entryFullPath, "utf-8");
@@ -151230,7 +151722,7 @@ var swarm_memory_propose = createSwarmTool({
151230
151722
  evidenceRefs: exports_external.array(exports_external.string().min(1).max(500)).max(20).optional().describe("Evidence refs such as files, commits, test outputs, or URLs")
151231
151723
  },
151232
151724
  execute: async (args2, directory, ctx) => {
151233
- const { config: config3 } = _internals116.loadPluginConfigWithMeta(directory);
151725
+ const { config: config3 } = _internals117.loadPluginConfigWithMeta(directory);
151234
151726
  if (config3.memory?.enabled !== true) {
151235
151727
  return JSON.stringify({
151236
151728
  success: false,
@@ -151246,7 +151738,7 @@ var swarm_memory_propose = createSwarmTool({
151246
151738
  });
151247
151739
  }
151248
151740
  const agent = getContextAgent3(ctx);
151249
- const gateway = _internals116.createMemoryGateway({
151741
+ const gateway = _internals117.createMemoryGateway({
151250
151742
  directory,
151251
151743
  sessionID: ctx?.sessionID,
151252
151744
  agentRole: agent,
@@ -151271,7 +151763,7 @@ var swarm_memory_propose = createSwarmTool({
151271
151763
  }
151272
151764
  }
151273
151765
  });
151274
- var _internals116 = {
151766
+ var _internals117 = {
151275
151767
  loadPluginConfigWithMeta,
151276
151768
  createMemoryGateway
151277
151769
  };
@@ -151309,7 +151801,7 @@ var swarm_memory_recall = createSwarmTool({
151309
151801
  maxItems: exports_external.number().int().min(1).max(20).optional().describe("Maximum memories to return")
151310
151802
  },
151311
151803
  execute: async (args2, directory, ctx) => {
151312
- const { config: config3 } = _internals117.loadPluginConfigWithMeta(directory);
151804
+ const { config: config3 } = _internals118.loadPluginConfigWithMeta(directory);
151313
151805
  if (config3.memory?.enabled !== true) {
151314
151806
  return JSON.stringify({
151315
151807
  success: false,
@@ -151325,7 +151817,7 @@ var swarm_memory_recall = createSwarmTool({
151325
151817
  });
151326
151818
  }
151327
151819
  const agent = getContextAgent4(ctx);
151328
- const gateway = _internals117.createMemoryGateway({
151820
+ const gateway = _internals118.createMemoryGateway({
151329
151821
  directory,
151330
151822
  sessionID: ctx?.sessionID,
151331
151823
  agentRole: agent,
@@ -151358,7 +151850,7 @@ var RecallArgsSchema = exports_external.object({
151358
151850
  kinds: exports_external.array(exports_external.enum(MEMORY_KINDS2)).optional(),
151359
151851
  maxItems: exports_external.number().int().min(1).max(20).optional()
151360
151852
  });
151361
- var _internals117 = {
151853
+ var _internals118 = {
151362
151854
  loadPluginConfigWithMeta,
151363
151855
  createMemoryGateway
151364
151856
  };
@@ -151371,7 +151863,7 @@ function getContextAgent4(ctx) {
151371
151863
 
151372
151864
  // src/tools/syntax-check.ts
151373
151865
  import * as fs132 from "node:fs";
151374
- import * as path205 from "node:path";
151866
+ import * as path207 from "node:path";
151375
151867
  init_zod();
151376
151868
  init_manager2();
151377
151869
  init_detector();
@@ -151443,7 +151935,7 @@ async function syntaxCheck(input, directory, config3) {
151443
151935
  if (languages?.length) {
151444
151936
  const lowerLangs = languages.map((l) => l.toLowerCase());
151445
151937
  filesToCheck = filesToCheck.filter((file3) => {
151446
- const ext = path205.extname(file3.path).toLowerCase();
151938
+ const ext = path207.extname(file3.path).toLowerCase();
151447
151939
  const langDef = getLanguageForExtension(ext);
151448
151940
  const fileProfile = getProfileForFile(file3.path);
151449
151941
  const langId = fileProfile?.id || langDef?.id;
@@ -151453,7 +151945,7 @@ async function syntaxCheck(input, directory, config3) {
151453
151945
  const { loadGrammar: loadGrammar2 } = await Promise.resolve().then(() => (init_runtime(), exports_runtime));
151454
151946
  async function checkOneFile(fileInfo) {
151455
151947
  const { path: filePath } = fileInfo;
151456
- const fullPath = path205.isAbsolute(filePath) ? filePath : path205.join(directory, filePath);
151948
+ const fullPath = path207.isAbsolute(filePath) ? filePath : path207.join(directory, filePath);
151457
151949
  const result = {
151458
151950
  path: filePath,
151459
151951
  language: "",
@@ -151500,7 +151992,7 @@ async function syntaxCheck(input, directory, config3) {
151500
151992
  result.skipped_reason = "binary_file";
151501
151993
  return { result, counted: false, failed: false, skipped: true };
151502
151994
  }
151503
- const ext = path205.extname(filePath).toLowerCase();
151995
+ const ext = path207.extname(filePath).toLowerCase();
151504
151996
  const langDef = getLanguageForExtension(ext);
151505
151997
  result.language = profile?.id || langDef?.id || "unknown";
151506
151998
  const errors5 = extractSyntaxErrors(parser, content);
@@ -151612,7 +152104,7 @@ init_utils();
151612
152104
  init_create_tool();
151613
152105
  init_path_security();
151614
152106
  import * as fs133 from "node:fs";
151615
- import * as path206 from "node:path";
152107
+ import * as path208 from "node:path";
151616
152108
  var MAX_TEXT_LENGTH = 200;
151617
152109
  var MAX_FILE_SIZE_BYTES10 = 1024 * 1024;
151618
152110
  var SUPPORTED_EXTENSIONS4 = new Set([
@@ -151678,9 +152170,9 @@ function validatePathsInput(paths, cwd) {
151678
152170
  return { error: "paths contains path traversal", resolvedPath: null };
151679
152171
  }
151680
152172
  try {
151681
- const resolvedPath = path206.resolve(paths);
151682
- const normalizedCwd = path206.resolve(cwd);
151683
- const normalizedResolved = path206.resolve(resolvedPath);
152173
+ const resolvedPath = path208.resolve(paths);
152174
+ const normalizedCwd = path208.resolve(cwd);
152175
+ const normalizedResolved = path208.resolve(resolvedPath);
151684
152176
  if (!normalizedResolved.startsWith(normalizedCwd)) {
151685
152177
  return {
151686
152178
  error: "paths must be within the current working directory",
@@ -151696,7 +152188,7 @@ function validatePathsInput(paths, cwd) {
151696
152188
  }
151697
152189
  }
151698
152190
  function isSupportedExtension(filePath) {
151699
- const ext = path206.extname(filePath).toLowerCase();
152191
+ const ext = path208.extname(filePath).toLowerCase();
151700
152192
  return SUPPORTED_EXTENSIONS4.has(ext);
151701
152193
  }
151702
152194
  function findSourceFiles3(dir, files = []) {
@@ -151711,7 +152203,7 @@ function findSourceFiles3(dir, files = []) {
151711
152203
  if (SKIP_DIRECTORIES6.has(entry)) {
151712
152204
  continue;
151713
152205
  }
151714
- const fullPath = path206.join(dir, entry);
152206
+ const fullPath = path208.join(dir, entry);
151715
152207
  let stat14;
151716
152208
  try {
151717
152209
  stat14 = fs133.statSync(fullPath);
@@ -151823,7 +152315,7 @@ var todo_extract = createSwarmTool({
151823
152315
  filesToScan.push(scanPath);
151824
152316
  } else {
151825
152317
  const errorResult = {
151826
- error: `unsupported file extension: ${path206.extname(scanPath)}`,
152318
+ error: `unsupported file extension: ${path208.extname(scanPath)}`,
151827
152319
  total: 0,
151828
152320
  byPriority: { high: 0, medium: 0, low: 0 },
151829
152321
  entries: []
@@ -151873,18 +152365,18 @@ init_schema();
151873
152365
  init_qa_gate_profile();
151874
152366
  init_gate_evidence();
151875
152367
  import * as fs137 from "node:fs";
151876
- import * as path210 from "node:path";
152368
+ import * as path212 from "node:path";
151877
152369
 
151878
152370
  // src/hooks/diff-scope.ts
151879
152371
  init_bun_compat();
151880
152372
  import * as fs135 from "node:fs";
151881
- import * as path208 from "node:path";
152373
+ import * as path210 from "node:path";
151882
152374
 
151883
152375
  // src/utils/gitignore-warning.ts
151884
152376
  init_bun_compat();
151885
152377
  import * as fs134 from "node:fs";
151886
- import * as path207 from "node:path";
151887
- var _internals118 = { bunSpawn };
152378
+ import * as path209 from "node:path";
152379
+ var _internals119 = { bunSpawn };
151888
152380
  var _swarmGitExcludedChecked = false;
151889
152381
  function fileCoversSwarm(content) {
151890
152382
  for (const rawLine of content.split(`
@@ -151917,7 +152409,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
151917
152409
  checkIgnoreExitCode
151918
152410
  ] = await Promise.all([
151919
152411
  (async () => {
151920
- const proc = _internals118.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
152412
+ const proc = _internals119.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
151921
152413
  try {
151922
152414
  return await Promise.all([proc.exited, proc.stdout.text()]);
151923
152415
  } finally {
@@ -151927,7 +152419,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
151927
152419
  }
151928
152420
  })(),
151929
152421
  (async () => {
151930
- const proc = _internals118.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
152422
+ const proc = _internals119.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
151931
152423
  try {
151932
152424
  return await Promise.all([proc.exited, proc.stdout.text()]);
151933
152425
  } finally {
@@ -151937,7 +152429,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
151937
152429
  }
151938
152430
  })(),
151939
152431
  (async () => {
151940
- const proc = _internals118.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
152432
+ const proc = _internals119.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
151941
152433
  try {
151942
152434
  return await proc.exited;
151943
152435
  } finally {
@@ -151957,10 +152449,10 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
151957
152449
  const excludeRelPath = excludePathRaw.trim();
151958
152450
  if (!excludeRelPath)
151959
152451
  return;
151960
- const excludePath = path207.isAbsolute(excludeRelPath) ? excludeRelPath : path207.join(directory, excludeRelPath);
152452
+ const excludePath = path209.isAbsolute(excludeRelPath) ? excludeRelPath : path209.join(directory, excludeRelPath);
151961
152453
  if (checkIgnoreExitCode !== 0) {
151962
152454
  try {
151963
- fs134.mkdirSync(path207.dirname(excludePath), { recursive: true });
152455
+ fs134.mkdirSync(path209.dirname(excludePath), { recursive: true });
151964
152456
  let existing = "";
151965
152457
  try {
151966
152458
  existing = fs134.readFileSync(excludePath, "utf8");
@@ -151976,7 +152468,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
151976
152468
  }
151977
152469
  } catch {}
151978
152470
  }
151979
- const trackedProc = _internals118.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
152471
+ const trackedProc = _internals119.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
151980
152472
  let trackedExitCode;
151981
152473
  let trackedOutput;
151982
152474
  try {
@@ -152001,10 +152493,10 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
152001
152493
  }
152002
152494
 
152003
152495
  // src/hooks/diff-scope.ts
152004
- var _internals119 = { bunSpawn };
152496
+ var _internals120 = { bunSpawn };
152005
152497
  function getDeclaredScope(taskId, directory) {
152006
152498
  try {
152007
- const planPath = path208.join(directory, ".swarm", "plan.json");
152499
+ const planPath = path210.join(directory, ".swarm", "plan.json");
152008
152500
  if (!fs135.existsSync(planPath))
152009
152501
  return null;
152010
152502
  const raw = fs135.readFileSync(planPath, "utf-8");
@@ -152036,7 +152528,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
152036
152528
  };
152037
152529
  async function getChangedFiles2(directory) {
152038
152530
  try {
152039
- const proc = _internals119.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
152531
+ const proc = _internals120.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
152040
152532
  cwd: directory,
152041
152533
  ...GIT_DIFF_SPAWN_OPTIONS
152042
152534
  });
@@ -152053,7 +152545,7 @@ async function getChangedFiles2(directory) {
152053
152545
  return stdout.trim().split(`
152054
152546
  `).map((f) => f.trim()).filter((f) => f.length > 0);
152055
152547
  }
152056
- const proc2 = _internals119.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
152548
+ const proc2 = _internals120.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
152057
152549
  cwd: directory,
152058
152550
  ...GIT_DIFF_SPAWN_OPTIONS
152059
152551
  });
@@ -152110,8 +152602,8 @@ init_telemetry();
152110
152602
  // src/turbo/lean/task-completion.ts
152111
152603
  init_file_locks();
152112
152604
  import * as fs136 from "node:fs";
152113
- import * as path209 from "node:path";
152114
- var _internals120 = {
152605
+ import * as path211 from "node:path";
152606
+ var _internals121 = {
152115
152607
  listActiveLocks,
152116
152608
  verifyLeanTurboTaskCompletion
152117
152609
  };
@@ -152129,7 +152621,7 @@ var TIER_3_PATTERNS = [
152129
152621
  ];
152130
152622
  function matchesTier3Pattern(files) {
152131
152623
  for (const file3 of files) {
152132
- const fileName = path209.basename(file3);
152624
+ const fileName = path211.basename(file3);
152133
152625
  for (const pattern of TIER_3_PATTERNS) {
152134
152626
  if (pattern.test(fileName)) {
152135
152627
  return true;
@@ -152141,7 +152633,7 @@ function matchesTier3Pattern(files) {
152141
152633
  function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
152142
152634
  let persisted = null;
152143
152635
  try {
152144
- const statePath = path209.join(directory, ".swarm", "turbo-state.json");
152636
+ const statePath = path211.join(directory, ".swarm", "turbo-state.json");
152145
152637
  if (!fs136.existsSync(statePath)) {
152146
152638
  return {
152147
152639
  ok: false,
@@ -152225,11 +152717,11 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
152225
152717
  };
152226
152718
  }
152227
152719
  const phase = runState.phase ?? 0;
152228
- const evidencePath = path209.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
152229
- const expectedDir = path209.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
152230
- const resolvedPath = path209.resolve(evidencePath);
152231
- const resolvedDir = path209.resolve(expectedDir);
152232
- if (!resolvedPath.startsWith(resolvedDir + path209.sep) && resolvedPath !== resolvedDir) {
152720
+ const evidencePath = path211.join(directory, ".swarm", "evidence", String(phase), "lean-turbo", `${lane.laneId}.json`);
152721
+ const expectedDir = path211.join(directory, ".swarm", "evidence", String(phase), "lean-turbo");
152722
+ const resolvedPath = path211.resolve(evidencePath);
152723
+ const resolvedDir = path211.resolve(expectedDir);
152724
+ if (!resolvedPath.startsWith(resolvedDir + path211.sep) && resolvedPath !== resolvedDir) {
152233
152725
  return {
152234
152726
  ok: false,
152235
152727
  reason: `Lane ID causes path traversal: ${lane.laneId}`,
@@ -152253,7 +152745,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
152253
152745
  }
152254
152746
  };
152255
152747
  }
152256
- const activeLocks = _internals120.listActiveLocks(directory);
152748
+ const activeLocks = _internals121.listActiveLocks(directory);
152257
152749
  const laneLocks = activeLocks.filter((lock) => lock.laneId === lane.laneId);
152258
152750
  if (laneLocks.length > 0) {
152259
152751
  return {
@@ -152269,7 +152761,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
152269
152761
  }
152270
152762
  let filesTouched = [];
152271
152763
  try {
152272
- const planPath = path209.join(directory, ".swarm", "plan.json");
152764
+ const planPath = path211.join(directory, ".swarm", "plan.json");
152273
152765
  const planRaw = fs136.readFileSync(planPath, "utf-8");
152274
152766
  const plan = JSON.parse(planRaw);
152275
152767
  for (const planPhase of plan.phases ?? []) {
@@ -152320,7 +152812,7 @@ function verifyLeanTurboTaskCompletion(directory, taskId, sessionID) {
152320
152812
  init_task_id();
152321
152813
  init_create_tool();
152322
152814
  init_resolve_working_directory();
152323
- var _internals121 = {
152815
+ var _internals122 = {
152324
152816
  tryAcquireLock,
152325
152817
  updateTaskStatus,
152326
152818
  resolveWorkingDirectory
@@ -152358,7 +152850,7 @@ var TIER_3_PATTERNS2 = [
152358
152850
  ];
152359
152851
  function matchesTier3Pattern2(files) {
152360
152852
  for (const file3 of files) {
152361
- const fileName = path210.basename(file3);
152853
+ const fileName = path212.basename(file3);
152362
152854
  for (const pattern of TIER_3_PATTERNS2) {
152363
152855
  if (pattern.test(fileName)) {
152364
152856
  return true;
@@ -152397,7 +152889,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
152397
152889
  if (!skipStandardTurboBypass && hasActiveTurboMode()) {
152398
152890
  const resolvedDir2 = workingDirectory;
152399
152891
  try {
152400
- const planPath = path210.join(resolvedDir2, ".swarm", "plan.json");
152892
+ const planPath = path212.join(resolvedDir2, ".swarm", "plan.json");
152401
152893
  const planRaw = fs137.readFileSync(planPath, "utf-8");
152402
152894
  const plan = JSON.parse(planRaw);
152403
152895
  for (const planPhase of plan.phases ?? []) {
@@ -152417,7 +152909,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
152417
152909
  }
152418
152910
  let resolvedDir;
152419
152911
  if (fallbackDir) {
152420
- const resolveResult = _internals121.resolveWorkingDirectory(workingDirectory, fallbackDir);
152912
+ const resolveResult = _internals122.resolveWorkingDirectory(workingDirectory, fallbackDir);
152421
152913
  if (resolveResult.success) {
152422
152914
  resolvedDir = resolveResult.directory;
152423
152915
  } else {
@@ -152475,7 +152967,7 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
152475
152967
  }
152476
152968
  if (resolvedDir) {
152477
152969
  try {
152478
- const planPath = path210.join(resolvedDir, ".swarm", "plan.json");
152970
+ const planPath = path212.join(resolvedDir, ".swarm", "plan.json");
152479
152971
  const planRaw = fs137.readFileSync(planPath, "utf-8");
152480
152972
  const plan = JSON.parse(planRaw);
152481
152973
  for (const planPhase of plan.phases ?? []) {
@@ -152686,7 +153178,7 @@ function checkCouncilGate(workingDirectory, taskId) {
152686
153178
  return { blocked: false, reason: "", active: false };
152687
153179
  }
152688
153180
  try {
152689
- const planPath = path210.join(workingDirectory, ".swarm", "plan.json");
153181
+ const planPath = path212.join(workingDirectory, ".swarm", "plan.json");
152690
153182
  const planRaw = fs137.readFileSync(planPath, "utf-8");
152691
153183
  const planObj = JSON.parse(planRaw);
152692
153184
  if (planObj.swarm && planObj.title) {
@@ -152764,7 +153256,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152764
153256
  }
152765
153257
  }
152766
153258
  let directory;
152767
- const resolveResult = _internals121.resolveWorkingDirectory(args2.working_directory, fallbackDir);
153259
+ const resolveResult = _internals122.resolveWorkingDirectory(args2.working_directory, fallbackDir);
152768
153260
  if (!resolveResult.success) {
152769
153261
  return {
152770
153262
  success: false,
@@ -152773,7 +153265,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152773
153265
  };
152774
153266
  }
152775
153267
  directory = resolveResult.directory;
152776
- const planPath = path210.join(directory, ".swarm", "plan.json");
153268
+ const planPath = path212.join(directory, ".swarm", "plan.json");
152777
153269
  if (!fs137.existsSync(planPath)) {
152778
153270
  return {
152779
153271
  success: false,
@@ -152782,9 +153274,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152782
153274
  };
152783
153275
  }
152784
153276
  if (fallbackDir && directory !== fallbackDir) {
152785
- const canonicalDir = fs137.realpathSync(path210.resolve(directory));
152786
- const canonicalRoot = fs137.realpathSync(path210.resolve(fallbackDir));
152787
- if (canonicalDir.startsWith(canonicalRoot + path210.sep)) {
153277
+ const canonicalDir = fs137.realpathSync(path212.resolve(directory));
153278
+ const canonicalRoot = fs137.realpathSync(path212.resolve(fallbackDir));
153279
+ if (canonicalDir.startsWith(canonicalRoot + path212.sep)) {
152788
153280
  return {
152789
153281
  success: false,
152790
153282
  message: `Invalid working_directory: "${directory}" is a subdirectory of ` + `the project root "${fallbackDir}". Pass the project root path or ` + `omit working_directory entirely.`,
@@ -152796,8 +153288,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152796
153288
  }
152797
153289
  if (args2.status === "in_progress") {
152798
153290
  try {
152799
- const evidencePath = path210.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
152800
- fs137.mkdirSync(path210.dirname(evidencePath), { recursive: true });
153291
+ const evidencePath = path212.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
153292
+ fs137.mkdirSync(path212.dirname(evidencePath), { recursive: true });
152801
153293
  const fd = fs137.openSync(evidencePath, "wx");
152802
153294
  let writeOk = false;
152803
153295
  try {
@@ -152821,7 +153313,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152821
153313
  recoverTaskStateFromDelegations(args2.task_id, directory);
152822
153314
  let phaseRequiresReviewer = true;
152823
153315
  try {
152824
- const planPath2 = path210.join(directory, ".swarm", "plan.json");
153316
+ const planPath2 = path212.join(directory, ".swarm", "plan.json");
152825
153317
  const planRaw = fs137.readFileSync(planPath2, "utf-8");
152826
153318
  const plan = JSON.parse(planRaw);
152827
153319
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
@@ -152857,7 +153349,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152857
153349
  }
152858
153350
  let lockResult;
152859
153351
  try {
152860
- lockResult = await _internals121.tryAcquireLock(directory, planFilePath, agentName, lockTaskId);
153352
+ lockResult = await _internals122.tryAcquireLock(directory, planFilePath, agentName, lockTaskId);
152861
153353
  } catch (error93) {
152862
153354
  return {
152863
153355
  success: false,
@@ -152876,7 +153368,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir, ctx) {
152876
153368
  };
152877
153369
  }
152878
153370
  try {
152879
- const updatedPlan = await _internals121.updateTaskStatus(directory, args2.task_id, args2.status);
153371
+ const updatedPlan = await _internals122.updateTaskStatus(directory, args2.task_id, args2.status);
152880
153372
  if (args2.status === "completed") {
152881
153373
  for (const [_sessionId, session] of swarmState.agentSessions) {
152882
153374
  if (!(session.taskWorkflowStates instanceof Map)) {
@@ -152940,7 +153432,7 @@ init_utils2();
152940
153432
  init_redaction();
152941
153433
  import { createHash as createHash26 } from "node:crypto";
152942
153434
  import { appendFile as appendFile18, mkdir as mkdir35 } from "node:fs/promises";
152943
- import * as path211 from "node:path";
153435
+ import * as path213 from "node:path";
152944
153436
  var EVIDENCE_CACHE_FILE = "evidence-cache/documents.jsonl";
152945
153437
  var MAX_EVIDENCE_TEXT_LENGTH = 4000;
152946
153438
  async function writeEvidenceDocuments(directory, inputs, now = () => new Date) {
@@ -152948,7 +153440,7 @@ async function writeEvidenceDocuments(directory, inputs, now = () => new Date) {
152948
153440
  const capturedAt = now().toISOString();
152949
153441
  const records = inputs.map((input) => createEvidenceDocumentRecord(input, capturedAt)).filter((record3) => record3 !== null);
152950
153442
  if (records.length > 0) {
152951
- await mkdir35(path211.dirname(filePath), { recursive: true });
153443
+ await mkdir35(path213.dirname(filePath), { recursive: true });
152952
153444
  await appendFile18(filePath, `${records.map((record3) => JSON.stringify(record3)).join(`
152953
153445
  `)}
152954
153446
  `, "utf-8");
@@ -153531,7 +154023,7 @@ var web_fetch = createSwarmTool({
153531
154023
  };
153532
154024
  return JSON.stringify(fail, null, 2);
153533
154025
  }
153534
- const config3 = _internals122.loadPluginConfig(dirResult.directory);
154026
+ const config3 = _internals123.loadPluginConfig(dirResult.directory);
153535
154027
  const generalConfig = config3.council?.general;
153536
154028
  if (!generalConfig || generalConfig.enabled !== true) {
153537
154029
  const fail = {
@@ -153541,7 +154033,7 @@ var web_fetch = createSwarmTool({
153541
154033
  };
153542
154034
  return JSON.stringify(fail, null, 2);
153543
154035
  }
153544
- const validated = await validateFetchUrl(parsed.data.url, _internals122.dnsLookup);
154036
+ const validated = await validateFetchUrl(parsed.data.url, _internals123.dnsLookup);
153545
154037
  if (!validated.ok) {
153546
154038
  const fail = {
153547
154039
  success: false,
@@ -153552,7 +154044,7 @@ var web_fetch = createSwarmTool({
153552
154044
  }
153553
154045
  const maxBytes = parsed.data.max_bytes ?? DEFAULT_MAX_BYTES;
153554
154046
  const timeoutMs = parsed.data.timeout_ms ?? DEFAULT_TIMEOUT_MS5;
153555
- const result = await boundedFetch({ url: validated.url, address: validated.address }, maxBytes, timeoutMs, _internals122);
154047
+ const result = await boundedFetch({ url: validated.url, address: validated.address }, maxBytes, timeoutMs, _internals123);
153556
154048
  if (!result.ok) {
153557
154049
  const fail = {
153558
154050
  success: false,
@@ -153587,7 +154079,7 @@ var web_fetch = createSwarmTool({
153587
154079
  });
153588
154080
  async function captureFetchEvidence(directory, url3, title, text) {
153589
154081
  try {
153590
- const written = await _internals122.writeEvidenceDocuments(directory, [
154082
+ const written = await _internals123.writeEvidenceDocuments(directory, [
153591
154083
  {
153592
154084
  sourceType: "crawl",
153593
154085
  url: url3,
@@ -153608,7 +154100,7 @@ async function captureFetchEvidence(directory, url3, title, text) {
153608
154100
  };
153609
154101
  }
153610
154102
  }
153611
- var _internals122 = {
154103
+ var _internals123 = {
153612
154104
  httpRequest: performHttpRequest,
153613
154105
  dnsLookup: lookup,
153614
154106
  loadPluginConfig,
@@ -153922,7 +154414,7 @@ var web_search = createSwarmTool({
153922
154414
  });
153923
154415
  async function captureSearchEvidence(directory, query, results) {
153924
154416
  try {
153925
- const written = await _internals123.writeEvidenceDocuments(directory, results.map((result) => ({
154417
+ const written = await _internals124.writeEvidenceDocuments(directory, results.map((result) => ({
153926
154418
  sourceType: "web_search",
153927
154419
  query,
153928
154420
  title: result.title,
@@ -153950,7 +154442,7 @@ async function captureSearchEvidence(directory, query, results) {
153950
154442
  };
153951
154443
  }
153952
154444
  }
153953
- var _internals123 = {
154445
+ var _internals124 = {
153954
154446
  writeEvidenceDocuments
153955
154447
  };
153956
154448
 
@@ -153965,7 +154457,7 @@ init_schema3();
153965
154457
  init_store();
153966
154458
  init_create_tool();
153967
154459
  init_resolve_working_directory();
153968
- import * as path212 from "node:path";
154460
+ import * as path214 from "node:path";
153969
154461
  var FindingSchema2 = exports_external.object({
153970
154462
  severity: exports_external.enum(["low", "medium", "high", "critical"]),
153971
154463
  category: exports_external.string().min(1),
@@ -154041,7 +154533,7 @@ var write_architecture_supervisor_evidence = createSwarmTool({
154041
154533
  if (config3.architectural_supervision?.persist_knowledge_recommendations && args2.knowledge_recommendations.length > 0) {
154042
154534
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
154043
154535
  const lessons = args2.knowledge_recommendations.map((r) => r.lesson);
154044
- const result = await curateAndStoreSwarm(lessons, path212.basename(dirResult.directory), { phase_number: args2.phase }, dirResult.directory, knowledgeConfig, {
154536
+ const result = await curateAndStoreSwarm(lessons, path214.basename(dirResult.directory), { phase_number: args2.phase }, dirResult.directory, knowledgeConfig, {
154045
154537
  skipAutoPromotion: true,
154046
154538
  llmDelegate: createCuratorLLMDelegate(dirResult.directory, "phase"),
154047
154539
  enrichmentQuota: {
@@ -154088,7 +154580,7 @@ init_ledger();
154088
154580
  init_manager();
154089
154581
  init_create_tool();
154090
154582
  import fs138 from "node:fs";
154091
- import path213 from "node:path";
154583
+ import path215 from "node:path";
154092
154584
  function normalizeVerdict(verdict) {
154093
154585
  switch (verdict) {
154094
154586
  case "APPROVED":
@@ -154142,7 +154634,7 @@ async function executeWriteDriftEvidence(args2, directory) {
154142
154634
  entries: [evidenceEntry]
154143
154635
  };
154144
154636
  const filename = "drift-verifier.json";
154145
- const relativePath = path213.join("evidence", String(phase), filename);
154637
+ const relativePath = path215.join("evidence", String(phase), filename);
154146
154638
  let validatedPath;
154147
154639
  try {
154148
154640
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -154153,10 +154645,10 @@ async function executeWriteDriftEvidence(args2, directory) {
154153
154645
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
154154
154646
  }, null, 2);
154155
154647
  }
154156
- const evidenceDir = path213.dirname(validatedPath);
154648
+ const evidenceDir = path215.dirname(validatedPath);
154157
154649
  try {
154158
154650
  await fs138.promises.mkdir(evidenceDir, { recursive: true });
154159
- const tempPath = path213.join(evidenceDir, `.${filename}.tmp`);
154651
+ const tempPath = path215.join(evidenceDir, `.${filename}.tmp`);
154160
154652
  await fs138.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
154161
154653
  await fs138.promises.rename(tempPath, validatedPath);
154162
154654
  let snapshotInfo;
@@ -154257,7 +154749,7 @@ var write_drift_evidence = createSwarmTool({
154257
154749
  init_zod();
154258
154750
  init_loader();
154259
154751
  import fs139 from "node:fs";
154260
- import path214 from "node:path";
154752
+ import path216 from "node:path";
154261
154753
  init_utils2();
154262
154754
  init_manager();
154263
154755
  init_create_tool();
@@ -154371,7 +154863,7 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
154371
154863
  timestamp: synthesis.timestamp
154372
154864
  };
154373
154865
  const filename = "final-council.json";
154374
- const relativePath = path214.join("evidence", filename);
154866
+ const relativePath = path216.join("evidence", filename);
154375
154867
  let validatedPath;
154376
154868
  try {
154377
154869
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -154385,10 +154877,10 @@ async function executeWriteFinalCouncilEvidence(args2, directory) {
154385
154877
  const evidenceContent = {
154386
154878
  entries: [evidenceEntry]
154387
154879
  };
154388
- const evidenceDir = path214.dirname(validatedPath);
154880
+ const evidenceDir = path216.dirname(validatedPath);
154389
154881
  try {
154390
154882
  await fs139.promises.mkdir(evidenceDir, { recursive: true });
154391
- const tempPath = path214.join(evidenceDir, `.${filename}.tmp`);
154883
+ const tempPath = path216.join(evidenceDir, `.${filename}.tmp`);
154392
154884
  await fs139.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
154393
154885
  await fs139.promises.rename(tempPath, validatedPath);
154394
154886
  return JSON.stringify({
@@ -154448,7 +154940,7 @@ init_zod();
154448
154940
  init_utils2();
154449
154941
  init_create_tool();
154450
154942
  import fs140 from "node:fs";
154451
- import path215 from "node:path";
154943
+ import path217 from "node:path";
154452
154944
  function normalizeVerdict2(verdict) {
154453
154945
  switch (verdict) {
154454
154946
  case "APPROVED":
@@ -154496,7 +154988,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
154496
154988
  entries: [evidenceEntry]
154497
154989
  };
154498
154990
  const filename = "hallucination-guard.json";
154499
- const relativePath = path215.join("evidence", String(phase), filename);
154991
+ const relativePath = path217.join("evidence", String(phase), filename);
154500
154992
  let validatedPath;
154501
154993
  try {
154502
154994
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -154507,10 +154999,10 @@ async function executeWriteHallucinationEvidence(args2, directory) {
154507
154999
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
154508
155000
  }, null, 2);
154509
155001
  }
154510
- const evidenceDir = path215.dirname(validatedPath);
155002
+ const evidenceDir = path217.dirname(validatedPath);
154511
155003
  try {
154512
155004
  await fs140.promises.mkdir(evidenceDir, { recursive: true });
154513
- const tempPath = path215.join(evidenceDir, `.${filename}.tmp`);
155005
+ const tempPath = path217.join(evidenceDir, `.${filename}.tmp`);
154514
155006
  await fs140.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
154515
155007
  await fs140.promises.rename(tempPath, validatedPath);
154516
155008
  return JSON.stringify({
@@ -154560,7 +155052,7 @@ init_zod();
154560
155052
  init_utils2();
154561
155053
  init_create_tool();
154562
155054
  import fs141 from "node:fs";
154563
- import path216 from "node:path";
155055
+ import path218 from "node:path";
154564
155056
  function normalizeVerdict3(verdict) {
154565
155057
  switch (verdict) {
154566
155058
  case "PASS":
@@ -154634,7 +155126,7 @@ async function executeWriteMutationEvidence(args2, directory) {
154634
155126
  entries: [evidenceEntry]
154635
155127
  };
154636
155128
  const filename = "mutation-gate.json";
154637
- const relativePath = path216.join("evidence", String(phase), filename);
155129
+ const relativePath = path218.join("evidence", String(phase), filename);
154638
155130
  let validatedPath;
154639
155131
  try {
154640
155132
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -154645,10 +155137,10 @@ async function executeWriteMutationEvidence(args2, directory) {
154645
155137
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
154646
155138
  }, null, 2);
154647
155139
  }
154648
- const evidenceDir = path216.dirname(validatedPath);
155140
+ const evidenceDir = path218.dirname(validatedPath);
154649
155141
  try {
154650
155142
  await fs141.promises.mkdir(evidenceDir, { recursive: true });
154651
- const tempPath = path216.join(evidenceDir, `.${filename}.tmp`);
155143
+ const tempPath = path218.join(evidenceDir, `.${filename}.tmp`);
154652
155144
  await fs141.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
154653
155145
  await fs141.promises.rename(tempPath, validatedPath);
154654
155146
  return JSON.stringify({
@@ -154771,6 +155263,7 @@ var TOOL_MANIFEST = defineHandlers({
154771
155263
  skill_list: () => skill_list,
154772
155264
  skill_apply: () => skill_apply,
154773
155265
  skill_inspect: () => skill_inspect,
155266
+ run_stale_reconciliation: () => run_stale_reconciliation,
154774
155267
  skill_regenerate: () => skill_regenerate,
154775
155268
  skill_retire: () => skill_retire,
154776
155269
  skill_improve: () => skill_improve,
@@ -154863,7 +155356,7 @@ ${footerLines.join(`
154863
155356
  init_warning_buffer();
154864
155357
  var _heartbeatTimers = new Map;
154865
155358
  var SWARM_COMMAND_SYSTEM_RULE_TAG = "[opencode-swarm:swarm-command-rule]";
154866
- var PACKAGE_ROOT2 = path218.resolve(path218.dirname(fileURLToPath5(import.meta.url)), "..");
155359
+ var PACKAGE_ROOT2 = path220.resolve(path220.dirname(fileURLToPath5(import.meta.url)), "..");
154867
155360
  var SYNC_BUNDLED_SKILLS_TIMEOUT_MS = 2000;
154868
155361
  function createSwarmCommandSystemRuleHook(agentDefinitions, registeredAgents) {
154869
155362
  return async (input, output) => {
@@ -155185,7 +155678,7 @@ async function initializeOpenCodeSwarm(ctx) {
155185
155678
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
155186
155679
  preflightTriggerManager = new PTM(automationConfig);
155187
155680
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
155188
- const swarmDir = path218.resolve(ctx.directory, ".swarm");
155681
+ const swarmDir = path220.resolve(ctx.directory, ".swarm");
155189
155682
  statusArtifact = new ASA(swarmDir);
155190
155683
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
155191
155684
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -155857,7 +156350,7 @@ ${promptRaw}`;
155857
156350
  const meta3 = readSkillMetadata(s.skillPath, ctx.directory);
155858
156351
  let desc = meta3.description || "";
155859
156352
  if (!desc || desc === "No description provided") {
155860
- desc = path218.basename(path218.dirname(s.skillPath));
156353
+ desc = path220.basename(path220.dirname(s.skillPath));
155861
156354
  }
155862
156355
  desc = desc.replace(/,/g, ";");
155863
156356
  return `file:${s.skillPath} (-- ${desc})`;
@@ -155867,7 +156360,7 @@ ${promptRaw}`;
155867
156360
 
155868
156361
  ${promptRaw}`;
155869
156362
  argsRecord.prompt = newPrompt;
155870
- const skillNames = topSkills.map((s) => `${path218.basename(s.skillPath)} (score: ${s.score.toFixed(2)})`).join(", ");
156363
+ const skillNames = topSkills.map((s) => `${path220.basename(s.skillPath)} (score: ${s.score.toFixed(2)})`).join(", ");
155871
156364
  console.warn(`[skill-propagation-gate] Injected skills: ${skillNames}`);
155872
156365
  for (const skill of topSkills) {
155873
156366
  try {