opencode-swarm 7.110.0 → 7.110.2

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 (43) hide show
  1. package/dist/agents/explorer.d.ts +1 -1
  2. package/dist/cli/{config-doctor-9vjyj9m3.js → config-doctor-q5e9yzn6.js} +2 -2
  3. package/dist/cli/{core-mbd2g302.js → core-gjac7vd9.js} +1 -1
  4. package/dist/cli/{curator-llm-factory-y4kvr1ph.js → curator-llm-factory-3x89ddtd.js} +13 -13
  5. package/dist/cli/{curator-4qqzpd85.js → curator-qpgdv0fp.js} +15 -13
  6. package/dist/cli/{explorer-ksr3xq7n.js → explorer-t5srbq64.js} +1 -1
  7. package/dist/cli/{guardrail-explain-10hh57cr.js → guardrail-explain-jdwp6h9c.js} +14 -14
  8. package/dist/cli/{guardrail-log-5240bawg.js → guardrail-log-973nan7m.js} +3 -3
  9. package/dist/cli/{hive-promoter-wvxqyayt.js → hive-promoter-rs5dr4pf.js} +13 -13
  10. package/dist/cli/{index-18690p15.js → index-0g5xsrp4.js} +19 -7
  11. package/dist/cli/{index-2nt4mq9n.js → index-40h0yp9e.js} +69 -1
  12. package/dist/cli/{index-xhsba2sn.js → index-4k3gh2nz.js} +2 -2
  13. package/dist/cli/{index-d3txrx5q.js → index-53z1afgh.js} +1 -1
  14. package/dist/cli/{index-p5vm9gy9.js → index-5rfxzgmt.js} +1 -1
  15. package/dist/cli/{index-41fgssqr.js → index-c483hnn4.js} +2 -2
  16. package/dist/cli/{index-b15qbvph.js → index-cmjq1kg7.js} +43 -34
  17. package/dist/cli/{index-3yk9196e.js → index-dm35e55e.js} +1 -1
  18. package/dist/cli/{index-09xpycan.js → index-jt58s751.js} +1 -1
  19. package/dist/cli/{index-mtzjbaaa.js → index-mvg66d9n.js} +3 -3
  20. package/dist/cli/{index-khj0knr0.js → index-rm8b4959.js} +19 -19
  21. package/dist/cli/{index-1mc2yfc2.js → index-smk3st51.js} +1219 -1017
  22. package/dist/cli/{index-8f10r7ay.js → index-v8pk35h7.js} +5 -5
  23. package/dist/cli/{index-x2q0gnt8.js → index-vzzt3ygr.js} +1 -1
  24. package/dist/cli/{index-zjh648z4.js → index-xddysq89.js} +1 -1
  25. package/dist/cli/{index-y5z2qdvk.js → index-yhmt3dw3.js} +2 -2
  26. package/dist/cli/index.js +15 -15
  27. package/dist/cli/{knowledge-escalator-9ksrgq7h.js → knowledge-escalator-0dkkenp2.js} +4 -4
  28. package/dist/cli/{knowledge-events-ymysgtrr.js → knowledge-events-bckbj6ah.js} +2 -2
  29. package/dist/cli/{knowledge-store-562fefjy.js → knowledge-store-dvjbdn00.js} +3 -2
  30. package/dist/cli/{knowledge-validator-b9nvmzjc.js → knowledge-validator-bqr936sg.js} +3 -3
  31. package/dist/cli/{schema-5vmb5dh8.js → schema-s48je8zt.js} +1 -1
  32. package/dist/cli/{scope-persistence-6m5nsp1r.js → scope-persistence-tgp00wtd.js} +1 -1
  33. package/dist/cli/{skill-generator-mjfqvnn0.js → skill-generator-5rsjmmfq.js} +7 -5
  34. package/dist/hooks/curator-postmortem.d.ts +33 -2
  35. package/dist/hooks/curator-types.d.ts +2 -2
  36. package/dist/hooks/curator.d.ts +2 -1
  37. package/dist/hooks/knowledge-link.d.ts +9 -0
  38. package/dist/hooks/knowledge-reader.d.ts +14 -0
  39. package/dist/index.js +82 -66
  40. package/dist/services/skill-generator.d.ts +1 -0
  41. package/dist/services/warning-buffer.d.ts +25 -0
  42. package/dist/tools/tool-metadata.d.ts +4 -4
  43. package/package.json +1 -1
@@ -1,7 +1,4 @@
1
1
  // @bun
2
- import {
3
- readRecentEscalations
4
- } from "./index-mtzjbaaa.js";
5
2
  import {
6
3
  getGlobalEventBus
7
4
  } from "./index-c8s9a3zh.js";
@@ -10,7 +7,23 @@ import {
10
7
  readDoctorArtifact,
11
8
  removeStraySwarmDir,
12
9
  runConfigDoctor
13
- } from "./index-zjh648z4.js";
10
+ } from "./index-xddysq89.js";
11
+ import {
12
+ AGENT_TOOL_MAP,
13
+ ALL_SUBAGENT_NAMES,
14
+ ExternalSkillsConfigSchema,
15
+ GATE_CONFIG_KNOWN_SECTION_KEYS,
16
+ GateConfigSchema,
17
+ KnowledgeConfigSchema,
18
+ ORCHESTRATOR_NAME,
19
+ PluginConfigSchema,
20
+ SkillImproverConfigSchema,
21
+ TOOL_NAMES,
22
+ TOOL_NAME_SET,
23
+ getCanonicalAgentRole,
24
+ resolveExternalSkillsConfig,
25
+ stripKnownSwarmPrefix
26
+ } from "./index-0g5xsrp4.js";
14
27
  import {
15
28
  MAX_TRANSIENT_RETRIES,
16
29
  PlanSchema,
@@ -76,27 +89,6 @@ import {
76
89
  subscribe,
77
90
  unsubscribe
78
91
  } from "./index-85bacexr.js";
79
- import {
80
- CURATOR_INIT_PROMPT,
81
- CURATOR_PHASE_PROMPT,
82
- READ_ONLY_LANE_GUIDANCE
83
- } from "./index-09xpycan.js";
84
- import {
85
- AGENT_TOOL_MAP,
86
- ALL_SUBAGENT_NAMES,
87
- ExternalSkillsConfigSchema,
88
- GATE_CONFIG_KNOWN_SECTION_KEYS,
89
- GateConfigSchema,
90
- KnowledgeConfigSchema,
91
- ORCHESTRATOR_NAME,
92
- PluginConfigSchema,
93
- SkillImproverConfigSchema,
94
- TOOL_NAMES,
95
- TOOL_NAME_SET,
96
- getCanonicalAgentRole,
97
- resolveExternalSkillsConfig,
98
- stripKnownSwarmPrefix
99
- } from "./index-18690p15.js";
100
92
  import {
101
93
  DEFAULT_SKILL_MIN_CONFIDENCE,
102
94
  DEFAULT_SKILL_MIN_CONFIRMATIONS,
@@ -113,15 +105,7 @@ import {
113
105
  retireOrMarkStale,
114
106
  retireSkill,
115
107
  selectCandidateEntries
116
- } from "./index-b15qbvph.js";
117
- import {
118
- effectiveRetrievalOutcomes,
119
- readKnowledgeCounterRollups,
120
- readKnowledgeEvents,
121
- recordHiveKnowledgeEvent,
122
- recordKnowledgeEvent,
123
- resolveKnowledgeEventsPath
124
- } from "./index-y5z2qdvk.js";
108
+ } from "./index-cmjq1kg7.js";
125
109
  import {
126
110
  appendUnactionable,
127
111
  quarantineEntry,
@@ -131,7 +115,18 @@ import {
131
115
  validateActionability,
132
116
  validateActionableFields,
133
117
  validateLesson
134
- } from "./index-41fgssqr.js";
118
+ } from "./index-c483hnn4.js";
119
+ import {
120
+ readRecentEscalations
121
+ } from "./index-mvg66d9n.js";
122
+ import {
123
+ effectiveRetrievalOutcomes,
124
+ readKnowledgeCounterRollups,
125
+ readKnowledgeEvents,
126
+ recordHiveKnowledgeEvent,
127
+ recordKnowledgeEvent,
128
+ resolveKnowledgeEventsPath
129
+ } from "./index-yhmt3dw3.js";
135
130
  import {
136
131
  appendKnowledge,
137
132
  appendRejectedLesson,
@@ -153,7 +148,12 @@ import {
153
148
  rewriteKnowledge,
154
149
  transactFile,
155
150
  transactKnowledge
156
- } from "./index-8f10r7ay.js";
151
+ } from "./index-v8pk35h7.js";
152
+ import {
153
+ KNOWLEDGE_SCHEMA_VERSION,
154
+ OUTCOME_BLOCK_THRESHOLD,
155
+ isActiveStatus
156
+ } from "./index-bfwt3abw.js";
157
157
  import {
158
158
  isLinked,
159
159
  readLinkPointer,
@@ -162,19 +162,19 @@ import {
162
162
  resolveLinkDir,
163
163
  sanitizeLinkId,
164
164
  writeLinkPointer
165
- } from "./index-2nt4mq9n.js";
165
+ } from "./index-40h0yp9e.js";
166
166
  import {
167
- KNOWLEDGE_SCHEMA_VERSION,
168
- OUTCOME_BLOCK_THRESHOLD,
169
- isActiveStatus
170
- } from "./index-bfwt3abw.js";
167
+ CURATOR_INIT_PROMPT,
168
+ CURATOR_PHASE_PROMPT,
169
+ READ_ONLY_LANE_GUIDANCE
170
+ } from "./index-jt58s751.js";
171
171
  import {
172
172
  SandboxCapabilityProbe,
173
173
  init_capability_probe
174
174
  } from "./index-wvrj16f0.js";
175
175
  import {
176
176
  clearAllScopes
177
- } from "./index-x2q0gnt8.js";
177
+ } from "./index-vzzt3ygr.js";
178
178
  import {
179
179
  readSwarmFileAsync,
180
180
  safeHook,
@@ -4983,7 +4983,18 @@ function loadPluginConfigWithMeta(directory) {
4983
4983
  return { config, loadedFromFile, configHadErrors };
4984
4984
  }
4985
4985
  // src/services/warning-buffer.ts
4986
+ init_logger();
4986
4987
  var deferredWarnings = [];
4988
+ var MAX_DEFERRED_WARNINGS = 50;
4989
+ function addDeferredWarning(warning) {
4990
+ if (deferredWarnings.length < MAX_DEFERRED_WARNINGS) {
4991
+ deferredWarnings.push(warning);
4992
+ }
4993
+ }
4994
+ function advisoryWarn(message, data) {
4995
+ addDeferredWarning(message);
4996
+ log(message, data);
4997
+ }
4987
4998
  function getDeferredWarnings() {
4988
4999
  return [...deferredWarnings];
4989
5000
  }
@@ -4992,6 +5003,7 @@ function getDeferredWarnings() {
4992
5003
  import { randomUUID as randomUUID3 } from "crypto";
4993
5004
  import * as fsp from "fs/promises";
4994
5005
  import * as path8 from "path";
5006
+ init_logger();
4995
5007
  var BUNDLED_PROJECT_SKILLS = [
4996
5008
  "brainstorm",
4997
5009
  "specify",
@@ -5030,9 +5042,9 @@ var BUNDLED_PROJECT_SKILLS = [
5030
5042
  ];
5031
5043
  var MAX_SKILL_FILES = 64;
5032
5044
  var MAX_SKILL_BYTES = 512000;
5033
- function warnBundledSkillSyncFailure(err) {
5045
+ function describeBundledSkillSyncFailure(err) {
5034
5046
  const message = err instanceof Error ? err.message : String(err);
5035
- console.warn(`[opencode-swarm] Could not install bundled project skills; continuing without sync: ${message}`);
5047
+ return `[opencode-swarm] Could not install bundled project skills; continuing without sync: ${message}`;
5036
5048
  }
5037
5049
  async function isSymbolicLinkAsync(p) {
5038
5050
  try {
@@ -5180,13 +5192,17 @@ async function syncBundledProjectSkillsIfMissingAsync(projectDirectory, packageR
5180
5192
  if (!await ensureNotSymlinkedDirectoryAsync(destDir))
5181
5193
  continue;
5182
5194
  await copyBundledDirectoryBoundedAsync(sourceDir, destDir);
5183
- if (!quiet) {
5184
- console.warn(`[opencode-swarm] Synchronized bundled skill .opencode/skills/${slug}/SKILL.md for first-class /swarm command support`);
5185
- }
5195
+ log("synchronized bundled skill", {
5196
+ slug: `.opencode/skills/${slug}/SKILL.md`
5197
+ });
5186
5198
  }
5187
5199
  } catch (err) {
5188
- if (!quiet)
5189
- warnBundledSkillSyncFailure(err);
5200
+ const failureMsg = describeBundledSkillSyncFailure(err);
5201
+ if (quiet) {
5202
+ advisoryWarn(failureMsg);
5203
+ } else {
5204
+ console.warn(failureMsg);
5205
+ }
5190
5206
  }
5191
5207
  }
5192
5208
 
@@ -6555,790 +6571,13 @@ import { promises as fs9 } from "fs";
6555
6571
  import path28 from "path";
6556
6572
 
6557
6573
  // src/hooks/curator-postmortem.ts
6558
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync4 } from "fs";
6559
- import * as path12 from "path";
6560
- var MAX_INPUT_TEXT_CHARS = 500;
6561
- var MAX_KNOWLEDGE_ENTRIES = 500;
6562
- var MAX_PROPOSALS = 50;
6563
- var MAX_RETROSPECTIVES = 50;
6564
- var MAX_DRIFT_REPORTS = 50;
6565
- var MAX_UNACTIONABLE = 1000;
6566
- async function collectKnowledgeSummary(directory, scope = "project", sessionID) {
6567
- const entries = await readKnowledge(resolveSwarmKnowledgePath(directory), MAX_KNOWLEDGE_ENTRIES);
6568
- let events = await readKnowledgeEvents(directory, MAX_KNOWLEDGE_ENTRIES * 4);
6569
- if (scope === "session" && sessionID) {
6570
- events = events.filter((e) => e.session_id === sessionID);
6571
- }
6572
- const countsMap = new Map;
6573
- for (const e of events) {
6574
- if (e.type !== "applied" && e.type !== "violated" && e.type !== "ignored")
6575
- continue;
6576
- const kid = e.knowledge_id ?? e.entry_id;
6577
- if (!kid)
6578
- continue;
6579
- const c = countsMap.get(kid) ?? { applied: 0, violated: 0, ignored: 0 };
6580
- if (e.type === "applied")
6581
- c.applied++;
6582
- else if (e.type === "violated")
6583
- c.violated++;
6584
- else if (e.type === "ignored")
6585
- c.ignored++;
6586
- countsMap.set(kid, c);
6587
- }
6588
- return entries.map((entry) => {
6589
- const c = countsMap.get(entry.id) ?? {
6590
- applied: 0,
6591
- violated: 0,
6592
- ignored: 0
6593
- };
6594
- return {
6595
- id: entry.id,
6596
- lesson: entry.lesson,
6597
- applied: c.applied,
6598
- violated: c.violated,
6599
- ignored: c.ignored,
6600
- confidence: entry.confidence ?? 0.5,
6601
- status: entry.status ?? "active"
6602
- };
6603
- });
6604
- }
6605
- function extractSection(text, sectionName) {
6606
- const pattern = new RegExp(`^${sectionName}:\\s*\\n([\\s\\S]*?)(?=\\n[A-Z_]+:\\s*(?:\\n|$)|$)`, "m");
6607
- const match = text.match(pattern);
6608
- return match?.[1]?.trim() || null;
6609
- }
6610
- function normalizeRecommendationAction(raw) {
6611
- const value = String(raw ?? "").toLowerCase().trim();
6612
- if (value === "promote" || value === "promote_to_hive")
6613
- return "promote";
6614
- if (value === "archive" || value === "flag_stale")
6615
- return "archive";
6616
- if (value === "rewrite")
6617
- return "rewrite";
6618
- if (value === "flag_contradiction")
6619
- return "flag_contradiction";
6620
- if (value === "merge")
6621
- return null;
6622
- return null;
6623
- }
6624
- function normalizeProposalSlug(raw) {
6625
- return raw.trim().replace(/^proposals[\\/]/, "").replace(/\.md$/i, "").replace(/\.json$/i, "");
6626
- }
6627
- function parseStructuredPostMortemActions(llmOutput) {
6628
- const parsed = {
6629
- summary: extractSection(llmOutput, "SUMMARY"),
6630
- recommendations: [],
6631
- queueTriage: [],
6632
- diagnostics: []
6633
- };
6634
- const fence = /```(?:json|jsonc)?\s+postmortem_actions\s*\n([\s\S]*?)\n```/g;
6635
- for (const match of llmOutput.matchAll(fence)) {
6636
- let data;
6637
- try {
6638
- data = JSON.parse(match[1]);
6639
- } catch (err) {
6640
- parsed.diagnostics.push(`postmortem_actions malformed_json: ${err instanceof Error ? err.message : String(err)}`);
6641
- continue;
6642
- }
6643
- if (!data || typeof data !== "object" || Array.isArray(data)) {
6644
- parsed.diagnostics.push("postmortem_actions expected object");
6645
- continue;
6646
- }
6647
- const obj = data;
6648
- if (typeof obj.summary === "string" && obj.summary.trim()) {
6649
- parsed.summary = obj.summary.trim().slice(0, 1000);
6650
- }
6651
- if (Array.isArray(obj.curation_recommendations)) {
6652
- for (const [index, item] of obj.curation_recommendations.entries()) {
6653
- if (!item || typeof item !== "object") {
6654
- parsed.diagnostics.push(`curation_recommendations[${index}] invalid object`);
6655
- continue;
6656
- }
6657
- const rec = item;
6658
- const action = normalizeRecommendationAction(rec.action);
6659
- const lesson = String(rec.lesson ?? rec.reason ?? "").trim();
6660
- const reason = String(rec.reason ?? lesson).trim();
6661
- if (!action || !reason) {
6662
- parsed.diagnostics.push(`curation_recommendations[${index}] missing action/reason`);
6663
- continue;
6664
- }
6665
- if (action === "rewrite" && lesson.length < 15) {
6666
- parsed.diagnostics.push(`curation_recommendations[${index}] rewrite missing lesson`);
6667
- continue;
6668
- }
6669
- parsed.recommendations.push({
6670
- action,
6671
- entry_id: typeof rec.entry_id === "string" && rec.entry_id.trim() ? rec.entry_id.trim() : undefined,
6672
- lesson: (lesson || reason).slice(0, 280),
6673
- reason: reason.slice(0, 280),
6674
- category: typeof rec.category === "string" ? rec.category : undefined,
6675
- confidence: typeof rec.confidence === "number" ? rec.confidence : undefined
6676
- });
6677
- }
6678
- }
6679
- if (Array.isArray(obj.queue_triage)) {
6680
- for (const [index, item] of obj.queue_triage.entries()) {
6681
- if (!item || typeof item !== "object") {
6682
- parsed.diagnostics.push(`queue_triage[${index}] invalid object`);
6683
- continue;
6684
- }
6685
- const triage = item;
6686
- const proposalId = String(triage.proposal_id ?? "").trim();
6687
- const action = String(triage.action ?? "").toLowerCase().trim();
6688
- if (!proposalId || action !== "apply" && action !== "reject") {
6689
- parsed.diagnostics.push(`queue_triage[${index}] missing proposal_id/action`);
6690
- continue;
6691
- }
6692
- parsed.queueTriage.push({
6693
- proposal_id: proposalId.slice(0, 120),
6694
- action,
6695
- reason: String(triage.reason ?? "").slice(0, 280)
6696
- });
6697
- }
6698
- }
6699
- }
6700
- return parsed;
6701
- }
6702
- function parseLegacyPostMortemActions(llmOutput) {
6703
- const parsed = {
6704
- summary: extractSection(llmOutput, "SUMMARY"),
6705
- recommendations: [],
6706
- queueTriage: [],
6707
- diagnostics: []
6708
- };
6709
- const curation = extractSection(llmOutput, "CURATION_RECOMMENDATIONS");
6710
- if (curation) {
6711
- let recIndex = 0;
6712
- for (const line of curation.split(`
6713
- `)) {
6714
- const trimmed = line.trim();
6715
- if (!trimmed.startsWith("-"))
6716
- continue;
6717
- const body = trimmed.replace(/^-\s*/, "");
6718
- const [head2, reasonPart = ""] = body.split(/\s+\u2014\s+|\s+-\s+/, 2);
6719
- const [rawAction, rest = ""] = head2.split(/:\s*/, 2);
6720
- const lowerRaw = rawAction.toLowerCase().trim();
6721
- const action = normalizeRecommendationAction(rawAction);
6722
- if (!action) {
6723
- if (lowerRaw === "merge") {
6724
- parsed.diagnostics.push("legacy curation_recommendations unsupported action 'merge' \u2014 dropped");
6725
- } else if (lowerRaw) {
6726
- parsed.diagnostics.push(`legacy curation_recommendations unrecognized action '${lowerRaw}'`);
6727
- }
6728
- continue;
6729
- }
6730
- const idMatch = rest.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);
6731
- const reason = (reasonPart || rest).trim();
6732
- if (!reason) {
6733
- parsed.diagnostics.push(`legacy curation_recommendations[${recIndex}] missing reason`);
6734
- continue;
6735
- }
6736
- parsed.recommendations.push({
6737
- action,
6738
- entry_id: idMatch?.[0],
6739
- lesson: reason.slice(0, 280),
6740
- reason: reason.slice(0, 280)
6741
- });
6742
- recIndex++;
6743
- }
6744
- }
6745
- const queue = extractSection(llmOutput, "QUEUE_TRIAGE");
6746
- if (queue) {
6747
- for (const line of queue.split(`
6748
- `)) {
6749
- const trimmed = line.trim();
6750
- if (!trimmed.startsWith("-"))
6751
- continue;
6752
- if (trimmed.includes(":")) {
6753
- const match = trimmed.match(/^-\s*([^:]+):\s*(APPLY|REJECT)\b\s*(?:\u2014|-)?\s*(.*)$/i);
6754
- if (!match) {
6755
- parsed.diagnostics.push("legacy queue_triage malformed line");
6756
- continue;
6757
- }
6758
- parsed.queueTriage.push({
6759
- proposal_id: match[1].trim().slice(0, 120),
6760
- action: match[2].toLowerCase(),
6761
- reason: match[3].trim().slice(0, 280)
6762
- });
6763
- }
6764
- }
6765
- }
6766
- return parsed;
6767
- }
6768
- function parsePostMortemActions(llmOutput) {
6769
- const structured = parseStructuredPostMortemActions(llmOutput);
6770
- const legacy = parseLegacyPostMortemActions(llmOutput);
6771
- return {
6772
- summary: structured.summary ?? legacy.summary,
6773
- recommendations: structured.recommendations.length > 0 ? structured.recommendations : legacy.recommendations,
6774
- queueTriage: structured.queueTriage.length > 0 ? structured.queueTriage : legacy.queueTriage,
6775
- diagnostics: [...structured.diagnostics, ...legacy.diagnostics]
6776
- };
6777
- }
6778
- async function executePostMortemActions(directory, parsed, options) {
6779
- const warnings = [];
6780
- const result = {
6781
- knowledge_applied: 0,
6782
- knowledge_skipped: 0,
6783
- hive_promotions: 0,
6784
- hive_encounters_incremented: 0,
6785
- hive_advancements: 0,
6786
- proposals_approved: 0,
6787
- proposals_rejected: 0,
6788
- proposals_skipped: 0
6789
- };
6790
- const knowledgeConfig = options.knowledgeConfig ?? await _internals7.loadDefaultKnowledgeConfig();
6791
- if (parsed.recommendations.length > 0) {
6792
- try {
6793
- const knowledgeResult = await _internals7.applyCuratorKnowledgeUpdates(directory, parsed.recommendations, knowledgeConfig);
6794
- result.knowledge_applied = knowledgeResult.applied;
6795
- result.knowledge_skipped = knowledgeResult.skipped;
6796
- } catch (err) {
6797
- warnings.push(`Post-mortem knowledge actions failed: ${err instanceof Error ? err.message : String(err)}`);
6798
- }
6799
- try {
6800
- const entries = await _internals7.readSwarmKnowledge(directory);
6801
- const hiveResult = await _internals7.checkHivePromotions(entries, knowledgeConfig);
6802
- result.hive_promotions = hiveResult.new_promotions;
6803
- result.hive_encounters_incremented = hiveResult.encounters_incremented;
6804
- result.hive_advancements = hiveResult.advancements;
6805
- } catch (err) {
6806
- warnings.push(`Post-mortem hive promotion check failed: ${err instanceof Error ? err.message : String(err)}`);
6807
- }
6808
- }
6809
- if (parsed.queueTriage.length > 0) {
6810
- try {
6811
- const proposalResult = await _internals7.applyProposalTriage(directory, parsed.queueTriage);
6812
- result.proposals_approved = proposalResult.approved.length;
6813
- result.proposals_rejected = proposalResult.rejected.length;
6814
- result.proposals_skipped = proposalResult.skipped.length;
6815
- } catch (err) {
6816
- warnings.push(`Post-mortem proposal triage failed: ${err instanceof Error ? err.message : String(err)}`);
6817
- }
6818
- }
6819
- return { result, warnings };
6820
- }
6821
- async function repairPostMortemActions(llmOutput, diagnostics, options) {
6822
- if (!options.llmDelegate || diagnostics.length === 0)
6823
- return null;
6824
- const ac = new AbortController;
6825
- const timer = setTimeout(() => ac.abort(), 30000);
6826
- try {
6827
- const repairPrompt = [
6828
- "Repair the supplied CURATOR_POSTMORTEM output into one valid fenced JSON block.",
6829
- "Return only this fence:",
6830
- "```json postmortem_actions",
6831
- '{"summary":"...","curation_recommendations":[],"queue_triage":[]}',
6832
- "```",
6833
- "Allowed curation action values: promote, archive, rewrite, flag_contradiction.",
6834
- "Allowed queue_triage action values: apply, reject.",
6835
- "Do not include unsupported actions such as merge.",
6836
- "Diagnostics:",
6837
- diagnostics.join("; "),
6838
- "Original output:",
6839
- llmOutput.slice(0, 8000)
6840
- ].join(`
6841
- `);
6842
- const repaired = await options.llmDelegate("", repairPrompt, ac.signal);
6843
- const parsed = _internals7.parsePostMortemActions(repaired);
6844
- if (parsed.diagnostics.length === 0) {
6845
- return parsed;
6846
- }
6847
- return null;
6848
- } catch {
6849
- return null;
6850
- } finally {
6851
- clearTimeout(timer);
6852
- }
6853
- }
6854
- function readJsonlFile(filePath, maxLines) {
6855
- try {
6856
- if (!existsSync7(filePath))
6857
- return [];
6858
- const content = readFileSync4(filePath, "utf-8");
6859
- const results = [];
6860
- const max = maxLines !== undefined && maxLines > 0 ? maxLines : Infinity;
6861
- for (const line of content.split(`
6862
- `)) {
6863
- if (results.length >= max)
6864
- break;
6865
- if (!line.trim())
6866
- continue;
6867
- try {
6868
- results.push(JSON.parse(line));
6869
- } catch {}
6870
- }
6871
- return results;
6872
- } catch {
6873
- return [];
6874
- }
6875
- }
6876
- function collectRetrospectives(directory) {
6877
- const results = [];
6878
- const evidenceDir = path12.join(directory, ".swarm", "evidence");
6879
- try {
6880
- if (!existsSync7(evidenceDir))
6881
- return results;
6882
- const retroDirs = readdirSync(evidenceDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("retro-")).slice(0, MAX_RETROSPECTIVES);
6883
- for (const entry of retroDirs) {
6884
- const retroPath = path12.join(evidenceDir, entry.name, "evidence.json");
6885
- if (existsSync7(retroPath)) {
6886
- try {
6887
- results.push(readFileSync4(retroPath, "utf-8"));
6888
- } catch {}
6889
- }
6890
- }
6891
- } catch {}
6892
- return results;
6893
- }
6894
- async function collectDriftReports(directory) {
6895
- try {
6896
- const reports = await _internals7.readPriorDriftReports(directory);
6897
- return reports.slice(-MAX_DRIFT_REPORTS).map((report) => JSON.stringify(report, null, 2));
6898
- } catch {
6899
- return [];
6900
- }
6901
- }
6902
- function collectPendingProposals(directory) {
6903
- const results = [];
6904
- const insightPath = path12.join(directory, ".swarm", "insight-candidates.jsonl");
6905
- if (existsSync7(insightPath)) {
6906
- try {
6907
- results.push({
6908
- source: "insight-candidates",
6909
- content: readFileSync4(insightPath, "utf-8")
6910
- });
6911
- } catch {}
6912
- }
6913
- const proposalsDir = path12.join(directory, ".swarm", "skills", "proposals");
6914
- try {
6915
- if (existsSync7(proposalsDir)) {
6916
- const proposalFiles = readdirSync(proposalsDir).filter((e) => e.endsWith(".md") || e.endsWith(".json")).slice(0, MAX_PROPOSALS);
6917
- for (const entry of proposalFiles) {
6918
- try {
6919
- results.push({
6920
- source: `proposals/${entry}`,
6921
- content: readFileSync4(path12.join(proposalsDir, entry), "utf-8")
6922
- });
6923
- } catch {}
6924
- }
6925
- }
6926
- } catch {}
6927
- return results;
6928
- }
6929
- function isReportValid(reportPath) {
6930
- try {
6931
- if (!existsSync7(reportPath))
6932
- return false;
6933
- const content = readFileSync4(reportPath, "utf-8").trim();
6934
- if (content.length === 0)
6935
- return false;
6936
- if (!content.startsWith("# Post-Mortem Report:"))
6937
- return false;
6938
- return true;
6939
- } catch {
6940
- return false;
6941
- }
6942
- }
6943
- async function acquirePostMortemLock(directory, planId) {
6944
- const result = await tryAcquireLock(directory, `post-mortem-${planId}.lock`, "curator-postmortem", planId);
6945
- if (result.acquired) {
6946
- return { acquired: true, release: result.lock?._release };
6947
- }
6948
- return { acquired: false };
6949
- }
6950
- function buildDataOnlyReport(planId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports) {
6951
- const now = new Date().toISOString();
6952
- const lines = [];
6953
- lines.push(`# Post-Mortem Report: ${planId}`);
6954
- lines.push(`Generated: ${now}`);
6955
- lines.push("");
6956
- lines.push("## Project Summary");
6957
- lines.push(planSummary);
6958
- lines.push("");
6959
- lines.push("## Knowledge Metrics");
6960
- const totalEntries = knowledgeSummary.length;
6961
- const totalApplied = knowledgeSummary.reduce((s, e) => s + e.applied, 0);
6962
- const totalViolated = knowledgeSummary.reduce((s, e) => s + e.violated, 0);
6963
- const totalIgnored = knowledgeSummary.reduce((s, e) => s + e.ignored, 0);
6964
- const neverApplied = knowledgeSummary.filter((e) => e.applied === 0 && e.violated === 0 && e.ignored === 0);
6965
- lines.push(`- Total entries: ${totalEntries}`);
6966
- lines.push(`- Application events: ${totalApplied} applied, ${totalViolated} violated, ${totalIgnored} ignored`);
6967
- lines.push(`- Never-applied entries: ${neverApplied.length}`);
6968
- if (totalApplied + totalViolated > 0) {
6969
- const appRate = (totalApplied / (totalApplied + totalViolated) * 100).toFixed(1);
6970
- lines.push(`- Application rate: ${appRate}%`);
6971
- }
6972
- lines.push("");
6973
- if (neverApplied.length > 0) {
6974
- lines.push("### Never-Applied Entries (review for retirement)");
6975
- for (const e of neverApplied.slice(0, 10)) {
6976
- lines.push(`- \`${e.id}\` (confidence: ${e.confidence.toFixed(2)}): ${e.lesson.slice(0, 80)}`);
6977
- }
6978
- if (neverApplied.length > 10) {
6979
- lines.push(`- ... and ${neverApplied.length - 10} more`);
6980
- }
6981
- lines.push("");
6982
- }
6983
- const highViolation = knowledgeSummary.filter((e) => e.violated > 0).sort((a, b) => b.violated - a.violated).slice(0, 5);
6984
- if (highViolation.length > 0) {
6985
- lines.push("### High-Violation Entries");
6986
- for (const e of highViolation) {
6987
- lines.push(`- \`${e.id}\` \u2014 ${e.violated} violations, ${e.applied} applied: ${e.lesson.slice(0, 80)}`);
6988
- }
6989
- lines.push("");
6990
- }
6991
- lines.push("## Queue Status");
6992
- lines.push(`- Pending proposals: ${proposals.length}`);
6993
- lines.push(`- Unactionable quarantine: ${unactionable.length}`);
6994
- for (const p of proposals) {
6995
- lines.push(` - ${p.source}`);
6996
- }
6997
- lines.push("");
6998
- if (retrospectives.length > 0) {
6999
- lines.push("## Retrospectives");
7000
- lines.push(`${retrospectives.length} phase retrospective(s) recorded.`);
7001
- lines.push("");
7002
- }
7003
- if (driftReports.length > 0) {
7004
- lines.push("## Drift Reports");
7005
- for (const dr of driftReports) {
7006
- try {
7007
- const parsed = JSON.parse(dr);
7008
- lines.push(`- Phase ${parsed.phase}: ${parsed.alignment} (score: ${parsed.drift_score})`);
7009
- } catch {
7010
- lines.push("- (unparseable drift report)");
7011
- }
7012
- }
7013
- lines.push("");
7014
- }
7015
- if (curatorDigest) {
7016
- lines.push("## Curator Digest Summary");
7017
- const trimmed = curatorDigest.length > 1000 ? `${curatorDigest.slice(0, 1000)}...` : curatorDigest;
7018
- lines.push(trimmed);
7019
- lines.push("");
7020
- }
7021
- return lines.join(`
7022
- `);
7023
- }
7024
- function assembleLLMInput(planId, scope, sessionID, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports) {
7025
- const sections = [];
7026
- sections.push(`TASK: CURATOR_POSTMORTEM ${planId}`);
7027
- sections.push(`SCOPE: ${scope}${sessionID ? ` (${sessionID})` : ""}`);
7028
- sections.push(`PLAN_SUMMARY: ${planSummary}`);
7029
- sections.push(`CURATOR_DIGESTS: ${curatorDigest ?? "none"}`);
7030
- const eventsSummary = knowledgeSummary.map((e) => `${e.id}: applied=${e.applied} violated=${e.violated} ignored=${e.ignored} confidence=${e.confidence.toFixed(2)} status=${e.status}`).join(`
7031
- `);
7032
- sections.push(`KNOWLEDGE_EVENTS_SUMMARY:
7033
- ${eventsSummary || "none"}`);
7034
- const knEntries = knowledgeSummary.map((e) => JSON.stringify({
7035
- id: e.id,
7036
- lesson: e.lesson.slice(0, MAX_INPUT_TEXT_CHARS)
7037
- })).join(`
7038
- `);
7039
- sections.push(`KNOWLEDGE_ENTRIES:
7040
- ${knEntries || "[]"}`);
7041
- const proposalText = proposals.length > 0 ? proposals.map((p) => `[${p.source}]
7042
- ${p.content.slice(0, MAX_INPUT_TEXT_CHARS)}`).join(`
7043
- ---
7044
- `) : "none";
7045
- sections.push(`PENDING_PROPOSALS:
7046
- ${proposalText}`);
7047
- sections.push(`UNACTIONABLE_QUARANTINE: ${unactionable.length} entries`);
7048
- const retroText = retrospectives.length > 0 ? retrospectives.map((r) => r.slice(0, MAX_INPUT_TEXT_CHARS)).join(`
7049
- ---
7050
- `) : "none";
7051
- sections.push(`RETROSPECTIVES:
7052
- ${retroText}`);
7053
- if (driftReports.length > 0) {
7054
- const driftText = driftReports.map((r) => r.slice(0, MAX_INPUT_TEXT_CHARS)).join(`
7055
- ---
7056
- `);
7057
- sections.push(`DRIFT_REPORTS:
7058
- ${driftText}`);
7059
- }
7060
- return sections.join(`
7061
-
7062
- `);
7063
- }
7064
- async function runCuratorPostMortem(directory, options = {}) {
7065
- const warnings = [];
7066
- const scope = options.scope ?? "project";
7067
- let planId = "unknown";
7068
- let planSummary = "Plan data unavailable.";
7069
- try {
7070
- const plan = await loadPlanJsonOnly(directory);
7071
- if (plan) {
7072
- planId = derivePlanId(plan);
7073
- const phaseCount = plan.phases?.length ?? 0;
7074
- const completedPhases = plan.phases?.filter((p) => p.status === "complete").length ?? 0;
7075
- planSummary = `Plan "${plan.title}" (${plan.swarm}): ${completedPhases}/${phaseCount} phases complete.`;
7076
- } else {
7077
- warnings.push("Plan not found \u2014 using fallback plan ID.");
7078
- }
7079
- } catch {
7080
- warnings.push("Failed to load plan data.");
7081
- }
7082
- const effectivePlanId = planId;
7083
- const reportFilename = `post-mortem-${effectivePlanId}.md`;
7084
- let reportPath;
7085
- try {
7086
- reportPath = validateSwarmPath(directory, reportFilename);
7087
- } catch {
7088
- return {
7089
- success: false,
7090
- planId,
7091
- reportPath: null,
7092
- summary: null,
7093
- warnings: [...warnings, "Invalid report path."]
7094
- };
7095
- }
7096
- if (!options.force && isReportValid(reportPath)) {
7097
- return {
7098
- success: true,
7099
- planId: effectivePlanId,
7100
- reportPath,
7101
- summary: "Post-mortem report already exists (idempotent skip).",
7102
- warnings
7103
- };
7104
- }
7105
- const lock = await _internals7.acquirePostMortemLock(directory, effectivePlanId);
7106
- if (!lock.acquired) {
7107
- return {
7108
- success: false,
7109
- planId: effectivePlanId,
7110
- reportPath,
7111
- summary: null,
7112
- warnings: [
7113
- ...warnings,
7114
- `Concurrent post-mortem run in progress for plan ${effectivePlanId}; skipped.`
7115
- ]
7116
- };
7117
- }
7118
- try {
7119
- let knowledgeSummary = [];
7120
- try {
7121
- knowledgeSummary = await collectKnowledgeSummary(directory, scope, options.sessionID);
7122
- } catch {
7123
- warnings.push("Failed to collect knowledge summary.");
7124
- }
7125
- if (knowledgeSummary.length > MAX_KNOWLEDGE_ENTRIES) {
7126
- warnings.push(`Knowledge entries capped at ${MAX_KNOWLEDGE_ENTRIES} (had ${knowledgeSummary.length}); older entries truncated.`);
7127
- knowledgeSummary = knowledgeSummary.slice(0, MAX_KNOWLEDGE_ENTRIES);
7128
- }
7129
- let curatorDigest = null;
7130
- try {
7131
- const raw = await readSwarmFileAsync(directory, "curator-summary.json");
7132
- if (raw) {
7133
- const parsed = JSON.parse(raw);
7134
- curatorDigest = parsed.digest ?? null;
7135
- }
7136
- } catch {
7137
- warnings.push("Failed to read curator digest.");
7138
- }
7139
- let proposals = collectPendingProposals(directory);
7140
- if (proposals.length > MAX_PROPOSALS) {
7141
- warnings.push(`Pending proposals capped at ${MAX_PROPOSALS} (had ${proposals.length}); older entries truncated.`);
7142
- proposals = proposals.slice(0, MAX_PROPOSALS);
7143
- }
7144
- const unactionablePath = path12.join(resolveKnowledgeStoreDir(directory), "knowledge-unactionable.jsonl");
7145
- let unactionable = readJsonlFile(unactionablePath, MAX_UNACTIONABLE);
7146
- if (unactionable.length > MAX_UNACTIONABLE) {
7147
- warnings.push(`Unactionable entries capped at ${MAX_UNACTIONABLE} (had ${unactionable.length}); older entries truncated.`);
7148
- unactionable = unactionable.slice(0, MAX_UNACTIONABLE);
7149
- }
7150
- let retrospectives = collectRetrospectives(directory);
7151
- if (retrospectives.length > MAX_RETROSPECTIVES) {
7152
- warnings.push(`Retrospectives capped at ${MAX_RETROSPECTIVES} (had ${retrospectives.length}); older entries truncated.`);
7153
- retrospectives = retrospectives.slice(0, MAX_RETROSPECTIVES);
7154
- }
7155
- let driftReports = await collectDriftReports(directory);
7156
- if (driftReports.length > MAX_DRIFT_REPORTS) {
7157
- warnings.push(`Drift reports capped at ${MAX_DRIFT_REPORTS} (had ${driftReports.length}); older entries truncated.`);
7158
- driftReports = driftReports.slice(0, MAX_DRIFT_REPORTS);
7159
- }
7160
- let reportContent;
7161
- let llmSummary = null;
7162
- let actionResult;
7163
- if (options.llmDelegate) {
7164
- try {
7165
- const { CURATOR_POSTMORTEM_PROMPT } = await import("./explorer-ksr3xq7n.js");
7166
- const userInput = assembleLLMInput(effectivePlanId, scope, options.sessionID, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
7167
- const ac = new AbortController;
7168
- const timer = setTimeout(() => ac.abort(), options.llmTimeoutMs ?? 300000);
7169
- let llmOutput;
7170
- try {
7171
- const delegatePromise = options.llmDelegate(CURATOR_POSTMORTEM_PROMPT, userInput, ac.signal);
7172
- delegatePromise.catch(() => {});
7173
- llmOutput = await Promise.race([
7174
- delegatePromise,
7175
- new Promise((_, reject) => {
7176
- ac.signal.addEventListener("abort", () => reject(new Error("CURATOR_LLM_TIMEOUT")));
7177
- })
7178
- ]);
7179
- } finally {
7180
- clearTimeout(timer);
7181
- }
7182
- let parsedActions = _internals7.parsePostMortemActions(llmOutput);
7183
- if (parsedActions.diagnostics.length > 0) {
7184
- warnings.push(`Post-mortem structured action parse diagnostics: ${parsedActions.diagnostics.join("; ")}`);
7185
- const repaired = await _internals7.repairPostMortemActions(llmOutput, parsedActions.diagnostics, options);
7186
- if (repaired) {
7187
- parsedActions = repaired;
7188
- warnings.push("Post-mortem structured actions repaired by LLM.");
7189
- }
7190
- }
7191
- llmSummary = parsedActions.summary;
7192
- const executed = await _internals7.executePostMortemActions(directory, parsedActions, options);
7193
- actionResult = executed.result;
7194
- warnings.push(...executed.warnings);
7195
- const actionSummary = [
7196
- "## Executed Post-Mortem Actions",
7197
- `- Knowledge actions: ${actionResult.knowledge_applied} applied, ${actionResult.knowledge_skipped} skipped`,
7198
- `- Hive actions: ${actionResult.hive_promotions} new promotions, ${actionResult.hive_encounters_incremented} encounters incremented, ${actionResult.hive_advancements} advancements`,
7199
- `- Proposal actions: ${actionResult.proposals_approved} approved, ${actionResult.proposals_rejected} rejected, ${actionResult.proposals_skipped} skipped`
7200
- ].join(`
7201
- `);
7202
- reportContent = `# Post-Mortem Report: ${effectivePlanId}
7203
- Generated: ${new Date().toISOString()}
7204
- Scope: ${scope}
7205
-
7206
- ${llmOutput}
7207
-
7208
- ${actionSummary}`;
7209
- } catch (err) {
7210
- const msg = err instanceof Error ? err.message : String(err);
7211
- warnings.push(`LLM delegate failed, falling back to data-only report: ${msg}`);
7212
- reportContent = _internals7.buildDataOnlyReport(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
7213
- }
7214
- } else {
7215
- reportContent = _internals7.buildDataOnlyReport(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
7216
- }
7217
- try {
7218
- const { mkdirSync: mkdirSync6 } = await import("fs");
7219
- mkdirSync6(path12.dirname(reportPath), { recursive: true });
7220
- await atomicWriteFile(reportPath, reportContent);
7221
- } catch (err) {
7222
- const msg = err instanceof Error ? err.message : String(err);
7223
- return {
7224
- success: false,
7225
- planId: effectivePlanId,
7226
- reportPath: null,
7227
- summary: null,
7228
- warnings: [...warnings, `Failed to write report: ${msg}`]
7229
- };
7230
- }
7231
- const totalEntries = knowledgeSummary.length;
7232
- const neverAppliedCount = knowledgeSummary.filter((e) => e.applied === 0 && e.violated === 0 && e.ignored === 0).length;
7233
- const totalViolations = knowledgeSummary.reduce((s, e) => s + e.violated, 0);
7234
- const mechanicalSummary = [
7235
- `Post-mortem for plan "${effectivePlanId}": ${totalEntries} knowledge entries reviewed.`,
7236
- `${neverAppliedCount} never-applied entries flagged; ${totalViolations} total violations recorded.`,
7237
- `${proposals.length} pending proposals, ${unactionable.length} quarantined entries.`
7238
- ].join(" ");
7239
- const summary = llmSummary ?? mechanicalSummary;
7240
- return {
7241
- success: true,
7242
- planId: effectivePlanId,
7243
- reportPath,
7244
- summary,
7245
- warnings,
7246
- actions: actionResult
7247
- };
7248
- } finally {
7249
- if (lock.release) {
7250
- try {
7251
- await lock.release();
7252
- } catch {}
7253
- }
7254
- }
7255
- }
7256
- var _internals7 = {
7257
- acquirePostMortemLock,
7258
- collectKnowledgeSummary,
7259
- collectRetrospectives,
7260
- collectDriftReports,
7261
- collectPendingProposals,
7262
- readJsonlFile,
7263
- buildDataOnlyReport,
7264
- assembleLLMInput,
7265
- isReportValid,
7266
- parsePostMortemActions,
7267
- executePostMortemActions,
7268
- repairPostMortemActions,
7269
- loadDefaultKnowledgeConfig: async () => {
7270
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-5vmb5dh8.js");
7271
- return KnowledgeConfigSchema2.parse({});
7272
- },
7273
- applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig) => {
7274
- const { applyCuratorKnowledgeUpdates } = await import("./curator-4qqzpd85.js");
7275
- return applyCuratorKnowledgeUpdates(directory, recommendations, knowledgeConfig);
7276
- },
7277
- checkHivePromotions: async (entries, knowledgeConfig) => {
7278
- const { checkHivePromotions } = await import("./hive-promoter-wvxqyayt.js");
7279
- return checkHivePromotions(entries, knowledgeConfig);
7280
- },
7281
- applyProposalTriage: async (directory, triage) => {
7282
- const {
7283
- _internals: skillInternals,
7284
- activateProposal,
7285
- listSkills: listSkills2,
7286
- sanitizeSlug
7287
- } = await import("./skill-generator-mjfqvnn0.js");
7288
- const result = {
7289
- approved: [],
7290
- rejected: [],
7291
- skipped: []
7292
- };
7293
- const skills = await listSkills2(directory);
7294
- const proposalSlugs = new Set(skills.proposals.map((p) => p.slug));
7295
- for (const item of triage) {
7296
- const slug = sanitizeSlug(normalizeProposalSlug(item.proposal_id));
7297
- if (!slug || !proposalSlugs.has(slug)) {
7298
- result.skipped.push(slug || item.proposal_id);
7299
- continue;
7300
- }
7301
- if (item.action === "apply") {
7302
- const activation = await activateProposal(directory, slug, false, {
7303
- evaluate: true,
7304
- operation: "post_mortem_queue_triage",
7305
- confirmUnevaluated: true
7306
- });
7307
- if (activation.activated) {
7308
- result.approved.push(slug);
7309
- } else {
7310
- result.skipped.push(slug);
7311
- }
7312
- continue;
7313
- }
7314
- const proposal = skills.proposals.find((p) => p.slug === slug);
7315
- if (!proposal) {
7316
- result.skipped.push(slug);
7317
- continue;
7318
- }
7319
- try {
7320
- skillInternals.unlinkSync(proposal.path);
7321
- result.rejected.push(slug);
7322
- } catch {
7323
- result.skipped.push(slug);
7324
- }
7325
- }
7326
- return result;
7327
- },
7328
- readPriorDriftReports: async (directory) => {
7329
- const { readPriorDriftReports } = await import("./curator-drift-169wgaxn.js");
7330
- return readPriorDriftReports(directory);
7331
- },
7332
- readSwarmKnowledge: (directory) => readKnowledge(resolveSwarmKnowledgePath(directory))
7333
- };
7334
-
7335
- // src/hooks/hive-promoter.ts
7336
- import path17 from "path";
6574
+ import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
6575
+ import * as path16 from "path";
7337
6576
 
7338
6577
  // src/hooks/curator.ts
7339
6578
  import { randomUUID as randomUUID5 } from "crypto";
7340
6579
  import * as fs5 from "fs";
7341
- import * as path16 from "path";
6580
+ import * as path15 from "path";
7342
6581
 
7343
6582
  // src/services/learning-metrics.ts
7344
6583
  var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
@@ -7751,9 +6990,9 @@ import { readFile as readFile5, rename as rename4, writeFile as writeFile5 } fro
7751
6990
 
7752
6991
  // src/services/skill-improver-quota.ts
7753
6992
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
7754
- import { existsSync as existsSync8 } from "fs";
6993
+ import { existsSync as existsSync7 } from "fs";
7755
6994
  import { mkdir as mkdir4, readFile as readFile4, rename as rename3, writeFile as writeFile4 } from "fs/promises";
7756
- import * as path13 from "path";
6995
+ import * as path12 from "path";
7757
6996
  var LOCK_ACQUIRE_TIMEOUT_MS = 1e4;
7758
6997
  var LOCK_RETRY_OPTS = {
7759
6998
  retries: {
@@ -7782,7 +7021,7 @@ async function acquireLock(dir) {
7782
7021
  }
7783
7022
  function resolveQuotaPath(directory, scope = "skill-improver") {
7784
7023
  const fileName = scope === "knowledge-enrichment" ? "knowledge-enrichment-quota.json" : "skill-improver-quota.json";
7785
- return path13.join(directory, ".swarm", fileName);
7024
+ return path12.join(directory, ".swarm", fileName);
7786
7025
  }
7787
7026
  function todayKey(window, now = new Date) {
7788
7027
  if (window === "utc") {
@@ -7794,7 +7033,7 @@ function todayKey(window, now = new Date) {
7794
7033
  return `${yr}-${m}-${d}`;
7795
7034
  }
7796
7035
  async function readState(filePath) {
7797
- if (!existsSync8(filePath))
7036
+ if (!existsSync7(filePath))
7798
7037
  return null;
7799
7038
  try {
7800
7039
  const raw = await readFile4(filePath, "utf-8");
@@ -7808,7 +7047,7 @@ async function readState(filePath) {
7808
7047
  }
7809
7048
  }
7810
7049
  async function writeState(filePath, state) {
7811
- await mkdir4(path13.dirname(filePath), { recursive: true });
7050
+ await mkdir4(path12.dirname(filePath), { recursive: true });
7812
7051
  const tmp = `${filePath}.tmp-${process.pid}`;
7813
7052
  await writeFile4(tmp, JSON.stringify(state, null, 2), "utf-8");
7814
7053
  await rename3(tmp, filePath);
@@ -7831,10 +7070,10 @@ async function getQuotaState(directory, opts) {
7831
7070
  }
7832
7071
  async function reserveQuota(directory, opts) {
7833
7072
  const filePath = resolveQuotaPath(directory, opts.scope);
7834
- await mkdir4(path13.dirname(filePath), { recursive: true });
7073
+ await mkdir4(path12.dirname(filePath), { recursive: true });
7835
7074
  let release = null;
7836
7075
  try {
7837
- release = await acquireLock(path13.dirname(filePath));
7076
+ release = await acquireLock(path12.dirname(filePath));
7838
7077
  const state = await getQuotaState(directory, opts);
7839
7078
  if (state.calls_used + opts.nCalls > opts.maxCalls) {
7840
7079
  return {
@@ -7861,10 +7100,10 @@ async function reserveQuota(directory, opts) {
7861
7100
  }
7862
7101
  async function releaseQuota(directory, opts) {
7863
7102
  const filePath = resolveQuotaPath(directory, opts.scope);
7864
- await mkdir4(path13.dirname(filePath), { recursive: true });
7103
+ await mkdir4(path12.dirname(filePath), { recursive: true });
7865
7104
  let release = null;
7866
7105
  try {
7867
- release = await acquireLock(path13.dirname(filePath));
7106
+ release = await acquireLock(path12.dirname(filePath));
7868
7107
  const state = await getQuotaState(directory, opts);
7869
7108
  const next = {
7870
7109
  ...state,
@@ -8015,7 +7254,7 @@ async function reviseSkill(params) {
8015
7254
  }
8016
7255
  if (!params.delegate) {
8017
7256
  try {
8018
- const revised = _internals8.buildDeterministicRevision(params.currentContent, params.currentVersion, params.violationContexts);
7257
+ const revised = _internals7.buildDeterministicRevision(params.currentContent, params.currentVersion, params.violationContexts);
8019
7258
  const validation = await validateRevisionCandidate(params, revised, "skill_reviser:deterministic");
8020
7259
  if (!validation.passed) {
8021
7260
  return {
@@ -8142,7 +7381,7 @@ async function reviseSkill(params) {
8142
7381
  };
8143
7382
  }
8144
7383
  }
8145
- var _internals8 = {
7384
+ var _internals7 = {
8146
7385
  reviseSkill,
8147
7386
  getSkillVersion,
8148
7387
  buildDeterministicRevision,
@@ -8157,7 +7396,7 @@ var _internals8 = {
8157
7396
  init_logger();
8158
7397
 
8159
7398
  // src/hooks/skill-invalidator.ts
8160
- import * as path14 from "path";
7399
+ import * as path13 from "path";
8161
7400
  init_logger();
8162
7401
  async function writeArchiveTombstoneAndInvalidateSkills(ctx) {
8163
7402
  const label = ctx.sourceLabel ?? "skill-invalidator";
@@ -8191,7 +7430,7 @@ async function writeArchiveTombstoneAndInvalidateSkills(ctx) {
8191
7430
  let retiredCount = 0;
8192
7431
  let staleCount = 0;
8193
7432
  for (const skillDir of allSkillDirs) {
8194
- const slug = path14.basename(skillDir);
7433
+ const slug = path13.basename(skillDir);
8195
7434
  if (slugSet.has(slug))
8196
7435
  continue;
8197
7436
  slugSet.add(slug);
@@ -8218,14 +7457,14 @@ async function writeArchiveTombstoneAndInvalidateSkills(ctx) {
8218
7457
  // src/hooks/skill-usage-log.ts
8219
7458
  import * as crypto2 from "crypto";
8220
7459
  import * as fs4 from "fs";
8221
- import * as path15 from "path";
7460
+ import * as path14 from "path";
8222
7461
  function resolveLogPath(directory) {
8223
7462
  return validateSwarmPath(directory, "skill-usage.jsonl");
8224
7463
  }
8225
7464
  function normalizeComplianceVerdict(verdict) {
8226
7465
  return verdict === "violation" ? "violated" : verdict;
8227
7466
  }
8228
- var _internals9 = {
7467
+ var _internals8 = {
8229
7468
  generateId: () => crypto2.randomUUID(),
8230
7469
  appendFileSync: fs4.appendFileSync.bind(fs4),
8231
7470
  readFileSync: fs4.readFileSync.bind(fs4),
@@ -8295,9 +7534,9 @@ function parseFeedbackMarker(raw) {
8295
7534
  function readFeedbackAppliedEntryIds(directory) {
8296
7535
  const resolved = resolveLogPath(directory);
8297
7536
  const processed = new Set;
8298
- if (!_internals9.existsSync(resolved))
7537
+ if (!_internals8.existsSync(resolved))
8299
7538
  return processed;
8300
- const raw = _internals9.readFileSync(resolved, "utf-8");
7539
+ const raw = _internals8.readFileSync(resolved, "utf-8");
8301
7540
  for (const line of raw.split(`
8302
7541
  `)) {
8303
7542
  const trimmed = line.trim();
@@ -8317,16 +7556,16 @@ function appendFeedbackAppliedMarker(directory, processedEntryIds) {
8317
7556
  if (processedEntryIds.length === 0)
8318
7557
  return;
8319
7558
  const resolved = resolveLogPath(directory);
8320
- const dir = path15.dirname(resolved);
8321
- if (!_internals9.existsSync(dir)) {
8322
- _internals9.mkdirSync(dir, { recursive: true });
7559
+ const dir = path14.dirname(resolved);
7560
+ if (!_internals8.existsSync(dir)) {
7561
+ _internals8.mkdirSync(dir, { recursive: true });
8323
7562
  }
8324
7563
  const marker = {
8325
7564
  type: "feedback_applied",
8326
7565
  timestamp: new Date().toISOString(),
8327
7566
  processedEntryIds: [...new Set(processedEntryIds)]
8328
7567
  };
8329
- _internals9.appendFileSync(resolved, `${JSON.stringify(marker)}
7568
+ _internals8.appendFileSync(resolved, `${JSON.stringify(marker)}
8330
7569
  `, "utf-8");
8331
7570
  }
8332
7571
  function appendSkillUsageEntry(directory, entry) {
@@ -8362,12 +7601,12 @@ function appendSkillUsageEntry(directory, entry) {
8362
7601
  throw new Error("sessionID is required and must be a non-empty string");
8363
7602
  }
8364
7603
  const resolved = validateSwarmPath(directory, "skill-usage.jsonl");
8365
- const dir = path15.dirname(resolved);
8366
- if (!_internals9.existsSync(dir)) {
8367
- _internals9.mkdirSync(dir, { recursive: true });
7604
+ const dir = path14.dirname(resolved);
7605
+ if (!_internals8.existsSync(dir)) {
7606
+ _internals8.mkdirSync(dir, { recursive: true });
8368
7607
  }
8369
7608
  const fullEntry = {
8370
- id: _internals9.generateId(),
7609
+ id: _internals8.generateId(),
8371
7610
  skillPath,
8372
7611
  agentName,
8373
7612
  taskID,
@@ -8377,21 +7616,21 @@ function appendSkillUsageEntry(directory, entry) {
8377
7616
  ...reviewerNotes !== undefined && { reviewerNotes },
8378
7617
  ...skillVersion !== undefined && { skillVersion }
8379
7618
  };
8380
- _internals9.appendFileSync(resolved, `${JSON.stringify(fullEntry)}
7619
+ _internals8.appendFileSync(resolved, `${JSON.stringify(fullEntry)}
8381
7620
  `, "utf-8");
8382
7621
  try {
8383
- const stat3 = _internals9.statSync(resolved);
7622
+ const stat3 = _internals8.statSync(resolved);
8384
7623
  if (stat3.size > SKILL_USAGE_LOG_ROTATE_BYTES) {
8385
- _internals9.pruneSkillUsageLog(directory, SKILL_USAGE_LOG_MAX_ENTRIES_PER_SKILL);
7624
+ _internals8.pruneSkillUsageLog(directory, SKILL_USAGE_LOG_MAX_ENTRIES_PER_SKILL);
8386
7625
  }
8387
7626
  } catch {}
8388
7627
  }
8389
7628
  function readSkillUsageEntries(directory, options) {
8390
7629
  const resolved = resolveLogPath(directory);
8391
- if (!_internals9.existsSync(resolved)) {
7630
+ if (!_internals8.existsSync(resolved)) {
8392
7631
  return [];
8393
7632
  }
8394
- const raw = _internals9.readFileSync(resolved, "utf-8");
7633
+ const raw = _internals8.readFileSync(resolved, "utf-8");
8395
7634
  const entries = [];
8396
7635
  for (const line of raw.split(`
8397
7636
  `)) {
@@ -8434,20 +7673,20 @@ var SKILL_USAGE_LOG_ROTATE_BYTES = 1024 * 1024;
8434
7673
  var SKILL_USAGE_LOG_MAX_ENTRIES_PER_SKILL = 500;
8435
7674
  function readSkillUsageEntriesTail(directory, filters, maxBytes = TAIL_BYTES_DEFAULT) {
8436
7675
  const logPath = resolveLogPath(directory);
8437
- if (!_internals9.existsSync(logPath))
7676
+ if (!_internals8.existsSync(logPath))
8438
7677
  return [];
8439
7678
  try {
8440
7679
  const normalizedMaxBytes = Number.isFinite(maxBytes) ? maxBytes : TAIL_BYTES_DEFAULT;
8441
7680
  const boundedMaxBytes = Math.min(Math.max(1, normalizedMaxBytes), MAX_TAIL_BYTES);
8442
- const stat3 = _internals9.statSync(logPath);
7681
+ const stat3 = _internals8.statSync(logPath);
8443
7682
  const start = Math.max(0, stat3.size - boundedMaxBytes);
8444
- const fd = _internals9.openSync(logPath, "r");
7683
+ const fd = _internals8.openSync(logPath, "r");
8445
7684
  try {
8446
7685
  const readLen = stat3.size - start;
8447
7686
  if (readLen === 0)
8448
7687
  return [];
8449
7688
  const buf = Buffer.alloc(readLen);
8450
- _internals9.readSync(fd, buf, 0, buf.length, start);
7689
+ _internals8.readSync(fd, buf, 0, buf.length, start);
8451
7690
  const content = buf.toString("utf-8");
8452
7691
  let usable;
8453
7692
  if (start > 0) {
@@ -8474,7 +7713,7 @@ function readSkillUsageEntriesTail(directory, filters, maxBytes = TAIL_BYTES_DEF
8474
7713
  }
8475
7714
  return entries;
8476
7715
  } finally {
8477
- _internals9.closeSync(fd);
7716
+ _internals8.closeSync(fd);
8478
7717
  }
8479
7718
  } catch {
8480
7719
  return [];
@@ -8511,10 +7750,10 @@ function computeComplianceByVersion(entries, skillPath) {
8511
7750
  }
8512
7751
  function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
8513
7752
  const resolved = resolveLogPath(directory);
8514
- if (!_internals9.existsSync(resolved)) {
7753
+ if (!_internals8.existsSync(resolved)) {
8515
7754
  return { pruned: 0, remaining: 0 };
8516
7755
  }
8517
- const raw = _internals9.readFileSync(resolved, "utf-8");
7756
+ const raw = _internals8.readFileSync(resolved, "utf-8");
8518
7757
  const lines = raw.split(`
8519
7758
  `);
8520
7759
  const entries = [];
@@ -8538,19 +7777,19 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
8538
7777
  }
8539
7778
  if (entries.length === 0) {
8540
7779
  if (preservedMarkers.length > 0) {
8541
- const dir2 = path15.dirname(resolved);
8542
- const tmpPath2 = path15.join(dir2, `skill-usage-${Date.now()}.tmp`);
7780
+ const dir2 = path14.dirname(resolved);
7781
+ const tmpPath2 = path14.join(dir2, `skill-usage-${Date.now()}.tmp`);
8543
7782
  const content2 = preservedMarkers.join(`
8544
7783
  `).concat(preservedMarkers.length > 0 ? `
8545
7784
  ` : "");
8546
7785
  try {
8547
- _internals9.writeFileSync(tmpPath2, content2, "utf-8");
8548
- _internals9.renameSync(tmpPath2, resolved);
7786
+ _internals8.writeFileSync(tmpPath2, content2, "utf-8");
7787
+ _internals8.renameSync(tmpPath2, resolved);
8549
7788
  } catch (writeErr) {
8550
7789
  const msg = writeErr instanceof Error ? writeErr.message : String(writeErr);
8551
7790
  try {
8552
- if (_internals9.existsSync(tmpPath2)) {
8553
- _internals9.writeFileSync(tmpPath2, "", "utf-8");
7791
+ if (_internals8.existsSync(tmpPath2)) {
7792
+ _internals8.writeFileSync(tmpPath2, "", "utf-8");
8554
7793
  }
8555
7794
  } catch {}
8556
7795
  return { pruned: 0, remaining: 0, error: msg };
@@ -8581,21 +7820,21 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
8581
7820
  if (pruned === 0) {
8582
7821
  return { pruned: 0, remaining: entries.length };
8583
7822
  }
8584
- const dir = path15.dirname(resolved);
8585
- const tmpPath = path15.join(dir, `skill-usage-${Date.now()}.tmp`);
7823
+ const dir = path14.dirname(resolved);
7824
+ const tmpPath = path14.join(dir, `skill-usage-${Date.now()}.tmp`);
8586
7825
  const entryLines = surviving.map((e) => JSON.stringify(e));
8587
7826
  const allLines = [...entryLines, ...preservedMarkers];
8588
7827
  const content = allLines.join(`
8589
7828
  `).concat(`
8590
7829
  `);
8591
7830
  try {
8592
- _internals9.writeFileSync(tmpPath, content, "utf-8");
8593
- _internals9.renameSync(tmpPath, resolved);
7831
+ _internals8.writeFileSync(tmpPath, content, "utf-8");
7832
+ _internals8.renameSync(tmpPath, resolved);
8594
7833
  } catch (writeErr) {
8595
7834
  const msg = writeErr instanceof Error ? writeErr.message : String(writeErr);
8596
7835
  try {
8597
- if (_internals9.existsSync(tmpPath)) {
8598
- _internals9.writeFileSync(tmpPath, "", "utf-8");
7836
+ if (_internals8.existsSync(tmpPath)) {
7837
+ _internals8.writeFileSync(tmpPath, "", "utf-8");
8599
7838
  }
8600
7839
  } catch {}
8601
7840
  return { pruned: 0, remaining: entries.length, error: msg };
@@ -8611,16 +7850,16 @@ async function resolveSourceKnowledgeIds(directory, skillPath) {
8611
7850
  if (/\.\.[/\\]/.test(cleanPath)) {
8612
7851
  return [];
8613
7852
  }
8614
- const absolute = path15.normalize(path15.isAbsolute(cleanPath) ? cleanPath : path15.resolve(directory, cleanPath));
8615
- const baseDir = path15.normalize(path15.resolve(directory));
8616
- const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir + path15.sep).toLowerCase()) : absolute.startsWith(baseDir + path15.sep);
7853
+ const absolute = path14.normalize(path14.isAbsolute(cleanPath) ? cleanPath : path14.resolve(directory, cleanPath));
7854
+ const baseDir = path14.normalize(path14.resolve(directory));
7855
+ const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir + path14.sep).toLowerCase()) : absolute.startsWith(baseDir + path14.sep);
8617
7856
  if (!isContained) {
8618
7857
  return [];
8619
7858
  }
8620
- if (!_internals9.existsSync(absolute)) {
7859
+ if (!_internals8.existsSync(absolute)) {
8621
7860
  return [];
8622
7861
  }
8623
- const content = _internals9.readFileSync(absolute, "utf-8");
7862
+ const content = _internals8.readFileSync(absolute, "utf-8");
8624
7863
  return parseGeneratedFromKnowledge(content);
8625
7864
  } catch (err) {
8626
7865
  console.warn("[skill-usage-log] resolveSourceKnowledgeIds failed (fail-open):", err instanceof Error ? err.message : String(err));
@@ -8728,7 +7967,7 @@ var DEFAULT_CURATOR_LLM_TIMEOUT_MS = 300000;
8728
7967
  var MAX_CURATOR_PHASE_DIGESTS = 50;
8729
7968
  var MAX_CURATOR_COMPLIANCE_OBSERVATIONS = 200;
8730
7969
  var MAX_CURATOR_RECOMMENDATIONS = 200;
8731
- var _internals10 = {
7970
+ var _internals9 = {
8732
7971
  parseKnowledgeRecommendations,
8733
7972
  parseKnowledgeRecommendationsWithDiagnostics,
8734
7973
  readCuratorSummary,
@@ -8749,6 +7988,37 @@ var _internals10 = {
8749
7988
  getSkillVersion,
8750
7989
  readLatestPostMortemDigest: (directory) => readLatestPostMortemDigest(directory)
8751
7990
  };
7991
+ var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
7992
+ var HEX_ID_PREFIX = /^[0-9a-f]{8,}$/i;
7993
+ function normalizeRecommendationEntryIdToken(token) {
7994
+ const trimmed = token.trim();
7995
+ if (UUID_V4.test(trimmed) || HEX_ID_PREFIX.test(trimmed))
7996
+ return trimmed;
7997
+ return;
7998
+ }
7999
+ function resolveKnowledgeRecommendationIds(recommendations, entries) {
8000
+ const diagnostics = [];
8001
+ const activeEntries = entries.filter((entry) => isActiveStatus(entry.status));
8002
+ const resolved = recommendations.map((recommendation) => {
8003
+ const entryId = typeof recommendation.entry_id === "string" ? normalizeRecommendationEntryIdToken(recommendation.entry_id) : undefined;
8004
+ if (!entryId)
8005
+ return recommendation;
8006
+ if (activeEntries.some((entry) => entry.id === entryId)) {
8007
+ return { ...recommendation, entry_id: entryId };
8008
+ }
8009
+ const matches = activeEntries.filter((entry) => entry.id.startsWith(entryId));
8010
+ if (matches.length === 1) {
8011
+ return { ...recommendation, entry_id: matches[0].id };
8012
+ }
8013
+ diagnostics.push({
8014
+ section: "RECOMMENDATION_ID",
8015
+ line: entryId,
8016
+ reason: matches.length === 0 ? "entry_id not found" : "entry_id prefix is ambiguous"
8017
+ });
8018
+ return null;
8019
+ }).filter((rec) => rec !== null);
8020
+ return { recommendations: resolved, diagnostics };
8021
+ }
8752
8022
  function capPhaseDigests(digests) {
8753
8023
  return digests.slice(-MAX_CURATOR_PHASE_DIGESTS);
8754
8024
  }
@@ -8767,9 +8037,9 @@ ${digest.summary}`).join(`
8767
8037
  async function autoRetireSkills(directory, _curatorKnowledgePath, excludeSlugs) {
8768
8038
  const observations = [];
8769
8039
  try {
8770
- const skillListResult = await _internals10.listSkills(directory);
8771
- const usageEntries = _internals10.readSkillUsageEntries(directory);
8772
- const allArchivedIds = await _internals10.getArchivedKnowledgeIds(directory);
8040
+ const skillListResult = await _internals9.listSkills(directory);
8041
+ const usageEntries = _internals9.readSkillUsageEntries(directory);
8042
+ const allArchivedIds = await _internals9.getArchivedKnowledgeIds(directory);
8773
8043
  for (const active of skillListResult.active) {
8774
8044
  if (excludeSlugs?.has(active.slug))
8775
8045
  continue;
@@ -8791,7 +8061,7 @@ async function autoRetireSkills(directory, _curatorKnowledgePath, excludeSlugs)
8791
8061
  const violationRate = skillUsage.length > 0 ? violations / skillUsage.length : 0;
8792
8062
  if (violationRate > 0.3) {
8793
8063
  const reason = `auto-retire: violation rate ${(violationRate * 100).toFixed(0)}% exceeds 30% threshold`;
8794
- await _internals10.retireSkill(directory, active.slug, reason);
8064
+ await _internals9.retireSkill(directory, active.slug, reason);
8795
8065
  observations.push(`Skill '${active.slug}' auto-retired: ${reason}`);
8796
8066
  warn(`[curator] ${observations[observations.length - 1]}`);
8797
8067
  continue;
@@ -8799,15 +8069,15 @@ async function autoRetireSkills(directory, _curatorKnowledgePath, excludeSlugs)
8799
8069
  let archivedSourceMatched = false;
8800
8070
  if (allArchivedIds.size > 0) {
8801
8071
  try {
8802
- const content = await _internals10.readFileAsync(active.path, "utf-8");
8803
- const sourceIds = _internals10.parseDraftFrontmatter(content)?.sourceKnowledgeIds ?? [];
8072
+ const content = await _internals9.readFileAsync(active.path, "utf-8");
8073
+ const sourceIds = _internals9.parseDraftFrontmatter(content)?.sourceKnowledgeIds ?? [];
8804
8074
  archivedSourceMatched = sourceIds.some((id) => allArchivedIds.has(id));
8805
8075
  } catch {
8806
8076
  archivedSourceMatched = false;
8807
8077
  }
8808
8078
  }
8809
8079
  if (archivedSourceMatched) {
8810
- const result = await _internals10.retireOrMarkStale(directory, path16.dirname(active.path), allArchivedIds);
8080
+ const result = await _internals9.retireOrMarkStale(directory, path15.dirname(active.path), allArchivedIds);
8811
8081
  if (result.action === "retire") {
8812
8082
  observations.push(`Skill '${active.slug}' auto-retired: all source knowledge entries archived`);
8813
8083
  warn(`[curator] ${observations[observations.length - 1]}`);
@@ -8828,7 +8098,6 @@ function parseKnowledgeRecommendations(llmOutput) {
8828
8098
  function parseKnowledgeRecommendationsWithDiagnostics(llmOutput) {
8829
8099
  const recommendations = [];
8830
8100
  const diagnostics = [];
8831
- const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
8832
8101
  const obsSection = llmOutput.match(/OBSERVATIONS:\s*\n([\s\S]*?)(?:\n\n|\n[A-Z_]+:|$)/);
8833
8102
  if (obsSection) {
8834
8103
  const lines = obsSection[1].split(`
@@ -8856,7 +8125,7 @@ function parseKnowledgeRecommendationsWithDiagnostics(llmOutput) {
8856
8125
  const text2 = staleEntry[2].trim().replace(/\s+\([^)]+\)$/, "");
8857
8126
  recommendations.push({
8858
8127
  action: "archive",
8859
- entry_id: UUID_V4.test(uuid2) ? uuid2 : undefined,
8128
+ entry_id: normalizeRecommendationEntryIdToken(uuid2),
8860
8129
  lesson: text2,
8861
8130
  reason: text2
8862
8131
  });
@@ -8872,7 +8141,7 @@ function parseKnowledgeRecommendationsWithDiagnostics(llmOutput) {
8872
8141
  const uuid = match[1];
8873
8142
  const parenthetical = match[2];
8874
8143
  const text = match[3].trim().replace(/\s+\([^)]+\)$/, "");
8875
- const entryId = uuid === "new" || !UUID_V4.test(uuid) ? undefined : uuid;
8144
+ const entryId = uuid === "new" ? undefined : normalizeRecommendationEntryIdToken(uuid);
8876
8145
  let action = "rewrite";
8877
8146
  const lowerParenthetical = parenthetical.toLowerCase();
8878
8147
  if (lowerParenthetical.includes("suggests boost confidence") || lowerParenthetical.includes("mark hive_eligible") || lowerParenthetical.includes("appears high-confidence")) {
@@ -9004,11 +8273,11 @@ function arrayOfStrings(v) {
9004
8273
  }
9005
8274
  function readLatestPostMortemDigest(directory) {
9006
8275
  try {
9007
- const swarmDir = path16.join(directory, ".swarm");
8276
+ const swarmDir = path15.join(directory, ".swarm");
9008
8277
  if (!fs5.existsSync(swarmDir))
9009
8278
  return null;
9010
8279
  const candidates = fs5.readdirSync(swarmDir).filter((name) => /^post-mortem-[^/\\]+\.md$/.test(name)).map((name) => {
9011
- const filePath = path16.join(swarmDir, name);
8280
+ const filePath = path15.join(swarmDir, name);
9012
8281
  return { name, filePath, mtimeMs: fs5.statSync(filePath).mtimeMs };
9013
8282
  }).sort((a, b) => b.mtimeMs - a.mtimeMs);
9014
8283
  const latest = candidates[0];
@@ -9051,7 +8320,7 @@ async function readCuratorSummary(directory) {
9051
8320
  }
9052
8321
  async function writeCuratorSummary(directory, summary) {
9053
8322
  const resolvedPath = validateSwarmPath(directory, "curator-summary.json");
9054
- fs5.mkdirSync(path16.dirname(resolvedPath), { recursive: true });
8323
+ fs5.mkdirSync(path15.dirname(resolvedPath), { recursive: true });
9055
8324
  await bunWrite(resolvedPath, JSON.stringify(summary, null, 2));
9056
8325
  }
9057
8326
  function normalizeAgentName(name) {
@@ -9086,8 +8355,8 @@ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, pha
9086
8355
  const observations = [];
9087
8356
  const timestamp = new Date().toISOString();
9088
8357
  for (const agent of requiredAgents) {
9089
- const normalizedAgent = _internals10.normalizeAgentName(agent);
9090
- const isDispatched = agentsDispatched.some((a) => _internals10.normalizeAgentName(a) === normalizedAgent);
8358
+ const normalizedAgent = _internals9.normalizeAgentName(agent);
8359
+ const isDispatched = agentsDispatched.some((a) => _internals9.normalizeAgentName(a) === normalizedAgent);
9091
8360
  if (!isDispatched) {
9092
8361
  observations.push({
9093
8362
  phase,
@@ -9106,7 +8375,7 @@ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, pha
9106
8375
  if (e.type === "agent.delegation") {
9107
8376
  const agent = e.agent;
9108
8377
  if (agent && typeof agent === "string") {
9109
- const normalized = _internals10.normalizeAgentName(agent);
8378
+ const normalized = _internals9.normalizeAgentName(agent);
9110
8379
  if (normalized === "coder") {
9111
8380
  coderDelegations.push({ event: e, index: i });
9112
8381
  } else if (normalized === "reviewer") {
@@ -9163,7 +8432,7 @@ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, pha
9163
8432
  if (e.type === "agent.delegation" && e.agent) {
9164
8433
  const agent = e.agent;
9165
8434
  if (agent && typeof agent === "string") {
9166
- const normalized = _internals10.normalizeAgentName(agent);
8435
+ const normalized = _internals9.normalizeAgentName(agent);
9167
8436
  if (normalized === "sme") {
9168
8437
  smeDelegations.push({ event: e, index: i });
9169
8438
  }
@@ -9187,7 +8456,7 @@ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, pha
9187
8456
  }
9188
8457
  async function runCuratorInit(directory, config, llmDelegate) {
9189
8458
  try {
9190
- const priorSummary = await _internals10.readCuratorSummary(directory);
8459
+ const priorSummary = await _internals9.readCuratorSummary(directory);
9191
8460
  const knowledgePath = resolveSwarmKnowledgePath(directory);
9192
8461
  const allEntries = await readKnowledge(knowledgePath);
9193
8462
  const highConfidenceEntries = allEntries.filter((e) => typeof e.confidence === "number" && e.confidence >= config.min_knowledge_confidence);
@@ -9228,7 +8497,7 @@ async function runCuratorInit(directory, config, llmDelegate) {
9228
8497
  const maxContextChars = config.max_summary_tokens * 2;
9229
8498
  briefingParts.push(contextMd.slice(0, maxContextChars));
9230
8499
  }
9231
- const latestPostMortemDigest = _internals10.readLatestPostMortemDigest(directory);
8500
+ const latestPostMortemDigest = _internals9.readLatestPostMortemDigest(directory);
9232
8501
  if (latestPostMortemDigest) {
9233
8502
  briefingParts.push(`
9234
8503
  ## Latest Post-Mortem`);
@@ -9315,7 +8584,7 @@ Could not load prior session context.`,
9315
8584
  }
9316
8585
  async function runCuratorPhase(directory, phase, agentsDispatched, config, knowledgeConfig, llmDelegate) {
9317
8586
  try {
9318
- const priorSummary = await _internals10.readCuratorSummary(directory);
8587
+ const priorSummary = await _internals9.readCuratorSummary(directory);
9319
8588
  if (priorSummary?.phase_digests.some((d) => d.phase === phase)) {
9320
8589
  const existingDigest = priorSummary.phase_digests.find((d) => d.phase === phase);
9321
8590
  return {
@@ -9328,10 +8597,10 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9328
8597
  };
9329
8598
  }
9330
8599
  const eventsJsonlContent = await readSwarmFileAsync(directory, "events.jsonl");
9331
- const phaseEvents = eventsJsonlContent ? _internals10.filterPhaseEvents(eventsJsonlContent, phase) : [];
8600
+ const phaseEvents = eventsJsonlContent ? _internals9.filterPhaseEvents(eventsJsonlContent, phase) : [];
9332
8601
  const contextMd = await readSwarmFileAsync(directory, "context.md");
9333
8602
  const requiredAgents = ["reviewer", "test_engineer"];
9334
- const complianceObservations = _internals10.checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, phase);
8603
+ const complianceObservations = _internals9.checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, phase);
9335
8604
  const plan = await loadPlanJsonOnly(directory);
9336
8605
  const phaseData = plan?.phases.find((p) => p.id === phase);
9337
8606
  const tasksCompleted = phaseData ? phaseData.tasks.filter((t) => t.status === "completed").length : 0;
@@ -9355,7 +8624,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9355
8624
  timestamp: new Date().toISOString(),
9356
8625
  summary: `Phase ${phase} completed. ${tasksCompleted}/${tasksTotal} tasks completed. ${complianceObservations.length} compliance observations.`,
9357
8626
  agents_used: [
9358
- ...new Set(agentsDispatched.map((a) => _internals10.normalizeAgentName(a)))
8627
+ ...new Set(agentsDispatched.map((a) => _internals9.normalizeAgentName(a)))
9359
8628
  ],
9360
8629
  tasks_completed: tasksCompleted,
9361
8630
  tasks_total: tasksTotal,
@@ -9407,24 +8676,22 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9407
8676
  clearTimeout(timer);
9408
8677
  }
9409
8678
  if (llmOutput?.trim()) {
9410
- const parsed = _internals10.parseKnowledgeRecommendationsWithDiagnostics(llmOutput);
8679
+ const parsed = _internals9.parseKnowledgeRecommendationsWithDiagnostics(llmOutput);
9411
8680
  for (const diagnostic of parsed.diagnostics) {
9412
8681
  warn("[curator] skipped malformed recommendation line", {
9413
8682
  phase,
9414
8683
  ...diagnostic
9415
8684
  });
9416
8685
  }
9417
- knowledgeRecommendations = parsed.recommendations.filter((recommendation) => {
9418
- if (!recommendation.entry_id || knownKnowledgeIds.has(recommendation.entry_id)) {
9419
- return true;
9420
- }
8686
+ const resolvedRecommendations = resolveKnowledgeRecommendationIds(parsed.recommendations, allKnowledgeEntries);
8687
+ for (const diagnostic of resolvedRecommendations.diagnostics) {
9421
8688
  warn("[curator] skipped recommendation for unknown knowledge entry", {
9422
8689
  phase,
9423
- entry_id: recommendation.entry_id,
9424
- action: recommendation.action
8690
+ entry_id: diagnostic.line,
8691
+ reason: diagnostic.reason
9425
8692
  });
9426
- return false;
9427
- });
8693
+ }
8694
+ knowledgeRecommendations = resolvedRecommendations.recommendations.filter((recommendation) => !recommendation.entry_id || knownKnowledgeIds.has(recommendation.entry_id));
9428
8695
  const structured = parseStructuredCuratorBlocks(llmOutput);
9429
8696
  for (const diagnostic of structured.diagnostics) {
9430
8697
  warn("[curator] skipped malformed structured block", {
@@ -9488,18 +8755,18 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9488
8755
  knowledge_recommendations: capKnowledgeRecommendations(knowledgeRecommendations)
9489
8756
  };
9490
8757
  }
9491
- await _internals10.writeCuratorSummary(directory, updatedSummary);
8758
+ await _internals9.writeCuratorSummary(directory, updatedSummary);
9492
8759
  if (knowledgeApplicationFindings.length > 0) {
9493
8760
  try {
9494
- const evidenceDir = path16.join(directory, ".swarm", "evidence", String(phase));
8761
+ const evidenceDir = path15.join(directory, ".swarm", "evidence", String(phase));
9495
8762
  fs5.mkdirSync(evidenceDir, { recursive: true });
9496
- const findingsPath = path16.join(evidenceDir, "curator-findings.json");
8763
+ const findingsPath = path15.join(evidenceDir, "curator-findings.json");
9497
8764
  await bunWrite(findingsPath, JSON.stringify({ findings: knowledgeApplicationFindings }, null, 2));
9498
8765
  } catch (err) {
9499
8766
  warn(`[curator] failed to persist application findings: ${err instanceof Error ? err.message : String(err)}`);
9500
8767
  }
9501
8768
  }
9502
- const eventsPath = path16.join(directory, ".swarm", "events.jsonl");
8769
+ const eventsPath = path15.join(directory, ".swarm", "events.jsonl");
9503
8770
  for (const obs of complianceObservations) {
9504
8771
  await appendKnowledge(eventsPath, {
9505
8772
  type: "curator_compliance",
@@ -9512,7 +8779,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9512
8779
  }
9513
8780
  if (config.skill_generation_enabled === true && skillCandidates.length > 0) {
9514
8781
  try {
9515
- const skillModule = await import("./skill-generator-mjfqvnn0.js");
8782
+ const skillModule = await import("./skill-generator-5rsjmmfq.js");
9516
8783
  for (const cand of skillCandidates) {
9517
8784
  if (cand.confidence < (config.min_skill_confidence ?? DEFAULT_SKILL_MIN_CONFIDENCE)) {
9518
8785
  continue;
@@ -9530,8 +8797,8 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9530
8797
  }
9531
8798
  const revisedSlugs = new Set;
9532
8799
  try {
9533
- const skillListResult = await _internals10.listSkills(directory);
9534
- const usageEntries = _internals10.readSkillUsageEntries(directory);
8800
+ const skillListResult = await _internals9.listSkills(directory);
8801
+ const usageEntries = _internals9.readSkillUsageEntries(directory);
9535
8802
  let revisionCallsThisPhase = 0;
9536
8803
  for (const active of skillListResult.active) {
9537
8804
  if (revisionCallsThisPhase >= MAX_REVISION_CALLS_PER_PHASE)
@@ -9555,8 +8822,8 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9555
8822
  const violations = skillUsage.filter((e) => e.complianceVerdict === "violated").length;
9556
8823
  const violationRate = violations / skillUsage.length;
9557
8824
  if (violationRate > REVISION_VIOLATION_THRESHOLD && violationRate <= 0.3) {
9558
- const content = await _internals10.readFileAsync(active.path, "utf-8");
9559
- const fm = _internals10.parseDraftFrontmatter(content);
8825
+ const content = await _internals9.readFileAsync(active.path, "utf-8");
8826
+ const fm = _internals9.parseDraftFrontmatter(content);
9560
8827
  if (fm && fm.skillOrigin === "promoted_external")
9561
8828
  continue;
9562
8829
  const currentVersion = fm?.version ?? 1;
@@ -9567,7 +8834,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9567
8834
  reviewerNotes: e.reviewerNotes,
9568
8835
  timestamp: e.timestamp
9569
8836
  }));
9570
- const result2 = await _internals10.reviseSkill({
8837
+ const result2 = await _internals9.reviseSkill({
9571
8838
  directory,
9572
8839
  slug: active.slug,
9573
8840
  skillPath: active.path,
@@ -9586,7 +8853,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
9586
8853
  } catch (revisionErr) {
9587
8854
  warn(`[curator] skill revision check failed: ${revisionErr instanceof Error ? revisionErr.message : String(revisionErr)}`);
9588
8855
  }
9589
- const autoRetireObservations = await _internals10.autoRetireSkills(directory, curatorKnowledgePath, revisedSlugs);
8856
+ const autoRetireObservations = await _internals9.autoRetireSkills(directory, curatorKnowledgePath, revisedSlugs);
9590
8857
  if (autoRetireObservations.length > 0) {
9591
8858
  const retireNote = ` [${autoRetireObservations.length} skill(s) auto-retired]`;
9592
8859
  phaseDigest.summary += retireNote;
@@ -9676,10 +8943,11 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
9676
8943
  if (knowledgeConfig == null) {
9677
8944
  return { applied: 0, skipped: 0 };
9678
8945
  }
9679
- const validRecommendations = recommendations.filter((rec) => rec != null);
8946
+ let validRecommendations = recommendations.filter((rec) => rec != null);
9680
8947
  const knowledgePath = resolveSwarmKnowledgePath(directory);
9681
8948
  const appliedIds = new Set;
9682
8949
  const foundIds = new Set;
8950
+ let idResolutionSkipped = 0;
9683
8951
  const archivedPrevStatus = new Map;
9684
8952
  const contradictedEntries = [];
9685
8953
  await transactKnowledge(knowledgePath, (entries) => {
@@ -9691,6 +8959,12 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
9691
8959
  let modified = false;
9692
8960
  for (const e of entries)
9693
8961
  foundIds.add(e.id);
8962
+ const resolvedRecommendations = resolveKnowledgeRecommendationIds(validRecommendations, entries);
8963
+ validRecommendations = resolvedRecommendations.recommendations;
8964
+ idResolutionSkipped = resolvedRecommendations.diagnostics.length;
8965
+ for (const diagnostic of resolvedRecommendations.diagnostics) {
8966
+ warn(`[curator] applyCuratorKnowledgeUpdates: entry_id '${diagnostic.line}' ${diagnostic.reason} \u2014 skipping`);
8967
+ }
9694
8968
  const updatedEntries = entries.map((entry) => {
9695
8969
  const rec = validRecommendations.find((r) => r.entry_id === entry.id);
9696
8970
  if (!rec)
@@ -9771,6 +9045,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
9771
9045
  applied += txApplied;
9772
9046
  return modified ? updatedEntries : null;
9773
9047
  });
9048
+ skipped += idResolutionSkipped;
9774
9049
  for (const { id, reason } of contradictedEntries) {
9775
9050
  try {
9776
9051
  await recordKnowledgeEvent(directory, {
@@ -9784,107 +9059,1031 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
9784
9059
  });
9785
9060
  } catch {}
9786
9061
  }
9787
- if (contradictedEntries.length > 0 && knowledgeConfig.contradiction_threshold_action === "quarantine") {
9788
- const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-9ksrgq7h.js");
9789
- for (const { id } of contradictedEntries) {
9062
+ if (contradictedEntries.length > 0 && knowledgeConfig.contradiction_threshold_action === "quarantine") {
9063
+ const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-0dkkenp2.js");
9064
+ for (const { id } of contradictedEntries) {
9065
+ try {
9066
+ await maybeQuarantineOnContradiction(directory, id, knowledgeConfig.contradiction_quarantine_threshold, knowledgeConfig.contradiction_quarantine_window_days);
9067
+ } catch {}
9068
+ }
9069
+ }
9070
+ for (const rec of validRecommendations) {
9071
+ if (rec.entry_id !== undefined && !appliedIds.has(rec.entry_id)) {
9072
+ if (!foundIds.has(rec.entry_id)) {
9073
+ warn(`[curator] applyCuratorKnowledgeUpdates: entry_id '${rec.entry_id}' not found \u2014 skipping`);
9074
+ }
9075
+ skipped++;
9076
+ }
9077
+ }
9078
+ const archivedRecs = validRecommendations.filter((r) => r.action === "archive" && r.entry_id && appliedIds.has(r.entry_id));
9079
+ const precomputedArchivedIds = archivedRecs.length > 0 ? await getArchivedKnowledgeIds(directory) : undefined;
9080
+ for (const rec of archivedRecs) {
9081
+ try {
9082
+ await writeArchiveTombstoneAndInvalidateSkills({
9083
+ directory,
9084
+ entryId: rec.entry_id,
9085
+ tier: "swarm",
9086
+ actor: "curator",
9087
+ reason: rec.reason ?? "curator archive recommendation",
9088
+ mode: "archive",
9089
+ previousStatus: archivedPrevStatus.get(rec.entry_id),
9090
+ sourceLabel: "curator",
9091
+ precomputedArchivedIds
9092
+ });
9093
+ } catch (err) {
9094
+ warn(`[curator] archive invalidation for entry '${rec.entry_id}' failed: ${err instanceof Error ? err.message : String(err)}`);
9095
+ }
9096
+ }
9097
+ const currentEntries = await readKnowledge(knowledgePath);
9098
+ const currentLessons = currentEntries.map((e) => e.lesson);
9099
+ for (const rec of validRecommendations) {
9100
+ if (rec.entry_id !== undefined)
9101
+ continue;
9102
+ if (rec.action !== "promote") {
9103
+ skipped++;
9104
+ continue;
9105
+ }
9106
+ const lesson = (rec.lesson?.trim() ?? "").slice(0, 280);
9107
+ if (lesson.length < 15) {
9108
+ skipped++;
9109
+ continue;
9110
+ }
9111
+ if (currentLessons.some((el) => el.toLowerCase() === lesson.toLowerCase())) {
9112
+ skipped++;
9113
+ continue;
9114
+ }
9115
+ if (knowledgeConfig.validation_enabled !== false) {
9116
+ const validation = validateLesson(lesson, currentLessons, {
9117
+ category: rec.category ?? "other",
9118
+ scope: "global",
9119
+ confidence: rec.confidence ?? 0.5
9120
+ });
9121
+ if (!validation.valid) {
9122
+ skipped++;
9123
+ continue;
9124
+ }
9125
+ }
9126
+ const now = new Date().toISOString();
9127
+ const newEntry = {
9128
+ id: randomUUID5(),
9129
+ tier: "swarm",
9130
+ lesson,
9131
+ category: rec.category ?? "other",
9132
+ tags: [],
9133
+ scope: "global",
9134
+ confidence: rec.confidence ?? 0.5,
9135
+ status: "candidate",
9136
+ confirmed_by: [],
9137
+ retrieval_outcomes: {
9138
+ applied_count: 0,
9139
+ succeeded_after_count: 0,
9140
+ failed_after_count: 0
9141
+ },
9142
+ schema_version: 1,
9143
+ created_at: now,
9144
+ updated_at: now,
9145
+ auto_generated: true,
9146
+ project_name: path15.basename(directory),
9147
+ triggers: rec.triggers,
9148
+ required_actions: rec.required_actions,
9149
+ forbidden_actions: rec.forbidden_actions,
9150
+ applies_to_agents: rec.applies_to_agents,
9151
+ applies_to_tools: rec.applies_to_tools,
9152
+ verification_checks: rec.verification_checks,
9153
+ directive_priority: rec.directive_priority
9154
+ };
9155
+ if (!validateActionability(newEntry).actionable) {
9156
+ try {
9157
+ await appendUnactionable(directory, newEntry, "curator_recommendation_unactionable");
9158
+ } catch {}
9159
+ skipped++;
9160
+ continue;
9161
+ }
9162
+ await appendKnowledge(knowledgePath, newEntry);
9163
+ applied++;
9164
+ currentLessons.push(lesson);
9165
+ }
9166
+ return { applied, skipped };
9167
+ }
9168
+
9169
+ // src/hooks/curator-postmortem.ts
9170
+ var MAX_INPUT_TEXT_CHARS = 500;
9171
+ var MAX_KNOWLEDGE_ENTRIES = 500;
9172
+ var MAX_PROPOSALS = 50;
9173
+ var MAX_RETROSPECTIVES = 50;
9174
+ var MAX_DRIFT_REPORTS = 50;
9175
+ var MAX_UNACTIONABLE = 1000;
9176
+ async function collectKnowledgeSummary(directory, scope = "project", sessionID) {
9177
+ const entries = await readKnowledge(resolveSwarmKnowledgePath(directory), MAX_KNOWLEDGE_ENTRIES);
9178
+ let events = await readKnowledgeEvents(directory, MAX_KNOWLEDGE_ENTRIES * 4);
9179
+ if (scope === "session" && sessionID) {
9180
+ events = events.filter((e) => e.session_id === sessionID);
9181
+ }
9182
+ const countsMap = new Map;
9183
+ for (const e of events) {
9184
+ if (e.type !== "applied" && e.type !== "violated" && e.type !== "ignored")
9185
+ continue;
9186
+ const kid = e.knowledge_id ?? e.entry_id;
9187
+ if (!kid)
9188
+ continue;
9189
+ const c = countsMap.get(kid) ?? { applied: 0, violated: 0, ignored: 0 };
9190
+ if (e.type === "applied")
9191
+ c.applied++;
9192
+ else if (e.type === "violated")
9193
+ c.violated++;
9194
+ else if (e.type === "ignored")
9195
+ c.ignored++;
9196
+ countsMap.set(kid, c);
9197
+ }
9198
+ return entries.map((entry) => {
9199
+ const c = countsMap.get(entry.id) ?? {
9200
+ applied: 0,
9201
+ violated: 0,
9202
+ ignored: 0
9203
+ };
9204
+ return {
9205
+ id: entry.id,
9206
+ lesson: entry.lesson,
9207
+ applied: c.applied,
9208
+ violated: c.violated,
9209
+ ignored: c.ignored,
9210
+ confidence: entry.confidence ?? 0.5,
9211
+ status: entry.status ?? "active"
9212
+ };
9213
+ });
9214
+ }
9215
+ function extractSection(text, sectionName) {
9216
+ const pattern = new RegExp(`^${sectionName}:\\s*\\n([\\s\\S]*?)(?=\\n[A-Z_]+:\\s*(?:\\n|$)|$)`, "m");
9217
+ const match = text.match(pattern);
9218
+ return match?.[1]?.trim() || null;
9219
+ }
9220
+ function normalizeRecommendationAction(raw) {
9221
+ const value = String(raw ?? "").toLowerCase().trim();
9222
+ if (value === "promote" || value === "promote_to_hive")
9223
+ return "promote";
9224
+ if (value === "archive" || value === "flag_stale")
9225
+ return "archive";
9226
+ if (value === "rewrite")
9227
+ return "rewrite";
9228
+ if (value === "flag_contradiction")
9229
+ return "flag_contradiction";
9230
+ if (value === "merge")
9231
+ return null;
9232
+ return null;
9233
+ }
9234
+ function normalizeProposalSlug(raw) {
9235
+ return raw.trim().replace(/^proposals[\\/]/, "").replace(/\.md$/i, "").replace(/\.json$/i, "");
9236
+ }
9237
+ function parseStructuredPostMortemActions(llmOutput) {
9238
+ const parsed = {
9239
+ summary: extractSection(llmOutput, "SUMMARY"),
9240
+ recommendations: [],
9241
+ queueTriage: [],
9242
+ diagnostics: []
9243
+ };
9244
+ const fence = /```(?:json|jsonc)?\s+postmortem_actions\s*\n([\s\S]*?)\n```/g;
9245
+ for (const match of llmOutput.matchAll(fence)) {
9246
+ let data;
9247
+ try {
9248
+ data = JSON.parse(match[1]);
9249
+ } catch (err) {
9250
+ parsed.diagnostics.push(`postmortem_actions malformed_json: ${err instanceof Error ? err.message : String(err)}`);
9251
+ continue;
9252
+ }
9253
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
9254
+ parsed.diagnostics.push("postmortem_actions expected object");
9255
+ continue;
9256
+ }
9257
+ const obj = data;
9258
+ if (typeof obj.summary === "string" && obj.summary.trim()) {
9259
+ parsed.summary = obj.summary.trim().slice(0, 1000);
9260
+ }
9261
+ if (Array.isArray(obj.curation_recommendations)) {
9262
+ for (const [index, item] of obj.curation_recommendations.entries()) {
9263
+ if (!item || typeof item !== "object") {
9264
+ parsed.diagnostics.push(`curation_recommendations[${index}] invalid object`);
9265
+ continue;
9266
+ }
9267
+ const rec = item;
9268
+ const action = normalizeRecommendationAction(rec.action);
9269
+ const lesson = String(rec.lesson ?? rec.reason ?? "").trim();
9270
+ const reason = String(rec.reason ?? lesson).trim();
9271
+ if (!action || !reason) {
9272
+ parsed.diagnostics.push(`curation_recommendations[${index}] missing action/reason`);
9273
+ continue;
9274
+ }
9275
+ if (action === "rewrite" && lesson.length < 15) {
9276
+ parsed.diagnostics.push(`curation_recommendations[${index}] rewrite missing lesson`);
9277
+ continue;
9278
+ }
9279
+ parsed.recommendations.push({
9280
+ action,
9281
+ entry_id: typeof rec.entry_id === "string" ? normalizeRecommendationEntryIdToken(rec.entry_id) : undefined,
9282
+ lesson: (lesson || reason).slice(0, 280),
9283
+ reason: reason.slice(0, 280),
9284
+ category: typeof rec.category === "string" ? rec.category : undefined,
9285
+ confidence: typeof rec.confidence === "number" ? rec.confidence : undefined,
9286
+ triggers: stringArray(rec.triggers),
9287
+ required_actions: stringArray(rec.required_actions),
9288
+ forbidden_actions: stringArray(rec.forbidden_actions),
9289
+ applies_to_agents: stringArray(rec.applies_to_agents),
9290
+ applies_to_tools: stringArray(rec.applies_to_tools),
9291
+ verification_checks: stringArray(rec.verification_checks),
9292
+ directive_priority: directivePriority(rec.directive_priority)
9293
+ });
9294
+ }
9295
+ }
9296
+ if (Array.isArray(obj.queue_triage)) {
9297
+ for (const [index, item] of obj.queue_triage.entries()) {
9298
+ if (!item || typeof item !== "object") {
9299
+ parsed.diagnostics.push(`queue_triage[${index}] invalid object`);
9300
+ continue;
9301
+ }
9302
+ const triage = item;
9303
+ const proposalId = String(triage.proposal_id ?? "").trim();
9304
+ const action = String(triage.action ?? "").toLowerCase().trim();
9305
+ if (!proposalId || action !== "apply" && action !== "reject") {
9306
+ parsed.diagnostics.push(`queue_triage[${index}] missing proposal_id/action`);
9307
+ continue;
9308
+ }
9309
+ parsed.queueTriage.push({
9310
+ proposal_id: proposalId.slice(0, 120),
9311
+ action,
9312
+ reason: String(triage.reason ?? "").slice(0, 280)
9313
+ });
9314
+ }
9315
+ }
9316
+ }
9317
+ return parsed;
9318
+ }
9319
+ function stringArray(value) {
9320
+ if (!Array.isArray(value))
9321
+ return;
9322
+ const strings = value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
9323
+ return strings.length > 0 ? strings : undefined;
9324
+ }
9325
+ function directivePriority(value) {
9326
+ if (value === "low" || value === "medium" || value === "high" || value === "critical") {
9327
+ return value;
9328
+ }
9329
+ return;
9330
+ }
9331
+ function parseLegacyPostMortemActions(llmOutput) {
9332
+ const parsed = {
9333
+ summary: extractSection(llmOutput, "SUMMARY"),
9334
+ recommendations: [],
9335
+ queueTriage: [],
9336
+ diagnostics: []
9337
+ };
9338
+ const curation = extractSection(llmOutput, "CURATION_RECOMMENDATIONS");
9339
+ if (curation) {
9340
+ let recIndex = 0;
9341
+ for (const line of curation.split(`
9342
+ `)) {
9343
+ const trimmed = line.trim();
9344
+ if (!trimmed.startsWith("-"))
9345
+ continue;
9346
+ const body = trimmed.replace(/^-\s*/, "");
9347
+ const [head2, reasonPart = ""] = body.split(/\s+\u2014\s+|\s+-\s+/, 2);
9348
+ const [rawAction, rest = ""] = head2.split(/:\s*/, 2);
9349
+ const lowerRaw = rawAction.toLowerCase().trim();
9350
+ const action = normalizeRecommendationAction(rawAction);
9351
+ if (!action) {
9352
+ if (lowerRaw === "merge") {
9353
+ parsed.diagnostics.push("legacy curation_recommendations unsupported action 'merge' \u2014 dropped");
9354
+ } else if (lowerRaw) {
9355
+ parsed.diagnostics.push(`legacy curation_recommendations unrecognized action '${lowerRaw}'`);
9356
+ }
9357
+ continue;
9358
+ }
9359
+ const idMatch = rest.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i);
9360
+ const reason = (reasonPart || rest).trim();
9361
+ if (!reason) {
9362
+ parsed.diagnostics.push(`legacy curation_recommendations[${recIndex}] missing reason`);
9363
+ continue;
9364
+ }
9365
+ parsed.recommendations.push({
9366
+ action,
9367
+ entry_id: idMatch?.[0],
9368
+ lesson: reason.slice(0, 280),
9369
+ reason: reason.slice(0, 280)
9370
+ });
9371
+ recIndex++;
9372
+ }
9373
+ }
9374
+ const queue = extractSection(llmOutput, "QUEUE_TRIAGE");
9375
+ if (queue) {
9376
+ for (const line of queue.split(`
9377
+ `)) {
9378
+ const trimmed = line.trim();
9379
+ if (!trimmed.startsWith("-"))
9380
+ continue;
9381
+ if (trimmed.includes(":")) {
9382
+ const match = trimmed.match(/^-\s*([^:]+):\s*(APPLY|REJECT)\b\s*(?:\u2014|-)?\s*(.*)$/i);
9383
+ if (!match) {
9384
+ parsed.diagnostics.push("legacy queue_triage malformed line");
9385
+ continue;
9386
+ }
9387
+ parsed.queueTriage.push({
9388
+ proposal_id: match[1].trim().slice(0, 120),
9389
+ action: match[2].toLowerCase(),
9390
+ reason: match[3].trim().slice(0, 280)
9391
+ });
9392
+ }
9393
+ }
9394
+ }
9395
+ return parsed;
9396
+ }
9397
+ function parsePostMortemActions(llmOutput) {
9398
+ const structured = parseStructuredPostMortemActions(llmOutput);
9399
+ const legacy = parseLegacyPostMortemActions(llmOutput);
9400
+ return {
9401
+ summary: structured.summary ?? legacy.summary,
9402
+ recommendations: structured.recommendations.length > 0 ? structured.recommendations : legacy.recommendations,
9403
+ queueTriage: structured.queueTriage.length > 0 ? structured.queueTriage : legacy.queueTriage,
9404
+ diagnostics: [...structured.diagnostics, ...legacy.diagnostics]
9405
+ };
9406
+ }
9407
+ async function executePostMortemActions(directory, parsed, options) {
9408
+ const warnings = [];
9409
+ const result = {
9410
+ knowledge_applied: 0,
9411
+ knowledge_skipped: 0,
9412
+ hive_promotions: 0,
9413
+ hive_encounters_incremented: 0,
9414
+ hive_advancements: 0,
9415
+ proposals_approved: 0,
9416
+ proposals_rejected: 0,
9417
+ proposals_skipped: 0
9418
+ };
9419
+ const knowledgeConfig = options.knowledgeConfig ?? await _internals10.loadDefaultKnowledgeConfig();
9420
+ if (parsed.recommendations.length > 0) {
9421
+ try {
9422
+ const knowledgeResult = await _internals10.applyCuratorKnowledgeUpdates(directory, parsed.recommendations, knowledgeConfig);
9423
+ result.knowledge_applied = knowledgeResult.applied;
9424
+ result.knowledge_skipped = knowledgeResult.skipped;
9425
+ } catch (err) {
9426
+ warnings.push(`Post-mortem knowledge actions failed: ${err instanceof Error ? err.message : String(err)}`);
9427
+ }
9428
+ try {
9429
+ const entries = await _internals10.readSwarmKnowledge(directory);
9430
+ const hiveResult = await _internals10.checkHivePromotions(entries, knowledgeConfig);
9431
+ result.hive_promotions = hiveResult.new_promotions;
9432
+ result.hive_encounters_incremented = hiveResult.encounters_incremented;
9433
+ result.hive_advancements = hiveResult.advancements;
9434
+ } catch (err) {
9435
+ warnings.push(`Post-mortem hive promotion check failed: ${err instanceof Error ? err.message : String(err)}`);
9436
+ }
9437
+ }
9438
+ if (parsed.queueTriage.length > 0) {
9439
+ try {
9440
+ const proposalResult = await _internals10.applyProposalTriage(directory, parsed.queueTriage);
9441
+ result.proposals_approved = proposalResult.approved.length;
9442
+ result.proposals_rejected = proposalResult.rejected.length;
9443
+ result.proposals_skipped = proposalResult.skipped.length;
9444
+ } catch (err) {
9445
+ warnings.push(`Post-mortem proposal triage failed: ${err instanceof Error ? err.message : String(err)}`);
9446
+ }
9447
+ }
9448
+ return { result, warnings };
9449
+ }
9450
+ async function verifyPostMortemKnowledgeActions(directory, recommendations) {
9451
+ if (recommendations.length === 0)
9452
+ return [];
9453
+ const entries = await _internals10.readSwarmKnowledge(directory);
9454
+ const activeEntries = entries.filter((entry) => isActiveStatus(entry.status));
9455
+ const exactIds = new Set(activeEntries.map((entry) => entry.id));
9456
+ const prefixMatches = new Map;
9457
+ return recommendations.map((rec) => {
9458
+ const inputId = typeof rec.entry_id === "string" ? normalizeRecommendationEntryIdToken(rec.entry_id) ?? null : null;
9459
+ if (!inputId) {
9460
+ const isNewPromote = rec.action === "promote";
9461
+ return {
9462
+ action: rec.action,
9463
+ input_entry_id: null,
9464
+ resolved_entry_id: null,
9465
+ status: isNewPromote ? "new_entry" : "missing_entry_id",
9466
+ reason: isNewPromote ? "promote without entry_id will create a new candidate if actionable" : `${rec.action} requires an existing entry_id`
9467
+ };
9468
+ }
9469
+ if (exactIds.has(inputId)) {
9470
+ return {
9471
+ action: rec.action,
9472
+ input_entry_id: inputId,
9473
+ resolved_entry_id: inputId,
9474
+ status: "exact_match",
9475
+ reason: "entry_id matched an existing knowledge entry exactly"
9476
+ };
9477
+ }
9478
+ let matches = prefixMatches.get(inputId);
9479
+ if (!matches) {
9480
+ matches = activeEntries.filter((entry) => entry.id.startsWith(inputId));
9481
+ prefixMatches.set(inputId, matches);
9482
+ }
9483
+ if (matches.length === 1) {
9484
+ return {
9485
+ action: rec.action,
9486
+ input_entry_id: inputId,
9487
+ resolved_entry_id: matches[0].id,
9488
+ status: "prefix_match",
9489
+ reason: "entry_id prefix resolved to one existing knowledge entry"
9490
+ };
9491
+ }
9492
+ return {
9493
+ action: rec.action,
9494
+ input_entry_id: inputId,
9495
+ resolved_entry_id: null,
9496
+ status: matches.length === 0 ? "not_found" : "ambiguous_prefix",
9497
+ reason: matches.length === 0 ? "entry_id did not match any existing knowledge entry" : `entry_id prefix matched ${matches.length} knowledge entries`
9498
+ };
9499
+ });
9500
+ }
9501
+ function buildStateFreshnessSection(args) {
9502
+ const planContext = args.planLoaded ? `loaded (${args.planId})` : "unavailable (plan_id: unknown; project-level fallback)";
9503
+ return [
9504
+ "## Generated Against State",
9505
+ `- Plan context: ${planContext}`,
9506
+ `- Scope: ${args.scope}${args.sessionID ? ` (${args.sessionID})` : ""}`,
9507
+ `- Knowledge entries summarized: ${args.knowledgeSummary.length}`,
9508
+ `- Pending proposals summarized: ${args.proposals.length}`,
9509
+ `- Unactionable entries summarized: ${args.unactionable.length}`,
9510
+ `- Retrospectives summarized: ${args.retrospectives.length}`,
9511
+ `- Drift reports summarized: ${args.driftReports.length}`
9512
+ ].join(`
9513
+ `);
9514
+ }
9515
+ function buildActionVerificationSection(verification) {
9516
+ const lines = ["## Post-Mortem Action Verification"];
9517
+ if (verification.length === 0) {
9518
+ lines.push("- Knowledge actions: none supplied.");
9519
+ return lines.join(`
9520
+ `);
9521
+ }
9522
+ for (const item of verification) {
9523
+ const input = item.input_entry_id ?? "new";
9524
+ const resolved = item.resolved_entry_id ? ` => ${item.resolved_entry_id}` : "";
9525
+ lines.push(`- ${item.action}: ${input}${resolved} [${item.status}] ${item.reason}`);
9526
+ }
9527
+ return lines.join(`
9528
+ `);
9529
+ }
9530
+ async function repairPostMortemActions(llmOutput, diagnostics, options) {
9531
+ if (!options.llmDelegate || diagnostics.length === 0)
9532
+ return null;
9533
+ const ac = new AbortController;
9534
+ const timer = setTimeout(() => ac.abort(), 30000);
9535
+ try {
9536
+ const repairPrompt = [
9537
+ "Repair the supplied CURATOR_POSTMORTEM output into one valid fenced JSON block.",
9538
+ "Return only this fence:",
9539
+ "```json postmortem_actions",
9540
+ '{"summary":"...","curation_recommendations":[],"queue_triage":[]}',
9541
+ "```",
9542
+ "Allowed curation action values: promote, archive, rewrite, flag_contradiction.",
9543
+ "For new promote recommendations, include at least one scope field (applies_to_agents or applies_to_tools) and at least one predicate field (required_actions, forbidden_actions, or verification_checks).",
9544
+ "Existing entry_id values may be full UUIDs or unique 8+ character hex prefixes copied from KNOWLEDGE_ENTRIES.",
9545
+ "Allowed queue_triage action values: apply, reject.",
9546
+ "Do not include unsupported actions such as merge.",
9547
+ "Diagnostics:",
9548
+ diagnostics.join("; "),
9549
+ "Original output:",
9550
+ llmOutput.slice(0, 8000)
9551
+ ].join(`
9552
+ `);
9553
+ const repaired = await options.llmDelegate("", repairPrompt, ac.signal);
9554
+ const parsed = _internals10.parsePostMortemActions(repaired);
9555
+ if (parsed.diagnostics.length === 0) {
9556
+ return parsed;
9557
+ }
9558
+ return null;
9559
+ } catch {
9560
+ return null;
9561
+ } finally {
9562
+ clearTimeout(timer);
9563
+ }
9564
+ }
9565
+ function readJsonlFile(filePath, maxLines) {
9566
+ try {
9567
+ if (!existsSync10(filePath))
9568
+ return [];
9569
+ const content = readFileSync6(filePath, "utf-8");
9570
+ const results = [];
9571
+ const max = maxLines !== undefined && maxLines > 0 ? maxLines : Infinity;
9572
+ for (const line of content.split(`
9573
+ `)) {
9574
+ if (results.length >= max)
9575
+ break;
9576
+ if (!line.trim())
9577
+ continue;
9790
9578
  try {
9791
- await maybeQuarantineOnContradiction(directory, id, knowledgeConfig.contradiction_quarantine_threshold, knowledgeConfig.contradiction_quarantine_window_days);
9579
+ results.push(JSON.parse(line));
9792
9580
  } catch {}
9793
9581
  }
9582
+ return results;
9583
+ } catch {
9584
+ return [];
9794
9585
  }
9795
- for (const rec of validRecommendations) {
9796
- if (rec.entry_id !== undefined && !appliedIds.has(rec.entry_id)) {
9797
- if (!foundIds.has(rec.entry_id)) {
9798
- warn(`[curator] applyCuratorKnowledgeUpdates: entry_id '${rec.entry_id}' not found \u2014 skipping`);
9586
+ }
9587
+ function collectRetrospectives(directory) {
9588
+ const results = [];
9589
+ const evidenceDir = path16.join(directory, ".swarm", "evidence");
9590
+ try {
9591
+ if (!existsSync10(evidenceDir))
9592
+ return results;
9593
+ const retroDirs = readdirSync2(evidenceDir, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("retro-")).slice(0, MAX_RETROSPECTIVES);
9594
+ for (const entry of retroDirs) {
9595
+ const retroPath = path16.join(evidenceDir, entry.name, "evidence.json");
9596
+ if (existsSync10(retroPath)) {
9597
+ try {
9598
+ results.push(readFileSync6(retroPath, "utf-8"));
9599
+ } catch {}
9799
9600
  }
9800
- skipped++;
9801
9601
  }
9602
+ } catch {}
9603
+ return results;
9604
+ }
9605
+ async function collectDriftReports(directory) {
9606
+ try {
9607
+ const reports = await _internals10.readPriorDriftReports(directory);
9608
+ return reports.slice(-MAX_DRIFT_REPORTS).map((report) => JSON.stringify(report, null, 2));
9609
+ } catch {
9610
+ return [];
9802
9611
  }
9803
- const archivedRecs = validRecommendations.filter((r) => r.action === "archive" && r.entry_id && appliedIds.has(r.entry_id));
9804
- const precomputedArchivedIds = archivedRecs.length > 0 ? await getArchivedKnowledgeIds(directory) : undefined;
9805
- for (const rec of archivedRecs) {
9612
+ }
9613
+ function collectPendingProposals(directory) {
9614
+ const results = [];
9615
+ const insightPath = path16.join(directory, ".swarm", "insight-candidates.jsonl");
9616
+ if (existsSync10(insightPath)) {
9806
9617
  try {
9807
- await writeArchiveTombstoneAndInvalidateSkills({
9808
- directory,
9809
- entryId: rec.entry_id,
9810
- tier: "swarm",
9811
- actor: "curator",
9812
- reason: rec.reason ?? "curator archive recommendation",
9813
- mode: "archive",
9814
- previousStatus: archivedPrevStatus.get(rec.entry_id),
9815
- sourceLabel: "curator",
9816
- precomputedArchivedIds
9618
+ results.push({
9619
+ source: "insight-candidates",
9620
+ content: readFileSync6(insightPath, "utf-8")
9817
9621
  });
9818
- } catch (err) {
9819
- warn(`[curator] archive invalidation for entry '${rec.entry_id}' failed: ${err instanceof Error ? err.message : String(err)}`);
9622
+ } catch {}
9623
+ }
9624
+ const proposalsDir = path16.join(directory, ".swarm", "skills", "proposals");
9625
+ try {
9626
+ if (existsSync10(proposalsDir)) {
9627
+ const proposalFiles = readdirSync2(proposalsDir).filter((e) => e.endsWith(".md") || e.endsWith(".json")).slice(0, MAX_PROPOSALS);
9628
+ for (const entry of proposalFiles) {
9629
+ try {
9630
+ results.push({
9631
+ source: `proposals/${entry}`,
9632
+ content: readFileSync6(path16.join(proposalsDir, entry), "utf-8")
9633
+ });
9634
+ } catch {}
9635
+ }
9820
9636
  }
9637
+ } catch {}
9638
+ return results;
9639
+ }
9640
+ function isReportValid(reportPath) {
9641
+ try {
9642
+ if (!existsSync10(reportPath))
9643
+ return false;
9644
+ const content = readFileSync6(reportPath, "utf-8").trim();
9645
+ if (content.length === 0)
9646
+ return false;
9647
+ if (!content.startsWith("# Post-Mortem Report:"))
9648
+ return false;
9649
+ return true;
9650
+ } catch {
9651
+ return false;
9821
9652
  }
9822
- const currentEntries = await readKnowledge(knowledgePath);
9823
- const currentLessons = currentEntries.map((e) => e.lesson);
9824
- for (const rec of validRecommendations) {
9825
- if (rec.entry_id !== undefined)
9826
- continue;
9827
- if (rec.action !== "promote") {
9828
- skipped++;
9829
- continue;
9653
+ }
9654
+ async function acquirePostMortemLock(directory, planId) {
9655
+ const result = await tryAcquireLock(directory, `post-mortem-${planId}.lock`, "curator-postmortem", planId);
9656
+ if (result.acquired) {
9657
+ return { acquired: true, release: result.lock?._release };
9658
+ }
9659
+ return { acquired: false };
9660
+ }
9661
+ function buildDataOnlyReport(planId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports, context) {
9662
+ const now = new Date().toISOString();
9663
+ const lines = [];
9664
+ lines.push(`# Post-Mortem Report: ${planId}`);
9665
+ lines.push(`Generated: ${now}`);
9666
+ lines.push("");
9667
+ lines.push(buildStateFreshnessSection({
9668
+ planId,
9669
+ scope: context?.scope ?? "project",
9670
+ sessionID: context?.sessionID,
9671
+ planLoaded: context?.planLoaded ?? planId !== "unknown",
9672
+ knowledgeSummary,
9673
+ proposals,
9674
+ unactionable,
9675
+ retrospectives,
9676
+ driftReports
9677
+ }));
9678
+ lines.push("");
9679
+ lines.push("## Project Summary");
9680
+ lines.push(planSummary);
9681
+ lines.push("");
9682
+ lines.push("## Knowledge Metrics");
9683
+ const totalEntries = knowledgeSummary.length;
9684
+ const totalApplied = knowledgeSummary.reduce((s, e) => s + e.applied, 0);
9685
+ const totalViolated = knowledgeSummary.reduce((s, e) => s + e.violated, 0);
9686
+ const totalIgnored = knowledgeSummary.reduce((s, e) => s + e.ignored, 0);
9687
+ const neverApplied = knowledgeSummary.filter((e) => e.applied === 0 && e.violated === 0 && e.ignored === 0);
9688
+ lines.push(`- Total entries: ${totalEntries}`);
9689
+ lines.push(`- Application events: ${totalApplied} applied, ${totalViolated} violated, ${totalIgnored} ignored`);
9690
+ lines.push(`- Never-applied entries: ${neverApplied.length}`);
9691
+ if (totalApplied + totalViolated > 0) {
9692
+ const appRate = (totalApplied / (totalApplied + totalViolated) * 100).toFixed(1);
9693
+ lines.push(`- Application rate: ${appRate}%`);
9694
+ }
9695
+ lines.push("");
9696
+ if (neverApplied.length > 0) {
9697
+ lines.push("### Never-Applied Entries (review for retirement)");
9698
+ for (const e of neverApplied.slice(0, 10)) {
9699
+ lines.push(`- \`${e.id}\` (confidence: ${e.confidence.toFixed(2)}): ${e.lesson.slice(0, 80)}`);
9830
9700
  }
9831
- const lesson = (rec.lesson?.trim() ?? "").slice(0, 280);
9832
- if (lesson.length < 15) {
9833
- skipped++;
9834
- continue;
9701
+ if (neverApplied.length > 10) {
9702
+ lines.push(`- ... and ${neverApplied.length - 10} more`);
9835
9703
  }
9836
- if (currentLessons.some((el) => el.toLowerCase() === lesson.toLowerCase())) {
9837
- skipped++;
9838
- continue;
9704
+ lines.push("");
9705
+ }
9706
+ const highViolation = knowledgeSummary.filter((e) => e.violated > 0).sort((a, b) => b.violated - a.violated).slice(0, 5);
9707
+ if (highViolation.length > 0) {
9708
+ lines.push("### High-Violation Entries");
9709
+ for (const e of highViolation) {
9710
+ lines.push(`- \`${e.id}\` \u2014 ${e.violated} violations, ${e.applied} applied: ${e.lesson.slice(0, 80)}`);
9839
9711
  }
9840
- if (knowledgeConfig.validation_enabled !== false) {
9841
- const validation = validateLesson(lesson, currentLessons, {
9842
- category: rec.category ?? "other",
9843
- scope: "global",
9844
- confidence: rec.confidence ?? 0.5
9845
- });
9846
- if (!validation.valid) {
9847
- skipped++;
9848
- continue;
9712
+ lines.push("");
9713
+ }
9714
+ lines.push("## Queue Status");
9715
+ lines.push(`- Pending proposals: ${proposals.length}`);
9716
+ lines.push(`- Unactionable quarantine: ${unactionable.length}`);
9717
+ for (const p of proposals) {
9718
+ lines.push(` - ${p.source}`);
9719
+ }
9720
+ lines.push("");
9721
+ if (retrospectives.length > 0) {
9722
+ lines.push("## Retrospectives");
9723
+ lines.push(`${retrospectives.length} phase retrospective(s) recorded.`);
9724
+ lines.push("");
9725
+ }
9726
+ if (driftReports.length > 0) {
9727
+ lines.push("## Drift Reports");
9728
+ for (const dr of driftReports) {
9729
+ try {
9730
+ const parsed = JSON.parse(dr);
9731
+ lines.push(`- Phase ${parsed.phase}: ${parsed.alignment} (score: ${parsed.drift_score})`);
9732
+ } catch {
9733
+ lines.push("- (unparseable drift report)");
9849
9734
  }
9850
9735
  }
9851
- const now = new Date().toISOString();
9852
- const newEntry = {
9853
- id: randomUUID5(),
9854
- tier: "swarm",
9855
- lesson,
9856
- category: rec.category ?? "other",
9857
- tags: [],
9858
- scope: "global",
9859
- confidence: rec.confidence ?? 0.5,
9860
- status: "candidate",
9861
- confirmed_by: [],
9862
- retrieval_outcomes: {
9863
- applied_count: 0,
9864
- succeeded_after_count: 0,
9865
- failed_after_count: 0
9866
- },
9867
- schema_version: 1,
9868
- created_at: now,
9869
- updated_at: now,
9870
- auto_generated: true,
9871
- project_name: path16.basename(directory)
9736
+ lines.push("");
9737
+ }
9738
+ if (curatorDigest) {
9739
+ lines.push("## Curator Digest Summary");
9740
+ const trimmed = curatorDigest.length > 1000 ? `${curatorDigest.slice(0, 1000)}...` : curatorDigest;
9741
+ lines.push(trimmed);
9742
+ lines.push("");
9743
+ }
9744
+ return lines.join(`
9745
+ `);
9746
+ }
9747
+ function assembleLLMInput(planId, scope, sessionID, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports) {
9748
+ const sections = [];
9749
+ sections.push(`TASK: CURATOR_POSTMORTEM ${planId}`);
9750
+ sections.push(`SCOPE: ${scope}${sessionID ? ` (${sessionID})` : ""}`);
9751
+ sections.push(`PLAN_SUMMARY: ${planSummary}`);
9752
+ sections.push(`CURATOR_DIGESTS: ${curatorDigest ?? "none"}`);
9753
+ const eventsSummary = knowledgeSummary.map((e) => `${e.id}: applied=${e.applied} violated=${e.violated} ignored=${e.ignored} confidence=${e.confidence.toFixed(2)} status=${e.status}`).join(`
9754
+ `);
9755
+ sections.push(`KNOWLEDGE_EVENTS_SUMMARY:
9756
+ ${eventsSummary || "none"}`);
9757
+ const knEntries = knowledgeSummary.map((e) => JSON.stringify({
9758
+ id: e.id,
9759
+ lesson: e.lesson.slice(0, MAX_INPUT_TEXT_CHARS)
9760
+ })).join(`
9761
+ `);
9762
+ sections.push(`KNOWLEDGE_ENTRIES:
9763
+ ${knEntries || "[]"}`);
9764
+ const proposalText = proposals.length > 0 ? proposals.map((p) => `[${p.source}]
9765
+ ${p.content.slice(0, MAX_INPUT_TEXT_CHARS)}`).join(`
9766
+ ---
9767
+ `) : "none";
9768
+ sections.push(`PENDING_PROPOSALS:
9769
+ ${proposalText}`);
9770
+ sections.push(`UNACTIONABLE_QUARANTINE: ${unactionable.length} entries`);
9771
+ const retroText = retrospectives.length > 0 ? retrospectives.map((r) => r.slice(0, MAX_INPUT_TEXT_CHARS)).join(`
9772
+ ---
9773
+ `) : "none";
9774
+ sections.push(`RETROSPECTIVES:
9775
+ ${retroText}`);
9776
+ if (driftReports.length > 0) {
9777
+ const driftText = driftReports.map((r) => r.slice(0, MAX_INPUT_TEXT_CHARS)).join(`
9778
+ ---
9779
+ `);
9780
+ sections.push(`DRIFT_REPORTS:
9781
+ ${driftText}`);
9782
+ }
9783
+ return sections.join(`
9784
+
9785
+ `);
9786
+ }
9787
+ async function runCuratorPostMortem(directory, options = {}) {
9788
+ const warnings = [];
9789
+ const scope = options.scope ?? "project";
9790
+ let planId = "unknown";
9791
+ let planSummary = "Plan data unavailable.";
9792
+ let planLoaded = false;
9793
+ try {
9794
+ const plan = await loadPlanJsonOnly(directory);
9795
+ if (plan) {
9796
+ planLoaded = true;
9797
+ planId = derivePlanId(plan);
9798
+ const phaseCount = plan.phases?.length ?? 0;
9799
+ const completedPhases = plan.phases?.filter((p) => p.status === "complete").length ?? 0;
9800
+ planSummary = `Plan "${plan.title}" (${plan.swarm}): ${completedPhases}/${phaseCount} phases complete.`;
9801
+ } else {
9802
+ warnings.push("Plan not found \u2014 using fallback plan ID.");
9803
+ }
9804
+ } catch {
9805
+ warnings.push("Failed to load plan data.");
9806
+ }
9807
+ const effectivePlanId = planId;
9808
+ const reportFilename = `post-mortem-${effectivePlanId}.md`;
9809
+ let reportPath;
9810
+ try {
9811
+ reportPath = validateSwarmPath(directory, reportFilename);
9812
+ } catch {
9813
+ return {
9814
+ success: false,
9815
+ planId,
9816
+ reportPath: null,
9817
+ summary: null,
9818
+ warnings: [...warnings, "Invalid report path."]
9872
9819
  };
9873
- if (!validateActionability(newEntry).actionable) {
9820
+ }
9821
+ if (!options.force && isReportValid(reportPath)) {
9822
+ return {
9823
+ success: true,
9824
+ planId: effectivePlanId,
9825
+ reportPath,
9826
+ summary: "Post-mortem report already exists (idempotent skip).",
9827
+ warnings
9828
+ };
9829
+ }
9830
+ const lock = await _internals10.acquirePostMortemLock(directory, effectivePlanId);
9831
+ if (!lock.acquired) {
9832
+ return {
9833
+ success: false,
9834
+ planId: effectivePlanId,
9835
+ reportPath,
9836
+ summary: null,
9837
+ warnings: [
9838
+ ...warnings,
9839
+ `Concurrent post-mortem run in progress for plan ${effectivePlanId}; skipped.`
9840
+ ]
9841
+ };
9842
+ }
9843
+ try {
9844
+ let knowledgeSummary = [];
9845
+ try {
9846
+ knowledgeSummary = await collectKnowledgeSummary(directory, scope, options.sessionID);
9847
+ } catch {
9848
+ warnings.push("Failed to collect knowledge summary.");
9849
+ }
9850
+ if (knowledgeSummary.length > MAX_KNOWLEDGE_ENTRIES) {
9851
+ warnings.push(`Knowledge entries capped at ${MAX_KNOWLEDGE_ENTRIES} (had ${knowledgeSummary.length}); older entries truncated.`);
9852
+ knowledgeSummary = knowledgeSummary.slice(0, MAX_KNOWLEDGE_ENTRIES);
9853
+ }
9854
+ let curatorDigest = null;
9855
+ try {
9856
+ const raw = await readSwarmFileAsync(directory, "curator-summary.json");
9857
+ if (raw) {
9858
+ const parsed = JSON.parse(raw);
9859
+ curatorDigest = parsed.digest ?? null;
9860
+ }
9861
+ } catch {
9862
+ warnings.push("Failed to read curator digest.");
9863
+ }
9864
+ let proposals = collectPendingProposals(directory);
9865
+ if (proposals.length > MAX_PROPOSALS) {
9866
+ warnings.push(`Pending proposals capped at ${MAX_PROPOSALS} (had ${proposals.length}); older entries truncated.`);
9867
+ proposals = proposals.slice(0, MAX_PROPOSALS);
9868
+ }
9869
+ const unactionablePath = path16.join(resolveKnowledgeStoreDir(directory), "knowledge-unactionable.jsonl");
9870
+ let unactionable = readJsonlFile(unactionablePath, MAX_UNACTIONABLE);
9871
+ if (unactionable.length > MAX_UNACTIONABLE) {
9872
+ warnings.push(`Unactionable entries capped at ${MAX_UNACTIONABLE} (had ${unactionable.length}); older entries truncated.`);
9873
+ unactionable = unactionable.slice(0, MAX_UNACTIONABLE);
9874
+ }
9875
+ let retrospectives = collectRetrospectives(directory);
9876
+ if (retrospectives.length > MAX_RETROSPECTIVES) {
9877
+ warnings.push(`Retrospectives capped at ${MAX_RETROSPECTIVES} (had ${retrospectives.length}); older entries truncated.`);
9878
+ retrospectives = retrospectives.slice(0, MAX_RETROSPECTIVES);
9879
+ }
9880
+ let driftReports = await collectDriftReports(directory);
9881
+ if (driftReports.length > MAX_DRIFT_REPORTS) {
9882
+ warnings.push(`Drift reports capped at ${MAX_DRIFT_REPORTS} (had ${driftReports.length}); older entries truncated.`);
9883
+ driftReports = driftReports.slice(0, MAX_DRIFT_REPORTS);
9884
+ }
9885
+ let reportContent;
9886
+ let llmSummary = null;
9887
+ let actionResult;
9888
+ if (options.llmDelegate) {
9874
9889
  try {
9875
- await appendUnactionable(directory, newEntry, "curator_recommendation_unactionable");
9890
+ const { CURATOR_POSTMORTEM_PROMPT } = await import("./explorer-t5srbq64.js");
9891
+ const userInput = assembleLLMInput(effectivePlanId, scope, options.sessionID, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
9892
+ const ac = new AbortController;
9893
+ const timer = setTimeout(() => ac.abort(), options.llmTimeoutMs ?? 300000);
9894
+ let llmOutput;
9895
+ try {
9896
+ const delegatePromise = options.llmDelegate(CURATOR_POSTMORTEM_PROMPT, userInput, ac.signal);
9897
+ delegatePromise.catch(() => {});
9898
+ llmOutput = await Promise.race([
9899
+ delegatePromise,
9900
+ new Promise((_, reject) => {
9901
+ ac.signal.addEventListener("abort", () => reject(new Error("CURATOR_LLM_TIMEOUT")));
9902
+ })
9903
+ ]);
9904
+ } finally {
9905
+ clearTimeout(timer);
9906
+ }
9907
+ let parsedActions = _internals10.parsePostMortemActions(llmOutput);
9908
+ if (parsedActions.diagnostics.length > 0) {
9909
+ warnings.push(`Post-mortem structured action parse diagnostics: ${parsedActions.diagnostics.join("; ")}`);
9910
+ const repaired = await _internals10.repairPostMortemActions(llmOutput, parsedActions.diagnostics, options);
9911
+ if (repaired) {
9912
+ parsedActions = repaired;
9913
+ warnings.push("Post-mortem structured actions repaired by LLM.");
9914
+ }
9915
+ }
9916
+ llmSummary = parsedActions.summary;
9917
+ const executed = await _internals10.executePostMortemActions(directory, parsedActions, options);
9918
+ actionResult = executed.result;
9919
+ warnings.push(...executed.warnings);
9920
+ const knowledgeVerification = await _internals10.verifyPostMortemKnowledgeActions(directory, parsedActions.recommendations);
9921
+ for (const item of knowledgeVerification) {
9922
+ if (item.status === "not_found" || item.status === "ambiguous_prefix" || item.status === "missing_entry_id") {
9923
+ warnings.push(`Post-mortem knowledge action ${item.action} for '${item.input_entry_id ?? "new"}' ${item.status}: ${item.reason}`);
9924
+ }
9925
+ }
9926
+ const freshnessSummary = buildStateFreshnessSection({
9927
+ planId: effectivePlanId,
9928
+ scope,
9929
+ sessionID: options.sessionID,
9930
+ planLoaded,
9931
+ knowledgeSummary,
9932
+ proposals,
9933
+ unactionable,
9934
+ retrospectives,
9935
+ driftReports
9936
+ });
9937
+ const verificationSummary = buildActionVerificationSection(knowledgeVerification);
9938
+ const actionSummary = [
9939
+ "## Executed Post-Mortem Actions",
9940
+ `- Knowledge actions: ${actionResult.knowledge_applied} applied, ${actionResult.knowledge_skipped} skipped`,
9941
+ `- Hive actions: ${actionResult.hive_promotions} new promotions, ${actionResult.hive_encounters_incremented} encounters incremented, ${actionResult.hive_advancements} advancements`,
9942
+ `- Proposal actions: ${actionResult.proposals_approved} approved, ${actionResult.proposals_rejected} rejected, ${actionResult.proposals_skipped} skipped`
9943
+ ].join(`
9944
+ `);
9945
+ reportContent = `# Post-Mortem Report: ${effectivePlanId}
9946
+ Generated: ${new Date().toISOString()}
9947
+ Scope: ${scope}
9948
+
9949
+ ${freshnessSummary}
9950
+
9951
+ ${llmOutput}
9952
+
9953
+ ${verificationSummary}
9954
+
9955
+ ${actionSummary}`;
9956
+ } catch (err) {
9957
+ const msg = err instanceof Error ? err.message : String(err);
9958
+ warnings.push(`LLM delegate failed, falling back to data-only report: ${msg}`);
9959
+ reportContent = _internals10.buildDataOnlyReport(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports, { scope, sessionID: options.sessionID, planLoaded });
9960
+ }
9961
+ } else {
9962
+ reportContent = _internals10.buildDataOnlyReport(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports, { scope, sessionID: options.sessionID, planLoaded });
9963
+ }
9964
+ try {
9965
+ const { mkdirSync: mkdirSync8 } = await import("fs");
9966
+ mkdirSync8(path16.dirname(reportPath), { recursive: true });
9967
+ await atomicWriteFile(reportPath, reportContent);
9968
+ } catch (err) {
9969
+ const msg = err instanceof Error ? err.message : String(err);
9970
+ return {
9971
+ success: false,
9972
+ planId: effectivePlanId,
9973
+ reportPath: null,
9974
+ summary: null,
9975
+ warnings: [...warnings, `Failed to write report: ${msg}`]
9976
+ };
9977
+ }
9978
+ const totalEntries = knowledgeSummary.length;
9979
+ const neverAppliedCount = knowledgeSummary.filter((e) => e.applied === 0 && e.violated === 0 && e.ignored === 0).length;
9980
+ const totalViolations = knowledgeSummary.reduce((s, e) => s + e.violated, 0);
9981
+ const mechanicalSummary = [
9982
+ `Post-mortem for plan "${effectivePlanId}": ${totalEntries} knowledge entries reviewed.`,
9983
+ `${neverAppliedCount} never-applied entries flagged; ${totalViolations} total violations recorded.`,
9984
+ `${proposals.length} pending proposals, ${unactionable.length} quarantined entries.`
9985
+ ].join(" ");
9986
+ const summary = llmSummary ?? mechanicalSummary;
9987
+ return {
9988
+ success: true,
9989
+ planId: effectivePlanId,
9990
+ reportPath,
9991
+ summary,
9992
+ warnings,
9993
+ actions: actionResult
9994
+ };
9995
+ } finally {
9996
+ if (lock.release) {
9997
+ try {
9998
+ await lock.release();
9876
9999
  } catch {}
9877
- skipped++;
9878
- continue;
9879
10000
  }
9880
- await appendKnowledge(knowledgePath, newEntry);
9881
- applied++;
9882
- currentLessons.push(lesson);
9883
10001
  }
9884
- return { applied, skipped };
9885
10002
  }
10003
+ var _internals10 = {
10004
+ acquirePostMortemLock,
10005
+ collectKnowledgeSummary,
10006
+ collectRetrospectives,
10007
+ collectDriftReports,
10008
+ collectPendingProposals,
10009
+ readJsonlFile,
10010
+ buildDataOnlyReport,
10011
+ assembleLLMInput,
10012
+ buildStateFreshnessSection,
10013
+ buildActionVerificationSection,
10014
+ isReportValid,
10015
+ parsePostMortemActions,
10016
+ executePostMortemActions,
10017
+ verifyPostMortemKnowledgeActions,
10018
+ repairPostMortemActions,
10019
+ loadDefaultKnowledgeConfig: async () => {
10020
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-s48je8zt.js");
10021
+ return KnowledgeConfigSchema2.parse({});
10022
+ },
10023
+ applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig) => {
10024
+ const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-qpgdv0fp.js");
10025
+ return applyCuratorKnowledgeUpdates2(directory, recommendations, knowledgeConfig);
10026
+ },
10027
+ checkHivePromotions: async (entries, knowledgeConfig) => {
10028
+ const { checkHivePromotions } = await import("./hive-promoter-rs5dr4pf.js");
10029
+ return checkHivePromotions(entries, knowledgeConfig);
10030
+ },
10031
+ applyProposalTriage: async (directory, triage) => {
10032
+ const {
10033
+ _internals: skillInternals,
10034
+ activateProposal,
10035
+ listSkills: listSkills2,
10036
+ sanitizeSlug
10037
+ } = await import("./skill-generator-5rsjmmfq.js");
10038
+ const result = {
10039
+ approved: [],
10040
+ rejected: [],
10041
+ skipped: []
10042
+ };
10043
+ const skills = await listSkills2(directory);
10044
+ const proposalSlugs = new Set(skills.proposals.map((p) => p.slug));
10045
+ for (const item of triage) {
10046
+ const slug = sanitizeSlug(normalizeProposalSlug(item.proposal_id));
10047
+ if (!slug || !proposalSlugs.has(slug)) {
10048
+ result.skipped.push(slug || item.proposal_id);
10049
+ continue;
10050
+ }
10051
+ if (item.action === "apply") {
10052
+ const activation = await activateProposal(directory, slug, false, {
10053
+ evaluate: true,
10054
+ operation: "post_mortem_queue_triage",
10055
+ confirmUnevaluated: true
10056
+ });
10057
+ if (activation.activated) {
10058
+ result.approved.push(slug);
10059
+ } else {
10060
+ result.skipped.push(slug);
10061
+ }
10062
+ continue;
10063
+ }
10064
+ const proposal = skills.proposals.find((p) => p.slug === slug);
10065
+ if (!proposal) {
10066
+ result.skipped.push(slug);
10067
+ continue;
10068
+ }
10069
+ try {
10070
+ skillInternals.unlinkSync(proposal.path);
10071
+ result.rejected.push(slug);
10072
+ } catch {
10073
+ result.skipped.push(slug);
10074
+ }
10075
+ }
10076
+ return result;
10077
+ },
10078
+ readPriorDriftReports: async (directory) => {
10079
+ const { readPriorDriftReports } = await import("./curator-drift-169wgaxn.js");
10080
+ return readPriorDriftReports(directory);
10081
+ },
10082
+ readSwarmKnowledge: (directory) => readKnowledge(resolveSwarmKnowledgePath(directory))
10083
+ };
9886
10084
 
9887
10085
  // src/hooks/hive-promoter.ts
10086
+ import path17 from "path";
9888
10087
  function carryActionableFields(source) {
9889
10088
  const out = {};
9890
10089
  if (source.triggers?.length)
@@ -14535,7 +14734,7 @@ async function runFinalizeStage(ctx) {
14535
14734
  }
14536
14735
  }
14537
14736
  try {
14538
- const { CuratorConfigSchema: CCS } = await import("./schema-5vmb5dh8.js");
14737
+ const { CuratorConfigSchema: CCS } = await import("./schema-s48je8zt.js");
14539
14738
  const { config: pmLoadedConfig } = _internals17.loadPluginConfigWithMeta(ctx.directory);
14540
14739
  const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
14541
14740
  if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
@@ -16648,9 +16847,9 @@ var _internals21 = {
16648
16847
  readSwarmFileAsync,
16649
16848
  loadCuratorDeps: async () => {
16650
16849
  const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate: createCuratorLLMDelegate2 }] = await Promise.all([
16651
- import("./schema-5vmb5dh8.js"),
16652
- import("./curator-4qqzpd85.js"),
16653
- import("./curator-llm-factory-y4kvr1ph.js")
16850
+ import("./schema-s48je8zt.js"),
16851
+ import("./curator-qpgdv0fp.js"),
16852
+ import("./curator-llm-factory-3x89ddtd.js")
16654
16853
  ]);
16655
16854
  return { CuratorConfigSchema, curator, createCuratorLLMDelegate: createCuratorLLMDelegate2 };
16656
16855
  }
@@ -17146,7 +17345,7 @@ import { fileURLToPath } from "url";
17146
17345
  // package.json
17147
17346
  var package_default = {
17148
17347
  name: "opencode-swarm",
17149
- version: "7.110.0",
17348
+ version: "7.110.2",
17150
17349
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
17151
17350
  main: "dist/index.js",
17152
17351
  types: "dist/index.d.ts",
@@ -18598,7 +18797,7 @@ async function handleDoctorCommand(directory, args) {
18598
18797
  const result = runConfigDoctor(config, directory);
18599
18798
  let output;
18600
18799
  if (enableAutoFix && result.hasAutoFixableIssues) {
18601
- const { runConfigDoctorWithFixes } = await import("./config-doctor-9vjyj9m3.js");
18800
+ const { runConfigDoctorWithFixes } = await import("./config-doctor-q5e9yzn6.js");
18602
18801
  const fixResult = await runConfigDoctorWithFixes(directory, config, true);
18603
18802
  output = formatDoctorMarkdown(fixResult.result);
18604
18803
  } else {
@@ -31871,7 +32070,7 @@ function buildDetailedHelp(commandName, entry) {
31871
32070
  async function handleHelpCommand(ctx) {
31872
32071
  const targetCommand = ctx.args.join(" ");
31873
32072
  if (!targetCommand) {
31874
- const { buildHelpText } = await import("./index-khj0knr0.js");
32073
+ const { buildHelpText } = await import("./index-rm8b4959.js");
31875
32074
  return buildHelpText();
31876
32075
  }
31877
32076
  const tokens = targetCommand.split(/\s+/);
@@ -31880,7 +32079,7 @@ async function handleHelpCommand(ctx) {
31880
32079
  return _internals46.buildDetailedHelp(resolved.key, resolved.entry);
31881
32080
  }
31882
32081
  const similar = _internals46.findSimilarCommands(targetCommand);
31883
- const { buildHelpText: fullHelp } = await import("./index-khj0knr0.js");
32082
+ const { buildHelpText: fullHelp } = await import("./index-rm8b4959.js");
31884
32083
  if (similar.length > 0) {
31885
32084
  return `Command '/swarm ${targetCommand}' not found.
31886
32085
 
@@ -31900,7 +32099,7 @@ Showing full help:
31900
32099
  }
31901
32100
  async function handleModeCommandWithBundledSkills(ctx, handler) {
31902
32101
  if (ctx.packageRoot) {
31903
- await syncBundledProjectSkillsIfMissingAsync(ctx.directory, ctx.packageRoot);
32102
+ await syncBundledProjectSkillsIfMissingAsync(ctx.directory, ctx.packageRoot, true);
31904
32103
  }
31905
32104
  return Promise.resolve(handler(ctx.directory, ctx.args));
31906
32105
  }
@@ -32013,7 +32212,7 @@ var COMMAND_REGISTRY = {
32013
32212
  },
32014
32213
  "guardrail explain": {
32015
32214
  handler: async (ctx) => {
32016
- const { handleGuardrailExplain } = await import("./guardrail-explain-10hh57cr.js");
32215
+ const { handleGuardrailExplain } = await import("./guardrail-explain-jdwp6h9c.js");
32017
32216
  return handleGuardrailExplain(ctx.directory, ctx.args);
32018
32217
  },
32019
32218
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -32023,7 +32222,7 @@ var COMMAND_REGISTRY = {
32023
32222
  },
32024
32223
  "guardrail-log": {
32025
32224
  handler: async (ctx) => {
32026
- const { handleGuardrailLog } = await import("./guardrail-log-5240bawg.js");
32225
+ const { handleGuardrailLog } = await import("./guardrail-log-973nan7m.js");
32027
32226
  return handleGuardrailLog(ctx.directory, ctx.args);
32028
32227
  },
32029
32228
  description: "Read the guardrail decision log (use --blocks-only for blocks)",
@@ -33776,6 +33975,9 @@ If you see references to other agents (like @reviewer, @coder, etc.) in your ins
33776
33975
  WRONG: "I'll use the Task tool to call another agent to review this code"
33777
33976
  RIGHT: "I'll read the changed files and review them myself"
33778
33977
 
33978
+ ## KNOWLEDGE RECEIPTS
33979
+ If you call \`knowledge_recall\` or receive a knowledge directive block with a trace_id, file exactly one \`knowledge_receipt\` before final output: mark each relevant entry as applied, ignored, or contradicted with evidence, or set \`no_relevant_knowledge:true\`. The receipt records audit events; it does not replace any required \`KNOWLEDGE_APPLIED\`, \`KNOWLEDGE_IGNORED\`, or \`KNOWLEDGE_VIOLATED\` directive-compliance line.
33980
+
33779
33981
  ${READ_ONLY_LANE_GUIDANCE}
33780
33982
 
33781
33983
  ## REVIEW FOCUS
@@ -37116,4 +37318,4 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
37116
37318
  };
37117
37319
  }
37118
37320
 
37119
- export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, createCuratorLLMDelegate, _internals10 as _internals, parseKnowledgeRecommendations, parseKnowledgeRecommendationsWithDiagnostics, parseStructuredCuratorBlocks, readCuratorSummary, writeCuratorSummary, filterPhaseEvents, checkPhaseCompliance, runCuratorInit, runCuratorPhase, applyCuratorKnowledgeUpdates, isHiveEligible, checkHivePromotions, createHivePromoterHook, promoteToHive, promoteFromSwarm, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryValueLogCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals46 as _internals1, resolveCommand };
37321
+ export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, createCuratorLLMDelegate, _internals9 as _internals, normalizeRecommendationEntryIdToken, parseKnowledgeRecommendations, parseKnowledgeRecommendationsWithDiagnostics, parseStructuredCuratorBlocks, readCuratorSummary, writeCuratorSummary, filterPhaseEvents, checkPhaseCompliance, runCuratorInit, runCuratorPhase, applyCuratorKnowledgeUpdates, isHiveEligible, checkHivePromotions, createHivePromoterHook, promoteToHive, promoteFromSwarm, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryValueLogCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals46 as _internals1, resolveCommand };