skilld 1.7.2 → 1.7.4
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/dist/_chunks/agent.mjs +693 -599
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +3 -3
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author-group.mjs.map +1 -1
- package/dist/_chunks/author.mjs +51 -121
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +315 -9
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +2 -2
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs +3 -3
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/core.mjs +7 -4
- package/dist/_chunks/detect.mjs +1 -1
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/embedding-cache2.mjs +2 -2
- package/dist/_chunks/embedding-cache2.mjs.map +1 -1
- package/dist/_chunks/index.d.mts +305 -112
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +267 -32
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +32 -577
- package/dist/_chunks/index3.d.mts.map +1 -1
- package/dist/_chunks/index4.d.mts +553 -0
- package/dist/_chunks/index4.d.mts.map +1 -0
- package/dist/_chunks/install.mjs +48 -88
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +1 -1
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +29 -6
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/monorepo.mjs +71 -0
- package/dist/_chunks/monorepo.mjs.map +1 -0
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/{shared.mjs → package-registry.mjs} +2 -40
- package/dist/_chunks/package-registry.mjs.map +1 -0
- package/dist/_chunks/paths.mjs +49 -0
- package/dist/_chunks/paths.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +7 -2
- package/dist/_chunks/pool2.mjs.map +1 -1
- package/dist/_chunks/prepare.mjs +1 -1
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +5 -5
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +366 -18
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/retriv.mjs.map +1 -1
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +5 -6
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +1 -1
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +1 -2
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/semver.mjs +13 -0
- package/dist/_chunks/semver.mjs.map +1 -0
- package/dist/_chunks/setup.mjs.map +1 -1
- package/dist/_chunks/skill-installer.mjs +2 -0
- package/dist/_chunks/skill-installer2.mjs +155 -0
- package/dist/_chunks/skill-installer2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +10 -9
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +575 -386
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-pipeline.mjs +952 -0
- package/dist/_chunks/sync-pipeline.mjs.map +1 -0
- package/dist/_chunks/sync-registry.mjs +19 -13
- package/dist/_chunks/sync-registry.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +797 -886
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +4 -2
- package/dist/_chunks/types.d.mts +65 -77
- package/dist/_chunks/types.d.mts.map +1 -1
- package/dist/_chunks/types2.d.mts +88 -0
- package/dist/_chunks/types2.d.mts.map +1 -0
- package/dist/_chunks/uninstall.mjs +7 -8
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/upload.mjs +2 -2
- package/dist/_chunks/upload.mjs.map +1 -1
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/_chunks/version.mjs +3 -13
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/wizard.mjs +2 -2
- package/dist/_chunks/wizard.mjs.map +1 -1
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -346
- package/dist/agent/index.mjs +2 -3
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +4 -3
- package/dist/cli.mjs +12 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +5 -4
- package/dist/index.mjs +4 -3
- package/dist/prepare.mjs +2 -2
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/index.d.mts +2 -2
- package/dist/retriv/worker.d.mts +2 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +2 -1
- package/dist/retriv/worker.mjs.map +1 -1
- package/dist/sources/index.d.mts +3 -2
- package/dist/sources/index.mjs +3 -3
- package/dist/types.d.mts +3 -3
- package/package.json +5 -5
- package/dist/_chunks/config.mjs +0 -122
- package/dist/_chunks/config.mjs.map +0 -1
- package/dist/_chunks/prefix.mjs +0 -108
- package/dist/_chunks/prefix.mjs.map +0 -1
- package/dist/_chunks/shared.mjs.map +0 -1
- package/dist/_chunks/skill.mjs +0 -329
- package/dist/_chunks/skill.mjs.map +0 -1
- package/dist/_chunks/sync-shared.mjs +0 -2
- package/dist/_chunks/sync-shared2.mjs +0 -1020
- package/dist/_chunks/sync-shared2.mjs.map +0 -1
- package/dist/agent/index.d.mts.map +0 -1
package/dist/_chunks/sync.mjs
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as
|
|
1
|
+
import { d as getSharedSkillsDir, g as skillRefsSection, t as CACHE_DIR } from "./paths.mjs";
|
|
2
|
+
import { A as getActiveFeatures, M as hasCompletedWizard, P as readConfig, h as listReferenceFiles, i as ensureCacheDir, t as createReferenceCache } from "./cache.mjs";
|
|
3
|
+
import { r as getVersionKey } from "./version.mjs";
|
|
4
4
|
import { n as sanitizeMarkdown } from "./sanitize.mjs";
|
|
5
|
-
import { a as hasShippedDocs, d as linkPkgNamed, g as readCachedSection, i as getPkgKeyFiles, m as listReferenceFiles, r as ensureCacheDir, s as isCached } from "./cache.mjs";
|
|
6
5
|
import { i as parseFrontmatter } from "./markdown.mjs";
|
|
7
|
-
import { a as
|
|
8
|
-
import { J as isPrerelease, M as resolveGitHubRepo, f as resolvePackageDocsWithAttempts, i as fetchPkgDist, it as parsePackageSpec, m as fetchGitSkills, nt as parseGitHubRepoSlug, p as searchNpmPackages, s as readLocalDependencies, w as resolveCrateDocsWithAttempts } from "./sources.mjs";
|
|
6
|
+
import { P as resolveGitHubRepo, a as toStoragePackageName, b as fetchGitSkills, dt as parsePackageSpec, i as resolveSkillName, l as fetchPkgDist, lt as parseGitHubRepoSlug, n as isCrateSpec, r as parseSkillInput, t as resolvePackageOrCrate, tt as isPrerelease, v as searchNpmPackages } from "./sources.mjs";
|
|
9
7
|
import { a as targets } from "./detect.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import { _ as timedSpinner, i as computeSkillDirName, n as writeGeneratedSkillMd, o as linkSkillToAgents, r as writeSkillMd, s as sanitizeName, u as formatDuration, v as todayIsoDate } from "./
|
|
12
|
-
import { a as readConfig, o as registerProject, r as hasCompletedWizard, t as defaultFeatures } from "./config.mjs";
|
|
8
|
+
import { i as getModelLabel, n as detectImportedPackages } from "./agent.mjs";
|
|
9
|
+
import { C as portabilizePrompt, E as SECTION_OUTPUT_FILES, _ as timedSpinner, i as computeSkillDirName, n as writeGeneratedSkillMd, o as linkSkillToAgents, r as writeSkillMd, s as sanitizeName, u as formatDuration, v as todayIsoDate, y as buildAllSectionPrompts } from "./prompts.mjs";
|
|
13
10
|
import { S as suggestPrepareHook, _ as promptForAgent, b as resolveAgent, f as introLine, o as getInstalledGenerators, p as isInteractive, x as sharedArgs } from "./cli-helpers.mjs";
|
|
14
|
-
import { a as
|
|
11
|
+
import { a as parsePackageNames, c as readLock, d as writeLock, n as findSkillDirByPackage } from "./lockfile.mjs";
|
|
12
|
+
import { t as semverDiff } from "./semver.mjs";
|
|
15
13
|
import { t as getProjectState } from "./skills.mjs";
|
|
16
|
-
import { n as resolveSkillName, r as toStoragePackageName, t as parseSkillInput } from "./prefix.mjs";
|
|
17
14
|
import { t as runWizard } from "./wizard.mjs";
|
|
18
|
-
import {
|
|
15
|
+
import { a as ensureProjectFiles, c as linkShippedToAgents, i as ensureGitignore, l as resolveBaseDir, o as handleShippedSkills, s as installSkill } from "./skill-installer2.mjs";
|
|
16
|
+
import { a as prepareSkillReferences, c as resolveAutoModel, d as applyCachedSections, h as writePromptFiles, i as findRelatedSkills, l as selectLlmConfig, m as writeBaseSkill, p as runSkillEnhancement, r as fetchAndCacheResources, s as DEFAULT_SECTIONS, t as buildSkillContext } from "./sync-pipeline.mjs";
|
|
19
17
|
import { n as shutdownWorker } from "./pool2.mjs";
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
20
19
|
import { dirname, join, relative, resolve } from "pathe";
|
|
21
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
22
20
|
import pLimit from "p-limit";
|
|
23
|
-
import { isCI } from "std-env";
|
|
24
21
|
import * as p from "@clack/prompts";
|
|
25
22
|
import { defineCommand } from "citty";
|
|
23
|
+
import { isCI } from "std-env";
|
|
26
24
|
import logUpdate from "log-update";
|
|
27
25
|
const TELEMETRY_URL = "https://add-skill.vercel.sh/t";
|
|
28
26
|
const SKILLS_VERSION = "1.3.9";
|
|
@@ -39,6 +37,374 @@ function track(data) {
|
|
|
39
37
|
fetch(`${TELEMETRY_URL}?${params.toString()}`).catch(() => {});
|
|
40
38
|
} catch {}
|
|
41
39
|
}
|
|
40
|
+
const npmResolver = async (spec, opts) => {
|
|
41
|
+
const resolution = await resolvePackageOrCrate(spec, {
|
|
42
|
+
cwd: opts.cwd,
|
|
43
|
+
onProgress: (msg) => opts.onProgress(`${spec}: ${msg}`)
|
|
44
|
+
});
|
|
45
|
+
const { isCrate, packageName, identityPackageName, storagePackageName, requestedTag, localVersion, attempts, registryVersion } = resolution;
|
|
46
|
+
if (!resolution.resolved) {
|
|
47
|
+
const result = {
|
|
48
|
+
identityName: identityPackageName,
|
|
49
|
+
attempts,
|
|
50
|
+
registryVersion
|
|
51
|
+
};
|
|
52
|
+
if (!isCrate) {
|
|
53
|
+
const shipped = handleShippedSkills(packageName, localVersion || registryVersion || "latest", opts.cwd, opts.agent, opts.global);
|
|
54
|
+
if (shipped) result.shipped = shipped.shipped;
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
const resolved = resolution.resolved;
|
|
59
|
+
return {
|
|
60
|
+
identityName: identityPackageName,
|
|
61
|
+
storageName: storagePackageName,
|
|
62
|
+
version: isCrate ? resolved.version || requestedTag || "latest" : localVersion || resolved.version || "latest",
|
|
63
|
+
resolved,
|
|
64
|
+
kind: isCrate ? "crate" : "npm",
|
|
65
|
+
requestedTag,
|
|
66
|
+
localVersion
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
function createGithubResolver(owner, repo) {
|
|
70
|
+
return async (_spec, opts) => {
|
|
71
|
+
const resolved = await resolveGitHubRepo(owner, repo, (msg) => opts.onProgress(msg));
|
|
72
|
+
if (!resolved) return {
|
|
73
|
+
identityName: `${owner}-${repo}`,
|
|
74
|
+
attempts: [{
|
|
75
|
+
source: "github-meta",
|
|
76
|
+
status: "not-found",
|
|
77
|
+
message: `Could not find docs for ${owner}/${repo}`
|
|
78
|
+
}]
|
|
79
|
+
};
|
|
80
|
+
const repoUrl = `https://github.com/${owner}/${repo}`;
|
|
81
|
+
const name = `${owner}-${repo}`;
|
|
82
|
+
return {
|
|
83
|
+
identityName: name,
|
|
84
|
+
storageName: name,
|
|
85
|
+
version: resolved.version || "main",
|
|
86
|
+
resolved: {
|
|
87
|
+
...resolved,
|
|
88
|
+
repoUrl
|
|
89
|
+
},
|
|
90
|
+
kind: "github"
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const RATE_LIMIT_RE = /\b429\b|rate.?limit|exhausted.*capacity|quota.*reset/i;
|
|
95
|
+
async function runBaseSync(spec, config, ui, resolver, cwd, defaultSections) {
|
|
96
|
+
ui.resolveStart(spec);
|
|
97
|
+
const resolverResult = await resolver(spec, {
|
|
98
|
+
cwd,
|
|
99
|
+
agent: config.agent,
|
|
100
|
+
global: config.global,
|
|
101
|
+
onProgress: (msg) => ui.resolveProgress(msg)
|
|
102
|
+
});
|
|
103
|
+
if (!("resolved" in resolverResult)) {
|
|
104
|
+
if (resolverResult.shipped && resolverResult.shipped.length > 0) {
|
|
105
|
+
for (const s of resolverResult.shipped) ui.shippedInstalled(s.skillName, relative(cwd, s.skillDir));
|
|
106
|
+
return { kind: "shipped" };
|
|
107
|
+
}
|
|
108
|
+
ui.resolveFailed(resolverResult.identityName);
|
|
109
|
+
return {
|
|
110
|
+
kind: "unresolved",
|
|
111
|
+
unresolved: resolverResult
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const { identityName, storageName, version, resolved, kind, requestedTag, localVersion } = resolverResult;
|
|
115
|
+
const cache = createReferenceCache(storageName, version);
|
|
116
|
+
if (config.force) cache.clearForce();
|
|
117
|
+
const useCache = cache.has();
|
|
118
|
+
if (kind !== "crate" && !existsSync(join(cwd, "node_modules", identityName))) {
|
|
119
|
+
ui.downloadingDist();
|
|
120
|
+
await fetchPkgDist(identityName, version);
|
|
121
|
+
}
|
|
122
|
+
if (kind !== "crate") {
|
|
123
|
+
const shipped = handleShippedSkills(identityName, version, cwd, config.agent, config.global);
|
|
124
|
+
if (shipped) {
|
|
125
|
+
linkShippedToAgents(shipped.shipped, cwd, config.agent, config.global);
|
|
126
|
+
for (const s of shipped.shipped) ui.shippedInstalled(s.skillName, relative(cwd, s.skillDir));
|
|
127
|
+
return { kind: "shipped" };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
ui.resolveDone(version, {
|
|
131
|
+
cached: useCache,
|
|
132
|
+
force: config.force
|
|
133
|
+
});
|
|
134
|
+
if (kind === "npm" && !localVersion && !requestedTag && !isPrerelease(version)) {
|
|
135
|
+
const nextTag = resolved.distTags?.next ?? resolved.distTags?.beta ?? resolved.distTags?.alpha;
|
|
136
|
+
if (nextTag && (!resolved.releasedAt || !nextTag.releasedAt || nextTag.releasedAt > resolved.releasedAt)) ui.warn(`No local dependency found — using latest stable (${version}). Prerelease ${nextTag.version} available: skilld add ${identityName}@beta`);
|
|
137
|
+
}
|
|
138
|
+
cache.ensure();
|
|
139
|
+
const isEject = !!config.eject;
|
|
140
|
+
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
141
|
+
let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(storageName);
|
|
142
|
+
if (config.mode === "update" && !config.name && !isEject) {
|
|
143
|
+
const lock = readLock(baseDir);
|
|
144
|
+
const found = lock ? findSkillDirByPackage(lock, identityName) : null;
|
|
145
|
+
if (found) skillDirName = found;
|
|
146
|
+
}
|
|
147
|
+
const skillDir = isEject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
|
|
148
|
+
mkdirSync(skillDir, { recursive: true });
|
|
149
|
+
const existingLock = isEject ? void 0 : readLock(baseDir)?.skills[skillDirName];
|
|
150
|
+
if (existingLock && existingLock.packageName && existingLock.packageName !== identityName) return {
|
|
151
|
+
kind: "merge-needed",
|
|
152
|
+
state: {
|
|
153
|
+
identityName,
|
|
154
|
+
storageName,
|
|
155
|
+
version,
|
|
156
|
+
resolved,
|
|
157
|
+
baseDir,
|
|
158
|
+
skillDir,
|
|
159
|
+
skillDirName,
|
|
160
|
+
existingLock
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const updateCtx = config.mode === "update" && existingLock ? {
|
|
164
|
+
oldVersion: existingLock.version,
|
|
165
|
+
newVersion: version,
|
|
166
|
+
syncedAt: existingLock.syncedAt,
|
|
167
|
+
wasEnhanced: (() => {
|
|
168
|
+
const skillMdPath = join(skillDir, "SKILL.md");
|
|
169
|
+
if (!existsSync(skillMdPath)) return false;
|
|
170
|
+
return !!parseFrontmatter(readFileSync(skillMdPath, "utf-8")).generated_by;
|
|
171
|
+
})()
|
|
172
|
+
} : void 0;
|
|
173
|
+
const features = getActiveFeatures(config.noSearch ? { search: false } : void 0);
|
|
174
|
+
ui.fetchStart();
|
|
175
|
+
const resources = await fetchAndCacheResources({
|
|
176
|
+
packageName: storageName,
|
|
177
|
+
resolved,
|
|
178
|
+
version,
|
|
179
|
+
useCache,
|
|
180
|
+
features,
|
|
181
|
+
from: config.from,
|
|
182
|
+
onProgress: (msg) => ui.fetchProgress(msg)
|
|
183
|
+
});
|
|
184
|
+
const parts = [];
|
|
185
|
+
if (resources.docsToIndex.length > 0) {
|
|
186
|
+
const docCount = resources.docsToIndex.filter((d) => d.metadata?.type === "doc").length;
|
|
187
|
+
if (docCount > 0) parts.push(`${docCount} docs`);
|
|
188
|
+
}
|
|
189
|
+
if (resources.hasIssues) parts.push("issues");
|
|
190
|
+
if (resources.hasDiscussions) parts.push("discussions");
|
|
191
|
+
if (resources.hasReleases) parts.push("releases");
|
|
192
|
+
ui.fetchDone(parts, resources.usedCache);
|
|
193
|
+
for (const w of resources.warnings) ui.warn(w);
|
|
194
|
+
if (features.search) ui.indexStart();
|
|
195
|
+
const prepared = await prepareSkillReferences({
|
|
196
|
+
packageName: storageName,
|
|
197
|
+
version,
|
|
198
|
+
cwd,
|
|
199
|
+
skillDir,
|
|
200
|
+
resources,
|
|
201
|
+
features,
|
|
202
|
+
baseDir,
|
|
203
|
+
onIndexProgress: (msg) => ui.indexProgress(msg)
|
|
204
|
+
});
|
|
205
|
+
if (features.search) ui.indexDone();
|
|
206
|
+
if (!isEject) {
|
|
207
|
+
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
208
|
+
cache.linkPkgNamed(skillDir, cwd);
|
|
209
|
+
const lock = {
|
|
210
|
+
packageName: identityName,
|
|
211
|
+
version,
|
|
212
|
+
repo: repoSlug,
|
|
213
|
+
source: resources.docSource,
|
|
214
|
+
syncedAt: todayIsoDate(),
|
|
215
|
+
generator: "skilld"
|
|
216
|
+
};
|
|
217
|
+
installSkill({
|
|
218
|
+
cwd,
|
|
219
|
+
agent: config.agent,
|
|
220
|
+
global: config.global,
|
|
221
|
+
baseDir,
|
|
222
|
+
skillDirName,
|
|
223
|
+
lock,
|
|
224
|
+
dedupePackageName: identityName,
|
|
225
|
+
skipLinkAgents: true
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const allPackages = parsePackageNames((isEject ? void 0 : readLock(baseDir)?.skills[skillDirName])?.packages);
|
|
229
|
+
const ctx = buildSkillContext({
|
|
230
|
+
packageName: identityName,
|
|
231
|
+
cachePackageName: storageName,
|
|
232
|
+
version,
|
|
233
|
+
skillDir,
|
|
234
|
+
skillDirName,
|
|
235
|
+
resources,
|
|
236
|
+
prepared,
|
|
237
|
+
resolved,
|
|
238
|
+
packages: allPackages,
|
|
239
|
+
features
|
|
240
|
+
});
|
|
241
|
+
ctx.overheadLines = writeBaseSkill(ctx, { eject: isEject }).split("\n").length;
|
|
242
|
+
ui.baseDone(relative(cwd, skillDir), config.mode === "update" ? "update" : "add");
|
|
243
|
+
const allSectionsCached = !config.force && applyCachedSections(ctx, defaultSections, { eject: isEject });
|
|
244
|
+
if (allSectionsCached) ui.sectionsCached();
|
|
245
|
+
return {
|
|
246
|
+
kind: "ready",
|
|
247
|
+
state: {
|
|
248
|
+
ctx,
|
|
249
|
+
skillDir,
|
|
250
|
+
skillDirName,
|
|
251
|
+
baseDir,
|
|
252
|
+
updateCtx,
|
|
253
|
+
allSectionsCached,
|
|
254
|
+
identityName,
|
|
255
|
+
storageName,
|
|
256
|
+
version,
|
|
257
|
+
docsType: resources.docsType,
|
|
258
|
+
repoInfo: resources.repoInfo
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async function runEnhancePhase(state, llmConfig, config, ui, cwd) {
|
|
263
|
+
const isEject = !!config.eject;
|
|
264
|
+
if (llmConfig?.promptOnly) writePromptFiles({
|
|
265
|
+
...state.ctx,
|
|
266
|
+
packageName: state.ctx.cachePackageName ?? state.ctx.packageName,
|
|
267
|
+
cachePackageName: void 0
|
|
268
|
+
}, {
|
|
269
|
+
sections: llmConfig.sections,
|
|
270
|
+
customPrompt: llmConfig.customPrompt
|
|
271
|
+
});
|
|
272
|
+
else if (llmConfig) await enhanceWithUi(state.ctx, llmConfig, {
|
|
273
|
+
...config,
|
|
274
|
+
eject: isEject
|
|
275
|
+
}, ui);
|
|
276
|
+
if (isEject) {
|
|
277
|
+
const cache = createReferenceCache(state.storageName, state.version);
|
|
278
|
+
if (!config.debug) cache.clearSkillInternal(state.skillDir);
|
|
279
|
+
cache.eject(state.skillDir, cwd, state.docsType, {
|
|
280
|
+
features: state.ctx.features ?? getActiveFeatures(),
|
|
281
|
+
repoInfo: state.repoInfo
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const shared = config.global ? false : getSharedSkillsDir(cwd) ?? false;
|
|
286
|
+
if (shared) linkSkillToAgents(state.skillDirName, shared, cwd, config.agent);
|
|
287
|
+
await ensureProjectFiles({
|
|
288
|
+
cwd,
|
|
289
|
+
agent: config.agent,
|
|
290
|
+
global: config.global,
|
|
291
|
+
shared
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
async function enhanceWithUi(ctx, llmConfig, config, ui) {
|
|
295
|
+
ui.llmStart(getModelLabel(llmConfig.model));
|
|
296
|
+
const result = await runSkillEnhancement(ctx, {
|
|
297
|
+
model: llmConfig.model,
|
|
298
|
+
force: config.force,
|
|
299
|
+
debug: config.debug,
|
|
300
|
+
sections: llmConfig.sections,
|
|
301
|
+
customPrompt: llmConfig.customPrompt,
|
|
302
|
+
eject: !!config.eject
|
|
303
|
+
}, (progress) => ui.llmProgress(progress));
|
|
304
|
+
if (result.wasOptimized) ui.llmDone({
|
|
305
|
+
usage: result.usage ? { totalTokens: result.usage.totalTokens } : void 0,
|
|
306
|
+
cost: result.cost,
|
|
307
|
+
debugLogsDir: result.debugLogsDir,
|
|
308
|
+
error: result.error,
|
|
309
|
+
warnings: result.warnings
|
|
310
|
+
});
|
|
311
|
+
else ui.llmFailed(result.error ?? "", { rateLimited: !!result.error && RATE_LIMIT_RE.test(result.error) });
|
|
312
|
+
}
|
|
313
|
+
function createClackUi({ cwd }) {
|
|
314
|
+
let spinner = null;
|
|
315
|
+
let resourceSpinner = null;
|
|
316
|
+
let indexSpinner = null;
|
|
317
|
+
let llmLog = null;
|
|
318
|
+
let currentSpec = "";
|
|
319
|
+
return {
|
|
320
|
+
resolveStart(spec) {
|
|
321
|
+
currentSpec = spec;
|
|
322
|
+
spinner = timedSpinner();
|
|
323
|
+
spinner.start(`Resolving ${spec}`);
|
|
324
|
+
},
|
|
325
|
+
resolveProgress(msg) {
|
|
326
|
+
spinner?.message(msg);
|
|
327
|
+
},
|
|
328
|
+
resolveDone(version, opts) {
|
|
329
|
+
const suffix = opts.force ? " (force)" : opts.cached ? " (cached)" : "";
|
|
330
|
+
spinner?.stop(`Resolved ${currentSpec}@${version}${suffix}`);
|
|
331
|
+
spinner = null;
|
|
332
|
+
},
|
|
333
|
+
resolveFailed(identityName) {
|
|
334
|
+
spinner?.stop(`Could not find docs for: ${identityName}`);
|
|
335
|
+
spinner = null;
|
|
336
|
+
},
|
|
337
|
+
downloadingDist() {
|
|
338
|
+
spinner?.message("Downloading dist");
|
|
339
|
+
},
|
|
340
|
+
fetchStart() {
|
|
341
|
+
resourceSpinner = timedSpinner();
|
|
342
|
+
resourceSpinner.start("Finding resources");
|
|
343
|
+
},
|
|
344
|
+
fetchProgress(msg) {
|
|
345
|
+
resourceSpinner?.message(msg);
|
|
346
|
+
},
|
|
347
|
+
fetchDone(parts, cached) {
|
|
348
|
+
const summary = parts.length > 0 ? parts.join(", ") : "resources";
|
|
349
|
+
resourceSpinner?.stop(cached ? `Loaded ${summary} (cached)` : `Fetched ${summary}`);
|
|
350
|
+
resourceSpinner = null;
|
|
351
|
+
},
|
|
352
|
+
indexStart() {
|
|
353
|
+
indexSpinner = timedSpinner();
|
|
354
|
+
indexSpinner.start("Creating search index");
|
|
355
|
+
},
|
|
356
|
+
indexProgress(msg) {
|
|
357
|
+
indexSpinner?.message(msg);
|
|
358
|
+
},
|
|
359
|
+
indexDone() {
|
|
360
|
+
indexSpinner?.stop("Search index ready");
|
|
361
|
+
indexSpinner = null;
|
|
362
|
+
},
|
|
363
|
+
warn(msg) {
|
|
364
|
+
p.log.warn(`\x1B[33m${msg}\x1B[0m`);
|
|
365
|
+
},
|
|
366
|
+
baseDone(relPath, mode) {
|
|
367
|
+
p.log.success(mode === "update" ? `Updated skill: ${relPath}` : `Created base skill: ${relPath}`);
|
|
368
|
+
},
|
|
369
|
+
sectionsCached() {
|
|
370
|
+
p.log.success("Applied cached SKILL.md sections");
|
|
371
|
+
},
|
|
372
|
+
llmStart(modelLabel) {
|
|
373
|
+
p.log.step(modelLabel);
|
|
374
|
+
llmLog = p.taskLog({
|
|
375
|
+
title: `Agent exploring ${currentSpec}`,
|
|
376
|
+
limit: 3
|
|
377
|
+
});
|
|
378
|
+
},
|
|
379
|
+
llmProgress(progress) {
|
|
380
|
+
if (!llmLog) return;
|
|
381
|
+
const sectionPrefix = progress.section ? `[${progress.section}] ` : "";
|
|
382
|
+
const line = progress.chunk.startsWith("[") ? `${sectionPrefix}${progress.chunk}` : `${sectionPrefix}${progress.chunk}`;
|
|
383
|
+
llmLog.message(line);
|
|
384
|
+
},
|
|
385
|
+
llmDone(info) {
|
|
386
|
+
if (!llmLog) return;
|
|
387
|
+
const parts = [];
|
|
388
|
+
if (info.usage) parts.push(`${Math.round(info.usage.totalTokens / 1e3)}k tokens`);
|
|
389
|
+
if (info.cost) parts.push(`$${info.cost.toFixed(2)}`);
|
|
390
|
+
const suffix = parts.length > 0 ? ` (${parts.join(", ")})` : "";
|
|
391
|
+
llmLog.success(`Generated best practices${suffix}`);
|
|
392
|
+
llmLog = null;
|
|
393
|
+
if (info.debugLogsDir) p.log.info(`Debug logs: ${relative(cwd, info.debugLogsDir)}`);
|
|
394
|
+
if (info.error) p.log.warn(`\x1B[33mPartial failure: ${info.error}\x1B[0m`);
|
|
395
|
+
if (info.warnings) for (const w of info.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
396
|
+
},
|
|
397
|
+
llmFailed(error, opts) {
|
|
398
|
+
if (!llmLog) return;
|
|
399
|
+
if (opts.rateLimited) llmLog.error(`Rate limited by LLM provider. Try again shortly or use a different model via \`skilld config\``);
|
|
400
|
+
else llmLog.error(`Enhancement failed${error ? `: ${error}` : ""}`);
|
|
401
|
+
llmLog = null;
|
|
402
|
+
},
|
|
403
|
+
shippedInstalled(skillName, relPath) {
|
|
404
|
+
p.log.success(`Using published SKILL.md: ${skillName} → ${relPath}`);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
42
408
|
async function syncGitSkills(opts) {
|
|
43
409
|
const { source, agent, global: isGlobal, yes } = opts;
|
|
44
410
|
const cwd = process.cwd();
|
|
@@ -93,16 +459,23 @@ async function syncGitSkills(opts) {
|
|
|
93
459
|
writeFileSync(filePath, f.content);
|
|
94
460
|
}
|
|
95
461
|
const sourceType = source.type === "local" ? "local" : source.type;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
462
|
+
installSkill({
|
|
463
|
+
cwd,
|
|
464
|
+
agent,
|
|
465
|
+
global: isGlobal,
|
|
466
|
+
baseDir,
|
|
467
|
+
skillDirName: skill.name,
|
|
468
|
+
lock: {
|
|
469
|
+
source: sourceType,
|
|
470
|
+
repo: source.type === "local" ? source.localPath : `${source.owner}/${source.repo}`,
|
|
471
|
+
path: skill.path || void 0,
|
|
472
|
+
ref: source.ref || "main",
|
|
473
|
+
syncedAt: todayIsoDate(),
|
|
474
|
+
generator: "external"
|
|
475
|
+
},
|
|
476
|
+
skipLinkAgents: true
|
|
103
477
|
});
|
|
104
478
|
}
|
|
105
|
-
if (!isGlobal) registerProject(cwd);
|
|
106
479
|
if (source.type !== "local" && source.owner && source.repo) track({
|
|
107
480
|
event: "install",
|
|
108
481
|
source: `${source.owner}/${source.repo}`,
|
|
@@ -111,156 +484,92 @@ async function syncGitSkills(opts) {
|
|
|
111
484
|
...isGlobal && { global: "1" },
|
|
112
485
|
sourceType: source.type
|
|
113
486
|
});
|
|
114
|
-
const
|
|
115
|
-
|
|
487
|
+
for (const skill of selected) {
|
|
488
|
+
const skillRel = relative(cwd, join(baseDir, skill.name));
|
|
489
|
+
const fileLines = ["SKILL.md", ...skill.files.map((f) => f.path)].map((f) => ` \x1B[90m└\x1B[0m ${f}`).join("\n");
|
|
490
|
+
p.log.success(`Installed \x1B[36m${skill.name}\x1B[0m \x1B[90m→ ${skillRel}\x1B[0m\n${fileLines}`);
|
|
491
|
+
}
|
|
116
492
|
}
|
|
117
493
|
async function syncGitHubRepo(opts) {
|
|
118
494
|
const { source, agent, global: isGlobal, yes } = opts;
|
|
119
495
|
const owner = source.owner;
|
|
120
496
|
const repo = source.repo;
|
|
121
497
|
const cwd = process.cwd();
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
from: opts.from,
|
|
150
|
-
onProgress: (msg) => resSpin.message(msg)
|
|
498
|
+
const ui = createClackUi({ cwd });
|
|
499
|
+
const spec = `${owner}/${repo}`;
|
|
500
|
+
const result = await runBaseSync(spec, {
|
|
501
|
+
agent,
|
|
502
|
+
global: isGlobal,
|
|
503
|
+
force: opts.force,
|
|
504
|
+
from: opts.from
|
|
505
|
+
}, ui, createGithubResolver(owner, repo), cwd, DEFAULT_SECTIONS);
|
|
506
|
+
if (result.kind !== "ready") return;
|
|
507
|
+
const { state } = result;
|
|
508
|
+
const globalConfig = readConfig();
|
|
509
|
+
let llmConfig = null;
|
|
510
|
+
if (!state.allSectionsCached && !globalConfig.skipLlm && (!yes || opts.model)) llmConfig = await selectLlmConfig(opts.model);
|
|
511
|
+
await runEnhancePhase(state, llmConfig, {
|
|
512
|
+
agent,
|
|
513
|
+
global: isGlobal,
|
|
514
|
+
force: opts.force,
|
|
515
|
+
debug: opts.debug
|
|
516
|
+
}, ui, cwd);
|
|
517
|
+
await shutdownWorker();
|
|
518
|
+
track({
|
|
519
|
+
event: "install",
|
|
520
|
+
source: spec,
|
|
521
|
+
skills: state.skillDirName,
|
|
522
|
+
agents: agent,
|
|
523
|
+
...isGlobal && { global: "1" },
|
|
524
|
+
sourceType: "github-generated"
|
|
151
525
|
});
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
packageName,
|
|
526
|
+
p.outro(`Synced ${spec} to ${relative(cwd, state.skillDir)}`);
|
|
527
|
+
}
|
|
528
|
+
async function handleMerge(state, config, cwd) {
|
|
529
|
+
const { identityName, storageName, version, resolved, baseDir, skillDir, skillDirName, existingLock } = state;
|
|
530
|
+
p.log.step(`Merging ${identityName} into ${skillDirName}`);
|
|
531
|
+
createReferenceCache(storageName, version).linkPkgNamed(skillDir, cwd);
|
|
532
|
+
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
533
|
+
installSkill({
|
|
534
|
+
cwd,
|
|
535
|
+
agent: config.agent,
|
|
536
|
+
global: config.global,
|
|
537
|
+
baseDir,
|
|
538
|
+
skillDirName,
|
|
539
|
+
lock: {
|
|
540
|
+
packageName: identityName,
|
|
168
541
|
version,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version), getCacheDir(packageName, version));
|
|
177
|
-
const shippedDocs = hasShippedDocs(packageName, cwd, version);
|
|
178
|
-
const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
|
|
179
|
-
writeLock(baseDir, skillDirName, {
|
|
180
|
-
packageName,
|
|
181
|
-
version,
|
|
182
|
-
repo: `${owner}/${repo}`,
|
|
183
|
-
source: resources.docSource,
|
|
184
|
-
syncedAt: todayIsoDate(),
|
|
185
|
-
generator: "skilld"
|
|
542
|
+
repo: repoSlug,
|
|
543
|
+
source: existingLock.source,
|
|
544
|
+
syncedAt: todayIsoDate(),
|
|
545
|
+
generator: "skilld"
|
|
546
|
+
},
|
|
547
|
+
skipLinkAgents: true
|
|
186
548
|
});
|
|
549
|
+
const updatedLock = readLock(baseDir)?.skills[skillDirName];
|
|
550
|
+
const allPackages = parsePackageNames(updatedLock?.packages);
|
|
551
|
+
const relatedSkills = await findRelatedSkills(storageName, baseDir);
|
|
552
|
+
const existingCache = createReferenceCache(toStoragePackageName(existingLock.packageName), existingLock.version);
|
|
553
|
+
const pkgFiles = existingCache.keyFiles(cwd);
|
|
554
|
+
const shippedDocs = existingCache.hasShipped(cwd);
|
|
555
|
+
const features = getActiveFeatures();
|
|
187
556
|
writeGeneratedSkillMd(skillDir, {
|
|
188
|
-
name: packageName,
|
|
189
|
-
version,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
hasReleases: resources.hasReleases,
|
|
196
|
-
hasChangelog,
|
|
197
|
-
docsType: resources.docsType,
|
|
557
|
+
name: existingLock.packageName,
|
|
558
|
+
version: existingLock.version,
|
|
559
|
+
relatedSkills,
|
|
560
|
+
hasIssues: features.issues && existsSync(skillRefsSection(skillDir, "issues")),
|
|
561
|
+
hasDiscussions: features.discussions && existsSync(skillRefsSection(skillDir, "discussions")),
|
|
562
|
+
hasReleases: features.releases && existsSync(skillRefsSection(skillDir, "releases")),
|
|
563
|
+
docsType: existingLock.source?.includes("llms.txt") ? "llms.txt" : "docs",
|
|
198
564
|
hasShippedDocs: shippedDocs,
|
|
199
565
|
pkgFiles,
|
|
200
566
|
dirName: skillDirName,
|
|
201
|
-
|
|
567
|
+
packages: allPackages,
|
|
202
568
|
features
|
|
203
569
|
});
|
|
204
|
-
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
if (llmConfig?.promptOnly) writePromptFiles({
|
|
208
|
-
packageName,
|
|
209
|
-
skillDir,
|
|
210
|
-
version,
|
|
211
|
-
hasIssues: resources.hasIssues,
|
|
212
|
-
hasDiscussions: resources.hasDiscussions,
|
|
213
|
-
hasReleases: resources.hasReleases,
|
|
214
|
-
hasChangelog,
|
|
215
|
-
docsType: resources.docsType,
|
|
216
|
-
hasShippedDocs: shippedDocs,
|
|
217
|
-
pkgFiles,
|
|
218
|
-
sections: llmConfig.sections,
|
|
219
|
-
customPrompt: llmConfig.customPrompt,
|
|
220
|
-
features
|
|
221
|
-
});
|
|
222
|
-
else if (llmConfig) {
|
|
223
|
-
p.log.step(getModelLabel(llmConfig.model));
|
|
224
|
-
await enhanceSkillWithLLM({
|
|
225
|
-
packageName,
|
|
226
|
-
version,
|
|
227
|
-
skillDir,
|
|
228
|
-
dirName: skillDirName,
|
|
229
|
-
model: llmConfig.model,
|
|
230
|
-
resolved,
|
|
231
|
-
relatedSkills: [],
|
|
232
|
-
hasIssues: resources.hasIssues,
|
|
233
|
-
hasDiscussions: resources.hasDiscussions,
|
|
234
|
-
hasReleases: resources.hasReleases,
|
|
235
|
-
hasChangelog,
|
|
236
|
-
docsType: resources.docsType,
|
|
237
|
-
hasShippedDocs: shippedDocs,
|
|
238
|
-
pkgFiles,
|
|
239
|
-
force: opts.force,
|
|
240
|
-
debug: opts.debug,
|
|
241
|
-
sections: llmConfig.sections,
|
|
242
|
-
customPrompt: llmConfig.customPrompt,
|
|
243
|
-
features
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
const shared = !isGlobal && getSharedSkillsDir(cwd);
|
|
248
|
-
if (shared) linkSkillToAgents(skillDirName, shared, cwd, agent);
|
|
249
|
-
if (!isGlobal) {
|
|
250
|
-
registerProject(cwd);
|
|
251
|
-
await ensureGitignore(shared || targets[agent].skillsDir, cwd, isGlobal);
|
|
252
|
-
await ensureAgentInstructions(agent, cwd, isGlobal);
|
|
253
|
-
}
|
|
254
|
-
await shutdownWorker();
|
|
255
|
-
track({
|
|
256
|
-
event: "install",
|
|
257
|
-
source: `${owner}/${repo}`,
|
|
258
|
-
skills: skillDirName,
|
|
259
|
-
agents: agent,
|
|
260
|
-
...isGlobal && { global: "1" },
|
|
261
|
-
sourceType: "github-generated"
|
|
262
|
-
});
|
|
263
|
-
p.outro(`Synced ${owner}/${repo} to ${relative(cwd, skillDir)}`);
|
|
570
|
+
const sharedDir = !config.global && getSharedSkillsDir(cwd);
|
|
571
|
+
if (sharedDir) linkSkillToAgents(skillDirName, sharedDir, cwd, config.agent);
|
|
572
|
+
p.outro(`Merged ${identityName} into ${skillDirName}`);
|
|
264
573
|
}
|
|
265
574
|
const STATUS_ICONS = {
|
|
266
575
|
pending: "○",
|
|
@@ -284,196 +593,250 @@ const STATUS_COLORS = {
|
|
|
284
593
|
done: "\x1B[32m",
|
|
285
594
|
error: "\x1B[31m"
|
|
286
595
|
};
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
596
|
+
function renderParallel(r) {
|
|
597
|
+
const maxNameLen = Math.max(...[...r.states.keys()].map((n) => n.length), 20);
|
|
598
|
+
const lines = [...r.states.values()].map((s) => {
|
|
599
|
+
const icon = STATUS_ICONS[s.status];
|
|
600
|
+
const color = STATUS_COLORS[s.status];
|
|
601
|
+
const reset = "\x1B[0m";
|
|
602
|
+
const dim = "\x1B[90m";
|
|
603
|
+
const name = s.name.padEnd(maxNameLen);
|
|
604
|
+
const version = s.version ? `${dim}${s.version}${reset} ` : "";
|
|
605
|
+
const elapsed = (s.status === "done" || s.status === "error") && s.startedAt && s.completedAt ? ` ${dim}(${formatDuration(s.completedAt - s.startedAt)})${reset}` : "";
|
|
606
|
+
const preview = s.streamPreview ? ` ${dim}${s.streamPreview}${reset}` : "";
|
|
607
|
+
return ` ${color}${icon}${reset} ${name} ${version}${s.message}${elapsed}${preview}`;
|
|
296
608
|
});
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const version = s.version ? `${dim}${s.version}${reset} ` : "";
|
|
306
|
-
const elapsed = (s.status === "done" || s.status === "error") && s.startedAt && s.completedAt ? ` ${dim}(${formatDuration(s.completedAt - s.startedAt)})${reset}` : "";
|
|
307
|
-
const preview = s.streamPreview ? ` ${dim}${s.streamPreview}${reset}` : "";
|
|
308
|
-
return ` ${color}${icon}${reset} ${name} ${version}${s.message}${elapsed}${preview}`;
|
|
309
|
-
});
|
|
310
|
-
const doneCount = [...states.values()].filter((s) => s.status === "done").length;
|
|
311
|
-
const errorCount = [...states.values()].filter((s) => s.status === "error").length;
|
|
312
|
-
logUpdate(`\x1B[1m${config.mode === "update" ? "Updating" : "Syncing"} ${packages.length} packages\x1B[0m (${doneCount} done${errorCount > 0 ? `, ${errorCount} failed` : ""})\n` + lines.join("\n"));
|
|
313
|
-
}
|
|
314
|
-
function update(pkg, status, message, version) {
|
|
315
|
-
const state = states.get(pkg);
|
|
609
|
+
const doneCount = [...r.states.values()].filter((s) => s.status === "done").length;
|
|
610
|
+
const errorCount = [...r.states.values()].filter((s) => s.status === "error").length;
|
|
611
|
+
logUpdate(`\x1B[1m${r.verb} ${r.total} packages\x1B[0m (${doneCount} done${errorCount > 0 ? `, ${errorCount} failed` : ""})\n` + lines.join("\n"));
|
|
612
|
+
}
|
|
613
|
+
function createParallelUi(name, render, version) {
|
|
614
|
+
const state = render.states.get(name);
|
|
615
|
+
if (!state) throw new Error(`createParallelUi: no state slot for "${name}"`);
|
|
616
|
+
function update(status, message, ver) {
|
|
316
617
|
if (!state.startedAt && status !== "pending") state.startedAt = performance.now();
|
|
317
618
|
if ((status === "done" || status === "error") && !state.completedAt) state.completedAt = performance.now();
|
|
318
619
|
state.status = status;
|
|
319
620
|
state.message = message;
|
|
320
621
|
state.streamPreview = void 0;
|
|
321
|
-
if (
|
|
322
|
-
render
|
|
622
|
+
if (ver) state.version = ver;
|
|
623
|
+
renderParallel(render);
|
|
323
624
|
}
|
|
625
|
+
if (version) state.version = version;
|
|
626
|
+
return {
|
|
627
|
+
resolveStart() {
|
|
628
|
+
update("resolving", "Resolving...");
|
|
629
|
+
},
|
|
630
|
+
resolveProgress(msg) {
|
|
631
|
+
update("resolving", msg);
|
|
632
|
+
},
|
|
633
|
+
resolveDone(ver, opts) {
|
|
634
|
+
update("downloading", opts.cached ? "Using cache" : opts.force ? "Re-fetching docs..." : "Fetching docs...", ver);
|
|
635
|
+
},
|
|
636
|
+
resolveFailed(_identityName) {},
|
|
637
|
+
downloadingDist() {
|
|
638
|
+
update("downloading", "Downloading dist...");
|
|
639
|
+
},
|
|
640
|
+
fetchStart() {},
|
|
641
|
+
fetchProgress(msg) {
|
|
642
|
+
update("downloading", msg);
|
|
643
|
+
},
|
|
644
|
+
fetchDone(_parts, _cached) {
|
|
645
|
+
update("downloading", "Linking references...");
|
|
646
|
+
},
|
|
647
|
+
indexStart() {
|
|
648
|
+
update("embedding", "Indexing docs");
|
|
649
|
+
},
|
|
650
|
+
indexProgress(msg) {
|
|
651
|
+
update("embedding", msg);
|
|
652
|
+
},
|
|
653
|
+
indexDone() {},
|
|
654
|
+
warn(_msg) {},
|
|
655
|
+
baseDone(_relPath, mode) {
|
|
656
|
+
update("done", mode === "update" ? "Skill updated" : "Base skill created");
|
|
657
|
+
},
|
|
658
|
+
sectionsCached() {},
|
|
659
|
+
llmStart(modelLabel) {
|
|
660
|
+
update("generating", modelLabel);
|
|
661
|
+
},
|
|
662
|
+
llmProgress(progress) {
|
|
663
|
+
const status = progress.type === "reasoning" ? "exploring" : "generating";
|
|
664
|
+
const sectionPrefix = progress.section ? `[${progress.section}] ` : "";
|
|
665
|
+
update(status, progress.chunk.startsWith("[") ? `${sectionPrefix}${progress.chunk}` : `${sectionPrefix}${progress.chunk}`);
|
|
666
|
+
},
|
|
667
|
+
llmDone(_info) {
|
|
668
|
+
update("done", "Skill optimized");
|
|
669
|
+
},
|
|
670
|
+
llmFailed(error, _opts) {
|
|
671
|
+
update("error", error);
|
|
672
|
+
},
|
|
673
|
+
shippedInstalled(_skillName, _relPath) {
|
|
674
|
+
update("done", "Published SKILL.md");
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
const DIFF_RANK = {
|
|
679
|
+
major: 5,
|
|
680
|
+
premajor: 4,
|
|
681
|
+
minor: 3,
|
|
682
|
+
preminor: 2,
|
|
683
|
+
patch: 1,
|
|
684
|
+
prepatch: 1,
|
|
685
|
+
prerelease: 0
|
|
686
|
+
};
|
|
687
|
+
async function syncPackagesParallel(config) {
|
|
688
|
+
const { packages, concurrency = 5 } = config;
|
|
689
|
+
const cwd = process.cwd();
|
|
690
|
+
const states = /* @__PURE__ */ new Map();
|
|
691
|
+
for (const spec of packages) states.set(spec, {
|
|
692
|
+
name: spec,
|
|
693
|
+
status: "pending",
|
|
694
|
+
message: "Waiting..."
|
|
695
|
+
});
|
|
696
|
+
const render = {
|
|
697
|
+
states,
|
|
698
|
+
verb: config.mode === "update" ? "Updating" : "Syncing",
|
|
699
|
+
total: packages.length
|
|
700
|
+
};
|
|
324
701
|
ensureCacheDir();
|
|
325
|
-
render
|
|
702
|
+
renderParallel(render);
|
|
326
703
|
const limit = pLimit(concurrency);
|
|
327
|
-
const
|
|
328
|
-
|
|
704
|
+
const baseConfig = {
|
|
705
|
+
agent: config.agent,
|
|
706
|
+
global: config.global,
|
|
707
|
+
mode: config.mode,
|
|
708
|
+
force: config.force
|
|
709
|
+
};
|
|
710
|
+
const baseResults = await Promise.allSettled(packages.map((spec) => limit(async () => {
|
|
711
|
+
const { name } = parsePackageSpec(spec);
|
|
712
|
+
return runBaseSync(spec, baseConfig, createParallelUi(name, render), npmResolver, cwd, DEFAULT_SECTIONS);
|
|
713
|
+
})));
|
|
329
714
|
logUpdate.done();
|
|
330
|
-
const
|
|
331
|
-
const
|
|
715
|
+
const ready = [];
|
|
716
|
+
const shippedCount = [];
|
|
332
717
|
const errors = [];
|
|
718
|
+
const aggregatedWarnings = [];
|
|
333
719
|
for (let i = 0; i < baseResults.length; i++) {
|
|
720
|
+
const spec = packages[i];
|
|
334
721
|
const r = baseResults[i];
|
|
335
|
-
if (r.status === "
|
|
336
|
-
successfulPkgs.push(packages[i]);
|
|
337
|
-
skillData.set(packages[i], r.value);
|
|
338
|
-
} else if (r.status === "fulfilled" && r.value === "shipped") shippedPkgs.push(packages[i]);
|
|
339
|
-
else if (r.status === "rejected") {
|
|
722
|
+
if (r.status === "rejected") {
|
|
340
723
|
const err = r.reason;
|
|
341
|
-
const reason = err instanceof Error ?
|
|
724
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
725
|
+
const slot = states.get(spec);
|
|
726
|
+
if (slot) slot.status = "error";
|
|
342
727
|
errors.push({
|
|
343
|
-
|
|
728
|
+
spec,
|
|
344
729
|
reason
|
|
345
730
|
});
|
|
731
|
+
continue;
|
|
346
732
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (!DEFAULT_SECTIONS.includes(s)) continue;
|
|
365
|
-
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
366
|
-
const content = readCachedSection(resolvedName, data.version, outputFile);
|
|
367
|
-
if (content) cachedParts.push(wrapSection(s, content));
|
|
733
|
+
const result = r.value;
|
|
734
|
+
if (result.kind === "shipped") {
|
|
735
|
+
shippedCount.push(spec);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (result.kind === "unresolved") {
|
|
739
|
+
const npmAttempt = result.unresolved.attempts.find((a) => a.source === "npm");
|
|
740
|
+
let reason;
|
|
741
|
+
if (npmAttempt?.status === "not-found") {
|
|
742
|
+
const suggestions = await searchNpmPackages(result.unresolved.identityName, 3);
|
|
743
|
+
const hint = suggestions.length > 0 ? ` (try: ${suggestions.map((s) => s.name).join(", ")})` : "";
|
|
744
|
+
reason = (npmAttempt.message || "Not on npm") + hint;
|
|
745
|
+
} else reason = result.unresolved.attempts.filter((a) => a.status !== "success").map((a) => a.message || a.source).join("; ") || "No docs found";
|
|
746
|
+
const slot = states.get(spec);
|
|
747
|
+
if (slot) {
|
|
748
|
+
slot.status = "error";
|
|
749
|
+
slot.message = reason;
|
|
368
750
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
version: data.version,
|
|
373
|
-
releasedAt: data.resolved.releasedAt,
|
|
374
|
-
distTags: data.resolved.distTags,
|
|
375
|
-
body: cachedBody,
|
|
376
|
-
relatedSkills: data.relatedSkills,
|
|
377
|
-
hasIssues: data.hasIssues,
|
|
378
|
-
hasDiscussions: data.hasDiscussions,
|
|
379
|
-
hasReleases: data.hasReleases,
|
|
380
|
-
hasChangelog: data.hasChangelog,
|
|
381
|
-
docsType: data.docsType,
|
|
382
|
-
hasShippedDocs: data.shippedDocs,
|
|
383
|
-
pkgFiles: data.pkgFiles,
|
|
384
|
-
generatedBy: "cached",
|
|
385
|
-
dirName: data.skillDirName,
|
|
386
|
-
packages: data.packages,
|
|
387
|
-
repoUrl: data.resolved.repoUrl,
|
|
388
|
-
features: data.features
|
|
751
|
+
errors.push({
|
|
752
|
+
spec,
|
|
753
|
+
reason
|
|
389
754
|
});
|
|
390
|
-
|
|
755
|
+
continue;
|
|
391
756
|
}
|
|
757
|
+
if (result.kind === "merge-needed") {
|
|
758
|
+
errors.push({
|
|
759
|
+
spec,
|
|
760
|
+
reason: `Skill dir already holds ${result.state.existingLock.packageName} — run sequentially to merge`
|
|
761
|
+
});
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
ready.push({
|
|
765
|
+
spec,
|
|
766
|
+
state: result.state
|
|
767
|
+
});
|
|
392
768
|
}
|
|
393
|
-
|
|
769
|
+
renderParallel(render);
|
|
770
|
+
logUpdate.done();
|
|
771
|
+
const pastVerb = config.mode === "update" ? "Updated" : "Created";
|
|
772
|
+
p.log.success(`${pastVerb} ${ready.length} base skills${shippedCount.length > 0 ? ` (${shippedCount.length} shipped)` : ""}`);
|
|
773
|
+
for (const w of aggregatedWarnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
774
|
+
for (const { spec, reason } of errors) p.log.error(` ${spec}: ${reason}`);
|
|
775
|
+
const cachedPkgs = [];
|
|
776
|
+
const uncached = [];
|
|
777
|
+
for (const r of ready) if (r.state.allSectionsCached) cachedPkgs.push(r.spec);
|
|
778
|
+
else uncached.push(r);
|
|
394
779
|
if (cachedPkgs.length > 0) p.log.success(`Applied cached SKILL.md sections for ${cachedPkgs.join(", ")}`);
|
|
395
780
|
const globalConfig = readConfig();
|
|
396
|
-
|
|
397
|
-
if (!
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
major: 5,
|
|
406
|
-
premajor: 4,
|
|
407
|
-
minor: 3,
|
|
408
|
-
preminor: 2,
|
|
409
|
-
patch: 1,
|
|
410
|
-
prepatch: 1,
|
|
411
|
-
prerelease: 0
|
|
412
|
-
};
|
|
413
|
-
let parallelUpdateCtx;
|
|
414
|
-
if (config.mode === "update") {
|
|
415
|
-
let maxDiff = "";
|
|
416
|
-
let allEnhanced = true;
|
|
417
|
-
let anySyncedAt;
|
|
418
|
-
for (const pkg of successfulPkgs) {
|
|
419
|
-
const data = skillData.get(pkg);
|
|
420
|
-
if (!data.wasEnhanced) allEnhanced = false;
|
|
421
|
-
if (data.oldSyncedAt && (!anySyncedAt || data.oldSyncedAt < anySyncedAt)) anySyncedAt = data.oldSyncedAt;
|
|
422
|
-
if (data.oldVersion) {
|
|
423
|
-
const diff = semverDiff(data.oldVersion, data.version);
|
|
424
|
-
if (diff && (DIFF_RANK[diff] ?? 0) > (DIFF_RANK[maxDiff] ?? -1)) maxDiff = diff;
|
|
781
|
+
const resolvedModel = await resolveAutoModel(config.model, config.yes);
|
|
782
|
+
if (uncached.length > 0 && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
|
|
783
|
+
const llmConfig = await selectLlmConfig(resolvedModel, void 0, config.mode === "update" ? aggregateUpdateCtx(uncached) : void 0);
|
|
784
|
+
if (llmConfig?.promptOnly) {
|
|
785
|
+
for (const r of uncached) {
|
|
786
|
+
const slot = states.get(r.spec);
|
|
787
|
+
if (slot) {
|
|
788
|
+
slot.status = "done";
|
|
789
|
+
slot.message = "Prompts written";
|
|
425
790
|
}
|
|
426
791
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (llmConfig
|
|
438
|
-
const data = skillData.get(pkg);
|
|
439
|
-
writePromptFiles({
|
|
440
|
-
packageName: pkg,
|
|
441
|
-
skillDir: join(resolveBaseDir(cwd, config.agent, config.global), data.skillDirName),
|
|
442
|
-
version: data.version,
|
|
443
|
-
hasIssues: data.hasIssues,
|
|
444
|
-
hasDiscussions: data.hasDiscussions,
|
|
445
|
-
hasReleases: data.hasReleases,
|
|
446
|
-
hasChangelog: data.hasChangelog,
|
|
447
|
-
docsType: data.docsType,
|
|
448
|
-
hasShippedDocs: data.shippedDocs,
|
|
449
|
-
pkgFiles: data.pkgFiles,
|
|
450
|
-
sections: llmConfig.sections,
|
|
451
|
-
customPrompt: llmConfig.customPrompt,
|
|
452
|
-
features: data.features,
|
|
453
|
-
overheadLines: data.overheadLines
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
else if (llmConfig) {
|
|
792
|
+
renderParallel(render);
|
|
793
|
+
for (const r of uncached) {
|
|
794
|
+
const ui = createParallelUi(r.spec, render, getVersionKey(r.state.version));
|
|
795
|
+
await runEnhancePhase(r.state, llmConfig, {
|
|
796
|
+
agent: config.agent,
|
|
797
|
+
global: config.global,
|
|
798
|
+
force: config.force,
|
|
799
|
+
debug: config.debug
|
|
800
|
+
}, ui, cwd);
|
|
801
|
+
}
|
|
802
|
+
} else if (llmConfig) {
|
|
457
803
|
p.log.step(getModelLabel(llmConfig.model));
|
|
458
|
-
for (const
|
|
459
|
-
name:
|
|
804
|
+
for (const r of uncached) states.set(r.spec, {
|
|
805
|
+
name: r.spec,
|
|
460
806
|
status: "pending",
|
|
461
|
-
message: "Waiting..."
|
|
807
|
+
message: "Waiting...",
|
|
808
|
+
version: getVersionKey(r.state.version)
|
|
462
809
|
});
|
|
463
|
-
render
|
|
464
|
-
const llmResults = await Promise.allSettled(
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
810
|
+
renderParallel(render);
|
|
811
|
+
const llmResults = await Promise.allSettled(uncached.map((r) => limit(async () => {
|
|
812
|
+
const ui = createParallelUi(r.spec, render, getVersionKey(r.state.version));
|
|
813
|
+
await runEnhancePhase(r.state, llmConfig, {
|
|
814
|
+
agent: config.agent,
|
|
815
|
+
global: config.global,
|
|
816
|
+
force: config.force,
|
|
817
|
+
debug: config.debug
|
|
818
|
+
}, ui, cwd);
|
|
819
|
+
})));
|
|
468
820
|
logUpdate.done();
|
|
469
|
-
const llmSucceeded = llmResults.filter((
|
|
470
|
-
p.log.success(`Enhanced ${llmSucceeded}/${
|
|
821
|
+
const llmSucceeded = llmResults.filter((x) => x.status === "fulfilled").length;
|
|
822
|
+
p.log.success(`Enhanced ${llmSucceeded}/${uncached.length} skills with LLM`);
|
|
471
823
|
}
|
|
824
|
+
} else for (const r of ready) {
|
|
825
|
+
const ui = createParallelUi(r.spec, render, getVersionKey(r.state.version));
|
|
826
|
+
await runEnhancePhase(r.state, null, {
|
|
827
|
+
agent: config.agent,
|
|
828
|
+
global: config.global,
|
|
829
|
+
force: config.force,
|
|
830
|
+
debug: config.debug
|
|
831
|
+
}, ui, cwd);
|
|
472
832
|
}
|
|
473
|
-
await
|
|
474
|
-
|
|
833
|
+
await ensureProjectFiles({
|
|
834
|
+
cwd,
|
|
835
|
+
agent: config.agent,
|
|
836
|
+
global: config.global
|
|
837
|
+
});
|
|
475
838
|
await shutdownWorker();
|
|
476
|
-
p.outro(`${pastVerb} ${
|
|
839
|
+
p.outro(`${pastVerb} ${ready.length}/${packages.length} packages`);
|
|
477
840
|
const { suggestPrepareHook } = await import("./cli-helpers2.mjs");
|
|
478
841
|
try {
|
|
479
842
|
await suggestPrepareHook(cwd);
|
|
@@ -481,213 +844,28 @@ async function syncPackagesParallel(config) {
|
|
|
481
844
|
p.log.warn(`Failed to suggest prepare hook: ${err instanceof Error ? err.message : String(err)}`);
|
|
482
845
|
}
|
|
483
846
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
resolved = await resolveLocalDep(packageName, cwd);
|
|
496
|
-
}
|
|
497
|
-
if (!resolved) {
|
|
498
|
-
const shippedVersion = localVersion || registryVersion || "latest";
|
|
499
|
-
const earlyShipped = handleShippedSkills(packageName, shippedVersion, cwd, config.agent, config.global);
|
|
500
|
-
if (earlyShipped) {
|
|
501
|
-
const shared = !config.global && getSharedSkillsDir(cwd);
|
|
502
|
-
if (shared) for (const shipped of earlyShipped.shipped) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
|
|
503
|
-
update(packageName, "done", "Published SKILL.md", getVersionKey(shippedVersion));
|
|
504
|
-
return "shipped";
|
|
847
|
+
function aggregateUpdateCtx(ready) {
|
|
848
|
+
let maxDiff = "";
|
|
849
|
+
let allEnhanced = true;
|
|
850
|
+
let anySyncedAt;
|
|
851
|
+
for (const r of ready) {
|
|
852
|
+
const u = r.state.updateCtx;
|
|
853
|
+
if (!u?.wasEnhanced) allEnhanced = false;
|
|
854
|
+
if (u?.syncedAt && (!anySyncedAt || u.syncedAt < anySyncedAt)) anySyncedAt = u.syncedAt;
|
|
855
|
+
if (u?.oldVersion && u.newVersion) {
|
|
856
|
+
const diff = semverDiff(u.oldVersion, u.newVersion);
|
|
857
|
+
if (diff && (DIFF_RANK[diff] ?? 0) > (DIFF_RANK[maxDiff] ?? -1)) maxDiff = diff;
|
|
505
858
|
}
|
|
506
|
-
const npmAttempt = attempts.find((a) => a.source === "npm");
|
|
507
|
-
let reason;
|
|
508
|
-
if (npmAttempt?.status === "not-found") {
|
|
509
|
-
const suggestions = await searchNpmPackages(packageName, 3);
|
|
510
|
-
const hint = suggestions.length > 0 ? ` (try: ${suggestions.map((s) => s.name).join(", ")})` : "";
|
|
511
|
-
reason = (npmAttempt.message || "Not on npm") + hint;
|
|
512
|
-
} else reason = attempts.filter((a) => a.status !== "success").map((a) => a.message || a.source).join("; ") || "No docs found";
|
|
513
|
-
update(packageName, "error", reason);
|
|
514
|
-
throw new Error(`Could not find docs for: ${packageName}`);
|
|
515
|
-
}
|
|
516
|
-
const version = localVersion || resolved.version || "latest";
|
|
517
|
-
const versionKey = getVersionKey(version);
|
|
518
|
-
if (!existsSync(join(cwd, "node_modules", packageName))) {
|
|
519
|
-
update(packageName, "downloading", "Downloading dist...", versionKey);
|
|
520
|
-
await fetchPkgDist(packageName, version);
|
|
521
|
-
}
|
|
522
|
-
const shippedResult = handleShippedSkills(packageName, version, cwd, config.agent, config.global);
|
|
523
|
-
if (shippedResult) {
|
|
524
|
-
const shared = !config.global && getSharedSkillsDir(cwd);
|
|
525
|
-
if (shared) for (const shipped of shippedResult.shipped) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
|
|
526
|
-
update(packageName, "done", "Published SKILL.md", versionKey);
|
|
527
|
-
return "shipped";
|
|
528
|
-
}
|
|
529
|
-
if (config.force) forceClearCache(packageName, version);
|
|
530
|
-
const useCache = isCached(packageName, version);
|
|
531
|
-
if (useCache) update(packageName, "downloading", "Using cache", versionKey);
|
|
532
|
-
else update(packageName, "downloading", config.force ? "Re-fetching docs..." : "Fetching docs...", versionKey);
|
|
533
|
-
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
534
|
-
let skillDirName = computeSkillDirName(packageName);
|
|
535
|
-
if (config.mode === "update") {
|
|
536
|
-
const lock = readLock(baseDir);
|
|
537
|
-
if (lock) {
|
|
538
|
-
for (const [name, info] of Object.entries(lock.skills)) if (info.packageName === packageName || parsePackages(info.packages).some((p) => p.name === packageName)) {
|
|
539
|
-
skillDirName = name;
|
|
540
|
-
break;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
const skillDir = join(baseDir, skillDirName);
|
|
545
|
-
mkdirSync(skillDir, { recursive: true });
|
|
546
|
-
const preLock = config.mode === "update" ? readLock(baseDir)?.skills[skillDirName] : void 0;
|
|
547
|
-
const preEnhanced = (() => {
|
|
548
|
-
if (!preLock) return false;
|
|
549
|
-
const skillMdPath = join(skillDir, "SKILL.md");
|
|
550
|
-
if (!existsSync(skillMdPath)) return false;
|
|
551
|
-
return !!parseFrontmatter(readFileSync(skillMdPath, "utf-8")).generated_by;
|
|
552
|
-
})();
|
|
553
|
-
const features = readConfig().features ?? defaultFeatures;
|
|
554
|
-
const resources = await fetchAndCacheResources({
|
|
555
|
-
packageName,
|
|
556
|
-
resolved,
|
|
557
|
-
version,
|
|
558
|
-
useCache,
|
|
559
|
-
features,
|
|
560
|
-
onProgress: (msg) => update(packageName, "downloading", msg, versionKey)
|
|
561
|
-
});
|
|
562
|
-
update(packageName, "downloading", "Linking references...", versionKey);
|
|
563
|
-
linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
|
|
564
|
-
if (features.search) {
|
|
565
|
-
update(packageName, "embedding", "Indexing docs", versionKey);
|
|
566
|
-
await indexResources({
|
|
567
|
-
packageName,
|
|
568
|
-
version,
|
|
569
|
-
cwd,
|
|
570
|
-
docsToIndex: resources.docsToIndex,
|
|
571
|
-
features,
|
|
572
|
-
onProgress: (msg) => update(packageName, "embedding", msg, versionKey)
|
|
573
|
-
});
|
|
574
859
|
}
|
|
575
|
-
const
|
|
576
|
-
const relatedSkills = await findRelatedSkills(packageName, baseDir);
|
|
577
|
-
const shippedDocs = hasShippedDocs(packageName, cwd, version);
|
|
578
|
-
const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
|
|
579
|
-
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
580
|
-
linkPkgNamed(skillDir, packageName, cwd, version);
|
|
581
|
-
writeLock(baseDir, skillDirName, {
|
|
582
|
-
packageName,
|
|
583
|
-
version,
|
|
584
|
-
repo: repoSlug,
|
|
585
|
-
source: resources.docSource,
|
|
586
|
-
syncedAt: todayIsoDate(),
|
|
587
|
-
generator: "skilld"
|
|
588
|
-
});
|
|
589
|
-
const updatedLock = readLock(baseDir)?.skills[skillDirName];
|
|
590
|
-
const allPackages = parsePackageNames(updatedLock?.packages);
|
|
591
|
-
const overheadLines = writeGeneratedSkillMd(skillDir, {
|
|
592
|
-
name: packageName,
|
|
593
|
-
version,
|
|
594
|
-
releasedAt: resolved.releasedAt,
|
|
595
|
-
description: resolved.description,
|
|
596
|
-
distTags: resolved.distTags,
|
|
597
|
-
relatedSkills,
|
|
598
|
-
hasIssues: resources.hasIssues,
|
|
599
|
-
hasDiscussions: resources.hasDiscussions,
|
|
600
|
-
hasReleases: resources.hasReleases,
|
|
601
|
-
hasChangelog,
|
|
602
|
-
docsType: resources.docsType,
|
|
603
|
-
hasShippedDocs: shippedDocs,
|
|
604
|
-
pkgFiles,
|
|
605
|
-
dirName: skillDirName,
|
|
606
|
-
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
607
|
-
repoUrl: resolved.repoUrl,
|
|
608
|
-
features
|
|
609
|
-
}).split("\n").length;
|
|
610
|
-
const shared = !config.global && getSharedSkillsDir(cwd);
|
|
611
|
-
if (shared) linkSkillToAgents(skillDirName, shared, cwd, config.agent);
|
|
612
|
-
if (!config.global) registerProject(cwd);
|
|
613
|
-
update(packageName, "done", config.mode === "update" ? "Skill updated" : "Base skill created", versionKey);
|
|
860
|
+
const first = ready[0]?.state.updateCtx;
|
|
614
861
|
return {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
hasDiscussions: resources.hasDiscussions,
|
|
621
|
-
hasReleases: resources.hasReleases,
|
|
622
|
-
hasChangelog,
|
|
623
|
-
shippedDocs,
|
|
624
|
-
pkgFiles,
|
|
625
|
-
relatedSkills,
|
|
626
|
-
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
627
|
-
warnings: resources.warnings,
|
|
628
|
-
features,
|
|
629
|
-
usedCache: resources.usedCache,
|
|
630
|
-
oldVersion: preLock?.version,
|
|
631
|
-
oldSyncedAt: preLock?.syncedAt,
|
|
632
|
-
wasEnhanced: preEnhanced,
|
|
633
|
-
overheadLines
|
|
862
|
+
oldVersion: ready.length === 1 ? first?.oldVersion : void 0,
|
|
863
|
+
newVersion: ready.length === 1 ? first?.newVersion : void 0,
|
|
864
|
+
syncedAt: anySyncedAt,
|
|
865
|
+
wasEnhanced: allEnhanced,
|
|
866
|
+
bumpType: maxDiff || void 0
|
|
634
867
|
};
|
|
635
868
|
}
|
|
636
|
-
async function enhanceWithLLM(packageName, data, config, cwd, update, sections, customPrompt) {
|
|
637
|
-
const versionKey = getVersionKey(data.version);
|
|
638
|
-
const skillDir = join(resolveBaseDir(cwd, config.agent, config.global), data.skillDirName);
|
|
639
|
-
const hasGithub = data.hasIssues || data.hasDiscussions;
|
|
640
|
-
const docFiles = listReferenceFiles(skillDir);
|
|
641
|
-
update(packageName, "generating", config.model, versionKey);
|
|
642
|
-
const { optimized, wasOptimized, error } = await optimizeDocs({
|
|
643
|
-
packageName,
|
|
644
|
-
skillDir,
|
|
645
|
-
model: config.model,
|
|
646
|
-
version: data.version,
|
|
647
|
-
hasGithub,
|
|
648
|
-
hasReleases: data.hasReleases,
|
|
649
|
-
hasChangelog: data.hasChangelog,
|
|
650
|
-
docFiles,
|
|
651
|
-
docsType: data.docsType,
|
|
652
|
-
hasShippedDocs: data.shippedDocs,
|
|
653
|
-
noCache: config.force,
|
|
654
|
-
debug: config.debug,
|
|
655
|
-
sections,
|
|
656
|
-
customPrompt,
|
|
657
|
-
features: data.features,
|
|
658
|
-
pkgFiles: data.pkgFiles,
|
|
659
|
-
overheadLines: data.overheadLines,
|
|
660
|
-
onProgress: (progress) => {
|
|
661
|
-
const status = progress.type === "reasoning" ? "exploring" : "generating";
|
|
662
|
-
const sectionPrefix = progress.section ? `[${progress.section}] ` : "";
|
|
663
|
-
update(packageName, status, progress.chunk.startsWith("[") ? `${sectionPrefix}${progress.chunk}` : `${sectionPrefix}${config.model}`, versionKey);
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
if (error) {
|
|
667
|
-
update(packageName, "error", error, versionKey);
|
|
668
|
-
throw new Error(error);
|
|
669
|
-
}
|
|
670
|
-
if (wasOptimized) writeGeneratedSkillMd(skillDir, {
|
|
671
|
-
name: packageName,
|
|
672
|
-
version: data.version,
|
|
673
|
-
releasedAt: data.resolved.releasedAt,
|
|
674
|
-
distTags: data.resolved.distTags,
|
|
675
|
-
body: optimized,
|
|
676
|
-
relatedSkills: data.relatedSkills,
|
|
677
|
-
hasIssues: data.hasIssues,
|
|
678
|
-
hasDiscussions: data.hasDiscussions,
|
|
679
|
-
hasReleases: data.hasReleases,
|
|
680
|
-
hasChangelog: data.hasChangelog,
|
|
681
|
-
docsType: data.docsType,
|
|
682
|
-
hasShippedDocs: data.shippedDocs,
|
|
683
|
-
pkgFiles: data.pkgFiles,
|
|
684
|
-
dirName: data.skillDirName,
|
|
685
|
-
packages: data.packages,
|
|
686
|
-
repoUrl: data.resolved.repoUrl,
|
|
687
|
-
features: data.features
|
|
688
|
-
});
|
|
689
|
-
update(packageName, "done", "Skill optimized", versionKey);
|
|
690
|
-
}
|
|
691
869
|
const RESOLVE_SOURCE_LABELS = {
|
|
692
870
|
"npm": "npm registry",
|
|
693
871
|
"github-docs": "GitHub versioned docs",
|
|
@@ -708,12 +886,6 @@ function showResolveAttempts(attempts) {
|
|
|
708
886
|
p.log.message(` ${icon} ${source}${msg}`);
|
|
709
887
|
}
|
|
710
888
|
}
|
|
711
|
-
function isCrateSpec(spec) {
|
|
712
|
-
return spec.startsWith("crate:");
|
|
713
|
-
}
|
|
714
|
-
function toCrateIdentity(crateName) {
|
|
715
|
-
return `crate:${crateName}`;
|
|
716
|
-
}
|
|
717
889
|
async function syncCommand(state, opts) {
|
|
718
890
|
if (opts.packages && opts.packages.length > 0) {
|
|
719
891
|
const crateSpecs = opts.packages.filter(isCrateSpec);
|
|
@@ -805,52 +977,30 @@ async function pickFromList(packages, state) {
|
|
|
805
977
|
}
|
|
806
978
|
return selected;
|
|
807
979
|
}
|
|
808
|
-
async function
|
|
809
|
-
const isCrate = isCrateSpec(packageSpec);
|
|
810
|
-
const normalizedSpec = isCrate ? packageSpec.slice(6).trim() : packageSpec;
|
|
811
|
-
if (isCrate && !normalizedSpec) {
|
|
812
|
-
p.log.error("Invalid crate spec. Use format: crate:<name>");
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
const { name: parsedName, tag: requestedTag } = parsePackageSpec(normalizedSpec);
|
|
816
|
-
const packageName = isCrate ? parsedName.toLowerCase() : parsedName;
|
|
817
|
-
const identityPackageName = isCrate ? toCrateIdentity(packageName) : packageName;
|
|
818
|
-
const storagePackageName = toStoragePackageName(identityPackageName);
|
|
819
|
-
const spin = timedSpinner();
|
|
820
|
-
spin.start(`Resolving ${packageSpec}`);
|
|
980
|
+
async function runSimpleSync(packageSpec, config) {
|
|
821
981
|
const cwd = process.cwd();
|
|
822
|
-
const
|
|
823
|
-
const
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
982
|
+
const ui = createClackUi({ cwd });
|
|
983
|
+
const isEject = !!config.eject;
|
|
984
|
+
const result = await runBaseSync(packageSpec, {
|
|
985
|
+
agent: config.agent,
|
|
986
|
+
global: config.global,
|
|
987
|
+
mode: config.mode,
|
|
988
|
+
force: config.force,
|
|
989
|
+
noSearch: config.noSearch,
|
|
990
|
+
name: config.name,
|
|
991
|
+
from: config.from,
|
|
992
|
+
eject: config.eject
|
|
993
|
+
}, ui, npmResolver, cwd, DEFAULT_SECTIONS);
|
|
994
|
+
if (result.kind === "shipped") {
|
|
995
|
+
p.outro(`Synced ${packageSpec}`);
|
|
996
|
+
return;
|
|
836
997
|
}
|
|
837
|
-
if (
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
const shared = !config.global && getSharedSkillsDir(cwd);
|
|
842
|
-
for (const shipped of earlyShipped.shipped) {
|
|
843
|
-
if (shared) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
|
|
844
|
-
p.log.success(`Using published SKILL.md: ${shipped.skillName} → ${relative(cwd, shipped.skillDir)}`);
|
|
845
|
-
}
|
|
846
|
-
spin.stop(`Using published SKILL.md(s) from ${packageName}`);
|
|
847
|
-
return;
|
|
848
|
-
}
|
|
849
|
-
spin.message(`Searching npm for "${packageName}"...`);
|
|
850
|
-
const suggestions = await searchNpmPackages(packageName);
|
|
998
|
+
if (result.kind === "unresolved") {
|
|
999
|
+
const { unresolved } = result;
|
|
1000
|
+
if (!isCrateSpec(packageSpec)) {
|
|
1001
|
+
const suggestions = await searchNpmPackages(unresolved.identityName);
|
|
851
1002
|
if (suggestions.length > 0) {
|
|
852
|
-
|
|
853
|
-
showResolveAttempts(resolveResult.attempts);
|
|
1003
|
+
showResolveAttempts(unresolved.attempts);
|
|
854
1004
|
const selected = await p.select({
|
|
855
1005
|
message: "Did you mean one of these?",
|
|
856
1006
|
options: [...suggestions.map((s) => ({
|
|
@@ -866,299 +1016,45 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
866
1016
|
return;
|
|
867
1017
|
}
|
|
868
1018
|
}
|
|
869
|
-
|
|
870
|
-
showResolveAttempts(resolveResult.attempts);
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
const version = isCrate ? resolved.version || requestedTag || "latest" : localVersion || resolved.version || "latest";
|
|
874
|
-
const versionKey = getVersionKey(version);
|
|
875
|
-
if (config.force) forceClearCache(storagePackageName, version);
|
|
876
|
-
const useCache = isCached(storagePackageName, version);
|
|
877
|
-
if (!isCrate && !existsSync(join(cwd, "node_modules", packageName))) {
|
|
878
|
-
spin.message(`Downloading ${packageName}@${version} dist`);
|
|
879
|
-
await fetchPkgDist(packageName, version);
|
|
880
|
-
}
|
|
881
|
-
const shippedResult = isCrate ? null : handleShippedSkills(packageName, version, cwd, config.agent, config.global);
|
|
882
|
-
if (shippedResult) {
|
|
883
|
-
const shared = !config.global && getSharedSkillsDir(cwd);
|
|
884
|
-
for (const shipped of shippedResult.shipped) {
|
|
885
|
-
if (shared) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
|
|
886
|
-
p.log.success(`Using published SKILL.md: ${shipped.skillName} → ${relative(cwd, shipped.skillDir)}`);
|
|
887
|
-
}
|
|
888
|
-
spin.stop(`Using published SKILL.md(s) from ${packageName}`);
|
|
1019
|
+
showResolveAttempts(unresolved.attempts);
|
|
889
1020
|
return;
|
|
890
1021
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
ensureCacheDir();
|
|
897
|
-
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
898
|
-
let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(storagePackageName);
|
|
899
|
-
if (config.mode === "update" && !config.name) {
|
|
900
|
-
const lock = readLock(baseDir);
|
|
901
|
-
if (lock) {
|
|
902
|
-
for (const [name, info] of Object.entries(lock.skills)) if (info.packageName === identityPackageName || parsePackages(info.packages).some((p) => p.name === identityPackageName)) {
|
|
903
|
-
skillDirName = name;
|
|
904
|
-
break;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
|
|
909
|
-
mkdirSync(skillDir, { recursive: true });
|
|
910
|
-
const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
|
|
911
|
-
const isMerge = existingLock && existingLock.packageName && existingLock.packageName !== identityPackageName;
|
|
912
|
-
const updateCtx = config.mode === "update" && existingLock ? {
|
|
913
|
-
oldVersion: existingLock.version,
|
|
914
|
-
newVersion: version,
|
|
915
|
-
syncedAt: existingLock.syncedAt,
|
|
916
|
-
wasEnhanced: (() => {
|
|
917
|
-
const skillMdPath = join(skillDir, "SKILL.md");
|
|
918
|
-
if (!existsSync(skillMdPath)) return false;
|
|
919
|
-
return !!parseFrontmatter(readFileSync(skillMdPath, "utf-8")).generated_by;
|
|
920
|
-
})()
|
|
921
|
-
} : void 0;
|
|
922
|
-
if (isMerge) {
|
|
923
|
-
spin.stop(`Merging ${identityPackageName} into ${skillDirName}`);
|
|
924
|
-
linkPkgNamed(skillDir, storagePackageName, cwd, version);
|
|
925
|
-
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
926
|
-
writeLock(baseDir, skillDirName, {
|
|
927
|
-
packageName: identityPackageName,
|
|
928
|
-
version,
|
|
929
|
-
repo: repoSlug,
|
|
930
|
-
source: existingLock.source,
|
|
931
|
-
syncedAt: todayIsoDate(),
|
|
932
|
-
generator: "skilld"
|
|
933
|
-
});
|
|
934
|
-
const updatedLock = readLock(baseDir)?.skills[skillDirName];
|
|
935
|
-
const allPackages = parsePackageNames(updatedLock?.packages);
|
|
936
|
-
const relatedSkills = await findRelatedSkills(storagePackageName, baseDir);
|
|
937
|
-
const existingStorageName = toStoragePackageName(existingLock.packageName);
|
|
938
|
-
const pkgFiles = getPkgKeyFiles(existingStorageName, cwd, existingLock.version);
|
|
939
|
-
const shippedDocs = hasShippedDocs(existingStorageName, cwd, existingLock.version);
|
|
940
|
-
const mergeFeatures = readConfig().features ?? defaultFeatures;
|
|
941
|
-
writeGeneratedSkillMd(skillDir, {
|
|
942
|
-
name: existingLock.packageName,
|
|
943
|
-
version: existingLock.version,
|
|
944
|
-
relatedSkills,
|
|
945
|
-
hasIssues: mergeFeatures.issues && existsSync(join(skillDir, ".skilld", "issues")),
|
|
946
|
-
hasDiscussions: mergeFeatures.discussions && existsSync(join(skillDir, ".skilld", "discussions")),
|
|
947
|
-
hasReleases: mergeFeatures.releases && existsSync(join(skillDir, ".skilld", "releases")),
|
|
948
|
-
docsType: existingLock.source?.includes("llms.txt") ? "llms.txt" : "docs",
|
|
949
|
-
hasShippedDocs: shippedDocs,
|
|
950
|
-
pkgFiles,
|
|
951
|
-
dirName: skillDirName,
|
|
952
|
-
packages: allPackages,
|
|
953
|
-
features: mergeFeatures
|
|
954
|
-
});
|
|
955
|
-
const mergeShared = !config.global && getSharedSkillsDir(cwd);
|
|
956
|
-
if (mergeShared) linkSkillToAgents(skillDirName, mergeShared, cwd, config.agent);
|
|
957
|
-
if (!config.global) registerProject(cwd);
|
|
958
|
-
p.outro(`Merged ${identityPackageName} into ${skillDirName}`);
|
|
1022
|
+
if (result.kind === "merge-needed") {
|
|
1023
|
+
await handleMerge(result.state, {
|
|
1024
|
+
agent: config.agent,
|
|
1025
|
+
global: config.global
|
|
1026
|
+
}, cwd);
|
|
959
1027
|
return;
|
|
960
1028
|
}
|
|
961
|
-
const
|
|
962
|
-
if (config.noSearch) features.search = false;
|
|
963
|
-
const resSpin = timedSpinner();
|
|
964
|
-
resSpin.start("Finding resources");
|
|
965
|
-
const resources = await fetchAndCacheResources({
|
|
966
|
-
packageName: storagePackageName,
|
|
967
|
-
resolved,
|
|
968
|
-
version,
|
|
969
|
-
useCache,
|
|
970
|
-
features,
|
|
971
|
-
from: config.from,
|
|
972
|
-
onProgress: (msg) => resSpin.message(msg)
|
|
973
|
-
});
|
|
974
|
-
const resParts = [];
|
|
975
|
-
if (resources.docsToIndex.length > 0) {
|
|
976
|
-
const docCount = resources.docsToIndex.filter((d) => d.metadata?.type === "doc").length;
|
|
977
|
-
if (docCount > 0) resParts.push(`${docCount} docs`);
|
|
978
|
-
}
|
|
979
|
-
if (resources.hasIssues) resParts.push("issues");
|
|
980
|
-
if (resources.hasDiscussions) resParts.push("discussions");
|
|
981
|
-
if (resources.hasReleases) resParts.push("releases");
|
|
982
|
-
resSpin.stop(resources.usedCache ? `Loaded ${resParts.length > 0 ? resParts.join(", ") : "resources"} (cached)` : `Fetched ${resParts.length > 0 ? resParts.join(", ") : "resources"}`);
|
|
983
|
-
for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
984
|
-
linkAllReferences(skillDir, storagePackageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
|
|
985
|
-
if (features.search) {
|
|
986
|
-
const idxSpin = timedSpinner();
|
|
987
|
-
idxSpin.start("Creating search index");
|
|
988
|
-
await indexResources({
|
|
989
|
-
packageName: storagePackageName,
|
|
990
|
-
version,
|
|
991
|
-
cwd,
|
|
992
|
-
docsToIndex: resources.docsToIndex,
|
|
993
|
-
features,
|
|
994
|
-
onProgress: (msg) => idxSpin.message(msg)
|
|
995
|
-
});
|
|
996
|
-
idxSpin.stop("Search index ready");
|
|
997
|
-
}
|
|
998
|
-
const hasChangelog = detectChangelog(resolvePkgDir(storagePackageName, cwd, version), getCacheDir(storagePackageName, version));
|
|
999
|
-
const relatedSkills = await findRelatedSkills(storagePackageName, baseDir);
|
|
1000
|
-
const shippedDocs = hasShippedDocs(storagePackageName, cwd, version);
|
|
1001
|
-
const pkgFiles = getPkgKeyFiles(storagePackageName, cwd, version);
|
|
1002
|
-
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
1003
|
-
if (!config.eject) linkPkgNamed(skillDir, storagePackageName, cwd, version);
|
|
1004
|
-
if (!config.eject) {
|
|
1005
|
-
writeLock(baseDir, skillDirName, {
|
|
1006
|
-
packageName: identityPackageName,
|
|
1007
|
-
version,
|
|
1008
|
-
repo: repoSlug,
|
|
1009
|
-
source: resources.docSource,
|
|
1010
|
-
syncedAt: todayIsoDate(),
|
|
1011
|
-
generator: "skilld"
|
|
1012
|
-
});
|
|
1013
|
-
const lock = readLock(baseDir);
|
|
1014
|
-
if (lock) for (const [name, info] of Object.entries(lock.skills)) {
|
|
1015
|
-
if (name === skillDirName) continue;
|
|
1016
|
-
if (info.packageName === identityPackageName || parsePackages(info.packages).some((p) => p.name === identityPackageName)) {
|
|
1017
|
-
removeLockEntry(baseDir, name);
|
|
1018
|
-
const staleDir = join(baseDir, name);
|
|
1019
|
-
if (existsSync(staleDir)) rmSync(staleDir, { recursive: true });
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
const allPackages = parsePackageNames((config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName])?.packages);
|
|
1024
|
-
const isEject = !!config.eject;
|
|
1025
|
-
const overheadLines = writeGeneratedSkillMd(skillDir, {
|
|
1026
|
-
name: identityPackageName,
|
|
1027
|
-
version,
|
|
1028
|
-
releasedAt: resolved.releasedAt,
|
|
1029
|
-
description: resolved.description,
|
|
1030
|
-
distTags: resolved.distTags,
|
|
1031
|
-
relatedSkills,
|
|
1032
|
-
hasIssues: resources.hasIssues,
|
|
1033
|
-
hasDiscussions: resources.hasDiscussions,
|
|
1034
|
-
hasReleases: resources.hasReleases,
|
|
1035
|
-
hasChangelog,
|
|
1036
|
-
docsType: resources.docsType,
|
|
1037
|
-
hasShippedDocs: shippedDocs,
|
|
1038
|
-
pkgFiles,
|
|
1039
|
-
dirName: skillDirName,
|
|
1040
|
-
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
1041
|
-
repoUrl: resolved.repoUrl,
|
|
1042
|
-
features,
|
|
1043
|
-
eject: isEject
|
|
1044
|
-
}).split("\n").length;
|
|
1045
|
-
p.log.success(config.mode === "update" ? `Updated skill: ${relative(cwd, skillDir)}` : `Created base skill: ${relative(cwd, skillDir)}`);
|
|
1046
|
-
const allSectionsCached = !config.force && DEFAULT_SECTIONS.every((s) => {
|
|
1047
|
-
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
1048
|
-
return readCachedSection(storagePackageName, version, outputFile) !== null;
|
|
1049
|
-
});
|
|
1050
|
-
if (allSectionsCached) {
|
|
1051
|
-
const cachedParts = [];
|
|
1052
|
-
for (const s of SECTION_MERGE_ORDER) {
|
|
1053
|
-
if (!DEFAULT_SECTIONS.includes(s)) continue;
|
|
1054
|
-
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
1055
|
-
const content = readCachedSection(storagePackageName, version, outputFile);
|
|
1056
|
-
if (content) cachedParts.push(wrapSection(s, content));
|
|
1057
|
-
}
|
|
1058
|
-
const cachedBody = cachedParts.join("\n\n");
|
|
1059
|
-
writeGeneratedSkillMd(skillDir, {
|
|
1060
|
-
name: identityPackageName,
|
|
1061
|
-
version,
|
|
1062
|
-
releasedAt: resolved.releasedAt,
|
|
1063
|
-
description: resolved.description,
|
|
1064
|
-
distTags: resolved.distTags,
|
|
1065
|
-
body: cachedBody,
|
|
1066
|
-
relatedSkills,
|
|
1067
|
-
hasIssues: resources.hasIssues,
|
|
1068
|
-
hasDiscussions: resources.hasDiscussions,
|
|
1069
|
-
hasReleases: resources.hasReleases,
|
|
1070
|
-
hasChangelog,
|
|
1071
|
-
docsType: resources.docsType,
|
|
1072
|
-
hasShippedDocs: shippedDocs,
|
|
1073
|
-
pkgFiles,
|
|
1074
|
-
generatedBy: "cached",
|
|
1075
|
-
dirName: skillDirName,
|
|
1076
|
-
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
1077
|
-
repoUrl: resolved.repoUrl,
|
|
1078
|
-
features,
|
|
1079
|
-
eject: isEject
|
|
1080
|
-
});
|
|
1081
|
-
p.log.success("Applied cached SKILL.md sections");
|
|
1082
|
-
}
|
|
1029
|
+
const { state } = result;
|
|
1083
1030
|
const globalConfig = readConfig();
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
skillDir,
|
|
1095
|
-
version,
|
|
1096
|
-
hasIssues: resources.hasIssues,
|
|
1097
|
-
hasDiscussions: resources.hasDiscussions,
|
|
1098
|
-
hasReleases: resources.hasReleases,
|
|
1099
|
-
hasChangelog,
|
|
1100
|
-
docsType: resources.docsType,
|
|
1101
|
-
hasShippedDocs: shippedDocs,
|
|
1102
|
-
pkgFiles,
|
|
1103
|
-
sections: llmConfig.sections,
|
|
1104
|
-
customPrompt: llmConfig.customPrompt,
|
|
1105
|
-
features,
|
|
1106
|
-
overheadLines
|
|
1107
|
-
});
|
|
1108
|
-
else if (llmConfig) {
|
|
1109
|
-
p.log.step(getModelLabel(llmConfig.model));
|
|
1110
|
-
await enhanceSkillWithLLM({
|
|
1111
|
-
packageName: identityPackageName,
|
|
1112
|
-
cachePackageName: storagePackageName,
|
|
1113
|
-
version,
|
|
1114
|
-
skillDir,
|
|
1115
|
-
dirName: skillDirName,
|
|
1116
|
-
model: llmConfig.model,
|
|
1117
|
-
resolved,
|
|
1118
|
-
relatedSkills,
|
|
1119
|
-
hasIssues: resources.hasIssues,
|
|
1120
|
-
hasDiscussions: resources.hasDiscussions,
|
|
1121
|
-
hasReleases: resources.hasReleases,
|
|
1122
|
-
hasChangelog,
|
|
1123
|
-
docsType: resources.docsType,
|
|
1124
|
-
hasShippedDocs: shippedDocs,
|
|
1125
|
-
pkgFiles,
|
|
1126
|
-
force: config.force,
|
|
1127
|
-
debug: config.debug,
|
|
1128
|
-
sections: llmConfig.sections,
|
|
1129
|
-
customPrompt: llmConfig.customPrompt,
|
|
1130
|
-
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
1131
|
-
features,
|
|
1132
|
-
eject: isEject,
|
|
1133
|
-
overheadLines
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
if (isEject) {
|
|
1138
|
-
const skilldDir = join(skillDir, ".skilld");
|
|
1139
|
-
if (existsSync(skilldDir) && !config.debug) rmSync(skilldDir, {
|
|
1140
|
-
recursive: true,
|
|
1141
|
-
force: true
|
|
1142
|
-
});
|
|
1143
|
-
ejectReferences(skillDir, storagePackageName, cwd, version, resources.docsType, features, resources.repoInfo);
|
|
1144
|
-
}
|
|
1145
|
-
if (!isEject) {
|
|
1146
|
-
const shared = !config.global && getSharedSkillsDir(cwd);
|
|
1147
|
-
if (shared) linkSkillToAgents(skillDirName, shared, cwd, config.agent);
|
|
1148
|
-
if (!config.global) registerProject(cwd);
|
|
1149
|
-
await ensureGitignore(shared ? SHARED_SKILLS_DIR : targets[config.agent].skillsDir, cwd, config.global);
|
|
1150
|
-
await ensureAgentInstructions(config.agent, cwd, config.global);
|
|
1151
|
-
}
|
|
1031
|
+
const resolvedModel = await resolveAutoModel(config.model, config.yes);
|
|
1032
|
+
let llmConfig = null;
|
|
1033
|
+
if (!state.allSectionsCached && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) llmConfig = await selectLlmConfig(resolvedModel, void 0, state.updateCtx);
|
|
1034
|
+
await runEnhancePhase(state, llmConfig, {
|
|
1035
|
+
agent: config.agent,
|
|
1036
|
+
global: config.global,
|
|
1037
|
+
force: config.force,
|
|
1038
|
+
debug: config.debug,
|
|
1039
|
+
eject: config.eject
|
|
1040
|
+
}, ui, cwd);
|
|
1152
1041
|
await shutdownWorker();
|
|
1153
1042
|
const ejectMsg = isEject ? " (ejected)" : "";
|
|
1154
|
-
const relDir = relative(cwd, skillDir);
|
|
1155
|
-
p.outro(config.mode === "update" ? `Updated ${
|
|
1043
|
+
const relDir = relative(cwd, state.skillDir);
|
|
1044
|
+
p.outro(config.mode === "update" ? `Updated ${state.identityName}${ejectMsg}` : `Synced ${state.identityName} → ${relDir}${ejectMsg}`);
|
|
1156
1045
|
try {
|
|
1157
1046
|
await suggestPrepareHook(cwd);
|
|
1158
1047
|
} catch (err) {
|
|
1159
1048
|
p.log.warn(`Failed to suggest prepare hook: ${err instanceof Error ? err.message : String(err)}`);
|
|
1160
1049
|
}
|
|
1161
1050
|
}
|
|
1051
|
+
async function syncSinglePackage(packageSpec, config) {
|
|
1052
|
+
if (isCrateSpec(packageSpec) && !packageSpec.slice(6).trim()) {
|
|
1053
|
+
p.log.error("Invalid crate spec. Use format: crate:<name>");
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
return runSimpleSync(packageSpec, config);
|
|
1057
|
+
}
|
|
1162
1058
|
const addCommandDef = defineCommand({
|
|
1163
1059
|
meta: {
|
|
1164
1060
|
name: "add",
|
|
@@ -1464,36 +1360,29 @@ const updateCommandDef = defineCommand({
|
|
|
1464
1360
|
}
|
|
1465
1361
|
});
|
|
1466
1362
|
async function exportPortablePrompts(packageSpec, opts) {
|
|
1467
|
-
const { name: packageName } = parsePackageSpec(packageSpec);
|
|
1468
1363
|
const sections = opts.sections ?? DEFAULT_SECTIONS;
|
|
1469
1364
|
const spin = timedSpinner();
|
|
1470
1365
|
spin.start(`Resolving ${packageSpec}`);
|
|
1471
1366
|
const cwd = process.cwd();
|
|
1472
|
-
const localVersion =
|
|
1473
|
-
let resolved = (await resolvePackageDocsWithAttempts(packageName, {
|
|
1474
|
-
version: localVersion,
|
|
1367
|
+
const { packageName, localVersion, resolved } = await resolvePackageOrCrate(packageSpec, {
|
|
1475
1368
|
cwd,
|
|
1476
|
-
onProgress: (
|
|
1477
|
-
})
|
|
1478
|
-
if (!resolved) {
|
|
1479
|
-
spin.message(`Resolving local package: ${packageName}`);
|
|
1480
|
-
resolved = await resolveLocalDep(packageName, cwd);
|
|
1481
|
-
}
|
|
1369
|
+
onProgress: (label) => spin.message(`${packageSpec}: ${label}`)
|
|
1370
|
+
});
|
|
1482
1371
|
if (!resolved) {
|
|
1483
|
-
spin.stop(`Could not find docs for: ${
|
|
1372
|
+
spin.stop(`Could not find docs for: ${packageSpec}`);
|
|
1484
1373
|
return;
|
|
1485
1374
|
}
|
|
1486
1375
|
const version = localVersion || resolved.version || "latest";
|
|
1487
|
-
const
|
|
1488
|
-
const useCache = !opts.force &&
|
|
1376
|
+
const cache = createReferenceCache(packageName, version);
|
|
1377
|
+
const useCache = !opts.force && cache.has();
|
|
1489
1378
|
if (!existsSync(join(cwd, "node_modules", packageName))) {
|
|
1490
1379
|
spin.message(`Downloading ${packageName}@${version} dist`);
|
|
1491
1380
|
await fetchPkgDist(packageName, version);
|
|
1492
1381
|
}
|
|
1493
|
-
spin.stop(`Resolved ${packageName}@${useCache ? versionKey : version}`);
|
|
1494
|
-
|
|
1382
|
+
spin.stop(`Resolved ${packageName}@${useCache ? cache.versionKey : version}`);
|
|
1383
|
+
cache.ensure();
|
|
1495
1384
|
const skillDirName = computeSkillDirName(packageName);
|
|
1496
|
-
const features =
|
|
1385
|
+
const features = getActiveFeatures();
|
|
1497
1386
|
const agent = opts.agent === "none" ? null : opts.agent ?? await import("./detect2.mjs").then((m) => m.detectTargetAgent());
|
|
1498
1387
|
const baseDir = agent ? resolveBaseDir(cwd, agent, false) : join(cwd, ".claude", "skills");
|
|
1499
1388
|
const skillDir = opts.out ? resolve(cwd, opts.out) : join(baseDir, skillDirName);
|
|
@@ -1514,10 +1403,15 @@ async function exportPortablePrompts(packageSpec, opts) {
|
|
|
1514
1403
|
});
|
|
1515
1404
|
resSpin.stop("Resources ready");
|
|
1516
1405
|
for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1406
|
+
const { hasChangelog, shippedDocs, pkgFiles, relatedSkills } = await prepareSkillReferences({
|
|
1407
|
+
packageName,
|
|
1408
|
+
version,
|
|
1409
|
+
cwd,
|
|
1410
|
+
skillDir,
|
|
1411
|
+
resources,
|
|
1412
|
+
features,
|
|
1413
|
+
baseDir: join(skillDir, "..")
|
|
1414
|
+
});
|
|
1521
1415
|
const docFiles = listReferenceFiles(skillDir);
|
|
1522
1416
|
const prompts = buildAllSectionPrompts({
|
|
1523
1417
|
packageName,
|
|
@@ -1534,17 +1428,15 @@ async function exportPortablePrompts(packageSpec, opts) {
|
|
|
1534
1428
|
features,
|
|
1535
1429
|
sections
|
|
1536
1430
|
});
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
recursive: true,
|
|
1541
|
-
force: true
|
|
1431
|
+
cache.eject(skillDir, cwd, resources.docsType, {
|
|
1432
|
+
features,
|
|
1433
|
+
repoInfo: resources.repoInfo
|
|
1542
1434
|
});
|
|
1435
|
+
cache.clearSkillInternal(skillDir);
|
|
1543
1436
|
for (const [section, prompt] of prompts) {
|
|
1544
1437
|
const portable = portabilizePrompt(prompt, section);
|
|
1545
1438
|
writeFileSync(join(skillDir, `PROMPT_${section}.md`), portable);
|
|
1546
1439
|
}
|
|
1547
|
-
const relatedSkills = await findRelatedSkills(packageName, join(skillDir, ".."));
|
|
1548
1440
|
writeGeneratedSkillMd(skillDir, {
|
|
1549
1441
|
name: packageName,
|
|
1550
1442
|
version,
|
|
@@ -1563,21 +1455,40 @@ async function exportPortablePrompts(packageSpec, opts) {
|
|
|
1563
1455
|
features,
|
|
1564
1456
|
eject: true
|
|
1565
1457
|
});
|
|
1566
|
-
|
|
1567
|
-
packageName,
|
|
1568
|
-
version,
|
|
1569
|
-
repo: parseGitHubRepoSlug(resolved.repoUrl),
|
|
1570
|
-
source: resources.docSource,
|
|
1571
|
-
syncedAt: todayIsoDate(),
|
|
1572
|
-
generator: "skilld"
|
|
1573
|
-
});
|
|
1458
|
+
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
1574
1459
|
if (agent) {
|
|
1575
|
-
const shared =
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1460
|
+
const { shared } = installSkill({
|
|
1461
|
+
cwd,
|
|
1462
|
+
agent,
|
|
1463
|
+
global: false,
|
|
1464
|
+
baseDir,
|
|
1465
|
+
skillDirName,
|
|
1466
|
+
lock: {
|
|
1467
|
+
packageName,
|
|
1468
|
+
version,
|
|
1469
|
+
repo: repoSlug,
|
|
1470
|
+
source: resources.docSource,
|
|
1471
|
+
syncedAt: todayIsoDate(),
|
|
1472
|
+
generator: "skilld"
|
|
1473
|
+
}
|
|
1474
|
+
});
|
|
1475
|
+
await ensureProjectFiles({
|
|
1476
|
+
cwd,
|
|
1477
|
+
agent,
|
|
1478
|
+
global: false,
|
|
1479
|
+
shared
|
|
1480
|
+
});
|
|
1481
|
+
} else {
|
|
1482
|
+
writeLock(baseDir, skillDirName, {
|
|
1483
|
+
packageName,
|
|
1484
|
+
version,
|
|
1485
|
+
repo: repoSlug,
|
|
1486
|
+
source: resources.docSource,
|
|
1487
|
+
syncedAt: todayIsoDate(),
|
|
1488
|
+
generator: "skilld"
|
|
1489
|
+
});
|
|
1490
|
+
await ensureGitignore(".claude/skills", cwd, false);
|
|
1491
|
+
}
|
|
1581
1492
|
const relDir = relative(cwd, skillDir);
|
|
1582
1493
|
const sectionList = [...prompts.keys()];
|
|
1583
1494
|
p.log.success(`Skill installed to ${relDir}`);
|
|
@@ -1585,6 +1496,6 @@ async function exportPortablePrompts(packageSpec, opts) {
|
|
|
1585
1496
|
const outputFileList = sectionList.map((s) => SECTION_OUTPUT_FILES[s]).join(", ");
|
|
1586
1497
|
p.log.info(`Have your agent enhance the skill. Give it this prompt:\n\x1B[2m\x1B[3m Read each prompt file (${promptFiles}) in ${relDir}/, read the\n referenced files, then write your output to the matching file (${outputFileList}).\n When done, run: skilld assemble\x1B[0m`);
|
|
1587
1498
|
}
|
|
1588
|
-
export {
|
|
1499
|
+
export { updateCommandDef as a, syncCommand as i, ejectCommandDef as n, exportPortablePrompts as r, addCommandDef as t };
|
|
1589
1500
|
|
|
1590
1501
|
//# sourceMappingURL=sync.mjs.map
|