skilld 1.7.0 → 1.7.1

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