opencode-swarm 7.107.2 → 7.107.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.opencode/skills/consult/SKILL.md +10 -0
  2. package/.opencode/skills/council/SKILL.md +10 -0
  3. package/.opencode/skills/engineering-conventions/SKILL.md +20 -0
  4. package/README.md +2 -2
  5. package/dist/agents/agent-output-schema.d.ts +1 -1
  6. package/dist/cli/{config-doctor-cntnpyvj.js → config-doctor-kdq3vae4.js} +3 -2
  7. package/dist/cli/{curator-drift-6ad8mxxb.js → curator-drift-ed7p5mfy.js} +2 -2
  8. package/dist/cli/{curator-llm-factory-r3m5e7n8.js → curator-llm-factory-abw56kg0.js} +18 -13
  9. package/dist/cli/{curator-6zvpn7fs.js → curator-rb05fjjk.js} +18 -13
  10. package/dist/cli/{dispatch-e4ejrsz8.js → dispatch-anmxxhen.js} +56 -13
  11. package/dist/cli/{evidence-summary-service-7nwhd8s4.js → evidence-summary-service-nwdfnbz1.js} +4 -4
  12. package/dist/cli/gate-evidence-ywys9vfs.js +1 -1
  13. package/dist/cli/guardrail-explain-dayy7zw4.js +37 -0
  14. package/dist/cli/{guardrail-log-fsc85hwa.js → guardrail-log-fjypsmek.js} +4 -3
  15. package/dist/cli/{hive-promoter-nwcsha2j.js → hive-promoter-34bdmw1w.js} +18 -13
  16. package/dist/cli/{index-r87xhtmx.js → index-19vxtwa6.js} +22 -17
  17. package/dist/cli/{index-t4hbye3v.js → index-4r5z8sgw.js} +4 -4
  18. package/dist/cli/{index-fxtrk7y8.js → index-4vsgp5a8.js} +2 -2
  19. package/dist/cli/{index-mpe0yk9s.js → index-57ymmh7h.js} +5 -3
  20. package/dist/cli/{index-357p0baj.js → index-91j1sqzm.js} +14 -2
  21. package/dist/cli/{index-f12bmedv.js → index-9b7a6agd.js} +91 -34
  22. package/dist/cli/index-bfwt3abw.js +14 -0
  23. package/dist/cli/{index-9wstcavp.js → index-bpgqbwmf.js} +115 -1019
  24. package/dist/cli/index-bq8kd9r9.js +199 -0
  25. package/dist/cli/index-dfdg4ws5.js +741 -0
  26. package/dist/cli/{index-jr54w7pb.js → index-f45hbd5x.js} +2 -2
  27. package/dist/cli/{index-168p3bfr.js → index-gyzxeza3.js} +910 -608
  28. package/dist/cli/index-kxm3bdjh.js +631 -0
  29. package/dist/cli/index-n1sptn1w.js +147 -0
  30. package/dist/cli/{index-2560cctg.js → index-pchpahdf.js} +11 -0
  31. package/dist/cli/{index-esg1554h.js → index-wvxhynxq.js} +1 -1
  32. package/dist/cli/{index-8w4d325g.js → index-xg18az81.js} +61 -22
  33. package/dist/cli/{index-f7nma02k.js → index-xmarctsf.js} +137 -175
  34. package/dist/cli/{index-w8dzxnx4.js → index-zej8cy0j.js} +1 -1
  35. package/dist/cli/index.js +18 -13
  36. package/dist/cli/knowledge-escalator-3sgwrgy9.js +32 -0
  37. package/dist/cli/knowledge-events-kfc6xmkw.js +62 -0
  38. package/dist/cli/{knowledge-store-tsa8ezka.js → knowledge-store-kyacem71.js} +3 -1
  39. package/dist/cli/knowledge-validator-ez3ws8ef.js +57 -0
  40. package/dist/cli/{pending-delegations-46xf2n2e.js → pending-delegations-vfnpm8zt.js} +4 -4
  41. package/dist/cli/{pr-subscriptions-3c34rnm1.js → pr-subscriptions-bpvazmsw.js} +3 -3
  42. package/dist/cli/{schema-vw2ffhe9.js → schema-x0ekqzvs.js} +2 -1
  43. package/dist/cli/{skill-generator-y6mmq8n5.js → skill-generator-x83re96d.js} +6 -2
  44. package/dist/commands/knowledge.d.ts +5 -1
  45. package/dist/commands/registry.d.ts +2 -2
  46. package/dist/config/evidence-schema.d.ts +9 -9
  47. package/dist/config/schema.d.ts +42 -12
  48. package/dist/hooks/guardrails/file-authority.d.ts +1 -1
  49. package/dist/hooks/knowledge-curator.d.ts +27 -0
  50. package/dist/hooks/knowledge-escalator.d.ts +16 -0
  51. package/dist/hooks/knowledge-events.d.ts +11 -0
  52. package/dist/hooks/knowledge-injector.d.ts +3 -0
  53. package/dist/hooks/knowledge-store.d.ts +16 -1
  54. package/dist/hooks/knowledge-types.d.ts +85 -0
  55. package/dist/hooks/knowledge-validator.d.ts +15 -0
  56. package/dist/hooks/semantic-diff-injection.d.ts +19 -0
  57. package/dist/hooks/skill-usage-log.d.ts +3 -0
  58. package/dist/index.js +354 -353
  59. package/dist/memory/consolidation.d.ts +1 -1
  60. package/dist/memory/schema.d.ts +4 -4
  61. package/dist/sast/rules/rust.d.ts +6 -0
  62. package/dist/services/directive-predicate-runner.d.ts +1 -1
  63. package/dist/tools/knowledge-archive.d.ts +6 -2
  64. package/dist/tools/knowledge-remove.d.ts +11 -0
  65. package/dist/tools/lint.d.ts +2 -2
  66. package/dist/tools/secretscan.d.ts +16 -0
  67. package/dist/tools/test-runner.d.ts +1 -1
  68. package/package.json +1 -1
  69. package/dist/cli/guardrail-explain-zajegz3a.js +0 -32
@@ -1,956 +1,52 @@
1
1
  // @bun
2
+ import {
3
+ ALLOWED_SKILL_PATH_PREFIXES,
4
+ validateSkillPath
5
+ } from "./index-dfdg4ws5.js";
6
+ import {
7
+ effectiveRetrievalOutcomes,
8
+ readKnowledgeCounterRollups
9
+ } from "./index-kxm3bdjh.js";
2
10
  import {
3
11
  computeOutcomeSignal,
4
- findNearDuplicate,
5
- inferTags,
6
12
  readKnowledge,
7
13
  resolveHiveKnowledgePath,
8
- resolveKnowledgeStoreDir,
9
14
  resolveSwarmKnowledgePath,
10
- resolveSwarmRejectedPath,
11
- rewriteKnowledge,
12
- transactKnowledge
13
- } from "./index-f7nma02k.js";
14
- import {
15
- atomicWriteFile
16
- } from "./index-9b7qp18e.js";
15
+ rewriteKnowledge
16
+ } from "./index-xmarctsf.js";
17
17
  import {
18
18
  init_logger,
19
19
  warn
20
20
  } from "./index-zgwm4ryv.js";
21
21
  import {
22
- require_proper_lockfile
23
- } from "./index-3naa2ajc.js";
24
- import {
25
- __require,
26
- __toESM
22
+ __require
27
23
  } from "./index-a76rekgs.js";
28
24
 
29
25
  // src/services/skill-generator.ts
30
- import { existsSync as existsSync3, unlinkSync } from "fs";
31
- import { mkdir as mkdir5, readFile as readFile4, rename as rename2, unlink, writeFile as writeFile3 } from "fs/promises";
32
- import * as path5 from "path";
33
-
34
- // src/hooks/knowledge-events.ts
35
- import { existsSync } from "fs";
36
- import { appendFile, mkdir, readFile, stat } from "fs/promises";
37
- var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
38
- import * as path from "path";
39
- init_logger();
40
- var counterRollupCache = new Map;
41
- var MAX_COUNTER_ROLLUP_CACHE_DIRS = 32;
42
- var RECEIPT_EVENT_TYPES = new Set([
43
- "acknowledged",
44
- "applied",
45
- "ignored",
46
- "contradicted",
47
- "violated",
48
- "n_a",
49
- "override"
50
- ]);
51
- function resolveKnowledgeEventsPath(directory) {
52
- return path.join(resolveKnowledgeStoreDir(directory), "knowledge-events.jsonl");
53
- }
54
- function resolveKnowledgeCounterBaselinePath(directory) {
55
- return path.join(resolveKnowledgeStoreDir(directory), "knowledge-counter-baseline.json");
56
- }
57
- function resolveLegacyApplicationLogPath(directory) {
58
- return path.join(resolveKnowledgeStoreDir(directory), "knowledge-application.jsonl");
59
- }
60
- async function readKnowledgeEvents(directory, maxEvents) {
61
- const filePath = resolveKnowledgeEventsPath(directory);
62
- if (!existsSync(filePath))
63
- return [];
64
- const content = await readFile(filePath, "utf-8");
65
- const out = [];
66
- const max = maxEvents !== undefined && maxEvents > 0 ? maxEvents : Infinity;
67
- for (const line of content.split(`
68
- `)) {
69
- if (out.length >= max)
70
- break;
71
- const trimmed = line.trim();
72
- if (!trimmed)
73
- continue;
74
- try {
75
- out.push(JSON.parse(trimmed));
76
- } catch {
77
- warn(`[knowledge-events] Skipping corrupted JSONL line in ${filePath}: ${trimmed.slice(0, 80)}`);
78
- }
79
- }
80
- return out;
81
- }
82
- async function readLegacyApplicationRecords(directory) {
83
- const filePath = resolveLegacyApplicationLogPath(directory);
84
- if (!existsSync(filePath))
85
- return [];
86
- const content = await readFile(filePath, "utf-8");
87
- const out = [];
88
- for (const line of content.split(`
89
- `)) {
90
- const trimmed = line.trim();
91
- if (!trimmed)
92
- continue;
93
- try {
94
- out.push(JSON.parse(trimmed));
95
- } catch {
96
- warn(`[knowledge-events] Skipping corrupted JSONL line in ${filePath}: ${trimmed.slice(0, 80)}`);
97
- }
98
- }
99
- return out;
100
- }
101
- var MAX_VIOLATION_TIMESTAMPS = 10;
102
- function emptyRollup() {
103
- return {
104
- shown_count: 0,
105
- acknowledged_count: 0,
106
- applied_explicit_count: 0,
107
- ignored_count: 0,
108
- violated_count: 0,
109
- contradicted_count: 0,
110
- n_a_count: 0,
111
- succeeded_after_shown_count: 0,
112
- failed_after_shown_count: 0,
113
- partial_after_shown_count: 0,
114
- violation_timestamps: []
115
- };
116
- }
117
- function cloneRollup(input) {
118
- return {
119
- ...emptyRollup(),
120
- ...input,
121
- violation_timestamps: [...input.violation_timestamps ?? []]
122
- };
123
- }
124
- function cloneRollupMap(input) {
125
- const out = new Map;
126
- for (const [id, rollup] of input) {
127
- out.set(id, cloneRollup(rollup));
128
- }
129
- return out;
130
- }
131
- function normalizeRollupTimestamps(rollup) {
132
- if (rollup.violation_timestamps.length > 1) {
133
- rollup.violation_timestamps.sort((a, b) => a < b ? 1 : a > b ? -1 : 0);
134
- }
135
- if (rollup.violation_timestamps.length > MAX_VIOLATION_TIMESTAMPS) {
136
- rollup.violation_timestamps = rollup.violation_timestamps.slice(0, MAX_VIOLATION_TIMESTAMPS);
137
- }
138
- return rollup;
139
- }
140
- function get(map, id) {
141
- let r = map.get(id);
142
- if (!r) {
143
- r = emptyRollup();
144
- map.set(id, r);
145
- }
146
- return r;
147
- }
148
- function maxIso(current, candidate) {
149
- if (!current)
150
- return candidate;
151
- return candidate > current ? candidate : current;
152
- }
153
- async function readCounterBaseline(directory) {
154
- const filePath = resolveKnowledgeCounterBaselinePath(directory);
155
- if (!existsSync(filePath))
156
- return new Map;
157
- let raw;
158
- try {
159
- raw = JSON.parse(await readFile(filePath, "utf-8"));
160
- } catch (err) {
161
- warn(`[knowledge-events] corrupted counter baseline at ${filePath}; ignoring folded baseline and replaying live events only: ${err instanceof Error ? err.message : String(err)}`);
162
- return new Map;
163
- }
164
- const map = new Map;
165
- for (const [id, rollup] of Object.entries(raw)) {
166
- map.set(id, normalizeRollupTimestamps(cloneRollup(rollup)));
167
- }
168
- return map;
169
- }
170
- async function statCacheKey(filePath) {
171
- try {
172
- const fileStat = await stat(filePath);
173
- return `${fileStat.mtimeMs}:${fileStat.ctimeMs}:${fileStat.size}`;
174
- } catch (err) {
175
- if (err?.code === "ENOENT")
176
- return "missing";
177
- throw err;
178
- }
179
- }
180
- async function buildCounterRollupCacheKey(directory) {
181
- const [eventsKey, legacyKey, baselineKey] = await Promise.all([
182
- statCacheKey(resolveKnowledgeEventsPath(directory)),
183
- statCacheKey(resolveLegacyApplicationLogPath(directory)),
184
- statCacheKey(resolveKnowledgeCounterBaselinePath(directory))
185
- ]);
186
- return `${eventsKey}|${legacyKey}|${baselineKey}`;
187
- }
188
- function setCounterRollupCache(directory, key, rollups) {
189
- if (counterRollupCache.has(directory)) {
190
- counterRollupCache.delete(directory);
191
- }
192
- counterRollupCache.set(directory, {
193
- key,
194
- rollups: cloneRollupMap(rollups)
195
- });
196
- while (counterRollupCache.size > MAX_COUNTER_ROLLUP_CACHE_DIRS) {
197
- const oldestKey = counterRollupCache.keys().next().value;
198
- if (oldestKey === undefined)
199
- break;
200
- counterRollupCache.delete(oldestKey);
201
- }
202
- }
203
- function recomputeCounters(events, legacyRecords = [], baseline = new Map) {
204
- const map = new Map;
205
- const retrievedIds = new Set;
206
- for (const [id, rollup] of baseline) {
207
- map.set(id, cloneRollup(rollup));
208
- if ((rollup.shown_count ?? 0) > 0)
209
- retrievedIds.add(id);
210
- }
211
- for (const e of events) {
212
- switch (e.type) {
213
- case "retrieved": {
214
- for (const id of e.result_ids) {
215
- retrievedIds.add(id);
216
- get(map, id).shown_count += 1;
217
- }
218
- break;
219
- }
220
- case "acknowledged": {
221
- const r = get(map, e.knowledge_id);
222
- r.acknowledged_count += 1;
223
- r.last_acknowledged_at = maxIso(r.last_acknowledged_at, e.timestamp);
224
- break;
225
- }
226
- case "applied": {
227
- const r = get(map, e.knowledge_id);
228
- r.applied_explicit_count += 1;
229
- r.last_applied_at = maxIso(r.last_applied_at, e.timestamp);
230
- break;
231
- }
232
- case "ignored":
233
- get(map, e.knowledge_id).ignored_count += 1;
234
- break;
235
- case "violated": {
236
- const r = get(map, e.knowledge_id);
237
- r.violated_count += 1;
238
- r.violation_timestamps.push(e.timestamp);
239
- break;
240
- }
241
- case "contradicted":
242
- get(map, e.knowledge_id).contradicted_count += 1;
243
- break;
244
- case "n_a":
245
- get(map, e.knowledge_id).n_a_count += 1;
246
- break;
247
- case "outcome": {
248
- if (!e.knowledge_id)
249
- break;
250
- const r = get(map, e.knowledge_id);
251
- if (e.outcome === "success")
252
- r.succeeded_after_shown_count += 1;
253
- else if (e.outcome === "failure")
254
- r.failed_after_shown_count += 1;
255
- else if (e.outcome === "partial")
256
- r.partial_after_shown_count += 1;
257
- break;
258
- }
259
- }
260
- }
261
- for (const rec of legacyRecords) {
262
- const r = get(map, rec.knowledgeId);
263
- switch (rec.result) {
264
- case "shown":
265
- if (!retrievedIds.has(rec.knowledgeId))
266
- r.shown_count += 1;
267
- break;
268
- case "acknowledged":
269
- r.acknowledged_count += 1;
270
- r.last_acknowledged_at = maxIso(r.last_acknowledged_at, rec.timestamp);
271
- break;
272
- case "applied":
273
- r.applied_explicit_count += 1;
274
- r.last_applied_at = maxIso(r.last_applied_at, rec.timestamp);
275
- break;
276
- case "ignored":
277
- r.ignored_count += 1;
278
- break;
279
- case "violated":
280
- r.violated_count += 1;
281
- r.violation_timestamps.push(rec.timestamp);
282
- break;
283
- }
284
- }
285
- for (const r of map.values()) {
286
- normalizeRollupTimestamps(r);
287
- }
288
- return map;
289
- }
290
- async function readKnowledgeCounterRollups(directory) {
291
- try {
292
- const cacheKey = await buildCounterRollupCacheKey(directory);
293
- const cached = counterRollupCache.get(directory);
294
- if (cached?.key === cacheKey) {
295
- counterRollupCache.delete(directory);
296
- counterRollupCache.set(directory, cached);
297
- return cloneRollupMap(cached.rollups);
298
- }
299
- const [events, legacyRecords, baseline] = await Promise.all([
300
- readKnowledgeEvents(directory),
301
- readLegacyApplicationRecords(directory),
302
- readCounterBaseline(directory)
303
- ]);
304
- const rollups = recomputeCounters(events, legacyRecords, baseline);
305
- setCounterRollupCache(directory, cacheKey, rollups);
306
- return cloneRollupMap(rollups);
307
- } catch (err) {
308
- warn(`[knowledge-events] readKnowledgeCounterRollups failed: ${err instanceof Error ? err.message : String(err)}`);
309
- return new Map;
310
- }
311
- }
312
- function effectiveRetrievalOutcomes(stored, rollup) {
313
- const base = stored ?? {
314
- applied_count: 0,
315
- succeeded_after_count: 0,
316
- failed_after_count: 0
317
- };
318
- if (!rollup)
319
- return base;
320
- const { n_a_count: _na, ...rollupWithoutNa } = rollup;
321
- return {
322
- ...base,
323
- ...rollupWithoutNa,
324
- succeeded_after_shown_count: (base.succeeded_after_shown_count ?? 0) + (rollup.succeeded_after_shown_count ?? 0),
325
- failed_after_shown_count: (base.failed_after_shown_count ?? 0) + (rollup.failed_after_shown_count ?? 0)
326
- };
327
- }
328
-
329
- // src/hooks/knowledge-validator.ts
330
- var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
331
- import { appendFile as appendFile2, mkdir as mkdir2 } from "fs/promises";
332
- import * as path2 from "path";
333
- init_logger();
334
- var DANGEROUS_COMMAND_ERROR_PATTERNS = [
335
- /\brm\s+-rf\b/,
336
- /\bsudo\s+rm\b/,
337
- /\bmkfs\b/,
338
- /\bdd\s+if=/,
339
- /:\(\)\s*\{/,
340
- /\bchmod\s+-R\s+777\b/i,
341
- /\bdeltree\b/,
342
- /\brmdir\s+\/s\b/
343
- ];
344
- var DANGEROUS_COMMAND_WARNING_PATTERNS = [
345
- /\bformat\b/,
346
- /\bkill\s+-9\b/,
347
- /\bpkill\b/,
348
- /\bkillall\b/,
349
- /`[^`]*`/,
350
- /\$\([^)]*\)/
351
- ];
352
- var DANGEROUS_COMMAND_PATTERNS = [
353
- ...DANGEROUS_COMMAND_ERROR_PATTERNS,
354
- ...DANGEROUS_COMMAND_WARNING_PATTERNS
355
- ];
356
- var SECURITY_DEGRADING_PATTERNS = [
357
- /disable\s+.{0,50}firewall/i,
358
- /turn\s+off\s+.{0,50}security/i,
359
- /skip\s+.{0,50}auth/i,
360
- /bypass\s+.{0,50}auth/i,
361
- /ignore\s+.{0,50}certificate/i,
362
- /disable\s+.{0,50}tls/i,
363
- /disable\s+.{0,50}ssl/i,
364
- /no\s+.{0,50}validation/i,
365
- /disable\s+.{0,50}2fa/i,
366
- /remove\s+.{0,50}password/i
367
- ];
368
- var INVISIBLE_FORMAT_CHARS = /[\u00AD\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g;
369
- var INJECTION_PATTERNS = [
370
- /[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/,
371
- /[\u00AD\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/,
372
- /^system\s*:/i,
373
- /<script/i,
374
- /javascript:/i,
375
- /\beval\(/i,
376
- /\b__proto__\b/,
377
- /\bconstructor\[/,
378
- /\.prototype\[/
379
- ];
380
- var VALID_CATEGORIES = new Set([
381
- "process",
382
- "architecture",
383
- "tooling",
384
- "security",
385
- "testing",
386
- "debugging",
387
- "performance",
388
- "integration",
389
- "todo",
390
- "other"
391
- ]);
392
- var TECH_REFERENCE_WORDS = new Set([
393
- "git",
394
- "docker",
395
- "typescript",
396
- "bun",
397
- "vitest",
398
- "node",
399
- "python",
400
- "react",
401
- "sql",
402
- "api",
403
- "hook",
404
- "test",
405
- "schema",
406
- "config",
407
- "file",
408
- "function",
409
- "class",
410
- "module",
411
- "import",
412
- "export"
413
- ]);
414
- var ACTION_VERB_WORDS = new Set([
415
- "use",
416
- "avoid",
417
- "prefer",
418
- "run",
419
- "check",
420
- "always",
421
- "never",
422
- "ensure",
423
- "call",
424
- "write",
425
- "add",
426
- "remove",
427
- "update",
428
- "set",
429
- "enable",
430
- "disable"
431
- ]);
432
- var NEGATION_PAIRS = [
433
- ["always", "never"],
434
- ["must", "must not"],
435
- ["must", "should not"],
436
- ["enable", "disable"],
437
- ["use", "avoid"],
438
- ["use", "don't use"],
439
- ["recommended", "not recommended"]
440
- ];
441
- function normalizeText(text) {
442
- return text.normalize("NFKC").toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
443
- }
444
- function extractContextWords(text, word, contextWindow = 3) {
445
- const words = text.split(" ");
446
- const context = new Set;
447
- if (!word.includes(" ")) {
448
- let from = 0;
449
- let idx = words.indexOf(word, from);
450
- while (idx !== -1) {
451
- const start = Math.max(0, idx - contextWindow);
452
- const end = Math.min(words.length, idx + contextWindow + 1);
453
- for (let i2 = start;i2 < end; i2++) {
454
- if (i2 !== idx && words[i2] && words[i2].length > 0) {
455
- context.add(words[i2]);
456
- }
457
- }
458
- from = idx + 1;
459
- idx = words.indexOf(word, from);
460
- }
461
- return context;
462
- }
463
- const termLen = word.split(" ").length;
464
- let i = 0;
465
- while (i <= words.length - termLen) {
466
- const slice = words.slice(i, i + termLen).join(" ");
467
- if (slice === word) {
468
- const start = Math.max(0, i - contextWindow);
469
- const end = Math.min(words.length, i + termLen + contextWindow);
470
- for (let j = start;j < end; j++) {
471
- if (j < i || j >= i + termLen) {
472
- if (words[j] && words[j].length > 0) {
473
- context.add(words[j]);
474
- }
475
- }
476
- }
477
- i += termLen;
478
- } else {
479
- i += 1;
480
- }
481
- }
482
- return context;
483
- }
484
- function hasSignificantOverlap(set1, set2) {
485
- if (set1.size === 0 || set2.size === 0)
486
- return false;
487
- return [...set1].some((word) => set2.has(word));
488
- }
489
- function detectContradiction(candidate, existingLessons) {
490
- const candidateTags = inferTags(candidate);
491
- if (candidateTags.length === 0)
492
- return false;
493
- const candidateNorm = normalizeText(candidate);
494
- for (const existing of existingLessons) {
495
- const existingTags = inferTags(existing);
496
- const shared = candidateTags.some((t) => existingTags.includes(t));
497
- if (!shared)
498
- continue;
499
- const existingNorm = normalizeText(existing);
500
- for (const [wordA, wordB] of NEGATION_PAIRS) {
501
- if (candidateNorm.includes(wordA) && existingNorm.includes(wordB)) {
502
- const contextA = extractContextWords(candidateNorm, wordA);
503
- const contextB = extractContextWords(existingNorm, wordB);
504
- if (hasSignificantOverlap(contextA, contextB)) {
505
- return true;
506
- }
507
- }
508
- if (candidateNorm.includes(wordB) && existingNorm.includes(wordA)) {
509
- const contextB = extractContextWords(candidateNorm, wordB);
510
- const contextA = extractContextWords(existingNorm, wordA);
511
- if (hasSignificantOverlap(contextA, contextB)) {
512
- return true;
513
- }
514
- }
515
- }
516
- }
517
- return false;
518
- }
519
- function isVagueLesson(lesson) {
520
- const lower = normalizeText(lesson);
521
- const words = lower.split(/\s+/);
522
- const hasTechRef = words.some((w) => TECH_REFERENCE_WORDS.has(w));
523
- const hasActionVerb = words.some((w) => ACTION_VERB_WORDS.has(w));
524
- return !hasTechRef && !hasActionVerb;
525
- }
526
- function validateLesson(candidate, existingLessons, meta) {
527
- if (!candidate || typeof candidate !== "string") {
528
- return {
529
- valid: false,
530
- layer: 1,
531
- reason: "lesson too short (min 15 chars)",
532
- severity: "error"
533
- };
534
- }
535
- if (!Array.isArray(existingLessons)) {
536
- existingLessons = [];
537
- }
538
- if (candidate.length < 15) {
539
- return {
540
- valid: false,
541
- layer: 1,
542
- reason: "lesson too short (min 15 chars)",
543
- severity: "error"
544
- };
545
- }
546
- if (candidate.length > 280) {
547
- return {
548
- valid: false,
549
- layer: 1,
550
- reason: "lesson too long (max 280 chars)",
551
- severity: "error"
552
- };
553
- }
554
- if (!VALID_CATEGORIES.has(meta.category)) {
555
- return {
556
- valid: false,
557
- layer: 1,
558
- reason: `invalid category: ${meta.category}`,
559
- severity: "error"
560
- };
561
- }
562
- const isGlobalScope = meta.scope === "global";
563
- const isStackScope = /^stack:[a-zA-Z0-9_-]{1,64}$/.test(meta.scope);
564
- if (!isGlobalScope && !isStackScope) {
565
- return {
566
- valid: false,
567
- layer: 1,
568
- reason: "invalid scope: must be 'global' or 'stack:<name>'",
569
- severity: "error"
570
- };
571
- }
572
- if (!(meta.confidence >= 0 && meta.confidence <= 1)) {
573
- return {
574
- valid: false,
575
- layer: 1,
576
- reason: "confidence out of range [0.0, 1.0]",
577
- severity: "error"
578
- };
579
- }
580
- const normalizedCandidate = candidate.normalize("NFKC").replace(INVISIBLE_FORMAT_CHARS, " ").replace(/\s+/g, " ").toLowerCase();
581
- for (const pattern of DANGEROUS_COMMAND_ERROR_PATTERNS) {
582
- if (pattern.test(normalizedCandidate)) {
583
- return {
584
- valid: false,
585
- layer: 2,
586
- reason: "dangerous command pattern detected",
587
- severity: "error"
588
- };
589
- }
590
- }
591
- for (const pattern of DANGEROUS_COMMAND_WARNING_PATTERNS) {
592
- if (pattern.test(normalizedCandidate)) {
593
- return {
594
- valid: true,
595
- layer: 2,
596
- reason: "potentially dangerous command pattern queued for review",
597
- severity: "warning"
598
- };
599
- }
600
- }
601
- for (const pattern of SECURITY_DEGRADING_PATTERNS) {
602
- if (pattern.test(normalizedCandidate)) {
603
- return {
604
- valid: false,
605
- layer: 2,
606
- reason: "security-degrading instruction detected",
607
- severity: "error"
608
- };
609
- }
610
- }
611
- for (const pattern of INJECTION_PATTERNS) {
612
- if (pattern.test(candidate)) {
613
- return {
614
- valid: false,
615
- layer: 2,
616
- reason: "injection pattern detected",
617
- severity: "error"
618
- };
619
- }
620
- }
621
- if (detectContradiction(candidate, existingLessons)) {
622
- return {
623
- valid: true,
624
- layer: 3,
625
- reason: "possible contradiction with an existing lesson with shared tags",
626
- severity: "warning"
627
- };
628
- }
629
- if (isVagueLesson(candidate)) {
630
- return {
631
- valid: true,
632
- layer: 3,
633
- reason: "lesson may be too vague (no tech reference or action verb)",
634
- severity: "warning"
635
- };
636
- }
637
- return {
638
- valid: true,
639
- layer: null,
640
- reason: null,
641
- severity: null
642
- };
643
- }
644
- var ACTIONABLE_STRING_MAX = 200;
645
- var ACTIONABLE_LIST_MAX = 20;
646
- var NAME_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
647
- var SOURCE_REF_FORBIDDEN = /(\.\.\/|\.\.\\|\0|[\x00-\x1f\x7f])/;
648
- var ALLOWED_SKILL_PATH_PREFIXES = [
649
- ".opencode/skills/generated/",
650
- ".swarm/skills/proposals/",
651
- ".swarm/skills/candidates/"
652
- ];
653
- var VALID_DIRECTIVE_PRIORITIES = new Set([
654
- "low",
655
- "medium",
656
- "high",
657
- "critical"
658
- ]);
659
- function isCleanShortString(s) {
660
- if (typeof s !== "string")
661
- return false;
662
- if (s.length === 0 || s.length > ACTIONABLE_STRING_MAX)
663
- return false;
664
- return !/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]/.test(s);
665
- }
666
- function validateSkillPath(p) {
667
- if (typeof p !== "string")
668
- return false;
669
- if (p.length === 0 || p.length > 256)
670
- return false;
671
- if (p.includes("\x00"))
672
- return false;
673
- if (path2.isAbsolute(p))
674
- return false;
675
- if (p.includes(".."))
676
- return false;
677
- const norm = p.replace(/\\/g, "/");
678
- return ALLOWED_SKILL_PATH_PREFIXES.some((prefix) => norm.startsWith(prefix));
679
- }
680
- function validateActionableFields(fields) {
681
- const errors = [];
682
- if (!fields)
683
- return { valid: true, errors };
684
- function checkStringList(name, list) {
685
- if (list === undefined)
686
- return;
687
- if (!Array.isArray(list)) {
688
- errors.push(`${name} must be an array`);
689
- return;
690
- }
691
- if (list.length > ACTIONABLE_LIST_MAX) {
692
- errors.push(`${name} exceeds ${ACTIONABLE_LIST_MAX} items`);
693
- }
694
- for (const item of list) {
695
- if (!isCleanShortString(item)) {
696
- errors.push(`${name} contains invalid string`);
697
- return;
698
- }
699
- }
700
- }
701
- function checkNameList(name, list) {
702
- if (list === undefined)
703
- return;
704
- if (!Array.isArray(list)) {
705
- errors.push(`${name} must be an array`);
706
- return;
707
- }
708
- if (list.length > ACTIONABLE_LIST_MAX) {
709
- errors.push(`${name} exceeds ${ACTIONABLE_LIST_MAX} items`);
710
- }
711
- for (const item of list) {
712
- if (typeof item !== "string" || !NAME_PATTERN.test(item)) {
713
- errors.push(`${name} contains invalid name`);
714
- return;
715
- }
716
- }
717
- }
718
- checkStringList("triggers", fields.triggers);
719
- checkStringList("required_actions", fields.required_actions);
720
- checkStringList("forbidden_actions", fields.forbidden_actions);
721
- checkStringList("verification_checks", fields.verification_checks);
722
- checkNameList("applies_to_agents", fields.applies_to_agents);
723
- checkNameList("applies_to_tools", fields.applies_to_tools);
724
- if (fields.source_refs !== undefined) {
725
- if (!Array.isArray(fields.source_refs)) {
726
- errors.push("source_refs must be an array");
727
- } else if (fields.source_refs.length > ACTIONABLE_LIST_MAX) {
728
- errors.push(`source_refs exceeds ${ACTIONABLE_LIST_MAX} items`);
729
- } else {
730
- for (const ref of fields.source_refs) {
731
- if (typeof ref !== "string" || ref.length === 0 || ref.length > ACTIONABLE_STRING_MAX || SOURCE_REF_FORBIDDEN.test(ref)) {
732
- errors.push("source_refs contains invalid value");
733
- break;
734
- }
735
- }
736
- }
737
- }
738
- if (fields.source_knowledge_ids !== undefined) {
739
- if (!Array.isArray(fields.source_knowledge_ids)) {
740
- errors.push("source_knowledge_ids must be an array");
741
- } else {
742
- for (const id of fields.source_knowledge_ids) {
743
- if (typeof id !== "string" || id.length === 0 || id.length > 64) {
744
- errors.push("source_knowledge_ids contains invalid value");
745
- break;
746
- }
747
- }
748
- }
749
- }
750
- if (fields.directive_priority !== undefined && !VALID_DIRECTIVE_PRIORITIES.has(String(fields.directive_priority))) {
751
- errors.push("directive_priority must be low|medium|high|critical");
752
- }
753
- if (fields.generated_skill_slug !== undefined) {
754
- if (typeof fields.generated_skill_slug !== "string" || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(fields.generated_skill_slug)) {
755
- errors.push("generated_skill_slug must be a kebab-case slug");
756
- }
757
- }
758
- if (fields.generated_skill_path !== undefined && !validateSkillPath(fields.generated_skill_path)) {
759
- errors.push("generated_skill_path must be repo-local under allowed prefix");
760
- }
761
- return { valid: errors.length === 0, errors };
762
- }
763
- function hasNonEmptyList(v) {
764
- return Array.isArray(v) && v.length > 0;
765
- }
766
- function validateActionability(entry) {
767
- const hasPredicate = hasNonEmptyList(entry.forbidden_actions) || hasNonEmptyList(entry.required_actions) || hasNonEmptyList(entry.verification_checks) || typeof entry.verification_predicate === "string" && entry.verification_predicate.trim().length > 0;
768
- const hasScope = hasNonEmptyList(entry.applies_to_tools) || hasNonEmptyList(entry.applies_to_agents);
769
- if (hasPredicate && hasScope)
770
- return { actionable: true };
771
- const reason = !hasPredicate && !hasScope ? "missing_predicate_and_scope" : !hasPredicate ? "missing_predicate" : "missing_scope";
772
- return { actionable: false, reason };
773
- }
774
- function resolveUnactionablePath(directory) {
775
- return path2.join(resolveKnowledgeStoreDir(directory), "knowledge-unactionable.jsonl");
776
- }
777
- async function appendUnactionable(directory, entry, reason) {
778
- const filePath = resolveUnactionablePath(directory);
779
- const dirPath = path2.dirname(filePath);
780
- await mkdir2(dirPath, { recursive: true });
781
- await transactKnowledge(filePath, (existing) => {
782
- const record = {
783
- ...entry,
784
- status: "quarantined_unactionable",
785
- unactionable_reason: reason,
786
- quarantined_at: new Date().toISOString()
787
- };
788
- const duplicate = findNearDuplicate(record.lesson, existing, 0.6);
789
- if (duplicate?.unactionable_reason === reason) {
790
- duplicate.quarantined_at = record.quarantined_at;
791
- duplicate.updated_at = record.updated_at;
792
- return existing;
793
- }
794
- const next = [...existing, record];
795
- return next.length > 200 ? next.slice(-200) : next;
796
- });
797
- }
798
- async function quarantineEntry(directory, entryId, reason, reportedBy) {
799
- if (!directory || directory.includes("..")) {
800
- warn("[knowledge-validator] quarantineEntry: directory traversal attempt blocked");
801
- return;
802
- }
803
- if (!entryId || entryId.includes("\x00") || entryId.includes(`
804
- `)) {
805
- warn("[knowledge-validator] quarantineEntry: invalid entryId rejected");
806
- return;
807
- }
808
- const validReportedBy = ["architect", "user", "auto"];
809
- if (!validReportedBy.includes(reportedBy)) {
810
- return;
811
- }
812
- const sanitizedReason = reason.slice(0, 500).replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/g, "");
813
- const knowledgePath = resolveSwarmKnowledgePath(directory);
814
- const quarantinePath = path2.join(resolveKnowledgeStoreDir(directory), "knowledge-quarantined.jsonl");
815
- const rejectedPath = resolveSwarmRejectedPath(directory);
816
- const swarmDir = resolveKnowledgeStoreDir(directory);
817
- await mkdir2(swarmDir, { recursive: true });
818
- let release;
819
- try {
820
- release = await import_proper_lockfile2.default.lock(swarmDir, {
821
- retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
822
- stale: 5000
823
- });
824
- const entries = await readKnowledge(knowledgePath);
825
- const entry = entries.find((e) => e.id === entryId);
826
- if (!entry) {
827
- return;
828
- }
829
- const remaining = entries.filter((e) => e.id !== entryId);
830
- const quarantined = {
831
- ...entry,
832
- status: "quarantined",
833
- original_status: entry.status,
834
- quarantine_reason: sanitizedReason,
835
- quarantined_at: new Date().toISOString(),
836
- reported_by: reportedBy
837
- };
838
- const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
839
- `)}
840
- ` : "";
841
- await atomicWriteFile(knowledgePath, jsonlContent);
842
- await appendFile2(quarantinePath, `${JSON.stringify(quarantined)}
843
- `, "utf-8");
844
- const quarantinedEntries = await readKnowledge(quarantinePath);
845
- if (quarantinedEntries.length > 100) {
846
- const trimmed = quarantinedEntries.slice(-100);
847
- const capContent = trimmed.length > 0 ? `${trimmed.map((e) => JSON.stringify(e)).join(`
848
- `)}
849
- ` : "";
850
- await atomicWriteFile(quarantinePath, capContent);
851
- }
852
- const rejectedRecord = {
853
- id: entryId,
854
- lesson: entry.lesson,
855
- rejection_reason: sanitizedReason,
856
- rejected_at: new Date().toISOString(),
857
- rejection_layer: 3
858
- };
859
- await appendFile2(rejectedPath, `${JSON.stringify(rejectedRecord)}
860
- `, "utf-8");
861
- } finally {
862
- if (release) {
863
- await release();
864
- }
865
- }
866
- }
867
- async function restoreEntry(directory, entryId) {
868
- if (!directory || directory.includes("..")) {
869
- warn("[knowledge-validator] restoreEntry: directory traversal attempt blocked");
870
- return;
871
- }
872
- if (!entryId || entryId.includes("\x00") || entryId.includes(`
873
- `)) {
874
- warn("[knowledge-validator] restoreEntry: invalid entryId rejected");
875
- return;
876
- }
877
- const storeDir = resolveKnowledgeStoreDir(directory);
878
- const knowledgePath = resolveSwarmKnowledgePath(directory);
879
- const quarantinePath = path2.join(storeDir, "knowledge-quarantined.jsonl");
880
- const rejectedPath = resolveSwarmRejectedPath(directory);
881
- const swarmDir = storeDir;
882
- await mkdir2(swarmDir, { recursive: true });
883
- let release;
884
- try {
885
- release = await import_proper_lockfile2.default.lock(swarmDir, {
886
- retries: { retries: 5, minTimeout: 100, maxTimeout: 500 },
887
- stale: 5000
888
- });
889
- const quarantinedEntries = await readKnowledge(quarantinePath);
890
- const entryToRestore = quarantinedEntries.find((e) => e.id === entryId);
891
- if (!entryToRestore) {
892
- return;
893
- }
894
- const remaining = quarantinedEntries.filter((e) => e.id !== entryId);
895
- const {
896
- quarantine_reason,
897
- quarantined_at,
898
- reported_by,
899
- original_status,
900
- status: _quarantineStatus,
901
- ...rest
902
- } = entryToRestore;
903
- const original = { ...rest, status: original_status ?? "candidate" };
904
- const validation = validateLesson(original.lesson, [], {
905
- category: original.category,
906
- scope: original.scope,
907
- confidence: original.confidence
908
- });
909
- if (!validation.valid) {
910
- warn(`[knowledge-validator] restoreEntry: entry ${entryId} failed re-validation: ${validation.reason}`);
911
- return;
912
- }
913
- const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
914
- `)}
915
- ` : "";
916
- await atomicWriteFile(quarantinePath, jsonlContent);
917
- await appendFile2(knowledgePath, `${JSON.stringify(original)}
918
- `, "utf-8");
919
- const rejectedEntries = await readKnowledge(rejectedPath);
920
- const filtered = rejectedEntries.filter((e) => e.id !== entryId);
921
- const rejectedContent = filtered.length > 0 ? `${filtered.map((e) => JSON.stringify(e)).join(`
922
- `)}
923
- ` : "";
924
- await atomicWriteFile(rejectedPath, rejectedContent);
925
- } finally {
926
- if (release) {
927
- await release();
928
- }
929
- }
930
- }
931
-
932
- // src/services/skill-generator.ts
26
+ import { existsSync as existsSync2, unlinkSync } from "fs";
27
+ import { mkdir as mkdir3, readFile as readFile3, rename as rename2, unlink, writeFile as writeFile3 } from "fs/promises";
28
+ import * as path3 from "path";
933
29
  init_logger();
934
30
 
935
31
  // src/services/skill-changelog.ts
936
32
  init_logger();
937
- import { appendFile as appendFile3, mkdir as mkdir3, readFile as readFile2, writeFile } from "fs/promises";
938
- import * as path3 from "path";
33
+ import { appendFile, mkdir, readFile, writeFile } from "fs/promises";
34
+ import * as path from "path";
939
35
  var MAX_CHANGELOG_ENTRIES_PER_SKILL = 200;
940
36
  function resolveSkillChangelogPath(directory, slug) {
941
37
  if (slug.includes("..") || slug.includes("/") || slug.includes("\\")) {
942
38
  throw new Error(`Invalid skill slug: ${slug} \u2014 must not contain "..", "/" or "\\"`);
943
39
  }
944
- return path3.join(directory, ".swarm", "skill-changelogs", `${slug}.jsonl`);
40
+ return path.join(directory, ".swarm", "skill-changelogs", `${slug}.jsonl`);
945
41
  }
946
42
  async function appendSkillChangelog(directory, slug, entry) {
947
43
  const filePath = resolveSkillChangelogPath(directory, slug);
948
- const dirPath = path3.dirname(filePath);
949
- await mkdir3(dirPath, { recursive: true });
950
- await appendFile3(filePath, `${JSON.stringify(entry)}
44
+ const dirPath = path.dirname(filePath);
45
+ await mkdir(dirPath, { recursive: true });
46
+ await appendFile(filePath, `${JSON.stringify(entry)}
951
47
  `, "utf-8");
952
48
  try {
953
- const content = await readFile2(filePath, "utf-8");
49
+ const content = await readFile(filePath, "utf-8");
954
50
  const lines = content.split(`
955
51
  `).filter((line) => line.trim().length > 0);
956
52
  if (lines.length > MAX_CHANGELOG_ENTRIES_PER_SKILL) {
@@ -966,18 +62,18 @@ async function appendSkillChangelog(directory, slug, entry) {
966
62
 
967
63
  // src/services/skill-evaluator.ts
968
64
  import { createHash } from "crypto";
969
- import { existsSync as existsSync2 } from "fs";
65
+ import { existsSync } from "fs";
970
66
  import {
971
67
  lstat,
972
- mkdir as mkdir4,
68
+ mkdir as mkdir2,
973
69
  readdir,
974
- readFile as readFile3,
70
+ readFile as readFile2,
975
71
  realpath,
976
72
  rename,
977
- stat as stat2,
73
+ stat,
978
74
  writeFile as writeFile2
979
75
  } from "fs/promises";
980
- import * as path4 from "path";
76
+ import * as path2 from "path";
981
77
  var SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
982
78
  var MAX_EVAL_FILES = 50;
983
79
  var MAX_EVAL_FILE_BYTES = 64 * 1024;
@@ -1043,15 +139,15 @@ function casesFromParsedJson(parsed, fileLabel) {
1043
139
  return cases;
1044
140
  }
1045
141
  function evalRoot(directory, slug) {
1046
- return path4.join(directory, ".swarm", "skills", "evals", slug);
142
+ return path2.join(directory, ".swarm", "skills", "evals", slug);
1047
143
  }
1048
144
  function isInsidePath(root, target) {
1049
- const resolvedRoot = path4.resolve(root);
1050
- const resolvedTarget = path4.resolve(target);
1051
- return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path4.sep);
145
+ const resolvedRoot = path2.resolve(root);
146
+ const resolvedTarget = path2.resolve(target);
147
+ return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path2.sep);
1052
148
  }
1053
149
  function rejectedEditsPath(directory) {
1054
- return path4.join(directory, ".swarm", "skills", "rejected-edits.jsonl");
150
+ return path2.join(directory, ".swarm", "skills", "rejected-edits.jsonl");
1055
151
  }
1056
152
  async function loadEvalSet(directory, slug) {
1057
153
  if (!isValidSlug(slug)) {
@@ -1063,7 +159,7 @@ async function loadEvalSet(directory, slug) {
1063
159
  };
1064
160
  }
1065
161
  const root = evalRoot(directory, slug);
1066
- if (!existsSync2(root)) {
162
+ if (!existsSync(root)) {
1067
163
  return { status: "missing", files: [], cases: [] };
1068
164
  }
1069
165
  let realRoot;
@@ -1104,9 +200,9 @@ async function loadEvalSet(directory, slug) {
1104
200
  const cases = [];
1105
201
  const fileLabels = [];
1106
202
  for (const file of files) {
1107
- const fullPath = path4.join(root, file);
1108
- const resolved = path4.resolve(fullPath);
1109
- const resolvedRoot = path4.resolve(root);
203
+ const fullPath = path2.join(root, file);
204
+ const resolved = path2.resolve(fullPath);
205
+ const resolvedRoot = path2.resolve(root);
1110
206
  if (!isInsidePath(resolvedRoot, resolved)) {
1111
207
  return {
1112
208
  status: "invalid",
@@ -1130,7 +226,7 @@ async function loadEvalSet(directory, slug) {
1130
226
  };
1131
227
  }
1132
228
  readPath = realFile;
1133
- info = await stat2(realFile);
229
+ info = await stat(realFile);
1134
230
  } else {
1135
231
  if (!linkInfo.isFile())
1136
232
  continue;
@@ -1156,7 +252,7 @@ async function loadEvalSet(directory, slug) {
1156
252
  }
1157
253
  let parsed;
1158
254
  try {
1159
- parsed = JSON.parse(await readFile3(readPath, "utf-8"));
255
+ parsed = JSON.parse(await readFile2(readPath, "utf-8"));
1160
256
  } catch (err) {
1161
257
  return {
1162
258
  status: "invalid",
@@ -1165,7 +261,7 @@ async function loadEvalSet(directory, slug) {
1165
261
  reason: `eval file invalid JSON: ${file}: ${err instanceof Error ? err.message : String(err)}`
1166
262
  };
1167
263
  }
1168
- fileLabels.push(path4.relative(directory, fullPath).replace(/\\/g, "/"));
264
+ fileLabels.push(path2.relative(directory, fullPath).replace(/\\/g, "/"));
1169
265
  cases.push(...casesFromParsedJson(parsed, file));
1170
266
  if (cases.length >= MAX_EVAL_CASES)
1171
267
  break;
@@ -1283,7 +379,7 @@ async function evaluateSkillChange(req) {
1283
379
  };
1284
380
  }
1285
381
  async function atomicWrite(filePath, content) {
1286
- await mkdir4(path4.dirname(filePath), { recursive: true });
382
+ await mkdir2(path2.dirname(filePath), { recursive: true });
1287
383
  const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
1288
384
  await writeFile2(tmp, content, "utf-8");
1289
385
  await rename(tmp, filePath);
@@ -1306,7 +402,7 @@ async function appendRejectedSkillEdit(req, evaluation) {
1306
402
  };
1307
403
  let prior = [];
1308
404
  try {
1309
- prior = (await readFile3(filePath, "utf-8")).split(/\r?\n/).filter((line) => line.trim().length > 0);
405
+ prior = (await readFile2(filePath, "utf-8")).split(/\r?\n/).filter((line) => line.trim().length > 0);
1310
406
  } catch {
1311
407
  prior = [];
1312
408
  }
@@ -1323,7 +419,7 @@ async function isRejectedSkillContent(directory, slug, content) {
1323
419
  const normalizedHash = hashNormalizedContent(content);
1324
420
  let raw = "";
1325
421
  try {
1326
- raw = await readFile3(rejectedEditsPath(directory), "utf-8");
422
+ raw = await readFile2(rejectedEditsPath(directory), "utf-8");
1327
423
  } catch {
1328
424
  return false;
1329
425
  }
@@ -1360,10 +456,10 @@ function isValidSlug2(slug) {
1360
456
  return SLUG_PATTERN2.test(slug);
1361
457
  }
1362
458
  function proposalPath(directory, slug) {
1363
- return path5.join(directory, ".swarm", "skills", "proposals", `${slug}.md`);
459
+ return path3.join(directory, ".swarm", "skills", "proposals", `${slug}.md`);
1364
460
  }
1365
461
  function activePath(directory, slug) {
1366
- return path5.join(directory, ".opencode", "skills", "generated", slug, "SKILL.md");
462
+ return path3.join(directory, ".opencode", "skills", "generated", slug, "SKILL.md");
1367
463
  }
1368
464
  function activeRepoRelativePath(slug) {
1369
465
  return `.opencode/skills/generated/${slug}/SKILL.md`;
@@ -1375,7 +471,7 @@ var HIGH_PRIORITY_SKILL_MIN_CONFIDENCE = 0.6;
1375
471
  async function selectCandidateEntries(directory, opts) {
1376
472
  const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
1377
473
  const hivePath = resolveHiveKnowledgePath();
1378
- const hive = existsSync3(hivePath) ? await readKnowledge(hivePath) : [];
474
+ const hive = existsSync2(hivePath) ? await readKnowledge(hivePath) : [];
1379
475
  const all = [...swarm, ...hive];
1380
476
  const counterRollups = await readKnowledgeCounterRollups(directory);
1381
477
  const selected = [];
@@ -1588,7 +684,7 @@ function escapeMarkdown(s) {
1588
684
  return s.replace(/[\r\n]+/g, " ").slice(0, 280);
1589
685
  }
1590
686
  async function atomicWrite2(p, content) {
1591
- await mkdir5(path5.dirname(p), { recursive: true });
687
+ await mkdir3(path3.dirname(p), { recursive: true });
1592
688
  const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
1593
689
  await writeFile3(tmp, content, "utf-8");
1594
690
  await rename2(tmp, p);
@@ -1605,7 +701,7 @@ async function generateSkills(req) {
1605
701
  const idSet = new Set(req.sourceKnowledgeIds);
1606
702
  const swarm = await readKnowledge(resolveSwarmKnowledgePath(req.directory));
1607
703
  const hivePath = resolveHiveKnowledgePath();
1608
- const hive = existsSync3(hivePath) ? await readKnowledge(hivePath) : [];
704
+ const hive = existsSync2(hivePath) ? await readKnowledge(hivePath) : [];
1609
705
  const rollups = await readKnowledgeCounterRollups(req.directory);
1610
706
  pool = [...swarm, ...hive].filter((e) => idSet.has(e.id) && e.status !== "archived").map((e) => ({
1611
707
  ...e,
@@ -1637,7 +733,7 @@ async function generateSkills(req) {
1637
733
  continue;
1638
734
  }
1639
735
  const targetPath = req.mode === "active" ? activePath(req.directory, cluster.slug) : proposalPath(req.directory, cluster.slug);
1640
- const repoRel = path5.relative(req.directory, targetPath).replace(/\\/g, "/");
736
+ const repoRel = path3.relative(req.directory, targetPath).replace(/\\/g, "/");
1641
737
  if (!validateSkillPath(repoRel)) {
1642
738
  result.skipped.push({
1643
739
  slug: cluster.slug,
@@ -1646,8 +742,8 @@ async function generateSkills(req) {
1646
742
  continue;
1647
743
  }
1648
744
  let preserved = false;
1649
- if (req.mode === "active" && existsSync3(targetPath) && !req.force) {
1650
- const existing = await readFile4(targetPath, "utf-8");
745
+ if (req.mode === "active" && existsSync2(targetPath) && !req.force) {
746
+ const existing = await readFile3(targetPath, "utf-8");
1651
747
  if (!existing.includes("generated by opencode-swarm skill-generator")) {
1652
748
  preserved = true;
1653
749
  result.skipped.push({
@@ -1669,9 +765,9 @@ async function generateSkills(req) {
1669
765
  if (req.evaluate) {
1670
766
  let incumbentContent;
1671
767
  const existingActivePath = activePath(req.directory, cluster.slug);
1672
- if (existsSync3(existingActivePath)) {
768
+ if (existsSync2(existingActivePath)) {
1673
769
  try {
1674
- incumbentContent = await readFile4(existingActivePath, "utf-8");
770
+ incumbentContent = await readFile3(existingActivePath, "utf-8");
1675
771
  } catch {
1676
772
  incumbentContent = undefined;
1677
773
  }
@@ -1791,7 +887,7 @@ async function stampSourceEntries(directory, slug, ids) {
1791
887
  await rewriteKnowledge(swarmPath, swarm);
1792
888
  stamped.push(...found);
1793
889
  const hivePath = resolveHiveKnowledgePath();
1794
- if (!existsSync3(hivePath)) {
890
+ if (!existsSync2(hivePath)) {
1795
891
  for (const id of ids) {
1796
892
  if (!found.has(id))
1797
893
  missing.push(id);
@@ -1936,7 +1032,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1936
1032
  }
1937
1033
  const from = proposalPath(directory, cleanSlug);
1938
1034
  const to = activePath(directory, cleanSlug);
1939
- if (!existsSync3(from)) {
1035
+ if (!existsSync2(from)) {
1940
1036
  return {
1941
1037
  activated: false,
1942
1038
  from,
@@ -1944,8 +1040,8 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1944
1040
  reason: `proposal not found: ${from}`
1945
1041
  };
1946
1042
  }
1947
- if (existsSync3(to) && !force) {
1948
- const existing = await readFile4(to, "utf-8");
1043
+ if (existsSync2(to) && !force) {
1044
+ const existing = await readFile3(to, "utf-8");
1949
1045
  if (!existing.includes("generated by opencode-swarm skill-generator")) {
1950
1046
  return {
1951
1047
  activated: false,
@@ -1957,7 +1053,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1957
1053
  }
1958
1054
  let proposalContent;
1959
1055
  try {
1960
- proposalContent = await readFile4(from, "utf-8");
1056
+ proposalContent = await readFile3(from, "utf-8");
1961
1057
  } catch (readErr) {
1962
1058
  return {
1963
1059
  activated: false,
@@ -1978,9 +1074,9 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1978
1074
  let evaluation;
1979
1075
  if (options.evaluate) {
1980
1076
  let incumbentContent;
1981
- if (existsSync3(to)) {
1077
+ if (existsSync2(to)) {
1982
1078
  try {
1983
- incumbentContent = await readFile4(to, "utf-8");
1079
+ incumbentContent = await readFile3(to, "utf-8");
1984
1080
  } catch {
1985
1081
  incumbentContent = undefined;
1986
1082
  }
@@ -2046,24 +1142,24 @@ async function activateProposal(directory, slug, force = false, options = {}) {
2046
1142
  }
2047
1143
  }
2048
1144
  async function findSkillsBySourceKnowledgeId(directory, sourceId) {
2049
- const activeDir = path5.join(directory, ".opencode", "skills", "generated");
1145
+ const activeDir = path3.join(directory, ".opencode", "skills", "generated");
2050
1146
  const fs = await import("fs/promises");
2051
- if (!existsSync3(activeDir))
1147
+ if (!existsSync2(activeDir))
2052
1148
  return [];
2053
1149
  const entries = await fs.readdir(activeDir, { withFileTypes: true });
2054
1150
  const matches = [];
2055
1151
  for (const e of entries) {
2056
1152
  if (!e.isDirectory())
2057
1153
  continue;
2058
- const skillDir = path5.join(activeDir, e.name);
2059
- const retiredMarker = path5.join(skillDir, "retired.marker");
2060
- if (existsSync3(retiredMarker))
1154
+ const skillDir = path3.join(activeDir, e.name);
1155
+ const retiredMarker = path3.join(skillDir, "retired.marker");
1156
+ if (existsSync2(retiredMarker))
2061
1157
  continue;
2062
- const staleMarker = path5.join(skillDir, "stale.marker");
2063
- if (existsSync3(staleMarker))
1158
+ const staleMarker = path3.join(skillDir, "stale.marker");
1159
+ if (existsSync2(staleMarker))
2064
1160
  continue;
2065
- const skillPath = path5.join(skillDir, "SKILL.md");
2066
- if (!existsSync3(skillPath))
1161
+ const skillPath = path3.join(skillDir, "SKILL.md");
1162
+ if (!existsSync2(skillPath))
2067
1163
  continue;
2068
1164
  let content;
2069
1165
  try {
@@ -2079,8 +1175,8 @@ async function findSkillsBySourceKnowledgeId(directory, sourceId) {
2079
1175
  return matches;
2080
1176
  }
2081
1177
  async function findStaleSkillsBySourceKnowledgeId(directory, archivedIds) {
2082
- const activeDir = path5.join(directory, ".opencode", "skills", "generated");
2083
- if (!existsSync3(activeDir))
1178
+ const activeDir = path3.join(directory, ".opencode", "skills", "generated");
1179
+ if (!existsSync2(activeDir))
2084
1180
  return [];
2085
1181
  const fs = await import("fs/promises");
2086
1182
  const entries = await fs.readdir(activeDir, { withFileTypes: true });
@@ -2088,15 +1184,15 @@ async function findStaleSkillsBySourceKnowledgeId(directory, archivedIds) {
2088
1184
  for (const e of entries) {
2089
1185
  if (!e.isDirectory())
2090
1186
  continue;
2091
- const skillDir = path5.join(activeDir, e.name);
2092
- const retiredMarker = path5.join(skillDir, "retired.marker");
2093
- if (existsSync3(retiredMarker))
1187
+ const skillDir = path3.join(activeDir, e.name);
1188
+ const retiredMarker = path3.join(skillDir, "retired.marker");
1189
+ if (existsSync2(retiredMarker))
2094
1190
  continue;
2095
- const staleMarker = path5.join(skillDir, "stale.marker");
2096
- if (!existsSync3(staleMarker))
1191
+ const staleMarker = path3.join(skillDir, "stale.marker");
1192
+ if (!existsSync2(staleMarker))
2097
1193
  continue;
2098
- const skillPath = path5.join(skillDir, "SKILL.md");
2099
- if (!existsSync3(skillPath))
1194
+ const skillPath = path3.join(skillDir, "SKILL.md");
1195
+ if (!existsSync2(skillPath))
2100
1196
  continue;
2101
1197
  let content;
2102
1198
  try {
@@ -2121,10 +1217,10 @@ async function listSkills(directory) {
2121
1217
  active: [],
2122
1218
  stale: []
2123
1219
  };
2124
- const proposalsDir = path5.join(directory, ".swarm", "skills", "proposals");
2125
- const activeDir = path5.join(directory, ".opencode", "skills", "generated");
1220
+ const proposalsDir = path3.join(directory, ".swarm", "skills", "proposals");
1221
+ const activeDir = path3.join(directory, ".opencode", "skills", "generated");
2126
1222
  const fs = await import("fs/promises");
2127
- if (existsSync3(proposalsDir)) {
1223
+ if (existsSync2(proposalsDir)) {
2128
1224
  const entries = await fs.readdir(proposalsDir);
2129
1225
  for (const f of entries) {
2130
1226
  if (!f.endsWith(".md"))
@@ -2132,20 +1228,20 @@ async function listSkills(directory) {
2132
1228
  const slug = f.replace(/\.md$/, "");
2133
1229
  result.proposals.push({
2134
1230
  slug,
2135
- path: path5.join(proposalsDir, f)
1231
+ path: path3.join(proposalsDir, f)
2136
1232
  });
2137
1233
  }
2138
1234
  }
2139
- if (existsSync3(activeDir)) {
1235
+ if (existsSync2(activeDir)) {
2140
1236
  const entries = await fs.readdir(activeDir, { withFileTypes: true });
2141
1237
  for (const e of entries) {
2142
1238
  if (!e.isDirectory())
2143
1239
  continue;
2144
- const retiredMarker = path5.join(activeDir, e.name, "retired.marker");
2145
- if (existsSync3(retiredMarker))
1240
+ const retiredMarker = path3.join(activeDir, e.name, "retired.marker");
1241
+ if (existsSync2(retiredMarker))
2146
1242
  continue;
2147
- const staleMarker = path5.join(activeDir, e.name, "stale.marker");
2148
- if (existsSync3(staleMarker)) {
1243
+ const staleMarker = path3.join(activeDir, e.name, "stale.marker");
1244
+ if (existsSync2(staleMarker)) {
2149
1245
  let reason = "stale";
2150
1246
  try {
2151
1247
  const content = await fs.readFile(staleMarker, "utf-8");
@@ -2154,8 +1250,8 @@ async function listSkills(directory) {
2154
1250
  result.stale.push({ slug: e.name, reason });
2155
1251
  continue;
2156
1252
  }
2157
- const skillPath = path5.join(activeDir, e.name, "SKILL.md");
2158
- if (existsSync3(skillPath)) {
1253
+ const skillPath = path3.join(activeDir, e.name, "SKILL.md");
1254
+ if (existsSync2(skillPath)) {
2159
1255
  result.active.push({
2160
1256
  slug: e.name,
2161
1257
  path: skillPath
@@ -2179,7 +1275,7 @@ async function autoApplyProposals(directory, llmDelegate) {
2179
1275
  }
2180
1276
  let content;
2181
1277
  try {
2182
- content = await readFile4(proposal.path, "utf-8");
1278
+ content = await readFile3(proposal.path, "utf-8");
2183
1279
  } catch {
2184
1280
  result.skipped.push(proposal.slug);
2185
1281
  continue;
@@ -2238,14 +1334,14 @@ async function inspectSkill(directory, slug, prefer = "auto") {
2238
1334
  if (prefer === "proposal" || prefer === "auto")
2239
1335
  candidates.push({ p: proposalPath(directory, cleanSlug), m: "draft" });
2240
1336
  for (const c of candidates) {
2241
- if (existsSync3(c.p)) {
2242
- const content = await readFile4(c.p, "utf-8");
1337
+ if (existsSync2(c.p)) {
1338
+ const content = await readFile3(c.p, "utf-8");
2243
1339
  const result = { found: true, path: c.p, content, mode: c.m };
2244
1340
  const fm = parseDraftFrontmatter(content);
2245
1341
  if (fm && fm.sourceKnowledgeIds.length > 0) {
2246
1342
  const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
2247
1343
  const hivePath = resolveHiveKnowledgePath();
2248
- const hive = existsSync3(hivePath) ? await readKnowledge(hivePath) : [];
1344
+ const hive = existsSync2(hivePath) ? await readKnowledge(hivePath) : [];
2249
1345
  const allEntries = [...swarm, ...hive];
2250
1346
  const entryMap = new Map(allEntries.map((e) => [e.id, e]));
2251
1347
  result.source_knowledge_status = fm.sourceKnowledgeIds.map((id) => {
@@ -2259,11 +1355,11 @@ async function inspectSkill(directory, slug, prefer = "auto") {
2259
1355
  });
2260
1356
  }
2261
1357
  if (c.m === "active") {
2262
- const skillDir = path5.join(directory, ".opencode", "skills", "generated", cleanSlug);
2263
- const staleMarker = path5.join(skillDir, "stale.marker");
2264
- if (existsSync3(staleMarker)) {
1358
+ const skillDir = path3.join(directory, ".opencode", "skills", "generated", cleanSlug);
1359
+ const staleMarker = path3.join(skillDir, "stale.marker");
1360
+ if (existsSync2(staleMarker)) {
2265
1361
  try {
2266
- result.stale_reason = await readFile4(staleMarker, "utf-8");
1362
+ result.stale_reason = await readFile3(staleMarker, "utf-8");
2267
1363
  } catch {}
2268
1364
  }
2269
1365
  }
@@ -2278,26 +1374,26 @@ async function retireSkill(directory, slug, reason) {
2278
1374
  return {
2279
1375
  retired: false,
2280
1376
  path: activePath(directory, cleanSlug),
2281
- markerPath: path5.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
1377
+ markerPath: path3.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
2282
1378
  reason: "invalid slug"
2283
1379
  };
2284
1380
  }
2285
1381
  const skillPath = activePath(directory, cleanSlug);
2286
- if (!existsSync3(skillPath)) {
1382
+ if (!existsSync2(skillPath)) {
2287
1383
  return {
2288
1384
  retired: false,
2289
1385
  path: skillPath,
2290
- markerPath: path5.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
1386
+ markerPath: path3.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
2291
1387
  reason: "active skill not found"
2292
1388
  };
2293
1389
  }
2294
- const markerDir = path5.join(directory, ".opencode", "skills", "generated", cleanSlug);
2295
- const markerPath = path5.join(markerDir, "retired.marker");
1390
+ const markerDir = path3.join(directory, ".opencode", "skills", "generated", cleanSlug);
1391
+ const markerPath = path3.join(markerDir, "retired.marker");
2296
1392
  const markerContent = JSON.stringify({
2297
1393
  retiredAt: new Date().toISOString(),
2298
1394
  reason: reason ?? "manual_retire"
2299
1395
  });
2300
- await mkdir5(markerDir, { recursive: true });
1396
+ await mkdir3(markerDir, { recursive: true });
2301
1397
  await writeFile3(markerPath, markerContent, "utf-8");
2302
1398
  return {
2303
1399
  retired: true,
@@ -2307,11 +1403,11 @@ async function retireSkill(directory, slug, reason) {
2307
1403
  };
2308
1404
  }
2309
1405
  async function markSkillStale(skillDir, reason) {
2310
- await mkdir5(skillDir, { recursive: true });
2311
- await writeFile3(path5.join(skillDir, "stale.marker"), reason, "utf-8");
1406
+ await mkdir3(skillDir, { recursive: true });
1407
+ await writeFile3(path3.join(skillDir, "stale.marker"), reason, "utf-8");
2312
1408
  }
2313
1409
  async function clearSkillStale(skillDir) {
2314
- const markerPath = path5.join(skillDir, "stale.marker");
1410
+ const markerPath = path3.join(skillDir, "stale.marker");
2315
1411
  try {
2316
1412
  await unlink(markerPath);
2317
1413
  } catch (err) {
@@ -2323,10 +1419,10 @@ async function clearSkillStale(skillDir) {
2323
1419
  }
2324
1420
  async function retireOrMarkStale(directory, skillDir, archivedKnowledgeIds) {
2325
1421
  const fs = await import("fs/promises");
2326
- const skillPath = path5.join(skillDir, "SKILL.md");
2327
- if (!existsSync3(skillPath)) {
1422
+ const skillPath = path3.join(skillDir, "SKILL.md");
1423
+ if (!existsSync2(skillPath)) {
2328
1424
  await markSkillStale(skillDir, "source knowledge archived, SKILL.md missing");
2329
- const slug2 = path5.basename(skillDir);
1425
+ const slug2 = path3.basename(skillDir);
2330
1426
  return { action: "stale", slug: slug2, skillDir };
2331
1427
  }
2332
1428
  let content;
@@ -2334,18 +1430,18 @@ async function retireOrMarkStale(directory, skillDir, archivedKnowledgeIds) {
2334
1430
  content = await fs.readFile(skillPath, "utf-8");
2335
1431
  } catch {
2336
1432
  await markSkillStale(skillDir, "source knowledge archived, SKILL.md unreadable");
2337
- const slug2 = path5.basename(skillDir);
1433
+ const slug2 = path3.basename(skillDir);
2338
1434
  return { action: "stale", slug: slug2, skillDir };
2339
1435
  }
2340
1436
  const fm = parseDraftFrontmatter(content);
2341
1437
  const sourceIds = fm?.sourceKnowledgeIds ?? [];
2342
1438
  if (sourceIds.length === 0) {
2343
1439
  await markSkillStale(skillDir, "source knowledge archived, no source_knowledge_ids in frontmatter");
2344
- const slug2 = path5.basename(skillDir);
1440
+ const slug2 = path3.basename(skillDir);
2345
1441
  return { action: "stale", slug: slug2, skillDir };
2346
1442
  }
2347
1443
  const allArchived = sourceIds.every((id) => archivedKnowledgeIds.has(id));
2348
- const slug = path5.basename(skillDir);
1444
+ const slug = path3.basename(skillDir);
2349
1445
  if (allArchived) {
2350
1446
  await retireSkill(directory, slug, "all source knowledge entries archived or deleted");
2351
1447
  return { action: "retire", slug, skillDir };
@@ -2365,7 +1461,7 @@ async function regenerateSkill(directory, slug, options = {}) {
2365
1461
  };
2366
1462
  }
2367
1463
  const skillPath = activePath(directory, cleanSlug);
2368
- if (!existsSync3(skillPath)) {
1464
+ if (!existsSync2(skillPath)) {
2369
1465
  return {
2370
1466
  regenerated: false,
2371
1467
  path: skillPath,
@@ -2375,7 +1471,7 @@ async function regenerateSkill(directory, slug, options = {}) {
2375
1471
  }
2376
1472
  let existingContent;
2377
1473
  try {
2378
- existingContent = await readFile4(skillPath, "utf-8");
1474
+ existingContent = await readFile3(skillPath, "utf-8");
2379
1475
  } catch (err) {
2380
1476
  return {
2381
1477
  regenerated: false,
@@ -2390,7 +1486,7 @@ async function regenerateSkill(directory, slug, options = {}) {
2390
1486
  try {
2391
1487
  const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
2392
1488
  const hivePath = resolveHiveKnowledgePath();
2393
- const hive = existsSync3(hivePath) ? await readKnowledge(hivePath) : [];
1489
+ const hive = existsSync2(hivePath) ? await readKnowledge(hivePath) : [];
2394
1490
  const all = [...swarm, ...hive];
2395
1491
  const idSet = new Set(fm.sourceKnowledgeIds);
2396
1492
  matchedEntries = all.filter((e) => idSet.has(e.id));
@@ -2513,7 +1609,7 @@ async function regenerateSkill(directory, slug, options = {}) {
2513
1609
  try {
2514
1610
  await atomicWrite2(skillPath, content);
2515
1611
  await stampSourceEntries(directory, cleanSlug, matchedEntries.map((e) => e.id));
2516
- await clearSkillStale(path5.dirname(activePath(directory, cleanSlug)));
1612
+ await clearSkillStale(path3.dirname(activePath(directory, cleanSlug)));
2517
1613
  } catch (writeErr) {
2518
1614
  return {
2519
1615
  regenerated: false,
@@ -2561,4 +1657,4 @@ var _internals = {
2561
1657
  unlinkSync
2562
1658
  };
2563
1659
 
2564
- export { resolveKnowledgeEventsPath, readKnowledgeEvents, readKnowledgeCounterRollups, effectiveRetrievalOutcomes, validateLesson, validateActionableFields, validateActionability, resolveUnactionablePath, appendUnactionable, quarantineEntry, restoreEntry, appendSkillChangelog, evaluateSkillChange, appendRejectedSkillEdit, sanitizeSlug, isValidSlug2 as isValidSlug, proposalPath, activePath, activeRepoRelativePath, DEFAULT_SKILL_MIN_CONFIDENCE, DEFAULT_SKILL_MIN_CONFIRMATIONS, STRONG_SKILL_OUTCOME_COUNT, HIGH_PRIORITY_SKILL_MIN_CONFIDENCE, selectCandidateEntries, isSkillMaturityEligible, clusterEntries, renderSkillMarkdown, generateSkills, parseDraftFrontmatter, activateProposal, findSkillsBySourceKnowledgeId, findStaleSkillsBySourceKnowledgeId, listSkills, autoApplyProposals, inspectSkill, retireSkill, markSkillStale, clearSkillStale, retireOrMarkStale, regenerateSkill, _internals };
1660
+ export { appendSkillChangelog, evaluateSkillChange, appendRejectedSkillEdit, sanitizeSlug, isValidSlug2 as isValidSlug, proposalPath, activePath, activeRepoRelativePath, DEFAULT_SKILL_MIN_CONFIDENCE, DEFAULT_SKILL_MIN_CONFIRMATIONS, STRONG_SKILL_OUTCOME_COUNT, HIGH_PRIORITY_SKILL_MIN_CONFIDENCE, selectCandidateEntries, isSkillMaturityEligible, clusterEntries, renderSkillMarkdown, generateSkills, parseDraftFrontmatter, activateProposal, findSkillsBySourceKnowledgeId, findStaleSkillsBySourceKnowledgeId, listSkills, autoApplyProposals, inspectSkill, retireSkill, markSkillStale, clearSkillStale, retireOrMarkStale, regenerateSkill, _internals };