skilld 1.7.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/add.mjs +66 -0
- package/dist/_chunks/add.mjs.map +1 -0
- package/dist/_chunks/agent-prompt.mjs +88 -0
- package/dist/_chunks/agent-prompt.mjs.map +1 -0
- package/dist/_chunks/agent.mjs +737 -619
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/args.mjs +42 -0
- package/dist/_chunks/args.mjs.map +1 -0
- package/dist/_chunks/assemble.mjs +11 -8
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +77 -131
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +320 -54
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +7 -6
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/client.mjs +117 -0
- package/dist/_chunks/client.mjs.map +1 -0
- package/dist/_chunks/core.mjs +7 -4
- package/dist/_chunks/detect.mjs +54 -44
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/eject.mjs +69 -0
- package/dist/_chunks/eject.mjs.map +1 -0
- package/dist/_chunks/embedding-cache2.mjs +2 -2
- package/dist/_chunks/env.mjs +19 -0
- package/dist/_chunks/env.mjs.map +1 -0
- package/dist/_chunks/install-many.mjs +376 -0
- package/dist/_chunks/install-many.mjs.map +1 -0
- package/dist/_chunks/install.mjs +86 -371
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/intro.mjs +63 -0
- package/dist/_chunks/intro.mjs.map +1 -0
- package/dist/_chunks/list.mjs +2 -2
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +31 -7
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/login.mjs +233 -0
- package/dist/_chunks/login.mjs.map +1 -0
- package/dist/_chunks/logout.mjs +27 -0
- package/dist/_chunks/logout.mjs.map +1 -0
- package/dist/_chunks/map.mjs +11 -0
- package/dist/_chunks/map.mjs.map +1 -0
- package/dist/_chunks/markdown.mjs +79 -54
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/menu.mjs +33 -0
- package/dist/_chunks/menu.mjs.map +1 -0
- package/dist/_chunks/model-picker.mjs +61 -0
- package/dist/_chunks/model-picker.mjs.map +1 -0
- package/dist/_chunks/monorepo.mjs +73 -0
- package/dist/_chunks/monorepo.mjs.map +1 -0
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/paths.mjs +47 -0
- package/dist/_chunks/paths.mjs.map +1 -0
- package/dist/_chunks/pipeline.mjs +985 -0
- package/dist/_chunks/pipeline.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +2 -2
- package/dist/_chunks/portable.mjs +151 -0
- package/dist/_chunks/portable.mjs.map +1 -0
- package/dist/_chunks/prepare-hook.mjs +2 -0
- package/dist/_chunks/prepare-hook2.mjs +61 -0
- package/dist/_chunks/prepare-hook2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +47 -3
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +9 -8
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +784 -26
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/pull.mjs +219 -0
- package/dist/_chunks/pull.mjs.map +1 -0
- package/dist/_chunks/regex.mjs +19 -0
- package/dist/_chunks/regex.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +2 -171
- package/dist/_chunks/retriv2.mjs +159 -0
- package/dist/_chunks/retriv2.mjs.map +1 -0
- package/dist/_chunks/sanitize.mjs +12 -9
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +9 -8
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +23 -20
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +3 -4
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/{sources.mjs → semver.mjs} +1128 -838
- package/dist/_chunks/semver.mjs.map +1 -0
- package/dist/_chunks/skill-installer.mjs +2 -0
- package/dist/_chunks/skill-installer2.mjs +154 -0
- package/dist/_chunks/skill-installer2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +12 -12
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/store.mjs +107 -0
- package/dist/_chunks/store.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +761 -1349
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +2 -3
- package/dist/_chunks/telemetry.mjs +26 -0
- package/dist/_chunks/telemetry.mjs.map +1 -0
- package/dist/_chunks/uninstall.mjs +15 -13
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/update.mjs +171 -0
- package/dist/_chunks/update.mjs.map +1 -0
- package/dist/_chunks/upload.mjs +4 -4
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +16 -27
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/whoami.mjs +21 -0
- package/dist/_chunks/whoami.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -190
- package/dist/_chunks/wizard2.mjs +200 -0
- package/dist/_chunks/wizard2.mjs.map +1 -0
- package/dist/cli.mjs +77 -59
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs +5 -4
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +5 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +1 -1
- package/package.json +20 -29
- package/dist/_chunks/author-group.mjs +0 -17
- package/dist/_chunks/author-group.mjs.map +0 -1
- package/dist/_chunks/cli-helpers.mjs +0 -335
- package/dist/_chunks/cli-helpers.mjs.map +0 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -2
- package/dist/_chunks/config.mjs +0 -122
- package/dist/_chunks/config.mjs.map +0 -1
- package/dist/_chunks/index.d.mts +0 -151
- package/dist/_chunks/index.d.mts.map +0 -1
- package/dist/_chunks/index2.d.mts +0 -44
- package/dist/_chunks/index2.d.mts.map +0 -1
- package/dist/_chunks/index3.d.mts +0 -589
- package/dist/_chunks/index3.d.mts.map +0 -1
- package/dist/_chunks/prefix.mjs +0 -108
- package/dist/_chunks/prefix.mjs.map +0 -1
- package/dist/_chunks/retriv.mjs.map +0 -1
- package/dist/_chunks/setup.mjs +0 -17
- package/dist/_chunks/setup.mjs.map +0 -1
- package/dist/_chunks/shared.mjs +0 -503
- 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/sources.mjs.map +0 -1
- package/dist/_chunks/sync-registry.mjs +0 -59
- package/dist/_chunks/sync-registry.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/_chunks/types.d.mts +0 -88
- package/dist/_chunks/types.d.mts.map +0 -1
- package/dist/_chunks/wizard.mjs.map +0 -1
- package/dist/agent/index.d.mts +0 -346
- package/dist/agent/index.d.mts.map +0 -1
- package/dist/agent/index.mjs +0 -5
- package/dist/cache/index.d.mts +0 -2
- package/dist/cache/index.mjs +0 -4
- package/dist/index.d.mts +0 -5
- package/dist/index.mjs +0 -5
- package/dist/retriv/index.d.mts +0 -3
- package/dist/retriv/index.mjs +0 -2
- package/dist/sources/index.d.mts +0 -2
- package/dist/sources/index.mjs +0 -3
- package/dist/types.d.mts +0 -4
- package/dist/types.mjs +0 -1
package/dist/_chunks/sync.mjs
CHANGED
|
@@ -1,266 +1,519 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { i as getModelLabel, n as detectImportedPackages } from "./agent.mjs";
|
|
2
|
+
import { a as sanitizeName, c as formatDuration, g as todayIsoDate, h as timedSpinner, i as linkSkillToAgents, r as computeSkillDirName, t as writeGeneratedSkillMd } from "./prompts.mjs";
|
|
3
|
+
import { _ as skillRefsSection, f as getSharedSkillsDir } from "./paths.mjs";
|
|
4
|
+
import { c as getVersionKey } from "./prepare.mjs";
|
|
5
|
+
import { d as readConfig, r as ensureCacheDir, s as getActiveFeatures, t as createReferenceCache } from "./cache.mjs";
|
|
6
|
+
import { r as suggestPrepareHook } from "./prepare-hook2.mjs";
|
|
7
|
+
import { E as resolveGitHubRepo, L as parseGitHubRepoSlug, U as isPrerelease, i as resolvePackageOrCrate, l as toStoragePackageName, m as searchNpmPackages, o as isCrateSpec, p as fetchPkgDist, t as semverDiff, z as parsePackageSpec } from "./semver.mjs";
|
|
6
8
|
import { i as parseFrontmatter } from "./markdown.mjs";
|
|
7
|
-
import { a as
|
|
8
|
-
import {
|
|
9
|
-
import { a as
|
|
10
|
-
import { c as wrapSection, n as SECTION_OUTPUT_FILES, r as buildAllSectionPrompts, s as portabilizePrompt, t as SECTION_MERGE_ORDER } from "./prompts.mjs";
|
|
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 "./skill.mjs";
|
|
12
|
-
import { a as readConfig, o as registerProject, r as hasCompletedWizard, t as defaultFeatures } from "./config.mjs";
|
|
13
|
-
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 readLock, c as writeLock, n as parsePackageNames, o as removeLockEntry, r as parsePackages } from "./lockfile.mjs";
|
|
15
|
-
import { t as getProjectState } from "./skills.mjs";
|
|
16
|
-
import { n as resolveSkillName, r as toStoragePackageName, t as parseSkillInput } from "./prefix.mjs";
|
|
17
|
-
import { t as runWizard } from "./wizard.mjs";
|
|
18
|
-
import { S as writePromptFiles, _ as linkAllReferences, b as selectLlmConfig, c as ejectReferences, d as ensureGitignore, f as fetchAndCacheResources, g as indexResources, h as handleShippedSkills, l as enhanceSkillWithLLM, m as forceClearCache, n as RESOLVE_STEP_LABELS, o as detectChangelog, p as findRelatedSkills, t as DEFAULT_SECTIONS, u as ensureAgentInstructions, v as resolveBaseDir, y as resolveLocalDep } from "./sync-shared2.mjs";
|
|
9
|
+
import { a as parsePackageNames, c as readLock, n as findSkillDirByPackage } from "./lockfile.mjs";
|
|
10
|
+
import { a as ensureProjectFiles, c as linkShippedToAgents, l as resolveBaseDir, o as handleShippedSkills, s as installSkill } from "./skill-installer2.mjs";
|
|
11
|
+
import { a as prepareSkillReferences, c as selectLlmConfig, d as runSkillEnhancement, f as writeBaseSkill, i as findRelatedSkills, l as applyCachedSections, o as DEFAULT_SECTIONS, p as writePromptFiles, r as fetchAndCacheResources, s as resolveAutoModel, t as buildSkillContext } from "./pipeline.mjs";
|
|
19
12
|
import { n as shutdownWorker } from "./pool2.mjs";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import pLimit from "p-limit";
|
|
23
|
-
import { isCI } from "std-env";
|
|
13
|
+
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
14
|
+
import { styleText } from "node:util";
|
|
24
15
|
import * as p from "@clack/prompts";
|
|
25
|
-
import
|
|
16
|
+
import pLimit from "p-limit";
|
|
17
|
+
import { join, relative, resolve } from "pathe";
|
|
26
18
|
import logUpdate from "log-update";
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const { source, agent, global: isGlobal, yes } = opts;
|
|
44
|
-
const cwd = process.cwd();
|
|
45
|
-
const agentConfig = targets[agent];
|
|
46
|
-
const baseDir = isGlobal ? join(CACHE_DIR, "skills") : join(cwd, agentConfig.skillsDir);
|
|
47
|
-
const label = source.type === "local" ? source.localPath : `${source.owner}/${source.repo}`;
|
|
48
|
-
const spin = timedSpinner();
|
|
49
|
-
spin.start(`Fetching skills from ${label}`);
|
|
50
|
-
const { skills } = await fetchGitSkills(source, (msg) => spin.message(msg));
|
|
51
|
-
if (skills.length === 0) {
|
|
52
|
-
if (source.type === "github" && source.owner && source.repo) {
|
|
53
|
-
spin.stop(`No pre-authored skills in ${label}, generating from repo docs...`);
|
|
54
|
-
return syncGitHubRepo(opts);
|
|
19
|
+
import { createHooks } from "hookable";
|
|
20
|
+
const npmResolver = async (spec, opts) => {
|
|
21
|
+
const resolution = await resolvePackageOrCrate(spec, {
|
|
22
|
+
cwd: opts.cwd,
|
|
23
|
+
onProgress: (msg) => opts.onProgress(`${spec}: ${msg}`)
|
|
24
|
+
});
|
|
25
|
+
const { isCrate, packageName, identityPackageName, storagePackageName, requestedTag, localVersion, attempts, registryVersion } = resolution;
|
|
26
|
+
if (!resolution.resolved) {
|
|
27
|
+
const result = {
|
|
28
|
+
identityName: identityPackageName,
|
|
29
|
+
attempts,
|
|
30
|
+
registryVersion
|
|
31
|
+
};
|
|
32
|
+
if (!isCrate) {
|
|
33
|
+
const shipped = handleShippedSkills(packageName, localVersion || registryVersion || "latest", opts.cwd, opts.agent, opts.global);
|
|
34
|
+
if (shipped) result.shipped = shipped.shipped;
|
|
55
35
|
}
|
|
56
|
-
|
|
57
|
-
return;
|
|
36
|
+
return result;
|
|
58
37
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
38
|
+
const resolved = resolution.resolved;
|
|
39
|
+
return {
|
|
40
|
+
identityName: identityPackageName,
|
|
41
|
+
storageName: storagePackageName,
|
|
42
|
+
version: isCrate ? resolved.version || requestedTag || "latest" : localVersion || resolved.version || "latest",
|
|
43
|
+
resolved,
|
|
44
|
+
kind: isCrate ? "crate" : "npm",
|
|
45
|
+
requestedTag,
|
|
46
|
+
localVersion
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
function createGithubResolver(owner, repo) {
|
|
50
|
+
return async (_spec, opts) => {
|
|
51
|
+
const resolved = await resolveGitHubRepo(owner, repo, (msg) => opts.onProgress(msg));
|
|
52
|
+
if (!resolved) return {
|
|
53
|
+
identityName: `${owner}-${repo}`,
|
|
54
|
+
attempts: [{
|
|
55
|
+
source: "github-meta",
|
|
56
|
+
status: "not-found",
|
|
57
|
+
message: `Could not find docs for ${owner}/${repo}`
|
|
58
|
+
}]
|
|
59
|
+
};
|
|
60
|
+
const repoUrl = `https://github.com/${owner}/${repo}`;
|
|
61
|
+
const name = `${owner}-${repo}`;
|
|
62
|
+
return {
|
|
63
|
+
identityName: name,
|
|
64
|
+
storageName: name,
|
|
65
|
+
version: resolved.version || "main",
|
|
66
|
+
resolved: {
|
|
67
|
+
...resolved,
|
|
68
|
+
repoUrl
|
|
69
|
+
},
|
|
70
|
+
kind: "github"
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const RATE_LIMIT_RE = /\b429\b|rate.?limit|exhausted.*capacity|quota.*reset/i;
|
|
75
|
+
async function runBaseSync(spec, config, hooks, resolver, cwd, defaultSections) {
|
|
76
|
+
await hooks.callHook("resolve:start", { spec });
|
|
77
|
+
const resolverResult = await resolver(spec, {
|
|
78
|
+
cwd,
|
|
79
|
+
agent: config.agent,
|
|
80
|
+
global: config.global,
|
|
81
|
+
onProgress: (msg) => hooks.callHook("resolve:progress", {
|
|
82
|
+
spec,
|
|
83
|
+
message: msg
|
|
84
|
+
})
|
|
85
|
+
});
|
|
86
|
+
if (!("resolved" in resolverResult)) {
|
|
87
|
+
if (resolverResult.shipped && resolverResult.shipped.length > 0) {
|
|
88
|
+
for (const s of resolverResult.shipped) await hooks.callHook("shipped:installed", {
|
|
89
|
+
spec,
|
|
90
|
+
skillName: s.skillName,
|
|
91
|
+
skillDir: s.skillDir
|
|
92
|
+
});
|
|
93
|
+
return { kind: "shipped" };
|
|
68
94
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
options: skills.map((s) => ({
|
|
74
|
-
label: s.name.replace(/-skilld$/, ""),
|
|
75
|
-
value: s.name,
|
|
76
|
-
hint: s.description || s.path
|
|
77
|
-
})),
|
|
78
|
-
initialValues: []
|
|
95
|
+
await hooks.callHook("resolve:failed", {
|
|
96
|
+
spec,
|
|
97
|
+
identityName: resolverResult.identityName,
|
|
98
|
+
attempts: resolverResult.attempts
|
|
79
99
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
100
|
+
return {
|
|
101
|
+
kind: "unresolved",
|
|
102
|
+
unresolved: resolverResult
|
|
103
|
+
};
|
|
84
104
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
105
|
+
const { identityName, storageName, version, resolved, kind, requestedTag, localVersion } = resolverResult;
|
|
106
|
+
const cache = createReferenceCache(storageName, version);
|
|
107
|
+
if (config.force) cache.clearForce();
|
|
108
|
+
const useCache = cache.has();
|
|
109
|
+
if (kind !== "crate" && !existsSync(join(cwd, "node_modules", identityName))) {
|
|
110
|
+
await hooks.callHook("dist:downloading", { spec });
|
|
111
|
+
await fetchPkgDist(identityName, version);
|
|
112
|
+
}
|
|
113
|
+
if (kind !== "crate") {
|
|
114
|
+
const shipped = handleShippedSkills(identityName, version, cwd, config.agent, config.global);
|
|
115
|
+
if (shipped) {
|
|
116
|
+
linkShippedToAgents(shipped.shipped, cwd, config.agent, config.global);
|
|
117
|
+
for (const s of shipped.shipped) await hooks.callHook("shipped:installed", {
|
|
118
|
+
spec,
|
|
119
|
+
skillName: s.skillName,
|
|
120
|
+
skillDir: s.skillDir
|
|
121
|
+
});
|
|
122
|
+
return { kind: "shipped" };
|
|
94
123
|
}
|
|
95
|
-
const sourceType = source.type === "local" ? "local" : source.type;
|
|
96
|
-
writeLock(baseDir, skill.name, {
|
|
97
|
-
source: sourceType,
|
|
98
|
-
repo: source.type === "local" ? source.localPath : `${source.owner}/${source.repo}`,
|
|
99
|
-
path: skill.path || void 0,
|
|
100
|
-
ref: source.ref || "main",
|
|
101
|
-
syncedAt: todayIsoDate(),
|
|
102
|
-
generator: "external"
|
|
103
|
-
});
|
|
104
124
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
agents: agent,
|
|
111
|
-
...isGlobal && { global: "1" },
|
|
112
|
-
sourceType: source.type
|
|
125
|
+
await hooks.callHook("resolve:done", {
|
|
126
|
+
spec,
|
|
127
|
+
version,
|
|
128
|
+
cached: useCache,
|
|
129
|
+
force: config.force
|
|
113
130
|
});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const repo = source.repo;
|
|
121
|
-
const cwd = process.cwd();
|
|
122
|
-
const spin = timedSpinner();
|
|
123
|
-
spin.start(`Resolving ${owner}/${repo}`);
|
|
124
|
-
const resolved = await resolveGitHubRepo(owner, repo, (msg) => spin.message(msg));
|
|
125
|
-
if (!resolved) {
|
|
126
|
-
spin.stop(`Could not find docs for ${owner}/${repo}`);
|
|
127
|
-
return;
|
|
131
|
+
if (kind === "npm" && !localVersion && !requestedTag && !isPrerelease(version)) {
|
|
132
|
+
const nextTag = resolved.distTags?.next ?? resolved.distTags?.beta ?? resolved.distTags?.alpha;
|
|
133
|
+
if (nextTag && (!resolved.releasedAt || !nextTag.releasedAt || nextTag.releasedAt > resolved.releasedAt)) await hooks.callHook("warn", {
|
|
134
|
+
spec,
|
|
135
|
+
message: `No local dependency found — using latest stable (${version}). Prerelease ${nextTag.version} available: skilld add ${identityName}@beta`
|
|
136
|
+
});
|
|
128
137
|
}
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const skillDir = join(baseDir, skillDirName);
|
|
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);
|
|
139
148
|
mkdirSync(skillDir, { recursive: true });
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
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
|
+
await hooks.callHook("fetch:start", { spec });
|
|
143
175
|
const resources = await fetchAndCacheResources({
|
|
144
|
-
packageName,
|
|
176
|
+
packageName: storageName,
|
|
145
177
|
resolved,
|
|
146
178
|
version,
|
|
147
179
|
useCache,
|
|
148
180
|
features,
|
|
149
|
-
from:
|
|
150
|
-
onProgress: (msg) =>
|
|
181
|
+
from: config.from,
|
|
182
|
+
onProgress: (msg) => hooks.callHook("fetch:progress", {
|
|
183
|
+
spec,
|
|
184
|
+
message: msg
|
|
185
|
+
})
|
|
151
186
|
});
|
|
152
|
-
const
|
|
187
|
+
const parts = [];
|
|
153
188
|
if (resources.docsToIndex.length > 0) {
|
|
154
189
|
const docCount = resources.docsToIndex.filter((d) => d.metadata?.type === "doc").length;
|
|
155
|
-
if (docCount > 0)
|
|
156
|
-
}
|
|
157
|
-
if (resources.hasIssues)
|
|
158
|
-
if (resources.hasDiscussions)
|
|
159
|
-
if (resources.hasReleases)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
190
|
+
if (docCount > 0) parts.push(`${docCount} docs`);
|
|
191
|
+
}
|
|
192
|
+
if (resources.hasIssues) parts.push("issues");
|
|
193
|
+
if (resources.hasDiscussions) parts.push("discussions");
|
|
194
|
+
if (resources.hasReleases) parts.push("releases");
|
|
195
|
+
await hooks.callHook("fetch:done", {
|
|
196
|
+
spec,
|
|
197
|
+
parts,
|
|
198
|
+
cached: resources.usedCache
|
|
199
|
+
});
|
|
200
|
+
for (const w of resources.warnings) await hooks.callHook("warn", {
|
|
201
|
+
spec,
|
|
202
|
+
message: w
|
|
203
|
+
});
|
|
204
|
+
if (features.search) await hooks.callHook("index:start", { spec });
|
|
205
|
+
const prepared = await prepareSkillReferences({
|
|
206
|
+
packageName: storageName,
|
|
207
|
+
version,
|
|
208
|
+
cwd,
|
|
209
|
+
skillDir,
|
|
210
|
+
resources,
|
|
211
|
+
features,
|
|
212
|
+
baseDir,
|
|
213
|
+
onIndexProgress: (msg) => hooks.callHook("index:progress", {
|
|
214
|
+
spec,
|
|
215
|
+
message: msg
|
|
216
|
+
})
|
|
217
|
+
});
|
|
218
|
+
if (features.search) await hooks.callHook("index:done", { spec });
|
|
219
|
+
if (!isEject) {
|
|
220
|
+
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
221
|
+
cache.linkPkgNamed(skillDir, cwd);
|
|
222
|
+
const lock = {
|
|
223
|
+
packageName: identityName,
|
|
168
224
|
version,
|
|
225
|
+
repo: repoSlug,
|
|
226
|
+
source: resources.docSource,
|
|
227
|
+
syncedAt: todayIsoDate(),
|
|
228
|
+
generator: "skilld"
|
|
229
|
+
};
|
|
230
|
+
installSkill({
|
|
169
231
|
cwd,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
232
|
+
agent: config.agent,
|
|
233
|
+
global: config.global,
|
|
234
|
+
baseDir,
|
|
235
|
+
skillDirName,
|
|
236
|
+
lock,
|
|
237
|
+
dedupePackageName: identityName,
|
|
238
|
+
skipLinkAgents: true
|
|
173
239
|
});
|
|
174
|
-
idxSpin.stop("Search index ready");
|
|
175
240
|
}
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
packageName,
|
|
241
|
+
const allPackages = parsePackageNames((isEject ? void 0 : readLock(baseDir)?.skills[skillDirName])?.packages);
|
|
242
|
+
const ctx = buildSkillContext({
|
|
243
|
+
packageName: identityName,
|
|
244
|
+
cachePackageName: storageName,
|
|
181
245
|
version,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
name: packageName,
|
|
189
|
-
version,
|
|
190
|
-
releasedAt: resolved.releasedAt,
|
|
191
|
-
description: resolved.description,
|
|
192
|
-
relatedSkills: [],
|
|
193
|
-
hasIssues: resources.hasIssues,
|
|
194
|
-
hasDiscussions: resources.hasDiscussions,
|
|
195
|
-
hasReleases: resources.hasReleases,
|
|
196
|
-
hasChangelog,
|
|
197
|
-
docsType: resources.docsType,
|
|
198
|
-
hasShippedDocs: shippedDocs,
|
|
199
|
-
pkgFiles,
|
|
200
|
-
dirName: skillDirName,
|
|
201
|
-
repoUrl,
|
|
246
|
+
skillDir,
|
|
247
|
+
skillDirName,
|
|
248
|
+
resources,
|
|
249
|
+
prepared,
|
|
250
|
+
resolved,
|
|
251
|
+
packages: allPackages,
|
|
202
252
|
features
|
|
203
253
|
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
254
|
+
ctx.overheadLines = writeBaseSkill(ctx, { eject: isEject }).split("\n").length;
|
|
255
|
+
await hooks.callHook("base:done", {
|
|
256
|
+
spec,
|
|
257
|
+
skillDir: relative(cwd, skillDir),
|
|
258
|
+
mode: config.mode === "update" ? "update" : "add"
|
|
259
|
+
});
|
|
260
|
+
const allSectionsCached = !config.force && applyCachedSections(ctx, defaultSections, { eject: isEject });
|
|
261
|
+
if (allSectionsCached) await hooks.callHook("sections:cached", { spec });
|
|
262
|
+
return {
|
|
263
|
+
kind: "ready",
|
|
264
|
+
state: {
|
|
265
|
+
ctx,
|
|
209
266
|
skillDir,
|
|
267
|
+
skillDirName,
|
|
268
|
+
baseDir,
|
|
269
|
+
updateCtx,
|
|
270
|
+
allSectionsCached,
|
|
271
|
+
identityName,
|
|
272
|
+
storageName,
|
|
210
273
|
version,
|
|
211
|
-
hasIssues: resources.hasIssues,
|
|
212
|
-
hasDiscussions: resources.hasDiscussions,
|
|
213
|
-
hasReleases: resources.hasReleases,
|
|
214
|
-
hasChangelog,
|
|
215
274
|
docsType: resources.docsType,
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
275
|
+
repoInfo: resources.repoInfo
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
async function runEnhancePhase(state, llmConfig, config, hooks, cwd) {
|
|
280
|
+
const isEject = !!config.eject;
|
|
281
|
+
const spec = state.identityName;
|
|
282
|
+
if (llmConfig?.promptOnly) writePromptFiles({
|
|
283
|
+
...state.ctx,
|
|
284
|
+
packageName: state.ctx.cachePackageName ?? state.ctx.packageName,
|
|
285
|
+
cachePackageName: void 0
|
|
286
|
+
}, {
|
|
287
|
+
sections: llmConfig.sections,
|
|
288
|
+
customPrompt: llmConfig.customPrompt
|
|
289
|
+
});
|
|
290
|
+
else if (llmConfig) await enhanceWithHooks(state.ctx, llmConfig, {
|
|
291
|
+
...config,
|
|
292
|
+
eject: isEject
|
|
293
|
+
}, hooks, spec);
|
|
294
|
+
if (isEject) {
|
|
295
|
+
const cache = createReferenceCache(state.storageName, state.version);
|
|
296
|
+
if (!config.debug) cache.clearSkillInternal(state.skillDir);
|
|
297
|
+
cache.eject(state.skillDir, cwd, state.docsType, {
|
|
298
|
+
features: state.ctx.features ?? getActiveFeatures(),
|
|
299
|
+
repoInfo: state.repoInfo
|
|
221
300
|
});
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const shared = config.global ? false : getSharedSkillsDir(cwd) ?? false;
|
|
304
|
+
if (shared) linkSkillToAgents(state.skillDirName, shared, cwd, config.agent);
|
|
305
|
+
await ensureProjectFiles({
|
|
306
|
+
cwd,
|
|
307
|
+
agent: config.agent,
|
|
308
|
+
global: config.global,
|
|
309
|
+
shared
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
async function enhanceWithHooks(ctx, llmConfig, config, hooks, spec) {
|
|
313
|
+
await hooks.callHook("enhance:start", {
|
|
314
|
+
spec,
|
|
315
|
+
modelLabel: getModelLabel(llmConfig.model)
|
|
316
|
+
});
|
|
317
|
+
const result = await runSkillEnhancement(ctx, {
|
|
318
|
+
model: llmConfig.model,
|
|
319
|
+
force: config.force,
|
|
320
|
+
debug: config.debug,
|
|
321
|
+
sections: llmConfig.sections,
|
|
322
|
+
customPrompt: llmConfig.customPrompt,
|
|
323
|
+
eject: !!config.eject
|
|
324
|
+
}, (progress) => hooks.callHook("enhance:progress", {
|
|
325
|
+
spec,
|
|
326
|
+
progress
|
|
327
|
+
}));
|
|
328
|
+
if (result.wasOptimized) await hooks.callHook("enhance:done", {
|
|
329
|
+
spec,
|
|
330
|
+
usage: result.usage ? { totalTokens: result.usage.totalTokens } : void 0,
|
|
331
|
+
cost: result.cost,
|
|
332
|
+
debugLogsDir: result.debugLogsDir,
|
|
333
|
+
error: result.error,
|
|
334
|
+
warnings: result.warnings
|
|
335
|
+
});
|
|
336
|
+
else await hooks.callHook("enhance:failed", {
|
|
337
|
+
spec,
|
|
338
|
+
error: result.error ?? "",
|
|
339
|
+
rateLimited: !!result.error && RATE_LIMIT_RE.test(result.error)
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
function createSyncRun(opts) {
|
|
343
|
+
const hooks = createHooks();
|
|
344
|
+
async function runBase(spec) {
|
|
345
|
+
const result = await runBaseSync(spec, {
|
|
346
|
+
agent: opts.agent,
|
|
347
|
+
global: opts.global,
|
|
348
|
+
mode: opts.mode,
|
|
349
|
+
force: opts.force,
|
|
350
|
+
noSearch: opts.noSearch,
|
|
351
|
+
name: opts.name,
|
|
352
|
+
from: opts.from,
|
|
353
|
+
eject: opts.eject
|
|
354
|
+
}, hooks, opts.resolver, opts.cwd, opts.defaultSections);
|
|
355
|
+
if (result.kind === "shipped") return {
|
|
356
|
+
kind: "shipped",
|
|
357
|
+
spec
|
|
358
|
+
};
|
|
359
|
+
if (result.kind === "unresolved") return {
|
|
360
|
+
kind: "unresolved",
|
|
361
|
+
spec,
|
|
362
|
+
identityName: result.unresolved.identityName,
|
|
363
|
+
attempts: result.unresolved.attempts
|
|
364
|
+
};
|
|
365
|
+
if (result.kind === "merge-needed") {
|
|
366
|
+
if (opts.onMergeNeeded) {
|
|
367
|
+
await opts.onMergeNeeded(result.state);
|
|
368
|
+
return {
|
|
369
|
+
kind: "merged",
|
|
370
|
+
spec
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
kind: "error",
|
|
375
|
+
spec,
|
|
376
|
+
reason: `Skill dir already holds ${result.state.existingLock.packageName} — run sequentially to merge`
|
|
377
|
+
};
|
|
245
378
|
}
|
|
379
|
+
return {
|
|
380
|
+
kind: "ready",
|
|
381
|
+
spec,
|
|
382
|
+
state: result.state
|
|
383
|
+
};
|
|
246
384
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
385
|
+
async function runEnhance(state, llmConfig) {
|
|
386
|
+
await runEnhancePhase(state, llmConfig, {
|
|
387
|
+
agent: opts.agent,
|
|
388
|
+
global: opts.global,
|
|
389
|
+
force: opts.force,
|
|
390
|
+
debug: opts.debug,
|
|
391
|
+
eject: opts.eject
|
|
392
|
+
}, hooks, opts.cwd);
|
|
393
|
+
}
|
|
394
|
+
async function run(spec) {
|
|
395
|
+
const base = await runBase(spec);
|
|
396
|
+
if (base.kind !== "ready") return base;
|
|
397
|
+
let llmConfig = null;
|
|
398
|
+
if (!base.state.allSectionsCached && opts.resolveLlmConfig) llmConfig = await opts.resolveLlmConfig({ ready: [{
|
|
399
|
+
spec,
|
|
400
|
+
state: base.state
|
|
401
|
+
}] }) ?? null;
|
|
402
|
+
await runEnhance(base.state, llmConfig);
|
|
403
|
+
return {
|
|
404
|
+
kind: "enhanced",
|
|
405
|
+
spec,
|
|
406
|
+
state: base.state
|
|
407
|
+
};
|
|
253
408
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
409
|
+
async function runMany(specs, runOpts) {
|
|
410
|
+
const limit = pLimit(runOpts?.concurrency ?? 5);
|
|
411
|
+
return (await Promise.allSettled(specs.map((spec) => limit(() => runBase(spec))))).map((r, i) => r.status === "fulfilled" ? r.value : {
|
|
412
|
+
kind: "error",
|
|
413
|
+
spec: specs[i],
|
|
414
|
+
reason: r.reason instanceof Error ? r.reason.message : String(r.reason)
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
return {
|
|
418
|
+
hooks,
|
|
419
|
+
runBase,
|
|
420
|
+
runEnhance,
|
|
421
|
+
run,
|
|
422
|
+
runMany
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
function bindClackUi(hooks, { cwd }) {
|
|
426
|
+
let spinner = null;
|
|
427
|
+
let resourceSpinner = null;
|
|
428
|
+
let indexSpinner = null;
|
|
429
|
+
let llmLog = null;
|
|
430
|
+
let currentSpec = "";
|
|
431
|
+
hooks.hook("resolve:start", ({ spec }) => {
|
|
432
|
+
currentSpec = spec;
|
|
433
|
+
spinner = timedSpinner();
|
|
434
|
+
spinner.start(`Resolving ${spec}`);
|
|
435
|
+
});
|
|
436
|
+
hooks.hook("resolve:progress", ({ message }) => {
|
|
437
|
+
spinner?.message(message);
|
|
438
|
+
});
|
|
439
|
+
hooks.hook("resolve:done", ({ version, cached, force }) => {
|
|
440
|
+
const suffix = force ? " (force)" : cached ? " (cached)" : "";
|
|
441
|
+
spinner?.stop(`Resolved ${currentSpec}@${version}${suffix}`);
|
|
442
|
+
spinner = null;
|
|
443
|
+
});
|
|
444
|
+
hooks.hook("resolve:failed", ({ identityName }) => {
|
|
445
|
+
spinner?.stop(`Could not find docs for: ${identityName}`);
|
|
446
|
+
spinner = null;
|
|
447
|
+
});
|
|
448
|
+
hooks.hook("dist:downloading", () => {
|
|
449
|
+
spinner?.message("Downloading dist");
|
|
450
|
+
});
|
|
451
|
+
hooks.hook("fetch:start", () => {
|
|
452
|
+
resourceSpinner = timedSpinner();
|
|
453
|
+
resourceSpinner.start("Finding resources");
|
|
454
|
+
});
|
|
455
|
+
hooks.hook("fetch:progress", ({ message }) => {
|
|
456
|
+
resourceSpinner?.message(message);
|
|
457
|
+
});
|
|
458
|
+
hooks.hook("fetch:done", ({ parts, cached }) => {
|
|
459
|
+
const summary = parts.length > 0 ? parts.join(", ") : "resources";
|
|
460
|
+
resourceSpinner?.stop(cached ? `Loaded ${summary} (cached)` : `Fetched ${summary}`);
|
|
461
|
+
resourceSpinner = null;
|
|
462
|
+
});
|
|
463
|
+
hooks.hook("index:start", () => {
|
|
464
|
+
indexSpinner = timedSpinner();
|
|
465
|
+
indexSpinner.start("Creating search index");
|
|
466
|
+
});
|
|
467
|
+
hooks.hook("index:progress", ({ message }) => {
|
|
468
|
+
indexSpinner?.message(message);
|
|
469
|
+
});
|
|
470
|
+
hooks.hook("index:done", () => {
|
|
471
|
+
indexSpinner?.stop("Search index ready");
|
|
472
|
+
indexSpinner = null;
|
|
473
|
+
});
|
|
474
|
+
hooks.hook("warn", ({ message }) => {
|
|
475
|
+
p.log.warn(styleText("yellow", message));
|
|
476
|
+
});
|
|
477
|
+
hooks.hook("base:done", ({ skillDir, mode }) => {
|
|
478
|
+
p.log.success(mode === "update" ? `Updated skill: ${skillDir}` : `Created base skill: ${skillDir}`);
|
|
479
|
+
});
|
|
480
|
+
hooks.hook("sections:cached", () => {
|
|
481
|
+
p.log.success("Applied cached SKILL.md sections");
|
|
482
|
+
});
|
|
483
|
+
hooks.hook("enhance:start", ({ spec, modelLabel }) => {
|
|
484
|
+
currentSpec = spec;
|
|
485
|
+
p.log.step(modelLabel);
|
|
486
|
+
llmLog = p.taskLog({
|
|
487
|
+
title: `Agent exploring ${spec}`,
|
|
488
|
+
limit: 3
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
hooks.hook("enhance:progress", ({ progress }) => {
|
|
492
|
+
if (!llmLog) return;
|
|
493
|
+
const line = `${progress.section ? `[${progress.section}] ` : ""}${progress.chunk}`;
|
|
494
|
+
llmLog.message(line);
|
|
495
|
+
});
|
|
496
|
+
hooks.hook("enhance:done", (info) => {
|
|
497
|
+
if (!llmLog) return;
|
|
498
|
+
const parts = [];
|
|
499
|
+
if (info.usage) parts.push(`${Math.round(info.usage.totalTokens / 1e3)}k tokens`);
|
|
500
|
+
if (info.cost) parts.push(`$${info.cost.toFixed(2)}`);
|
|
501
|
+
const suffix = parts.length > 0 ? ` (${parts.join(", ")})` : "";
|
|
502
|
+
llmLog.success(`Generated best practices${suffix}`);
|
|
503
|
+
llmLog = null;
|
|
504
|
+
if (info.debugLogsDir) p.log.info(`Debug logs: ${relative(cwd, info.debugLogsDir)}`);
|
|
505
|
+
if (info.error) p.log.warn(styleText("yellow", `Partial failure: ${info.error}`));
|
|
506
|
+
if (info.warnings) for (const w of info.warnings) p.log.warn(styleText("yellow", w));
|
|
507
|
+
});
|
|
508
|
+
hooks.hook("enhance:failed", ({ error, rateLimited }) => {
|
|
509
|
+
if (!llmLog) return;
|
|
510
|
+
if (rateLimited) llmLog.error(`Rate limited by LLM provider. Try again shortly or use a different model via \`skilld config\``);
|
|
511
|
+
else llmLog.error(`Enhancement failed${error ? `: ${error}` : ""}`);
|
|
512
|
+
llmLog = null;
|
|
513
|
+
});
|
|
514
|
+
hooks.hook("shipped:installed", ({ skillName, skillDir }) => {
|
|
515
|
+
p.log.success(`Using published SKILL.md: ${skillName} → ${relative(cwd, skillDir)}`);
|
|
262
516
|
});
|
|
263
|
-
p.outro(`Synced ${owner}/${repo} to ${relative(cwd, skillDir)}`);
|
|
264
517
|
}
|
|
265
518
|
const STATUS_ICONS = {
|
|
266
519
|
pending: "○",
|
|
@@ -274,419 +527,290 @@ const STATUS_ICONS = {
|
|
|
274
527
|
error: "✗"
|
|
275
528
|
};
|
|
276
529
|
const STATUS_COLORS = {
|
|
277
|
-
pending: "
|
|
278
|
-
resolving: "
|
|
279
|
-
downloading: "
|
|
280
|
-
embedding: "
|
|
281
|
-
exploring: "
|
|
282
|
-
thinking: "
|
|
283
|
-
generating: "
|
|
284
|
-
done: "
|
|
285
|
-
error: "
|
|
530
|
+
pending: "gray",
|
|
531
|
+
resolving: "cyan",
|
|
532
|
+
downloading: "cyan",
|
|
533
|
+
embedding: "cyan",
|
|
534
|
+
exploring: "blue",
|
|
535
|
+
thinking: "magenta",
|
|
536
|
+
generating: "yellow",
|
|
537
|
+
done: "green",
|
|
538
|
+
error: "red"
|
|
286
539
|
};
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
message
|
|
540
|
+
function renderParallel(r) {
|
|
541
|
+
const maxNameLen = Math.max(...[...r.states.keys()].map((n) => n.length), 20);
|
|
542
|
+
const lines = [...r.states.values()].map((s) => {
|
|
543
|
+
const icon = styleText(STATUS_COLORS[s.status], STATUS_ICONS[s.status]);
|
|
544
|
+
const name = s.name.padEnd(maxNameLen);
|
|
545
|
+
const version = s.version ? `${styleText("gray", s.version)} ` : "";
|
|
546
|
+
const elapsed = (s.status === "done" || s.status === "error") && s.startedAt && s.completedAt ? ` ${styleText("gray", `(${formatDuration(s.completedAt - s.startedAt)})`)}` : "";
|
|
547
|
+
const preview = s.streamPreview ? ` ${styleText("gray", s.streamPreview)}` : "";
|
|
548
|
+
return ` ${icon} ${name} ${version}${s.message}${elapsed}${preview}`;
|
|
296
549
|
});
|
|
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);
|
|
550
|
+
const doneCount = [...r.states.values()].filter((s) => s.status === "done").length;
|
|
551
|
+
const errorCount = [...r.states.values()].filter((s) => s.status === "error").length;
|
|
552
|
+
logUpdate(`${styleText("bold", `${r.verb} ${r.total} packages`)} (${doneCount} done${errorCount > 0 ? `, ${errorCount} failed` : ""})\n` + lines.join("\n"));
|
|
553
|
+
}
|
|
554
|
+
function bindParallelUi(hooks, render) {
|
|
555
|
+
function update(spec, status, message, ver) {
|
|
556
|
+
const state = render.states.get(spec);
|
|
557
|
+
if (!state) return;
|
|
316
558
|
if (!state.startedAt && status !== "pending") state.startedAt = performance.now();
|
|
317
559
|
if ((status === "done" || status === "error") && !state.completedAt) state.completedAt = performance.now();
|
|
318
560
|
state.status = status;
|
|
319
561
|
state.message = message;
|
|
320
562
|
state.streamPreview = void 0;
|
|
321
|
-
if (
|
|
322
|
-
render
|
|
563
|
+
if (ver) state.version = ver;
|
|
564
|
+
renderParallel(render);
|
|
323
565
|
}
|
|
566
|
+
hooks.hook("resolve:start", ({ spec }) => update(spec, "resolving", "Resolving..."));
|
|
567
|
+
hooks.hook("resolve:progress", ({ spec, message }) => update(spec, "resolving", message));
|
|
568
|
+
hooks.hook("resolve:done", ({ spec, version, cached, force }) => {
|
|
569
|
+
update(spec, "downloading", cached ? "Using cache" : force ? "Re-fetching docs..." : "Fetching docs...", version);
|
|
570
|
+
});
|
|
571
|
+
hooks.hook("resolve:failed", () => {});
|
|
572
|
+
hooks.hook("dist:downloading", ({ spec }) => update(spec, "downloading", "Downloading dist..."));
|
|
573
|
+
hooks.hook("fetch:start", () => {});
|
|
574
|
+
hooks.hook("fetch:progress", ({ spec, message }) => update(spec, "downloading", message));
|
|
575
|
+
hooks.hook("fetch:done", ({ spec }) => update(spec, "downloading", "Linking references..."));
|
|
576
|
+
hooks.hook("index:start", ({ spec }) => update(spec, "embedding", "Indexing docs"));
|
|
577
|
+
hooks.hook("index:progress", ({ spec, message }) => update(spec, "embedding", message));
|
|
578
|
+
hooks.hook("index:done", () => {});
|
|
579
|
+
hooks.hook("warn", () => {});
|
|
580
|
+
hooks.hook("base:done", ({ spec, mode }) => {
|
|
581
|
+
update(spec, "done", mode === "update" ? "Skill updated" : "Base skill created");
|
|
582
|
+
});
|
|
583
|
+
hooks.hook("sections:cached", () => {});
|
|
584
|
+
hooks.hook("enhance:start", ({ spec, modelLabel }) => update(spec, "generating", modelLabel));
|
|
585
|
+
hooks.hook("enhance:progress", ({ spec, progress }) => {
|
|
586
|
+
update(spec, progress.type === "reasoning" ? "exploring" : "generating", `${progress.section ? `[${progress.section}] ` : ""}${progress.chunk}`);
|
|
587
|
+
});
|
|
588
|
+
hooks.hook("enhance:done", ({ spec }) => update(spec, "done", "Skill optimized"));
|
|
589
|
+
hooks.hook("enhance:failed", ({ spec, error }) => update(spec, "error", error));
|
|
590
|
+
hooks.hook("shipped:installed", ({ spec }) => update(spec, "done", "Published SKILL.md"));
|
|
591
|
+
}
|
|
592
|
+
const DIFF_RANK = {
|
|
593
|
+
major: 5,
|
|
594
|
+
premajor: 4,
|
|
595
|
+
minor: 3,
|
|
596
|
+
preminor: 2,
|
|
597
|
+
patch: 1,
|
|
598
|
+
prepatch: 1,
|
|
599
|
+
prerelease: 0
|
|
600
|
+
};
|
|
601
|
+
async function syncPackagesParallel(config) {
|
|
602
|
+
const { packages, concurrency = 5 } = config;
|
|
603
|
+
const cwd = process.cwd();
|
|
604
|
+
const states = /* @__PURE__ */ new Map();
|
|
605
|
+
const specToName = /* @__PURE__ */ new Map();
|
|
606
|
+
for (const spec of packages) {
|
|
607
|
+
const { name } = parsePackageSpec(spec);
|
|
608
|
+
specToName.set(spec, name);
|
|
609
|
+
states.set(spec, {
|
|
610
|
+
name,
|
|
611
|
+
status: "pending",
|
|
612
|
+
message: "Waiting..."
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
const render = {
|
|
616
|
+
states,
|
|
617
|
+
verb: config.mode === "update" ? "Updating" : "Syncing",
|
|
618
|
+
total: packages.length
|
|
619
|
+
};
|
|
324
620
|
ensureCacheDir();
|
|
325
|
-
render
|
|
621
|
+
renderParallel(render);
|
|
622
|
+
const run = createSyncRun({
|
|
623
|
+
cwd,
|
|
624
|
+
resolver: npmResolver,
|
|
625
|
+
agent: config.agent,
|
|
626
|
+
global: config.global,
|
|
627
|
+
mode: config.mode,
|
|
628
|
+
force: config.force,
|
|
629
|
+
debug: config.debug,
|
|
630
|
+
defaultSections: DEFAULT_SECTIONS
|
|
631
|
+
});
|
|
632
|
+
bindParallelUi(run.hooks, render);
|
|
326
633
|
const limit = pLimit(concurrency);
|
|
327
|
-
const
|
|
328
|
-
const baseResults = await Promise.allSettled(packages.map((pkg) => limit(() => syncBaseSkill(pkg, config, cwd, update))));
|
|
634
|
+
const baseResults = await Promise.allSettled(packages.map((spec) => limit(() => run.runBase(spec))));
|
|
329
635
|
logUpdate.done();
|
|
330
|
-
const
|
|
331
|
-
const
|
|
636
|
+
const ready = [];
|
|
637
|
+
const shippedCount = [];
|
|
332
638
|
const errors = [];
|
|
639
|
+
const aggregatedWarnings = [];
|
|
333
640
|
for (let i = 0; i < baseResults.length; i++) {
|
|
641
|
+
const spec = packages[i];
|
|
334
642
|
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") {
|
|
643
|
+
if (r.status === "rejected") {
|
|
340
644
|
const err = r.reason;
|
|
341
|
-
const reason = err instanceof Error ?
|
|
645
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
646
|
+
const slot = states.get(spec);
|
|
647
|
+
if (slot) slot.status = "error";
|
|
342
648
|
errors.push({
|
|
343
|
-
|
|
649
|
+
spec,
|
|
344
650
|
reason
|
|
345
651
|
});
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
366
|
-
const content = readCachedSection(resolvedName, data.version, outputFile);
|
|
367
|
-
if (content) cachedParts.push(wrapSection(s, content));
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
const result = r.value;
|
|
655
|
+
if (result.kind === "shipped") {
|
|
656
|
+
shippedCount.push(spec);
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (result.kind === "unresolved") {
|
|
660
|
+
const npmAttempt = result.attempts.find((a) => a.source === "npm");
|
|
661
|
+
let reason;
|
|
662
|
+
if (npmAttempt?.status === "not-found") {
|
|
663
|
+
const suggestions = await searchNpmPackages(result.identityName, 3);
|
|
664
|
+
const hint = suggestions.length > 0 ? ` (try: ${suggestions.map((s) => s.name).join(", ")})` : "";
|
|
665
|
+
reason = (npmAttempt.message || "Not on npm") + hint;
|
|
666
|
+
} else reason = result.attempts.filter((a) => a.status !== "success").map((a) => a.message || a.source).join("; ") || "No docs found";
|
|
667
|
+
const slot = states.get(spec);
|
|
668
|
+
if (slot) {
|
|
669
|
+
slot.status = "error";
|
|
670
|
+
slot.message = reason;
|
|
368
671
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
|
672
|
+
errors.push({
|
|
673
|
+
spec,
|
|
674
|
+
reason
|
|
675
|
+
});
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (result.kind === "error") {
|
|
679
|
+
errors.push({
|
|
680
|
+
spec,
|
|
681
|
+
reason: result.reason
|
|
389
682
|
});
|
|
390
|
-
|
|
683
|
+
continue;
|
|
391
684
|
}
|
|
685
|
+
if (result.kind === "ready") ready.push({
|
|
686
|
+
spec,
|
|
687
|
+
state: result.state
|
|
688
|
+
});
|
|
392
689
|
}
|
|
393
|
-
|
|
690
|
+
renderParallel(render);
|
|
691
|
+
logUpdate.done();
|
|
692
|
+
const pastVerb = config.mode === "update" ? "Updated" : "Created";
|
|
693
|
+
p.log.success(`${pastVerb} ${ready.length} base skills${shippedCount.length > 0 ? ` (${shippedCount.length} shipped)` : ""}`);
|
|
694
|
+
for (const w of aggregatedWarnings) p.log.warn(styleText("yellow", w));
|
|
695
|
+
for (const { spec, reason } of errors) p.log.error(` ${spec}: ${reason}`);
|
|
696
|
+
const cachedPkgs = [];
|
|
697
|
+
const uncached = [];
|
|
698
|
+
for (const r of ready) if (r.state.allSectionsCached) cachedPkgs.push(r.spec);
|
|
699
|
+
else uncached.push(r);
|
|
394
700
|
if (cachedPkgs.length > 0) p.log.success(`Applied cached SKILL.md sections for ${cachedPkgs.join(", ")}`);
|
|
395
701
|
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;
|
|
702
|
+
const resolvedModel = await resolveAutoModel(config.model, config.yes);
|
|
703
|
+
if (uncached.length > 0 && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
|
|
704
|
+
const llmConfig = await selectLlmConfig(resolvedModel, void 0, config.mode === "update" ? aggregateUpdateCtx(uncached) : void 0);
|
|
705
|
+
if (llmConfig?.promptOnly) {
|
|
706
|
+
for (const r of uncached) {
|
|
707
|
+
const slot = states.get(r.spec);
|
|
708
|
+
if (slot) {
|
|
709
|
+
slot.status = "done";
|
|
710
|
+
slot.message = "Prompts written";
|
|
425
711
|
}
|
|
426
712
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
newVersion: successfulPkgs.length === 1 ? first.version : void 0,
|
|
431
|
-
syncedAt: anySyncedAt,
|
|
432
|
-
wasEnhanced: allEnhanced,
|
|
433
|
-
bumpType: maxDiff || void 0
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
const llmConfig = await selectLlmConfig(resolvedModel, void 0, parallelUpdateCtx);
|
|
437
|
-
if (llmConfig?.promptOnly) for (const pkg of uncachedPkgs) {
|
|
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) {
|
|
713
|
+
renderParallel(render);
|
|
714
|
+
for (const r of uncached) await run.runEnhance(r.state, llmConfig);
|
|
715
|
+
} else if (llmConfig) {
|
|
457
716
|
p.log.step(getModelLabel(llmConfig.model));
|
|
458
|
-
for (const
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
717
|
+
for (const r of uncached) {
|
|
718
|
+
const displayName = specToName.get(r.spec) ?? r.spec;
|
|
719
|
+
states.set(r.spec, {
|
|
720
|
+
name: displayName,
|
|
721
|
+
status: "pending",
|
|
722
|
+
message: "Waiting...",
|
|
723
|
+
version: getVersionKey(r.state.version)
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
renderParallel(render);
|
|
727
|
+
const llmResults = await Promise.allSettled(uncached.map((r) => limit(() => run.runEnhance(r.state, llmConfig))));
|
|
468
728
|
logUpdate.done();
|
|
469
|
-
const llmSucceeded = llmResults.filter((
|
|
470
|
-
p.log.success(`Enhanced ${llmSucceeded}/${
|
|
729
|
+
const llmSucceeded = llmResults.filter((x) => x.status === "fulfilled").length;
|
|
730
|
+
p.log.success(`Enhanced ${llmSucceeded}/${uncached.length} skills with LLM`);
|
|
471
731
|
}
|
|
472
|
-
}
|
|
473
|
-
await
|
|
474
|
-
|
|
732
|
+
} else for (const r of ready) await run.runEnhance(r.state, null);
|
|
733
|
+
await ensureProjectFiles({
|
|
734
|
+
cwd,
|
|
735
|
+
agent: config.agent,
|
|
736
|
+
global: config.global
|
|
737
|
+
});
|
|
475
738
|
await shutdownWorker();
|
|
476
|
-
p.outro(`${pastVerb} ${
|
|
477
|
-
const { suggestPrepareHook } = await import("./
|
|
739
|
+
p.outro(`${pastVerb} ${ready.length}/${packages.length} packages`);
|
|
740
|
+
const { suggestPrepareHook } = await import("./prepare-hook.mjs");
|
|
478
741
|
try {
|
|
479
742
|
await suggestPrepareHook(cwd);
|
|
480
743
|
} catch (err) {
|
|
481
744
|
p.log.warn(`Failed to suggest prepare hook: ${err instanceof Error ? err.message : String(err)}`);
|
|
482
745
|
}
|
|
483
746
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
747
|
+
function aggregateUpdateCtx(ready) {
|
|
748
|
+
let maxDiff = "";
|
|
749
|
+
let allEnhanced = true;
|
|
750
|
+
let anySyncedAt;
|
|
751
|
+
for (const r of ready) {
|
|
752
|
+
const u = r.state.updateCtx;
|
|
753
|
+
if (!u?.wasEnhanced) allEnhanced = false;
|
|
754
|
+
if (u?.syncedAt && (!anySyncedAt || u.syncedAt < anySyncedAt)) anySyncedAt = u.syncedAt;
|
|
755
|
+
if (u?.oldVersion && u.newVersion) {
|
|
756
|
+
const diff = semverDiff(u.oldVersion, u.newVersion);
|
|
757
|
+
if (diff && (DIFF_RANK[diff] ?? 0) > (DIFF_RANK[maxDiff] ?? -1)) maxDiff = diff;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
const first = ready[0]?.state.updateCtx;
|
|
761
|
+
return {
|
|
762
|
+
oldVersion: ready.length === 1 ? first?.oldVersion : void 0,
|
|
763
|
+
newVersion: ready.length === 1 ? first?.newVersion : void 0,
|
|
764
|
+
syncedAt: anySyncedAt,
|
|
765
|
+
wasEnhanced: allEnhanced,
|
|
766
|
+
bumpType: maxDiff || void 0
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
async function handleMerge(state, config, cwd) {
|
|
770
|
+
const { identityName, storageName, version, resolved, baseDir, skillDir, skillDirName, existingLock } = state;
|
|
771
|
+
p.log.step(`Merging ${identityName} into ${skillDirName}`);
|
|
772
|
+
createReferenceCache(storageName, version).linkPkgNamed(skillDir, cwd);
|
|
773
|
+
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
774
|
+
installSkill({
|
|
489
775
|
cwd,
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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";
|
|
505
|
-
}
|
|
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,
|
|
776
|
+
agent: config.agent,
|
|
777
|
+
global: config.global,
|
|
778
|
+
baseDir,
|
|
779
|
+
skillDirName,
|
|
780
|
+
lock: {
|
|
781
|
+
packageName: identityName,
|
|
568
782
|
version,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version), getCacheDir(packageName, version));
|
|
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"
|
|
783
|
+
repo: repoSlug,
|
|
784
|
+
source: existingLock.source,
|
|
785
|
+
syncedAt: todayIsoDate(),
|
|
786
|
+
generator: "skilld"
|
|
787
|
+
},
|
|
788
|
+
skipLinkAgents: true
|
|
588
789
|
});
|
|
589
790
|
const updatedLock = readLock(baseDir)?.skills[skillDirName];
|
|
590
791
|
const allPackages = parsePackageNames(updatedLock?.packages);
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
792
|
+
const relatedSkills = await findRelatedSkills(storageName, baseDir);
|
|
793
|
+
const existingCache = createReferenceCache(toStoragePackageName(existingLock.packageName), existingLock.version);
|
|
794
|
+
const pkgFiles = existingCache.keyFiles(cwd);
|
|
795
|
+
const shippedDocs = existingCache.hasShipped(cwd);
|
|
796
|
+
const features = getActiveFeatures();
|
|
797
|
+
writeGeneratedSkillMd(skillDir, {
|
|
798
|
+
name: existingLock.packageName,
|
|
799
|
+
version: existingLock.version,
|
|
597
800
|
relatedSkills,
|
|
598
|
-
hasIssues:
|
|
599
|
-
hasDiscussions:
|
|
600
|
-
hasReleases:
|
|
601
|
-
|
|
602
|
-
docsType: resources.docsType,
|
|
801
|
+
hasIssues: features.issues && existsSync(skillRefsSection(skillDir, "issues")),
|
|
802
|
+
hasDiscussions: features.discussions && existsSync(skillRefsSection(skillDir, "discussions")),
|
|
803
|
+
hasReleases: features.releases && existsSync(skillRefsSection(skillDir, "releases")),
|
|
804
|
+
docsType: existingLock.source?.includes("llms.txt") ? "llms.txt" : "docs",
|
|
603
805
|
hasShippedDocs: shippedDocs,
|
|
604
806
|
pkgFiles,
|
|
605
807
|
dirName: skillDirName,
|
|
606
|
-
packages: allPackages
|
|
607
|
-
repoUrl: resolved.repoUrl,
|
|
808
|
+
packages: allPackages,
|
|
608
809
|
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);
|
|
614
|
-
return {
|
|
615
|
-
resolved,
|
|
616
|
-
version,
|
|
617
|
-
skillDirName,
|
|
618
|
-
docsType: resources.docsType,
|
|
619
|
-
hasIssues: resources.hasIssues,
|
|
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
|
|
634
|
-
};
|
|
635
|
-
}
|
|
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
810
|
});
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
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);
|
|
811
|
+
const sharedDir = !config.global && getSharedSkillsDir(cwd);
|
|
812
|
+
if (sharedDir) linkSkillToAgents(skillDirName, sharedDir, cwd, config.agent);
|
|
813
|
+
p.outro(`Merged ${identityName} into ${skillDirName}`);
|
|
690
814
|
}
|
|
691
815
|
const RESOLVE_SOURCE_LABELS = {
|
|
692
816
|
"npm": "npm registry",
|
|
@@ -700,20 +824,14 @@ const RESOLVE_SOURCE_LABELS = {
|
|
|
700
824
|
};
|
|
701
825
|
function showResolveAttempts(attempts) {
|
|
702
826
|
if (attempts.length === 0) return;
|
|
703
|
-
p.log.message("
|
|
827
|
+
p.log.message(styleText("gray", "Doc resolution:"));
|
|
704
828
|
for (const attempt of attempts) {
|
|
705
|
-
const icon = attempt.status === "success" ? "
|
|
706
|
-
const source =
|
|
707
|
-
const msg = attempt.message ? `
|
|
829
|
+
const icon = attempt.status === "success" ? styleText("green", "✓") : styleText("gray", "✗");
|
|
830
|
+
const source = styleText("gray", RESOLVE_SOURCE_LABELS[attempt.source] ?? attempt.source);
|
|
831
|
+
const msg = attempt.message ? ` ${styleText("gray", `— ${attempt.message}`)}` : "";
|
|
708
832
|
p.log.message(` ${icon} ${source}${msg}`);
|
|
709
833
|
}
|
|
710
834
|
}
|
|
711
|
-
function isCrateSpec(spec) {
|
|
712
|
-
return spec.startsWith("crate:");
|
|
713
|
-
}
|
|
714
|
-
function toCrateIdentity(crateName) {
|
|
715
|
-
return `crate:${crateName}`;
|
|
716
|
-
}
|
|
717
835
|
async function syncCommand(state, opts) {
|
|
718
836
|
if (opts.packages && opts.packages.length > 0) {
|
|
719
837
|
const crateSpecs = opts.packages.filter(isCrateSpec);
|
|
@@ -805,52 +923,38 @@ async function pickFromList(packages, state) {
|
|
|
805
923
|
}
|
|
806
924
|
return selected;
|
|
807
925
|
}
|
|
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}`);
|
|
926
|
+
async function runSimpleSync(packageSpec, config) {
|
|
821
927
|
const cwd = process.cwd();
|
|
822
|
-
const
|
|
823
|
-
const
|
|
824
|
-
const resolveResult = isCrate ? await resolveCrateDocsWithAttempts(packageName, {
|
|
825
|
-
version: requestedTag,
|
|
826
|
-
onProgress: (step) => spin.message(`${identityPackageName}: ${step}`)
|
|
827
|
-
}) : await resolvePackageDocsWithAttempts(requestedTag ? normalizedSpec : packageName, {
|
|
828
|
-
version: localVersion,
|
|
928
|
+
const isEject = !!config.eject;
|
|
929
|
+
const run = createSyncRun({
|
|
829
930
|
cwd,
|
|
830
|
-
|
|
931
|
+
resolver: npmResolver,
|
|
932
|
+
agent: config.agent,
|
|
933
|
+
global: config.global,
|
|
934
|
+
mode: config.mode,
|
|
935
|
+
force: config.force,
|
|
936
|
+
noSearch: config.noSearch,
|
|
937
|
+
name: config.name,
|
|
938
|
+
from: config.from,
|
|
939
|
+
debug: config.debug,
|
|
940
|
+
eject: config.eject,
|
|
941
|
+
defaultSections: DEFAULT_SECTIONS,
|
|
942
|
+
onMergeNeeded: (state) => handleMerge(state, {
|
|
943
|
+
agent: config.agent,
|
|
944
|
+
global: config.global
|
|
945
|
+
}, cwd)
|
|
831
946
|
});
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
947
|
+
bindClackUi(run.hooks, { cwd });
|
|
948
|
+
const base = await run.runBase(packageSpec);
|
|
949
|
+
if (base.kind === "shipped") {
|
|
950
|
+
p.outro(`Synced ${packageSpec}`);
|
|
951
|
+
return;
|
|
836
952
|
}
|
|
837
|
-
if (
|
|
838
|
-
if (!
|
|
839
|
-
const
|
|
840
|
-
if (earlyShipped) {
|
|
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);
|
|
953
|
+
if (base.kind === "unresolved") {
|
|
954
|
+
if (!isCrateSpec(packageSpec)) {
|
|
955
|
+
const suggestions = await searchNpmPackages(base.identityName);
|
|
851
956
|
if (suggestions.length > 0) {
|
|
852
|
-
|
|
853
|
-
showResolveAttempts(resolveResult.attempts);
|
|
957
|
+
showResolveAttempts(base.attempts);
|
|
854
958
|
const selected = await p.select({
|
|
855
959
|
message: "Did you mean one of these?",
|
|
856
960
|
options: [...suggestions.map((s) => ({
|
|
@@ -866,725 +970,33 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
866
970
|
return;
|
|
867
971
|
}
|
|
868
972
|
}
|
|
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}`);
|
|
889
|
-
return;
|
|
890
|
-
}
|
|
891
|
-
spin.stop(`Resolved ${identityPackageName}@${useCache ? versionKey : version}${config.force ? " (force)" : useCache ? " (cached)" : ""}`);
|
|
892
|
-
if (!isCrate && !localVersion && !requestedTag && !isPrerelease(version)) {
|
|
893
|
-
const nextTag = resolved.distTags?.next ?? resolved.distTags?.beta ?? resolved.distTags?.alpha;
|
|
894
|
-
if (nextTag && (!resolved.releasedAt || !nextTag.releasedAt || nextTag.releasedAt > resolved.releasedAt)) p.log.warn(`\x1B[33mNo local dependency found — using latest stable (${version}). Prerelease ${nextTag.version} available: skilld add ${packageName}@beta\x1B[0m`);
|
|
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}`);
|
|
973
|
+
showResolveAttempts(base.attempts);
|
|
959
974
|
return;
|
|
960
975
|
}
|
|
961
|
-
|
|
962
|
-
|
|
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
|
-
}
|
|
976
|
+
if (base.kind === "merged" || base.kind === "error") return;
|
|
977
|
+
const { state } = base;
|
|
1083
978
|
const globalConfig = readConfig();
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
if (auto) resolvedModel = auto;
|
|
1089
|
-
}
|
|
1090
|
-
if (!allSectionsCached && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
|
|
1091
|
-
const llmConfig = await selectLlmConfig(resolvedModel, void 0, updateCtx);
|
|
1092
|
-
if (llmConfig?.promptOnly) writePromptFiles({
|
|
1093
|
-
packageName: storagePackageName,
|
|
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
|
-
}
|
|
979
|
+
const resolvedModel = await resolveAutoModel(config.model, config.yes);
|
|
980
|
+
let llmConfig = null;
|
|
981
|
+
if (!state.allSectionsCached && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) llmConfig = await selectLlmConfig(resolvedModel, void 0, state.updateCtx);
|
|
982
|
+
await run.runEnhance(state, llmConfig);
|
|
1152
983
|
await shutdownWorker();
|
|
1153
984
|
const ejectMsg = isEject ? " (ejected)" : "";
|
|
1154
|
-
const relDir = relative(cwd, skillDir);
|
|
1155
|
-
p.outro(config.mode === "update" ? `Updated ${
|
|
985
|
+
const relDir = relative(cwd, state.skillDir);
|
|
986
|
+
p.outro(config.mode === "update" ? `Updated ${state.identityName}${ejectMsg}` : `Synced ${state.identityName} → ${relDir}${ejectMsg}`);
|
|
1156
987
|
try {
|
|
1157
988
|
await suggestPrepareHook(cwd);
|
|
1158
989
|
} catch (err) {
|
|
1159
990
|
p.log.warn(`Failed to suggest prepare hook: ${err instanceof Error ? err.message : String(err)}`);
|
|
1160
991
|
}
|
|
1161
992
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
description: "Install skills (npm:<pkg>, crate:<name>, gh:<owner/repo>, @<curator>)"
|
|
1166
|
-
},
|
|
1167
|
-
args: {
|
|
1168
|
-
package: {
|
|
1169
|
-
type: "positional",
|
|
1170
|
-
description: "Package(s) to sync (space/comma-separated; npm:<pkg>, crate:<name>, or owner/repo)",
|
|
1171
|
-
required: true
|
|
1172
|
-
},
|
|
1173
|
-
skill: {
|
|
1174
|
-
type: "string",
|
|
1175
|
-
alias: "s",
|
|
1176
|
-
description: "Select specific skills from a git repo (comma-separated)",
|
|
1177
|
-
valueHint: "name"
|
|
1178
|
-
},
|
|
1179
|
-
...sharedArgs
|
|
1180
|
-
},
|
|
1181
|
-
async run({ args }) {
|
|
1182
|
-
const cwd = process.cwd();
|
|
1183
|
-
let agent = resolveAgent(args.agent);
|
|
1184
|
-
if (!agent) {
|
|
1185
|
-
agent = await promptForAgent();
|
|
1186
|
-
if (!agent) return;
|
|
1187
|
-
}
|
|
1188
|
-
const rawInputs = [...new Set([args.package, ...args._ || []].map((s) => s.trim()).filter(Boolean))];
|
|
1189
|
-
if (agent === "none") {
|
|
1190
|
-
const packages = [...new Set(rawInputs.flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
|
|
1191
|
-
for (const pkg of packages) await exportPortablePrompts(pkg, {
|
|
1192
|
-
force: args.force,
|
|
1193
|
-
agent: "none"
|
|
1194
|
-
});
|
|
1195
|
-
return;
|
|
1196
|
-
}
|
|
1197
|
-
if (!hasCompletedWizard()) await runWizard({ agent });
|
|
1198
|
-
const parsedSources = rawInputs.map(parseSkillInput);
|
|
1199
|
-
const gitSources = [];
|
|
1200
|
-
const npmEntries = [];
|
|
1201
|
-
const crateSpecs = [];
|
|
1202
|
-
const unsupported = [];
|
|
1203
|
-
for (const source of parsedSources) switch (source.type) {
|
|
1204
|
-
case "git":
|
|
1205
|
-
gitSources.push(source.source);
|
|
1206
|
-
break;
|
|
1207
|
-
case "npm":
|
|
1208
|
-
npmEntries.push({
|
|
1209
|
-
name: source.package,
|
|
1210
|
-
spec: source.tag ? `${source.package}@${source.tag}` : source.package
|
|
1211
|
-
});
|
|
1212
|
-
break;
|
|
1213
|
-
case "crate":
|
|
1214
|
-
crateSpecs.push(source.version ? `crate:${source.package}@${source.version}` : `crate:${source.package}`);
|
|
1215
|
-
break;
|
|
1216
|
-
case "bare":
|
|
1217
|
-
p.log.warn(`Bare names are deprecated. Use \x1B[36mnpm:${source.package}\x1B[0m instead.`);
|
|
1218
|
-
npmEntries.push({
|
|
1219
|
-
name: source.package,
|
|
1220
|
-
spec: source.tag ? `${source.package}@${source.tag}` : source.package
|
|
1221
|
-
});
|
|
1222
|
-
break;
|
|
1223
|
-
case "curator":
|
|
1224
|
-
unsupported.push(`@${source.handle} (curator)`);
|
|
1225
|
-
break;
|
|
1226
|
-
case "collection":
|
|
1227
|
-
unsupported.push(`@${source.handle}/${source.name} (collection)`);
|
|
1228
|
-
break;
|
|
1229
|
-
default: throw new Error(`Unhandled SkillSource type: ${JSON.stringify(source)}`);
|
|
1230
|
-
}
|
|
1231
|
-
if (unsupported.length > 0) {
|
|
1232
|
-
p.log.error(`Curator and collection installs are not yet available:\n ${unsupported.join("\n ")}\n\nFollow https://skilld.dev for launch updates.`);
|
|
1233
|
-
process.exitCode = 1;
|
|
1234
|
-
if (gitSources.length === 0 && npmEntries.length === 0 && crateSpecs.length === 0) return;
|
|
1235
|
-
}
|
|
1236
|
-
if (gitSources.length > 0) for (const source of gitSources) {
|
|
1237
|
-
const skillFilter = args.skill ? args.skill.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean) : void 0;
|
|
1238
|
-
await syncGitSkills({
|
|
1239
|
-
source,
|
|
1240
|
-
global: args.global,
|
|
1241
|
-
agent,
|
|
1242
|
-
yes: args.yes,
|
|
1243
|
-
model: args.model,
|
|
1244
|
-
force: args.force,
|
|
1245
|
-
debug: args.debug,
|
|
1246
|
-
skillFilter
|
|
1247
|
-
});
|
|
1248
|
-
}
|
|
1249
|
-
if (npmEntries.length > 0) {
|
|
1250
|
-
const { syncRegistrySkill } = await import("./sync-registry.mjs");
|
|
1251
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1252
|
-
const dedupedEntries = npmEntries.filter((e) => {
|
|
1253
|
-
if (seen.has(e.name)) return false;
|
|
1254
|
-
seen.add(e.name);
|
|
1255
|
-
return true;
|
|
1256
|
-
});
|
|
1257
|
-
const fallbackPackages = [];
|
|
1258
|
-
for (const entry of dedupedEntries) {
|
|
1259
|
-
const result = await syncRegistrySkill({
|
|
1260
|
-
packageName: entry.name,
|
|
1261
|
-
agent,
|
|
1262
|
-
cwd
|
|
1263
|
-
});
|
|
1264
|
-
if (result) p.log.success(`Installed \x1B[36m${result.name}\x1B[0m from registry`);
|
|
1265
|
-
else fallbackPackages.push(entry.spec);
|
|
1266
|
-
}
|
|
1267
|
-
if (fallbackPackages.length > 0) {
|
|
1268
|
-
const state = await getProjectState(cwd);
|
|
1269
|
-
p.intro(introLine({
|
|
1270
|
-
state,
|
|
1271
|
-
agentId: agent || void 0
|
|
1272
|
-
}));
|
|
1273
|
-
await syncCommand(state, {
|
|
1274
|
-
packages: [...fallbackPackages, ...crateSpecs],
|
|
1275
|
-
global: args.global,
|
|
1276
|
-
agent,
|
|
1277
|
-
model: args.model,
|
|
1278
|
-
yes: args.yes,
|
|
1279
|
-
force: args.force,
|
|
1280
|
-
debug: args.debug
|
|
1281
|
-
});
|
|
1282
|
-
return;
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
if (crateSpecs.length > 0) {
|
|
1286
|
-
const state = await getProjectState(cwd);
|
|
1287
|
-
p.intro(introLine({
|
|
1288
|
-
state,
|
|
1289
|
-
agentId: agent || void 0
|
|
1290
|
-
}));
|
|
1291
|
-
await syncCommand(state, {
|
|
1292
|
-
packages: crateSpecs,
|
|
1293
|
-
global: args.global,
|
|
1294
|
-
agent,
|
|
1295
|
-
model: args.model,
|
|
1296
|
-
yes: args.yes,
|
|
1297
|
-
force: args.force,
|
|
1298
|
-
debug: args.debug
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
const ejectCommandDef = defineCommand({
|
|
1304
|
-
meta: {
|
|
1305
|
-
name: "eject",
|
|
1306
|
-
description: "Eject skill with references as real files (portable, no symlinks)"
|
|
1307
|
-
},
|
|
1308
|
-
args: {
|
|
1309
|
-
package: {
|
|
1310
|
-
type: "positional",
|
|
1311
|
-
description: "Package to eject",
|
|
1312
|
-
required: true
|
|
1313
|
-
},
|
|
1314
|
-
name: {
|
|
1315
|
-
type: "string",
|
|
1316
|
-
alias: "n",
|
|
1317
|
-
description: "Custom skill directory name (default: derived from package)"
|
|
1318
|
-
},
|
|
1319
|
-
out: {
|
|
1320
|
-
type: "string",
|
|
1321
|
-
alias: "o",
|
|
1322
|
-
description: "Output directory path override"
|
|
1323
|
-
},
|
|
1324
|
-
from: {
|
|
1325
|
-
type: "string",
|
|
1326
|
-
description: "Collect releases/issues/discussions from this date onward (YYYY-MM-DD)"
|
|
1327
|
-
},
|
|
1328
|
-
search: {
|
|
1329
|
-
type: "boolean",
|
|
1330
|
-
description: "Build search index / embeddings (use --no-search to skip)",
|
|
1331
|
-
default: true
|
|
1332
|
-
},
|
|
1333
|
-
...sharedArgs
|
|
1334
|
-
},
|
|
1335
|
-
async run({ args }) {
|
|
1336
|
-
const cwd = process.cwd();
|
|
1337
|
-
const resolved = resolveAgent(args.agent);
|
|
1338
|
-
const agent = resolved && resolved !== "none" ? resolved : "claude-code";
|
|
1339
|
-
if (!hasCompletedWizard()) await runWizard({ agent });
|
|
1340
|
-
const state = await getProjectState(cwd);
|
|
1341
|
-
p.intro(introLine({
|
|
1342
|
-
state,
|
|
1343
|
-
agentId: agent || void 0
|
|
1344
|
-
}));
|
|
1345
|
-
return syncCommand(state, {
|
|
1346
|
-
packages: [args.package],
|
|
1347
|
-
global: args.global,
|
|
1348
|
-
agent,
|
|
1349
|
-
model: args.model,
|
|
1350
|
-
yes: args.yes,
|
|
1351
|
-
force: args.force,
|
|
1352
|
-
debug: args.debug,
|
|
1353
|
-
eject: args.out || true,
|
|
1354
|
-
name: args.name,
|
|
1355
|
-
from: args.from,
|
|
1356
|
-
noSearch: !args.search
|
|
1357
|
-
});
|
|
1358
|
-
}
|
|
1359
|
-
});
|
|
1360
|
-
const updateCommandDef = defineCommand({
|
|
1361
|
-
meta: {
|
|
1362
|
-
name: "update",
|
|
1363
|
-
description: "Update outdated skills"
|
|
1364
|
-
},
|
|
1365
|
-
args: {
|
|
1366
|
-
package: {
|
|
1367
|
-
type: "positional",
|
|
1368
|
-
description: "Package(s) to update (space or comma-separated). Without args, syncs all outdated.",
|
|
1369
|
-
required: false
|
|
1370
|
-
},
|
|
1371
|
-
background: {
|
|
1372
|
-
type: "boolean",
|
|
1373
|
-
alias: "b",
|
|
1374
|
-
description: "Run in background (detached process, non-interactive)",
|
|
1375
|
-
default: false
|
|
1376
|
-
},
|
|
1377
|
-
...sharedArgs
|
|
1378
|
-
},
|
|
1379
|
-
async run({ args }) {
|
|
1380
|
-
const cwd = process.cwd();
|
|
1381
|
-
if (args.background) {
|
|
1382
|
-
const { spawn } = await import("node:child_process");
|
|
1383
|
-
const updateArgs = [
|
|
1384
|
-
"update",
|
|
1385
|
-
...args.package ? [args.package] : [],
|
|
1386
|
-
...args.agent ? ["--agent", args.agent] : [],
|
|
1387
|
-
...args.model ? ["--model", args.model] : []
|
|
1388
|
-
];
|
|
1389
|
-
spawn(process.execPath, [process.argv[1], ...updateArgs], {
|
|
1390
|
-
cwd,
|
|
1391
|
-
detached: true,
|
|
1392
|
-
stdio: "ignore"
|
|
1393
|
-
}).unref();
|
|
1394
|
-
return;
|
|
1395
|
-
}
|
|
1396
|
-
const silent = !isInteractive();
|
|
1397
|
-
let agent = resolveAgent(args.agent);
|
|
1398
|
-
if (!agent) {
|
|
1399
|
-
agent = await promptForAgent();
|
|
1400
|
-
if (!agent) return;
|
|
1401
|
-
}
|
|
1402
|
-
if (agent === "none") {
|
|
1403
|
-
const state = await getProjectState(cwd);
|
|
1404
|
-
const packages = args.package ? Array.from(new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean)), (s) => resolveSkillName(s)).filter((s) => s !== null) : state.outdated.map((s) => s.packageName || s.name);
|
|
1405
|
-
if (packages.length === 0) {
|
|
1406
|
-
if (!silent) p.log.success("All skills up to date");
|
|
1407
|
-
return;
|
|
1408
|
-
}
|
|
1409
|
-
for (const pkg of packages) await exportPortablePrompts(pkg, {
|
|
1410
|
-
force: args.force,
|
|
1411
|
-
agent: "none"
|
|
1412
|
-
});
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
|
-
const config = readConfig();
|
|
1416
|
-
const state = await getProjectState(cwd);
|
|
1417
|
-
if (!silent) {
|
|
1418
|
-
const generators = getInstalledGenerators();
|
|
1419
|
-
p.intro(introLine({
|
|
1420
|
-
state,
|
|
1421
|
-
generators,
|
|
1422
|
-
modelId: config.model,
|
|
1423
|
-
agentId: config.agent || agent || void 0
|
|
1424
|
-
}));
|
|
1425
|
-
}
|
|
1426
|
-
if (args.package) {
|
|
1427
|
-
const raw = [...new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
|
|
1428
|
-
const packages = [];
|
|
1429
|
-
for (const r of raw) {
|
|
1430
|
-
const name = resolveSkillName(r);
|
|
1431
|
-
if (!name) {
|
|
1432
|
-
p.log.warn(`Cannot update \x1B[36m${r}\x1B[0m: curator/collection inputs are not addressable here.`);
|
|
1433
|
-
continue;
|
|
1434
|
-
}
|
|
1435
|
-
packages.push(name);
|
|
1436
|
-
}
|
|
1437
|
-
if (packages.length === 0) return;
|
|
1438
|
-
return syncCommand(state, {
|
|
1439
|
-
packages,
|
|
1440
|
-
global: args.global,
|
|
1441
|
-
agent,
|
|
1442
|
-
model: args.model || (silent ? config.model : void 0),
|
|
1443
|
-
yes: args.yes || silent,
|
|
1444
|
-
force: args.force,
|
|
1445
|
-
debug: args.debug,
|
|
1446
|
-
mode: "update"
|
|
1447
|
-
});
|
|
1448
|
-
}
|
|
1449
|
-
const crateSpecs = state.skills.map((s) => s.info?.packageName).filter((name) => !!name && name.startsWith("crate:"));
|
|
1450
|
-
if (state.outdated.length === 0 && crateSpecs.length === 0) {
|
|
1451
|
-
p.log.success("All skills up to date");
|
|
1452
|
-
return;
|
|
1453
|
-
}
|
|
1454
|
-
return syncCommand(state, {
|
|
1455
|
-
packages: [...state.outdated.map((s) => s.packageName || s.name), ...crateSpecs],
|
|
1456
|
-
global: args.global,
|
|
1457
|
-
agent,
|
|
1458
|
-
model: args.model || (silent ? config.model : void 0),
|
|
1459
|
-
yes: args.yes || silent,
|
|
1460
|
-
force: args.force,
|
|
1461
|
-
debug: args.debug,
|
|
1462
|
-
mode: "update"
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
});
|
|
1466
|
-
async function exportPortablePrompts(packageSpec, opts) {
|
|
1467
|
-
const { name: packageName } = parsePackageSpec(packageSpec);
|
|
1468
|
-
const sections = opts.sections ?? DEFAULT_SECTIONS;
|
|
1469
|
-
const spin = timedSpinner();
|
|
1470
|
-
spin.start(`Resolving ${packageSpec}`);
|
|
1471
|
-
const cwd = process.cwd();
|
|
1472
|
-
const localVersion = (await readLocalDependencies(cwd).catch(() => [])).find((d) => d.name === packageName)?.version;
|
|
1473
|
-
let resolved = (await resolvePackageDocsWithAttempts(packageName, {
|
|
1474
|
-
version: localVersion,
|
|
1475
|
-
cwd,
|
|
1476
|
-
onProgress: (step) => spin.message(`${packageName}: ${RESOLVE_STEP_LABELS[step]}`)
|
|
1477
|
-
})).package;
|
|
1478
|
-
if (!resolved) {
|
|
1479
|
-
spin.message(`Resolving local package: ${packageName}`);
|
|
1480
|
-
resolved = await resolveLocalDep(packageName, cwd);
|
|
1481
|
-
}
|
|
1482
|
-
if (!resolved) {
|
|
1483
|
-
spin.stop(`Could not find docs for: ${packageName}`);
|
|
993
|
+
async function syncSinglePackage(packageSpec, config) {
|
|
994
|
+
if (isCrateSpec(packageSpec) && !packageSpec.slice(6).trim()) {
|
|
995
|
+
p.log.error("Invalid crate spec. Use format: crate:<name>");
|
|
1484
996
|
return;
|
|
1485
997
|
}
|
|
1486
|
-
|
|
1487
|
-
const versionKey = getVersionKey(version);
|
|
1488
|
-
const useCache = !opts.force && isCached(packageName, version);
|
|
1489
|
-
if (!existsSync(join(cwd, "node_modules", packageName))) {
|
|
1490
|
-
spin.message(`Downloading ${packageName}@${version} dist`);
|
|
1491
|
-
await fetchPkgDist(packageName, version);
|
|
1492
|
-
}
|
|
1493
|
-
spin.stop(`Resolved ${packageName}@${useCache ? versionKey : version}`);
|
|
1494
|
-
ensureCacheDir();
|
|
1495
|
-
const skillDirName = computeSkillDirName(packageName);
|
|
1496
|
-
const features = readConfig().features ?? defaultFeatures;
|
|
1497
|
-
const agent = opts.agent === "none" ? null : opts.agent ?? await import("./detect2.mjs").then((m) => m.detectTargetAgent());
|
|
1498
|
-
const baseDir = agent ? resolveBaseDir(cwd, agent, false) : join(cwd, ".claude", "skills");
|
|
1499
|
-
const skillDir = opts.out ? resolve(cwd, opts.out) : join(baseDir, skillDirName);
|
|
1500
|
-
if (existsSync(skillDir) && !opts.force) {
|
|
1501
|
-
const existing = Object.values(SECTION_OUTPUT_FILES).filter((f) => existsSync(join(skillDir, f)));
|
|
1502
|
-
if (existing.length > 0) p.log.warn(`Overwriting existing output files in ${relative(cwd, skillDir)}: ${existing.join(", ")}`);
|
|
1503
|
-
}
|
|
1504
|
-
mkdirSync(skillDir, { recursive: true });
|
|
1505
|
-
const resSpin = timedSpinner();
|
|
1506
|
-
resSpin.start("Fetching resources");
|
|
1507
|
-
const resources = await fetchAndCacheResources({
|
|
1508
|
-
packageName,
|
|
1509
|
-
resolved,
|
|
1510
|
-
version,
|
|
1511
|
-
useCache,
|
|
1512
|
-
features,
|
|
1513
|
-
onProgress: (msg) => resSpin.message(msg)
|
|
1514
|
-
});
|
|
1515
|
-
resSpin.stop("Resources ready");
|
|
1516
|
-
for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
1517
|
-
linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
|
|
1518
|
-
const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version), getCacheDir(packageName, version));
|
|
1519
|
-
const shippedDocs = hasShippedDocs(packageName, cwd, version);
|
|
1520
|
-
const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
|
|
1521
|
-
const docFiles = listReferenceFiles(skillDir);
|
|
1522
|
-
const prompts = buildAllSectionPrompts({
|
|
1523
|
-
packageName,
|
|
1524
|
-
skillDir,
|
|
1525
|
-
version,
|
|
1526
|
-
hasIssues: resources.hasIssues,
|
|
1527
|
-
hasDiscussions: resources.hasDiscussions,
|
|
1528
|
-
hasReleases: resources.hasReleases,
|
|
1529
|
-
hasChangelog,
|
|
1530
|
-
docFiles,
|
|
1531
|
-
docsType: resources.docsType,
|
|
1532
|
-
hasShippedDocs: shippedDocs,
|
|
1533
|
-
pkgFiles,
|
|
1534
|
-
features,
|
|
1535
|
-
sections
|
|
1536
|
-
});
|
|
1537
|
-
ejectReferences(skillDir, packageName, cwd, version, resources.docsType, features, resources.repoInfo);
|
|
1538
|
-
const skilldDir = join(skillDir, ".skilld");
|
|
1539
|
-
if (existsSync(skilldDir)) rmSync(skilldDir, {
|
|
1540
|
-
recursive: true,
|
|
1541
|
-
force: true
|
|
1542
|
-
});
|
|
1543
|
-
for (const [section, prompt] of prompts) {
|
|
1544
|
-
const portable = portabilizePrompt(prompt, section);
|
|
1545
|
-
writeFileSync(join(skillDir, `PROMPT_${section}.md`), portable);
|
|
1546
|
-
}
|
|
1547
|
-
const relatedSkills = await findRelatedSkills(packageName, join(skillDir, ".."));
|
|
1548
|
-
writeGeneratedSkillMd(skillDir, {
|
|
1549
|
-
name: packageName,
|
|
1550
|
-
version,
|
|
1551
|
-
releasedAt: resolved.releasedAt,
|
|
1552
|
-
description: resolved.description,
|
|
1553
|
-
distTags: resolved.distTags,
|
|
1554
|
-
relatedSkills,
|
|
1555
|
-
hasIssues: resources.hasIssues,
|
|
1556
|
-
hasDiscussions: resources.hasDiscussions,
|
|
1557
|
-
hasReleases: resources.hasReleases,
|
|
1558
|
-
hasChangelog,
|
|
1559
|
-
docsType: resources.docsType,
|
|
1560
|
-
hasShippedDocs: shippedDocs,
|
|
1561
|
-
pkgFiles,
|
|
1562
|
-
repoUrl: resolved.repoUrl,
|
|
1563
|
-
features,
|
|
1564
|
-
eject: true
|
|
1565
|
-
});
|
|
1566
|
-
writeLock(baseDir, skillDirName, {
|
|
1567
|
-
packageName,
|
|
1568
|
-
version,
|
|
1569
|
-
repo: parseGitHubRepoSlug(resolved.repoUrl),
|
|
1570
|
-
source: resources.docSource,
|
|
1571
|
-
syncedAt: todayIsoDate(),
|
|
1572
|
-
generator: "skilld"
|
|
1573
|
-
});
|
|
1574
|
-
if (agent) {
|
|
1575
|
-
const shared = getSharedSkillsDir(cwd);
|
|
1576
|
-
if (shared) linkSkillToAgents(skillDirName, shared, cwd, agent);
|
|
1577
|
-
await ensureGitignore(shared ? SHARED_SKILLS_DIR : targets[agent].skillsDir, cwd, false);
|
|
1578
|
-
await ensureAgentInstructions(agent, cwd, false);
|
|
1579
|
-
registerProject(cwd);
|
|
1580
|
-
} else await ensureGitignore(".claude/skills", cwd, false);
|
|
1581
|
-
const relDir = relative(cwd, skillDir);
|
|
1582
|
-
const sectionList = [...prompts.keys()];
|
|
1583
|
-
p.log.success(`Skill installed to ${relDir}`);
|
|
1584
|
-
const promptFiles = sectionList.map((s) => `PROMPT_${s}.md`).join(", ");
|
|
1585
|
-
const outputFileList = sectionList.map((s) => SECTION_OUTPUT_FILES[s]).join(", ");
|
|
1586
|
-
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`);
|
|
998
|
+
return runSimpleSync(packageSpec, config);
|
|
1587
999
|
}
|
|
1588
|
-
export {
|
|
1000
|
+
export { createGithubResolver as i, bindClackUi as n, createSyncRun as r, syncCommand as t };
|
|
1589
1001
|
|
|
1590
1002
|
//# sourceMappingURL=sync.mjs.map
|