skilld 1.7.4 → 2.0.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 (156) hide show
  1. package/dist/_chunks/add.mjs +66 -0
  2. package/dist/_chunks/add.mjs.map +1 -0
  3. package/dist/_chunks/agent-prompt.mjs +88 -0
  4. package/dist/_chunks/agent-prompt.mjs.map +1 -0
  5. package/dist/_chunks/agent.mjs +81 -57
  6. package/dist/_chunks/agent.mjs.map +1 -1
  7. package/dist/_chunks/args.mjs +42 -0
  8. package/dist/_chunks/args.mjs.map +1 -0
  9. package/dist/_chunks/assemble.mjs +10 -7
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +33 -17
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +143 -183
  14. package/dist/_chunks/cache.mjs.map +1 -1
  15. package/dist/_chunks/cache2.mjs +7 -6
  16. package/dist/_chunks/cache2.mjs.map +1 -1
  17. package/dist/_chunks/client.mjs +117 -0
  18. package/dist/_chunks/client.mjs.map +1 -0
  19. package/dist/_chunks/core.mjs +5 -5
  20. package/dist/_chunks/detect.mjs +53 -43
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/eject.mjs +69 -0
  23. package/dist/_chunks/eject.mjs.map +1 -0
  24. package/dist/_chunks/embedding-cache2.mjs +1 -1
  25. package/dist/_chunks/env.mjs +19 -0
  26. package/dist/_chunks/env.mjs.map +1 -0
  27. package/dist/_chunks/install-many.mjs +376 -0
  28. package/dist/_chunks/install-many.mjs.map +1 -0
  29. package/dist/_chunks/install.mjs +81 -326
  30. package/dist/_chunks/install.mjs.map +1 -1
  31. package/dist/_chunks/intro.mjs +63 -0
  32. package/dist/_chunks/intro.mjs.map +1 -0
  33. package/dist/_chunks/list.mjs +2 -2
  34. package/dist/_chunks/list.mjs.map +1 -1
  35. package/dist/_chunks/lockfile.mjs +3 -2
  36. package/dist/_chunks/lockfile.mjs.map +1 -1
  37. package/dist/_chunks/login.mjs +233 -0
  38. package/dist/_chunks/login.mjs.map +1 -0
  39. package/dist/_chunks/logout.mjs +27 -0
  40. package/dist/_chunks/logout.mjs.map +1 -0
  41. package/dist/_chunks/map.mjs +11 -0
  42. package/dist/_chunks/map.mjs.map +1 -0
  43. package/dist/_chunks/markdown.mjs +79 -54
  44. package/dist/_chunks/markdown.mjs.map +1 -1
  45. package/dist/_chunks/menu.mjs +33 -0
  46. package/dist/_chunks/menu.mjs.map +1 -0
  47. package/dist/_chunks/model-picker.mjs +61 -0
  48. package/dist/_chunks/model-picker.mjs.map +1 -0
  49. package/dist/_chunks/monorepo.mjs +4 -2
  50. package/dist/_chunks/monorepo.mjs.map +1 -1
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +3 -5
  53. package/dist/_chunks/paths.mjs.map +1 -1
  54. package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +1 -1
  57. package/dist/_chunks/portable.mjs +151 -0
  58. package/dist/_chunks/portable.mjs.map +1 -0
  59. package/dist/_chunks/prepare-hook.mjs +2 -0
  60. package/dist/_chunks/prepare-hook2.mjs +61 -0
  61. package/dist/_chunks/prepare-hook2.mjs.map +1 -0
  62. package/dist/_chunks/prepare.mjs +47 -3
  63. package/dist/_chunks/prepare.mjs.map +1 -1
  64. package/dist/_chunks/prepare2.mjs +7 -6
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +484 -74
  67. package/dist/_chunks/prompts.mjs.map +1 -1
  68. package/dist/_chunks/pull.mjs +219 -0
  69. package/dist/_chunks/pull.mjs.map +1 -0
  70. package/dist/_chunks/regex.mjs +19 -0
  71. package/dist/_chunks/regex.mjs.map +1 -0
  72. package/dist/_chunks/retriv.mjs +2 -171
  73. package/dist/_chunks/retriv2.mjs +159 -0
  74. package/dist/_chunks/retriv2.mjs.map +1 -0
  75. package/dist/_chunks/sanitize.mjs +12 -9
  76. package/dist/_chunks/sanitize.mjs.map +1 -1
  77. package/dist/_chunks/search-helpers.mjs +8 -6
  78. package/dist/_chunks/search-helpers.mjs.map +1 -1
  79. package/dist/_chunks/search-interactive.mjs +23 -20
  80. package/dist/_chunks/search-interactive.mjs.map +1 -1
  81. package/dist/_chunks/search.mjs +3 -3
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/semver.mjs +2755 -1
  84. package/dist/_chunks/semver.mjs.map +1 -1
  85. package/dist/_chunks/skill-installer2.mjs +10 -11
  86. package/dist/_chunks/skill-installer2.mjs.map +1 -1
  87. package/dist/_chunks/skills.mjs +6 -7
  88. package/dist/_chunks/skills.mjs.map +1 -1
  89. package/dist/_chunks/store.mjs +107 -0
  90. package/dist/_chunks/store.mjs.map +1 -0
  91. package/dist/_chunks/sync.mjs +411 -910
  92. package/dist/_chunks/sync.mjs.map +1 -1
  93. package/dist/_chunks/sync2.mjs +2 -5
  94. package/dist/_chunks/telemetry.mjs +26 -0
  95. package/dist/_chunks/telemetry.mjs.map +1 -0
  96. package/dist/_chunks/uninstall.mjs +12 -9
  97. package/dist/_chunks/uninstall.mjs.map +1 -1
  98. package/dist/_chunks/update.mjs +171 -0
  99. package/dist/_chunks/update.mjs.map +1 -0
  100. package/dist/_chunks/upload.mjs +3 -3
  101. package/dist/_chunks/validate.mjs +1 -1
  102. package/dist/_chunks/version.mjs +16 -17
  103. package/dist/_chunks/version.mjs.map +1 -1
  104. package/dist/_chunks/whoami.mjs +21 -0
  105. package/dist/_chunks/whoami.mjs.map +1 -0
  106. package/dist/_chunks/wizard.mjs +2 -190
  107. package/dist/_chunks/wizard2.mjs +200 -0
  108. package/dist/_chunks/wizard2.mjs.map +1 -0
  109. package/dist/cli.mjs +72 -53
  110. package/dist/cli.mjs.map +1 -1
  111. package/dist/prepare.mjs +4 -3
  112. package/dist/prepare.mjs.map +1 -1
  113. package/dist/retriv/worker.d.mts +5 -1
  114. package/dist/retriv/worker.d.mts.map +1 -1
  115. package/dist/retriv/worker.mjs +1 -1
  116. package/package.json +19 -28
  117. package/dist/_chunks/author-group.mjs +0 -17
  118. package/dist/_chunks/author-group.mjs.map +0 -1
  119. package/dist/_chunks/cli-helpers.mjs +0 -335
  120. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  121. package/dist/_chunks/cli-helpers2.mjs +0 -2
  122. package/dist/_chunks/index.d.mts +0 -344
  123. package/dist/_chunks/index.d.mts.map +0 -1
  124. package/dist/_chunks/index2.d.mts +0 -279
  125. package/dist/_chunks/index2.d.mts.map +0 -1
  126. package/dist/_chunks/index3.d.mts +0 -44
  127. package/dist/_chunks/index3.d.mts.map +0 -1
  128. package/dist/_chunks/index4.d.mts +0 -553
  129. package/dist/_chunks/index4.d.mts.map +0 -1
  130. package/dist/_chunks/package-registry.mjs +0 -465
  131. package/dist/_chunks/package-registry.mjs.map +0 -1
  132. package/dist/_chunks/retriv.mjs.map +0 -1
  133. package/dist/_chunks/setup.mjs +0 -17
  134. package/dist/_chunks/setup.mjs.map +0 -1
  135. package/dist/_chunks/sources.mjs +0 -2654
  136. package/dist/_chunks/sources.mjs.map +0 -1
  137. package/dist/_chunks/sync-pipeline.mjs.map +0 -1
  138. package/dist/_chunks/sync-registry.mjs +0 -65
  139. package/dist/_chunks/sync-registry.mjs.map +0 -1
  140. package/dist/_chunks/types.d.mts +0 -76
  141. package/dist/_chunks/types.d.mts.map +0 -1
  142. package/dist/_chunks/types2.d.mts +0 -88
  143. package/dist/_chunks/types2.d.mts.map +0 -1
  144. package/dist/_chunks/wizard.mjs.map +0 -1
  145. package/dist/agent/index.d.mts +0 -2
  146. package/dist/agent/index.mjs +0 -4
  147. package/dist/cache/index.d.mts +0 -2
  148. package/dist/cache/index.mjs +0 -5
  149. package/dist/index.d.mts +0 -6
  150. package/dist/index.mjs +0 -6
  151. package/dist/retriv/index.d.mts +0 -3
  152. package/dist/retriv/index.mjs +0 -2
  153. package/dist/sources/index.d.mts +0 -3
  154. package/dist/sources/index.mjs +0 -3
  155. package/dist/types.d.mts +0 -4
  156. package/dist/types.mjs +0 -1
@@ -1,11 +1,10 @@
1
- import { l as getPackageDbPath, n as CONFIG_PATH, o as REFERENCES_DIR, p as skillInternalDir, s as REPOS_DIR, t as CACHE_DIR, u as getRepoCacheDir } from "./paths.mjs";
2
- import { n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./yaml.mjs";
3
- import { i as readPackageJsonSafe } from "./package-json.mjs";
4
- import { r as getVersionKey, t as getCacheDir } from "./version.mjs";
5
- import { r as resolvePkgDir } from "./prepare.mjs";
1
+ import { c as REPOS_DIR, d as getRepoCacheDir, m as skillInternalDir, n as CACHE_DIR, r as CONFIG_PATH, s as REFERENCES_DIR, u as getPackageDbPath } from "./paths.mjs";
6
2
  import { n as sanitizeMarkdown } from "./sanitize.mjs";
3
+ import { n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./yaml.mjs";
4
+ import { a as resolvePkgDir, c as getVersionKey, r as hasShippedDocs, s as getCacheDir, t as getPkgKeyFiles } from "./prepare.mjs";
7
5
  import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
8
- import { basename, dirname, join, resolve } from "pathe";
6
+ import { dirname, join, resolve } from "pathe";
7
+ const STATIC_REGEX_1$1 = /^ {2}(\w+):\s*(.+)/;
9
8
  const defaultFeatures = {
10
9
  search: true,
11
10
  issues: true,
@@ -61,7 +60,7 @@ function readConfig() {
61
60
  inBlock = null;
62
61
  }
63
62
  if (inBlock === "features") {
64
- const m = line.match(/^ {2}(\w+):\s*(.+)/);
63
+ const m = line.match(STATIC_REGEX_1$1);
65
64
  if (m) {
66
65
  const key = m[1];
67
66
  if (key in defaultFeatures) features[key] = m[2] === "true";
@@ -130,31 +129,15 @@ function unregisterProject(projectPath) {
130
129
  function getRegisteredProjects() {
131
130
  return readConfig().projects || [];
132
131
  }
133
- function getSkillReferenceDirs(skillDir) {
134
- const refsDir = skillInternalDir(skillDir);
135
- if (!existsSync(refsDir)) return [];
136
- const resolved = readdirSync(refsDir).map((entry) => join(refsDir, entry)).filter((p) => lstatSync(p).isSymbolicLink() && existsSync(p)).map((p) => realpathSync(p));
137
- const parents = /* @__PURE__ */ new Set();
138
- for (const p of resolved) {
139
- const parent = dirname(p);
140
- if (!resolved.includes(parent)) parents.add(parent);
141
- }
142
- return [...resolved, ...parents];
143
- }
144
- function clearSkillInternalDir(skillDir) {
145
- const refsDir = skillInternalDir(skillDir);
146
- if (existsSync(refsDir)) rmSync(refsDir, {
147
- recursive: true,
148
- force: true
149
- });
150
- }
132
+ const STATIC_REGEX_1 = /^issues\/issue-(\d+)\.md$/;
133
+ const STATIC_REGEX_2 = /^discussions\/discussion-(\d+)\.md$/;
151
134
  function classifyCachedDoc(path) {
152
- const issueMatch = path.match(/^issues\/issue-(\d+)\.md$/);
135
+ const issueMatch = path.match(STATIC_REGEX_1);
153
136
  if (issueMatch) return {
154
137
  type: "issue",
155
138
  number: Number(issueMatch[1])
156
139
  };
157
- const discussionMatch = path.match(/^discussions\/discussion-(\d+)\.md$/);
140
+ const discussionMatch = path.match(STATIC_REGEX_2);
158
141
  if (discussionMatch) return {
159
142
  type: "discussion",
160
143
  number: Number(discussionMatch[1])
@@ -162,118 +145,6 @@ function classifyCachedDoc(path) {
162
145
  if (path.startsWith("releases/")) return { type: "release" };
163
146
  return { type: "doc" };
164
147
  }
165
- function forceClearCache(packageName, version, repoInfo) {
166
- clearCache(packageName, version);
167
- const forcedDbPath = getPackageDbPath(packageName, version);
168
- if (existsSync(forcedDbPath)) rmSync(forcedDbPath, {
169
- recursive: true,
170
- force: true
171
- });
172
- if (repoInfo) {
173
- const repoDir = getRepoCacheDir(repoInfo.owner, repoInfo.repo);
174
- if (existsSync(repoDir)) rmSync(repoDir, {
175
- recursive: true,
176
- force: true
177
- });
178
- }
179
- }
180
- function linkAllReferences(skillDir, packageName, cwd, version, docsType, extraPackages, features, repoInfo) {
181
- const f = features ?? readConfig().features ?? defaultFeatures;
182
- try {
183
- linkPkg(skillDir, packageName, cwd, version);
184
- linkPkgNamed(skillDir, packageName, cwd, version);
185
- if (!hasShippedDocs(packageName, cwd, version) && docsType !== "readme") linkCachedDir(skillDir, packageName, version, "docs");
186
- if (f.issues) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "issues");
187
- else linkCachedDir(skillDir, packageName, version, "issues");
188
- if (f.discussions) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "discussions");
189
- else linkCachedDir(skillDir, packageName, version, "discussions");
190
- if (f.releases) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "releases");
191
- else linkCachedDir(skillDir, packageName, version, "releases");
192
- linkCachedDir(skillDir, packageName, version, "sections");
193
- if (extraPackages) {
194
- for (const pkg of extraPackages) if (pkg.name !== packageName) linkPkgNamed(skillDir, pkg.name, cwd, pkg.version);
195
- }
196
- } catch {}
197
- }
198
- function detectDocsType(packageName, version, repoUrl, llmsUrl) {
199
- const cacheDir = getCacheDir(packageName, version);
200
- if (existsSync(join(cacheDir, "docs", "index.md")) || existsSync(join(cacheDir, "docs", "guide"))) return {
201
- docsType: "docs",
202
- docSource: repoUrl ? `${repoUrl}/tree/v${version}/docs` : "git"
203
- };
204
- if (existsSync(join(cacheDir, "llms.txt"))) return {
205
- docsType: "llms.txt",
206
- docSource: llmsUrl || "llms.txt"
207
- };
208
- if (existsSync(join(cacheDir, "docs", "README.md"))) return { docsType: "readme" };
209
- return { docsType: "readme" };
210
- }
211
- function ejectReferences(skillDir, packageName, cwd, version, docsType, features, repoInfo) {
212
- const f = features ?? readConfig().features ?? defaultFeatures;
213
- const cacheDir = getCacheDir(packageName, version);
214
- const refsDir = join(skillDir, "references");
215
- const repoDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : cacheDir;
216
- if (!hasShippedDocs(packageName, cwd, version) && docsType !== "readme") copyCachedSubdir(cacheDir, refsDir, "docs");
217
- if (f.issues) copyCachedSubdir(repoDir, refsDir, "issues");
218
- if (f.discussions) copyCachedSubdir(repoDir, refsDir, "discussions");
219
- if (f.releases) copyCachedSubdir(repoDir, refsDir, "releases");
220
- }
221
- function copyCachedSubdir(cacheDir, refsDir, subdir) {
222
- const srcDir = join(cacheDir, subdir);
223
- if (!existsSync(srcDir)) return;
224
- const destDir = join(refsDir, subdir);
225
- mkdirSync(destDir, { recursive: true });
226
- function walk(dir, rel) {
227
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
228
- const srcPath = join(dir, entry.name);
229
- const destPath = join(destDir, rel ? `${rel}/${entry.name}` : entry.name);
230
- if (entry.isDirectory()) {
231
- mkdirSync(destPath, { recursive: true });
232
- walk(srcPath, rel ? `${rel}/${entry.name}` : entry.name);
233
- } else copyFileSync(srcPath, destPath);
234
- }
235
- }
236
- walk(srcDir, "");
237
- }
238
- function loadCachedReferences(opts) {
239
- const { packageName, version, repoUrl, llmsUrl, readmeUrl, onProgress, generateDocsIndex } = opts;
240
- onProgress("Loading cached docs");
241
- const detected = detectDocsType(packageName, version, repoUrl, llmsUrl);
242
- const docsType = detected.docsType;
243
- const docSource = detected.docSource ?? readmeUrl ?? "readme";
244
- const docsToIndex = [];
245
- if (!existsSync(getPackageDbPath(packageName, version))) {
246
- onProgress("Reading cached docs for indexing");
247
- const cached = readCachedDocs(packageName, version);
248
- for (const doc of cached) docsToIndex.push({
249
- id: doc.path,
250
- content: doc.content,
251
- metadata: {
252
- package: packageName,
253
- source: doc.path,
254
- ...classifyCachedDoc(doc.path)
255
- }
256
- });
257
- }
258
- let backfillIndex;
259
- if (docsType !== "readme" && !existsSync(join(getCacheDir(packageName, version), "docs", "_INDEX.md"))) {
260
- onProgress("Generating docs index");
261
- const cached = readCachedDocs(packageName, version);
262
- if (cached.filter((d) => d.path.startsWith("docs/") && d.path.endsWith(".md")).length > 1) {
263
- const docsIndex = generateDocsIndex(cached);
264
- if (docsIndex) backfillIndex = {
265
- path: "docs/_INDEX.md",
266
- content: docsIndex
267
- };
268
- }
269
- }
270
- return {
271
- docsToIndex,
272
- docSource,
273
- docsType,
274
- backfillIndex
275
- };
276
- }
277
148
  function safeSymlink(target, linkPath) {
278
149
  const resolved = resolve(target);
279
150
  if (!resolved.startsWith(REFERENCES_DIR) && !resolved.startsWith(REPOS_DIR)) throw new Error(`Symlink target outside allowed dirs: ${resolved}`);
@@ -379,22 +250,6 @@ function linkPkgNamed(skillDir, name, cwd, version) {
379
250
  } catch {}
380
251
  symlinkSync(pkgPath, linkPath, "junction");
381
252
  }
382
- function getPkgKeyFiles(name, cwd, version) {
383
- const pkgPath = resolvePkgDir(name, cwd, version);
384
- if (!pkgPath) return [];
385
- const files = [];
386
- const pkgJsonResult = readPackageJsonSafe(join(pkgPath, "package.json"));
387
- if (pkgJsonResult) {
388
- const pkg = pkgJsonResult.parsed;
389
- if (pkg.main) files.push(basename(pkg.main));
390
- if (pkg.module && pkg.module !== pkg.main) files.push(basename(pkg.module));
391
- const typesPath = pkg.types || pkg.typings;
392
- if (typesPath && existsSync(join(pkgPath, typesPath))) files.push(typesPath);
393
- }
394
- const entries = readdirSync(pkgPath).filter((f) => /^readme\.md$/i.test(f) || /^changelog\.md$/i.test(f));
395
- files.push(...entries);
396
- return [...new Set(files)];
397
- }
398
253
  function writeSections(name, version, sections) {
399
254
  const sectionsDir = join(getCacheDir(name, version), "sections");
400
255
  mkdirSync(sectionsDir, {
@@ -408,27 +263,6 @@ function readCachedSection(name, version, file) {
408
263
  if (!existsSync(path)) return null;
409
264
  return readFileSync(path, "utf-8");
410
265
  }
411
- function hasShippedDocs(name, cwd, version) {
412
- const pkgPath = resolvePkgDir(name, cwd, version);
413
- if (!pkgPath) return false;
414
- for (const candidate of [
415
- "docs",
416
- "documentation",
417
- "doc"
418
- ]) if (existsSync(join(pkgPath, candidate))) return true;
419
- return false;
420
- }
421
- function listCached() {
422
- if (!existsSync(REFERENCES_DIR)) return [];
423
- return readdirSync(REFERENCES_DIR).filter((name) => name.includes("@")).map((dir) => {
424
- const atIdx = dir.lastIndexOf("@");
425
- return {
426
- name: dir.slice(0, atIdx),
427
- version: dir.slice(atIdx + 1),
428
- dir: join(REFERENCES_DIR, dir)
429
- };
430
- });
431
- }
432
266
  function readCachedDocs(name, version) {
433
267
  const cacheDir = getCacheDir(name, version);
434
268
  if (!existsSync(cacheDir)) return [];
@@ -453,12 +287,6 @@ function clearCache(name, version) {
453
287
  rmSync(cacheDir, { recursive: true });
454
288
  return true;
455
289
  }
456
- function clearAllCache() {
457
- const packages = listCached();
458
- for (const pkg of packages) clearCache(pkg.name, pkg.version);
459
- if (existsSync(REPOS_DIR)) rmSync(REPOS_DIR, { recursive: true });
460
- return packages.length;
461
- }
462
290
  function listReferenceFiles(skillDir, maxDepth = 3) {
463
291
  const referencesDir = skillInternalDir(skillDir);
464
292
  if (!existsSync(referencesDir)) return [];
@@ -483,6 +311,136 @@ function listReferenceFiles(skillDir, maxDepth = 3) {
483
311
  walk(referencesDir, 0);
484
312
  return files;
485
313
  }
314
+ function getSkillReferenceDirs(skillDir) {
315
+ const refsDir = skillInternalDir(skillDir);
316
+ if (!existsSync(refsDir)) return [];
317
+ const resolved = readdirSync(refsDir).map((entry) => join(refsDir, entry)).filter((p) => lstatSync(p).isSymbolicLink() && existsSync(p)).map((p) => realpathSync(p));
318
+ const parents = /* @__PURE__ */ new Set();
319
+ for (const p of resolved) {
320
+ const parent = dirname(p);
321
+ if (!resolved.includes(parent)) parents.add(parent);
322
+ }
323
+ return [...resolved, ...parents];
324
+ }
325
+ function clearSkillInternalDir(skillDir) {
326
+ const refsDir = skillInternalDir(skillDir);
327
+ if (existsSync(refsDir)) rmSync(refsDir, {
328
+ recursive: true,
329
+ force: true
330
+ });
331
+ }
332
+ function forceClearCache(packageName, version, repoInfo) {
333
+ clearCache(packageName, version);
334
+ const forcedDbPath = getPackageDbPath(packageName, version);
335
+ if (existsSync(forcedDbPath)) rmSync(forcedDbPath, {
336
+ recursive: true,
337
+ force: true
338
+ });
339
+ if (repoInfo) {
340
+ const repoDir = getRepoCacheDir(repoInfo.owner, repoInfo.repo);
341
+ if (existsSync(repoDir)) rmSync(repoDir, {
342
+ recursive: true,
343
+ force: true
344
+ });
345
+ }
346
+ }
347
+ function linkAllReferences(skillDir, packageName, cwd, version, docsType, extraPackages, features, repoInfo) {
348
+ const f = features ?? readConfig().features ?? defaultFeatures;
349
+ try {
350
+ linkPkg(skillDir, packageName, cwd, version);
351
+ linkPkgNamed(skillDir, packageName, cwd, version);
352
+ if (!hasShippedDocs(packageName, cwd, version) && docsType !== "readme") linkCachedDir(skillDir, packageName, version, "docs");
353
+ if (f.issues) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "issues");
354
+ else linkCachedDir(skillDir, packageName, version, "issues");
355
+ if (f.discussions) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "discussions");
356
+ else linkCachedDir(skillDir, packageName, version, "discussions");
357
+ if (f.releases) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "releases");
358
+ else linkCachedDir(skillDir, packageName, version, "releases");
359
+ linkCachedDir(skillDir, packageName, version, "sections");
360
+ if (extraPackages) {
361
+ for (const pkg of extraPackages) if (pkg.name !== packageName) linkPkgNamed(skillDir, pkg.name, cwd, pkg.version);
362
+ }
363
+ } catch {}
364
+ }
365
+ function detectDocsType(packageName, version, repoUrl, llmsUrl) {
366
+ const cacheDir = getCacheDir(packageName, version);
367
+ if (existsSync(join(cacheDir, "docs", "index.md")) || existsSync(join(cacheDir, "docs", "guide"))) return {
368
+ docsType: "docs",
369
+ docSource: repoUrl ? `${repoUrl}/tree/v${version}/docs` : "git"
370
+ };
371
+ if (existsSync(join(cacheDir, "llms.txt"))) return {
372
+ docsType: "llms.txt",
373
+ docSource: llmsUrl || "llms.txt"
374
+ };
375
+ if (existsSync(join(cacheDir, "docs", "README.md"))) return { docsType: "readme" };
376
+ return { docsType: "readme" };
377
+ }
378
+ function ejectReferences(skillDir, packageName, cwd, version, docsType, features, repoInfo) {
379
+ const f = features ?? readConfig().features ?? defaultFeatures;
380
+ const cacheDir = getCacheDir(packageName, version);
381
+ const refsDir = join(skillDir, "references");
382
+ const repoDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : cacheDir;
383
+ if (!hasShippedDocs(packageName, cwd, version) && docsType !== "readme") copyCachedSubdir(cacheDir, refsDir, "docs");
384
+ if (f.issues) copyCachedSubdir(repoDir, refsDir, "issues");
385
+ if (f.discussions) copyCachedSubdir(repoDir, refsDir, "discussions");
386
+ if (f.releases) copyCachedSubdir(repoDir, refsDir, "releases");
387
+ }
388
+ function copyCachedSubdir(cacheDir, refsDir, subdir) {
389
+ const srcDir = join(cacheDir, subdir);
390
+ if (!existsSync(srcDir)) return;
391
+ const destDir = join(refsDir, subdir);
392
+ mkdirSync(destDir, { recursive: true });
393
+ function walk(dir, rel) {
394
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
395
+ const srcPath = join(dir, entry.name);
396
+ const destPath = join(destDir, rel ? `${rel}/${entry.name}` : entry.name);
397
+ if (entry.isDirectory()) {
398
+ mkdirSync(destPath, { recursive: true });
399
+ walk(srcPath, rel ? `${rel}/${entry.name}` : entry.name);
400
+ } else copyFileSync(srcPath, destPath);
401
+ }
402
+ }
403
+ walk(srcDir, "");
404
+ }
405
+ function loadCachedReferences(opts) {
406
+ const { packageName, version, repoUrl, llmsUrl, readmeUrl, onProgress, generateDocsIndex } = opts;
407
+ onProgress("Loading cached docs");
408
+ const detected = detectDocsType(packageName, version, repoUrl, llmsUrl);
409
+ const docsType = detected.docsType;
410
+ const docSource = detected.docSource ?? readmeUrl ?? "readme";
411
+ const docsToIndex = [];
412
+ if (!existsSync(getPackageDbPath(packageName, version))) {
413
+ onProgress("Reading cached docs for indexing");
414
+ const cached = readCachedDocs(packageName, version);
415
+ for (const doc of cached) docsToIndex.push({
416
+ id: doc.path,
417
+ content: doc.content,
418
+ metadata: {
419
+ package: packageName,
420
+ source: doc.path,
421
+ ...classifyCachedDoc(doc.path)
422
+ }
423
+ });
424
+ }
425
+ let backfillIndex;
426
+ if (docsType !== "readme" && !existsSync(join(getCacheDir(packageName, version), "docs", "_INDEX.md"))) {
427
+ onProgress("Generating docs index");
428
+ const cached = readCachedDocs(packageName, version);
429
+ if (cached.filter((d) => d.path.startsWith("docs/") && d.path.endsWith(".md")).length > 1) {
430
+ const docsIndex = generateDocsIndex(cached);
431
+ if (docsIndex) backfillIndex = {
432
+ path: "docs/_INDEX.md",
433
+ content: docsIndex
434
+ };
435
+ }
436
+ }
437
+ return {
438
+ docsToIndex,
439
+ docSource,
440
+ docsType,
441
+ backfillIndex
442
+ };
443
+ }
486
444
  function createReferenceCache(packageName, version) {
487
445
  const requireVersion = (op) => {
488
446
  if (!version) throw new Error(`ReferenceCache.${op} requires a version (package: ${packageName})`);
@@ -499,6 +457,8 @@ function createReferenceCache(packageName, version) {
499
457
  },
500
458
  ensure: () => ensureCacheDir(),
501
459
  has: () => !!version && isCached(packageName, version),
460
+ isReadmeOnly: () => isReadmeOnlyCache(getCacheDir(packageName, requireVersion("isReadmeOnly"))),
461
+ inferDocsType: (source) => inferDocsTypeFromCache(getCacheDir(packageName, requireVersion("inferDocsType")), source),
502
462
  write: (docs) => void writeToCache(packageName, requireVersion("write"), docs),
503
463
  writeSections: (sections) => writeSections(packageName, requireVersion("writeSections"), sections),
504
464
  readSection: (file) => readCachedSection(packageName, requireVersion("readSection"), file),
@@ -519,6 +479,6 @@ function createReferenceCache(packageName, version) {
519
479
  keyFiles: (cwd) => getPkgKeyFiles(packageName, cwd, version)
520
480
  };
521
481
  }
522
- export { getActiveFeatures as A, detectDocsType as C, linkAllReferences as D, getSkillReferenceDirs as E, registerProject as F, unregisterProject as I, updateConfig as L, hasCompletedWizard as M, hasConfig as N, loadCachedReferences as O, readConfig as P, clearSkillInternalDir as S, forceClearCache as T, readCachedSection as _, getPkgKeyFiles as a, writeToRepoCache as b, isCached as c, linkPkg as d, linkPkgNamed as f, readCachedDocs as g, listReferenceFiles as h, ensureCacheDir as i, getRegisteredProjects as j, defaultFeatures as k, isReadmeOnlyCache as l, listCached as m, clearAllCache as n, hasShippedDocs as o, linkRepoCachedDir as p, clearCache as r, inferDocsTypeFromCache as s, createReferenceCache as t, linkCachedDir as u, writeSections as v, ejectReferences as w, classifyCachedDoc as x, writeToCache as y };
482
+ export { writeToRepoCache as a, getRegisteredProjects as c, readConfig as d, registerProject as f, listReferenceFiles as i, hasCompletedWizard as l, updateConfig as m, getSkillReferenceDirs as n, defaultFeatures as o, unregisterProject as p, ensureCacheDir as r, getActiveFeatures as s, createReferenceCache as t, hasConfig as u };
523
483
 
524
484
  //# sourceMappingURL=cache.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.mjs","names":[],"sources":["../../src/core/config.ts","../../src/cache/references.ts","../../src/cache/storage.ts","../../src/cache/reference-cache.ts"],"sourcesContent":["import type { OptimizeModel } from '../agent/index.ts'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { CACHE_DIR, CONFIG_PATH } from './paths.ts'\nimport { yamlEscape, yamlParseKV, yamlUnescape } from './yaml.ts'\n\nexport interface FeaturesConfig {\n search: boolean\n issues: boolean\n discussions: boolean\n releases: boolean\n}\n\nexport const defaultFeatures: FeaturesConfig = {\n search: true,\n issues: true,\n discussions: true,\n releases: true,\n}\n\n/**\n * Resolve the active feature set: defaults overlaid with user config, then\n * caller-supplied overrides. Single seam so feature gating doesn't drift.\n */\nexport function getActiveFeatures(overrides?: Partial<FeaturesConfig>): FeaturesConfig {\n const fromConfig = readConfig().features\n const merged: FeaturesConfig = { ...defaultFeatures, ...(fromConfig ?? {}) }\n return overrides ? { ...merged, ...overrides } : merged\n}\n\nexport interface SkilldConfig {\n model?: OptimizeModel\n agent?: string\n features?: FeaturesConfig\n projects?: string[]\n skipLlm?: boolean\n}\n\nlet configCache: SkilldConfig | undefined\n\nexport function hasConfig(): boolean {\n return existsSync(CONFIG_PATH)\n}\n\n/** Whether the first-run wizard has been completed (not just agent selection) */\nexport function hasCompletedWizard(): boolean {\n if (!existsSync(CONFIG_PATH))\n return false\n const config = readConfig()\n return config.features !== undefined || config.model !== undefined || config.skipLlm !== undefined\n}\n\nexport function readConfig(): SkilldConfig {\n if (configCache) {\n return {\n ...configCache,\n features: configCache.features ? { ...configCache.features } : undefined,\n projects: configCache.projects ? [...configCache.projects] : undefined,\n }\n }\n if (!existsSync(CONFIG_PATH))\n return {}\n\n const content = readFileSync(CONFIG_PATH, 'utf-8')\n const config: SkilldConfig = {}\n let inBlock: 'projects' | 'features' | null = null\n const projects: string[] = []\n const features: Partial<FeaturesConfig> = {}\n\n for (const line of content.split('\\n')) {\n if (line.startsWith('projects:')) {\n inBlock = 'projects'\n continue\n }\n if (line.startsWith('features:')) {\n inBlock = 'features'\n continue\n }\n if (inBlock === 'projects') {\n if (line.startsWith(' - ')) {\n projects.push(yamlUnescape(line.slice(4)))\n continue\n }\n inBlock = null\n }\n if (inBlock === 'features') {\n const m = line.match(/^ {2}(\\w+):\\s*(.+)/)\n if (m) {\n const key = m[1] as keyof FeaturesConfig\n if (key in defaultFeatures)\n features[key] = m[2] === 'true'\n continue\n }\n inBlock = null\n }\n const kv = yamlParseKV(line)\n if (!kv)\n continue\n const [key, value] = kv\n if (key === 'model' && value)\n config.model = value as OptimizeModel\n if (key === 'agent' && value)\n config.agent = value\n if (key === 'skipLlm')\n config.skipLlm = value === 'true'\n }\n\n if (projects.length > 0)\n config.projects = projects\n if (Object.keys(features).length > 0)\n config.features = { ...defaultFeatures, ...features }\n configCache = config\n return config\n}\n\nexport function writeConfig(config: SkilldConfig): void {\n mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 })\n\n let yaml = ''\n if (config.model)\n yaml += `model: ${config.model}\\n`\n if (config.agent)\n yaml += `agent: ${config.agent}\\n`\n if (config.skipLlm)\n yaml += `skipLlm: true\\n`\n if (config.features) {\n yaml += 'features:\\n'\n for (const [k, v] of Object.entries(config.features)) {\n yaml += ` ${k}: ${v}\\n`\n }\n }\n if (config.projects?.length) {\n yaml += 'projects:\\n'\n for (const p of config.projects) {\n yaml += ` - ${yamlEscape(p)}\\n`\n }\n }\n\n writeFileSync(CONFIG_PATH, yaml, { mode: 0o600 })\n configCache = undefined\n}\n\nexport function updateConfig(updates: Partial<SkilldConfig>): void {\n const config = readConfig()\n writeConfig({ ...config, ...updates })\n}\n\nexport function registerProject(projectPath: string): void {\n const config = readConfig()\n const projects = new Set(config.projects || [])\n projects.add(projectPath)\n writeConfig({ ...config, projects: [...projects] })\n}\n\nexport function unregisterProject(projectPath: string): void {\n const config = readConfig()\n const projects = (config.projects || []).filter(p => p !== projectPath)\n writeConfig({ ...config, projects })\n}\n\nexport function getRegisteredProjects(): string[] {\n return readConfig().projects || []\n}\n","/**\n * Higher-level reference-cache operations: composition over the cache\n * primitives in `src/cache/index.ts`.\n *\n * Owns:\n * - The on-disk shape of `~/.skilld/references/<pkg>@<version>/`\n * - `.skilld/` symlinks inside agent skill dirs (linkAllReferences)\n * - Loading cached docs back as a `ResolvedContent`-shaped result\n * - Force-clearing and ejecting (portable copy) caches\n *\n * Callers (sync, sync-parallel, sync-git, install, author) should use these\n * helpers instead of touching cache primitives directly.\n */\n\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { IndexDoc } from '../sources/content-resolver.ts'\nimport { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, rmSync } from 'node:fs'\nimport { dirname, join } from 'pathe'\nimport { defaultFeatures, readConfig } from '../core/config.ts'\nimport { skillInternalDir } from '../core/paths.ts'\nimport {\n clearCache,\n getCacheDir,\n getPackageDbPath,\n getRepoCacheDir,\n hasShippedDocs,\n linkCachedDir,\n linkPkg,\n linkPkgNamed,\n linkRepoCachedDir,\n readCachedDocs,\n} from './index.ts'\n\n/**\n * Resolve every symlink under `<skillDir>/.skilld/` to its real path, plus\n * the parent dirs CLI sandboxes need (e.g. Gemini). What an LLM CLI passes to\n * `--add-dir` to make references readable.\n */\nexport function getSkillReferenceDirs(skillDir: string): string[] {\n const refsDir = skillInternalDir(skillDir)\n if (!existsSync(refsDir))\n return []\n const resolved = readdirSync(refsDir)\n .map(entry => join(refsDir, entry))\n .filter(p => lstatSync(p).isSymbolicLink() && existsSync(p))\n .map(p => realpathSync(p))\n\n const parents = new Set<string>()\n for (const p of resolved) {\n const parent = dirname(p)\n if (!resolved.includes(parent))\n parents.add(parent)\n }\n\n return [...resolved, ...parents]\n}\n\n/**\n * Remove the transient `<skillDir>/.skilld/` symlink dir. Used after eject to\n * clean up references that have been copied as real files.\n */\nexport function clearSkillInternalDir(skillDir: string): void {\n const refsDir = skillInternalDir(skillDir)\n if (existsSync(refsDir))\n rmSync(refsDir, { recursive: true, force: true })\n}\n\n/** Classify a cached doc path into the right metadata type */\nexport function classifyCachedDoc(path: string): { type: string, number?: number } {\n const issueMatch = path.match(/^issues\\/issue-(\\d+)\\.md$/)\n if (issueMatch)\n return { type: 'issue', number: Number(issueMatch[1]) }\n const discussionMatch = path.match(/^discussions\\/discussion-(\\d+)\\.md$/)\n if (discussionMatch)\n return { type: 'discussion', number: Number(discussionMatch[1]) }\n if (path.startsWith('releases/'))\n return { type: 'release' }\n return { type: 'doc' }\n}\n\n/** Clear cache + db for --force flag */\nexport function forceClearCache(packageName: string, version: string, repoInfo?: { owner: string, repo: string }): void {\n clearCache(packageName, version)\n const forcedDbPath = getPackageDbPath(packageName, version)\n if (existsSync(forcedDbPath))\n rmSync(forcedDbPath, { recursive: true, force: true })\n // Also clear repo-level cache when force is used\n if (repoInfo) {\n const repoDir = getRepoCacheDir(repoInfo.owner, repoInfo.repo)\n if (existsSync(repoDir))\n rmSync(repoDir, { recursive: true, force: true })\n }\n}\n\n/** Link all reference symlinks (pkg, docs, issues, discussions, releases) */\nexport function linkAllReferences(skillDir: string, packageName: string, cwd: string, version: string, docsType: string, extraPackages?: Array<{ name: string, version?: string }>, features?: FeaturesConfig, repoInfo?: { owner: string, repo: string }): void {\n const f = features ?? readConfig().features ?? defaultFeatures\n try {\n linkPkg(skillDir, packageName, cwd, version)\n linkPkgNamed(skillDir, packageName, cwd, version)\n if (!hasShippedDocs(packageName, cwd, version) && docsType !== 'readme') {\n linkCachedDir(skillDir, packageName, version, 'docs')\n }\n // Issues/discussions/releases: use repo cache when available, else package cache\n if (f.issues) {\n if (repoInfo)\n linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, 'issues')\n else\n linkCachedDir(skillDir, packageName, version, 'issues')\n }\n if (f.discussions) {\n if (repoInfo)\n linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, 'discussions')\n else\n linkCachedDir(skillDir, packageName, version, 'discussions')\n }\n if (f.releases) {\n if (repoInfo)\n linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, 'releases')\n else\n linkCachedDir(skillDir, packageName, version, 'releases')\n }\n linkCachedDir(skillDir, packageName, version, 'sections')\n // Create named symlinks for additional packages in multi-package skills\n if (extraPackages) {\n for (const pkg of extraPackages) {\n if (pkg.name !== packageName)\n linkPkgNamed(skillDir, pkg.name, cwd, pkg.version)\n }\n }\n }\n catch {\n // Symlink may fail on some systems\n }\n}\n\n/** Detect docs type from cached directory contents */\nexport function detectDocsType(packageName: string, version: string, repoUrl?: string, llmsUrl?: string): { docsType: 'docs' | 'llms.txt' | 'readme', docSource?: string } {\n const cacheDir = getCacheDir(packageName, version)\n if (existsSync(join(cacheDir, 'docs', 'index.md')) || existsSync(join(cacheDir, 'docs', 'guide'))) {\n return {\n docsType: 'docs',\n docSource: repoUrl ? `${repoUrl}/tree/v${version}/docs` : 'git',\n }\n }\n if (existsSync(join(cacheDir, 'llms.txt'))) {\n return {\n docsType: 'llms.txt',\n docSource: llmsUrl || 'llms.txt',\n }\n }\n if (existsSync(join(cacheDir, 'docs', 'README.md'))) {\n return { docsType: 'readme' }\n }\n return { docsType: 'readme' }\n}\n\n/** Eject (portable copy) of cached references into a skill dir */\nexport function ejectReferences(skillDir: string, packageName: string, cwd: string, version: string, docsType: string, features?: FeaturesConfig, repoInfo?: { owner: string, repo: string }): void {\n const f = features ?? readConfig().features ?? defaultFeatures\n const cacheDir = getCacheDir(packageName, version)\n const refsDir = join(skillDir, 'references')\n // Repo-level data source (falls back to package cache)\n const repoDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : cacheDir\n\n // Copy cached docs (skip pkg — eject is for portable sharing, pkg references node_modules)\n if (!hasShippedDocs(packageName, cwd, version) && docsType !== 'readme')\n copyCachedSubdir(cacheDir, refsDir, 'docs')\n\n if (f.issues)\n copyCachedSubdir(repoDir, refsDir, 'issues')\n if (f.discussions)\n copyCachedSubdir(repoDir, refsDir, 'discussions')\n if (f.releases)\n copyCachedSubdir(repoDir, refsDir, 'releases')\n}\n\n/** Recursively copy a cached subdirectory into the references dir */\nfunction copyCachedSubdir(cacheDir: string, refsDir: string, subdir: string): void {\n const srcDir = join(cacheDir, subdir)\n if (!existsSync(srcDir))\n return\n\n const destDir = join(refsDir, subdir)\n mkdirSync(destDir, { recursive: true })\n\n function walk(dir: string, rel: string) {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const srcPath = join(dir, entry.name)\n const destPath = join(destDir, rel ? `${rel}/${entry.name}` : entry.name)\n if (entry.isDirectory()) {\n mkdirSync(destPath, { recursive: true })\n walk(srcPath, rel ? `${rel}/${entry.name}` : entry.name)\n }\n else {\n copyFileSync(srcPath, destPath)\n }\n }\n }\n\n walk(srcDir, '')\n}\n\nexport interface CachedReferencesResult {\n /** Docs to feed the embedding index (empty if db already exists) */\n docsToIndex: IndexDoc[]\n /** Resolved doc-source label (URL or git path) */\n docSource: string\n /** Detected docs type from cache layout */\n docsType: 'docs' | 'llms.txt' | 'readme'\n /** _INDEX.md to write if missing (backfill for older caches) */\n backfillIndex?: { path: string, content: string }\n}\n\nexport interface LoadCachedReferencesOptions {\n packageName: string\n version: string\n repoUrl?: string\n llmsUrl?: string\n readmeUrl?: string\n onProgress: (message: string) => void\n /** Caller supplies index generator to avoid the cache module pulling sources */\n generateDocsIndex: (docs: Array<{ path: string, content: string }>) => string | null\n}\n\n/**\n * Load cached references for a package and produce the index/backfill data\n * needed to continue the sync pipeline without re-fetching.\n */\nexport function loadCachedReferences(opts: LoadCachedReferencesOptions): CachedReferencesResult {\n const { packageName, version, repoUrl, llmsUrl, readmeUrl, onProgress, generateDocsIndex } = opts\n onProgress('Loading cached docs')\n const detected = detectDocsType(packageName, version, repoUrl, llmsUrl)\n const docsType = detected.docsType\n const docSource = detected.docSource ?? readmeUrl ?? 'readme'\n const docsToIndex: IndexDoc[] = []\n\n // Load cached docs for indexing if db doesn't exist yet\n const dbPath = getPackageDbPath(packageName, version)\n if (!existsSync(dbPath)) {\n onProgress('Reading cached docs for indexing')\n const cached = readCachedDocs(packageName, version)\n for (const doc of cached) {\n docsToIndex.push({\n id: doc.path,\n content: doc.content,\n metadata: { package: packageName, source: doc.path, ...classifyCachedDoc(doc.path) },\n })\n }\n }\n\n // Backfill docs index for caches created before this feature\n let backfillIndex: { path: string, content: string } | undefined\n if (docsType !== 'readme' && !existsSync(join(getCacheDir(packageName, version), 'docs', '_INDEX.md'))) {\n onProgress('Generating docs index')\n const cached = readCachedDocs(packageName, version)\n const docFiles = cached.filter(d => d.path.startsWith('docs/') && d.path.endsWith('.md'))\n if (docFiles.length > 1) {\n const docsIndex = generateDocsIndex(cached)\n if (docsIndex)\n backfillIndex = { path: 'docs/_INDEX.md', content: docsIndex }\n }\n }\n\n return { docsToIndex, docSource, docsType, backfillIndex }\n}\n","/**\n * Cache storage operations\n */\n\nimport type { CachedDoc, CachedPackage } from './types.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'pathe'\nimport { readPackageJsonSafe } from '../core/package-json.ts'\nimport { getRepoCacheDir, REFERENCES_DIR, REPOS_DIR, skillInternalDir } from '../core/paths.ts'\nimport { resolvePkgDir } from '../core/prepare.ts'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport { getCacheDir } from './version.ts'\n\n/** Safely create a symlink, validating target is under REFERENCES_DIR or REPOS_DIR */\nfunction safeSymlink(target: string, linkPath: string): void {\n const resolved = resolve(target)\n if (!resolved.startsWith(REFERENCES_DIR) && !resolved.startsWith(REPOS_DIR))\n throw new Error(`Symlink target outside allowed dirs: ${resolved}`)\n // Remove pre-existing symlink (check with lstat to detect symlinks)\n try {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink() || stat.isFile())\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(target, linkPath, 'junction')\n}\n\n/**\n * Check if package is cached at given version\n * @internal\n */\nexport function isCached(name: string, version: string): boolean {\n return existsSync(getCacheDir(name, version))\n}\n\n/** Check if cache only has docs/README.md (pkg/ already has this) */\nexport function isReadmeOnlyCache(cacheDir: string): boolean {\n const docsDir = join(cacheDir, 'docs')\n if (!existsSync(docsDir))\n return false\n const files = readdirSync(docsDir)\n return files.length === 1 && files[0] === 'README.md'\n}\n\nexport function inferDocsTypeFromCache(cacheDir: string, source?: string): 'llms.txt' | 'readme' | 'docs' {\n if (source?.includes('llms.txt') || existsSync(join(cacheDir, 'docs', 'llms.txt')))\n return 'llms.txt'\n return isReadmeOnlyCache(cacheDir) ? 'readme' : 'docs'\n}\n\n/**\n * Ensure cache directories exist\n */\nexport function ensureCacheDir(): void {\n mkdirSync(REFERENCES_DIR, { recursive: true, mode: 0o700 })\n mkdirSync(REPOS_DIR, { recursive: true, mode: 0o700 })\n}\n\n/**\n * Write docs to cache\n * @internal\n */\nexport function writeToCache(\n name: string,\n version: string,\n docs: CachedDoc[],\n): string {\n const cacheDir = getCacheDir(name, version)\n mkdirSync(cacheDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(cacheDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return cacheDir\n}\n\n/**\n * Write docs to repo-level cache (~/.skilld/repos/<owner>/<repo>/)\n */\nexport function writeToRepoCache(\n owner: string,\n repo: string,\n docs: CachedDoc[],\n): string {\n const repoDir = getRepoCacheDir(owner, repo)\n mkdirSync(repoDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(repoDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return repoDir\n}\n\n/**\n * Create symlink from .skilld dir to a repo-level cached subdirectory.\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/repos/<owner>/<repo>/<subdir>\n */\nexport function linkRepoCachedDir(skillDir: string, owner: string, repo: string, subdir: string): void {\n const repoDir = getRepoCacheDir(owner, repo)\n const referencesDir = skillInternalDir(skillDir)\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(repoDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Create symlink from .skilld dir to a cached subdirectory.\n * Unified handler for docs, issues, discussions, sections, releases.\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/references/<pkg>@<version>/<subdir>\n *\n * The .skilld/ dirs are gitignored. After clone, `skilld install` recreates from lockfile.\n */\nexport function linkCachedDir(skillDir: string, name: string, version: string, subdir: string): void {\n const cacheDir = getCacheDir(name, version)\n const referencesDir = skillInternalDir(skillDir)\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(cacheDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Resolve the package directory: node_modules first, then cached dist fallback.\n * Returns the path if found, null otherwise.\n */\nexport { resolvePkgDir } from '../core/prepare.ts'\nexport { getShippedSkills, linkShippedSkill } from '../core/prepare.ts'\nexport type { ShippedSkill } from '../core/prepare.ts'\n\n/**\n * Create symlink from .skilld dir to package directory\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg -> node_modules/<pkg> OR ~/.skilld/references/<pkg>@<version>/pkg\n *\n * This gives access to package.json, README.md, dist/, and any shipped docs/\n */\nexport function linkPkg(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const referencesDir = skillInternalDir(skillDir)\n mkdirSync(referencesDir, { recursive: true })\n\n const pkgLinkPath = join(referencesDir, 'pkg')\n try {\n lstatSync(pkgLinkPath)\n unlinkSync(pkgLinkPath)\n }\n catch {}\n symlinkSync(pkgPath, pkgLinkPath, 'junction')\n}\n\n/**\n * Create named symlink from .skilld dir to package directory.\n * Short name = last segment of package name (e.g., @vue/reactivity → pkg-reactivity)\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg-<short> -> node_modules/<pkg>\n */\nexport function linkPkgNamed(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const shortName = name.split('/').pop()!.toLowerCase()\n const referencesDir = skillInternalDir(skillDir)\n mkdirSync(referencesDir, { recursive: true })\n\n const linkPath = join(referencesDir, `pkg-${shortName}`)\n try {\n lstatSync(linkPath)\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(pkgPath, linkPath, 'junction')\n}\n\n/**\n * Get key files from a package directory for display\n * Returns entry points + docs files\n */\nexport function getPkgKeyFiles(name: string, cwd: string, version?: string): string[] {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return []\n\n const files: string[] = []\n const pkgJsonPath = join(pkgPath, 'package.json')\n\n const pkgJsonResult = readPackageJsonSafe(pkgJsonPath)\n if (pkgJsonResult) {\n const pkg = pkgJsonResult.parsed as Record<string, any>\n\n // Entry points\n if (pkg.main)\n files.push(basename(pkg.main))\n if (pkg.module && pkg.module !== pkg.main)\n files.push(basename(pkg.module))\n\n // Type definitions (relative path preserved for LLM tool hints)\n const typesPath = pkg.types || pkg.typings\n if (typesPath && existsSync(join(pkgPath, typesPath)))\n files.push(typesPath)\n }\n\n // Check for common doc files (case-insensitive readme match)\n const entries = readdirSync(pkgPath).filter(f =>\n /^readme\\.md$/i.test(f) || /^changelog\\.md$/i.test(f),\n )\n files.push(...entries)\n\n return [...new Set(files)]\n}\n\n/**\n * Write LLM-generated section outputs to global cache for cross-project reuse\n *\n * Structure:\n * ~/.skilld/references/<pkg>@<version>/sections/_BEST_PRACTICES.md\n */\nexport function writeSections(name: string, version: string, sections: Array<{ file: string, content: string }>): void {\n const cacheDir = getCacheDir(name, version)\n const sectionsDir = join(cacheDir, 'sections')\n mkdirSync(sectionsDir, { recursive: true, mode: 0o700 })\n for (const { file, content } of sections) {\n writeFileSync(join(sectionsDir, file), content, { mode: 0o600 })\n }\n}\n\n/**\n * Read a cached section from the global references dir\n */\nexport function readCachedSection(name: string, version: string, file: string): string | null {\n const path = join(getCacheDir(name, version), 'sections', file)\n if (!existsSync(path))\n return null\n return readFileSync(path, 'utf-8')\n}\n\nexport function hasShippedDocs(name: string, cwd: string, version?: string): boolean {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return false\n\n const docsCandidates = ['docs', 'documentation', 'doc']\n for (const candidate of docsCandidates) {\n const docsPath = join(pkgPath, candidate)\n if (existsSync(docsPath))\n return true\n }\n return false\n}\n\n/**\n * List all cached packages\n */\nexport function listCached(): CachedPackage[] {\n if (!existsSync(REFERENCES_DIR))\n return []\n\n return readdirSync(REFERENCES_DIR)\n .filter(name => name.includes('@'))\n .map((dir) => {\n const atIdx = dir.lastIndexOf('@')\n return { name: dir.slice(0, atIdx), version: dir.slice(atIdx + 1), dir: join(REFERENCES_DIR, dir) }\n })\n}\n\n/**\n * Read cached docs for a package\n */\nexport function readCachedDocs(name: string, version: string): CachedDoc[] {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return []\n\n const docs: CachedDoc[] = []\n\n function walk(dir: string, prefix = '') {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const entryPath = join(dir, entry.name)\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) {\n walk(entryPath, relativePath)\n }\n else if (entry.name.endsWith('.md') || entry.name.endsWith('.mdx')) {\n docs.push({\n path: relativePath,\n content: readFileSync(entryPath, 'utf-8'),\n })\n }\n }\n }\n\n walk(cacheDir)\n return docs\n}\n\n/**\n * Clear cache for a specific package\n */\nexport function clearCache(name: string, version: string): boolean {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return false\n\n rmSync(cacheDir, { recursive: true })\n return true\n}\n\n/**\n * Clear all cache\n */\nexport function clearAllCache(): number {\n const packages = listCached()\n for (const pkg of packages) {\n clearCache(pkg.name, pkg.version)\n }\n // Also clear repo-level cache\n if (existsSync(REPOS_DIR))\n rmSync(REPOS_DIR, { recursive: true })\n return packages.length\n}\n\n/**\n * List files in .skilld directory (pkg + docs) as relative paths for prompt context\n * Returns paths like ./.skilld/pkg/README.md, ./.skilld/docs/api.md\n */\nexport function listReferenceFiles(skillDir: string, maxDepth = 3): string[] {\n const referencesDir = skillInternalDir(skillDir)\n if (!existsSync(referencesDir))\n return []\n\n const files: string[] = []\n\n function walk(dir: string, depth: number) {\n if (depth > maxDepth)\n return\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory() || entry.isSymbolicLink()) {\n try {\n const stat = statSync(full)\n if (stat.isDirectory()) {\n walk(full, depth + 1)\n continue\n }\n }\n catch { continue }\n }\n if (entry.name.endsWith('.md')) {\n files.push(full)\n }\n }\n }\n catch {\n // Broken symlink or permission error\n }\n }\n\n walk(referencesDir, 0)\n return files\n}\n","/**\n * Per-package reference cache facade. Closes over `(packageName, version)` so\n * call sites stop threading those tuples through chained primitives.\n */\n\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type {\n CachedReferencesResult,\n LoadCachedReferencesOptions,\n} from './references.ts'\nimport type { CachedDoc } from './types.ts'\nimport {\n clearSkillInternalDir,\n detectDocsType,\n ejectReferences,\n forceClearCache,\n linkAllReferences,\n loadCachedReferences,\n} from './references.ts'\nimport {\n ensureCacheDir,\n getPkgKeyFiles,\n hasShippedDocs,\n isCached,\n linkPkgNamed,\n readCachedDocs,\n readCachedSection,\n resolvePkgDir,\n writeSections,\n writeToCache,\n} from './storage.ts'\nimport { getCacheDir, getVersionKey } from './version.ts'\n\nexport interface ReferenceCacheLinkOpts {\n extraPackages?: Array<{ name: string, version?: string }>\n features?: FeaturesConfig\n repoInfo?: { owner: string, repo: string }\n}\n\nexport interface ReferenceCacheEjectOpts {\n features?: FeaturesConfig\n repoInfo?: { owner: string, repo: string }\n}\n\nexport interface ReferenceCache {\n readonly packageName: string\n /** May be undefined when caller only knows the package name (e.g. merge against a lock without a recorded version). Cache-keyed methods/getters throw in that case; pkg/has/keyFiles fall back to node_modules. */\n readonly version: string | undefined\n /** Throws if accessed when version is undefined. */\n readonly versionKey: string\n /** Throws if accessed when version is undefined. */\n readonly dir: string\n ensure: () => void\n has: () => boolean\n write: (docs: CachedDoc[]) => void\n writeSections: (sections: Array<{ file: string, content: string }>) => void\n readSection: (file: string) => string | null\n readDocs: () => CachedDoc[]\n detectDocs: (\n repoUrl?: string,\n llmsUrl?: string,\n ) => { docsType: 'docs' | 'llms.txt' | 'readme', docSource?: string }\n load: (\n opts: Omit<LoadCachedReferencesOptions, 'packageName' | 'version'>,\n ) => CachedReferencesResult\n linkInto: (\n skillDir: string,\n cwd: string,\n docsType: string,\n opts?: ReferenceCacheLinkOpts,\n ) => void\n linkPkgNamed: (skillDir: string, cwd: string) => void\n eject: (\n skillDir: string,\n cwd: string,\n docsType: string,\n opts?: ReferenceCacheEjectOpts,\n ) => void\n clearForce: (repoInfo?: { owner: string, repo: string }) => void\n clearSkillInternal: (skillDir: string) => void\n pkgDir: (cwd: string) => string | null\n hasShipped: (cwd: string) => boolean\n keyFiles: (cwd: string) => string[]\n}\n\nexport function createReferenceCache(packageName: string, version?: string): ReferenceCache {\n const requireVersion = (op: string): string => {\n if (!version)\n throw new Error(`ReferenceCache.${op} requires a version (package: ${packageName})`)\n return version\n }\n return {\n packageName,\n version,\n get versionKey() { return getVersionKey(requireVersion('versionKey')) },\n get dir() { return getCacheDir(packageName, requireVersion('dir')) },\n ensure: () => ensureCacheDir(),\n has: () => !!version && isCached(packageName, version),\n write: docs => void writeToCache(packageName, requireVersion('write'), docs),\n writeSections: sections => writeSections(packageName, requireVersion('writeSections'), sections),\n readSection: file => readCachedSection(packageName, requireVersion('readSection'), file),\n readDocs: () => readCachedDocs(packageName, requireVersion('readDocs')),\n detectDocs: (repoUrl, llmsUrl) =>\n detectDocsType(packageName, requireVersion('detectDocs'), repoUrl, llmsUrl),\n load: opts =>\n loadCachedReferences({ ...opts, packageName, version: requireVersion('load') }),\n linkInto: (skillDir, cwd, docsType, opts) =>\n linkAllReferences(\n skillDir,\n packageName,\n cwd,\n requireVersion('linkInto'),\n docsType,\n opts?.extraPackages,\n opts?.features,\n opts?.repoInfo,\n ),\n linkPkgNamed: (skillDir, cwd) =>\n linkPkgNamed(skillDir, packageName, cwd, version),\n eject: (skillDir, cwd, docsType, opts) =>\n ejectReferences(\n skillDir,\n packageName,\n cwd,\n requireVersion('eject'),\n docsType,\n opts?.features,\n opts?.repoInfo,\n ),\n clearForce: repoInfo => forceClearCache(packageName, requireVersion('clearForce'), repoInfo),\n clearSkillInternal: skillDir => clearSkillInternalDir(skillDir),\n pkgDir: cwd => resolvePkgDir(packageName, cwd, version),\n hasShipped: cwd => hasShippedDocs(packageName, cwd, version),\n keyFiles: cwd => getPkgKeyFiles(packageName, cwd, version),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cache.mjs","names":["STATIC_REGEX_1"],"sources":["../../src/core/config.ts","../../src/cache/internal/classify.ts","../../src/cache/internal/storage.ts","../../src/cache/internal/references.ts","../../src/cache/reference-cache.ts"],"sourcesContent":["import type { OptimizeModel } from '../agent/index.ts'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { CACHE_DIR, CONFIG_PATH } from './paths.ts'\nimport { yamlEscape, yamlParseKV, yamlUnescape } from './yaml.ts'\n\nconst STATIC_REGEX_1 = /^ {2}(\\w+):\\s*(.+)/\n\nexport interface FeaturesConfig {\n search: boolean\n issues: boolean\n discussions: boolean\n releases: boolean\n}\n\nexport const defaultFeatures: FeaturesConfig = {\n search: true,\n issues: true,\n discussions: true,\n releases: true,\n}\n\n/**\n * Resolve the active feature set: defaults overlaid with user config, then\n * caller-supplied overrides. Single seam so feature gating doesn't drift.\n */\nexport function getActiveFeatures(overrides?: Partial<FeaturesConfig>): FeaturesConfig {\n const fromConfig = readConfig().features\n const merged: FeaturesConfig = { ...defaultFeatures, ...(fromConfig ?? {}) }\n return overrides ? { ...merged, ...overrides } : merged\n}\n\nexport interface SkilldConfig {\n model?: OptimizeModel\n agent?: string\n features?: FeaturesConfig\n projects?: string[]\n skipLlm?: boolean\n}\n\nlet configCache: SkilldConfig | undefined\n\nexport function hasConfig(): boolean {\n return existsSync(CONFIG_PATH)\n}\n\n/** Whether the first-run wizard has been completed (not just agent selection) */\nexport function hasCompletedWizard(): boolean {\n if (!existsSync(CONFIG_PATH))\n return false\n const config = readConfig()\n return config.features !== undefined || config.model !== undefined || config.skipLlm !== undefined\n}\n\nexport function readConfig(): SkilldConfig {\n if (configCache) {\n return {\n ...configCache,\n features: configCache.features ? { ...configCache.features } : undefined,\n projects: configCache.projects ? [...configCache.projects] : undefined,\n }\n }\n if (!existsSync(CONFIG_PATH))\n return {}\n\n const content = readFileSync(CONFIG_PATH, 'utf-8')\n const config: SkilldConfig = {}\n let inBlock: 'projects' | 'features' | null = null\n const projects: string[] = []\n const features: Partial<FeaturesConfig> = {}\n\n for (const line of content.split('\\n')) {\n if (line.startsWith('projects:')) {\n inBlock = 'projects'\n continue\n }\n if (line.startsWith('features:')) {\n inBlock = 'features'\n continue\n }\n if (inBlock === 'projects') {\n if (line.startsWith(' - ')) {\n projects.push(yamlUnescape(line.slice(4)))\n continue\n }\n inBlock = null\n }\n if (inBlock === 'features') {\n const m = line.match(STATIC_REGEX_1)\n if (m) {\n const key = m[1] as keyof FeaturesConfig\n if (key in defaultFeatures)\n features[key] = m[2] === 'true'\n continue\n }\n inBlock = null\n }\n const kv = yamlParseKV(line)\n if (!kv)\n continue\n const [key, value] = kv\n if (key === 'model' && value)\n config.model = value as OptimizeModel\n if (key === 'agent' && value)\n config.agent = value\n if (key === 'skipLlm')\n config.skipLlm = value === 'true'\n }\n\n if (projects.length > 0)\n config.projects = projects\n if (Object.keys(features).length > 0)\n config.features = { ...defaultFeatures, ...features }\n configCache = config\n return config\n}\n\nexport function writeConfig(config: SkilldConfig): void {\n mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 })\n\n let yaml = ''\n if (config.model)\n yaml += `model: ${config.model}\\n`\n if (config.agent)\n yaml += `agent: ${config.agent}\\n`\n if (config.skipLlm)\n yaml += `skipLlm: true\\n`\n if (config.features) {\n yaml += 'features:\\n'\n for (const [k, v] of Object.entries(config.features)) {\n yaml += ` ${k}: ${v}\\n`\n }\n }\n if (config.projects?.length) {\n yaml += 'projects:\\n'\n for (const p of config.projects) {\n yaml += ` - ${yamlEscape(p)}\\n`\n }\n }\n\n writeFileSync(CONFIG_PATH, yaml, { mode: 0o600 })\n configCache = undefined\n}\n\nexport function updateConfig(updates: Partial<SkilldConfig>): void {\n const config = readConfig()\n writeConfig({ ...config, ...updates })\n}\n\nexport function registerProject(projectPath: string): void {\n const config = readConfig()\n const projects = new Set(config.projects || [])\n projects.add(projectPath)\n writeConfig({ ...config, projects: [...projects] })\n}\n\nexport function unregisterProject(projectPath: string): void {\n const config = readConfig()\n const projects = (config.projects || []).filter(p => p !== projectPath)\n writeConfig({ ...config, projects })\n}\n\nexport function getRegisteredProjects(): string[] {\n return readConfig().projects || []\n}\n","const STATIC_REGEX_1 = /^issues\\/issue-(\\d+)\\.md$/\nconst STATIC_REGEX_2 = /^discussions\\/discussion-(\\d+)\\.md$/\n\n/**\n * Classify a cached doc path into the right metadata type.\n * Pure utility — no I/O.\n */\nexport function classifyCachedDoc(path: string): { type: string, number?: number } {\n const issueMatch = path.match(STATIC_REGEX_1)\n if (issueMatch)\n return { type: 'issue', number: Number(issueMatch[1]) }\n const discussionMatch = path.match(STATIC_REGEX_2)\n if (discussionMatch)\n return { type: 'discussion', number: Number(discussionMatch[1]) }\n if (path.startsWith('releases/'))\n return { type: 'release' }\n return { type: 'doc' }\n}\n","/**\n * Cache storage operations\n */\n\nimport type { CachedDoc, CachedPackage } from '../types.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join, resolve } from 'pathe'\nimport { getRepoCacheDir, REFERENCES_DIR, REPOS_DIR, skillInternalDir } from '../../core/paths.ts'\nimport { resolvePkgDir } from '../../core/prepare.ts'\nimport { sanitizeMarkdown } from '../../core/sanitize.ts'\nimport { getCacheDir } from './version.ts'\n\n/** Safely create a symlink, validating target is under REFERENCES_DIR or REPOS_DIR */\nfunction safeSymlink(target: string, linkPath: string): void {\n const resolved = resolve(target)\n if (!resolved.startsWith(REFERENCES_DIR) && !resolved.startsWith(REPOS_DIR))\n throw new Error(`Symlink target outside allowed dirs: ${resolved}`)\n // Remove pre-existing symlink (check with lstat to detect symlinks)\n try {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink() || stat.isFile())\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(target, linkPath, 'junction')\n}\n\n/**\n * Check if package is cached at given version\n * @internal\n */\nexport function isCached(name: string, version: string): boolean {\n return existsSync(getCacheDir(name, version))\n}\n\n/** Check if cache only has docs/README.md (pkg/ already has this) */\nexport function isReadmeOnlyCache(cacheDir: string): boolean {\n const docsDir = join(cacheDir, 'docs')\n if (!existsSync(docsDir))\n return false\n const files = readdirSync(docsDir)\n return files.length === 1 && files[0] === 'README.md'\n}\n\nexport function inferDocsTypeFromCache(cacheDir: string, source?: string): 'llms.txt' | 'readme' | 'docs' {\n if (source?.includes('llms.txt') || existsSync(join(cacheDir, 'docs', 'llms.txt')))\n return 'llms.txt'\n return isReadmeOnlyCache(cacheDir) ? 'readme' : 'docs'\n}\n\n/**\n * Ensure cache directories exist\n */\nexport function ensureCacheDir(): void {\n mkdirSync(REFERENCES_DIR, { recursive: true, mode: 0o700 })\n mkdirSync(REPOS_DIR, { recursive: true, mode: 0o700 })\n}\n\n/**\n * Write docs to cache\n * @internal\n */\nexport function writeToCache(\n name: string,\n version: string,\n docs: CachedDoc[],\n): string {\n const cacheDir = getCacheDir(name, version)\n mkdirSync(cacheDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(cacheDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return cacheDir\n}\n\n/**\n * Write docs to repo-level cache (~/.skilld/repos/<owner>/<repo>/)\n */\nexport function writeToRepoCache(\n owner: string,\n repo: string,\n docs: CachedDoc[],\n): string {\n const repoDir = getRepoCacheDir(owner, repo)\n mkdirSync(repoDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(repoDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return repoDir\n}\n\n/**\n * Create symlink from .skilld dir to a repo-level cached subdirectory.\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/repos/<owner>/<repo>/<subdir>\n */\nexport function linkRepoCachedDir(skillDir: string, owner: string, repo: string, subdir: string): void {\n const repoDir = getRepoCacheDir(owner, repo)\n const referencesDir = skillInternalDir(skillDir)\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(repoDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Create symlink from .skilld dir to a cached subdirectory.\n * Unified handler for docs, issues, discussions, sections, releases.\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/references/<pkg>@<version>/<subdir>\n *\n * The .skilld/ dirs are gitignored. After clone, `skilld install` recreates from lockfile.\n */\nexport function linkCachedDir(skillDir: string, name: string, version: string, subdir: string): void {\n const cacheDir = getCacheDir(name, version)\n const referencesDir = skillInternalDir(skillDir)\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(cacheDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Create symlink from .skilld dir to package directory\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg -> node_modules/<pkg> OR ~/.skilld/references/<pkg>@<version>/pkg\n *\n * This gives access to package.json, README.md, dist/, and any shipped docs/\n */\nexport function linkPkg(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const referencesDir = skillInternalDir(skillDir)\n mkdirSync(referencesDir, { recursive: true })\n\n const pkgLinkPath = join(referencesDir, 'pkg')\n try {\n lstatSync(pkgLinkPath)\n unlinkSync(pkgLinkPath)\n }\n catch {}\n symlinkSync(pkgPath, pkgLinkPath, 'junction')\n}\n\n/**\n * Create named symlink from .skilld dir to package directory.\n * Short name = last segment of package name (e.g., @vue/reactivity → pkg-reactivity)\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg-<short> -> node_modules/<pkg>\n */\nexport function linkPkgNamed(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const shortName = name.split('/').pop()!.toLowerCase()\n const referencesDir = skillInternalDir(skillDir)\n mkdirSync(referencesDir, { recursive: true })\n\n const linkPath = join(referencesDir, `pkg-${shortName}`)\n try {\n lstatSync(linkPath)\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(pkgPath, linkPath, 'junction')\n}\n\n/**\n * Write LLM-generated section outputs to global cache for cross-project reuse\n *\n * Structure:\n * ~/.skilld/references/<pkg>@<version>/sections/_BEST_PRACTICES.md\n */\nexport function writeSections(name: string, version: string, sections: Array<{ file: string, content: string }>): void {\n const cacheDir = getCacheDir(name, version)\n const sectionsDir = join(cacheDir, 'sections')\n mkdirSync(sectionsDir, { recursive: true, mode: 0o700 })\n for (const { file, content } of sections) {\n writeFileSync(join(sectionsDir, file), content, { mode: 0o600 })\n }\n}\n\n/**\n * Read a cached section from the global references dir\n */\nexport function readCachedSection(name: string, version: string, file: string): string | null {\n const path = join(getCacheDir(name, version), 'sections', file)\n if (!existsSync(path))\n return null\n return readFileSync(path, 'utf-8')\n}\n\n/**\n * List all cached packages\n */\nexport function listCached(): CachedPackage[] {\n if (!existsSync(REFERENCES_DIR))\n return []\n\n return readdirSync(REFERENCES_DIR)\n .filter(name => name.includes('@'))\n .map((dir) => {\n const atIdx = dir.lastIndexOf('@')\n return { name: dir.slice(0, atIdx), version: dir.slice(atIdx + 1), dir: join(REFERENCES_DIR, dir) }\n })\n}\n\n/**\n * Read cached docs for a package\n */\nexport function readCachedDocs(name: string, version: string): CachedDoc[] {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return []\n\n const docs: CachedDoc[] = []\n\n function walk(dir: string, prefix = '') {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const entryPath = join(dir, entry.name)\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) {\n walk(entryPath, relativePath)\n }\n else if (entry.name.endsWith('.md') || entry.name.endsWith('.mdx')) {\n docs.push({\n path: relativePath,\n content: readFileSync(entryPath, 'utf-8'),\n })\n }\n }\n }\n\n walk(cacheDir)\n return docs\n}\n\n/**\n * Clear cache for a specific package\n */\nexport function clearCache(name: string, version: string): boolean {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return false\n\n rmSync(cacheDir, { recursive: true })\n return true\n}\n\n/**\n * List files in .skilld directory (pkg + docs) as relative paths for prompt context\n * Returns paths like ./.skilld/pkg/README.md, ./.skilld/docs/api.md\n */\nexport function listReferenceFiles(skillDir: string, maxDepth = 3): string[] {\n const referencesDir = skillInternalDir(skillDir)\n if (!existsSync(referencesDir))\n return []\n\n const files: string[] = []\n\n function walk(dir: string, depth: number) {\n if (depth > maxDepth)\n return\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory() || entry.isSymbolicLink()) {\n try {\n const stat = statSync(full)\n if (stat.isDirectory()) {\n walk(full, depth + 1)\n continue\n }\n }\n catch { continue }\n }\n if (entry.name.endsWith('.md')) {\n files.push(full)\n }\n }\n }\n catch {\n // Broken symlink or permission error\n }\n }\n\n walk(referencesDir, 0)\n return files\n}\n","/**\n * Higher-level reference-cache operations: composition over the cache\n * primitives in `src/cache/index.ts`.\n *\n * Owns:\n * - The on-disk shape of `~/.skilld/references/<pkg>@<version>/`\n * - `.skilld/` symlinks inside agent skill dirs (linkAllReferences)\n * - Loading cached docs back as a `ResolvedContent`-shaped result\n * - Force-clearing and ejecting (portable copy) caches\n *\n * Callers (sync, sync-parallel, sync-git, install, author) should use these\n * helpers instead of touching cache primitives directly.\n */\n\nimport type { FeaturesConfig } from '../../core/config.ts'\nimport type { IndexDoc } from '../../sources/content-resolver.ts'\nimport type { CachedReferencesResult, LoadCachedReferencesOptions } from '../types.ts'\nimport { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, realpathSync, rmSync } from 'node:fs'\nimport { dirname, join } from 'pathe'\nimport { defaultFeatures, readConfig } from '../../core/config.ts'\nimport { getPackageDbPath, getRepoCacheDir, skillInternalDir } from '../../core/paths.ts'\nimport { hasShippedDocs } from '../../core/prepare.ts'\nimport { classifyCachedDoc } from './classify.ts'\nimport {\n clearCache,\n linkCachedDir,\n linkPkg,\n linkPkgNamed,\n linkRepoCachedDir,\n readCachedDocs,\n} from './storage.ts'\nimport { getCacheDir } from './version.ts'\n\n/**\n * Resolve every symlink under `<skillDir>/.skilld/` to its real path, plus\n * the parent dirs CLI sandboxes need (e.g. Gemini). What an LLM CLI passes to\n * `--add-dir` to make references readable.\n */\nexport function getSkillReferenceDirs(skillDir: string): string[] {\n const refsDir = skillInternalDir(skillDir)\n if (!existsSync(refsDir))\n return []\n const resolved = readdirSync(refsDir)\n .map(entry => join(refsDir, entry))\n .filter(p => lstatSync(p).isSymbolicLink() && existsSync(p))\n .map(p => realpathSync(p))\n\n const parents = new Set<string>()\n for (const p of resolved) {\n const parent = dirname(p)\n if (!resolved.includes(parent))\n parents.add(parent)\n }\n\n return [...resolved, ...parents]\n}\n\n/**\n * Remove the transient `<skillDir>/.skilld/` symlink dir. Used after eject to\n * clean up references that have been copied as real files.\n */\nexport function clearSkillInternalDir(skillDir: string): void {\n const refsDir = skillInternalDir(skillDir)\n if (existsSync(refsDir))\n rmSync(refsDir, { recursive: true, force: true })\n}\n\n/** Clear cache + db for --force flag */\nexport function forceClearCache(packageName: string, version: string, repoInfo?: { owner: string, repo: string }): void {\n clearCache(packageName, version)\n const forcedDbPath = getPackageDbPath(packageName, version)\n if (existsSync(forcedDbPath))\n rmSync(forcedDbPath, { recursive: true, force: true })\n // Also clear repo-level cache when force is used\n if (repoInfo) {\n const repoDir = getRepoCacheDir(repoInfo.owner, repoInfo.repo)\n if (existsSync(repoDir))\n rmSync(repoDir, { recursive: true, force: true })\n }\n}\n\n/** Link all reference symlinks (pkg, docs, issues, discussions, releases) */\nexport function linkAllReferences(skillDir: string, packageName: string, cwd: string, version: string, docsType: string, extraPackages?: Array<{ name: string, version?: string }>, features?: FeaturesConfig, repoInfo?: { owner: string, repo: string }): void {\n const f = features ?? readConfig().features ?? defaultFeatures\n try {\n linkPkg(skillDir, packageName, cwd, version)\n linkPkgNamed(skillDir, packageName, cwd, version)\n if (!hasShippedDocs(packageName, cwd, version) && docsType !== 'readme') {\n linkCachedDir(skillDir, packageName, version, 'docs')\n }\n // Issues/discussions/releases: use repo cache when available, else package cache\n if (f.issues) {\n if (repoInfo)\n linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, 'issues')\n else\n linkCachedDir(skillDir, packageName, version, 'issues')\n }\n if (f.discussions) {\n if (repoInfo)\n linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, 'discussions')\n else\n linkCachedDir(skillDir, packageName, version, 'discussions')\n }\n if (f.releases) {\n if (repoInfo)\n linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, 'releases')\n else\n linkCachedDir(skillDir, packageName, version, 'releases')\n }\n linkCachedDir(skillDir, packageName, version, 'sections')\n // Create named symlinks for additional packages in multi-package skills\n if (extraPackages) {\n for (const pkg of extraPackages) {\n if (pkg.name !== packageName)\n linkPkgNamed(skillDir, pkg.name, cwd, pkg.version)\n }\n }\n }\n catch {\n // Symlink may fail on some systems\n }\n}\n\n/** Detect docs type from cached directory contents */\nexport function detectDocsType(packageName: string, version: string, repoUrl?: string, llmsUrl?: string): { docsType: 'docs' | 'llms.txt' | 'readme', docSource?: string } {\n const cacheDir = getCacheDir(packageName, version)\n if (existsSync(join(cacheDir, 'docs', 'index.md')) || existsSync(join(cacheDir, 'docs', 'guide'))) {\n return {\n docsType: 'docs',\n docSource: repoUrl ? `${repoUrl}/tree/v${version}/docs` : 'git',\n }\n }\n if (existsSync(join(cacheDir, 'llms.txt'))) {\n return {\n docsType: 'llms.txt',\n docSource: llmsUrl || 'llms.txt',\n }\n }\n if (existsSync(join(cacheDir, 'docs', 'README.md'))) {\n return { docsType: 'readme' }\n }\n return { docsType: 'readme' }\n}\n\n/** Eject (portable copy) of cached references into a skill dir */\nexport function ejectReferences(skillDir: string, packageName: string, cwd: string, version: string, docsType: string, features?: FeaturesConfig, repoInfo?: { owner: string, repo: string }): void {\n const f = features ?? readConfig().features ?? defaultFeatures\n const cacheDir = getCacheDir(packageName, version)\n const refsDir = join(skillDir, 'references')\n // Repo-level data source (falls back to package cache)\n const repoDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : cacheDir\n\n // Copy cached docs (skip pkg — eject is for portable sharing, pkg references node_modules)\n if (!hasShippedDocs(packageName, cwd, version) && docsType !== 'readme')\n copyCachedSubdir(cacheDir, refsDir, 'docs')\n\n if (f.issues)\n copyCachedSubdir(repoDir, refsDir, 'issues')\n if (f.discussions)\n copyCachedSubdir(repoDir, refsDir, 'discussions')\n if (f.releases)\n copyCachedSubdir(repoDir, refsDir, 'releases')\n}\n\n/** Recursively copy a cached subdirectory into the references dir */\nfunction copyCachedSubdir(cacheDir: string, refsDir: string, subdir: string): void {\n const srcDir = join(cacheDir, subdir)\n if (!existsSync(srcDir))\n return\n\n const destDir = join(refsDir, subdir)\n mkdirSync(destDir, { recursive: true })\n\n function walk(dir: string, rel: string) {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const srcPath = join(dir, entry.name)\n const destPath = join(destDir, rel ? `${rel}/${entry.name}` : entry.name)\n if (entry.isDirectory()) {\n mkdirSync(destPath, { recursive: true })\n walk(srcPath, rel ? `${rel}/${entry.name}` : entry.name)\n }\n else {\n copyFileSync(srcPath, destPath)\n }\n }\n }\n\n walk(srcDir, '')\n}\n\n/**\n * Load cached references for a package and produce the index/backfill data\n * needed to continue the sync pipeline without re-fetching.\n */\nexport function loadCachedReferences(opts: LoadCachedReferencesOptions): CachedReferencesResult {\n const { packageName, version, repoUrl, llmsUrl, readmeUrl, onProgress, generateDocsIndex } = opts\n onProgress('Loading cached docs')\n const detected = detectDocsType(packageName, version, repoUrl, llmsUrl)\n const docsType = detected.docsType\n const docSource = detected.docSource ?? readmeUrl ?? 'readme'\n const docsToIndex: IndexDoc[] = []\n\n // Load cached docs for indexing if db doesn't exist yet\n const dbPath = getPackageDbPath(packageName, version)\n if (!existsSync(dbPath)) {\n onProgress('Reading cached docs for indexing')\n const cached = readCachedDocs(packageName, version)\n for (const doc of cached) {\n docsToIndex.push({\n id: doc.path,\n content: doc.content,\n metadata: { package: packageName, source: doc.path, ...classifyCachedDoc(doc.path) },\n })\n }\n }\n\n // Backfill docs index for caches created before this feature\n let backfillIndex: { path: string, content: string } | undefined\n if (docsType !== 'readme' && !existsSync(join(getCacheDir(packageName, version), 'docs', '_INDEX.md'))) {\n onProgress('Generating docs index')\n const cached = readCachedDocs(packageName, version)\n const docFiles = cached.filter(d => d.path.startsWith('docs/') && d.path.endsWith('.md'))\n if (docFiles.length > 1) {\n const docsIndex = generateDocsIndex(cached)\n if (docsIndex)\n backfillIndex = { path: 'docs/_INDEX.md', content: docsIndex }\n }\n }\n\n return { docsToIndex, docSource, docsType, backfillIndex }\n}\n","/**\n * Per-package reference cache facade. Closes over `(packageName, version)` so\n * call sites stop threading those tuples through chained primitives.\n */\n\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { CachedDoc, CachedReferencesResult, LoadCachedReferencesOptions } from './types.ts'\nimport { getPkgKeyFiles, hasShippedDocs, resolvePkgDir } from '../core/prepare.ts'\nimport {\n clearSkillInternalDir,\n detectDocsType,\n ejectReferences,\n forceClearCache,\n linkAllReferences,\n loadCachedReferences,\n} from './internal/references.ts'\nimport {\n ensureCacheDir,\n inferDocsTypeFromCache,\n isCached,\n isReadmeOnlyCache,\n linkPkgNamed,\n readCachedDocs,\n readCachedSection,\n writeSections,\n writeToCache,\n} from './internal/storage.ts'\nimport { getCacheDir, getVersionKey } from './internal/version.ts'\n\nexport interface ReferenceCacheLinkOpts {\n extraPackages?: Array<{ name: string, version?: string }>\n features?: FeaturesConfig\n repoInfo?: { owner: string, repo: string }\n}\n\nexport interface ReferenceCacheEjectOpts {\n features?: FeaturesConfig\n repoInfo?: { owner: string, repo: string }\n}\n\nexport interface ReferenceCache {\n readonly packageName: string\n /** May be undefined when caller only knows the package name (e.g. merge against a lock without a recorded version). Cache-keyed methods/getters throw in that case; pkg/has/keyFiles fall back to node_modules. */\n readonly version: string | undefined\n /** Throws if accessed when version is undefined. */\n readonly versionKey: string\n /** Throws if accessed when version is undefined. */\n readonly dir: string\n ensure: () => void\n has: () => boolean\n isReadmeOnly: () => boolean\n inferDocsType: (source?: string) => 'llms.txt' | 'readme' | 'docs'\n write: (docs: CachedDoc[]) => void\n writeSections: (sections: Array<{ file: string, content: string }>) => void\n readSection: (file: string) => string | null\n readDocs: () => CachedDoc[]\n detectDocs: (\n repoUrl?: string,\n llmsUrl?: string,\n ) => { docsType: 'docs' | 'llms.txt' | 'readme', docSource?: string }\n load: (\n opts: Omit<LoadCachedReferencesOptions, 'packageName' | 'version'>,\n ) => CachedReferencesResult\n linkInto: (\n skillDir: string,\n cwd: string,\n docsType: string,\n opts?: ReferenceCacheLinkOpts,\n ) => void\n linkPkgNamed: (skillDir: string, cwd: string) => void\n eject: (\n skillDir: string,\n cwd: string,\n docsType: string,\n opts?: ReferenceCacheEjectOpts,\n ) => void\n clearForce: (repoInfo?: { owner: string, repo: string }) => void\n clearSkillInternal: (skillDir: string) => void\n pkgDir: (cwd: string) => string | null\n hasShipped: (cwd: string) => boolean\n keyFiles: (cwd: string) => string[]\n}\n\nexport function createReferenceCache(packageName: string, version?: string): ReferenceCache {\n const requireVersion = (op: string): string => {\n if (!version)\n throw new Error(`ReferenceCache.${op} requires a version (package: ${packageName})`)\n return version\n }\n return {\n packageName,\n version,\n get versionKey() { return getVersionKey(requireVersion('versionKey')) },\n get dir() { return getCacheDir(packageName, requireVersion('dir')) },\n ensure: () => ensureCacheDir(),\n has: () => !!version && isCached(packageName, version),\n isReadmeOnly: () => isReadmeOnlyCache(getCacheDir(packageName, requireVersion('isReadmeOnly'))),\n inferDocsType: source => inferDocsTypeFromCache(getCacheDir(packageName, requireVersion('inferDocsType')), source),\n write: docs => void writeToCache(packageName, requireVersion('write'), docs),\n writeSections: sections => writeSections(packageName, requireVersion('writeSections'), sections),\n readSection: file => readCachedSection(packageName, requireVersion('readSection'), file),\n readDocs: () => readCachedDocs(packageName, requireVersion('readDocs')),\n detectDocs: (repoUrl, llmsUrl) =>\n detectDocsType(packageName, requireVersion('detectDocs'), repoUrl, llmsUrl),\n load: opts =>\n loadCachedReferences({ ...opts, packageName, version: requireVersion('load') }),\n linkInto: (skillDir, cwd, docsType, opts) =>\n linkAllReferences(\n skillDir,\n packageName,\n cwd,\n requireVersion('linkInto'),\n docsType,\n opts?.extraPackages,\n opts?.features,\n opts?.repoInfo,\n ),\n linkPkgNamed: (skillDir, cwd) =>\n linkPkgNamed(skillDir, packageName, cwd, version),\n eject: (skillDir, cwd, docsType, opts) =>\n ejectReferences(\n skillDir,\n packageName,\n cwd,\n requireVersion('eject'),\n docsType,\n opts?.features,\n opts?.repoInfo,\n ),\n clearForce: repoInfo => forceClearCache(packageName, requireVersion('clearForce'), repoInfo),\n clearSkillInternal: skillDir => clearSkillInternalDir(skillDir),\n pkgDir: cwd => resolvePkgDir(packageName, cwd, version),\n hasShipped: cwd => hasShippedDocs(packageName, cwd, version),\n keyFiles: cwd => getPkgKeyFiles(packageName, cwd, version),\n }\n}\n"],"mappings":"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"}
@@ -1,10 +1,11 @@
1
- import { o as REFERENCES_DIR, s as REPOS_DIR, t as CACHE_DIR } from "./paths.mjs";
1
+ import { c as REPOS_DIR, n as CACHE_DIR, s as REFERENCES_DIR } from "./paths.mjs";
2
2
  import "./cache.mjs";
3
3
  import { n as clearEmbeddingCache } from "./embedding-cache2.mjs";
4
4
  import { existsSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
5
- import { join } from "pathe";
5
+ import { styleText } from "node:util";
6
6
  import * as p from "@clack/prompts";
7
7
  import { defineCommand } from "citty";
8
+ import { join } from "pathe";
8
9
  const LLM_CACHE_DIR = join(CACHE_DIR, "llm-cache");
9
10
  const LLM_CACHE_MAX_AGE = 10080 * 60 * 1e3;
10
11
  function safeRemove(path) {
@@ -85,7 +86,7 @@ function fmtBytes(n) {
85
86
  return i === 0 ? `${n}${units[i]}` : `${n.toFixed(1)}${units[i]}`;
86
87
  }
87
88
  function cacheStatsCommand() {
88
- const dim = (s) => `\x1B[90m${s}\x1B[0m`;
89
+ const dim = (s) => styleText("gray", s);
89
90
  const refs = dirEntries(REFERENCES_DIR);
90
91
  const repos = dirEntries(REPOS_DIR);
91
92
  const llm = dirEntries(LLM_CACHE_DIR);
@@ -132,16 +133,16 @@ const cacheCommandDef = defineCommand({
132
133
  },
133
134
  async run({ args }) {
134
135
  if (args.stats) {
135
- p.intro(`\x1B[1m\x1B[35mskilld\x1B[0m cache stats`);
136
+ p.intro(`${styleText(["bold", "magenta"], "skilld")} cache stats`);
136
137
  cacheStatsCommand();
137
138
  return;
138
139
  }
139
140
  if (args.clean) {
140
- p.intro(`\x1B[1m\x1B[35mskilld\x1B[0m cache clean`);
141
+ p.intro(`${styleText(["bold", "magenta"], "skilld")} cache clean`);
141
142
  await cacheCleanCommand();
142
143
  return;
143
144
  }
144
- p.intro(`\x1B[1m\x1B[35mskilld\x1B[0m cache`);
145
+ p.intro(`${styleText(["bold", "magenta"], "skilld")} cache`);
145
146
  p.log.message("Usage:\n skilld cache --clean Remove expired cache entries\n skilld cache --stats Show cache disk usage");
146
147
  }
147
148
  });