opencode-swarm 7.74.0 → 7.74.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.
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.74.0",
72
+ version: "7.74.2",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -648,7 +648,7 @@ var init_tool_metadata = __esm(() => {
648
648
  agents: ["architect", "coder"]
649
649
  },
650
650
  knowledge_archive: {
651
- description: "archive (default), quarantine, or purge a swarm knowledge entry by ID with an immutable audit tombstone; purge requires an admin flag",
651
+ description: "archive (default), quarantine, or purge a swarm or hive knowledge entry by ID with an immutable audit tombstone; purge requires an admin flag",
652
652
  agents: ["architect"]
653
653
  },
654
654
  swarm_memory_recall: {
@@ -15921,7 +15921,11 @@ var init_schema = __esm(() => {
15921
15921
  cold_start_max_age_phases: exports_external.number().int().min(0).max(100).default(3),
15922
15922
  synonym_min_cooccurrence: exports_external.number().int().min(1).max(100).default(3),
15923
15923
  synonym_map_max_pairs: exports_external.number().int().min(1).max(1e4).default(500)
15924
- }).optional()
15924
+ }).optional(),
15925
+ enrichment: exports_external.object({
15926
+ max_calls_per_day: exports_external.number().int().min(0).max(1000).default(30),
15927
+ quota_window: exports_external.enum(["utc", "local"]).default("utc")
15928
+ }).default({ max_calls_per_day: 30, quota_window: "utc" })
15925
15929
  });
15926
15930
  MemoryConfigSchema = exports_external.object({
15927
15931
  enabled: exports_external.boolean().default(false),
@@ -15988,7 +15992,7 @@ var init_schema = __esm(() => {
15988
15992
  llm_timeout_ms: exports_external.number().int().min(5000).max(600000).default(300000),
15989
15993
  skill_generation_enabled: exports_external.boolean().default(true),
15990
15994
  skill_generation_mode: exports_external.enum(["draft", "active"]).default("draft"),
15991
- min_skill_confidence: exports_external.number().min(0).max(1).default(0.85),
15995
+ min_skill_confidence: exports_external.number().min(0).max(1).default(0.7),
15992
15996
  min_skill_confirmations: exports_external.number().int().min(1).max(50).default(2)
15993
15997
  });
15994
15998
  ArchitecturalSupervisionConfigSchema = exports_external.object({
@@ -59523,7 +59527,7 @@ async function appendKnowledgeWithCapEnforcement(filePath, entry, maxEntries) {
59523
59527
  return transactKnowledge(filePath, (entries) => {
59524
59528
  const updated = [...entries, entry];
59525
59529
  if (updated.length > maxEntries) {
59526
- return updated.slice(updated.length - maxEntries);
59530
+ return selectKnowledgeCapSurvivors(updated, maxEntries);
59527
59531
  }
59528
59532
  return updated;
59529
59533
  });
@@ -59532,9 +59536,46 @@ async function enforceKnowledgeCap(filePath, maxEntries) {
59532
59536
  await transactKnowledge(filePath, (entries) => {
59533
59537
  if (entries.length <= maxEntries)
59534
59538
  return null;
59535
- return entries.slice(entries.length - maxEntries);
59539
+ return selectKnowledgeCapSurvivors(entries, maxEntries);
59536
59540
  });
59537
59541
  }
59542
+ function selectKnowledgeCapSurvivors(entries, maxEntries) {
59543
+ if (entries.length <= maxEntries)
59544
+ return entries;
59545
+ if (maxEntries <= 0)
59546
+ return [];
59547
+ const candidates = entries.map((entry, index) => {
59548
+ const maybeKnowledge = entry;
59549
+ return {
59550
+ entry,
59551
+ index,
59552
+ status: maybeKnowledge.status,
59553
+ outcomeSignal: computeOutcomeSignal(maybeKnowledge.retrieval_outcomes)
59554
+ };
59555
+ });
59556
+ const allPromoted = candidates.every((c) => c.status === "promoted");
59557
+ const evictable = allPromoted ? candidates : candidates.filter((c) => c.status !== "promoted");
59558
+ const targetDropCount = entries.length - maxEntries;
59559
+ const dropCount = Math.min(targetDropCount, evictable.length);
59560
+ if (dropCount <= 0)
59561
+ return entries;
59562
+ const drop = new Set([...evictable].sort((a, b) => {
59563
+ const inactiveDelta = getKnowledgeCapStatusPriority(a.status) - getKnowledgeCapStatusPriority(b.status);
59564
+ if (inactiveDelta !== 0)
59565
+ return inactiveDelta;
59566
+ const signalDelta = a.outcomeSignal - b.outcomeSignal;
59567
+ if (signalDelta !== 0)
59568
+ return signalDelta;
59569
+ return a.index - b.index;
59570
+ }).slice(0, dropCount).map((c) => c.index));
59571
+ return candidates.filter((c) => !drop.has(c.index)).map((c) => c.entry);
59572
+ }
59573
+ function getKnowledgeCapStatusPriority(status) {
59574
+ if (status === "archived" || status === "quarantined" || status === "quarantined_unactionable") {
59575
+ return 0;
59576
+ }
59577
+ return 1;
59578
+ }
59538
59579
  async function sweepAgedEntries(filePath, defaultMaxPhases) {
59539
59580
  const result = {
59540
59581
  scanned: 0,
@@ -59770,6 +59811,7 @@ var init_knowledge_store = __esm(() => {
59770
59811
  findNearDuplicate,
59771
59812
  computeConfidence,
59772
59813
  computeOutcomeSignal,
59814
+ selectKnowledgeCapSurvivors,
59773
59815
  inferTags,
59774
59816
  bumpKnowledgeConfidenceBatch
59775
59817
  };
@@ -59780,6 +59822,7 @@ var exports_knowledge_events = {};
59780
59822
  __export(exports_knowledge_events, {
59781
59823
  resolveLegacyApplicationLogPath: () => resolveLegacyApplicationLogPath,
59782
59824
  resolveKnowledgeEventsPath: () => resolveKnowledgeEventsPath,
59825
+ resolveKnowledgeCounterBaselinePath: () => resolveKnowledgeCounterBaselinePath,
59783
59826
  recordKnowledgeEvent: () => recordKnowledgeEvent,
59784
59827
  recomputeCounters: () => recomputeCounters,
59785
59828
  readLegacyApplicationRecords: () => readLegacyApplicationRecords,
@@ -59800,11 +59843,14 @@ __export(exports_knowledge_events, {
59800
59843
  });
59801
59844
  import { randomUUID as randomUUID2 } from "node:crypto";
59802
59845
  import { existsSync as existsSync15 } from "node:fs";
59803
- import { appendFile as appendFile4, mkdir as mkdir4, readFile as readFile5, writeFile as writeFile3 } from "node:fs/promises";
59846
+ import { appendFile as appendFile4, mkdir as mkdir4, readFile as readFile5, stat as stat3 } from "node:fs/promises";
59804
59847
  import * as path32 from "node:path";
59805
59848
  function resolveKnowledgeEventsPath(directory) {
59806
59849
  return path32.join(directory, ".swarm", "knowledge-events.jsonl");
59807
59850
  }
59851
+ function resolveKnowledgeCounterBaselinePath(directory) {
59852
+ return path32.join(directory, ".swarm", "knowledge-counter-baseline.json");
59853
+ }
59808
59854
  function resolveLegacyApplicationLogPath(directory) {
59809
59855
  return path32.join(directory, ".swarm", "knowledge-application.jsonl");
59810
59856
  }
@@ -59839,10 +59885,12 @@ async function appendKnowledgeEvent(directory, event) {
59839
59885
  const lines = content.split(`
59840
59886
  `).filter((line) => line.trim().length > 0);
59841
59887
  if (lines.length > MAX_EVENT_LOG_ENTRIES) {
59888
+ const evicted = lines.slice(0, lines.length - MAX_EVENT_LOG_ENTRIES);
59842
59889
  const trimmed = lines.slice(lines.length - MAX_EVENT_LOG_ENTRIES);
59843
- await writeFile3(filePath, `${trimmed.join(`
59890
+ await foldEvictedEventsIntoBaseline(directory, evicted, filePath);
59891
+ await atomicWriteFile(filePath, `${trimmed.join(`
59844
59892
  `)}
59845
- `, "utf-8");
59893
+ `);
59846
59894
  }
59847
59895
  } catch (err2) {
59848
59896
  warn(`[knowledge-events] local cap trim failed (non-fatal): ${err2 instanceof Error ? err2.message : String(err2)}`);
@@ -59866,19 +59914,8 @@ async function readKnowledgeEvents(directory) {
59866
59914
  if (!existsSync15(filePath))
59867
59915
  return [];
59868
59916
  const content = await readFile5(filePath, "utf-8");
59869
- const out2 = [];
59870
- for (const line of content.split(`
59871
- `)) {
59872
- const trimmed = line.trim();
59873
- if (!trimmed)
59874
- continue;
59875
- try {
59876
- out2.push(JSON.parse(trimmed));
59877
- } catch {
59878
- warn(`[knowledge-events] Skipping corrupted JSONL line in ${filePath}: ${trimmed.slice(0, 80)}`);
59879
- }
59880
- }
59881
- return out2;
59917
+ return parseEventLines(content.split(`
59918
+ `), filePath);
59882
59919
  }
59883
59920
  async function readLegacyApplicationRecords(directory) {
59884
59921
  const filePath = resolveLegacyApplicationLogPath(directory);
@@ -59914,6 +59951,49 @@ function emptyRollup() {
59914
59951
  violation_timestamps: []
59915
59952
  };
59916
59953
  }
59954
+ function cloneRollup(input) {
59955
+ return {
59956
+ ...emptyRollup(),
59957
+ ...input,
59958
+ violation_timestamps: [...input.violation_timestamps ?? []]
59959
+ };
59960
+ }
59961
+ function cloneRollupMap(input) {
59962
+ const out2 = new Map;
59963
+ for (const [id, rollup] of input) {
59964
+ out2.set(id, cloneRollup(rollup));
59965
+ }
59966
+ return out2;
59967
+ }
59968
+ function normalizeRollupTimestamps(rollup) {
59969
+ if (rollup.violation_timestamps.length > 1) {
59970
+ rollup.violation_timestamps.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
59971
+ }
59972
+ if (rollup.violation_timestamps.length > MAX_VIOLATION_TIMESTAMPS) {
59973
+ rollup.violation_timestamps = rollup.violation_timestamps.slice(0, MAX_VIOLATION_TIMESTAMPS);
59974
+ }
59975
+ return rollup;
59976
+ }
59977
+ function mergeRollupInto(target, source) {
59978
+ target.shown_count += source.shown_count ?? 0;
59979
+ target.acknowledged_count += source.acknowledged_count ?? 0;
59980
+ target.applied_explicit_count += source.applied_explicit_count ?? 0;
59981
+ target.ignored_count += source.ignored_count ?? 0;
59982
+ target.violated_count += source.violated_count ?? 0;
59983
+ target.contradicted_count += source.contradicted_count ?? 0;
59984
+ target.n_a_count += source.n_a_count ?? 0;
59985
+ target.succeeded_after_shown_count += source.succeeded_after_shown_count ?? 0;
59986
+ target.failed_after_shown_count += source.failed_after_shown_count ?? 0;
59987
+ target.partial_after_shown_count += source.partial_after_shown_count ?? 0;
59988
+ if (source.last_applied_at) {
59989
+ target.last_applied_at = maxIso(target.last_applied_at, source.last_applied_at);
59990
+ }
59991
+ if (source.last_acknowledged_at) {
59992
+ target.last_acknowledged_at = maxIso(target.last_acknowledged_at, source.last_acknowledged_at);
59993
+ }
59994
+ target.violation_timestamps.push(...source.violation_timestamps ?? []);
59995
+ normalizeRollupTimestamps(target);
59996
+ }
59917
59997
  function get(map3, id) {
59918
59998
  let r = map3.get(id);
59919
59999
  if (!r) {
@@ -59927,9 +60007,91 @@ function maxIso(current, candidate) {
59927
60007
  return candidate;
59928
60008
  return candidate > current ? candidate : current;
59929
60009
  }
59930
- function recomputeCounters(events, legacyRecords = []) {
60010
+ async function readCounterBaseline(directory) {
60011
+ const filePath = resolveKnowledgeCounterBaselinePath(directory);
60012
+ if (!existsSync15(filePath))
60013
+ return new Map;
60014
+ const raw = JSON.parse(await readFile5(filePath, "utf-8"));
60015
+ const map3 = new Map;
60016
+ for (const [id, rollup] of Object.entries(raw)) {
60017
+ map3.set(id, normalizeRollupTimestamps(cloneRollup(rollup)));
60018
+ }
60019
+ return map3;
60020
+ }
60021
+ async function writeCounterBaseline(directory, baseline) {
60022
+ const filePath = resolveKnowledgeCounterBaselinePath(directory);
60023
+ const out2 = {};
60024
+ for (const [id, rollup] of [...baseline.entries()].sort(([a], [b]) => a.localeCompare(b))) {
60025
+ out2[id] = normalizeRollupTimestamps(cloneRollup(rollup));
60026
+ }
60027
+ await atomicWriteFile(filePath, `${JSON.stringify(out2, null, 2)}
60028
+ `);
60029
+ }
60030
+ async function statCacheKey(filePath) {
60031
+ try {
60032
+ const fileStat = await stat3(filePath);
60033
+ return `${fileStat.mtimeMs}:${fileStat.ctimeMs}:${fileStat.size}`;
60034
+ } catch (err2) {
60035
+ if (err2?.code === "ENOENT")
60036
+ return "missing";
60037
+ throw err2;
60038
+ }
60039
+ }
60040
+ async function buildCounterRollupCacheKey(directory) {
60041
+ const [eventsKey, legacyKey, baselineKey] = await Promise.all([
60042
+ statCacheKey(resolveKnowledgeEventsPath(directory)),
60043
+ statCacheKey(resolveLegacyApplicationLogPath(directory)),
60044
+ statCacheKey(resolveKnowledgeCounterBaselinePath(directory))
60045
+ ]);
60046
+ return `${eventsKey}|${legacyKey}|${baselineKey}`;
60047
+ }
60048
+ function setCounterRollupCache(directory, key, rollups) {
60049
+ if (counterRollupCache.has(directory)) {
60050
+ counterRollupCache.delete(directory);
60051
+ }
60052
+ counterRollupCache.set(directory, {
60053
+ key,
60054
+ rollups: cloneRollupMap(rollups)
60055
+ });
60056
+ while (counterRollupCache.size > MAX_COUNTER_ROLLUP_CACHE_DIRS) {
60057
+ const oldestKey = counterRollupCache.keys().next().value;
60058
+ if (oldestKey === undefined)
60059
+ break;
60060
+ counterRollupCache.delete(oldestKey);
60061
+ }
60062
+ }
60063
+ function parseEventLines(lines, filePath) {
60064
+ const out2 = [];
60065
+ for (const line of lines) {
60066
+ const trimmed = line.trim();
60067
+ if (!trimmed)
60068
+ continue;
60069
+ try {
60070
+ out2.push(JSON.parse(trimmed));
60071
+ } catch {
60072
+ warn(`[knowledge-events] Skipping corrupted JSONL line in ${filePath}: ${trimmed.slice(0, 80)}`);
60073
+ }
60074
+ }
60075
+ return out2;
60076
+ }
60077
+ async function foldEvictedEventsIntoBaseline(directory, evictedLines, filePath) {
60078
+ const evictedEvents = parseEventLines(evictedLines, filePath);
60079
+ if (evictedEvents.length === 0)
60080
+ return;
60081
+ const baseline = await readCounterBaseline(directory);
60082
+ for (const [id, rollup] of recomputeCounters(evictedEvents)) {
60083
+ mergeRollupInto(get(baseline, id), rollup);
60084
+ }
60085
+ await writeCounterBaseline(directory, baseline);
60086
+ }
60087
+ function recomputeCounters(events, legacyRecords = [], baseline = new Map) {
59931
60088
  const map3 = new Map;
59932
60089
  const retrievedIds = new Set;
60090
+ for (const [id, rollup] of baseline) {
60091
+ map3.set(id, cloneRollup(rollup));
60092
+ if ((rollup.shown_count ?? 0) > 0)
60093
+ retrievedIds.add(id);
60094
+ }
59933
60095
  for (const e of events) {
59934
60096
  switch (e.type) {
59935
60097
  case "retrieved": {
@@ -60005,12 +60167,7 @@ function recomputeCounters(events, legacyRecords = []) {
60005
60167
  }
60006
60168
  }
60007
60169
  for (const r of map3.values()) {
60008
- if (r.violation_timestamps.length > 1) {
60009
- r.violation_timestamps.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
60010
- }
60011
- if (r.violation_timestamps.length > MAX_VIOLATION_TIMESTAMPS) {
60012
- r.violation_timestamps = r.violation_timestamps.slice(0, MAX_VIOLATION_TIMESTAMPS);
60013
- }
60170
+ normalizeRollupTimestamps(r);
60014
60171
  }
60015
60172
  return map3;
60016
60173
  }
@@ -60053,11 +60210,21 @@ async function countEntryViolationsInWindow(directory, entryId, windowDays, now
60053
60210
  }
60054
60211
  async function readKnowledgeCounterRollups(directory) {
60055
60212
  try {
60056
- const [events, legacyRecords] = await Promise.all([
60213
+ const cacheKey = await buildCounterRollupCacheKey(directory);
60214
+ const cached3 = counterRollupCache.get(directory);
60215
+ if (cached3?.key === cacheKey) {
60216
+ counterRollupCache.delete(directory);
60217
+ counterRollupCache.set(directory, cached3);
60218
+ return cloneRollupMap(cached3.rollups);
60219
+ }
60220
+ const [events, legacyRecords, baseline] = await Promise.all([
60057
60221
  readKnowledgeEvents(directory),
60058
- readLegacyApplicationRecords(directory)
60222
+ readLegacyApplicationRecords(directory),
60223
+ readCounterBaseline(directory)
60059
60224
  ]);
60060
- return recomputeCounters(events, legacyRecords);
60225
+ const rollups = recomputeCounters(events, legacyRecords, baseline);
60226
+ setCounterRollupCache(directory, cacheKey, rollups);
60227
+ return cloneRollupMap(rollups);
60061
60228
  } catch (err2) {
60062
60229
  warn(`[knowledge-events] readKnowledgeCounterRollups failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
60063
60230
  return new Map;
@@ -60124,10 +60291,12 @@ async function applyKnowledgeVerdictFeedback(directory, options) {
60124
60291
  return { processed: 0, bumps: 0 };
60125
60292
  }
60126
60293
  }
60127
- var import_proper_lockfile4, KNOWLEDGE_EVENT_SCHEMA_VERSION = 1, MAX_EVENT_LOG_ENTRIES = 5000, RECEIPT_EVENT_TYPES, MAX_VIOLATION_TIMESTAMPS = 10, VERDICT_CONFIDENCE_BOOST = 0.03, VERDICT_CONFIDENCE_DECAY = 0.05, _internals23;
60294
+ var import_proper_lockfile4, KNOWLEDGE_EVENT_SCHEMA_VERSION = 1, MAX_EVENT_LOG_ENTRIES = 5000, counterRollupCache, MAX_COUNTER_ROLLUP_CACHE_DIRS = 32, RECEIPT_EVENT_TYPES, MAX_VIOLATION_TIMESTAMPS = 10, VERDICT_CONFIDENCE_BOOST = 0.03, VERDICT_CONFIDENCE_DECAY = 0.05, _internals23;
60128
60295
  var init_knowledge_events = __esm(() => {
60296
+ init_task_file();
60129
60297
  init_logger();
60130
60298
  import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
60299
+ counterRollupCache = new Map;
60131
60300
  RECEIPT_EVENT_TYPES = new Set([
60132
60301
  "acknowledged",
60133
60302
  "applied",
@@ -60139,9 +60308,11 @@ var init_knowledge_events = __esm(() => {
60139
60308
  ]);
60140
60309
  _internals23 = {
60141
60310
  resolveKnowledgeEventsPath,
60311
+ resolveKnowledgeCounterBaselinePath,
60142
60312
  appendKnowledgeEvent,
60143
60313
  recordKnowledgeEvent,
60144
60314
  readKnowledgeEvents,
60315
+ readCounterBaseline,
60145
60316
  readLegacyApplicationRecords,
60146
60317
  readKnowledgeCounterRollups,
60147
60318
  effectiveRetrievalOutcomes,
@@ -60779,7 +60950,7 @@ function validateLesson(candidate, existingLessons, meta3) {
60779
60950
  };
60780
60951
  }
60781
60952
  const normalizedCandidate = candidate.normalize("NFKC").replace(INVISIBLE_FORMAT_CHARS, " ").replace(/\s+/g, " ").toLowerCase();
60782
- for (const pattern of DANGEROUS_COMMAND_PATTERNS) {
60953
+ for (const pattern of DANGEROUS_COMMAND_ERROR_PATTERNS) {
60783
60954
  if (pattern.test(normalizedCandidate)) {
60784
60955
  return {
60785
60956
  valid: false,
@@ -60789,6 +60960,16 @@ function validateLesson(candidate, existingLessons, meta3) {
60789
60960
  };
60790
60961
  }
60791
60962
  }
60963
+ for (const pattern of DANGEROUS_COMMAND_WARNING_PATTERNS) {
60964
+ if (pattern.test(normalizedCandidate)) {
60965
+ return {
60966
+ valid: true,
60967
+ layer: 2,
60968
+ reason: "potentially dangerous command pattern queued for review",
60969
+ severity: "warning"
60970
+ };
60971
+ }
60972
+ }
60792
60973
  for (const pattern of SECURITY_DEGRADING_PATTERNS) {
60793
60974
  if (pattern.test(normalizedCandidate)) {
60794
60975
  return {
@@ -60811,10 +60992,10 @@ function validateLesson(candidate, existingLessons, meta3) {
60811
60992
  }
60812
60993
  if (detectContradiction(candidate, existingLessons)) {
60813
60994
  return {
60814
- valid: false,
60995
+ valid: true,
60815
60996
  layer: 3,
60816
- reason: "lesson contradicts an existing lesson with shared tags",
60817
- severity: "error"
60997
+ reason: "possible contradiction with an existing lesson with shared tags",
60998
+ severity: "warning"
60818
60999
  };
60819
61000
  }
60820
61001
  if (isVagueLesson(candidate)) {
@@ -60954,31 +61135,22 @@ async function appendUnactionable(directory, entry, reason) {
60954
61135
  const filePath = resolveUnactionablePath(directory);
60955
61136
  const dirPath = path33.dirname(filePath);
60956
61137
  await mkdir5(dirPath, { recursive: true });
60957
- let release = null;
60958
- try {
60959
- release = await import_proper_lockfile5.default.lock(dirPath, {
60960
- retries: { retries: 50, minTimeout: 10, maxTimeout: 100 },
60961
- stale: 5000
60962
- });
61138
+ await transactKnowledge(filePath, (existing) => {
60963
61139
  const record3 = {
60964
61140
  ...entry,
60965
61141
  status: "quarantined_unactionable",
60966
61142
  unactionable_reason: reason,
60967
61143
  quarantined_at: new Date().toISOString()
60968
61144
  };
60969
- await appendFile5(filePath, `${JSON.stringify(record3)}
60970
- `, "utf-8");
60971
- const existing = await readKnowledge(filePath);
60972
- if (existing.length > 200) {
60973
- const trimmed = existing.slice(-200);
60974
- await atomicWriteFile(filePath, `${trimmed.map((e) => JSON.stringify(e)).join(`
60975
- `)}
60976
- `);
61145
+ const duplicate = findNearDuplicate(record3.lesson, existing, 0.6);
61146
+ if (duplicate?.unactionable_reason === reason) {
61147
+ duplicate.quarantined_at = record3.quarantined_at;
61148
+ duplicate.updated_at = record3.updated_at;
61149
+ return existing;
60977
61150
  }
60978
- } finally {
60979
- if (release)
60980
- await release().catch(() => {});
60981
- }
61151
+ const next = [...existing, record3];
61152
+ return next.length > 200 ? next.slice(-200) : next;
61153
+ });
60982
61154
  }
60983
61155
  async function quarantineEntry(directory, entryId, reason, reportedBy) {
60984
61156
  if (!directory || directory.includes("..")) {
@@ -61112,28 +61284,34 @@ async function restoreEntry(directory, entryId) {
61112
61284
  }
61113
61285
  }
61114
61286
  }
61115
- var import_proper_lockfile5, DANGEROUS_COMMAND_PATTERNS, SECURITY_DEGRADING_PATTERNS, INVISIBLE_FORMAT_CHARS, INJECTION_PATTERNS, VALID_CATEGORIES, TECH_REFERENCE_WORDS, ACTION_VERB_WORDS, NEGATION_PAIRS, ACTIONABLE_STRING_MAX = 200, ACTIONABLE_LIST_MAX = 20, NAME_PATTERN, SOURCE_REF_FORBIDDEN, ALLOWED_SKILL_PATH_PREFIXES, VALID_DIRECTIVE_PRIORITIES;
61287
+ var import_proper_lockfile5, DANGEROUS_COMMAND_ERROR_PATTERNS, DANGEROUS_COMMAND_WARNING_PATTERNS, DANGEROUS_COMMAND_PATTERNS, SECURITY_DEGRADING_PATTERNS, INVISIBLE_FORMAT_CHARS, INJECTION_PATTERNS, VALID_CATEGORIES, TECH_REFERENCE_WORDS, ACTION_VERB_WORDS, NEGATION_PAIRS, ACTIONABLE_STRING_MAX = 200, ACTIONABLE_LIST_MAX = 20, NAME_PATTERN, SOURCE_REF_FORBIDDEN, ALLOWED_SKILL_PATH_PREFIXES, VALID_DIRECTIVE_PRIORITIES;
61116
61288
  var init_knowledge_validator = __esm(() => {
61117
61289
  init_task_file();
61118
61290
  init_logger();
61119
61291
  init_knowledge_store();
61120
61292
  import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
61121
- DANGEROUS_COMMAND_PATTERNS = [
61293
+ DANGEROUS_COMMAND_ERROR_PATTERNS = [
61122
61294
  /\brm\s+-rf\b/,
61123
61295
  /\bsudo\s+rm\b/,
61124
- /\bformat\b/,
61125
61296
  /\bmkfs\b/,
61126
61297
  /\bdd\s+if=/,
61127
61298
  /:\(\)\s*\{/,
61128
61299
  /\bchmod\s+-R\s+777\b/i,
61129
61300
  /\bdeltree\b/,
61130
- /\brmdir\s+\/s\b/,
61301
+ /\brmdir\s+\/s\b/
61302
+ ];
61303
+ DANGEROUS_COMMAND_WARNING_PATTERNS = [
61304
+ /\bformat\b/,
61131
61305
  /\bkill\s+-9\b/,
61132
61306
  /\bpkill\b/,
61133
61307
  /\bkillall\b/,
61134
61308
  /`[^`]*`/,
61135
61309
  /\$\([^)]*\)/
61136
61310
  ];
61311
+ DANGEROUS_COMMAND_PATTERNS = [
61312
+ ...DANGEROUS_COMMAND_ERROR_PATTERNS,
61313
+ ...DANGEROUS_COMMAND_WARNING_PATTERNS
61314
+ ];
61137
61315
  SECURITY_DEGRADING_PATTERNS = [
61138
61316
  /disable\s+.{0,50}firewall/i,
61139
61317
  /turn\s+off\s+.{0,50}security/i,
@@ -61235,7 +61413,7 @@ var init_knowledge_validator = __esm(() => {
61235
61413
  });
61236
61414
 
61237
61415
  // src/services/skill-changelog.ts
61238
- import { appendFile as appendFile6, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
61416
+ import { appendFile as appendFile6, mkdir as mkdir6, readFile as readFile6, writeFile as writeFile3 } from "node:fs/promises";
61239
61417
  import * as path34 from "node:path";
61240
61418
  function resolveSkillChangelogPath(directory, slug) {
61241
61419
  if (slug.includes("..") || slug.includes("/") || slug.includes("\\")) {
@@ -61255,7 +61433,7 @@ async function appendSkillChangelog(directory, slug, entry) {
61255
61433
  `).filter((line) => line.trim().length > 0);
61256
61434
  if (lines.length > MAX_CHANGELOG_ENTRIES_PER_SKILL) {
61257
61435
  const trimmed = lines.slice(lines.length - MAX_CHANGELOG_ENTRIES_PER_SKILL);
61258
- await writeFile4(filePath, `${trimmed.join(`
61436
+ await writeFile3(filePath, `${trimmed.join(`
61259
61437
  `)}
61260
61438
  `, "utf-8");
61261
61439
  }
@@ -61280,6 +61458,7 @@ __export(exports_skill_generator, {
61280
61458
  parseDraftFrontmatter: () => parseDraftFrontmatter,
61281
61459
  listSkills: () => listSkills,
61282
61460
  isValidSlug: () => isValidSlug,
61461
+ isSkillMaturityEligible: () => isSkillMaturityEligible,
61283
61462
  inspectSkill: () => inspectSkill,
61284
61463
  generateSkills: () => generateSkills,
61285
61464
  clusterEntries: () => clusterEntries,
@@ -61287,10 +61466,13 @@ __export(exports_skill_generator, {
61287
61466
  activeRepoRelativePath: () => activeRepoRelativePath,
61288
61467
  activePath: () => activePath,
61289
61468
  activateProposal: () => activateProposal,
61290
- _internals: () => _internals24
61469
+ _internals: () => _internals24,
61470
+ STRONG_SKILL_OUTCOME_COUNT: () => STRONG_SKILL_OUTCOME_COUNT,
61471
+ DEFAULT_SKILL_MIN_CONFIRMATIONS: () => DEFAULT_SKILL_MIN_CONFIRMATIONS,
61472
+ DEFAULT_SKILL_MIN_CONFIDENCE: () => DEFAULT_SKILL_MIN_CONFIDENCE
61291
61473
  });
61292
61474
  import { existsSync as existsSync17, unlinkSync as unlinkSync5 } from "node:fs";
61293
- import { mkdir as mkdir7, readFile as readFile7, rename as rename3, writeFile as writeFile5 } from "node:fs/promises";
61475
+ import { mkdir as mkdir7, readFile as readFile7, rename as rename3, writeFile as writeFile4 } from "node:fs/promises";
61294
61476
  import * as path35 from "node:path";
61295
61477
  function sanitizeSlug(input) {
61296
61478
  const lc = input.toLowerCase().trim();
@@ -61315,18 +61497,35 @@ async function selectCandidateEntries(directory, opts) {
61315
61497
  const hivePath = resolveHiveKnowledgePath();
61316
61498
  const hive = existsSync17(hivePath) ? await readKnowledge(hivePath) : [];
61317
61499
  const all = [...swarm, ...hive];
61318
- return all.filter((e) => {
61500
+ const counterRollups = await readKnowledgeCounterRollups(directory);
61501
+ const selected = [];
61502
+ for (const e of all) {
61319
61503
  if (e.status === "archived")
61320
- return false;
61321
- if (e.confidence < opts.minConfidence)
61322
- return false;
61323
- const confirmations = (e.confirmed_by ?? []).length;
61324
- if (confirmations < opts.minConfirmations)
61325
- return false;
61504
+ continue;
61326
61505
  if (e.generated_skill_slug)
61327
- return false;
61328
- return true;
61329
- });
61506
+ continue;
61507
+ const outcomes = effectiveRetrievalOutcomes(e.retrieval_outcomes, counterRollups.get(e.id));
61508
+ if (!isSkillMaturityEligible(e, opts, outcomes))
61509
+ continue;
61510
+ selected.push({ ...e, retrieval_outcomes: outcomes });
61511
+ }
61512
+ return selected;
61513
+ }
61514
+ function hasStrongSkillOutcomeRecord(outcomes) {
61515
+ return (outcomes?.applied_explicit_count ?? 0) >= STRONG_SKILL_OUTCOME_COUNT || (outcomes?.succeeded_after_shown_count ?? 0) >= STRONG_SKILL_OUTCOME_COUNT;
61516
+ }
61517
+ function isHighPriorityDirective(entry) {
61518
+ return entry.directive_priority === "critical" || entry.directive_priority === "high";
61519
+ }
61520
+ function isSkillMaturityEligible(entry, opts, outcomes = entry.retrieval_outcomes) {
61521
+ const outcomeSignal = computeOutcomeSignal(outcomes);
61522
+ if (outcomeSignal < 0)
61523
+ return false;
61524
+ const strongOutcomes = hasStrongSkillOutcomeRecord(outcomes);
61525
+ if (entry.confidence < opts.minConfidence && !strongOutcomes)
61526
+ return false;
61527
+ const confirmations = (entry.confirmed_by ?? []).length;
61528
+ return confirmations >= opts.minConfirmations || strongOutcomes;
61330
61529
  }
61331
61530
  function jaccardSimilarity(setA, setB) {
61332
61531
  const normA = setA.map((s) => s.toLowerCase());
@@ -61366,8 +61565,9 @@ function clusterEntries(entries) {
61366
61565
  }
61367
61566
  const result = [];
61368
61567
  for (const c of clusters) {
61369
- if (c.members.length < MIN_CLUSTER_SIZE)
61568
+ if (c.members.length < MIN_CLUSTER_SIZE && !isSkillSingletonEligible(c.members[0])) {
61370
61569
  continue;
61570
+ }
61371
61571
  const arr = c.members;
61372
61572
  const triggers = uniqueStrings(arr.flatMap((e) => e.triggers ?? []));
61373
61573
  const required3 = uniqueStrings(arr.flatMap((e) => e.required_actions ?? []));
@@ -61393,6 +61593,11 @@ function clusterEntries(entries) {
61393
61593
  result.sort((a, b) => b.entries.length - a.entries.length || b.avgConfidence - a.avgConfidence || a.slug.localeCompare(b.slug));
61394
61594
  return result;
61395
61595
  }
61596
+ function isSkillSingletonEligible(entry) {
61597
+ if (!entry)
61598
+ return false;
61599
+ return isHighPriorityDirective(entry) || hasStrongSkillOutcomeRecord(entry.retrieval_outcomes);
61600
+ }
61396
61601
  function uniqueStrings(arr) {
61397
61602
  return [...new Set(arr.filter((s) => typeof s === "string" && s.length > 0))];
61398
61603
  }
@@ -61493,12 +61698,12 @@ function escapeMarkdown(s) {
61493
61698
  async function atomicWrite2(p, content) {
61494
61699
  await mkdir7(path35.dirname(p), { recursive: true });
61495
61700
  const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
61496
- await writeFile5(tmp, content, "utf-8");
61701
+ await writeFile4(tmp, content, "utf-8");
61497
61702
  await rename3(tmp, p);
61498
61703
  }
61499
61704
  async function generateSkills(req) {
61500
- const minConfidence = req.minConfidence ?? 0.85;
61501
- const minConfirmations = req.minConfirmations ?? 2;
61705
+ const minConfidence = req.minConfidence ?? DEFAULT_SKILL_MIN_CONFIDENCE;
61706
+ const minConfirmations = req.minConfirmations ?? DEFAULT_SKILL_MIN_CONFIRMATIONS;
61502
61707
  const candidates = await selectCandidateEntries(req.directory, {
61503
61708
  minConfidence,
61504
61709
  minConfirmations
@@ -61893,7 +62098,7 @@ async function retireSkill(directory, slug, reason) {
61893
62098
  reason: reason ?? "manual_retire"
61894
62099
  });
61895
62100
  await mkdir7(markerDir, { recursive: true });
61896
- await writeFile5(markerPath, markerContent, "utf-8");
62101
+ await writeFile4(markerPath, markerContent, "utf-8");
61897
62102
  return {
61898
62103
  retired: true,
61899
62104
  path: skillPath,
@@ -62056,8 +62261,9 @@ async function regenerateSkill(directory, slug) {
62056
62261
  entryCount: matchedEntries.length
62057
62262
  };
62058
62263
  }
62059
- var SLUG_PATTERN, MIN_CLUSTER_SIZE = 2, JACCARD_THRESHOLD = 0.5, AUTO_APPLY_BATCH_LIMIT = 5, _internals24;
62264
+ var SLUG_PATTERN, DEFAULT_SKILL_MIN_CONFIDENCE = 0.7, DEFAULT_SKILL_MIN_CONFIRMATIONS = 2, STRONG_SKILL_OUTCOME_COUNT = 3, MIN_CLUSTER_SIZE = 2, JACCARD_THRESHOLD = 0.5, AUTO_APPLY_BATCH_LIMIT = 5, _internals24;
62060
62265
  var init_skill_generator = __esm(() => {
62266
+ init_knowledge_events();
62061
62267
  init_knowledge_store();
62062
62268
  init_knowledge_validator();
62063
62269
  init_logger();
@@ -62067,6 +62273,7 @@ var init_skill_generator = __esm(() => {
62067
62273
  sanitizeSlug,
62068
62274
  isValidSlug,
62069
62275
  selectCandidateEntries,
62276
+ isSkillMaturityEligible,
62070
62277
  clusterEntries,
62071
62278
  jaccardSimilarity,
62072
62279
  renderSkillMarkdown,
@@ -62085,7 +62292,7 @@ var init_skill_generator = __esm(() => {
62085
62292
 
62086
62293
  // src/services/skill-improver-quota.ts
62087
62294
  import { existsSync as existsSync18 } from "node:fs";
62088
- import { mkdir as mkdir8, readFile as readFile8, rename as rename4, writeFile as writeFile6 } from "node:fs/promises";
62295
+ import { mkdir as mkdir8, readFile as readFile8, rename as rename4, writeFile as writeFile5 } from "node:fs/promises";
62089
62296
  import * as path36 from "node:path";
62090
62297
  async function acquireLock(dir) {
62091
62298
  const acquire = import_proper_lockfile6.default.lock(dir, LOCK_RETRY_OPTS);
@@ -62103,8 +62310,9 @@ async function acquireLock(dir) {
62103
62310
  clearTimeout(timer);
62104
62311
  }
62105
62312
  }
62106
- function resolveQuotaPath(directory) {
62107
- return path36.join(directory, ".swarm", "skill-improver-quota.json");
62313
+ function resolveQuotaPath(directory, scope = "skill-improver") {
62314
+ const fileName = scope === "knowledge-enrichment" ? "knowledge-enrichment-quota.json" : "skill-improver-quota.json";
62315
+ return path36.join(directory, ".swarm", fileName);
62108
62316
  }
62109
62317
  function todayKey(window2, now = new Date) {
62110
62318
  if (window2 === "utc") {
@@ -62132,11 +62340,11 @@ async function readState(filePath) {
62132
62340
  async function writeState(filePath, state) {
62133
62341
  await mkdir8(path36.dirname(filePath), { recursive: true });
62134
62342
  const tmp = `${filePath}.tmp-${process.pid}`;
62135
- await writeFile6(tmp, JSON.stringify(state, null, 2), "utf-8");
62343
+ await writeFile5(tmp, JSON.stringify(state, null, 2), "utf-8");
62136
62344
  await rename4(tmp, filePath);
62137
62345
  }
62138
62346
  async function getQuotaState(directory, opts) {
62139
- const filePath = resolveQuotaPath(directory);
62347
+ const filePath = resolveQuotaPath(directory, opts.scope);
62140
62348
  const today = todayKey(opts.window, opts.now);
62141
62349
  const existing = await readState(filePath);
62142
62350
  if (!existing || existing.date !== today || existing.window !== opts.window) {
@@ -62152,7 +62360,7 @@ async function getQuotaState(directory, opts) {
62152
62360
  return { ...existing, max_calls: opts.maxCalls };
62153
62361
  }
62154
62362
  async function reserveQuota(directory, opts) {
62155
- const filePath = resolveQuotaPath(directory);
62363
+ const filePath = resolveQuotaPath(directory, opts.scope);
62156
62364
  await mkdir8(path36.dirname(filePath), { recursive: true });
62157
62365
  let release = null;
62158
62366
  try {
@@ -62182,7 +62390,7 @@ async function reserveQuota(directory, opts) {
62182
62390
  }
62183
62391
  }
62184
62392
  async function releaseQuota(directory, opts) {
62185
- const filePath = resolveQuotaPath(directory);
62393
+ const filePath = resolveQuotaPath(directory, opts.scope);
62186
62394
  await mkdir8(path36.dirname(filePath), { recursive: true });
62187
62395
  let release = null;
62188
62396
  try {
@@ -62218,7 +62426,7 @@ var init_skill_improver_quota = __esm(() => {
62218
62426
  });
62219
62427
 
62220
62428
  // src/services/skill-reviser.ts
62221
- import { readFile as readFile9, rename as rename5, writeFile as writeFile7 } from "node:fs/promises";
62429
+ import { readFile as readFile9, rename as rename5, writeFile as writeFile6 } from "node:fs/promises";
62222
62430
  async function getSkillVersion(skillPath) {
62223
62431
  try {
62224
62432
  const content = await readFile9(skillPath, "utf-8");
@@ -62324,7 +62532,7 @@ async function reviseSkill(params) {
62324
62532
  try {
62325
62533
  const revised = _internals25.buildDeterministicRevision(params.currentContent, params.currentVersion, params.violationContexts);
62326
62534
  const tmpPath = `${params.skillPath}.tmp-${process.pid}-${Date.now()}`;
62327
- await writeFile7(tmpPath, revised, "utf-8");
62535
+ await writeFile6(tmpPath, revised, "utf-8");
62328
62536
  await rename5(tmpPath, params.skillPath);
62329
62537
  const newVersion = params.currentVersion + 1;
62330
62538
  const entry = {
@@ -62392,7 +62600,7 @@ async function reviseSkill(params) {
62392
62600
  finalOutput = finalOutput.replace(/^version:\s*\d+\s*$/m, `version: ${expectedVersion}`);
62393
62601
  }
62394
62602
  const tmpPath = `${params.skillPath}.tmp-${process.pid}-${Date.now()}`;
62395
- await writeFile7(tmpPath, `${finalOutput}
62603
+ await writeFile6(tmpPath, `${finalOutput}
62396
62604
  `, "utf-8");
62397
62605
  await rename5(tmpPath, params.skillPath);
62398
62606
  const newVersion = expectedVersion;
@@ -62458,6 +62666,89 @@ function resolveLogPath(directory) {
62458
62666
  function normalizeComplianceVerdict(verdict) {
62459
62667
  return verdict === "violation" ? "violated" : verdict;
62460
62668
  }
62669
+ function normalizeSkillUsageEntry(raw) {
62670
+ const entry = raw;
62671
+ return {
62672
+ ...entry,
62673
+ complianceVerdict: normalizeComplianceVerdict(entry.complianceVerdict)
62674
+ };
62675
+ }
62676
+ function legacySkillUsageId(entry) {
62677
+ const stable = JSON.stringify({
62678
+ skillPath: entry.skillPath,
62679
+ agentName: entry.agentName,
62680
+ taskID: entry.taskID,
62681
+ timestamp: entry.timestamp,
62682
+ complianceVerdict: entry.complianceVerdict,
62683
+ sessionID: entry.sessionID,
62684
+ skillVersion: entry.skillVersion
62685
+ });
62686
+ return `legacy:${crypto4.createHash("sha256").update(stable).digest("hex")}`;
62687
+ }
62688
+ function parseSkillUsageEntry(raw) {
62689
+ const entry = raw;
62690
+ if (entry.type === "feedback_applied")
62691
+ return null;
62692
+ if (typeof entry.skillPath !== "string" || typeof entry.agentName !== "string" || typeof entry.taskID !== "string" || typeof entry.timestamp !== "string" || typeof entry.complianceVerdict !== "string" || typeof entry.sessionID !== "string") {
62693
+ return null;
62694
+ }
62695
+ return normalizeSkillUsageEntry({
62696
+ ...entry,
62697
+ id: typeof entry.id === "string" ? entry.id : legacySkillUsageId(entry)
62698
+ });
62699
+ }
62700
+ function parseFeedbackMarker(raw) {
62701
+ const marker = raw;
62702
+ if (marker.type !== "feedback_applied")
62703
+ return null;
62704
+ if (typeof marker.timestamp !== "string")
62705
+ return null;
62706
+ if (!Array.isArray(marker.processedEntryIds))
62707
+ return null;
62708
+ const processedEntryIds = marker.processedEntryIds.filter((id) => typeof id === "string" && id.length > 0);
62709
+ return {
62710
+ type: "feedback_applied",
62711
+ timestamp: marker.timestamp,
62712
+ processedEntryIds
62713
+ };
62714
+ }
62715
+ function readFeedbackAppliedEntryIds(directory) {
62716
+ const resolved = resolveLogPath(directory);
62717
+ const processed = new Set;
62718
+ if (!_internals26.existsSync(resolved))
62719
+ return processed;
62720
+ const raw = _internals26.readFileSync(resolved, "utf-8");
62721
+ for (const line of raw.split(`
62722
+ `)) {
62723
+ const trimmed = line.trim();
62724
+ if (!trimmed)
62725
+ continue;
62726
+ try {
62727
+ const marker = parseFeedbackMarker(JSON.parse(trimmed));
62728
+ if (!marker)
62729
+ continue;
62730
+ for (const id of marker.processedEntryIds)
62731
+ processed.add(id);
62732
+ } catch {}
62733
+ }
62734
+ return processed;
62735
+ }
62736
+ function appendFeedbackAppliedMarker(directory, processedEntryIds) {
62737
+ if (processedEntryIds.length === 0)
62738
+ return;
62739
+ const resolved = resolveLogPath(directory);
62740
+ const dir = path37.dirname(resolved);
62741
+ if (!_internals26.existsSync(dir)) {
62742
+ _internals26.mkdirSync(dir, { recursive: true });
62743
+ }
62744
+ const marker = {
62745
+ type: "feedback_applied",
62746
+ timestamp: new Date().toISOString(),
62747
+ processedEntryIds: [...new Set(processedEntryIds)]
62748
+ };
62749
+ _internals26.appendFileSync(resolved, `${JSON.stringify(marker)}
62750
+ `, "utf-8");
62751
+ }
62461
62752
  function appendSkillUsageEntry(directory, entry) {
62462
62753
  const {
62463
62754
  skillPath,
@@ -62501,7 +62792,7 @@ function appendSkillUsageEntry(directory, entry) {
62501
62792
  agentName,
62502
62793
  taskID,
62503
62794
  timestamp,
62504
- complianceVerdict,
62795
+ complianceVerdict: normalizeComplianceVerdict(complianceVerdict),
62505
62796
  sessionID,
62506
62797
  ...reviewerNotes !== undefined && { reviewerNotes },
62507
62798
  ...skillVersion !== undefined && { skillVersion }
@@ -62509,8 +62800,8 @@ function appendSkillUsageEntry(directory, entry) {
62509
62800
  _internals26.appendFileSync(resolved, `${JSON.stringify(fullEntry)}
62510
62801
  `, "utf-8");
62511
62802
  try {
62512
- const stat3 = _internals26.statSync(resolved);
62513
- if (stat3.size > SKILL_USAGE_LOG_ROTATE_BYTES) {
62803
+ const stat4 = _internals26.statSync(resolved);
62804
+ if (stat4.size > SKILL_USAGE_LOG_ROTATE_BYTES) {
62514
62805
  _internals26.pruneSkillUsageLog(directory, SKILL_USAGE_LOG_MAX_ENTRIES_PER_SKILL);
62515
62806
  }
62516
62807
  } catch {}
@@ -62528,9 +62819,9 @@ function readSkillUsageEntries(directory, options) {
62528
62819
  if (!trimmed)
62529
62820
  continue;
62530
62821
  try {
62531
- const entry = JSON.parse(trimmed);
62532
- entry.complianceVerdict = normalizeComplianceVerdict(entry.complianceVerdict);
62533
- entries.push(entry);
62822
+ const entry = parseSkillUsageEntry(JSON.parse(trimmed));
62823
+ if (entry)
62824
+ entries.push(entry);
62534
62825
  } catch {}
62535
62826
  }
62536
62827
  if (!options)
@@ -62564,11 +62855,11 @@ function readSkillUsageEntriesTail(directory, filters, maxBytes = TAIL_BYTES_DEF
62564
62855
  try {
62565
62856
  const normalizedMaxBytes = Number.isFinite(maxBytes) ? maxBytes : TAIL_BYTES_DEFAULT;
62566
62857
  const boundedMaxBytes = Math.min(Math.max(1, normalizedMaxBytes), MAX_TAIL_BYTES);
62567
- const stat3 = _internals26.statSync(logPath);
62568
- const start2 = Math.max(0, stat3.size - boundedMaxBytes);
62858
+ const stat4 = _internals26.statSync(logPath);
62859
+ const start2 = Math.max(0, stat4.size - boundedMaxBytes);
62569
62860
  const fd = _internals26.openSync(logPath, "r");
62570
62861
  try {
62571
- const readLen = stat3.size - start2;
62862
+ const readLen = stat4.size - start2;
62572
62863
  if (readLen === 0)
62573
62864
  return [];
62574
62865
  const buf = Buffer.alloc(readLen);
@@ -62588,8 +62879,9 @@ function readSkillUsageEntriesTail(directory, filters, maxBytes = TAIL_BYTES_DEF
62588
62879
  if (!line.trim())
62589
62880
  continue;
62590
62881
  try {
62591
- const entry = JSON.parse(line);
62592
- entry.complianceVerdict = normalizeComplianceVerdict(entry.complianceVerdict);
62882
+ const entry = parseSkillUsageEntry(JSON.parse(line));
62883
+ if (!entry)
62884
+ continue;
62593
62885
  if (filters.sessionID !== undefined && entry.sessionID !== filters.sessionID) {
62594
62886
  continue;
62595
62887
  }
@@ -62624,8 +62916,9 @@ function computeComplianceByVersion(entries, skillPath) {
62624
62916
  stats.total += 1;
62625
62917
  if (e.complianceVerdict === "compliant")
62626
62918
  stats.compliant += 1;
62627
- if (e.complianceVerdict === "violated")
62919
+ if (normalizeComplianceVerdict(e.complianceVerdict) === "violated") {
62628
62920
  stats.violation += 1;
62921
+ }
62629
62922
  }
62630
62923
  for (const stats of map3.values()) {
62631
62924
  stats.rate = stats.total === 0 ? 0 : stats.compliant / stats.total;
@@ -62736,6 +63029,7 @@ async function applySkillUsageFeedback(directory, options) {
62736
63029
  let bumps = 0;
62737
63030
  try {
62738
63031
  const allEntries = readSkillUsageEntries(directory);
63032
+ const alreadyProcessed = readFeedbackAppliedEntryIds(directory);
62739
63033
  const actionable = allEntries.filter((e) => {
62740
63034
  if (e.complianceVerdict !== "compliant" && e.complianceVerdict !== "violated") {
62741
63035
  return false;
@@ -62743,6 +63037,9 @@ async function applySkillUsageFeedback(directory, options) {
62743
63037
  if (options?.sinceTimestamp && e.timestamp <= options.sinceTimestamp) {
62744
63038
  return false;
62745
63039
  }
63040
+ if (alreadyProcessed.has(e.id)) {
63041
+ return false;
63042
+ }
62746
63043
  return true;
62747
63044
  });
62748
63045
  if (actionable.length === 0) {
@@ -62757,6 +63054,7 @@ async function applySkillUsageFeedback(directory, options) {
62757
63054
  groups.set(entry.skillPath, [entry]);
62758
63055
  }
62759
63056
  const allDeltas = [];
63057
+ const processedEntryIds = [];
62760
63058
  for (const [skillPath, entries] of Array.from(groups)) {
62761
63059
  let compliantCount = 0;
62762
63060
  let violationCount = 0;
@@ -62775,6 +63073,7 @@ async function applySkillUsageFeedback(directory, options) {
62775
63073
  for (const id of sourceIds) {
62776
63074
  allDeltas.push({ id, delta });
62777
63075
  }
63076
+ processedEntryIds.push(...entries.map((entry) => entry.id));
62778
63077
  processed++;
62779
63078
  bumps += sourceIds.length;
62780
63079
  }
@@ -62788,6 +63087,7 @@ async function applySkillUsageFeedback(directory, options) {
62788
63087
  }));
62789
63088
  if (clampedDeltas.length > 0) {
62790
63089
  await bumpKnowledgeConfidenceBatch(directory, clampedDeltas);
63090
+ appendFeedbackAppliedMarker(directory, processedEntryIds);
62791
63091
  }
62792
63092
  } catch (err2) {
62793
63093
  console.warn("[skill-usage-log] applySkillUsageFeedback failed (fail-open):", err2 instanceof Error ? err2.message : String(err2));
@@ -62814,7 +63114,10 @@ var init_skill_usage_log = __esm(() => {
62814
63114
  resolveSourceKnowledgeIds,
62815
63115
  applySkillUsageFeedback,
62816
63116
  parseGeneratedFromKnowledge,
62817
- computeComplianceByVersion
63117
+ computeComplianceByVersion,
63118
+ normalizeComplianceVerdict,
63119
+ readFeedbackAppliedEntryIds,
63120
+ appendFeedbackAppliedMarker
62818
63121
  };
62819
63122
  TAIL_BYTES_DEFAULT = 64 * 1024;
62820
63123
  MAX_TAIL_BYTES = TAIL_BYTES_DEFAULT;
@@ -62847,7 +63150,7 @@ async function autoRetireSkills(directory, curatorKnowledgePath, excludeSlugs) {
62847
63150
  return true;
62848
63151
  return false;
62849
63152
  });
62850
- const violations = skillUsage.filter((e) => e.complianceVerdict === "violated").length;
63153
+ const violations = skillUsage.filter((e) => normalizeComplianceVerdict(e.complianceVerdict) === "violated").length;
62851
63154
  const violationRate = skillUsage.length > 0 ? violations / skillUsage.length : 0;
62852
63155
  let allArchived = false;
62853
63156
  try {
@@ -63512,7 +63815,7 @@ ${phaseDigest.summary}`,
63512
63815
  });
63513
63816
  if (skillUsage.length === 0)
63514
63817
  continue;
63515
- const violations = skillUsage.filter((e) => e.complianceVerdict === "violated").length;
63818
+ const violations = skillUsage.filter((e) => normalizeComplianceVerdict(e.complianceVerdict) === "violated").length;
63516
63819
  const violationRate = violations / skillUsage.length;
63517
63820
  if (violationRate > REVISION_VIOLATION_THRESHOLD && violationRate <= 0.3) {
63518
63821
  const content = await _internals27.readFileAsync(active.path, "utf-8");
@@ -63520,7 +63823,7 @@ ${phaseDigest.summary}`,
63520
63823
  if (fm && fm.skillOrigin === "promoted_external")
63521
63824
  continue;
63522
63825
  const currentVersion = fm?.version ?? 1;
63523
- const violationContexts = skillUsage.filter((e) => e.complianceVerdict === "violated").slice(-10).map((e) => ({
63826
+ const violationContexts = skillUsage.filter((e) => normalizeComplianceVerdict(e.complianceVerdict) === "violated").slice(-10).map((e) => ({
63524
63827
  taskId: e.taskID,
63525
63828
  agent: e.agentName,
63526
63829
  verdict: e.complianceVerdict,
@@ -63814,6 +64117,9 @@ function isAlreadyInHive(entry, hiveEntries, threshold) {
63814
64117
  return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
63815
64118
  }
63816
64119
  function isHiveEligible(entry, autoPromoteDays) {
64120
+ if (!isActiveForHivePromotion(entry)) {
64121
+ return false;
64122
+ }
63817
64123
  const phaseNumbers = new Set;
63818
64124
  for (const record3 of entry.confirmed_by ?? []) {
63819
64125
  if (record3 && typeof record3.phase_number === "number") {
@@ -63834,6 +64140,9 @@ function isHiveEligible(entry, autoPromoteDays) {
63834
64140
  }
63835
64141
  return false;
63836
64142
  }
64143
+ function isActiveForHivePromotion(entry) {
64144
+ return !["archived", "quarantined", "quarantined_unactionable"].includes(entry.status);
64145
+ }
63837
64146
  function countDistinctProjects(confirmedBy) {
63838
64147
  const projectNames = new Set;
63839
64148
  for (const record3 of confirmedBy) {
@@ -63916,7 +64225,7 @@ async function checkHivePromotions(swarmEntries, config3) {
63916
64225
  }
63917
64226
  let hiveModified = false;
63918
64227
  for (const hiveEntry of hiveEntries) {
63919
- const nearDuplicate = findNearDuplicate(hiveEntry.lesson, swarmEntries, config3.dedup_threshold);
64228
+ const nearDuplicate = findNearDuplicate(hiveEntry.lesson, swarmEntries.filter(isActiveForHivePromotion), config3.dedup_threshold);
63920
64229
  if (!nearDuplicate) {
63921
64230
  continue;
63922
64231
  }
@@ -64074,9 +64383,9 @@ import {
64074
64383
  mkdir as mkdir9,
64075
64384
  readFile as readFile10,
64076
64385
  rename as rename6,
64077
- stat as stat3,
64386
+ stat as stat4,
64078
64387
  unlink as unlink2,
64079
- writeFile as writeFile8
64388
+ writeFile as writeFile7
64080
64389
  } from "node:fs/promises";
64081
64390
  import * as path40 from "node:path";
64082
64391
  function emptySynonymMap() {
@@ -64263,7 +64572,7 @@ async function readSynonymMap(directory, maxPairs = DEFAULT_MAX_PAIRS) {
64263
64572
  }
64264
64573
  try {
64265
64574
  const ceiling = Math.max(MIN_READ_CEILING_BYTES, Math.floor(maxPairs) * APPROX_BYTES_PER_PAIR);
64266
- const st = await stat3(filePath);
64575
+ const st = await stat4(filePath);
64267
64576
  if (st.size > ceiling)
64268
64577
  return emptySynonymMap();
64269
64578
  const raw = await readFile10(filePath, "utf-8");
@@ -64276,7 +64585,7 @@ async function writeSynonymMapAtomic(filePath, map3) {
64276
64585
  await mkdir9(path40.dirname(filePath), { recursive: true });
64277
64586
  const tmp = `${filePath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
64278
64587
  try {
64279
- await writeFile8(tmp, JSON.stringify(map3, null, 2), "utf-8");
64588
+ await writeFile7(tmp, JSON.stringify(map3, null, 2), "utf-8");
64280
64589
  await rename6(tmp, filePath);
64281
64590
  } finally {
64282
64591
  try {
@@ -64485,12 +64794,12 @@ function extractKeywords(text) {
64485
64794
  const words = text.toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= MIN_KEYWORD_LENGTH);
64486
64795
  return new Set(words);
64487
64796
  }
64488
- function computeContextMatchScore(taskDescription, skillPath) {
64797
+ function computeContextMatchScore(taskDescription, skillPath, metadata2) {
64489
64798
  const taskKeywords = extractKeywords(taskDescription);
64490
64799
  if (taskKeywords.size === 0)
64491
64800
  return 0;
64492
64801
  const skillName = extractSkillName(skillPath);
64493
- const skillText = `${skillPath} ${skillName}`;
64802
+ const skillText = `${skillPath} ${skillName} ${metadata2?.name ?? ""} ${metadata2?.description ?? ""}`;
64494
64803
  const skillKeywords = extractKeywords(skillText);
64495
64804
  let matchCount = 0;
64496
64805
  for (const kw of taskKeywords) {
@@ -64501,7 +64810,7 @@ function computeContextMatchScore(taskDescription, skillPath) {
64501
64810
  return matchCount / taskKeywords.size;
64502
64811
  }
64503
64812
  function computeSkillRelevanceScore(skillPath, taskDescription, usageHistory, metadata2) {
64504
- const contextScore = computeContextMatchScore(taskDescription, skillPath) * CONTEXT_WEIGHT;
64813
+ const contextScore = computeContextMatchScore(taskDescription, skillPath, metadata2) * CONTEXT_WEIGHT;
64505
64814
  if (usageHistory.length === 0)
64506
64815
  return Math.min(1, contextScore);
64507
64816
  const usageCount = usageHistory.length;
@@ -64576,8 +64885,8 @@ function formatSkillIndexWithContext(skills, directory) {
64576
64885
  const usageLogPath = path41.join(directory, ".swarm", "skill-usage.jsonl");
64577
64886
  let hasHistory = false;
64578
64887
  try {
64579
- const stat4 = fs21.statSync(usageLogPath);
64580
- hasHistory = stat4.size > 0;
64888
+ const stat5 = fs21.statSync(usageLogPath);
64889
+ hasHistory = stat5.size > 0;
64581
64890
  } catch {}
64582
64891
  if (!hasHistory) {
64583
64892
  return skills.map((sp) => {
@@ -65098,24 +65407,32 @@ async function skillPropagationTransformScan(directory, output, sessionID) {
65098
65407
  if (!text)
65099
65408
  continue;
65100
65409
  const skillPaths = [];
65410
+ let explicitReviewerTaskID;
65101
65411
  for (const line of text.split(`
65102
65412
  `)) {
65103
- const coderMatch = line.trim().match(CODER_SKILLS_PATTERN);
65413
+ const trimmed = line.trim();
65414
+ const taskMatch = trimmed.match(REVIEWER_TASK_PATTERN);
65415
+ if (taskMatch) {
65416
+ explicitReviewerTaskID = taskMatch[1];
65417
+ }
65418
+ const coderMatch = trimmed.match(CODER_SKILLS_PATTERN);
65104
65419
  if (coderMatch) {
65105
65420
  const parsed = _internals29.parseSkillPaths(coderMatch[1]);
65106
65421
  skillPaths.push(...parsed);
65107
65422
  }
65108
65423
  }
65109
- let resolvedTaskID = "unknown";
65424
+ let resolvedTaskID = explicitReviewerTaskID ?? "unknown";
65110
65425
  if (existingEntries.length > 0) {
65111
- const latestDelegation = [...existingEntries].reverse().find((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__");
65112
- if (latestDelegation) {
65113
- resolvedTaskID = latestDelegation.taskID;
65114
- if (skillPaths.length === 0) {
65115
- const delegatedPaths = existingEntries.filter((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__" && e.taskID === resolvedTaskID).map((e) => e.skillPath);
65116
- if (delegatedPaths.length > 0) {
65117
- skillPaths.push(...new Set(delegatedPaths));
65118
- }
65426
+ if (!explicitReviewerTaskID) {
65427
+ const latestDelegation = [...existingEntries].reverse().find((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__");
65428
+ if (latestDelegation) {
65429
+ resolvedTaskID = latestDelegation.taskID;
65430
+ }
65431
+ }
65432
+ if (skillPaths.length === 0 && resolvedTaskID !== "unknown") {
65433
+ const delegatedPaths = existingEntries.filter((e) => e.agentName !== "reviewer" && e.skillPath !== "__overall__" && e.taskID === resolvedTaskID).map((e) => e.skillPath);
65434
+ if (delegatedPaths.length > 0) {
65435
+ skillPaths.push(...new Set(delegatedPaths));
65119
65436
  }
65120
65437
  }
65121
65438
  }
@@ -65205,7 +65522,7 @@ async function skillPropagationTransformScan(directory, output, sessionID) {
65205
65522
  break;
65206
65523
  }
65207
65524
  }
65208
- var SKILL_CAPABLE_AGENTS, SKILL_SEARCH_ROOTS, MAX_SCORING_SESSION_ENTRIES = 500, _internals29, COMPLIANCE_PATTERN, CODER_SKILLS_PATTERN;
65525
+ var SKILL_CAPABLE_AGENTS, SKILL_SEARCH_ROOTS, MAX_SCORING_SESSION_ENTRIES = 500, _internals29, COMPLIANCE_PATTERN, CODER_SKILLS_PATTERN, REVIEWER_TASK_PATTERN;
65209
65526
  var init_skill_propagation_gate = __esm(() => {
65210
65527
  init_schema();
65211
65528
  init_logger();
@@ -65251,6 +65568,7 @@ var init_skill_propagation_gate = __esm(() => {
65251
65568
  };
65252
65569
  COMPLIANCE_PATTERN = /SKILL_COMPLIANCE\s*:\s*(COMPLIANT|PARTIAL|VIOLATED)(?:\s*(?:—|-)\s*(.*))?\s*$/i;
65253
65570
  CODER_SKILLS_PATTERN = /SKILLS_USED_BY_CODER\s*:\s*(.+)/i;
65571
+ REVIEWER_TASK_PATTERN = /TASK\s*:\s*(\S+)/i;
65254
65572
  _internals29.skillPropagationGateBefore = skillPropagationGateBefore;
65255
65573
  _internals29.skillPropagationTransformScan = skillPropagationTransformScan;
65256
65574
  _internals29.writeWarnEvent = writeWarnEvent;
@@ -65265,7 +65583,7 @@ var init_skill_propagation_gate = __esm(() => {
65265
65583
 
65266
65584
  // src/hooks/micro-reflector.ts
65267
65585
  import { existsSync as existsSync22 } from "node:fs";
65268
- import { readFile as readFile11, writeFile as writeFile9 } from "node:fs/promises";
65586
+ import { readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
65269
65587
  import * as path43 from "node:path";
65270
65588
  function resolveInsightCandidatesPath(directory) {
65271
65589
  return validateSwarmPath(directory, "insight-candidates.jsonl");
@@ -65334,7 +65652,7 @@ async function appendInsightCandidates(directory, candidates) {
65334
65652
  const body2 = data.length === 0 ? "" : `${data.map((c) => JSON.stringify(c)).join(`
65335
65653
  `)}
65336
65654
  `;
65337
- await writeFile9(p, body2, "utf-8");
65655
+ await writeFile8(p, body2, "utf-8");
65338
65656
  }, (all) => {
65339
65657
  const merged = [...all, ...candidates];
65340
65658
  const capped = merged.length > INSIGHT_CANDIDATES_MAX_ENTRIES ? merged.slice(-INSIGHT_CANDIDATES_MAX_ENTRIES) : merged;
@@ -65455,7 +65773,8 @@ async function runMicroReflection(params) {
65455
65773
  const reservation = await reserveQuota(params.directory, {
65456
65774
  nCalls: 1,
65457
65775
  maxCalls: quota.maxCalls,
65458
- window: quota.window
65776
+ window: quota.window,
65777
+ scope: "knowledge-enrichment"
65459
65778
  });
65460
65779
  if (!reservation.allowed)
65461
65780
  return result;
@@ -65542,7 +65861,7 @@ var init_micro_reflector = __esm(() => {
65542
65861
 
65543
65862
  // src/hooks/knowledge-curator.ts
65544
65863
  import { existsSync as existsSync23 } from "node:fs";
65545
- import { appendFile as appendFile7, mkdir as mkdir10, readFile as readFile12, writeFile as writeFile10 } from "node:fs/promises";
65864
+ import { appendFile as appendFile7, mkdir as mkdir10, readFile as readFile12, writeFile as writeFile9 } from "node:fs/promises";
65546
65865
  import * as path44 from "node:path";
65547
65866
  function pruneSeenRetroSections() {
65548
65867
  const cutoff = Date.now() - 86400000;
@@ -65783,7 +66102,8 @@ async function enrichLessonToV3(params) {
65783
66102
  const reservation = await reserveQuota(params.directory, {
65784
66103
  nCalls: 1,
65785
66104
  maxCalls: quota.maxCalls,
65786
- window: quota.window
66105
+ window: quota.window,
66106
+ scope: "knowledge-enrichment"
65787
66107
  });
65788
66108
  if (!reservation.allowed)
65789
66109
  return null;
@@ -65837,7 +66157,7 @@ async function consumeInsightCandidates(directory, batchLimit = MESO_INSIGHT_BAT
65837
66157
  const body2 = data.length === 0 ? "" : `${data.map((c) => JSON.stringify(c)).join(`
65838
66158
  `)}
65839
66159
  `;
65840
- await writeFile10(p, body2, "utf-8");
66160
+ await writeFile9(p, body2, "utf-8");
65841
66161
  }, (all) => {
65842
66162
  if (all.length === 0)
65843
66163
  return null;
@@ -66128,7 +66448,7 @@ async function runAutoPromotion(directory, config3) {
66128
66448
  await rewriteKnowledge(knowledgePath, entries);
66129
66449
  }
66130
66450
  }
66131
- function createKnowledgeCuratorHook(directory, config3) {
66451
+ function createKnowledgeCuratorHook(directory, config3, options = {}) {
66132
66452
  const handler = async (input, _output) => {
66133
66453
  pruneSeenRetroSections();
66134
66454
  if (!config3.enabled)
@@ -66173,7 +66493,10 @@ function createKnowledgeCuratorHook(directory, config3) {
66173
66493
  recordSeenRetroSection(evidenceKey, evidenceHash, Date.now());
66174
66494
  const projectName2 = evidenceData.project_name ?? "unknown";
66175
66495
  const phaseNumber2 = typeof evidenceData.phase_number === "number" ? evidenceData.phase_number : 1;
66176
- await _internals30.curateAndStoreSwarm(lessons, projectName2, { phase_number: phaseNumber2 }, directory, config3);
66496
+ await _internals30.curateAndStoreSwarm(lessons, projectName2, { phase_number: phaseNumber2 }, directory, config3, {
66497
+ llmDelegate: options.llmDelegateFactory?.(sessionID),
66498
+ enrichmentQuota: options.enrichmentQuota
66499
+ });
66177
66500
  return;
66178
66501
  }
66179
66502
  const planContent = await readSwarmFileAsync(directory, "plan.md");
@@ -66195,7 +66518,10 @@ function createKnowledgeCuratorHook(directory, config3) {
66195
66518
  const projectName = projectNameMatch ? projectNameMatch[1].trim() : "unknown";
66196
66519
  const phaseMatch = /^Phase:\s*(\d+)/m.exec(planContent);
66197
66520
  const phaseNumber = phaseMatch ? parseInt(phaseMatch[1], 10) : 1;
66198
- await _internals30.curateAndStoreSwarm(normalLessons, projectName, { phase_number: phaseNumber }, directory, config3);
66521
+ await _internals30.curateAndStoreSwarm(normalLessons, projectName, { phase_number: phaseNumber }, directory, config3, {
66522
+ llmDelegate: options.llmDelegateFactory?.(sessionID),
66523
+ enrichmentQuota: options.enrichmentQuota
66524
+ });
66199
66525
  };
66200
66526
  return safeHook(handler);
66201
66527
  }
@@ -66354,7 +66680,7 @@ var init_skill_improver_llm_factory = __esm(() => {
66354
66680
  });
66355
66681
 
66356
66682
  // src/services/trajectory-cluster.ts
66357
- import { mkdir as mkdir11, writeFile as writeFile11 } from "node:fs/promises";
66683
+ import { mkdir as mkdir11, writeFile as writeFile10 } from "node:fs/promises";
66358
66684
  import * as path45 from "node:path";
66359
66685
  function failureKind(e) {
66360
66686
  const tool3 = (e.tool ?? "").toLowerCase();
@@ -66489,7 +66815,7 @@ async function writeMotifProposals(directory, opts = {}) {
66489
66815
  for (const motif of motifs.slice(0, max)) {
66490
66816
  const slug = `motif-${slugify2(motif.signature)}`;
66491
66817
  const filePath = path45.join(proposalsDir, `${slug}.md`);
66492
- await writeFile11(filePath, buildMotifProposal(motif), "utf-8");
66818
+ await writeFile10(filePath, buildMotifProposal(motif), "utf-8");
66493
66819
  result.proposalsWritten.push(filePath);
66494
66820
  }
66495
66821
  return result;
@@ -66633,7 +66959,7 @@ async function writeSuccessMotifProposals(directory, opts = {}) {
66633
66959
  for (const motif of motifs.slice(0, max)) {
66634
66960
  const slug = workflowSlug(motif.signature);
66635
66961
  const filePath = path45.join(proposalsDir, `${slug}.md`);
66636
- await writeFile11(filePath, buildWorkflowProposal(motif), "utf-8");
66962
+ await writeFile10(filePath, buildWorkflowProposal(motif), "utf-8");
66637
66963
  result.proposalsWritten.push(filePath);
66638
66964
  }
66639
66965
  return result;
@@ -66764,7 +67090,7 @@ var init_unactionable_hardening = __esm(() => {
66764
67090
 
66765
67091
  // src/services/skill-improver.ts
66766
67092
  import { existsSync as existsSync25 } from "node:fs";
66767
- import { mkdir as mkdir12, readFile as readFile13, rename as rename7, writeFile as writeFile12 } from "node:fs/promises";
67093
+ import { mkdir as mkdir12, readFile as readFile13, rename as rename7, writeFile as writeFile11 } from "node:fs/promises";
66768
67094
  import * as path46 from "node:path";
66769
67095
  function timestampSlug(d) {
66770
67096
  return d.toISOString().replace(/[:.]/g, "-");
@@ -66772,7 +67098,7 @@ function timestampSlug(d) {
66772
67098
  async function atomicWrite3(p, content) {
66773
67099
  await mkdir12(path46.dirname(p), { recursive: true });
66774
67100
  const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
66775
- await writeFile12(tmp, content, "utf-8");
67101
+ await writeFile11(tmp, content, "utf-8");
66776
67102
  await rename7(tmp, p);
66777
67103
  }
66778
67104
  async function gatherInventory(directory) {
@@ -66826,7 +67152,10 @@ async function gatherInventory(directory) {
66826
67152
  });
66827
67153
  }
66828
67154
  }
66829
- const matureCandidates = swarm.concat(hive).filter((e) => e.status !== "archived" && e.confidence >= 0.85 && !e.generated_skill_slug && (e.confirmed_by ?? []).length >= 2);
67155
+ const matureCandidates = await selectCandidateEntries(directory, {
67156
+ minConfidence: DEFAULT_SKILL_MIN_CONFIDENCE,
67157
+ minConfirmations: DEFAULT_SKILL_MIN_CONFIRMATIONS
67158
+ });
66830
67159
  return {
66831
67160
  knowledge: { swarm: swarm.length, hive: hive.length, archived },
66832
67161
  skills: {
@@ -67092,8 +67421,8 @@ async function runSkillImprover(req) {
67092
67421
  const gen = await generateSkills({
67093
67422
  directory: req.directory,
67094
67423
  mode: "draft",
67095
- minConfidence: 0.85,
67096
- minConfirmations: 2
67424
+ minConfidence: DEFAULT_SKILL_MIN_CONFIDENCE,
67425
+ minConfirmations: DEFAULT_SKILL_MIN_CONFIRMATIONS
67097
67426
  });
67098
67427
  draftSkillsWritten = gen.written.map((w) => ({
67099
67428
  slug: w.slug,
@@ -67129,7 +67458,7 @@ async function runSkillImprover(req) {
67129
67458
  unactionableHardening = await hardenUnactionableEntries({
67130
67459
  directory: req.directory,
67131
67460
  llmDelegate: delegate,
67132
- quota: { maxCalls: cfg.max_calls_per_day, window: cfg.quota_window }
67461
+ quota: req.enrichmentQuota
67133
67462
  });
67134
67463
  }
67135
67464
  const motifResult = await writeMotifProposals(req.directory);
@@ -67955,8 +68284,8 @@ async function copyDirRecursive(src, dest) {
67955
68284
  const srcEntry = path48.join(src, entry);
67956
68285
  const destEntry = path48.join(dest, entry);
67957
68286
  try {
67958
- const stat4 = await fs23.stat(srcEntry);
67959
- if (stat4.isDirectory()) {
68287
+ const stat5 = await fs23.stat(srcEntry);
68288
+ if (stat5.isDirectory()) {
67960
68289
  const subCount = await copyDirRecursive(srcEntry, destEntry).catch(() => 0);
67961
68290
  count += subCount;
67962
68291
  } else {
@@ -67992,8 +68321,8 @@ function guaranteeAllPlansComplete(planData) {
67992
68321
  async function handleCloseCommand(directory, args2, options = {}) {
67993
68322
  const swarmDir = path48.join(directory, ".swarm");
67994
68323
  try {
67995
- const stat4 = fsSync5.lstatSync(swarmDir);
67996
- if (stat4.isSymbolicLink()) {
68324
+ const stat5 = fsSync5.lstatSync(swarmDir);
68325
+ if (stat5.isSymbolicLink()) {
67997
68326
  return `❌ Refused: .swarm/ is a symlink or junction. Refusing to operate on a redirected directory for safety.`;
67998
68327
  }
67999
68328
  } catch (err2) {
@@ -68147,12 +68476,11 @@ async function handleCloseCommand(directory, args2, options = {}) {
68147
68476
  let curationSucceeded = false;
68148
68477
  let curationResult;
68149
68478
  try {
68150
- const skillImproverCfg = SkillImproverConfigSchema.parse(loadedConfig.skill_improver ?? {});
68151
68479
  curationResult = await curateAndStoreSwarm(allLessons, projectName, { phase_number: 0 }, directory, config3, {
68152
68480
  llmDelegate: createCuratorLLMDelegate(directory, "phase", options.sessionID),
68153
68481
  enrichmentQuota: {
68154
- maxCalls: skillImproverCfg.max_calls_per_day,
68155
- window: skillImproverCfg.quota_window
68482
+ maxCalls: config3.enrichment.max_calls_per_day,
68483
+ window: config3.enrichment.quota_window
68156
68484
  }
68157
68485
  });
68158
68486
  curationSucceeded = true;
@@ -68217,7 +68545,11 @@ async function handleCloseCommand(directory, args2, options = {}) {
68217
68545
  config: skillImproverConfig,
68218
68546
  targets: ["skills", "knowledge"],
68219
68547
  mode: "proposal",
68220
- sessionId: options.sessionID
68548
+ sessionId: options.sessionID,
68549
+ enrichmentQuota: {
68550
+ maxCalls: config3.enrichment.max_calls_per_day,
68551
+ window: config3.enrichment.quota_window
68552
+ }
68221
68553
  }, options.skillReviewTimeoutMs ?? CLOSE_SKILL_REVIEW_TIMEOUT_MS);
68222
68554
  if (skillReviewResult.ran) {
68223
68555
  const proposal = skillReviewResult.proposalPath ? ` Proposal: ${skillReviewResult.proposalPath}.` : "";
@@ -68986,7 +69318,7 @@ __export(exports_co_change_analyzer, {
68986
69318
  });
68987
69319
  import * as child_process3 from "node:child_process";
68988
69320
  import { randomUUID as randomUUID5 } from "node:crypto";
68989
- import { readdir as readdir2, readFile as readFile14, stat as stat4 } from "node:fs/promises";
69321
+ import { readdir as readdir2, readFile as readFile14, stat as stat5 } from "node:fs/promises";
68990
69322
  import * as path50 from "node:path";
68991
69323
  import { promisify } from "node:util";
68992
69324
  function getExecFileAsync() {
@@ -69137,7 +69469,7 @@ async function getStaticEdges(directory) {
69137
69469
  for (const ext of extensions) {
69138
69470
  const testPath = resolvedPath + ext;
69139
69471
  try {
69140
- const testStat = await stat4(testPath);
69472
+ const testStat = await stat5(testPath);
69141
69473
  if (testStat.isFile()) {
69142
69474
  targetFile = testPath;
69143
69475
  break;
@@ -75517,7 +75849,7 @@ var KNOWLEDGE_SCHEMA_VERSION = 2;
75517
75849
  // src/hooks/knowledge-migrator.ts
75518
75850
  import { randomUUID as randomUUID6 } from "node:crypto";
75519
75851
  import { existsSync as existsSync33, readFileSync as readFileSync18 } from "node:fs";
75520
- import { mkdir as mkdir13, readFile as readFile16, writeFile as writeFile13 } from "node:fs/promises";
75852
+ import { mkdir as mkdir13, readFile as readFile16, writeFile as writeFile12 } from "node:fs/promises";
75521
75853
  import * as os13 from "node:os";
75522
75854
  import * as path58 from "node:path";
75523
75855
  async function migrateKnowledgeToExternal(_directory, _config) {
@@ -75866,7 +76198,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
75866
76198
  migration_tool: "knowledge-migrator.ts"
75867
76199
  };
75868
76200
  await mkdir13(path58.dirname(sentinelPath), { recursive: true });
75869
- await writeFile13(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
76201
+ await writeFile12(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
75870
76202
  }
75871
76203
  function resolveLegacyHiveKnowledgePath() {
75872
76204
  const platform = process.platform;
@@ -76297,7 +76629,7 @@ var init_redaction = __esm(() => {
76297
76629
  });
76298
76630
 
76299
76631
  // src/memory/schema.ts
76300
- import { createHash as createHash6 } from "node:crypto";
76632
+ import { createHash as createHash7 } from "node:crypto";
76301
76633
  function normalizeMemoryText(text) {
76302
76634
  return text.replace(/\s+/g, " ").trim();
76303
76635
  }
@@ -76321,7 +76653,7 @@ function stableScopeKey(scope) {
76321
76653
  }
76322
76654
  function computeMemoryContentHash(recordLike) {
76323
76655
  const normalized = normalizeMemoryText(recordLike.text).toLowerCase();
76324
- return createHash6("sha256").update(`${stableScopeKey(recordLike.scope)}
76656
+ return createHash7("sha256").update(`${stableScopeKey(recordLike.scope)}
76325
76657
  ${recordLike.kind}
76326
76658
  ${normalized}`).digest("hex");
76327
76659
  }
@@ -76329,14 +76661,14 @@ function createMemoryId(recordLike) {
76329
76661
  return `mem_${computeMemoryContentHash(recordLike).slice(0, 16)}`;
76330
76662
  }
76331
76663
  function createProposalId(input) {
76332
- const hash4 = createHash6("sha256").update(`${input.createdAt}
76664
+ const hash4 = createHash7("sha256").update(`${input.createdAt}
76333
76665
  ${input.proposer}
76334
76666
  ${normalizeMemoryText(input.text)}`).digest("hex");
76335
76667
  return `prop_${hash4.slice(0, 16)}`;
76336
76668
  }
76337
76669
  function createBundleId(query, generatedAt) {
76338
76670
  const compactTimestamp = generatedAt.replace(/[-:.TZ]/g, "").slice(0, 14);
76339
- const hash4 = createHash6("sha256").update(`${generatedAt}
76671
+ const hash4 = createHash7("sha256").update(`${generatedAt}
76340
76672
  ${query}`).digest("hex").slice(0, 8);
76341
76673
  return `bundle_${compactTimestamp}_${hash4}`;
76342
76674
  }
@@ -77088,7 +77420,7 @@ import {
77088
77420
  mkdir as mkdir14,
77089
77421
  readFile as readFile17,
77090
77422
  rename as rename8,
77091
- writeFile as writeFile14
77423
+ writeFile as writeFile13
77092
77424
  } from "node:fs/promises";
77093
77425
  import * as path59 from "node:path";
77094
77426
 
@@ -77499,7 +77831,7 @@ async function writeJsonlAtomic(filePath, values) {
77499
77831
  const content = values.map((value) => JSON.stringify(value)).join(`
77500
77832
  `) + (values.length > 0 ? `
77501
77833
  ` : "");
77502
- await writeFile14(tmp, content, "utf-8");
77834
+ await writeFile13(tmp, content, "utf-8");
77503
77835
  await rename8(tmp, filePath);
77504
77836
  }
77505
77837
  var init_local_jsonl_provider = __esm(() => {
@@ -77594,7 +77926,7 @@ var init_prompt_block = __esm(() => {
77594
77926
 
77595
77927
  // src/memory/jsonl-migration.ts
77596
77928
  import { existsSync as existsSync35 } from "node:fs";
77597
- import { copyFile, mkdir as mkdir15, readFile as readFile18, stat as stat5, writeFile as writeFile15 } from "node:fs/promises";
77929
+ import { copyFile, mkdir as mkdir15, readFile as readFile18, stat as stat6, writeFile as writeFile14 } from "node:fs/promises";
77598
77930
  import * as path60 from "node:path";
77599
77931
  function resolveMemoryStorageDir(rootDirectory, config3 = {}) {
77600
77932
  const resolved = resolveConfig(config3);
@@ -77642,14 +77974,14 @@ async function writeJsonlExport(rootDirectory, config3, memories, proposals) {
77642
77974
  await mkdir15(exportDir, { recursive: true });
77643
77975
  const memoriesPath = path60.join(exportDir, "memories.jsonl");
77644
77976
  const proposalsPath = path60.join(exportDir, "proposals.jsonl");
77645
- await writeFile15(memoriesPath, toJsonl(memories), "utf-8");
77646
- await writeFile15(proposalsPath, toJsonl(proposals), "utf-8");
77977
+ await writeFile14(memoriesPath, toJsonl(memories), "utf-8");
77978
+ await writeFile14(proposalsPath, toJsonl(proposals), "utf-8");
77647
77979
  return { directory: exportDir, memoriesPath, proposalsPath };
77648
77980
  }
77649
77981
  async function writeMigrationReport(rootDirectory, report, config3 = {}) {
77650
77982
  const reportPath = path60.join(resolveMemoryStorageDir(rootDirectory, config3), "migration-report.json");
77651
77983
  await mkdir15(path60.dirname(reportPath), { recursive: true });
77652
- await writeFile15(reportPath, `${JSON.stringify(report, null, 2)}
77984
+ await writeFile14(reportPath, `${JSON.stringify(report, null, 2)}
77653
77985
  `, "utf-8");
77654
77986
  return reportPath;
77655
77987
  }
@@ -77670,7 +78002,7 @@ async function getLegacyJsonlFileStatus(rootDirectory, config3 = {}) {
77670
78002
  const filePath = path60.join(storageDir, file3);
77671
78003
  let sizeBytes = 0;
77672
78004
  if (existsSync35(filePath)) {
77673
- sizeBytes = (await stat5(filePath)).size;
78005
+ sizeBytes = (await stat6(filePath)).size;
77674
78006
  }
77675
78007
  statuses.push({
77676
78008
  file: file3,
@@ -78719,7 +79051,7 @@ var init_sqlite_provider = __esm(() => {
78719
79051
  });
78720
79052
 
78721
79053
  // src/memory/gateway.ts
78722
- import { createHash as createHash7 } from "node:crypto";
79054
+ import { createHash as createHash8 } from "node:crypto";
78723
79055
  import { existsSync as existsSync36, readFileSync as readFileSync19 } from "node:fs";
78724
79056
  import * as path62 from "node:path";
78725
79057
 
@@ -79039,7 +79371,7 @@ function sourceFromEvidence(evidenceRefs, context) {
79039
79371
  return { type: "manual", ref: first };
79040
79372
  }
79041
79373
  function createStableId(value) {
79042
- return createHash7("sha256").update(value.toLowerCase()).digest("hex").slice(0, 16);
79374
+ return createHash8("sha256").update(value.toLowerCase()).digest("hex").slice(0, 16);
79043
79375
  }
79044
79376
  function readGitRemoteUrl(directory) {
79045
79377
  if (gitRemoteUrlCache.has(directory))
@@ -82192,8 +82524,8 @@ var init_secretscan = __esm(() => {
82192
82524
  break;
82193
82525
  const fileFindings = scanFileForSecrets(filePath);
82194
82526
  try {
82195
- const stat6 = fs30.statSync(filePath);
82196
- if (stat6.size > MAX_FILE_SIZE_BYTES) {
82527
+ const stat7 = fs30.statSync(filePath);
82528
+ if (stat7.size > MAX_FILE_SIZE_BYTES) {
82197
82529
  skippedFiles++;
82198
82530
  continue;
82199
82531
  }
@@ -83003,8 +83335,8 @@ function sharedTrailingSegments(a, b) {
83003
83335
  function isCacheStale(impactMap, generatedAtMs) {
83004
83336
  for (const sourcePath of Object.keys(impactMap)) {
83005
83337
  try {
83006
- const stat6 = fs34.statSync(sourcePath);
83007
- if (stat6.mtimeMs > generatedAtMs) {
83338
+ const stat7 = fs34.statSync(sourcePath);
83339
+ if (stat7.mtimeMs > generatedAtMs) {
83008
83340
  return true;
83009
83341
  }
83010
83342
  } catch {
@@ -84350,8 +84682,8 @@ function manifestHash(dir) {
84350
84682
  if (!entries.has(name2))
84351
84683
  continue;
84352
84684
  try {
84353
- const stat6 = fs39.statSync(path77.join(dir, name2));
84354
- parts2.push(`${name2}:${stat6.size}:${stat6.mtimeMs}:${stat6.ino}`);
84685
+ const stat7 = fs39.statSync(path77.join(dir, name2));
84686
+ parts2.push(`${name2}:${stat7.size}:${stat7.mtimeMs}:${stat7.ino}`);
84355
84687
  } catch {}
84356
84688
  }
84357
84689
  return parts2.join("|");
@@ -94335,6 +94667,7 @@ SKILL COMPLIANCE REVIEW: When SKILLS_USED_BY_CODER is provided and not "none":
94335
94667
  - For each skill rule, verify the coder's changes comply
94336
94668
  - Flag violations at the same severity as logic errors
94337
94669
  - Report the overall compliance verdict in SKILL_COMPLIANCE field of your output
94670
+ - Report TASK: <task id> immediately before SKILL_COMPLIANCE when a task id is available
94338
94671
  - If you cannot load a skill (SKILL_LOAD_FAILED), report SKILL_COMPLIANCE: PARTIAL — [skill path] could not be loaded
94339
94672
 
94340
94673
  PROCESSING: If GATES is provided and includes passing results for lint, SAST, placeholder-scan, or secret-scan: skip the corresponding Tier 2 checks that those gates already cover. Focus Tier 2 time on checks NOT covered by automated gates.
@@ -94346,6 +94679,7 @@ VERDICT: APPROVED | REJECTED
94346
94679
  REUSE_RE_VERIFICATION: [VERIFIED | DUPLICATION_DETECTED | SKIPPED] — DUPLICATION_DETECTED is only valid when VERDICT is REJECTED
94347
94680
  RISK: LOW | MEDIUM | HIGH | CRITICAL
94348
94681
  ISSUES: list with line numbers, grouped by CHECK dimension
94682
+ TASK: [task id being reviewed, or "unknown"]
94349
94683
  SKILL_COMPLIANCE: COMPLIANT | PARTIAL | VIOLATED — [list of violations or "all rules followed"]
94350
94684
  DIRECTIVE_COMPLIANCE: one line per knowledge directive shown during this phase (IDs listed in the DIRECTIVES TO VERIFY block of your prompt, when present). Use exactly one of:
94351
94685
  VERIFIED:<id> evidence=<file:line | predicate_passed>
@@ -94926,7 +95260,7 @@ COVERAGE REPORTING:
94926
95260
  `;
94927
95261
 
94928
95262
  // src/agents/index.ts
94929
- import { mkdir as mkdir17, writeFile as writeFile16 } from "node:fs/promises";
95263
+ import { mkdir as mkdir17, writeFile as writeFile15 } from "node:fs/promises";
94930
95264
  import * as path88 from "node:path";
94931
95265
  function stripSwarmPrefix(agentName, swarmPrefix) {
94932
95266
  if (!swarmPrefix || !agentName)
@@ -95406,7 +95740,7 @@ function getAgentConfigs(config3, directory, sessionId, projectContext) {
95406
95740
  generatedAt: new Date().toISOString(),
95407
95741
  agents: agentToolSnapshot
95408
95742
  }, null, 2);
95409
- mkdir17(evidenceDir, { recursive: true }).then(() => writeFile16(path88.join(evidenceDir, filename), snapshotData)).catch(() => {});
95743
+ mkdir17(evidenceDir, { recursive: true }).then(() => writeFile15(path88.join(evidenceDir, filename), snapshotData)).catch(() => {});
95410
95744
  }
95411
95745
  return result;
95412
95746
  }
@@ -100118,8 +100452,8 @@ import {
100118
100452
  readdir as readdir6,
100119
100453
  readFile as readFile22,
100120
100454
  realpath as realpath3,
100121
- stat as stat8,
100122
- writeFile as writeFile18
100455
+ stat as stat9,
100456
+ writeFile as writeFile17
100123
100457
  } from "node:fs/promises";
100124
100458
  import * as path119 from "node:path";
100125
100459
  function normalizeSeparators(filePath) {
@@ -100201,8 +100535,8 @@ async function scanDocIndex(directory) {
100201
100535
  for (const file3 of existingManifest.files) {
100202
100536
  try {
100203
100537
  const fullPath = path119.join(directory, file3.path);
100204
- const stat9 = fs71.statSync(fullPath);
100205
- if (stat9.mtimeMs > file3.mtime) {
100538
+ const stat10 = fs71.statSync(fullPath);
100539
+ if (stat10.mtimeMs > file3.mtime) {
100206
100540
  cacheValid = false;
100207
100541
  break;
100208
100542
  }
@@ -100240,7 +100574,7 @@ async function scanDocIndex(directory) {
100240
100574
  const rel = path119.relative(resolvedDirectory, resolved);
100241
100575
  if (rel.startsWith("..") || path119.isAbsolute(rel))
100242
100576
  continue;
100243
- const targetStat = await stat8(symlinkPath);
100577
+ const targetStat = await stat9(symlinkPath);
100244
100578
  isFile = targetStat.isFile();
100245
100579
  } catch {
100246
100580
  continue;
@@ -100269,7 +100603,7 @@ async function scanDocIndex(directory) {
100269
100603
  continue;
100270
100604
  let fileStat;
100271
100605
  try {
100272
- fileStat = await stat8(fullPath);
100606
+ fileStat = await stat9(fullPath);
100273
100607
  } catch {
100274
100608
  continue;
100275
100609
  }
@@ -100317,7 +100651,7 @@ async function scanDocIndex(directory) {
100317
100651
  };
100318
100652
  try {
100319
100653
  await mkdir20(path119.dirname(manifestPath), { recursive: true });
100320
- await writeFile18(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
100654
+ await writeFile17(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
100321
100655
  } catch {}
100322
100656
  return { manifest, cached: false };
100323
100657
  }
@@ -101004,7 +101338,7 @@ async function searchKnowledge(params) {
101004
101338
  const confBoost = context && entry.confidence >= minConf && (ds.actionHit || ds.agentHit) ? 0.25 : 0;
101005
101339
  const generatedSkillBoost = entry.generated_skill_path && entry.status !== "archived" ? 0.05 : 0;
101006
101340
  const outcomeBoost = computeOutcomeSignal(retrievalOutcomes) * OUTCOME_RANK_WEIGHT;
101007
- const coldStartBonus = retrievalOutcomes.applied_count === 0 && entryAgePhases(entry) < (config3.retrieval?.cold_start_max_age_phases ?? DEFAULT_COLD_START_MAX_AGE_PHASES) ? config3.retrieval?.cold_start_bonus ?? DEFAULT_COLD_START_BONUS : 0;
101341
+ const coldStartBonus = (retrievalOutcomes.applied_explicit_count ?? 0) === 0 && entryAgePhases(entry) < (config3.retrieval?.cold_start_max_age_phases ?? DEFAULT_COLD_START_MAX_AGE_PHASES) ? config3.retrieval?.cold_start_bonus ?? DEFAULT_COLD_START_BONUS : 0;
101008
101342
  let synonymBoost = 0;
101009
101343
  if (synonymTokens.length > 0) {
101010
101344
  const entryHay = normalize4(entryText(entry));
@@ -101029,6 +101363,7 @@ async function searchKnowledge(params) {
101029
101363
  ...entry,
101030
101364
  retrieval_outcomes: retrievalOutcomes,
101031
101365
  finalScore,
101366
+ coldStartBoost: coldStartBonus,
101032
101367
  __critical: isCritical
101033
101368
  };
101034
101369
  });
@@ -101060,7 +101395,8 @@ async function searchKnowledge(params) {
101060
101395
  }
101061
101396
  }
101062
101397
  results = top.map(({ __critical: _c, ...rest }) => rest);
101063
- } catch {
101398
+ } catch (err2) {
101399
+ warn(`[search-knowledge] retrieval failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
101064
101400
  results = [];
101065
101401
  }
101066
101402
  if (emitEvent) {
@@ -101100,6 +101436,7 @@ var TEXT_WEIGHT = 0.6, META_WEIGHT = 0.4, DIRECTIVE_BOOST_MIN_CONFIDENCE = 0.75,
101100
101436
  var init_search_knowledge = __esm(() => {
101101
101437
  init_schema();
101102
101438
  init_synonym_map();
101439
+ init_logger();
101103
101440
  init_knowledge_events();
101104
101441
  init_knowledge_reader();
101105
101442
  init_knowledge_store();
@@ -101485,8 +101822,8 @@ async function runDesignDocDriftCheck(directory, phase, outDir) {
101485
101822
  const traceabilityAbs = path165.join(outAbs, TRACEABILITY_REL);
101486
101823
  let registry3 = null;
101487
101824
  try {
101488
- const stat10 = await fs112.promises.stat(traceabilityAbs);
101489
- if (stat10.size <= MAX_TRACEABILITY_BYTES) {
101825
+ const stat11 = await fs112.promises.stat(traceabilityAbs);
101826
+ if (stat11.size <= MAX_TRACEABILITY_BYTES) {
101490
101827
  const raw = await fs112.promises.readFile(traceabilityAbs, "utf-8");
101491
101828
  const parsed = JSON.parse(raw);
101492
101829
  registry3 = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
@@ -102799,8 +103136,8 @@ function writeProjectConfigIfNew(directory, quiet = false) {
102799
103136
  const dest = path92.join(opencodeDir, "opencode-swarm.json");
102800
103137
  const normalizePathForCompare = (p) => process.platform === "win32" ? p.toLowerCase() : p;
102801
103138
  try {
102802
- const stat6 = fs50.lstatSync(opencodeDir);
102803
- if (stat6.isSymbolicLink())
103139
+ const stat7 = fs50.lstatSync(opencodeDir);
103140
+ if (stat7.isSymbolicLink())
102804
103141
  return;
102805
103142
  const resolvedDir = fs50.realpathSync(opencodeDir);
102806
103143
  const canonicalOpencode = path92.join(fs50.realpathSync(directory), ".opencode");
@@ -102973,8 +103310,8 @@ function extractFileSummary(filePath, content, absolutePath, existingEntry) {
102973
103310
  let mtimeMs = 0;
102974
103311
  if (absolutePath) {
102975
103312
  try {
102976
- const stat6 = fs52.statSync(absolutePath);
102977
- mtimeMs = stat6.mtimeMs;
103313
+ const stat7 = fs52.statSync(absolutePath);
103314
+ mtimeMs = stat7.mtimeMs;
102978
103315
  } catch {}
102979
103316
  }
102980
103317
  const base = {
@@ -105924,9 +106261,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, dele
105924
106261
  const initResult = await runner(directory, curatorConfig, llmDelegate);
105925
106262
  if (initResult.briefing) {
105926
106263
  const briefingPath = path103.join(directory, ".swarm", "curator-briefing.md");
105927
- const { mkdir: mkdir18, writeFile: writeFile17 } = await import("node:fs/promises");
106264
+ const { mkdir: mkdir18, writeFile: writeFile16 } = await import("node:fs/promises");
105928
106265
  await mkdir18(path103.dirname(briefingPath), { recursive: true });
105929
- await writeFile17(briefingPath, initResult.briefing, "utf-8");
106266
+ await writeFile16(briefingPath, initResult.briefing, "utf-8");
105930
106267
  const { buildApprovedReceipt: buildApprovedReceipt2, persistReviewReceipt: persistReviewReceipt2 } = await Promise.resolve().then(() => (init_review_receipt(), exports_review_receipt));
105931
106268
  const initReceipt = buildApprovedReceipt2({
105932
106269
  agent: "curator",
@@ -108515,16 +108852,16 @@ function tryResolveTSJS(rawModule, sourceFileAbs) {
108515
108852
  for (const ext of RESOLVE_EXTENSION_CANDIDATES) {
108516
108853
  const test = basePath + ext;
108517
108854
  try {
108518
- const stat8 = fs66.statSync(test);
108519
- if (stat8.isFile())
108855
+ const stat9 = fs66.statSync(test);
108856
+ if (stat9.isFile())
108520
108857
  return test;
108521
108858
  } catch {}
108522
108859
  }
108523
108860
  for (const indexFile of RESOLVE_INDEX_CANDIDATES) {
108524
108861
  const test = path113.join(basePath, indexFile);
108525
108862
  try {
108526
- const stat8 = fs66.statSync(test);
108527
- if (stat8.isFile())
108863
+ const stat9 = fs66.statSync(test);
108864
+ if (stat9.isFile())
108528
108865
  return test;
108529
108866
  } catch {}
108530
108867
  }
@@ -108555,8 +108892,8 @@ function tryResolvePython(rawModule, sourceFileAbs, workspaceRoot) {
108555
108892
  const baseAbs = path113.resolve(sourceDir, upDirs + remainder);
108556
108893
  const accept = (test) => {
108557
108894
  try {
108558
- const stat8 = fs66.statSync(test);
108559
- if (stat8.isFile()) {
108895
+ const stat9 = fs66.statSync(test);
108896
+ if (stat9.isFile()) {
108560
108897
  const rel = path113.relative(workspaceRoot, test).replace(/\\/g, "/");
108561
108898
  if (rel.startsWith(".."))
108562
108899
  return null;
@@ -109409,8 +109746,8 @@ function saveGraph2(workspaceRoot, graph) {
109409
109746
  const file3 = getGraphPath2(workspaceRoot);
109410
109747
  const dir = path116.dirname(file3);
109411
109748
  try {
109412
- const stat8 = fs68.lstatSync(dir);
109413
- if (stat8.isSymbolicLink()) {
109749
+ const stat9 = fs68.lstatSync(dir);
109750
+ if (stat9.isSymbolicLink()) {
109414
109751
  throw new Error(`refusing to write graph: ${SWARM_DIR}/ is a symbolic link`);
109415
109752
  }
109416
109753
  } catch (err2) {
@@ -109446,15 +109783,15 @@ function isGraphFresh(graph, maxAgeMs = 5 * 60 * 1000) {
109446
109783
  var cache2 = new Map;
109447
109784
  function getCachedGraph2(directory) {
109448
109785
  const file3 = getGraphPath2(directory);
109449
- let stat8;
109786
+ let stat9;
109450
109787
  try {
109451
- stat8 = fs69.statSync(file3);
109788
+ stat9 = fs69.statSync(file3);
109452
109789
  } catch {
109453
109790
  cache2.delete(directory);
109454
109791
  return null;
109455
109792
  }
109456
109793
  const cached3 = cache2.get(directory);
109457
- if (cached3 && cached3.mtimeMs === stat8.mtimeMs && cached3.size === stat8.size) {
109794
+ if (cached3 && cached3.mtimeMs === stat9.mtimeMs && cached3.size === stat9.size) {
109458
109795
  return cached3.graph;
109459
109796
  }
109460
109797
  const graph = loadGraph2(directory);
@@ -109462,7 +109799,7 @@ function getCachedGraph2(directory) {
109462
109799
  cache2.delete(directory);
109463
109800
  return null;
109464
109801
  }
109465
- cache2.set(directory, { graph, mtimeMs: stat8.mtimeMs, size: stat8.size });
109802
+ cache2.set(directory, { graph, mtimeMs: stat9.mtimeMs, size: stat9.size });
109466
109803
  return graph;
109467
109804
  }
109468
109805
  function buildCoderLocalizationBlock(directory, targetFile) {
@@ -112023,6 +112360,7 @@ import { appendFile as appendFile13, mkdir as mkdir22 } from "node:fs/promises";
112023
112360
  import * as path124 from "node:path";
112024
112361
 
112025
112362
  // src/hooks/knowledge-application.ts
112363
+ init_task_file();
112026
112364
  init_logger();
112027
112365
  init_knowledge_store();
112028
112366
  var import_proper_lockfile9 = __toESM(require_proper_lockfile(), 1);
@@ -112032,6 +112370,7 @@ import * as path122 from "node:path";
112032
112370
  function resolveApplicationLogPath(directory) {
112033
112371
  return path122.join(directory, ".swarm", "knowledge-application.jsonl");
112034
112372
  }
112373
+ var MAX_LEGACY_APPLICATION_LOG_ENTRIES = 5000;
112035
112374
  var ACK_PATTERN = /KNOWLEDGE_(APPLIED|IGNORED|VIOLATED|N_A)\s*:\s*([0-9a-fA-F-]{8,64})(?:\s+reason\s*=\s*([^\n\r]+?))?(?=$|[\n\r]|\s+KNOWLEDGE_)/g;
112036
112375
  function parseAcknowledgments(text) {
112037
112376
  if (!text || typeof text !== "string")
@@ -112048,9 +112387,29 @@ function parseAcknowledgments(text) {
112048
112387
  }
112049
112388
  async function appendAudit(directory, record3) {
112050
112389
  const filePath = resolveApplicationLogPath(directory);
112051
- await mkdir21(path122.dirname(filePath), { recursive: true });
112052
- await appendFile11(filePath, `${JSON.stringify(record3)}
112390
+ const dirPath = path122.dirname(filePath);
112391
+ await mkdir21(dirPath, { recursive: true });
112392
+ let release;
112393
+ try {
112394
+ release = await import_proper_lockfile9.default.lock(dirPath, {
112395
+ retries: { retries: 50, minTimeout: 10, maxTimeout: 100 },
112396
+ stale: 5000
112397
+ });
112398
+ await appendFile11(filePath, `${JSON.stringify(record3)}
112053
112399
  `, "utf-8");
112400
+ const content = await readFile24(filePath, "utf-8");
112401
+ const lines = content.split(`
112402
+ `).filter((line) => line.trim().length > 0);
112403
+ if (lines.length > MAX_LEGACY_APPLICATION_LOG_ENTRIES) {
112404
+ const trimmed = lines.slice(-MAX_LEGACY_APPLICATION_LOG_ENTRIES);
112405
+ await atomicWriteFile(filePath, `${trimmed.join(`
112406
+ `)}
112407
+ `);
112408
+ }
112409
+ } finally {
112410
+ if (release)
112411
+ await release().catch(() => {});
112412
+ }
112054
112413
  }
112055
112414
  async function bumpCountersBatch(directory, bumps) {
112056
112415
  const filteredBumps = bumps.filter((b) => b.ids.length > 0);
@@ -112088,14 +112447,10 @@ async function bumpCountersBatch(directory, bumps) {
112088
112447
  return updated;
112089
112448
  };
112090
112449
  const swarmPath = resolveSwarmKnowledgePath(directory);
112091
- const swarm = await readKnowledge(swarmPath);
112092
- if (applyOne(swarm))
112093
- await rewriteKnowledge(swarmPath, swarm);
112450
+ await transactKnowledge(swarmPath, (swarm) => applyOne(swarm) ? swarm : null);
112094
112451
  const hivePath = resolveHiveKnowledgePath();
112095
112452
  if (existsSync69(hivePath)) {
112096
- const hive = await readKnowledge(hivePath);
112097
- if (applyOne(hive))
112098
- await rewriteKnowledge(hivePath, hive);
112453
+ await transactKnowledge(hivePath, (hive) => applyOne(hive) ? hive : null);
112099
112454
  }
112100
112455
  }
112101
112456
  async function bumpCounters(directory, ids, field) {
@@ -112165,7 +112520,7 @@ init_knowledge_events();
112165
112520
  // src/hooks/knowledge-injector.ts
112166
112521
  init_schema();
112167
112522
  init_manager();
112168
- import { createHash as createHash11 } from "node:crypto";
112523
+ import { createHash as createHash12 } from "node:crypto";
112169
112524
 
112170
112525
  // src/services/run-memory.ts
112171
112526
  import * as crypto11 from "node:crypto";
@@ -112342,6 +112697,7 @@ init_extractors();
112342
112697
  init_knowledge_escalator();
112343
112698
  init_knowledge_events();
112344
112699
  init_knowledge_store();
112700
+ init_model_limits();
112345
112701
  init_search_knowledge();
112346
112702
  init_utils2();
112347
112703
  var INJECTION_SENTINEL = `${String.fromCharCode(8204)}[[KNOWLEDGE-INJECTED]]`;
@@ -112658,7 +113014,7 @@ function injectKnowledgeMessage(output, text) {
112658
113014
  };
112659
113015
  output.messages.splice(insertIdx, 0, knowledgeMessage);
112660
113016
  }
112661
- function createKnowledgeInjectorHook(directory, config3) {
113017
+ function createKnowledgeInjectorHook(directory, config3, modelLimitOverrides = {}) {
112662
113018
  function buildContextCacheKey(phase, ctx) {
112663
113019
  const parts2 = [
112664
113020
  String(phase),
@@ -112668,7 +113024,7 @@ function createKnowledgeInjectorHook(directory, config3) {
112668
113024
  ctx.taskId ?? "",
112669
113025
  (ctx.filePaths ?? []).slice(0, 8).join(",")
112670
113026
  ].join("|");
112671
- return createHash11("sha1").update(parts2).digest("hex").slice(0, 16);
113027
+ return createHash12("sha1").update(parts2).digest("hex").slice(0, 16);
112672
113028
  }
112673
113029
  let lastSeenCacheKey = null;
112674
113030
  let cachedInjectionText = null;
@@ -112679,7 +113035,9 @@ function createKnowledgeInjectorHook(directory, config3) {
112679
113035
  const plan = await loadPlan(directory);
112680
113036
  const currentPhase = plan?.current_phase ?? 1;
112681
113037
  const CHARS_PER_TOKEN = 1 / 0.33;
112682
- const MODEL_LIMIT_CHARS = Math.floor(128000 * CHARS_PER_TOKEN);
113038
+ const { modelID, providerID } = extractModelInfo(output.messages);
113039
+ const modelLimitTokens = resolveModelLimit(modelID, providerID, modelLimitOverrides);
113040
+ const MODEL_LIMIT_CHARS = Math.floor(modelLimitTokens * CHARS_PER_TOKEN);
112683
113041
  const existingChars = output.messages.reduce((sum, msg) => {
112684
113042
  return sum + (msg.parts?.reduce((s, p) => s + (p.text?.length ?? 0), 0) ?? 0);
112685
113043
  }, 0);
@@ -115919,8 +116277,8 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
115919
116277
  continue;
115920
116278
  const filePath = path131.join(dirPath, entry.name);
115921
116279
  try {
115922
- const stat10 = await fs81.stat(filePath);
115923
- if (now - stat10.mtimeMs > cutoffMs) {
116280
+ const stat11 = await fs81.stat(filePath);
116281
+ if (now - stat11.mtimeMs > cutoffMs) {
115924
116282
  await fs81.unlink(filePath);
115925
116283
  }
115926
116284
  } catch {}
@@ -118786,8 +119144,8 @@ function estimateCyclomaticComplexity(content) {
118786
119144
  }
118787
119145
  function getComplexityForFile(filePath) {
118788
119146
  try {
118789
- const stat10 = fs87.statSync(filePath);
118790
- if (stat10.size > MAX_FILE_SIZE_BYTES4) {
119147
+ const stat11 = fs87.statSync(filePath);
119148
+ if (stat11.size > MAX_FILE_SIZE_BYTES4) {
118791
119149
  return null;
118792
119150
  }
118793
119151
  const content = fs87.readFileSync(filePath, "utf-8");
@@ -118988,8 +119346,8 @@ async function computeDuplicationRatio(files, workingDir) {
118988
119346
  continue;
118989
119347
  }
118990
119348
  try {
118991
- const stat10 = fs87.statSync(fullPath);
118992
- if (stat10.size > MAX_FILE_SIZE_BYTES4) {
119349
+ const stat11 = fs87.statSync(fullPath);
119350
+ if (stat11.size > MAX_FILE_SIZE_BYTES4) {
118993
119351
  continue;
118994
119352
  }
118995
119353
  const content = fs87.readFileSync(fullPath, "utf-8");
@@ -119449,8 +119807,8 @@ async function getGitChurn(days, directory) {
119449
119807
  }
119450
119808
  function getComplexityForFile2(filePath) {
119451
119809
  try {
119452
- const stat10 = fs88.statSync(filePath);
119453
- if (stat10.size > MAX_FILE_SIZE_BYTES5) {
119810
+ const stat11 = fs88.statSync(filePath);
119811
+ if (stat11.size > MAX_FILE_SIZE_BYTES5) {
119454
119812
  return null;
119455
119813
  }
119456
119814
  const content = fs88.readFileSync(filePath, "utf-8");
@@ -121919,8 +122277,8 @@ function readEvidenceFiles(evidenceDir, _cwd) {
121919
122277
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
121920
122278
  continue;
121921
122279
  }
121922
- const stat10 = fs93.lstatSync(filePath);
121923
- if (!stat10.isFile()) {
122280
+ const stat11 = fs93.lstatSync(filePath);
122281
+ if (!stat11.isFile()) {
121924
122282
  continue;
121925
122283
  }
121926
122284
  } catch {
@@ -122342,11 +122700,11 @@ var external_skill_delete = createSwarmTool({
122342
122700
  // src/tools/external-skill-discover.ts
122343
122701
  init_zod();
122344
122702
  init_loader();
122345
- import { createHash as createHash13, randomUUID as randomUUID13 } from "node:crypto";
122703
+ import { createHash as createHash14, randomUUID as randomUUID13 } from "node:crypto";
122346
122704
 
122347
122705
  // src/services/external-skill-validator.ts
122348
122706
  init_knowledge_validator();
122349
- import { createHash as createHash12 } from "node:crypto";
122707
+ import { createHash as createHash13 } from "node:crypto";
122350
122708
  var PROMPT_INJECTION_PATTERNS = [
122351
122709
  {
122352
122710
  pattern: /system\s*:/i,
@@ -122480,31 +122838,31 @@ var UNSAFE_INSTRUCTION_PATTERNS = [
122480
122838
  pattern: /\bkill\s+-9\b/,
122481
122839
  name: "force_kill",
122482
122840
  description: "Force process termination",
122483
- severity: "error"
122841
+ severity: "warning"
122484
122842
  },
122485
122843
  {
122486
122844
  pattern: /\bpkill\b/,
122487
122845
  name: "process_group_kill",
122488
122846
  description: "Process group kill",
122489
- severity: "error"
122847
+ severity: "warning"
122490
122848
  },
122491
122849
  {
122492
122850
  pattern: /\bkillall\b/,
122493
122851
  name: "kill_all_processes",
122494
122852
  description: "Kill all processes by name",
122495
- severity: "error"
122853
+ severity: "warning"
122496
122854
  },
122497
122855
  {
122498
122856
  pattern: /`[^`]*`/,
122499
122857
  name: "backtick_execution",
122500
122858
  description: "Backtick shell execution",
122501
- severity: "error"
122859
+ severity: "warning"
122502
122860
  },
122503
122861
  {
122504
122862
  pattern: /\$\([^)]*\)/,
122505
122863
  name: "shell_substitution",
122506
122864
  description: "Shell command substitution",
122507
- severity: "error"
122865
+ severity: "warning"
122508
122866
  },
122509
122867
  {
122510
122868
  pattern: /disable\s+.{0,50}firewall/i,
@@ -122639,6 +122997,9 @@ function scanInvisibleFormatChars(text, fieldName) {
122639
122997
  }
122640
122998
  return findings;
122641
122999
  }
123000
+ function stripMarkdownCodeForUnsafeScan(text) {
123001
+ return text.replace(/```[\s\S]*?```/g, " ").replace(/~~~[\s\S]*?~~~/g, " ").replace(/`[^`\n]*`/g, " ");
123002
+ }
122642
123003
  function scanPromptInjection(candidate, trustLevel = "low") {
122643
123004
  const fields = extractCandidateFields(candidate);
122644
123005
  const findings = [];
@@ -122705,8 +123066,9 @@ function scanUnsafeInstructions(candidate, trustLevel = "low") {
122705
123066
  const fieldsScanned = [];
122706
123067
  for (const { field, value } of fields) {
122707
123068
  fieldsScanned.push(field);
123069
+ const scanValue = field === "skill_body" ? stripMarkdownCodeForUnsafeScan(value) : value;
122708
123070
  for (const entry of UNSAFE_INSTRUCTION_PATTERNS) {
122709
- const match = entry.pattern.exec(value);
123071
+ const match = entry.pattern.exec(scanValue);
122710
123072
  if (match !== null) {
122711
123073
  findings.push({
122712
123074
  pattern: entry.name,
@@ -122877,7 +123239,8 @@ function evaluateCandidate(candidate, options) {
122877
123239
  }
122878
123240
  var _internals78 = {
122879
123241
  getTimestamp: () => new Date().toISOString(),
122880
- computeSha256: (content) => createHash12("sha256").update(content).digest("hex")
123242
+ computeSha256: (content) => createHash13("sha256").update(content).digest("hex"),
123243
+ stripMarkdownCodeForUnsafeScan
122881
123244
  };
122882
123245
 
122883
123246
  // src/tools/external-skill-discover.ts
@@ -122898,7 +123261,7 @@ var _internals79 = {
122898
123261
  return { content, finalUrl: response.url };
122899
123262
  },
122900
123263
  getTimestamp: () => new Date().toISOString(),
122901
- computeSha256: (content) => createHash13("sha256").update(content).digest("hex"),
123264
+ computeSha256: (content) => createHash14("sha256").update(content).digest("hex"),
122902
123265
  uuid: () => randomUUID13()
122903
123266
  };
122904
123267
  var SOURCE_TRUST_LEVELS = {
@@ -123284,7 +123647,7 @@ var external_skill_list = createSwarmTool({
123284
123647
  // src/tools/external-skill-promote.ts
123285
123648
  init_zod();
123286
123649
  init_loader();
123287
- import { createHash as createHash14 } from "node:crypto";
123650
+ import { createHash as createHash15 } from "node:crypto";
123288
123651
  import * as fs95 from "node:fs/promises";
123289
123652
  import * as path146 from "node:path";
123290
123653
  init_create_tool();
@@ -123449,7 +123812,7 @@ var external_skill_promote = createSwarmTool({
123449
123812
  }
123450
123813
  throw writeErr;
123451
123814
  }
123452
- const promotedContentHash = createHash14("sha256").update(skillMarkdown).digest("hex");
123815
+ const promotedContentHash = createHash15("sha256").update(skillMarkdown).digest("hex");
123453
123816
  const prePromotionHistory = candidate.evaluation_history;
123454
123817
  const lastPrePromotionEntry = prePromotionHistory.length > 0 ? prePromotionHistory[prePromotionHistory.length - 1] : undefined;
123455
123818
  const originalEvaluation = lastPrePromotionEntry ? {
@@ -124418,8 +124781,8 @@ var git_blame = createSwarmTool({
124418
124781
  lines: []
124419
124782
  });
124420
124783
  }
124421
- const stat10 = fs97.statSync(resolvedPath);
124422
- if (stat10.isDirectory()) {
124784
+ const stat11 = fs97.statSync(resolvedPath);
124785
+ if (stat11.isDirectory()) {
124423
124786
  return JSON.stringify({
124424
124787
  error: "path is a directory, not a file",
124425
124788
  file: file3,
@@ -124536,6 +124899,102 @@ var git_blame = createSwarmTool({
124536
124899
 
124537
124900
  // src/tools/gitingest.ts
124538
124901
  init_zod();
124902
+
124903
+ // src/services/external-content-scanner.ts
124904
+ init_knowledge_validator();
124905
+ function scanInvisibleFormatChars2(text) {
124906
+ const findings = [];
124907
+ const matches = text.match(INVISIBLE_FORMAT_CHARS);
124908
+ if (matches !== null && matches.length > 0) {
124909
+ for (const match of matches) {
124910
+ findings.push({
124911
+ pattern: "invisible_format_chars",
124912
+ field: "external_content",
124913
+ description: `Invisible format characters detected (${matches.length} occurrence(s))`,
124914
+ severity: "error",
124915
+ match: match.slice(0, 100)
124916
+ });
124917
+ }
124918
+ }
124919
+ return findings;
124920
+ }
124921
+ function neutralizeThreatPatterns(text, findings) {
124922
+ if (findings.length === 0) {
124923
+ return text;
124924
+ }
124925
+ let result = text;
124926
+ for (const finding of findings.filter((f) => f.severity === "error")) {
124927
+ const escapedMatch = finding.match.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
124928
+ const pattern = new RegExp(escapedMatch, "g");
124929
+ result = result.replace(pattern, () => `[EXTERNAL_CONTENT_THREAT: ${finding.pattern}] ${finding.match} [/EXTERNAL_CONTENT_THREAT]`);
124930
+ }
124931
+ return result;
124932
+ }
124933
+ function scanExternalContent(text, options) {
124934
+ const trustLevel = options?.trustLevel ?? "low";
124935
+ const maxLength = options?.maxLength ?? 50000;
124936
+ if (text == null) {
124937
+ text = "";
124938
+ }
124939
+ const originalLength = text.length;
124940
+ const findings = [];
124941
+ if (text.length > maxLength) {
124942
+ findings.push({
124943
+ pattern: "oversized_content",
124944
+ field: "external_content",
124945
+ description: `External content exceeds safe size threshold (${text.length} > ${maxLength} bytes)`,
124946
+ severity: "error",
124947
+ match: `${text.length} bytes`
124948
+ });
124949
+ }
124950
+ findings.push(...scanInvisibleFormatChars2(text));
124951
+ for (const entry of PROMPT_INJECTION_PATTERNS) {
124952
+ const match = entry.pattern.exec(text);
124953
+ if (match !== null) {
124954
+ findings.push({
124955
+ pattern: entry.name,
124956
+ field: "external_content",
124957
+ description: entry.description,
124958
+ severity: entry.severity,
124959
+ match: match[0]
124960
+ });
124961
+ }
124962
+ }
124963
+ for (const entry of UNSAFE_INSTRUCTION_PATTERNS) {
124964
+ const match = entry.pattern.exec(text);
124965
+ if (match !== null) {
124966
+ findings.push({
124967
+ pattern: entry.name,
124968
+ field: "external_content",
124969
+ description: entry.description,
124970
+ severity: entry.severity,
124971
+ match: match[0]
124972
+ });
124973
+ }
124974
+ }
124975
+ const promoteWarnings = trustLevel === "low";
124976
+ const modulatedFindings = findings.map((f) => promoteWarnings && f.severity === "warning" ? { ...f, severity: "error" } : f);
124977
+ const hasErrors = modulatedFindings.some((f) => f.severity === "error");
124978
+ const hasWarnings = modulatedFindings.some((f) => f.severity === "warning");
124979
+ let threatLevel;
124980
+ if (hasErrors) {
124981
+ threatLevel = "error";
124982
+ } else if (hasWarnings) {
124983
+ threatLevel = "warning";
124984
+ } else {
124985
+ threatLevel = "none";
124986
+ }
124987
+ const neutralized = neutralizeThreatPatterns(text, modulatedFindings.filter((f) => f.severity === "error"));
124988
+ return {
124989
+ clean: threatLevel === "none",
124990
+ findings: modulatedFindings,
124991
+ threatLevel,
124992
+ originalLength,
124993
+ neutralized
124994
+ };
124995
+ }
124996
+
124997
+ // src/tools/gitingest.ts
124539
124998
  init_create_tool();
124540
124999
  var GITINGEST_TIMEOUT_MS = 1e4;
124541
125000
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
@@ -124573,7 +125032,31 @@ async function fetchGitingest(args2) {
124573
125032
  if (Number.isFinite(contentLength) && contentLength > GITINGEST_MAX_RESPONSE_BYTES) {
124574
125033
  throw new Error("gitingest response too large");
124575
125034
  }
124576
- const text = await response.text();
125035
+ let text;
125036
+ const reader = response.body?.getReader();
125037
+ if (reader) {
125038
+ let buffer = "";
125039
+ const decoder = new TextDecoder;
125040
+ let totalBytes = 0;
125041
+ try {
125042
+ while (true) {
125043
+ const { done, value } = await reader.read();
125044
+ if (done)
125045
+ break;
125046
+ totalBytes += value.byteLength;
125047
+ if (totalBytes > GITINGEST_MAX_RESPONSE_BYTES) {
125048
+ throw new Error("gitingest response too large");
125049
+ }
125050
+ buffer += decoder.decode(value, { stream: true });
125051
+ }
125052
+ buffer += decoder.decode();
125053
+ text = buffer;
125054
+ } finally {
125055
+ reader.cancel().catch(() => {});
125056
+ }
125057
+ } else {
125058
+ text = await response.text();
125059
+ }
124577
125060
  if (Buffer.byteLength(text) > GITINGEST_MAX_RESPONSE_BYTES) {
124578
125061
  throw new Error("gitingest response too large");
124579
125062
  }
@@ -124583,11 +125066,24 @@ async function fetchGitingest(args2) {
124583
125066
  } catch {
124584
125067
  throw new Error(`gitingest API returned non-JSON response (${text.length} chars, starts: ${text.slice(0, 80)})`);
124585
125068
  }
124586
- return `${data.summary}
125069
+ const combined = `${data.summary}
124587
125070
 
124588
125071
  ${data.tree}
124589
125072
 
124590
125073
  ${data.content}`;
125074
+ const scanResult = scanExternalContent(combined, { trustLevel: "low" });
125075
+ let result = combined;
125076
+ if (!scanResult.clean) {
125077
+ const threatSummary = scanResult.findings.filter((f) => f.severity === "error").map((f) => `- ${f.pattern}: ${f.description}`).join(`
125078
+ `);
125079
+ result = `[GITINGEST SECURITY NOTE: External repository content scanned and contains potential threat patterns]
125080
+ ${threatSummary}
125081
+
125082
+ [Content follows with threats marked for LLM awareness]
125083
+
125084
+ ${scanResult.neutralized}`;
125085
+ }
125086
+ return result;
124591
125087
  } catch (error93) {
124592
125088
  if (error93 instanceof DOMException && (error93.name === "TimeoutError" || error93.name === "AbortError")) {
124593
125089
  if (attempt >= GITINGEST_MAX_RETRIES) {
@@ -124806,9 +125302,9 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
124806
125302
  continue;
124807
125303
  }
124808
125304
  const fullPath = path150.join(dir, entry);
124809
- let stat10;
125305
+ let stat11;
124810
125306
  try {
124811
- stat10 = fs98.statSync(fullPath);
125307
+ stat11 = fs98.statSync(fullPath);
124812
125308
  } catch (e) {
124813
125309
  stats.fileErrors.push({
124814
125310
  path: fullPath,
@@ -124816,9 +125312,9 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
124816
125312
  });
124817
125313
  continue;
124818
125314
  }
124819
- if (stat10.isDirectory()) {
125315
+ if (stat11.isDirectory()) {
124820
125316
  findSourceFiles3(fullPath, files, stats);
124821
- } else if (stat10.isFile()) {
125317
+ } else if (stat11.isFile()) {
124822
125318
  const ext = path150.extname(fullPath).toLowerCase();
124823
125319
  if (SUPPORTED_EXTENSIONS3.includes(ext)) {
124824
125320
  files.push(fullPath);
@@ -124913,8 +125409,8 @@ var imports = createSwarmTool({
124913
125409
  if (consumers.length >= MAX_CONSUMERS)
124914
125410
  break;
124915
125411
  try {
124916
- const stat10 = fs98.statSync(filePath);
124917
- if (stat10.size > MAX_FILE_SIZE_BYTES7) {
125412
+ const stat11 = fs98.statSync(filePath);
125413
+ if (stat11.size > MAX_FILE_SIZE_BYTES7) {
124918
125414
  skippedFileCount++;
124919
125415
  continue;
124920
125416
  }
@@ -125276,10 +125772,12 @@ init_knowledge_store();
125276
125772
  init_logger();
125277
125773
  init_create_tool();
125278
125774
  var MODES2 = ["archive", "quarantine", "purge"];
125775
+ var TIERS = ["swarm", "hive"];
125279
125776
  var knowledge_archive = createSwarmTool({
125280
- description: "Archive (default), quarantine, or purge a swarm knowledge entry by ID, appending an immutable audit tombstone. 'archive'/'quarantine' set the entry status reversibly and hide it from recall; 'purge' hard-deletes and requires allow_purge:true.",
125777
+ description: "Archive (default), quarantine, or purge a swarm or hive knowledge entry by ID, appending an immutable audit tombstone. 'archive'/'quarantine' set the entry status reversibly and hide it from recall; 'purge' hard-deletes and requires allow_purge:true.",
125281
125778
  args: {
125282
125779
  id: exports_external.string().min(1).describe("UUID of the knowledge entry"),
125780
+ tier: exports_external.enum(TIERS).optional().describe("Knowledge tier to modify; default 'swarm'"),
125283
125781
  reason: exports_external.string().min(1).max(500).describe("Why the entry is being archived/quarantined/purged"),
125284
125782
  evidence: exports_external.string().max(1000).optional().describe('Supporting evidence (e.g. "ignored 8 times, contradicted by tests")'),
125285
125783
  mode: exports_external.enum(MODES2).optional().describe("Default 'archive'"),
@@ -125302,6 +125800,7 @@ var knowledge_archive = createSwarmTool({
125302
125800
  });
125303
125801
  }
125304
125802
  const evidence = typeof a.evidence === "string" ? a.evidence : undefined;
125803
+ const tier = a.tier === "hive" ? "hive" : "swarm";
125305
125804
  const mode = a.mode === "quarantine" || a.mode === "purge" ? a.mode : "archive";
125306
125805
  if (mode === "purge" && a.allow_purge !== true) {
125307
125806
  return JSON.stringify({
@@ -125309,44 +125808,40 @@ var knowledge_archive = createSwarmTool({
125309
125808
  error: "purge requires allow_purge:true (admin flag)"
125310
125809
  });
125311
125810
  }
125312
- const swarmPath = resolveSwarmKnowledgePath(directory);
125313
- let entries;
125314
- try {
125315
- entries = await readKnowledge(swarmPath);
125316
- } catch (err2) {
125317
- return JSON.stringify({
125318
- success: false,
125319
- error: err2 instanceof Error ? err2.message : "Unknown error"
125320
- });
125321
- }
125322
- const target = entries.find((e) => e.id === id);
125323
- if (!target) {
125324
- return JSON.stringify({ success: false, message: "entry not found" });
125325
- }
125326
- const previousStatus = target.status;
125811
+ const knowledgePath = tier === "hive" ? resolveHiveKnowledgePath() : resolveSwarmKnowledgePath(directory);
125812
+ let found = false;
125813
+ let previousStatus;
125327
125814
  const now = new Date().toISOString();
125328
- let nextEntries;
125329
125815
  let resultStatus;
125330
- if (mode === "purge") {
125331
- warn(`[knowledge_archive] PURGE: hard-deleting entry id=${id} actor=${ctx?.agent ?? "unknown"} reason=${reason}`);
125332
- nextEntries = entries.filter((e) => e.id !== id);
125333
- resultStatus = "purged";
125334
- } else {
125335
- const newStatus = mode === "quarantine" ? "quarantined" : "archived";
125336
- nextEntries = entries.map((e) => e.id === id ? { ...e, status: newStatus, updated_at: now } : e);
125337
- resultStatus = newStatus;
125338
- }
125339
125816
  try {
125340
- await rewriteKnowledge(swarmPath, nextEntries);
125817
+ await transactKnowledge(knowledgePath, (entries) => {
125818
+ const target = entries.find((e) => e.id === id);
125819
+ if (!target)
125820
+ return null;
125821
+ found = true;
125822
+ previousStatus = target.status;
125823
+ if (mode === "purge") {
125824
+ warn(`[knowledge_archive] PURGE: hard-deleting ${tier} entry id=${id} actor=${ctx?.agent ?? "unknown"} reason=${reason}`);
125825
+ resultStatus = "purged";
125826
+ return entries.filter((e) => e.id !== id);
125827
+ }
125828
+ const newStatus = mode === "quarantine" ? "quarantined" : "archived";
125829
+ resultStatus = newStatus;
125830
+ return entries.map((e) => e.id === id ? { ...e, status: newStatus, updated_at: now } : e);
125831
+ });
125341
125832
  } catch (err2) {
125342
125833
  return JSON.stringify({
125343
125834
  success: false,
125344
125835
  error: err2 instanceof Error ? err2.message : "Unknown error"
125345
125836
  });
125346
125837
  }
125838
+ if (!found) {
125839
+ return JSON.stringify({ success: false, message: "entry not found" });
125840
+ }
125347
125841
  await recordKnowledgeEvent(directory, {
125348
125842
  type: "archived",
125349
125843
  entry_id: id,
125844
+ tier,
125350
125845
  actor: ctx?.agent ?? "unknown",
125351
125846
  reason,
125352
125847
  mode,
@@ -125356,6 +125851,7 @@ var knowledge_archive = createSwarmTool({
125356
125851
  return JSON.stringify({
125357
125852
  success: true,
125358
125853
  id,
125854
+ tier,
125359
125855
  mode,
125360
125856
  previous_status: previousStatus,
125361
125857
  status: resultStatus
@@ -130326,12 +130822,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
130326
130822
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
130327
130823
  try {
130328
130824
  const projectName = path166.basename(dir);
130329
- const skillImproverCfg = SkillImproverConfigSchema.parse(config3.skill_improver ?? {});
130330
130825
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig, {
130331
130826
  llmDelegate: createCuratorLLMDelegate(dir, "phase", sessionID),
130332
130827
  enrichmentQuota: {
130333
- maxCalls: skillImproverCfg.max_calls_per_day,
130334
- window: skillImproverCfg.quota_window
130828
+ maxCalls: knowledgeConfig.enrichment.max_calls_per_day,
130829
+ window: knowledgeConfig.enrichment.quota_window
130335
130830
  }
130336
130831
  });
130337
130832
  if (curationResult) {
@@ -132432,8 +132927,8 @@ async function placeholderScan(input, directory) {
132432
132927
  }
132433
132928
  let content;
132434
132929
  try {
132435
- const stat10 = fs115.statSync(fullPath);
132436
- if (stat10.size > MAX_FILE_SIZE) {
132930
+ const stat11 = fs115.statSync(fullPath);
132931
+ if (stat11.size > MAX_FILE_SIZE) {
132437
132932
  continue;
132438
132933
  }
132439
132934
  content = fs115.readFileSync(fullPath, "utf-8");
@@ -134614,14 +135109,14 @@ async function runSecretscanWithFiles(files, directory) {
134614
135109
  skippedFiles++;
134615
135110
  continue;
134616
135111
  }
134617
- let stat10;
135112
+ let stat11;
134618
135113
  try {
134619
- stat10 = fs119.statSync(file3);
135114
+ stat11 = fs119.statSync(file3);
134620
135115
  } catch {
134621
135116
  skippedFiles++;
134622
135117
  continue;
134623
135118
  }
134624
- if (stat10.size > MAX_FILE_SIZE_BYTES9) {
135119
+ if (stat11.size > MAX_FILE_SIZE_BYTES9) {
134625
135120
  skippedFiles++;
134626
135121
  continue;
134627
135122
  }
@@ -135400,8 +135895,8 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
135400
135895
  for (const entry of entries) {
135401
135896
  const entryPath = path174.join(evidenceDir, entry);
135402
135897
  try {
135403
- const stat10 = fs120.statSync(entryPath);
135404
- if (!stat10.isDirectory()) {
135898
+ const stat11 = fs120.statSync(entryPath);
135899
+ if (!stat11.isDirectory()) {
135405
135900
  continue;
135406
135901
  }
135407
135902
  } catch {
@@ -135421,11 +135916,11 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
135421
135916
  if (!resolvedPath.startsWith(evidenceDirResolved + path174.sep)) {
135422
135917
  continue;
135423
135918
  }
135424
- const stat10 = fs120.lstatSync(evidenceFilePath);
135425
- if (!stat10.isFile()) {
135919
+ const stat11 = fs120.lstatSync(evidenceFilePath);
135920
+ if (!stat11.isFile()) {
135426
135921
  continue;
135427
135922
  }
135428
- if (stat10.size > MAX_FILE_SIZE_BYTES9) {
135923
+ if (stat11.size > MAX_FILE_SIZE_BYTES9) {
135429
135924
  continue;
135430
135925
  }
135431
135926
  } catch {
@@ -138176,6 +138671,11 @@ var skill_improve = createSwarmTool({
138176
138671
  const a = args2 ?? {};
138177
138672
  const { config: config3 } = loadPluginConfigWithMeta(directory);
138178
138673
  const parsed = SkillImproverConfigSchema.parse(config3.skill_improver ?? {});
138674
+ const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
138675
+ const enrichmentConfig = knowledgeConfig.enrichment ?? {
138676
+ max_calls_per_day: 30,
138677
+ quota_window: "utc"
138678
+ };
138179
138679
  if (!parsed.enabled) {
138180
138680
  return JSON.stringify({
138181
138681
  ran: false,
@@ -138188,7 +138688,11 @@ var skill_improve = createSwarmTool({
138188
138688
  targets: a.targets,
138189
138689
  mode: a.mode,
138190
138690
  maxCalls: a.max_calls,
138191
- sessionId: ctx?.sessionID
138691
+ sessionId: ctx?.sessionID,
138692
+ enrichmentQuota: {
138693
+ maxCalls: enrichmentConfig.max_calls_per_day,
138694
+ window: enrichmentConfig.quota_window
138695
+ }
138192
138696
  });
138193
138697
  return JSON.stringify(result, null, 2);
138194
138698
  }
@@ -138270,7 +138774,7 @@ init_zod();
138270
138774
  init_config();
138271
138775
  init_schema();
138272
138776
  init_create_tool();
138273
- import { mkdir as mkdir30, rename as rename12, writeFile as writeFile22 } from "node:fs/promises";
138777
+ import { mkdir as mkdir30, rename as rename12, writeFile as writeFile21 } from "node:fs/promises";
138274
138778
  import * as path179 from "node:path";
138275
138779
  var MAX_SPEC_BYTES2 = 256 * 1024;
138276
138780
  var spec_write = createSwarmTool({
@@ -138332,7 +138836,7 @@ ${content}
138332
138836
  }
138333
138837
  } catch {}
138334
138838
  }
138335
- await writeFile22(tmp, finalContent, "utf-8");
138839
+ await writeFile21(tmp, finalContent, "utf-8");
138336
138840
  await rename12(tmp, target);
138337
138841
  return JSON.stringify({ written: true, path: target, bytes: finalContent.length }, null, 2);
138338
138842
  }
@@ -139551,8 +140055,8 @@ async function syntaxCheck(input, directory, config3) {
139551
140055
  return { result, counted: false, failed: false, skipped: true };
139552
140056
  }
139553
140057
  try {
139554
- const stat10 = fs126.statSync(fullPath);
139555
- if (stat10.size >= MAX_FILE_SIZE2) {
140058
+ const stat11 = fs126.statSync(fullPath);
140059
+ if (stat11.size >= MAX_FILE_SIZE2) {
139556
140060
  result.skipped_reason = "file_too_large";
139557
140061
  return { result, counted: false, failed: false, skipped: true };
139558
140062
  }
@@ -139784,15 +140288,15 @@ function findSourceFiles4(dir, files = []) {
139784
140288
  continue;
139785
140289
  }
139786
140290
  const fullPath = path183.join(dir, entry);
139787
- let stat10;
140291
+ let stat11;
139788
140292
  try {
139789
- stat10 = fs127.statSync(fullPath);
140293
+ stat11 = fs127.statSync(fullPath);
139790
140294
  } catch {
139791
140295
  continue;
139792
140296
  }
139793
- if (stat10.isDirectory()) {
140297
+ if (stat11.isDirectory()) {
139794
140298
  findSourceFiles4(fullPath, files);
139795
- } else if (stat10.isFile()) {
140299
+ } else if (stat11.isFile()) {
139796
140300
  if (isSupportedExtension(fullPath)) {
139797
140301
  files.push(fullPath);
139798
140302
  }
@@ -139889,8 +140393,8 @@ var todo_extract = createSwarmTool({
139889
140393
  return JSON.stringify(errorResult, null, 2);
139890
140394
  }
139891
140395
  const filesToScan = [];
139892
- const stat10 = fs127.statSync(scanPath);
139893
- if (stat10.isFile()) {
140396
+ const stat11 = fs127.statSync(scanPath);
140397
+ if (stat11.isFile()) {
139894
140398
  if (isSupportedExtension(scanPath)) {
139895
140399
  filesToScan.push(scanPath);
139896
140400
  } else {
@@ -141010,7 +141514,7 @@ import * as zlib from "node:zlib";
141010
141514
  // src/evidence/documents.ts
141011
141515
  init_utils2();
141012
141516
  init_redaction();
141013
- import { createHash as createHash16 } from "node:crypto";
141517
+ import { createHash as createHash17 } from "node:crypto";
141014
141518
  import { appendFile as appendFile17, mkdir as mkdir31 } from "node:fs/promises";
141015
141519
  import * as path188 from "node:path";
141016
141520
  var EVIDENCE_CACHE_FILE = "evidence-cache/documents.jsonl";
@@ -141054,7 +141558,7 @@ function createEvidenceDocumentRecord(input, defaultCapturedAt) {
141054
141558
  };
141055
141559
  }
141056
141560
  function createEvidenceDocumentId(input) {
141057
- const hash4 = createHash16("sha256").update([
141561
+ const hash4 = createHash17("sha256").update([
141058
141562
  input.sourceType,
141059
141563
  input.query ?? "",
141060
141564
  input.title ?? "",
@@ -141951,6 +142455,20 @@ var web_search = createSwarmTool({
141951
142455
  freshness
141952
142456
  });
141953
142457
  const evidence = await captureSearchEvidence(dirResult.directory, policy.query, results);
142458
+ const scannedResults = results.map(({ title, url: url3, snippet }) => {
142459
+ const titleScan = scanExternalContent(title, { trustLevel: "low" });
142460
+ const snippetScan = scanExternalContent(snippet, {
142461
+ trustLevel: "low"
142462
+ });
142463
+ const threatLevel = titleScan.threatLevel === "error" || snippetScan.threatLevel === "error" ? "error" : titleScan.threatLevel === "warning" || snippetScan.threatLevel === "warning" ? "warning" : "none";
142464
+ return {
142465
+ title: titleScan.clean ? title : titleScan.neutralized,
142466
+ url: url3,
142467
+ snippet: snippetScan.clean ? snippet : snippetScan.neutralized,
142468
+ evidenceRef: evidence.refByUrl.get(url3),
142469
+ threatLevel
142470
+ };
142471
+ });
141954
142472
  const ok2 = {
141955
142473
  success: true,
141956
142474
  query: policy.query,
@@ -141959,12 +142477,7 @@ var web_search = createSwarmTool({
141959
142477
  freshness,
141960
142478
  removedStaleYears: policy.removedStaleYears,
141961
142479
  totalResults: results.length,
141962
- results: results.map(({ title, url: url3, snippet }) => ({
141963
- title,
141964
- url: url3,
141965
- snippet,
141966
- evidenceRef: evidence.refByUrl.get(url3)
141967
- })),
142480
+ results: scannedResults,
141968
142481
  evidence: {
141969
142482
  stored: evidence.stored,
141970
142483
  path: evidence.path,
@@ -142104,13 +142617,12 @@ var write_architecture_supervisor_evidence = createSwarmTool({
142104
142617
  if (config3.architectural_supervision?.persist_knowledge_recommendations && args2.knowledge_recommendations.length > 0) {
142105
142618
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
142106
142619
  const lessons = args2.knowledge_recommendations.map((r) => r.lesson);
142107
- const skillImproverCfg = SkillImproverConfigSchema.parse(config3.skill_improver ?? {});
142108
142620
  const result = await curateAndStoreSwarm(lessons, path189.basename(dirResult.directory), { phase_number: args2.phase }, dirResult.directory, knowledgeConfig, {
142109
142621
  skipAutoPromotion: true,
142110
142622
  llmDelegate: createCuratorLLMDelegate(dirResult.directory, "phase"),
142111
142623
  enrichmentQuota: {
142112
- maxCalls: skillImproverCfg.max_calls_per_day,
142113
- window: skillImproverCfg.quota_window
142624
+ maxCalls: knowledgeConfig.enrichment.max_calls_per_day,
142625
+ window: knowledgeConfig.enrichment.quota_window
142114
142626
  }
142115
142627
  });
142116
142628
  knowledgeProposed = result.stored;
@@ -143127,11 +143639,16 @@ async function initializeOpenCodeSwarm(ctx) {
143127
143639
  const summaryConfig = SummaryConfigSchema.parse(config3.summaries ?? {});
143128
143640
  const toolSummarizerHook = createToolSummarizerHook(summaryConfig, ctx.directory);
143129
143641
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
143130
- const skillImproverConfig = SkillImproverConfigSchema.parse(config3.skill_improver ?? {});
143131
143642
  const skillPropagationConfig = SkillPropagationConfigSchema.parse(config3.skillPropagation ?? {});
143132
- const knowledgeCuratorHook = knowledgeConfig.enabled ? createKnowledgeCuratorHook(ctx.directory, knowledgeConfig) : undefined;
143643
+ const knowledgeCuratorHook = knowledgeConfig.enabled ? createKnowledgeCuratorHook(ctx.directory, knowledgeConfig, {
143644
+ llmDelegateFactory: (sessionID) => createCuratorLLMDelegate(ctx.directory, "phase", sessionID),
143645
+ enrichmentQuota: {
143646
+ maxCalls: knowledgeConfig.enrichment.max_calls_per_day,
143647
+ window: knowledgeConfig.enrichment.quota_window
143648
+ }
143649
+ }) : undefined;
143133
143650
  const hivePromoterHook = knowledgeConfig.enabled && knowledgeConfig.hive_enabled ? createHivePromoterHook(ctx.directory, knowledgeConfig) : undefined;
143134
- const knowledgeInjectorHook = knowledgeConfig.enabled ? createKnowledgeInjectorHook(ctx.directory, knowledgeConfig) : undefined;
143651
+ const knowledgeInjectorHook = knowledgeConfig.enabled ? createKnowledgeInjectorHook(ctx.directory, knowledgeConfig, config3.context_budget?.model_limits ?? {}) : undefined;
143135
143652
  const steeringConsumedHook = createSteeringConsumedHook(ctx.directory);
143136
143653
  const coChangeSuggesterHook = createCoChangeSuggesterHook(ctx.directory);
143137
143654
  const darkMatterDetectorHook = createDarkMatterDetectorHook(ctx.directory);
@@ -143858,8 +144375,8 @@ ${usedByCoderLine}`;
143858
144375
  await safeHook(() => collectDelegateAcksAfter(ctx.directory, input, output))(input, output);
143859
144376
  await safeHook(() => collectReviewerVerdictsAfter(ctx.directory, input, output))(input, output);
143860
144377
  await safeHook(() => microReflectorAfter(ctx.directory, input, output, createCuratorLLMDelegate(ctx.directory, "phase", input.sessionID), {
143861
- maxCalls: skillImproverConfig.max_calls_per_day,
143862
- window: skillImproverConfig.quota_window
144378
+ maxCalls: knowledgeConfig.enrichment.max_calls_per_day,
144379
+ window: knowledgeConfig.enrichment.quota_window
143863
144380
  }))(input, output);
143864
144381
  }
143865
144382
  await safeHook(prmHook.toolAfter)(input, output);