opencode-swarm 7.112.2 → 7.113.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.opencode/skills/brainstorm/SKILL.md +1 -0
  2. package/.opencode/skills/ci-failure-batching/SKILL.md +2 -1
  3. package/.opencode/skills/ci-fix-monitor/SKILL.md +203 -0
  4. package/.opencode/skills/clarify/SKILL.md +1 -0
  5. package/.opencode/skills/clarify-spec/SKILL.md +1 -0
  6. package/.opencode/skills/codebase-review-swarm/SKILL.md +1 -0
  7. package/.opencode/skills/commit-pr/SKILL.md +15 -0
  8. package/.opencode/skills/consult/SKILL.md +1 -0
  9. package/.opencode/skills/council/SKILL.md +1 -0
  10. package/.opencode/skills/critic-gate/SKILL.md +1 -0
  11. package/.opencode/skills/deep-dive/SKILL.md +1 -0
  12. package/.opencode/skills/deep-research/SKILL.md +1 -0
  13. package/.opencode/skills/design-docs/SKILL.md +2 -1
  14. package/.opencode/skills/discover/SKILL.md +1 -0
  15. package/.opencode/skills/engineering-conventions/SKILL.md +2 -1
  16. package/.opencode/skills/execute/SKILL.md +1 -0
  17. package/.opencode/skills/fork-pr-operations/SKILL.md +136 -0
  18. package/.opencode/skills/gate-attribution/SKILL.md +2 -1
  19. package/.opencode/skills/issue-ingest/SKILL.md +1 -0
  20. package/.opencode/skills/loop/SKILL.md +7 -6
  21. package/.opencode/skills/merge-queue-readiness/SKILL.md +2 -1
  22. package/.opencode/skills/parallel-work-check/SKILL.md +133 -0
  23. package/.opencode/skills/phase-wrap/SKILL.md +1 -0
  24. package/.opencode/skills/plan/SKILL.md +1 -0
  25. package/.opencode/skills/pre-phase-briefing/SKILL.md +1 -0
  26. package/.opencode/skills/resume/SKILL.md +1 -0
  27. package/.opencode/skills/running-tests/SKILL.md +1 -0
  28. package/.opencode/skills/skill-edit-validation/SKILL.md +2 -1
  29. package/.opencode/skills/specify/SKILL.md +1 -0
  30. package/.opencode/skills/swarm/SKILL.md +1 -0
  31. package/.opencode/skills/swarm-ci-monitor/SKILL.md +5 -4
  32. package/.opencode/skills/swarm-implement/SKILL.md +4 -4
  33. package/.opencode/skills/swarm-pr-feedback/SKILL.md +26 -5
  34. package/.opencode/skills/swarm-pr-review/SKILL.md +2 -1
  35. package/.opencode/skills/swarm-pr-subscribe/SKILL.md +1 -0
  36. package/.opencode/skills/test-file-split/SKILL.md +102 -0
  37. package/.opencode/skills/worktree-retry-cleanup/SKILL.md +2 -1
  38. package/.opencode/skills/writing-tests/SKILL.md +43 -0
  39. package/dist/cli/{config-doctor-mmw4c50z.js → config-doctor-az11cwf5.js} +2 -2
  40. package/dist/cli/{curator-llm-factory-5bns4xy6.js → curator-llm-factory-3t0ehhfe.js} +5 -5
  41. package/dist/cli/{curator-snvp9542.js → curator-pdcpw4x6.js} +5 -5
  42. package/dist/cli/{guardrail-explain-4s7djf9p.js → guardrail-explain-xsfdc49z.js} +6 -6
  43. package/dist/cli/{guardrail-log-xjgr00eq.js → guardrail-log-hysxdwg9.js} +3 -3
  44. package/dist/cli/{hive-promoter-zs295trk.js → hive-promoter-4htgk6zb.js} +5 -5
  45. package/dist/cli/{index-xehrmy76.js → index-0gf6de8b.js} +1 -1
  46. package/dist/cli/{index-cq2hgvd2.js → index-1ey3dxq7.js} +9 -1
  47. package/dist/cli/{index-k6wd3chp.js → index-6gdxwfsh.js} +7 -7
  48. package/dist/cli/{index-npxmfj48.js → index-8f256d7t.js} +1 -1
  49. package/dist/cli/{index-snmfqhez.js → index-bsvwnzh7.js} +1989 -935
  50. package/dist/cli/{index-82v0d72f.js → index-h88ktb5r.js} +418 -87
  51. package/dist/cli/{index-w84stmkx.js → index-r9fjzr3k.js} +1 -1
  52. package/dist/cli/{index-9fjpecax.js → index-v96kmbkw.js} +2 -2
  53. package/dist/cli/index.js +5 -5
  54. package/dist/cli/{schema-2p15yrvn.js → schema-qb313fyy.js} +1 -1
  55. package/dist/cli/{skill-generator-fe6q8xgm.js → skill-generator-0my4jrx6.js} +1 -1
  56. package/dist/commands/loop.d.ts +1 -1
  57. package/dist/commands/registry.d.ts +1 -1
  58. package/dist/config/bundled-skills.d.ts +15 -5
  59. package/dist/config/schema.d.ts +2 -0
  60. package/dist/hooks/skill-propagation-gate.d.ts +45 -5
  61. package/dist/hooks/skill-scoring.d.ts +22 -1
  62. package/dist/index.js +83 -83
  63. package/package.json +5 -1
@@ -19,6 +19,7 @@ import {
19
19
  } from "./index-bfwt3abw.js";
20
20
  import {
21
21
  init_logger,
22
+ log,
22
23
  warn
23
24
  } from "./index-zgwm4ryv.js";
24
25
  import {
@@ -27,34 +28,345 @@ import {
27
28
 
28
29
  // src/services/skill-generator.ts
29
30
  import { existsSync as existsSync2, unlinkSync } from "fs";
30
- import { mkdir as mkdir3, readFile as readFile3, rename as rename2, unlink, writeFile as writeFile3 } from "fs/promises";
31
- import * as path3 from "path";
31
+ import { mkdir as mkdir4, readFile as readFile4, rename as rename3, unlink, writeFile as writeFile4 } from "fs/promises";
32
+ import * as path4 from "path";
33
+
34
+ // src/config/bundled-skills.ts
35
+ import { randomUUID } from "crypto";
36
+ import * as fsp from "fs/promises";
37
+ import * as path from "path";
38
+
39
+ // src/services/warning-buffer.ts
40
+ init_logger();
41
+ var deferredWarnings = [];
42
+ var MAX_DEFERRED_WARNINGS = 50;
43
+ function addDeferredWarning(warning) {
44
+ if (deferredWarnings.length < MAX_DEFERRED_WARNINGS) {
45
+ deferredWarnings.push(warning);
46
+ }
47
+ }
48
+ function advisoryWarn(message, data) {
49
+ addDeferredWarning(message);
50
+ log(message, data);
51
+ }
52
+ function getDeferredWarnings() {
53
+ return [...deferredWarnings];
54
+ }
55
+
56
+ // src/config/bundled-skills.ts
57
+ init_logger();
58
+ var BUNDLED_PROJECT_SKILLS = [
59
+ "brainstorm",
60
+ "specify",
61
+ "clarify-spec",
62
+ "resume",
63
+ "clarify",
64
+ "discover",
65
+ "consult",
66
+ "pre-phase-briefing",
67
+ "council",
68
+ "deep-dive",
69
+ "deep-research",
70
+ "codebase-review-swarm",
71
+ "swarm-implement",
72
+ "design-docs",
73
+ "swarm-pr-review",
74
+ "swarm",
75
+ "swarm-pr-feedback",
76
+ "swarm-pr-subscribe",
77
+ "swarm-ci-monitor",
78
+ "issue-ingest",
79
+ "plan",
80
+ "critic-gate",
81
+ "execute",
82
+ "phase-wrap",
83
+ "loop",
84
+ "writing-tests",
85
+ "running-tests",
86
+ "engineering-conventions",
87
+ "commit-pr",
88
+ "ci-failure-batching",
89
+ "gate-attribution",
90
+ "merge-queue-readiness",
91
+ "skill-edit-validation",
92
+ "worktree-retry-cleanup",
93
+ "test-file-split",
94
+ "fork-pr-operations",
95
+ "parallel-work-check",
96
+ "ci-fix-monitor"
97
+ ];
98
+ var BUNDLED_PROJECT_SKILL_ROOT = ".swarm/bundled-skills";
99
+ function bundledProjectSkillFileReference(slug) {
100
+ return `file:${BUNDLED_PROJECT_SKILL_ROOT}/${slug}/SKILL.md`;
101
+ }
102
+ var MAX_SKILL_FILES = 64;
103
+ var MAX_SKILL_BYTES = 512000;
104
+ var MAX_IN_FLIGHT_SYNCS = 64;
105
+ var inFlightSyncs = new Map;
106
+ function describeBundledSkillSyncFailure(err) {
107
+ const message = err instanceof Error ? err.message : String(err);
108
+ return `[opencode-swarm] Could not install bundled project skills; continuing without sync: ${message}`;
109
+ }
110
+ async function isSymbolicLinkAsync(p) {
111
+ try {
112
+ return (await fsp.lstat(p)).isSymbolicLink();
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
117
+ async function ensureNotSymlinkedDirectoryAsync(p) {
118
+ try {
119
+ const stat2 = await fsp.lstat(p);
120
+ return stat2.isDirectory() && !stat2.isSymbolicLink();
121
+ } catch (err) {
122
+ return err.code === "ENOENT";
123
+ }
124
+ }
125
+ async function pathExistsAsync(p) {
126
+ try {
127
+ await fsp.access(p);
128
+ return true;
129
+ } catch {
130
+ return false;
131
+ }
132
+ }
133
+ async function collectBundledSkillFilesBoundedAsync(sourceDir, state, relativeDir = "") {
134
+ const currentSource = path.join(sourceDir, relativeDir);
135
+ const entries = await fsp.readdir(currentSource, { withFileTypes: true });
136
+ entries.sort((a, b) => a.name.localeCompare(b.name));
137
+ const files = [];
138
+ for (const entry of entries) {
139
+ const relativeEntry = path.join(relativeDir, entry.name);
140
+ const sourcePath = path.join(sourceDir, relativeEntry);
141
+ if (entry.isSymbolicLink() || await isSymbolicLinkAsync(sourcePath)) {
142
+ throw new Error("refusing to copy symlinked bundled skill entry");
143
+ }
144
+ if (entry.isDirectory()) {
145
+ files.push(...await collectBundledSkillFilesBoundedAsync(sourceDir, state, relativeEntry));
146
+ continue;
147
+ }
148
+ if (!entry.isFile())
149
+ continue;
150
+ const stat2 = await fsp.stat(sourcePath);
151
+ const nextFiles = state.files + 1;
152
+ const nextBytes = state.bytes + stat2.size;
153
+ if (nextFiles > MAX_SKILL_FILES || nextBytes > MAX_SKILL_BYTES) {
154
+ throw new Error("bundled skill package exceeds copy bounds");
155
+ }
156
+ state.files = nextFiles;
157
+ state.bytes = nextBytes;
158
+ files.push({ relativePath: relativeEntry });
159
+ }
160
+ return files;
161
+ }
162
+ async function ensureContainedDirectoryAsync(rootDir, directory) {
163
+ const safeRoot = path.resolve(rootDir);
164
+ const safeDirectory = path.resolve(directory);
165
+ const relative2 = path.relative(safeRoot, safeDirectory);
166
+ if (relative2.startsWith("..") || path.isAbsolute(relative2)) {
167
+ throw new Error("bundled skill destination escaped its private root");
168
+ }
169
+ try {
170
+ const rootStat = await fsp.lstat(safeRoot);
171
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
172
+ throw new Error("refusing to traverse unsafe bundled skill directory");
173
+ }
174
+ } catch (err) {
175
+ if (err.code !== "ENOENT")
176
+ throw err;
177
+ await fsp.mkdir(safeRoot, { recursive: true });
178
+ const rootStat = await fsp.lstat(safeRoot);
179
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
180
+ throw new Error("refusing to traverse unsafe bundled skill directory");
181
+ }
182
+ }
183
+ let current = safeRoot;
184
+ for (const segment of relative2.split(path.sep).filter(Boolean)) {
185
+ current = path.join(current, segment);
186
+ try {
187
+ const stat2 = await fsp.lstat(current);
188
+ if (stat2.isSymbolicLink() || !stat2.isDirectory()) {
189
+ throw new Error("refusing to traverse unsafe bundled skill directory");
190
+ }
191
+ } catch (err) {
192
+ if (err.code !== "ENOENT")
193
+ throw err;
194
+ try {
195
+ await fsp.mkdir(current);
196
+ } catch (mkdirErr) {
197
+ if (mkdirErr.code !== "EEXIST") {
198
+ throw mkdirErr;
199
+ }
200
+ }
201
+ const stat2 = await fsp.lstat(current);
202
+ if (stat2.isSymbolicLink() || !stat2.isDirectory()) {
203
+ throw new Error("refusing to traverse unsafe bundled skill directory");
204
+ }
205
+ }
206
+ }
207
+ }
208
+ async function rollbackCopiedFilesAsync(copiedFiles, destDir, overwrittenFiles = []) {
209
+ const safeDestDir = path.resolve(destDir);
210
+ const dirs = new Set;
211
+ for (const copiedFile of copiedFiles) {
212
+ const resolvedFile = path.resolve(copiedFile);
213
+ const relative2 = path.relative(safeDestDir, resolvedFile);
214
+ if (relative2.startsWith("..") || path.isAbsolute(relative2))
215
+ continue;
216
+ try {
217
+ await fsp.rm(resolvedFile, { force: true });
218
+ } catch {}
219
+ dirs.add(path.dirname(resolvedFile));
220
+ }
221
+ for (const overwritten of overwrittenFiles.reverse()) {
222
+ const resolvedFile = path.resolve(overwritten.path);
223
+ const relative2 = path.relative(safeDestDir, resolvedFile);
224
+ if (relative2.startsWith("..") || path.isAbsolute(relative2))
225
+ continue;
226
+ try {
227
+ await fsp.writeFile(resolvedFile, overwritten.contents);
228
+ } catch {}
229
+ }
230
+ for (const dir of [...dirs].sort((a, b) => b.length - a.length)) {
231
+ const relative2 = path.relative(safeDestDir, path.resolve(dir));
232
+ if (relative2.startsWith("..") || path.isAbsolute(relative2))
233
+ continue;
234
+ try {
235
+ await fsp.rmdir(dir);
236
+ } catch {}
237
+ }
238
+ }
239
+ async function copyFileAtomicAsync(sourcePath, destPath) {
240
+ const tempPath = path.join(path.dirname(destPath), `.${path.basename(destPath)}.tmp.${randomUUID()}`);
241
+ try {
242
+ await fsp.copyFile(sourcePath, tempPath);
243
+ await fsp.rename(tempPath, destPath);
244
+ } catch (err) {
245
+ try {
246
+ await fsp.rm(tempPath, { force: true });
247
+ } catch {}
248
+ throw err;
249
+ }
250
+ }
251
+ async function copyBundledDirectoryBoundedAsync(sourceDir, destDir) {
252
+ const files = await collectBundledSkillFilesBoundedAsync(sourceDir, {
253
+ files: 0,
254
+ bytes: 0
255
+ });
256
+ const copiedFiles = [];
257
+ const overwrittenFiles = [];
258
+ try {
259
+ for (const file of files) {
260
+ const sourcePath = path.join(sourceDir, file.relativePath);
261
+ const destPath = path.join(destDir, file.relativePath);
262
+ await ensureContainedDirectoryAsync(destDir, path.dirname(destPath));
263
+ if (await pathExistsAsync(destPath)) {
264
+ if (await isSymbolicLinkAsync(destPath)) {
265
+ throw new Error("refusing to overwrite symlinked bundled skill file");
266
+ }
267
+ const [sourceContents, destContents] = await Promise.all([
268
+ fsp.readFile(sourcePath),
269
+ fsp.readFile(destPath)
270
+ ]);
271
+ if (sourceContents.equals(destContents)) {
272
+ continue;
273
+ }
274
+ overwrittenFiles.push({ path: destPath, contents: destContents });
275
+ await copyFileAtomicAsync(sourcePath, destPath);
276
+ } else {
277
+ await copyFileAtomicAsync(sourcePath, destPath);
278
+ copiedFiles.push(destPath);
279
+ }
280
+ }
281
+ } catch (err) {
282
+ await rollbackCopiedFilesAsync(copiedFiles, destDir, overwrittenFiles);
283
+ throw err;
284
+ }
285
+ }
286
+ async function performBundledProjectSkillSyncAsync(projectDirectory, packageRoot, quiet) {
287
+ try {
288
+ const sourceRoot = path.join(packageRoot, ".opencode", "skills");
289
+ const swarmDir = path.join(projectDirectory, ".swarm");
290
+ const skillsDir = path.join(projectDirectory, BUNDLED_PROJECT_SKILL_ROOT);
291
+ if (!await ensureNotSymlinkedDirectoryAsync(sourceRoot)) {
292
+ throw new Error("refusing to copy symlinked bundled skill source root");
293
+ }
294
+ if (!await ensureNotSymlinkedDirectoryAsync(swarmDir))
295
+ return;
296
+ if (!await ensureNotSymlinkedDirectoryAsync(skillsDir))
297
+ return;
298
+ for (const slug of BUNDLED_PROJECT_SKILLS) {
299
+ const sourceDir = path.join(sourceRoot, slug);
300
+ const sourceSkill = path.join(sourceDir, "SKILL.md");
301
+ const destDir = path.join(skillsDir, slug);
302
+ if (!await pathExistsAsync(sourceSkill))
303
+ continue;
304
+ if (!await ensureNotSymlinkedDirectoryAsync(sourceDir)) {
305
+ throw new Error("refusing to copy symlinked bundled skill directory");
306
+ }
307
+ if (!await ensureNotSymlinkedDirectoryAsync(destDir))
308
+ continue;
309
+ await copyBundledDirectoryBoundedAsync(sourceDir, destDir);
310
+ log("synchronized bundled skill", {
311
+ slug: bundledProjectSkillFileReference(slug)
312
+ });
313
+ }
314
+ } catch (err) {
315
+ const failureMsg = describeBundledSkillSyncFailure(err);
316
+ if (quiet) {
317
+ advisoryWarn(failureMsg);
318
+ } else {
319
+ console.warn(failureMsg);
320
+ }
321
+ }
322
+ }
323
+ async function syncBundledProjectSkillsIfMissingAsync(projectDirectory, packageRoot, quiet = false) {
324
+ const syncKey = path.resolve(projectDirectory, BUNDLED_PROJECT_SKILL_ROOT);
325
+ const existing = inFlightSyncs.get(syncKey);
326
+ if (existing)
327
+ return existing;
328
+ if (inFlightSyncs.size >= MAX_IN_FLIGHT_SYNCS) {
329
+ log("skipping bundled skill sync because the in-flight limit was reached", {
330
+ limit: MAX_IN_FLIGHT_SYNCS
331
+ });
332
+ return;
333
+ }
334
+ const syncPromise = performBundledProjectSkillSyncAsync(projectDirectory, packageRoot, quiet).finally(() => {
335
+ if (inFlightSyncs.get(syncKey) === syncPromise) {
336
+ inFlightSyncs.delete(syncKey);
337
+ }
338
+ });
339
+ inFlightSyncs.set(syncKey, syncPromise);
340
+ return syncPromise;
341
+ }
342
+
343
+ // src/services/skill-generator.ts
32
344
  init_logger();
33
345
 
34
346
  // src/services/skill-changelog.ts
35
347
  init_logger();
36
- import { appendFile, mkdir, readFile, writeFile } from "fs/promises";
37
- import * as path from "path";
348
+ import { appendFile, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
349
+ import * as path2 from "path";
38
350
  var MAX_CHANGELOG_ENTRIES_PER_SKILL = 200;
39
351
  function resolveSkillChangelogPath(directory, slug) {
40
352
  if (slug.includes("..") || slug.includes("/") || slug.includes("\\")) {
41
353
  throw new Error(`Invalid skill slug: ${slug} \u2014 must not contain "..", "/" or "\\"`);
42
354
  }
43
- return path.join(directory, ".swarm", "skill-changelogs", `${slug}.jsonl`);
355
+ return path2.join(directory, ".swarm", "skill-changelogs", `${slug}.jsonl`);
44
356
  }
45
357
  async function appendSkillChangelog(directory, slug, entry) {
46
358
  const filePath = resolveSkillChangelogPath(directory, slug);
47
- const dirPath = path.dirname(filePath);
48
- await mkdir(dirPath, { recursive: true });
359
+ const dirPath = path2.dirname(filePath);
360
+ await mkdir2(dirPath, { recursive: true });
49
361
  await appendFile(filePath, `${JSON.stringify(entry)}
50
362
  `, "utf-8");
51
363
  try {
52
- const content = await readFile(filePath, "utf-8");
364
+ const content = await readFile2(filePath, "utf-8");
53
365
  const lines = content.split(`
54
366
  `).filter((line) => line.trim().length > 0);
55
367
  if (lines.length > MAX_CHANGELOG_ENTRIES_PER_SKILL) {
56
368
  const trimmed = lines.slice(lines.length - MAX_CHANGELOG_ENTRIES_PER_SKILL);
57
- await writeFile(filePath, `${trimmed.join(`
369
+ await writeFile2(filePath, `${trimmed.join(`
58
370
  `)}
59
371
  `, "utf-8");
60
372
  }
@@ -67,16 +379,16 @@ async function appendSkillChangelog(directory, slug, entry) {
67
379
  import { createHash } from "crypto";
68
380
  import { existsSync } from "fs";
69
381
  import {
70
- lstat,
71
- mkdir as mkdir2,
72
- readdir,
73
- readFile as readFile2,
382
+ lstat as lstat2,
383
+ mkdir as mkdir3,
384
+ readdir as readdir2,
385
+ readFile as readFile3,
74
386
  realpath,
75
- rename,
76
- stat,
77
- writeFile as writeFile2
387
+ rename as rename2,
388
+ stat as stat2,
389
+ writeFile as writeFile3
78
390
  } from "fs/promises";
79
- import * as path2 from "path";
391
+ import * as path3 from "path";
80
392
  var SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
81
393
  var MAX_EVAL_FILES = 50;
82
394
  var MAX_EVAL_FILE_BYTES = 64 * 1024;
@@ -142,15 +454,15 @@ function casesFromParsedJson(parsed, fileLabel) {
142
454
  return cases;
143
455
  }
144
456
  function evalRoot(directory, slug) {
145
- return path2.join(directory, ".swarm", "skills", "evals", slug);
457
+ return path3.join(directory, ".swarm", "skills", "evals", slug);
146
458
  }
147
459
  function isInsidePath(root, target) {
148
- const resolvedRoot = path2.resolve(root);
149
- const resolvedTarget = path2.resolve(target);
150
- return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path2.sep);
460
+ const resolvedRoot = path3.resolve(root);
461
+ const resolvedTarget = path3.resolve(target);
462
+ return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path3.sep);
151
463
  }
152
464
  function rejectedEditsPath(directory) {
153
- return path2.join(directory, ".swarm", "skills", "rejected-edits.jsonl");
465
+ return path3.join(directory, ".swarm", "skills", "rejected-edits.jsonl");
154
466
  }
155
467
  async function loadEvalSet(directory, slug) {
156
468
  if (!isValidSlug(slug)) {
@@ -187,7 +499,7 @@ async function loadEvalSet(directory, slug) {
187
499
  }
188
500
  let entries;
189
501
  try {
190
- entries = await readdir(root);
502
+ entries = await readdir2(root);
191
503
  } catch (err) {
192
504
  return {
193
505
  status: "invalid",
@@ -203,9 +515,9 @@ async function loadEvalSet(directory, slug) {
203
515
  const cases = [];
204
516
  const fileLabels = [];
205
517
  for (const file of files) {
206
- const fullPath = path2.join(root, file);
207
- const resolved = path2.resolve(fullPath);
208
- const resolvedRoot = path2.resolve(root);
518
+ const fullPath = path3.join(root, file);
519
+ const resolved = path3.resolve(fullPath);
520
+ const resolvedRoot = path3.resolve(root);
209
521
  if (!isInsidePath(resolvedRoot, resolved)) {
210
522
  return {
211
523
  status: "invalid",
@@ -217,7 +529,7 @@ async function loadEvalSet(directory, slug) {
217
529
  let readPath = fullPath;
218
530
  let info;
219
531
  try {
220
- const linkInfo = await lstat(fullPath);
532
+ const linkInfo = await lstat2(fullPath);
221
533
  if (linkInfo.isSymbolicLink()) {
222
534
  const realFile = await realpath(fullPath);
223
535
  if (!isInsidePath(realRoot, realFile)) {
@@ -229,7 +541,7 @@ async function loadEvalSet(directory, slug) {
229
541
  };
230
542
  }
231
543
  readPath = realFile;
232
- info = await stat(realFile);
544
+ info = await stat2(realFile);
233
545
  } else {
234
546
  if (!linkInfo.isFile())
235
547
  continue;
@@ -255,7 +567,7 @@ async function loadEvalSet(directory, slug) {
255
567
  }
256
568
  let parsed;
257
569
  try {
258
- parsed = JSON.parse(await readFile2(readPath, "utf-8"));
570
+ parsed = JSON.parse(await readFile3(readPath, "utf-8"));
259
571
  } catch (err) {
260
572
  return {
261
573
  status: "invalid",
@@ -264,7 +576,7 @@ async function loadEvalSet(directory, slug) {
264
576
  reason: `eval file invalid JSON: ${file}: ${err instanceof Error ? err.message : String(err)}`
265
577
  };
266
578
  }
267
- fileLabels.push(path2.relative(directory, fullPath).replace(/\\/g, "/"));
579
+ fileLabels.push(path3.relative(directory, fullPath).replace(/\\/g, "/"));
268
580
  cases.push(...casesFromParsedJson(parsed, file));
269
581
  if (cases.length >= MAX_EVAL_CASES)
270
582
  break;
@@ -382,10 +694,10 @@ async function evaluateSkillChange(req) {
382
694
  };
383
695
  }
384
696
  async function atomicWrite(filePath, content) {
385
- await mkdir2(path2.dirname(filePath), { recursive: true });
697
+ await mkdir3(path3.dirname(filePath), { recursive: true });
386
698
  const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
387
- await writeFile2(tmp, content, "utf-8");
388
- await rename(tmp, filePath);
699
+ await writeFile3(tmp, content, "utf-8");
700
+ await rename2(tmp, filePath);
389
701
  }
390
702
  async function appendRejectedSkillEdit(req, evaluation) {
391
703
  const filePath = rejectedEditsPath(req.directory);
@@ -405,7 +717,7 @@ async function appendRejectedSkillEdit(req, evaluation) {
405
717
  };
406
718
  let prior = [];
407
719
  try {
408
- prior = (await readFile2(filePath, "utf-8")).split(/\r?\n/).filter((line) => line.trim().length > 0);
720
+ prior = (await readFile3(filePath, "utf-8")).split(/\r?\n/).filter((line) => line.trim().length > 0);
409
721
  } catch {
410
722
  prior = [];
411
723
  }
@@ -422,7 +734,7 @@ async function isRejectedSkillContent(directory, slug, content) {
422
734
  const normalizedHash = hashNormalizedContent(content);
423
735
  let raw = "";
424
736
  try {
425
- raw = await readFile2(rejectedEditsPath(directory), "utf-8");
737
+ raw = await readFile3(rejectedEditsPath(directory), "utf-8");
426
738
  } catch {
427
739
  return false;
428
740
  }
@@ -449,6 +761,10 @@ async function isRejectedSkillContent(directory, slug, content) {
449
761
 
450
762
  // src/services/skill-generator.ts
451
763
  var SLUG_PATTERN2 = /^[a-z0-9][a-z0-9-]{0,63}$/;
764
+ var RESERVED_ACTIVE_SKILL_SLUGS = new Set(BUNDLED_PROJECT_SKILLS);
765
+ function reservedActiveSlugReason(slug) {
766
+ return `reserved bundled skill slug "${slug}" cannot be used for an active generated skill`;
767
+ }
452
768
  function sanitizeSlug(input) {
453
769
  const lc = input.toLowerCase().trim();
454
770
  const mapped = lc.replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-");
@@ -459,10 +775,10 @@ function isValidSlug2(slug) {
459
775
  return SLUG_PATTERN2.test(slug);
460
776
  }
461
777
  function proposalPath(directory, slug) {
462
- return path3.join(directory, ".swarm", "skills", "proposals", `${slug}.md`);
778
+ return path4.join(directory, ".swarm", "skills", "proposals", `${slug}.md`);
463
779
  }
464
780
  function activePath(directory, slug) {
465
- return path3.join(directory, ".opencode", "skills", "generated", slug, "SKILL.md");
781
+ return path4.join(directory, ".opencode", "skills", "generated", slug, "SKILL.md");
466
782
  }
467
783
  function activeRepoRelativePath(slug) {
468
784
  return `.opencode/skills/generated/${slug}/SKILL.md`;
@@ -486,12 +802,12 @@ function generateEvalStub(cluster) {
486
802
  ];
487
803
  }
488
804
  async function writeEvalStub(directory, slug, cases) {
489
- const stubPath = path3.join(directory, ".swarm", "skills", "evals", slug, "auto-stub.json");
805
+ const stubPath = path4.join(directory, ".swarm", "skills", "evals", slug, "auto-stub.json");
490
806
  if (cases.length === 0) {
491
807
  return { written: false, path: stubPath, reason: "no directive fields" };
492
808
  }
493
809
  try {
494
- await mkdir3(path3.dirname(stubPath), { recursive: true });
810
+ await mkdir4(path4.dirname(stubPath), { recursive: true });
495
811
  await atomicWrite2(stubPath, `${JSON.stringify({ cases })}
496
812
  `);
497
813
  return { written: true, path: stubPath };
@@ -726,10 +1042,10 @@ function escapeMarkdown(s) {
726
1042
  return s.replace(/[\r\n]+/g, " ").slice(0, 280);
727
1043
  }
728
1044
  async function atomicWrite2(p, content) {
729
- await mkdir3(path3.dirname(p), { recursive: true });
1045
+ await mkdir4(path4.dirname(p), { recursive: true });
730
1046
  const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
731
- await writeFile3(tmp, content, "utf-8");
732
- await rename2(tmp, p);
1047
+ await writeFile4(tmp, content, "utf-8");
1048
+ await rename3(tmp, p);
733
1049
  }
734
1050
  async function generateSkills(req) {
735
1051
  const minConfidence = req.minConfidence ?? DEFAULT_SKILL_MIN_CONFIDENCE;
@@ -778,8 +1094,15 @@ async function generateSkills(req) {
778
1094
  });
779
1095
  continue;
780
1096
  }
1097
+ if (req.mode === "active" && RESERVED_ACTIVE_SKILL_SLUGS.has(cluster.slug)) {
1098
+ result.skipped.push({
1099
+ slug: cluster.slug,
1100
+ reason: reservedActiveSlugReason(cluster.slug)
1101
+ });
1102
+ continue;
1103
+ }
781
1104
  const targetPath = req.mode === "active" ? activePath(req.directory, cluster.slug) : proposalPath(req.directory, cluster.slug);
782
- const repoRel = path3.relative(req.directory, targetPath).replace(/\\/g, "/");
1105
+ const repoRel = path4.relative(req.directory, targetPath).replace(/\\/g, "/");
783
1106
  if (!validateSkillPath(repoRel)) {
784
1107
  result.skipped.push({
785
1108
  slug: cluster.slug,
@@ -789,7 +1112,7 @@ async function generateSkills(req) {
789
1112
  }
790
1113
  let preserved = false;
791
1114
  if (req.mode === "active" && existsSync2(targetPath) && !req.force) {
792
- const existing = await readFile3(targetPath, "utf-8");
1115
+ const existing = await readFile4(targetPath, "utf-8");
793
1116
  if (!existing.includes("generated by opencode-swarm skill-generator")) {
794
1117
  preserved = true;
795
1118
  result.skipped.push({
@@ -814,7 +1137,7 @@ async function generateSkills(req) {
814
1137
  const existingActivePath = activePath(req.directory, cluster.slug);
815
1138
  if (existsSync2(existingActivePath)) {
816
1139
  try {
817
- incumbentContent = await readFile3(existingActivePath, "utf-8");
1140
+ incumbentContent = await readFile4(existingActivePath, "utf-8");
818
1141
  } catch {
819
1142
  incumbentContent = undefined;
820
1143
  }
@@ -1089,6 +1412,14 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1089
1412
  }
1090
1413
  const from = proposalPath(directory, cleanSlug);
1091
1414
  const to = activePath(directory, cleanSlug);
1415
+ if (RESERVED_ACTIVE_SKILL_SLUGS.has(cleanSlug)) {
1416
+ return {
1417
+ activated: false,
1418
+ from,
1419
+ to,
1420
+ reason: reservedActiveSlugReason(cleanSlug)
1421
+ };
1422
+ }
1092
1423
  if (!existsSync2(from)) {
1093
1424
  return {
1094
1425
  activated: false,
@@ -1098,7 +1429,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1098
1429
  };
1099
1430
  }
1100
1431
  if (existsSync2(to) && !force) {
1101
- const existing = await readFile3(to, "utf-8");
1432
+ const existing = await readFile4(to, "utf-8");
1102
1433
  if (!existing.includes("generated by opencode-swarm skill-generator")) {
1103
1434
  return {
1104
1435
  activated: false,
@@ -1110,7 +1441,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1110
1441
  }
1111
1442
  let proposalContent;
1112
1443
  try {
1113
- proposalContent = await readFile3(from, "utf-8");
1444
+ proposalContent = await readFile4(from, "utf-8");
1114
1445
  } catch (readErr) {
1115
1446
  return {
1116
1447
  activated: false,
@@ -1133,7 +1464,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1133
1464
  let incumbentContent;
1134
1465
  if (existsSync2(to)) {
1135
1466
  try {
1136
- incumbentContent = await readFile3(to, "utf-8");
1467
+ incumbentContent = await readFile4(to, "utf-8");
1137
1468
  } catch {
1138
1469
  incumbentContent = undefined;
1139
1470
  }
@@ -1208,7 +1539,7 @@ async function activateProposal(directory, slug, force = false, options = {}) {
1208
1539
  }
1209
1540
  }
1210
1541
  async function findSkillsBySourceKnowledgeId(directory, sourceId) {
1211
- const activeDir = path3.join(directory, ".opencode", "skills", "generated");
1542
+ const activeDir = path4.join(directory, ".opencode", "skills", "generated");
1212
1543
  const fs = await import("fs/promises");
1213
1544
  if (!existsSync2(activeDir))
1214
1545
  return [];
@@ -1217,14 +1548,14 @@ async function findSkillsBySourceKnowledgeId(directory, sourceId) {
1217
1548
  for (const e of entries) {
1218
1549
  if (!e.isDirectory())
1219
1550
  continue;
1220
- const skillDir = path3.join(activeDir, e.name);
1221
- const retiredMarker = path3.join(skillDir, "retired.marker");
1551
+ const skillDir = path4.join(activeDir, e.name);
1552
+ const retiredMarker = path4.join(skillDir, "retired.marker");
1222
1553
  if (existsSync2(retiredMarker))
1223
1554
  continue;
1224
- const staleMarker = path3.join(skillDir, "stale.marker");
1555
+ const staleMarker = path4.join(skillDir, "stale.marker");
1225
1556
  if (existsSync2(staleMarker))
1226
1557
  continue;
1227
- const skillPath = path3.join(skillDir, "SKILL.md");
1558
+ const skillPath = path4.join(skillDir, "SKILL.md");
1228
1559
  if (!existsSync2(skillPath))
1229
1560
  continue;
1230
1561
  let content;
@@ -1241,7 +1572,7 @@ async function findSkillsBySourceKnowledgeId(directory, sourceId) {
1241
1572
  return matches;
1242
1573
  }
1243
1574
  async function findStaleSkillsBySourceKnowledgeId(directory, archivedIds) {
1244
- const activeDir = path3.join(directory, ".opencode", "skills", "generated");
1575
+ const activeDir = path4.join(directory, ".opencode", "skills", "generated");
1245
1576
  if (!existsSync2(activeDir))
1246
1577
  return [];
1247
1578
  const fs = await import("fs/promises");
@@ -1250,14 +1581,14 @@ async function findStaleSkillsBySourceKnowledgeId(directory, archivedIds) {
1250
1581
  for (const e of entries) {
1251
1582
  if (!e.isDirectory())
1252
1583
  continue;
1253
- const skillDir = path3.join(activeDir, e.name);
1254
- const retiredMarker = path3.join(skillDir, "retired.marker");
1584
+ const skillDir = path4.join(activeDir, e.name);
1585
+ const retiredMarker = path4.join(skillDir, "retired.marker");
1255
1586
  if (existsSync2(retiredMarker))
1256
1587
  continue;
1257
- const staleMarker = path3.join(skillDir, "stale.marker");
1588
+ const staleMarker = path4.join(skillDir, "stale.marker");
1258
1589
  if (!existsSync2(staleMarker))
1259
1590
  continue;
1260
- const skillPath = path3.join(skillDir, "SKILL.md");
1591
+ const skillPath = path4.join(skillDir, "SKILL.md");
1261
1592
  if (!existsSync2(skillPath))
1262
1593
  continue;
1263
1594
  let content;
@@ -1283,8 +1614,8 @@ async function listSkills(directory) {
1283
1614
  active: [],
1284
1615
  stale: []
1285
1616
  };
1286
- const proposalsDir = path3.join(directory, ".swarm", "skills", "proposals");
1287
- const activeDir = path3.join(directory, ".opencode", "skills", "generated");
1617
+ const proposalsDir = path4.join(directory, ".swarm", "skills", "proposals");
1618
+ const activeDir = path4.join(directory, ".opencode", "skills", "generated");
1288
1619
  const fs = await import("fs/promises");
1289
1620
  if (existsSync2(proposalsDir)) {
1290
1621
  const entries = await fs.readdir(proposalsDir);
@@ -1294,7 +1625,7 @@ async function listSkills(directory) {
1294
1625
  const slug = f.replace(/\.md$/, "");
1295
1626
  result.proposals.push({
1296
1627
  slug,
1297
- path: path3.join(proposalsDir, f)
1628
+ path: path4.join(proposalsDir, f)
1298
1629
  });
1299
1630
  }
1300
1631
  }
@@ -1303,10 +1634,10 @@ async function listSkills(directory) {
1303
1634
  for (const e of entries) {
1304
1635
  if (!e.isDirectory())
1305
1636
  continue;
1306
- const retiredMarker = path3.join(activeDir, e.name, "retired.marker");
1637
+ const retiredMarker = path4.join(activeDir, e.name, "retired.marker");
1307
1638
  if (existsSync2(retiredMarker))
1308
1639
  continue;
1309
- const staleMarker = path3.join(activeDir, e.name, "stale.marker");
1640
+ const staleMarker = path4.join(activeDir, e.name, "stale.marker");
1310
1641
  if (existsSync2(staleMarker)) {
1311
1642
  let reason = "stale";
1312
1643
  try {
@@ -1316,7 +1647,7 @@ async function listSkills(directory) {
1316
1647
  result.stale.push({ slug: e.name, reason });
1317
1648
  continue;
1318
1649
  }
1319
- const skillPath = path3.join(activeDir, e.name, "SKILL.md");
1650
+ const skillPath = path4.join(activeDir, e.name, "SKILL.md");
1320
1651
  if (existsSync2(skillPath)) {
1321
1652
  result.active.push({
1322
1653
  slug: e.name,
@@ -1341,7 +1672,7 @@ async function autoApplyProposals(directory, llmDelegate) {
1341
1672
  }
1342
1673
  let content;
1343
1674
  try {
1344
- content = await readFile3(proposal.path, "utf-8");
1675
+ content = await readFile4(proposal.path, "utf-8");
1345
1676
  } catch {
1346
1677
  result.skipped.push(proposal.slug);
1347
1678
  continue;
@@ -1407,7 +1738,7 @@ async function inspectSkill(directory, slug, prefer = "auto") {
1407
1738
  candidates.push({ p: proposalPath(directory, cleanSlug), m: "draft" });
1408
1739
  for (const c of candidates) {
1409
1740
  if (existsSync2(c.p)) {
1410
- const content = await readFile3(c.p, "utf-8");
1741
+ const content = await readFile4(c.p, "utf-8");
1411
1742
  const result = { found: true, path: c.p, content, mode: c.m };
1412
1743
  const fm = parseDraftFrontmatter(content);
1413
1744
  if (fm && fm.sourceKnowledgeIds.length > 0) {
@@ -1427,11 +1758,11 @@ async function inspectSkill(directory, slug, prefer = "auto") {
1427
1758
  });
1428
1759
  }
1429
1760
  if (c.m === "active") {
1430
- const skillDir = path3.join(directory, ".opencode", "skills", "generated", cleanSlug);
1431
- const staleMarker = path3.join(skillDir, "stale.marker");
1761
+ const skillDir = path4.join(directory, ".opencode", "skills", "generated", cleanSlug);
1762
+ const staleMarker = path4.join(skillDir, "stale.marker");
1432
1763
  if (existsSync2(staleMarker)) {
1433
1764
  try {
1434
- result.stale_reason = await readFile3(staleMarker, "utf-8");
1765
+ result.stale_reason = await readFile4(staleMarker, "utf-8");
1435
1766
  } catch {}
1436
1767
  }
1437
1768
  }
@@ -1446,7 +1777,7 @@ async function retireSkill(directory, slug, reason) {
1446
1777
  return {
1447
1778
  retired: false,
1448
1779
  path: activePath(directory, cleanSlug),
1449
- markerPath: path3.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
1780
+ markerPath: path4.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
1450
1781
  reason: "invalid slug"
1451
1782
  };
1452
1783
  }
@@ -1455,18 +1786,18 @@ async function retireSkill(directory, slug, reason) {
1455
1786
  return {
1456
1787
  retired: false,
1457
1788
  path: skillPath,
1458
- markerPath: path3.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
1789
+ markerPath: path4.join(directory, ".opencode", "skills", "generated", cleanSlug, "retired.marker"),
1459
1790
  reason: "active skill not found"
1460
1791
  };
1461
1792
  }
1462
- const markerDir = path3.join(directory, ".opencode", "skills", "generated", cleanSlug);
1463
- const markerPath = path3.join(markerDir, "retired.marker");
1793
+ const markerDir = path4.join(directory, ".opencode", "skills", "generated", cleanSlug);
1794
+ const markerPath = path4.join(markerDir, "retired.marker");
1464
1795
  const markerContent = JSON.stringify({
1465
1796
  retiredAt: new Date().toISOString(),
1466
1797
  reason: reason ?? "manual_retire"
1467
1798
  });
1468
- await mkdir3(markerDir, { recursive: true });
1469
- await writeFile3(markerPath, markerContent, "utf-8");
1799
+ await mkdir4(markerDir, { recursive: true });
1800
+ await writeFile4(markerPath, markerContent, "utf-8");
1470
1801
  let clearedLinks = [];
1471
1802
  try {
1472
1803
  clearedLinks = await clearRetiredSkillLinks(directory, skillPath, cleanSlug);
@@ -1490,7 +1821,7 @@ async function clearRetiredSkillLinks(directory, skillFilePath, slug) {
1490
1821
  async function clearSkillLinks(directory, skillFilePath, slug, mode) {
1491
1822
  let content;
1492
1823
  try {
1493
- content = await readFile3(skillFilePath, "utf-8");
1824
+ content = await readFile4(skillFilePath, "utf-8");
1494
1825
  } catch (err) {
1495
1826
  warn(`[skill-generator] clearSkillLinks: failed to read '${skillFilePath}' for slug '${slug}': ${err instanceof Error ? err.message : String(err)}`);
1496
1827
  return [];
@@ -1555,11 +1886,11 @@ async function clearSkillLinks(directory, skillFilePath, slug, mode) {
1555
1886
  return cleared;
1556
1887
  }
1557
1888
  async function markSkillStale(skillDir, reason) {
1558
- await mkdir3(skillDir, { recursive: true });
1559
- await writeFile3(path3.join(skillDir, "stale.marker"), reason, "utf-8");
1889
+ await mkdir4(skillDir, { recursive: true });
1890
+ await writeFile4(path4.join(skillDir, "stale.marker"), reason, "utf-8");
1560
1891
  }
1561
1892
  async function clearSkillStale(skillDir) {
1562
- const markerPath = path3.join(skillDir, "stale.marker");
1893
+ const markerPath = path4.join(skillDir, "stale.marker");
1563
1894
  try {
1564
1895
  await unlink(markerPath);
1565
1896
  } catch (err) {
@@ -1571,10 +1902,10 @@ async function clearSkillStale(skillDir) {
1571
1902
  }
1572
1903
  async function retireOrMarkStale(directory, skillDir, archivedKnowledgeIds) {
1573
1904
  const fs = await import("fs/promises");
1574
- const skillPath = path3.join(skillDir, "SKILL.md");
1905
+ const skillPath = path4.join(skillDir, "SKILL.md");
1575
1906
  if (!existsSync2(skillPath)) {
1576
1907
  await markSkillStale(skillDir, "source knowledge archived, SKILL.md missing");
1577
- const slug2 = path3.basename(skillDir);
1908
+ const slug2 = path4.basename(skillDir);
1578
1909
  return { action: "stale", slug: slug2, skillDir };
1579
1910
  }
1580
1911
  let content;
@@ -1582,18 +1913,18 @@ async function retireOrMarkStale(directory, skillDir, archivedKnowledgeIds) {
1582
1913
  content = await fs.readFile(skillPath, "utf-8");
1583
1914
  } catch {
1584
1915
  await markSkillStale(skillDir, "source knowledge archived, SKILL.md unreadable");
1585
- const slug2 = path3.basename(skillDir);
1916
+ const slug2 = path4.basename(skillDir);
1586
1917
  return { action: "stale", slug: slug2, skillDir };
1587
1918
  }
1588
1919
  const fm = parseDraftFrontmatter(content);
1589
1920
  const sourceIds = fm?.sourceKnowledgeIds ?? [];
1590
1921
  if (sourceIds.length === 0) {
1591
1922
  await markSkillStale(skillDir, "source knowledge archived, no source_knowledge_ids in frontmatter");
1592
- const slug2 = path3.basename(skillDir);
1923
+ const slug2 = path4.basename(skillDir);
1593
1924
  return { action: "stale", slug: slug2, skillDir };
1594
1925
  }
1595
1926
  const allArchived = sourceIds.every((id) => archivedKnowledgeIds.has(id));
1596
- const slug = path3.basename(skillDir);
1927
+ const slug = path4.basename(skillDir);
1597
1928
  if (allArchived) {
1598
1929
  await retireSkill(directory, slug, "all source knowledge entries archived or deleted");
1599
1930
  return { action: "retire", slug, skillDir };
@@ -1623,7 +1954,7 @@ async function regenerateSkill(directory, slug, options = {}) {
1623
1954
  }
1624
1955
  let existingContent;
1625
1956
  try {
1626
- existingContent = await readFile3(skillPath, "utf-8");
1957
+ existingContent = await readFile4(skillPath, "utf-8");
1627
1958
  } catch (err) {
1628
1959
  return {
1629
1960
  regenerated: false,
@@ -1762,7 +2093,7 @@ async function regenerateSkill(directory, slug, options = {}) {
1762
2093
  try {
1763
2094
  await atomicWrite2(skillPath, content);
1764
2095
  await stampSourceEntries(directory, cleanSlug, matchedEntries.map((e) => e.id));
1765
- await clearSkillStale(path3.dirname(activePath(directory, cleanSlug)));
2096
+ await clearSkillStale(path4.dirname(activePath(directory, cleanSlug)));
1766
2097
  } catch (writeErr) {
1767
2098
  return {
1768
2099
  regenerated: false,
@@ -1815,4 +2146,4 @@ var _internals = {
1815
2146
  clearRetiredSkillLinks
1816
2147
  };
1817
2148
 
1818
- export { appendSkillChangelog, evaluateSkillChange, appendRejectedSkillEdit, sanitizeSlug, isValidSlug2 as isValidSlug, proposalPath, activePath, activeRepoRelativePath, proposalRepoRelativePath, generateEvalStub, writeEvalStub, DEFAULT_SKILL_MIN_CONFIDENCE, DEFAULT_SKILL_MIN_CONFIRMATIONS, STRONG_SKILL_OUTCOME_COUNT, HIGH_PRIORITY_SKILL_MIN_CONFIDENCE, selectCandidateEntries, isSkillMaturityEligible, clusterEntries, buildKnowledgeCluster, renderSkillMarkdown, generateSkills, parseDraftFrontmatter, activateProposal, findSkillsBySourceKnowledgeId, findStaleSkillsBySourceKnowledgeId, listSkills, autoApplyProposals, inspectSkill, retireSkill, clearDraftSkillLinks, clearRetiredSkillLinks, markSkillStale, clearSkillStale, retireOrMarkStale, regenerateSkill, _internals };
2149
+ export { getDeferredWarnings, BUNDLED_PROJECT_SKILL_ROOT, bundledProjectSkillFileReference, syncBundledProjectSkillsIfMissingAsync, appendSkillChangelog, evaluateSkillChange, appendRejectedSkillEdit, sanitizeSlug, isValidSlug2 as isValidSlug, proposalPath, activePath, activeRepoRelativePath, proposalRepoRelativePath, generateEvalStub, writeEvalStub, DEFAULT_SKILL_MIN_CONFIDENCE, DEFAULT_SKILL_MIN_CONFIRMATIONS, STRONG_SKILL_OUTCOME_COUNT, HIGH_PRIORITY_SKILL_MIN_CONFIDENCE, selectCandidateEntries, isSkillMaturityEligible, clusterEntries, buildKnowledgeCluster, renderSkillMarkdown, generateSkills, parseDraftFrontmatter, activateProposal, findSkillsBySourceKnowledgeId, findStaleSkillsBySourceKnowledgeId, listSkills, autoApplyProposals, inspectSkill, retireSkill, clearDraftSkillLinks, clearRetiredSkillLinks, markSkillStale, clearSkillStale, retireOrMarkStale, regenerateSkill, _internals };