skilld 1.5.5 → 1.7.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 (120) hide show
  1. package/README.md +32 -23
  2. package/dist/_chunks/agent.mjs +2 -78
  3. package/dist/_chunks/agent.mjs.map +1 -1
  4. package/dist/_chunks/assemble.mjs +1 -18
  5. package/dist/_chunks/assemble.mjs.map +1 -1
  6. package/dist/_chunks/author-group.mjs +17 -0
  7. package/dist/_chunks/author-group.mjs.map +1 -0
  8. package/dist/_chunks/author.mjs +8 -24
  9. package/dist/_chunks/author.mjs.map +1 -1
  10. package/dist/_chunks/cache.mjs +1 -73
  11. package/dist/_chunks/cache.mjs.map +1 -1
  12. package/dist/_chunks/cache2.mjs +84 -17
  13. package/dist/_chunks/cache2.mjs.map +1 -1
  14. package/dist/_chunks/cli-helpers.mjs +3 -166
  15. package/dist/_chunks/cli-helpers.mjs.map +1 -1
  16. package/dist/_chunks/cli-helpers2.mjs +0 -11
  17. package/dist/_chunks/config.mjs +119 -54
  18. package/dist/_chunks/config.mjs.map +1 -1
  19. package/dist/_chunks/core.mjs +9 -0
  20. package/dist/_chunks/detect.mjs +29 -226
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/embedding-cache.mjs +0 -5
  23. package/dist/_chunks/embedding-cache2.mjs +2 -3
  24. package/dist/_chunks/formatting.mjs +0 -6
  25. package/dist/_chunks/formatting.mjs.map +1 -1
  26. package/dist/_chunks/index.d.mts +0 -10
  27. package/dist/_chunks/index.d.mts.map +1 -1
  28. package/dist/_chunks/index2.d.mts +3 -6
  29. package/dist/_chunks/index2.d.mts.map +1 -1
  30. package/dist/_chunks/index3.d.mts +81 -109
  31. package/dist/_chunks/index3.d.mts.map +1 -1
  32. package/dist/_chunks/install.mjs +85 -550
  33. package/dist/_chunks/install.mjs.map +1 -1
  34. package/dist/_chunks/install2.mjs +554 -0
  35. package/dist/_chunks/install2.mjs.map +1 -0
  36. package/dist/_chunks/libs/@sinclair/typebox.mjs +0 -444
  37. package/dist/_chunks/libs/@sinclair/typebox.mjs.map +1 -1
  38. package/dist/_chunks/list.mjs +0 -16
  39. package/dist/_chunks/list.mjs.map +1 -1
  40. package/dist/_chunks/lockfile.mjs +2 -10
  41. package/dist/_chunks/lockfile.mjs.map +1 -1
  42. package/dist/_chunks/markdown.mjs +0 -9
  43. package/dist/_chunks/markdown.mjs.map +1 -1
  44. package/dist/_chunks/package-json.mjs +0 -25
  45. package/dist/_chunks/package-json.mjs.map +1 -1
  46. package/dist/_chunks/package-registry.mjs +465 -0
  47. package/dist/_chunks/package-registry.mjs.map +1 -0
  48. package/dist/_chunks/pool2.mjs +0 -2
  49. package/dist/_chunks/pool2.mjs.map +1 -1
  50. package/dist/_chunks/prefix.mjs +108 -0
  51. package/dist/_chunks/prefix.mjs.map +1 -0
  52. package/dist/_chunks/prepare.mjs +14 -9
  53. package/dist/_chunks/prepare.mjs.map +1 -1
  54. package/dist/_chunks/prepare2.mjs +1 -19
  55. package/dist/_chunks/prepare2.mjs.map +1 -1
  56. package/dist/_chunks/prompts.mjs +6 -201
  57. package/dist/_chunks/prompts.mjs.map +1 -1
  58. package/dist/_chunks/retriv.mjs +23 -24
  59. package/dist/_chunks/retriv.mjs.map +1 -1
  60. package/dist/_chunks/rolldown-runtime.mjs +0 -2
  61. package/dist/_chunks/sanitize.mjs +0 -78
  62. package/dist/_chunks/sanitize.mjs.map +1 -1
  63. package/dist/_chunks/search-helpers.mjs +99 -0
  64. package/dist/_chunks/search-helpers.mjs.map +1 -0
  65. package/dist/_chunks/search-interactive.mjs +1 -18
  66. package/dist/_chunks/search-interactive.mjs.map +1 -1
  67. package/dist/_chunks/search.mjs +218 -19
  68. package/dist/_chunks/search.mjs.map +1 -0
  69. package/dist/_chunks/setup.mjs +0 -13
  70. package/dist/_chunks/setup.mjs.map +1 -1
  71. package/dist/_chunks/shared.mjs +1 -473
  72. package/dist/_chunks/shared.mjs.map +1 -1
  73. package/dist/_chunks/skills.mjs +3 -3
  74. package/dist/_chunks/skills.mjs.map +1 -1
  75. package/dist/_chunks/sources.mjs +1179 -1440
  76. package/dist/_chunks/sources.mjs.map +1 -1
  77. package/dist/_chunks/sync-registry.mjs +59 -0
  78. package/dist/_chunks/sync-registry.mjs.map +1 -0
  79. package/dist/_chunks/sync-shared.mjs +0 -16
  80. package/dist/_chunks/sync-shared2.mjs +10 -49
  81. package/dist/_chunks/sync-shared2.mjs.map +1 -1
  82. package/dist/_chunks/sync.mjs +209 -120
  83. package/dist/_chunks/sync.mjs.map +1 -1
  84. package/dist/_chunks/sync2.mjs +1 -21
  85. package/dist/_chunks/types.d.mts +0 -2
  86. package/dist/_chunks/types.d.mts.map +1 -1
  87. package/dist/_chunks/uninstall.mjs +3 -27
  88. package/dist/_chunks/uninstall.mjs.map +1 -1
  89. package/dist/_chunks/upload.mjs +152 -0
  90. package/dist/_chunks/upload.mjs.map +1 -0
  91. package/dist/_chunks/validate.mjs +1 -8
  92. package/dist/_chunks/validate.mjs.map +1 -1
  93. package/dist/_chunks/version.mjs +30 -0
  94. package/dist/_chunks/version.mjs.map +1 -0
  95. package/dist/_chunks/wizard.mjs +2 -3
  96. package/dist/_chunks/yaml.mjs +0 -21
  97. package/dist/_chunks/yaml.mjs.map +1 -1
  98. package/dist/agent/index.d.mts +0 -24
  99. package/dist/agent/index.d.mts.map +1 -1
  100. package/dist/agent/index.mjs +2 -9
  101. package/dist/cache/index.mjs +1 -3
  102. package/dist/cli-entry.mjs +0 -6
  103. package/dist/cli-entry.mjs.map +1 -1
  104. package/dist/cli.mjs +48 -33
  105. package/dist/cli.mjs.map +1 -1
  106. package/dist/index.d.mts +1 -1
  107. package/dist/index.mjs +2 -8
  108. package/dist/prepare.mjs +0 -12
  109. package/dist/prepare.mjs.map +1 -1
  110. package/dist/retriv/index.mjs +0 -2
  111. package/dist/retriv/worker.d.mts +0 -3
  112. package/dist/retriv/worker.d.mts.map +1 -1
  113. package/dist/retriv/worker.mjs +0 -2
  114. package/dist/retriv/worker.mjs.map +1 -1
  115. package/dist/sources/index.d.mts +2 -2
  116. package/dist/sources/index.mjs +3 -7
  117. package/dist/types.d.mts +1 -1
  118. package/package.json +20 -21
  119. package/dist/_chunks/search2.mjs +0 -319
  120. package/dist/_chunks/search2.mjs.map +0 -1
@@ -1,566 +1,101 @@
1
- import { a as getRepoCacheDir, i as getPackageDbPath, o as getCacheDir } from "./config.mjs";
2
- import { i as readPackageJsonSafe } from "./package-json.mjs";
3
- import { n as linkShippedSkill, r as resolvePkgDir, t as getShippedSkills } from "./prepare.mjs";
4
- import { n as sanitizeMarkdown } from "./sanitize.mjs";
5
- import { a as hasShippedDocs, f as listReferenceFiles, g as writeToCache, i as getPkgKeyFiles, l as linkPkgNamed, o as isCached, p as readCachedDocs, r as ensureCacheDir } from "./cache.mjs";
6
- import "./yaml.mjs";
7
- import "./markdown.mjs";
8
- import { r as createIndex, t as SearchDepsUnavailableError } from "./retriv.mjs";
9
- import { n as getSharedSkillsDir } from "./shared.mjs";
10
- import { C as downloadLlmsDocs, D as normalizeLlmsLinks, M as resolveEntryFiles, T as fetchLlmsTxt, Z as fetchGitHubRaw, b as isShallowGitDocs, d as resolvePackageDocs, h as fetchGitDocs, k as fetchGitSkills, tt as parseGitHubUrl, v as fetchReadmeContent, y as filterFrameworkDocs } from "./sources.mjs";
11
- import { a as targets } from "./detect.mjs";
12
- import { i as linkSkillToAgents, t as generateSkillMd } from "./prompts.mjs";
13
- import { a as getModelLabel, r as createToolProgress, s as optimizeDocs } from "./agent.mjs";
14
- import "./libs/@sinclair/typebox.mjs";
15
- import { O as readConfig, _ as promptForAgent, b as resolveAgent, w as defaultFeatures, x as sharedArgs } from "./cli-helpers.mjs";
16
- import { i as readLock, n as parsePackages, o as syncLockfilesToDirs, s as writeLock, t as mergeLocks } from "./lockfile.mjs";
17
- import "./skills.mjs";
18
- import { l as timedSpinner } from "./formatting.mjs";
19
- import "./wizard.mjs";
20
- import { S as writePromptFiles, a as classifyCachedDoc, b as selectLlmConfig, g as indexResources } from "./sync-shared2.mjs";
21
- import { n as shutdownWorker } from "./pool2.mjs";
22
- import "./sync.mjs";
23
- import { homedir } from "node:os";
24
- import { dirname, join } from "pathe";
25
- import { copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
26
- import * as p from "@clack/prompts";
27
- import { defineCommand } from "citty";
28
- //#region src/commands/install.ts
29
- async function installCommand(opts) {
30
- const cwd = process.cwd();
31
- const agent = targets[opts.agent];
32
- const shared = !opts.global && getSharedSkillsDir(cwd);
33
- const skillsDir = opts.global ? join(homedir(), ".skilld", "skills") : shared || join(cwd, agent.skillsDir);
34
- const allSkillsDirs = shared ? [shared] : Object.values(targets).map((t) => opts.global ? t.globalSkillsDir : join(cwd, t.skillsDir));
35
- const allLocks = allSkillsDirs.map((dir) => readLock(dir)).filter((l) => !!l && Object.keys(l.skills).length > 0);
36
- if (allLocks.length === 0) {
37
- p.log.warn("No skilld-lock.yaml found. Run `skilld` to sync skills first.");
38
- return;
39
- }
40
- const lock = mergeLocks(allLocks);
41
- const skills = Object.entries(lock.skills);
42
- const toRestore = [];
43
- const features = readConfig().features ?? defaultFeatures;
44
- for (const [name, info] of skills) {
45
- if (!info.version) continue;
46
- if (info.source === "shipped") {
47
- if (!existsSync(join(skillsDir, name))) toRestore.push({
48
- name,
49
- info
1
+ import { n as sanitizeMarkdown, t as repairMarkdown } from "./sanitize.mjs";
2
+ import { a as targets, t as detectInstalledAgents } from "./detect.mjs";
3
+ import { join, relative } from "pathe";
4
+ import { existsSync, lstatSync, mkdirSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
5
+ function sanitizeName(name) {
6
+ return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").slice(0, 255) || "unnamed-skill";
7
+ }
8
+ function computeSkillDirName(packageName) {
9
+ return `${sanitizeName(packageName)}-skilld`;
10
+ }
11
+ function installSkillForAgents(skillName, skillContent, options = {}) {
12
+ const isGlobal = options.global ?? false;
13
+ const cwd = options.cwd || process.cwd();
14
+ const sanitized = sanitizeName(skillName);
15
+ const explicit = !!options.agents;
16
+ const targetAgents = options.agents || detectInstalledAgents();
17
+ const installed = [];
18
+ const skipped = [];
19
+ const paths = [];
20
+ const writtenDirs = /* @__PURE__ */ new Set();
21
+ for (const agentType of targetAgents) {
22
+ const agent = targets[agentType];
23
+ if (isGlobal && !agent.globalSkillsDir) {
24
+ skipped.push({
25
+ agent: agentType,
26
+ reason: "no global support"
50
27
  });
51
28
  continue;
52
29
  }
53
- const skillDir = join(skillsDir, name);
54
- const referencesPath = join(skillDir, ".skilld");
55
- const skillMdPath = join(skillDir, "SKILL.md");
56
- if (!existsSync(skillDir) || !existsSync(skillMdPath) || !existsSync(referencesPath) || hasStaleReferences(referencesPath, info.packageName || name, info.version, features)) toRestore.push({
57
- name,
58
- info
59
- });
60
- }
61
- if (toRestore.length === 0) {
62
- p.log.success("All up to date");
63
- return;
64
- }
65
- p.log.info(`Restoring ${toRestore.length} references`);
66
- ensureCacheDir();
67
- const allSkillNames = skills.map(([, info]) => info.packageName || "").filter(Boolean);
68
- const regenerated = [];
69
- for (const { name, info } of toRestore) {
70
- const version = info.version;
71
- const pkgName = info.packageName || unsanitizeName(name, info.source);
72
- if (info.source === "shipped") {
73
- const match = getShippedSkills(pkgName, cwd, version).find((s) => s.skillName === name);
74
- if (match) {
75
- linkShippedSkill(skillsDir, name, match.skillDir);
76
- p.log.success(`Linked ${name}`);
77
- } else p.log.warn(`${name}: package ${pkgName} no longer ships this skill`);
78
- continue;
79
- }
80
- if (info.source === "github" || info.source === "gitlab" || info.source === "local") {
81
- const match = (await fetchGitSkills({
82
- type: info.source,
83
- ...info.repo?.includes("/") ? {
84
- owner: info.repo.split("/")[0],
85
- repo: info.repo.split("/")[1]
86
- } : {},
87
- skillPath: info.path,
88
- ref: info.ref,
89
- ...info.source === "local" ? { localPath: info.repo } : {}
90
- })).skills.find((s) => s.name === name);
91
- if (match) {
92
- const skillDir = join(skillsDir, name);
93
- mkdirSync(skillDir, { recursive: true });
94
- writeFileSync(join(skillDir, "SKILL.md"), sanitizeMarkdown(match.content));
95
- for (const f of match.files) {
96
- const filePath = join(skillDir, f.path);
97
- mkdirSync(dirname(filePath), { recursive: true });
98
- writeFileSync(filePath, f.content);
99
- }
100
- p.log.success(`Restored ${name} from ${info.repo}`);
101
- } else p.log.warn(`${name}: skill not found in ${info.repo}`);
102
- continue;
103
- }
104
- const skillDir = join(skillsDir, name);
105
- const referencesPath = join(skillDir, ".skilld");
106
- const globalCachePath = getCacheDir(pkgName, version);
107
- const spin = timedSpinner();
108
- if (isCached(pkgName, version)) {
109
- spin.start(`Linking ${name}`);
110
- mkdirSync(skillDir, { recursive: true });
111
- mkdirSync(referencesPath, { recursive: true });
112
- linkPkgSymlink(referencesPath, pkgName, cwd, version);
113
- for (const pkg of parsePackages(info.packages)) linkPkgNamed(skillDir, pkg.name, cwd, pkg.version);
114
- if (!pkgHasShippedDocs(pkgName, cwd, version) && !isReadmeOnly(globalCachePath)) {
115
- const docsLink = join(referencesPath, "docs");
116
- const cachedDocs = join(globalCachePath, "docs");
117
- if (existsSync(docsLink)) unlinkSync(docsLink);
118
- if (existsSync(cachedDocs)) symlinkSync(cachedDocs, docsLink, "junction");
119
- }
120
- const repoGh = info.repo ? parseGitHubUrl(`https://github.com/${info.repo}`) : null;
121
- const repoCachePath = repoGh ? getRepoCacheDir(repoGh.owner, repoGh.repo) : null;
122
- if (features.issues) {
123
- const issuesLink = join(referencesPath, "issues");
124
- const repoIssues = repoCachePath ? join(repoCachePath, "issues") : null;
125
- const cachedIssues = repoIssues && existsSync(repoIssues) ? repoIssues : join(globalCachePath, "issues");
126
- if (existsSync(issuesLink)) unlinkSync(issuesLink);
127
- if (existsSync(cachedIssues)) symlinkSync(cachedIssues, issuesLink, "junction");
128
- }
129
- if (features.discussions) {
130
- const discussionsLink = join(referencesPath, "discussions");
131
- const repoDiscussions = repoCachePath ? join(repoCachePath, "discussions") : null;
132
- const cachedDiscussions = repoDiscussions && existsSync(repoDiscussions) ? repoDiscussions : join(globalCachePath, "discussions");
133
- if (existsSync(discussionsLink)) unlinkSync(discussionsLink);
134
- if (existsSync(cachedDiscussions)) symlinkSync(cachedDiscussions, discussionsLink, "junction");
135
- }
136
- if (features.releases) {
137
- const releasesLink = join(referencesPath, "releases");
138
- const repoReleases = repoCachePath ? join(repoCachePath, "releases") : null;
139
- const cachedReleases = repoReleases && existsSync(repoReleases) ? repoReleases : join(globalCachePath, "releases");
140
- if (existsSync(releasesLink)) unlinkSync(releasesLink);
141
- if (existsSync(cachedReleases)) symlinkSync(cachedReleases, releasesLink, "junction");
142
- }
143
- const sectionsLink = join(referencesPath, "sections");
144
- const cachedSections = join(globalCachePath, "sections");
145
- if (existsSync(sectionsLink)) unlinkSync(sectionsLink);
146
- if (existsSync(cachedSections)) symlinkSync(cachedSections, sectionsLink, "junction");
147
- if (features.search && !existsSync(getPackageDbPath(pkgName, version))) {
148
- spin.message(`Indexing ${name}`);
149
- await indexResources({
150
- packageName: pkgName,
151
- version,
152
- cwd,
153
- docsToIndex: readCachedDocs(pkgName, version).map((d) => ({
154
- id: d.path,
155
- content: d.content,
156
- metadata: {
157
- package: pkgName,
158
- source: d.path,
159
- type: classifyCachedDoc(d.path).type
160
- }
161
- })),
162
- features,
163
- onProgress: (msg) => spin.message(msg)
164
- });
165
- }
166
- if (!copyFromExistingAgent(skillDir, name, allSkillsDirs)) {
167
- if (regenerateBaseSkillMd(skillDir, pkgName, version, cwd, allSkillNames, info.source, info.packages)) regenerated.push({
168
- name,
169
- pkgName,
170
- version,
171
- skillDir,
172
- packages: info.packages
173
- });
174
- }
175
- spin.stop(`Linked ${name}`);
30
+ const baseDir = isGlobal ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
31
+ if (!explicit && !existsSync(baseDir)) {
32
+ skipped.push({
33
+ agent: agentType,
34
+ reason: "skills dir not found"
35
+ });
176
36
  continue;
177
37
  }
178
- spin.start(`Downloading ${name}@${version}`);
179
- const resolved = await resolvePackageDocs(pkgName, { version });
180
- if (!resolved) {
181
- spin.stop(`Could not resolve: ${name}`);
38
+ if (isGlobal && (writtenDirs.has(baseDir) || agent.additionalSkillsDirs.some((d) => writtenDirs.has(d)))) {
39
+ skipped.push({
40
+ agent: agentType,
41
+ reason: "already covered by another agent dir"
42
+ });
182
43
  continue;
183
44
  }
184
- const cachedDocs = [];
185
- const docsToIndex = [];
186
- const isFrameworkDoc = (path) => filterFrameworkDocs([path], pkgName).length > 0;
187
- if (resolved.gitDocsUrl && resolved.repoUrl) {
188
- const gh = parseGitHubUrl(resolved.repoUrl);
189
- if (gh) {
190
- const gitDocs = await fetchGitDocs(gh.owner, gh.repo, version, pkgName);
191
- if (gitDocs?.files.length) {
192
- const BATCH_SIZE = 20;
193
- for (let i = 0; i < gitDocs.files.length; i += BATCH_SIZE) {
194
- const batch = gitDocs.files.slice(i, i + BATCH_SIZE);
195
- const results = await Promise.all(batch.map(async (file) => {
196
- const content = await fetchGitHubRaw(`${gitDocs.baseUrl}/${file}`);
197
- if (!content) return null;
198
- return {
199
- file,
200
- content
201
- };
202
- }));
203
- for (const r of results) if (r) {
204
- const stripped = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, "") : r.file;
205
- const cachePath = stripped.startsWith("docs/") ? stripped : `docs/${stripped}`;
206
- cachedDocs.push({
207
- path: cachePath,
208
- content: r.content
209
- });
210
- docsToIndex.push({
211
- id: cachePath,
212
- content: r.content,
213
- metadata: {
214
- package: pkgName,
215
- source: cachePath,
216
- type: "doc"
217
- }
218
- });
219
- }
220
- }
221
- if (isShallowGitDocs(cachedDocs.length) && resolved.llmsUrl) {
222
- cachedDocs.length = 0;
223
- docsToIndex.length = 0;
224
- } else if (cachedDocs.length > 0 && resolved.llmsUrl) {
225
- const llmsContent = await fetchLlmsTxt(resolved.llmsUrl);
226
- if (llmsContent) {
227
- const baseUrl = resolved.docsUrl || new URL(resolved.llmsUrl).origin;
228
- cachedDocs.push({
229
- path: "llms.txt",
230
- content: normalizeLlmsLinks(llmsContent.raw)
231
- });
232
- if (llmsContent.links.length > 0) {
233
- const docs = await downloadLlmsDocs(llmsContent, baseUrl);
234
- for (const doc of docs) {
235
- if (!isFrameworkDoc(doc.url)) continue;
236
- const localPath = doc.url.startsWith("/") ? doc.url.slice(1) : doc.url;
237
- cachedDocs.push({
238
- path: join("llms-docs", ...localPath.split("/")),
239
- content: doc.content
240
- });
241
- }
242
- }
243
- }
244
- }
245
- }
246
- }
247
- }
248
- if (resolved.llmsUrl && cachedDocs.length === 0) {
249
- const llmsContent = await fetchLlmsTxt(resolved.llmsUrl);
250
- if (llmsContent) {
251
- cachedDocs.push({
252
- path: "llms.txt",
253
- content: normalizeLlmsLinks(llmsContent.raw)
254
- });
255
- if (llmsContent.links.length > 0) {
256
- const docs = await downloadLlmsDocs(llmsContent, resolved.docsUrl || new URL(resolved.llmsUrl).origin);
257
- for (const doc of docs) {
258
- if (!isFrameworkDoc(doc.url)) continue;
259
- const cachePath = join("docs", ...(doc.url.startsWith("/") ? doc.url.slice(1) : doc.url).split("/"));
260
- cachedDocs.push({
261
- path: cachePath,
262
- content: doc.content
263
- });
264
- docsToIndex.push({
265
- id: doc.url,
266
- content: doc.content,
267
- metadata: {
268
- package: pkgName,
269
- source: cachePath,
270
- type: "doc"
271
- }
272
- });
273
- }
274
- }
275
- }
276
- }
277
- if (resolved.readmeUrl && cachedDocs.length === 0) {
278
- const content = await fetchReadmeContent(resolved.readmeUrl);
279
- if (content) {
280
- cachedDocs.push({
281
- path: "docs/README.md",
282
- content
283
- });
284
- docsToIndex.push({
285
- id: "README.md",
286
- content,
287
- metadata: {
288
- package: pkgName,
289
- source: "docs/README.md",
290
- type: "doc"
291
- }
292
- });
293
- }
294
- }
295
- if (cachedDocs.length > 0) {
296
- writeToCache(pkgName, version, cachedDocs);
297
- mkdirSync(referencesPath, { recursive: true });
298
- linkPkgSymlink(referencesPath, pkgName, cwd, version);
299
- for (const pkg of parsePackages(info.packages)) linkPkgNamed(skillDir, pkg.name, cwd, pkg.version);
300
- if (!isReadmeOnly(globalCachePath)) {
301
- const docsLink = join(referencesPath, "docs");
302
- const cachedDocsDir = join(globalCachePath, "docs");
303
- if (existsSync(docsLink)) unlinkSync(docsLink);
304
- if (existsSync(cachedDocsDir)) symlinkSync(cachedDocsDir, docsLink, "junction");
305
- }
306
- if (features.search) try {
307
- if (docsToIndex.length > 0) await createIndex(docsToIndex, { dbPath: getPackageDbPath(pkgName, version) });
308
- const pkgDir = resolvePkgDir(pkgName, cwd, version);
309
- const entryFiles = pkgDir ? await resolveEntryFiles(pkgDir) : [];
310
- if (entryFiles.length > 0) await createIndex(entryFiles.map((e) => ({
311
- id: e.path,
312
- content: e.content,
313
- metadata: {
314
- package: pkgName,
315
- source: `pkg/${e.path}`,
316
- type: e.type
317
- }
318
- })), { dbPath: getPackageDbPath(pkgName, version) });
319
- } catch (err) {
320
- if (!(err instanceof SearchDepsUnavailableError)) throw err;
321
- }
322
- if (!copyFromExistingAgent(skillDir, name, allSkillsDirs)) {
323
- if (regenerateBaseSkillMd(skillDir, pkgName, version, cwd, allSkillNames, info.source, info.packages)) regenerated.push({
324
- name,
325
- pkgName,
326
- version,
327
- skillDir,
328
- packages: info.packages
329
- });
330
- }
331
- spin.stop(`Downloaded and linked ${name}`);
332
- } else spin.stop(`No docs found for ${name}`);
333
- }
334
- if (regenerated.length > 0 && !readConfig().skipLlm) {
335
- const llmConfig = await selectLlmConfig(void 0, `Enhance SKILL.md for ${regenerated.map((r) => r.name).join(", ")}`);
336
- if (llmConfig?.promptOnly) {
337
- const features = readConfig().features ?? defaultFeatures;
338
- for (const { pkgName, version, skillDir } of regenerated) {
339
- const globalCachePath = getCacheDir(pkgName, version);
340
- writePromptFiles({
341
- packageName: pkgName,
342
- skillDir,
343
- version,
344
- hasIssues: existsSync(join(globalCachePath, "issues")),
345
- hasDiscussions: existsSync(join(globalCachePath, "discussions")),
346
- hasReleases: existsSync(join(globalCachePath, "releases")),
347
- hasChangelog: false,
348
- docsType: "docs",
349
- hasShippedDocs: false,
350
- pkgFiles: getPkgKeyFiles(pkgName, process.cwd(), version),
351
- sections: llmConfig.sections,
352
- customPrompt: llmConfig.customPrompt,
353
- features
354
- });
355
- }
356
- } else if (llmConfig) {
357
- p.log.step(getModelLabel(llmConfig.model));
358
- for (const { pkgName, version, skillDir, packages: pkgPackages } of regenerated) await enhanceRegenerated(pkgName, version, skillDir, llmConfig.model, llmConfig.sections, llmConfig.customPrompt, pkgPackages);
359
- }
360
- }
361
- for (const [name, info] of Object.entries(lock.skills)) writeLock(skillsDir, name, info);
362
- if (shared) for (const [name] of skills) linkSkillToAgents(name, shared, cwd, opts.agent);
363
- else syncLockfilesToDirs(lock, allSkillsDirs.filter((d) => d !== skillsDir));
364
- await shutdownWorker();
365
- p.outro("Install complete");
366
- }
367
- /** Copy SKILL.md from another agent's skill dir if one exists */
368
- function copyFromExistingAgent(skillDir, name, allSkillsDirs) {
369
- const targetMd = join(skillDir, "SKILL.md");
370
- if (existsSync(targetMd)) return false;
371
- for (const dir of allSkillsDirs) {
372
- if (dir === skillDir) continue;
373
- const candidateMd = join(dir, name, "SKILL.md");
374
- if (existsSync(candidateMd) && !lstatSync(candidateMd).isSymbolicLink()) {
375
- mkdirSync(skillDir, { recursive: true });
376
- copyFileSync(candidateMd, targetMd);
377
- return true;
378
- }
379
- }
380
- return false;
381
- }
382
- /** Try to recover original package name from sanitized name + source */
383
- function unsanitizeName(sanitized, source) {
384
- if (source?.includes("ungh://")) {
385
- const match = source.match(/ungh:\/\/([^/]+)\/(.+)/);
386
- if (match) return `@${match[1]}/${match[2]}`;
45
+ const skillDir = join(baseDir, sanitized);
46
+ const skilldDir = join(skillDir, ".skilld");
47
+ mkdirSync(skilldDir, { recursive: true });
48
+ writeFileSync(join(skilldDir, "_SKILL.md"), sanitizeMarkdown(repairMarkdown(skillContent)));
49
+ if (options.files) for (const [filename, content] of Object.entries(options.files)) writeFileSync(join(skillDir, filename), filename.endsWith(".md") ? sanitizeMarkdown(repairMarkdown(content)) : content);
50
+ installed.push(agentType);
51
+ paths.push(skillDir);
52
+ writtenDirs.add(baseDir);
387
53
  }
388
- if (sanitized.startsWith("antfu-")) return `@antfu/${sanitized.slice(6)}`;
389
- if (sanitized.startsWith("clack-")) return `@clack/${sanitized.slice(6)}`;
390
- if (sanitized.startsWith("nuxt-")) return `@nuxt/${sanitized.slice(5)}`;
391
- if (sanitized.startsWith("vue-")) return `@vue/${sanitized.slice(4)}`;
392
- if (sanitized.startsWith("vueuse-")) return `@vueuse/${sanitized.slice(7)}`;
393
- return sanitized;
394
- }
395
- /** Create pkg symlink inside references dir (links to entire package or cached dist) */
396
- function linkPkgSymlink(referencesDir, name, cwd, version) {
397
- const pkgPath = resolvePkgDir(name, cwd, version);
398
- if (!pkgPath) return;
399
- const pkgLink = join(referencesDir, "pkg");
400
- if (existsSync(pkgLink)) unlinkSync(pkgLink);
401
- symlinkSync(pkgPath, pkgLink, "junction");
402
- }
403
- /** Check if cache only has docs/README.md (pkg/ already has this) */
404
- function isReadmeOnly(cacheDir) {
405
- const docsDir = join(cacheDir, "docs");
406
- if (!existsSync(docsDir)) return false;
407
- const files = readdirSync(docsDir);
408
- return files.length === 1 && files[0] === "README.md";
54
+ return {
55
+ installed,
56
+ skipped,
57
+ paths
58
+ };
409
59
  }
410
- /** Check if package ships its own docs folder */
411
- function pkgHasShippedDocs(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
- /** Run LLM enhancement on a regenerated SKILL.md */
422
- async function enhanceRegenerated(pkgName, version, skillDir, model, sections, customPrompt, packages) {
423
- const llmLog = p.taskLog({
424
- title: `Agent exploring ${pkgName}`,
425
- limit: 3
426
- });
427
- const docFiles = listReferenceFiles(skillDir);
428
- const globalCachePath = getCacheDir(pkgName, version);
429
- const hasIssues = existsSync(join(globalCachePath, "issues"));
430
- const hasDiscussions = existsSync(join(globalCachePath, "discussions"));
431
- const hasGithub = hasIssues || hasDiscussions;
432
- const hasReleases = existsSync(join(globalCachePath, "releases"));
433
- const features = readConfig().features ?? defaultFeatures;
434
- const { optimized, wasOptimized } = await optimizeDocs({
435
- packageName: pkgName,
436
- skillDir,
437
- model,
438
- version,
439
- hasGithub,
440
- hasReleases,
441
- docFiles,
442
- sections,
443
- customPrompt,
444
- features,
445
- pkgFiles: getPkgKeyFiles(pkgName, process.cwd(), version),
446
- onProgress: createToolProgress(llmLog)
447
- });
448
- if (wasOptimized) {
449
- llmLog.success("Generated best practices");
450
- const cwd = process.cwd();
451
- const pkgPath = resolvePkgDir(pkgName, cwd, version);
452
- let description;
453
- if (pkgPath) {
454
- const pkgJsonResult = readPackageJsonSafe(join(pkgPath, "package.json"));
455
- if (pkgJsonResult) description = pkgJsonResult.parsed.description;
456
- }
457
- let docsType = "docs";
458
- if (existsSync(join(globalCachePath, "docs", "llms.txt"))) docsType = "llms.txt";
459
- else if (isReadmeOnly(globalCachePath)) docsType = "readme";
460
- const dirName = skillDir.split("/").pop();
461
- const allPackages = parsePackages(packages).map((p) => ({ name: p.name }));
462
- const skillMd = generateSkillMd({
463
- name: pkgName,
464
- version,
465
- description,
466
- body: optimized,
467
- relatedSkills: [],
468
- hasIssues,
469
- hasDiscussions,
470
- hasReleases,
471
- docsType,
472
- hasShippedDocs: hasShippedDocs(pkgName, cwd, version),
473
- pkgFiles: getPkgKeyFiles(pkgName, cwd, version),
474
- dirName,
475
- packages: allPackages.length > 1 ? allPackages : void 0,
476
- features
477
- });
478
- writeFileSync(join(skillDir, "SKILL.md"), skillMd);
479
- } else llmLog.message("Enhancement skipped");
480
- }
481
- const installCommandDef = defineCommand({
482
- meta: {
483
- name: "install",
484
- description: "Restore references from lockfile"
485
- },
486
- args: {
487
- global: sharedArgs.global,
488
- agent: sharedArgs.agent
489
- },
490
- async run({ args }) {
491
- let agent = resolveAgent(args.agent);
492
- if (!agent || agent === "none") {
493
- if (agent === "none") return;
494
- const picked = await promptForAgent();
495
- if (!picked || picked === "none") return;
496
- agent = picked;
60
+ function linkSkillToAgents(skillName, sharedDir, cwd, agentType) {
61
+ const targetAgents = agentType ? [[agentType, targets[agentType]]] : Object.entries(targets);
62
+ const linkedDirs = /* @__PURE__ */ new Set();
63
+ for (const [type, agent] of targetAgents) {
64
+ const agentSkillsDir = join(cwd, agent.skillsDir);
65
+ if (agentType === type) mkdirSync(agentSkillsDir, { recursive: true });
66
+ else {
67
+ if (!existsSync(agentSkillsDir)) continue;
68
+ if (agent.additionalSkillsDirs.map((d) => join(cwd, d)).some((d) => linkedDirs.has(d))) {
69
+ const staleTarget = join(agentSkillsDir, skillName);
70
+ try {
71
+ if (lstatSync(staleTarget).isSymbolicLink() && !existsSync(staleTarget)) unlinkSync(staleTarget);
72
+ } catch {}
73
+ continue;
74
+ }
497
75
  }
498
- p.intro(`\x1B[1m\x1B[35mskilld\x1B[0m install`);
499
- return installCommand({
500
- global: args.global,
501
- agent
502
- });
503
- }
504
- });
505
- /** Regenerate base SKILL.md from local metadata if missing */
506
- function regenerateBaseSkillMd(skillDir, pkgName, version, cwd, allSkillNames, source, packages) {
507
- const skillMdPath = join(skillDir, "SKILL.md");
508
- if (existsSync(skillMdPath)) return false;
509
- const pkgPath = resolvePkgDir(pkgName, cwd, version);
510
- let description;
511
- if (pkgPath) {
512
- const pkgResult = readPackageJsonSafe(join(pkgPath, "package.json"));
513
- if (pkgResult) description = pkgResult.parsed.description;
76
+ const target = join(agentSkillsDir, skillName);
77
+ let isSymlink = false;
78
+ let targetExists = false;
79
+ try {
80
+ const stat = lstatSync(target);
81
+ targetExists = true;
82
+ isSymlink = stat.isSymbolicLink();
83
+ } catch {}
84
+ if (targetExists && !isSymlink) continue;
85
+ if (isSymlink) unlinkSync(target);
86
+ symlinkSync(relative(agentSkillsDir, join(sharedDir, skillName)), target);
87
+ linkedDirs.add(agentSkillsDir);
514
88
  }
515
- const globalCachePath = getCacheDir(pkgName, version);
516
- let docsType = "docs";
517
- if (source?.includes("llms.txt") || existsSync(join(globalCachePath, "docs", "llms.txt"))) docsType = "llms.txt";
518
- else if (isReadmeOnly(globalCachePath)) docsType = "readme";
519
- const feat = readConfig().features ?? defaultFeatures;
520
- const hasIssues = feat.issues && existsSync(join(globalCachePath, "issues"));
521
- const hasDiscussions = feat.discussions && existsSync(join(globalCachePath, "discussions"));
522
- const hasReleases = feat.releases && existsSync(join(globalCachePath, "releases"));
523
- const relatedSkills = allSkillNames.filter((n) => n !== pkgName);
524
- const dirName = skillDir.split("/").pop();
525
- const allPackages = parsePackages(packages).map((p) => ({ name: p.name }));
526
- const content = generateSkillMd({
527
- name: pkgName,
528
- version,
529
- description,
530
- relatedSkills,
531
- hasIssues,
532
- hasDiscussions,
533
- hasReleases,
534
- docsType,
535
- hasShippedDocs: hasShippedDocs(pkgName, cwd, version),
536
- pkgFiles: getPkgKeyFiles(pkgName, cwd, version),
537
- dirName,
538
- packages: allPackages.length > 1 ? allPackages : void 0,
539
- features: readConfig().features ?? defaultFeatures
540
- });
541
- mkdirSync(skillDir, { recursive: true });
542
- writeFileSync(skillMdPath, content);
543
- return true;
544
89
  }
545
- /** Check if .skilld/ has broken symlinks or is missing expected references from global cache */
546
- function hasStaleReferences(referencesPath, pkgName, version, features) {
547
- for (const entry of readdirSync(referencesPath)) {
548
- const entryPath = join(referencesPath, entry);
549
- if (lstatSync(entryPath).isSymbolicLink() && !existsSync(entryPath)) return true;
90
+ function unlinkSkillFromAgents(skillName, cwd, agentType) {
91
+ const targetAgents = agentType ? [[agentType, targets[agentType]]] : Object.entries(targets);
92
+ for (const [, agent] of targetAgents) {
93
+ const target = join(cwd, agent.skillsDir, skillName);
94
+ try {
95
+ if (lstatSync(target).isSymbolicLink()) unlinkSync(target);
96
+ } catch {}
550
97
  }
551
- if (!existsSync(join(referencesPath, "pkg"))) return true;
552
- const globalCachePath = getCacheDir(pkgName, version);
553
- const expected = [
554
- ["docs", existsSync(join(globalCachePath, "docs"))],
555
- ["issues", features.issues && existsSync(join(globalCachePath, "issues"))],
556
- ["discussions", features.discussions && existsSync(join(globalCachePath, "discussions"))],
557
- ["releases", features.releases && existsSync(join(globalCachePath, "releases"))],
558
- ["sections", existsSync(join(globalCachePath, "sections"))]
559
- ];
560
- for (const [name, shouldExist] of expected) if (shouldExist && !existsSync(join(referencesPath, name))) return true;
561
- return false;
562
98
  }
563
- //#endregion
564
- export { installCommandDef };
99
+ export { unlinkSkillFromAgents as a, sanitizeName as i, installSkillForAgents as n, linkSkillToAgents as r, computeSkillDirName as t };
565
100
 
566
101
  //# sourceMappingURL=install.mjs.map