skilld 0.1.2 → 0.2.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.
- package/README.md +70 -120
- package/dist/_chunks/config.mjs +8 -2
- package/dist/_chunks/config.mjs.map +1 -1
- package/dist/_chunks/llm.mjs +710 -204
- package/dist/_chunks/llm.mjs.map +1 -1
- package/dist/_chunks/pool.mjs +115 -0
- package/dist/_chunks/pool.mjs.map +1 -0
- package/dist/_chunks/releases.mjs +689 -179
- package/dist/_chunks/releases.mjs.map +1 -1
- package/dist/_chunks/storage.mjs +311 -19
- package/dist/_chunks/storage.mjs.map +1 -1
- package/dist/_chunks/sync-parallel.mjs +134 -378
- package/dist/_chunks/sync-parallel.mjs.map +1 -1
- package/dist/_chunks/types.d.mts +9 -6
- package/dist/_chunks/types.d.mts.map +1 -1
- package/dist/_chunks/utils.d.mts +137 -68
- package/dist/_chunks/utils.d.mts.map +1 -1
- package/dist/_chunks/version.d.mts +43 -6
- package/dist/_chunks/version.d.mts.map +1 -1
- package/dist/agent/index.d.mts +58 -15
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +4 -2
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +2 -2
- package/dist/cli.mjs +2175 -1435
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +2 -2
- package/dist/retriv/index.d.mts +16 -2
- package/dist/retriv/index.d.mts.map +1 -1
- package/dist/retriv/index.mjs +44 -15
- package/dist/retriv/index.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +33 -0
- package/dist/retriv/worker.d.mts.map +1 -0
- package/dist/retriv/worker.mjs +47 -0
- package/dist/retriv/worker.mjs.map +1 -0
- package/dist/sources/index.d.mts +2 -2
- package/dist/sources/index.mjs +2 -2
- package/dist/types.d.mts +5 -3
- package/package.json +11 -7
|
@@ -1,26 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _ as
|
|
1
|
+
import { s as getVersionKey } from "./config.mjs";
|
|
2
|
+
import { _ as listReferenceFiles, b as resolvePkgDir, d as linkPkgNamed, i as getPkgKeyFiles, o as hasShippedDocs, r as ensureCacheDir, s as isCached } from "./storage.mjs";
|
|
3
3
|
import "../cache/index.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { A as resolveEntryFiles, E as parseGitHubUrl, S as fetchReadmeContent, _ as normalizeLlmsLinks, a as fetchPkgDist, c as readLocalDependencies, d as resolvePackageDocs, f as resolvePackageDocsWithAttempts, h as fetchLlmsTxt, p as downloadLlmsDocs, r as fetchNpmPackage, t as fetchReleaseNotes, u as resolveLocalPackageDocs, v as parseMarkdownLinks, y as fetchGitDocs } from "./releases.mjs";
|
|
4
|
+
import { h as searchNpmPackages, l as readLocalDependencies, m as resolvePackageDocsWithAttempts, o as fetchPkgDist } from "./releases.mjs";
|
|
6
5
|
import "../sources/index.mjs";
|
|
7
|
-
import {
|
|
6
|
+
import { a as generateSkillMd, i as optimizeDocs, m as computeSkillDirName, n as getModelLabel, x as agents } from "./llm.mjs";
|
|
8
7
|
import "../agent/index.mjs";
|
|
9
|
-
import {
|
|
10
|
-
import { join } from "
|
|
11
|
-
import { existsSync, mkdirSync,
|
|
12
|
-
import * as p from "@clack/prompts";
|
|
8
|
+
import { _ as defaultFeatures, a as fetchAndCacheResources, c as handleShippedSkills, d as resolveBaseDir, f as resolveLocalDep, g as formatDuration, h as writeLock, i as detectChangelog, l as indexResources, m as readLock, n as selectLlmConfig, o as findRelatedSkills, p as parsePackages, r as RESOLVE_STEP_LABELS, s as forceClearCache, t as ensureGitignore, u as linkAllReferences, v as readConfig, y as registerProject } from "../cli.mjs";
|
|
9
|
+
import { join } from "pathe";
|
|
10
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
13
11
|
import pLimit from "p-limit";
|
|
12
|
+
import * as p from "@clack/prompts";
|
|
14
13
|
import logUpdate from "log-update";
|
|
15
|
-
const RESOLVE_STEP_LABELS = {
|
|
16
|
-
"npm": "npm registry",
|
|
17
|
-
"github-docs": "GitHub docs",
|
|
18
|
-
"github-meta": "GitHub meta",
|
|
19
|
-
"github-search": "GitHub search",
|
|
20
|
-
"readme": "README",
|
|
21
|
-
"llms.txt": "llms.txt",
|
|
22
|
-
"local": "node_modules"
|
|
23
|
-
};
|
|
24
14
|
const STATUS_ICONS = {
|
|
25
15
|
pending: "○",
|
|
26
16
|
resolving: "◐",
|
|
@@ -62,8 +52,9 @@ async function syncPackagesParallel(config) {
|
|
|
62
52
|
const dim = "\x1B[90m";
|
|
63
53
|
const name = s.name.padEnd(maxNameLen);
|
|
64
54
|
const version = s.version ? `${dim}${s.version}${reset} ` : "";
|
|
55
|
+
const elapsed = (s.status === "done" || s.status === "error") && s.startedAt && s.completedAt ? ` ${dim}(${formatDuration(s.completedAt - s.startedAt)})${reset}` : "";
|
|
65
56
|
const preview = s.streamPreview ? ` ${dim}${s.streamPreview}${reset}` : "";
|
|
66
|
-
return ` ${color}${icon}${reset} ${name} ${version}${s.message}${preview}`;
|
|
57
|
+
return ` ${color}${icon}${reset} ${name} ${version}${s.message}${elapsed}${preview}`;
|
|
67
58
|
});
|
|
68
59
|
const doneCount = [...states.values()].filter((s) => s.status === "done").length;
|
|
69
60
|
const errorCount = [...states.values()].filter((s) => s.status === "error").length;
|
|
@@ -71,6 +62,8 @@ async function syncPackagesParallel(config) {
|
|
|
71
62
|
}
|
|
72
63
|
function update(pkg, status, message, version) {
|
|
73
64
|
const state = states.get(pkg);
|
|
65
|
+
if (!state.startedAt && status !== "pending") state.startedAt = performance.now();
|
|
66
|
+
if ((status === "done" || status === "error") && !state.completedAt) state.completedAt = performance.now();
|
|
74
67
|
state.status = status;
|
|
75
68
|
state.message = message;
|
|
76
69
|
state.streamPreview = void 0;
|
|
@@ -80,13 +73,18 @@ async function syncPackagesParallel(config) {
|
|
|
80
73
|
ensureCacheDir();
|
|
81
74
|
render();
|
|
82
75
|
const limit = pLimit(concurrency);
|
|
76
|
+
const skillData = /* @__PURE__ */ new Map();
|
|
83
77
|
const baseResults = await Promise.allSettled(packages.map((pkg) => limit(() => syncBaseSkill(pkg, config, cwd, update))));
|
|
84
78
|
logUpdate.done();
|
|
85
79
|
const successfulPkgs = [];
|
|
80
|
+
const shippedPkgs = [];
|
|
86
81
|
const errors = [];
|
|
87
82
|
for (let i = 0; i < baseResults.length; i++) {
|
|
88
83
|
const r = baseResults[i];
|
|
89
|
-
if (r.status === "fulfilled" && r.value !== "shipped")
|
|
84
|
+
if (r.status === "fulfilled" && r.value !== "shipped") {
|
|
85
|
+
successfulPkgs.push(packages[i]);
|
|
86
|
+
skillData.set(packages[i], r.value);
|
|
87
|
+
} else if (r.status === "fulfilled" && r.value === "shipped") shippedPkgs.push(packages[i]);
|
|
90
88
|
else if (r.status === "rejected") {
|
|
91
89
|
const err = r.reason;
|
|
92
90
|
const reason = err instanceof Error ? `${err.message}\n${err.stack}` : String(err);
|
|
@@ -96,35 +94,32 @@ async function syncPackagesParallel(config) {
|
|
|
96
94
|
});
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
|
-
|
|
97
|
+
const skillMsg = `Created ${successfulPkgs.length} base skills${shippedPkgs.length > 1 ? ` (Skipping ${shippedPkgs.length})` : ""}`;
|
|
98
|
+
p.log.success(skillMsg);
|
|
100
99
|
if (errors.length > 0) for (const { pkg, reason } of errors) p.log.error(` ${pkg}: ${reason}`);
|
|
101
100
|
const globalConfig = readConfig();
|
|
102
101
|
if (successfulPkgs.length > 0 && !globalConfig.skipLlm && !(config.yes && !config.model)) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
model
|
|
120
|
-
}, cwd, update, sections, customPrompt))));
|
|
121
|
-
logUpdate.done();
|
|
122
|
-
const llmSucceeded = llmResults.filter((r) => r.status === "fulfilled").length;
|
|
123
|
-
p.log.success(`Enhanced ${llmSucceeded}/${successfulPkgs.length} skills with LLM`);
|
|
124
|
-
}
|
|
102
|
+
const llmConfig = await selectLlmConfig(config.model);
|
|
103
|
+
if (llmConfig) {
|
|
104
|
+
p.log.step(getModelLabel(llmConfig.model));
|
|
105
|
+
for (const pkg of successfulPkgs) states.set(pkg, {
|
|
106
|
+
name: pkg,
|
|
107
|
+
status: "pending",
|
|
108
|
+
message: "Waiting..."
|
|
109
|
+
});
|
|
110
|
+
render();
|
|
111
|
+
const llmResults = await Promise.allSettled(successfulPkgs.map((pkg) => limit(() => enhanceWithLLM(pkg, skillData.get(pkg), {
|
|
112
|
+
...config,
|
|
113
|
+
model: llmConfig.model
|
|
114
|
+
}, cwd, update, llmConfig.sections, llmConfig.customPrompt))));
|
|
115
|
+
logUpdate.done();
|
|
116
|
+
const llmSucceeded = llmResults.filter((r) => r.status === "fulfilled").length;
|
|
117
|
+
p.log.success(`Enhanced ${llmSucceeded}/${successfulPkgs.length} skills with LLM`);
|
|
125
118
|
}
|
|
126
119
|
}
|
|
127
120
|
await ensureGitignore(agent.skillsDir, cwd, config.global);
|
|
121
|
+
const { shutdownWorker } = await import("./pool.mjs");
|
|
122
|
+
await shutdownWorker();
|
|
128
123
|
p.outro(`Synced ${successfulPkgs.length}/${packages.length} packages`);
|
|
129
124
|
}
|
|
130
125
|
async function syncBaseSkill(packageName, config, cwd, update) {
|
|
@@ -136,25 +131,17 @@ async function syncBaseSkill(packageName, config, cwd, update) {
|
|
|
136
131
|
});
|
|
137
132
|
let resolved = resolvedPkg;
|
|
138
133
|
if (!resolved) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
142
|
-
const depVersion = {
|
|
143
|
-
...pkg.dependencies,
|
|
144
|
-
...pkg.devDependencies
|
|
145
|
-
}[packageName];
|
|
146
|
-
if (depVersion?.startsWith("link:")) {
|
|
147
|
-
update(packageName, "resolving", "Local package...");
|
|
148
|
-
const { resolve } = await import("node:path");
|
|
149
|
-
resolved = await resolveLocalPackageDocs(resolve(cwd, depVersion.slice(5)));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
134
|
+
update(packageName, "resolving", "Local package...");
|
|
135
|
+
resolved = await resolveLocalDep(packageName, cwd);
|
|
152
136
|
}
|
|
153
137
|
if (!resolved) {
|
|
154
138
|
const npmAttempt = attempts.find((a) => a.source === "npm");
|
|
155
139
|
let reason;
|
|
156
|
-
if (npmAttempt?.status === "not-found")
|
|
157
|
-
|
|
140
|
+
if (npmAttempt?.status === "not-found") {
|
|
141
|
+
const suggestions = await searchNpmPackages(packageName, 3);
|
|
142
|
+
const hint = suggestions.length > 0 ? ` (try: ${suggestions.map((s) => s.name).join(", ")})` : "";
|
|
143
|
+
reason = (npmAttempt.message || "Not on npm") + hint;
|
|
144
|
+
} else reason = attempts.filter((a) => a.status !== "success").map((a) => a.message || a.source).join("; ") || "No docs found";
|
|
158
145
|
update(packageName, "error", reason);
|
|
159
146
|
throw new Error(`Could not find docs for: ${packageName}`);
|
|
160
147
|
}
|
|
@@ -164,218 +151,54 @@ async function syncBaseSkill(packageName, config, cwd, update) {
|
|
|
164
151
|
update(packageName, "downloading", "Downloading dist...", versionKey);
|
|
165
152
|
await fetchPkgDist(packageName, version);
|
|
166
153
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const agent = agents[config.agent];
|
|
170
|
-
const baseDir = config.global ? join(CACHE_DIR, "skills") : join(cwd, agent.skillsDir);
|
|
171
|
-
mkdirSync(baseDir, { recursive: true });
|
|
172
|
-
for (const shipped of shippedSkills) {
|
|
173
|
-
linkShippedSkill(baseDir, shipped.skillName, shipped.skillDir);
|
|
174
|
-
writeLock(baseDir, shipped.skillName, {
|
|
175
|
-
packageName,
|
|
176
|
-
version,
|
|
177
|
-
source: "shipped",
|
|
178
|
-
syncedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
179
|
-
generator: "skilld"
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
if (!config.global) registerProject(cwd);
|
|
183
|
-
update(packageName, "done", "Shipped", versionKey);
|
|
154
|
+
if (handleShippedSkills(packageName, version, cwd, config.agent, config.global)) {
|
|
155
|
+
update(packageName, "done", "Published SKILL.md", versionKey);
|
|
184
156
|
return "shipped";
|
|
185
157
|
}
|
|
186
|
-
if (config.force)
|
|
187
|
-
clearCache(packageName, version);
|
|
188
|
-
const forcedDbPath = getPackageDbPath(packageName, version);
|
|
189
|
-
if (existsSync(forcedDbPath)) rmSync(forcedDbPath, {
|
|
190
|
-
recursive: true,
|
|
191
|
-
force: true
|
|
192
|
-
});
|
|
193
|
-
}
|
|
158
|
+
if (config.force) forceClearCache(packageName, version);
|
|
194
159
|
const useCache = isCached(packageName, version);
|
|
195
160
|
if (useCache) update(packageName, "downloading", "Using cache", versionKey);
|
|
196
161
|
else update(packageName, "downloading", config.force ? "Re-fetching docs..." : "Fetching docs...", versionKey);
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
const skillDir = join(baseDir,
|
|
162
|
+
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
163
|
+
const skillDirName = computeSkillDirName(packageName, resolved.repoUrl);
|
|
164
|
+
const skillDir = join(baseDir, skillDirName);
|
|
200
165
|
mkdirSync(skillDir, { recursive: true });
|
|
201
|
-
let docSource = resolved.readmeUrl || "readme";
|
|
202
|
-
let docsType = "readme";
|
|
203
|
-
const docsToIndex = [];
|
|
204
|
-
if (!useCache) {
|
|
205
|
-
const cachedDocs = [];
|
|
206
|
-
if (resolved.gitDocsUrl && resolved.repoUrl) {
|
|
207
|
-
const gh = parseGitHubUrl(resolved.repoUrl);
|
|
208
|
-
if (gh) {
|
|
209
|
-
update(packageName, "downloading", "Git docs...", versionKey);
|
|
210
|
-
const gitDocs = await fetchGitDocs(gh.owner, gh.repo, version, packageName);
|
|
211
|
-
if (gitDocs && gitDocs.files.length > 0) {
|
|
212
|
-
update(packageName, "downloading", `0/${gitDocs.files.length} docs @ ${gitDocs.ref}`, versionKey);
|
|
213
|
-
const BATCH_SIZE = 20;
|
|
214
|
-
const results = [];
|
|
215
|
-
let downloaded = 0;
|
|
216
|
-
for (let i = 0; i < gitDocs.files.length; i += BATCH_SIZE) {
|
|
217
|
-
const batch = gitDocs.files.slice(i, i + BATCH_SIZE);
|
|
218
|
-
const batchResults = await Promise.all(batch.map(async (file) => {
|
|
219
|
-
const url = `${gitDocs.baseUrl}/${file}`;
|
|
220
|
-
const res = await fetch(url, { headers: { "User-Agent": "skilld/1.0" } }).catch(() => null);
|
|
221
|
-
if (!res?.ok) return null;
|
|
222
|
-
const content = await res.text();
|
|
223
|
-
downloaded++;
|
|
224
|
-
update(packageName, "downloading", `${downloaded}/${gitDocs.files.length} docs @ ${gitDocs.ref}`, versionKey);
|
|
225
|
-
return {
|
|
226
|
-
file,
|
|
227
|
-
content
|
|
228
|
-
};
|
|
229
|
-
}));
|
|
230
|
-
results.push(...batchResults);
|
|
231
|
-
}
|
|
232
|
-
for (const r of results) if (r) {
|
|
233
|
-
const cachePath = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, "") : r.file;
|
|
234
|
-
cachedDocs.push({
|
|
235
|
-
path: cachePath,
|
|
236
|
-
content: r.content
|
|
237
|
-
});
|
|
238
|
-
docsToIndex.push({
|
|
239
|
-
id: cachePath,
|
|
240
|
-
content: r.content,
|
|
241
|
-
metadata: {
|
|
242
|
-
package: packageName,
|
|
243
|
-
source: cachePath,
|
|
244
|
-
type: "doc"
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
if (results.filter(Boolean).length > 0) {
|
|
249
|
-
docSource = `${resolved.repoUrl}/tree/${gitDocs.ref}/docs`;
|
|
250
|
-
docsType = "docs";
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (resolved.llmsUrl && cachedDocs.length === 0) {
|
|
256
|
-
update(packageName, "downloading", "Fetching llms.txt...", versionKey);
|
|
257
|
-
const llmsContent = await fetchLlmsTxt(resolved.llmsUrl);
|
|
258
|
-
if (llmsContent) {
|
|
259
|
-
docSource = resolved.llmsUrl;
|
|
260
|
-
docsType = "llms.txt";
|
|
261
|
-
cachedDocs.push({
|
|
262
|
-
path: "llms.txt",
|
|
263
|
-
content: normalizeLlmsLinks(llmsContent.raw)
|
|
264
|
-
});
|
|
265
|
-
if (llmsContent.links.length > 0) {
|
|
266
|
-
update(packageName, "downloading", `0/${llmsContent.links.length} linked docs...`, versionKey);
|
|
267
|
-
const docs = await downloadLlmsDocs(llmsContent, resolved.docsUrl || new URL(resolved.llmsUrl).origin);
|
|
268
|
-
for (const doc of docs) {
|
|
269
|
-
const cachePath = join("docs", ...(doc.url.startsWith("/") ? doc.url.slice(1) : doc.url).split("/"));
|
|
270
|
-
cachedDocs.push({
|
|
271
|
-
path: cachePath,
|
|
272
|
-
content: doc.content
|
|
273
|
-
});
|
|
274
|
-
docsToIndex.push({
|
|
275
|
-
id: doc.url,
|
|
276
|
-
content: doc.content,
|
|
277
|
-
metadata: {
|
|
278
|
-
package: packageName,
|
|
279
|
-
source: cachePath,
|
|
280
|
-
type: "doc"
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
if (resolved.readmeUrl && cachedDocs.length === 0) {
|
|
288
|
-
update(packageName, "downloading", "Fetching README...", versionKey);
|
|
289
|
-
const content = await fetchReadmeContent(resolved.readmeUrl);
|
|
290
|
-
if (content) {
|
|
291
|
-
cachedDocs.push({
|
|
292
|
-
path: "docs/README.md",
|
|
293
|
-
content
|
|
294
|
-
});
|
|
295
|
-
docsToIndex.push({
|
|
296
|
-
id: "README.md",
|
|
297
|
-
content,
|
|
298
|
-
metadata: {
|
|
299
|
-
package: packageName,
|
|
300
|
-
source: "docs/README.md",
|
|
301
|
-
type: "doc"
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
if (cachedDocs.length > 0) writeToCache(packageName, version, cachedDocs);
|
|
307
|
-
} else {
|
|
308
|
-
const cacheDir = getCacheDir(packageName, version);
|
|
309
|
-
if (existsSync(join(cacheDir, "docs", "index.md")) || existsSync(join(cacheDir, "docs", "guide"))) docsType = "docs";
|
|
310
|
-
else if (existsSync(join(cacheDir, "llms.txt"))) docsType = "llms.txt";
|
|
311
|
-
if (!existsSync(getPackageDbPath(packageName, version))) {
|
|
312
|
-
const cached = readCachedDocs(packageName, version);
|
|
313
|
-
for (const doc of cached) docsToIndex.push({
|
|
314
|
-
id: doc.path,
|
|
315
|
-
content: doc.content,
|
|
316
|
-
metadata: {
|
|
317
|
-
package: packageName,
|
|
318
|
-
source: doc.path,
|
|
319
|
-
type: "doc"
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
166
|
const features = readConfig().features ?? defaultFeatures;
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
for (const doc of releaseDocs) docsToIndex.push({
|
|
334
|
-
id: doc.path,
|
|
335
|
-
content: doc.content,
|
|
336
|
-
metadata: {
|
|
337
|
-
package: packageName,
|
|
338
|
-
source: doc.path,
|
|
339
|
-
type: "release"
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
167
|
+
const resources = await fetchAndCacheResources({
|
|
168
|
+
packageName,
|
|
169
|
+
resolved,
|
|
170
|
+
version,
|
|
171
|
+
useCache,
|
|
172
|
+
features,
|
|
173
|
+
onProgress: (msg) => update(packageName, "downloading", msg, versionKey)
|
|
174
|
+
});
|
|
345
175
|
update(packageName, "downloading", "Linking references...", versionKey);
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
if (entryFiles.length > 0) for (const e of entryFiles) docsToIndex.push({
|
|
356
|
-
id: e.path,
|
|
357
|
-
content: e.content,
|
|
358
|
-
metadata: {
|
|
359
|
-
package: packageName,
|
|
360
|
-
source: `pkg/${e.path}`,
|
|
361
|
-
type: e.type
|
|
362
|
-
}
|
|
176
|
+
linkAllReferences(skillDir, packageName, cwd, version, resources.docsType);
|
|
177
|
+
update(packageName, "embedding", "Indexing docs", versionKey);
|
|
178
|
+
await indexResources({
|
|
179
|
+
packageName,
|
|
180
|
+
version,
|
|
181
|
+
cwd,
|
|
182
|
+
docsToIndex: resources.docsToIndex,
|
|
183
|
+
features,
|
|
184
|
+
onProgress: (msg) => update(packageName, "embedding", msg, versionKey)
|
|
363
185
|
});
|
|
364
|
-
const
|
|
365
|
-
if (docsToIndex.length > 0) {
|
|
366
|
-
update(packageName, "embedding", `Indexing ${docsToIndex.length} documents...`, versionKey);
|
|
367
|
-
await createIndex(docsToIndex, {
|
|
368
|
-
dbPath,
|
|
369
|
-
onProgress: (current, total, doc) => {
|
|
370
|
-
update(packageName, "embedding", `Indexing ${doc?.type === "source" || doc?.type === "types" ? "code" : "doc"} ${doc?.id ? doc.id.split("/").pop() : ""}... ${current}/${total} ${Math.round(current / total * 100)}%`, versionKey);
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
const hasReleases = existsSync(releasesPath);
|
|
375
|
-
const hasChangelog = pkgDir ? ["CHANGELOG.md", "changelog.md"].find((f) => existsSync(join(pkgDir, f))) || false : false;
|
|
186
|
+
const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version));
|
|
376
187
|
const relatedSkills = await findRelatedSkills(packageName, baseDir);
|
|
377
188
|
const shippedDocs = hasShippedDocs(packageName, cwd, version);
|
|
378
189
|
const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
|
|
190
|
+
const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
|
|
191
|
+
linkPkgNamed(skillDir, packageName, cwd, version);
|
|
192
|
+
writeLock(baseDir, skillDirName, {
|
|
193
|
+
packageName,
|
|
194
|
+
version,
|
|
195
|
+
repo: repoSlug,
|
|
196
|
+
source: resources.docSource,
|
|
197
|
+
syncedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
198
|
+
generator: "skilld"
|
|
199
|
+
});
|
|
200
|
+
const updatedLock = readLock(baseDir)?.skills[skillDirName];
|
|
201
|
+
const allPackages = parsePackages(updatedLock?.packages).map((p) => ({ name: p.name }));
|
|
379
202
|
const skillMd = generateSkillMd({
|
|
380
203
|
name: packageName,
|
|
381
204
|
version,
|
|
@@ -384,106 +207,60 @@ async function syncBaseSkill(packageName, config, cwd, update) {
|
|
|
384
207
|
dependencies: resolved.dependencies,
|
|
385
208
|
distTags: resolved.distTags,
|
|
386
209
|
relatedSkills,
|
|
387
|
-
|
|
388
|
-
|
|
210
|
+
hasIssues: resources.hasIssues,
|
|
211
|
+
hasDiscussions: resources.hasDiscussions,
|
|
212
|
+
hasReleases: resources.hasReleases,
|
|
389
213
|
hasChangelog,
|
|
390
|
-
docsType,
|
|
214
|
+
docsType: resources.docsType,
|
|
391
215
|
hasShippedDocs: shippedDocs,
|
|
392
|
-
pkgFiles
|
|
216
|
+
pkgFiles,
|
|
217
|
+
dirName: skillDirName,
|
|
218
|
+
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
219
|
+
repoUrl: resolved.repoUrl
|
|
393
220
|
});
|
|
394
221
|
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
395
|
-
writeLock(baseDir, sanitizeName(packageName), {
|
|
396
|
-
packageName,
|
|
397
|
-
version,
|
|
398
|
-
source: docSource,
|
|
399
|
-
syncedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
400
|
-
generator: "skilld"
|
|
401
|
-
});
|
|
402
222
|
if (!config.global) registerProject(cwd);
|
|
403
|
-
update(packageName, "done", "
|
|
404
|
-
return
|
|
223
|
+
update(packageName, "done", "Base skill created", versionKey);
|
|
224
|
+
return {
|
|
225
|
+
resolved,
|
|
226
|
+
version,
|
|
227
|
+
skillDirName,
|
|
228
|
+
docsType: resources.docsType,
|
|
229
|
+
hasIssues: resources.hasIssues,
|
|
230
|
+
hasDiscussions: resources.hasDiscussions,
|
|
231
|
+
hasReleases: resources.hasReleases,
|
|
232
|
+
hasChangelog,
|
|
233
|
+
shippedDocs,
|
|
234
|
+
pkgFiles,
|
|
235
|
+
relatedSkills,
|
|
236
|
+
packages: allPackages.length > 1 ? allPackages : void 0
|
|
237
|
+
};
|
|
405
238
|
}
|
|
406
|
-
async function enhanceWithLLM(packageName, config, cwd, update, sections, customPrompt) {
|
|
407
|
-
const
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
const version = localVersion || resolved.version || "latest";
|
|
411
|
-
const versionKey = getVersionKey(version);
|
|
412
|
-
const agent = agents[config.agent];
|
|
413
|
-
const baseDir = config.global ? join(CACHE_DIR, "skills") : join(cwd, agent.skillsDir);
|
|
414
|
-
const skillDir = join(baseDir, sanitizeName(packageName));
|
|
415
|
-
const cacheDir = getCacheDir(packageName, version);
|
|
416
|
-
let docsContent = null;
|
|
417
|
-
let llmsRaw = null;
|
|
418
|
-
let docsType = "readme";
|
|
419
|
-
if (existsSync(join(cacheDir, "docs", "index.md")) || existsSync(join(cacheDir, "docs", "guide"))) docsType = "docs";
|
|
420
|
-
else if (existsSync(join(cacheDir, "llms.txt"))) docsType = "llms.txt";
|
|
421
|
-
const guideDir = join(cacheDir, "docs", "guide");
|
|
422
|
-
const docsDir = join(cacheDir, "docs");
|
|
423
|
-
if (existsSync(guideDir) || existsSync(join(docsDir, "index.md"))) {
|
|
424
|
-
const sections = [];
|
|
425
|
-
const indexPath = join(docsDir, "index.md");
|
|
426
|
-
if (existsSync(indexPath)) sections.push(readFileSync(indexPath, "utf-8"));
|
|
427
|
-
if (existsSync(guideDir)) {
|
|
428
|
-
const priorityFiles = [
|
|
429
|
-
"index.md",
|
|
430
|
-
"features.md",
|
|
431
|
-
"migration.md",
|
|
432
|
-
"why.md"
|
|
433
|
-
];
|
|
434
|
-
const guideFiles = readdirSync(guideDir, { withFileTypes: true }).filter((f) => f.isFile() && f.name.endsWith(".md")).map((f) => f.name).sort((a, b) => {
|
|
435
|
-
const aIdx = priorityFiles.indexOf(a);
|
|
436
|
-
const bIdx = priorityFiles.indexOf(b);
|
|
437
|
-
if (aIdx >= 0 && bIdx >= 0) return aIdx - bIdx;
|
|
438
|
-
if (aIdx >= 0) return -1;
|
|
439
|
-
if (bIdx >= 0) return 1;
|
|
440
|
-
return a.localeCompare(b);
|
|
441
|
-
});
|
|
442
|
-
for (const file of guideFiles.slice(0, 10)) {
|
|
443
|
-
const content = readFileSync(join(guideDir, file), "utf-8");
|
|
444
|
-
sections.push(`# guide/${file}\n\n${content}`);
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
if (sections.length > 0) docsContent = sections.join("\n\n---\n\n");
|
|
448
|
-
}
|
|
449
|
-
if (!docsContent) {
|
|
450
|
-
if (existsSync(join(cacheDir, "llms.txt"))) llmsRaw = readFileSync(join(cacheDir, "llms.txt"), "utf-8");
|
|
451
|
-
if (llmsRaw) {
|
|
452
|
-
const bestPracticesPaths = parseMarkdownLinks(llmsRaw).map((l) => l.url).filter((lp) => lp.includes("/style-guide/") || lp.includes("/best-practices/") || lp.includes("/typescript/"));
|
|
453
|
-
const sections = [];
|
|
454
|
-
for (const mdPath of bestPracticesPaths) {
|
|
455
|
-
const filePath = join(cacheDir, "docs", mdPath.startsWith("/") ? mdPath.slice(1) : mdPath);
|
|
456
|
-
if (existsSync(filePath)) {
|
|
457
|
-
const content = readFileSync(filePath, "utf-8");
|
|
458
|
-
sections.push(`# ${mdPath}\n\n${content}`);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
docsContent = sections.length > 0 ? sections.join("\n\n---\n\n") : llmsRaw;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
if (!docsContent) {
|
|
465
|
-
const readmePath = join(cacheDir, "docs", "README.md");
|
|
466
|
-
if (existsSync(readmePath)) docsContent = readFileSync(readmePath, "utf-8");
|
|
467
|
-
}
|
|
468
|
-
const hasGithub = existsSync(join(cacheDir, "github"));
|
|
469
|
-
const hasReleases = existsSync(join(cacheDir, "releases"));
|
|
470
|
-
const hasChangelog = ["CHANGELOG.md", "changelog.md"].find((f) => existsSync(join(cwd, "node_modules", packageName, f))) || false;
|
|
239
|
+
async function enhanceWithLLM(packageName, data, config, cwd, update, sections, customPrompt) {
|
|
240
|
+
const versionKey = getVersionKey(data.version);
|
|
241
|
+
const skillDir = join(resolveBaseDir(cwd, config.agent, config.global), data.skillDirName);
|
|
242
|
+
const hasGithub = data.hasIssues || data.hasDiscussions;
|
|
471
243
|
const docFiles = listReferenceFiles(skillDir);
|
|
472
244
|
update(packageName, "generating", config.model, versionKey);
|
|
473
245
|
const { optimized, wasOptimized, error } = await optimizeDocs({
|
|
474
246
|
packageName,
|
|
475
247
|
skillDir,
|
|
476
248
|
model: config.model,
|
|
477
|
-
version,
|
|
249
|
+
version: data.version,
|
|
478
250
|
hasGithub,
|
|
479
|
-
hasReleases,
|
|
480
|
-
hasChangelog,
|
|
251
|
+
hasReleases: data.hasReleases,
|
|
252
|
+
hasChangelog: data.hasChangelog,
|
|
481
253
|
docFiles,
|
|
254
|
+
docsType: data.docsType,
|
|
255
|
+
hasShippedDocs: data.shippedDocs,
|
|
482
256
|
noCache: config.force,
|
|
257
|
+
debug: config.debug,
|
|
483
258
|
sections,
|
|
484
259
|
customPrompt,
|
|
485
260
|
onProgress: (progress) => {
|
|
486
|
-
|
|
261
|
+
const status = progress.type === "reasoning" ? "exploring" : "generating";
|
|
262
|
+
const sectionPrefix = progress.section ? `[${progress.section}] ` : "";
|
|
263
|
+
update(packageName, status, progress.chunk.startsWith("[") ? `${sectionPrefix}${progress.chunk}` : `${sectionPrefix}${config.model}`, versionKey);
|
|
487
264
|
}
|
|
488
265
|
});
|
|
489
266
|
if (error) {
|
|
@@ -491,49 +268,28 @@ async function enhanceWithLLM(packageName, config, cwd, update, sections, custom
|
|
|
491
268
|
throw new Error(error);
|
|
492
269
|
}
|
|
493
270
|
if (wasOptimized) {
|
|
494
|
-
const relatedSkills = await findRelatedSkills(packageName, baseDir);
|
|
495
|
-
const shippedDocs = hasShippedDocs(packageName, cwd, version);
|
|
496
|
-
const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
|
|
497
|
-
const body = cleanSkillMd(optimized);
|
|
498
271
|
const skillMd = generateSkillMd({
|
|
499
272
|
name: packageName,
|
|
500
|
-
version,
|
|
501
|
-
releasedAt: resolved.releasedAt,
|
|
502
|
-
dependencies: resolved.dependencies,
|
|
503
|
-
distTags: resolved.distTags,
|
|
504
|
-
body,
|
|
505
|
-
relatedSkills,
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
273
|
+
version: data.version,
|
|
274
|
+
releasedAt: data.resolved.releasedAt,
|
|
275
|
+
dependencies: data.resolved.dependencies,
|
|
276
|
+
distTags: data.resolved.distTags,
|
|
277
|
+
body: optimized,
|
|
278
|
+
relatedSkills: data.relatedSkills,
|
|
279
|
+
hasIssues: data.hasIssues,
|
|
280
|
+
hasDiscussions: data.hasDiscussions,
|
|
281
|
+
hasReleases: data.hasReleases,
|
|
282
|
+
hasChangelog: data.hasChangelog,
|
|
283
|
+
docsType: data.docsType,
|
|
284
|
+
hasShippedDocs: data.shippedDocs,
|
|
285
|
+
pkgFiles: data.pkgFiles,
|
|
286
|
+
dirName: data.skillDirName,
|
|
287
|
+
packages: data.packages,
|
|
288
|
+
repoUrl: data.resolved.repoUrl
|
|
512
289
|
});
|
|
513
290
|
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
514
291
|
}
|
|
515
|
-
update(packageName, "done", "
|
|
516
|
-
}
|
|
517
|
-
async function findRelatedSkills(packageName, skillsDir) {
|
|
518
|
-
const related = [];
|
|
519
|
-
const npmInfo = await fetchNpmPackage(packageName);
|
|
520
|
-
if (!npmInfo?.dependencies) return related;
|
|
521
|
-
const deps = Object.keys(npmInfo.dependencies);
|
|
522
|
-
if (!existsSync(skillsDir)) return related;
|
|
523
|
-
const installedSkills = readdirSync(skillsDir);
|
|
524
|
-
for (const skill of installedSkills) if (deps.some((d) => sanitizeName(d) === skill)) related.push(skill);
|
|
525
|
-
return related.slice(0, 5);
|
|
526
|
-
}
|
|
527
|
-
function cleanSkillMd(content) {
|
|
528
|
-
let cleaned = content.replace(/^```markdown\n?/m, "").replace(/\n?```$/m, "").trim();
|
|
529
|
-
const fmMatch = cleaned.match(/^-{3,}\n/);
|
|
530
|
-
if (fmMatch) {
|
|
531
|
-
const afterOpen = fmMatch[0].length;
|
|
532
|
-
const closeMatch = cleaned.slice(afterOpen).match(/\n-{3,}/);
|
|
533
|
-
if (closeMatch) cleaned = cleaned.slice(afterOpen + closeMatch.index + closeMatch[0].length).trim();
|
|
534
|
-
else cleaned = cleaned.slice(afterOpen).trim();
|
|
535
|
-
}
|
|
536
|
-
return cleaned;
|
|
292
|
+
update(packageName, "done", "Skill optimized", versionKey);
|
|
537
293
|
}
|
|
538
294
|
export { syncPackagesParallel };
|
|
539
295
|
|