skilld 1.7.4 → 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 +81 -57
- 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 +10 -7
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +33 -17
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +143 -183
- 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 +5 -5
- package/dist/_chunks/detect.mjs +53 -43
- 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 +1 -1
- 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 +81 -326
- 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 +3 -2
- 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 +4 -2
- package/dist/_chunks/monorepo.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/paths.mjs +3 -5
- package/dist/_chunks/paths.mjs.map +1 -1
- package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
- package/dist/_chunks/pipeline.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +1 -1
- 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 +7 -6
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +484 -74
- 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 +8 -6
- 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 -3
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/semver.mjs +2755 -1
- package/dist/_chunks/semver.mjs.map +1 -1
- package/dist/_chunks/skill-installer2.mjs +10 -11
- package/dist/_chunks/skill-installer2.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +6 -7
- 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 +411 -910
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +2 -5
- package/dist/_chunks/telemetry.mjs +26 -0
- package/dist/_chunks/telemetry.mjs.map +1 -0
- package/dist/_chunks/uninstall.mjs +12 -9
- 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 +3 -3
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +16 -17
- 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 +72 -53
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs +4 -3
- 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 +19 -28
- 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/index.d.mts +0 -344
- package/dist/_chunks/index.d.mts.map +0 -1
- package/dist/_chunks/index2.d.mts +0 -279
- package/dist/_chunks/index2.d.mts.map +0 -1
- package/dist/_chunks/index3.d.mts +0 -44
- package/dist/_chunks/index3.d.mts.map +0 -1
- package/dist/_chunks/index4.d.mts +0 -553
- package/dist/_chunks/index4.d.mts.map +0 -1
- package/dist/_chunks/package-registry.mjs +0 -465
- package/dist/_chunks/package-registry.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/sources.mjs +0 -2654
- package/dist/_chunks/sources.mjs.map +0 -1
- package/dist/_chunks/sync-pipeline.mjs.map +0 -1
- package/dist/_chunks/sync-registry.mjs +0 -65
- package/dist/_chunks/sync-registry.mjs.map +0 -1
- package/dist/_chunks/types.d.mts +0 -76
- package/dist/_chunks/types.d.mts.map +0 -1
- package/dist/_chunks/types2.d.mts +0 -88
- package/dist/_chunks/types2.d.mts.map +0 -1
- package/dist/_chunks/wizard.mjs.map +0 -1
- package/dist/agent/index.d.mts +0 -2
- package/dist/agent/index.mjs +0 -4
- package/dist/cache/index.d.mts +0 -2
- package/dist/cache/index.mjs +0 -5
- package/dist/index.d.mts +0 -6
- package/dist/index.mjs +0 -6
- package/dist/retriv/index.d.mts +0 -3
- package/dist/retriv/index.mjs +0 -2
- package/dist/sources/index.d.mts +0 -3
- package/dist/sources/index.mjs +0 -3
- package/dist/types.d.mts +0 -4
- package/dist/types.mjs +0 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { a as targets } from "./detect.mjs";
|
|
2
|
+
import { a as getModelName, c as getOAuthProviderList, l as loginOAuthProvider, r as getAvailableModels } from "./agent.mjs";
|
|
3
|
+
import { m as updateConfig, o as defaultFeatures } from "./cache.mjs";
|
|
4
|
+
import { t as isInteractive } from "./env.mjs";
|
|
5
|
+
import { r as resolveAgent } from "./agent-prompt.mjs";
|
|
6
|
+
import { t as sharedArgs } from "./args.mjs";
|
|
7
|
+
import { n as OAUTH_NOTE, r as pickModel, t as NO_MODELS_MESSAGE } from "./model-picker.mjs";
|
|
8
|
+
import { styleText } from "node:util";
|
|
9
|
+
import * as p from "@clack/prompts";
|
|
10
|
+
import { defineCommand } from "citty";
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
function hasGhCli() {
|
|
13
|
+
if (process.env.SKILLD_NO_GH) return false;
|
|
14
|
+
try {
|
|
15
|
+
execSync("gh --version", { stdio: "ignore" });
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function runWizard(opts = {}) {
|
|
22
|
+
if (!isInteractive()) return false;
|
|
23
|
+
const agentLabel = opts.agent ? targets[opts.agent].displayName : null;
|
|
24
|
+
const skillsDir = opts.agent ? targets[opts.agent].skillsDir : ".claude/skills";
|
|
25
|
+
const agentLine = agentLabel ? `\n${styleText("gray", `Target agent: ${agentLabel}`)}` : "";
|
|
26
|
+
p.note(`Your AI agent reads docs from its training data - but APIs change,
|
|
27
|
+
versions drift, and patterns go stale. Skilld fixes this.
|
|
28
|
+
|
|
29
|
+
It generates a ${styleText("bold", "SKILL.md")} - a markdown reference card built from\nthe ${styleText("bold", "actual docs, issues, and release notes")} for the exact\npackage versions in your project. Your agent reads this file\nevery session - no hallucinated APIs.\n\n${styleText("bold", "How it works:")}\n 1. Fetch docs, issues, and types for your packages\n 2. Optionally compress with an LLM into a concise cheat sheet\n\n${styleText("gray", `Example: \`skilld add vue\` creates ${skillsDir}/vue-skilld/SKILL.md\nYour agent then knows the right APIs, gotchas, and patterns\nfor your exact version.`)}${agentLine}`, "Welcome to skilld");
|
|
30
|
+
const ghInstalled = hasGhCli();
|
|
31
|
+
if (ghInstalled) p.log.success("GitHub CLI detected — will use it to pull issues and discussions.");
|
|
32
|
+
else p.log.info(`${styleText("gray", "GitHub CLI not installed — issues and discussions disabled.")}\n Install later to enable: ${styleText("cyan", "https://cli.github.com")}`);
|
|
33
|
+
const selected = await p.multiselect({
|
|
34
|
+
message: "What data sources should skills include?",
|
|
35
|
+
options: [
|
|
36
|
+
{
|
|
37
|
+
label: "Local search",
|
|
38
|
+
value: "search",
|
|
39
|
+
hint: "query engine for `skilld search` across all skill docs"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
label: "Release notes",
|
|
43
|
+
value: "releases",
|
|
44
|
+
hint: "changelogs and migration notes per version"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: "GitHub issues",
|
|
48
|
+
value: "issues",
|
|
49
|
+
hint: "common bugs, workarounds, and solutions",
|
|
50
|
+
disabled: !ghInstalled
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
label: "GitHub discussions",
|
|
54
|
+
value: "discussions",
|
|
55
|
+
hint: "community Q&A and usage examples",
|
|
56
|
+
disabled: !ghInstalled
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
initialValues: [...Object.entries(defaultFeatures).filter(([, v]) => v).map(([k]) => k), ...ghInstalled ? ["issues", "discussions"] : []],
|
|
60
|
+
required: false
|
|
61
|
+
});
|
|
62
|
+
if (p.isCancel(selected)) {
|
|
63
|
+
p.cancel("Setup cancelled");
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const features = {
|
|
67
|
+
search: selected.includes("search"),
|
|
68
|
+
issues: selected.includes("issues"),
|
|
69
|
+
discussions: selected.includes("discussions"),
|
|
70
|
+
releases: selected.includes("releases")
|
|
71
|
+
};
|
|
72
|
+
p.note(`An LLM can optionally summarize raw docs into a focused reference
|
|
73
|
+
highlighting best practices, gotchas, and migrations.
|
|
74
|
+
|
|
75
|
+
${styleText("bold", "Without LLM:")} ~2 KB skill with package metadata, types, and links\n${styleText("bold", "With LLM:")} ~5 KB skill with curated gotchas, patterns, and migration notes\n\n${styleText("bold", "This is a one-time build step")} - it generates the SKILL.md, then your\ncoding agent reads the result every session. Can be a different model.\n\n${styleText("gray", "Works with API keys (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY)\nor CLI tools (claude, gemini, codex).")}`, "Enhancement model (optional)");
|
|
76
|
+
let modelId;
|
|
77
|
+
let skippedEnhancement = false;
|
|
78
|
+
let oauthJustConnected = false;
|
|
79
|
+
while (true) {
|
|
80
|
+
const allModels = process.env.SKILLD_NO_AGENTS ? [] : await getAvailableModels();
|
|
81
|
+
if (allModels.length === 0) p.log.warn(NO_MODELS_MESSAGE);
|
|
82
|
+
else if (oauthJustConnected) p.log.step(`${allModels.length} models now available. Select one below.`);
|
|
83
|
+
else {
|
|
84
|
+
const providers = /* @__PURE__ */ new Set();
|
|
85
|
+
for (const m of allModels) {
|
|
86
|
+
const vendor = m.vendorGroup ?? m.providerName;
|
|
87
|
+
if (!m.id.startsWith("pi:")) providers.add(`${vendor} via CLI`);
|
|
88
|
+
else if (m.hint?.includes("API key")) providers.add(`${vendor} via API key`);
|
|
89
|
+
else if (m.hint?.includes("OAuth")) providers.add(`${vendor} via OAuth`);
|
|
90
|
+
}
|
|
91
|
+
if (providers.size > 0) p.log.success(`Found: ${[...providers].join(", ")}`);
|
|
92
|
+
}
|
|
93
|
+
const afterOptions = getOAuthProviderList().length > 0 ? [{
|
|
94
|
+
label: "⚠ Connect OAuth provider...",
|
|
95
|
+
value: "_connect",
|
|
96
|
+
hint: "may violate provider ToS"
|
|
97
|
+
}, {
|
|
98
|
+
label: "Skip enhancement",
|
|
99
|
+
value: "_skip",
|
|
100
|
+
hint: "base skill with docs, issues, and types, add LLM later via `skilld config`"
|
|
101
|
+
}] : [{
|
|
102
|
+
label: "Skip enhancement",
|
|
103
|
+
value: "_skip",
|
|
104
|
+
hint: "base skill with docs, issues, and types, add LLM later via `skilld config`"
|
|
105
|
+
}];
|
|
106
|
+
const choice = await pickModel(allModels, {
|
|
107
|
+
before: allModels.length > 0 ? [{
|
|
108
|
+
label: "Auto",
|
|
109
|
+
value: "_auto",
|
|
110
|
+
hint: "picks best available model from connected providers"
|
|
111
|
+
}] : [],
|
|
112
|
+
after: afterOptions
|
|
113
|
+
});
|
|
114
|
+
if (choice === null) {
|
|
115
|
+
p.cancel("Setup cancelled");
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (choice === "_connect") {
|
|
119
|
+
await wizardConnectProvider();
|
|
120
|
+
oauthJustConnected = true;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (choice === "_skip") {
|
|
124
|
+
skippedEnhancement = true;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
if (choice === "_auto") break;
|
|
128
|
+
modelId = choice;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
updateConfig({
|
|
132
|
+
features,
|
|
133
|
+
...modelId ? {
|
|
134
|
+
model: modelId,
|
|
135
|
+
skipLlm: false
|
|
136
|
+
} : {
|
|
137
|
+
model: void 0,
|
|
138
|
+
skipLlm: skippedEnhancement
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
const modelSummary = modelId ? getModelName(modelId) : skippedEnhancement ? "none (raw docs)" : "auto";
|
|
142
|
+
const featureList = Object.entries(features).filter(([, v]) => v).map(([k]) => k).join(", ") || "none";
|
|
143
|
+
p.log.success(`Model: ${modelSummary} · Features: ${featureList}`);
|
|
144
|
+
if (opts.showOutro !== false) p.note(`Run ${styleText("cyan", "skilld add <pkg>")} to generate skills for specific packages\nRun ${styleText("cyan", "skilld")} to scan your project and pick packages interactively\nRun ${styleText("cyan", "skilld config")} to change settings later`, "Setup complete");
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
async function wizardConnectProvider() {
|
|
148
|
+
p.note(OAUTH_NOTE, "How OAuth works");
|
|
149
|
+
const providers = getOAuthProviderList();
|
|
150
|
+
const provider = await p.select({
|
|
151
|
+
message: "Connect provider",
|
|
152
|
+
options: providers.map((pr) => ({
|
|
153
|
+
label: pr.name,
|
|
154
|
+
value: pr.id,
|
|
155
|
+
hint: pr.loggedIn ? "connected" : void 0
|
|
156
|
+
}))
|
|
157
|
+
});
|
|
158
|
+
if (p.isCancel(provider)) return;
|
|
159
|
+
const spinner = p.spinner();
|
|
160
|
+
spinner.start("Connecting...");
|
|
161
|
+
const success = await loginOAuthProvider(provider, {
|
|
162
|
+
onAuth: (url, instructions) => {
|
|
163
|
+
spinner.stop("Open this URL in your browser:");
|
|
164
|
+
p.log.info(` ${styleText("cyan", url)}`);
|
|
165
|
+
if (instructions) p.log.info(` ${styleText("gray", instructions)}`);
|
|
166
|
+
spinner.start("Waiting for authentication...");
|
|
167
|
+
},
|
|
168
|
+
onPrompt: async (message, placeholder) => {
|
|
169
|
+
const value = await p.text({
|
|
170
|
+
message,
|
|
171
|
+
placeholder
|
|
172
|
+
});
|
|
173
|
+
if (p.isCancel(value)) return "";
|
|
174
|
+
return value;
|
|
175
|
+
},
|
|
176
|
+
onProgress: (msg) => p.log.step(msg)
|
|
177
|
+
}).catch((err) => {
|
|
178
|
+
spinner.stop(`Login failed: ${err.message}`);
|
|
179
|
+
return false;
|
|
180
|
+
});
|
|
181
|
+
spinner.stop();
|
|
182
|
+
if (success) {
|
|
183
|
+
const name = providers.find((pr) => pr.id === provider)?.name ?? provider;
|
|
184
|
+
p.log.success(`Connected to ${name}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const setupCommandDef = defineCommand({
|
|
188
|
+
meta: {
|
|
189
|
+
name: "setup",
|
|
190
|
+
description: "Re-run the setup wizard to configure features and model"
|
|
191
|
+
},
|
|
192
|
+
args: { agent: sharedArgs.agent },
|
|
193
|
+
async run({ args }) {
|
|
194
|
+
const agent = resolveAgent(args.agent);
|
|
195
|
+
await runWizard({ agent: agent && agent !== "none" ? agent : void 0 });
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
export { setupCommandDef as n, runWizard as t };
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=wizard2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard2.mjs","names":["agents"],"sources":["../../src/commands/wizard.ts"],"sourcesContent":["import type { AgentType, OptimizeModel } from '../agent/index.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport { execSync } from 'node:child_process'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { getOAuthProviderList, loginOAuthProvider } from '../agent/clis/pi-ai.ts'\nimport { agents, getAvailableModels, getModelName } from '../agent/index.ts'\nimport { resolveAgent } from '../cli/agent-prompt.ts'\nimport { sharedArgs } from '../cli/args.ts'\nimport { isInteractive } from '../cli/env.ts'\nimport { NO_MODELS_MESSAGE, OAUTH_NOTE, pickModel } from '../cli/model-picker.ts'\nimport { defaultFeatures, updateConfig } from '../core/config.ts'\n\nfunction hasGhCli(): boolean {\n if (process.env.SKILLD_NO_GH)\n return false\n try {\n execSync('gh --version', { stdio: 'ignore' })\n return true\n }\n catch {\n return false\n }\n}\n\nexport interface WizardOptions {\n /** Resolved target agent, if known */\n agent?: AgentType\n /** Show next-steps outro when done (default: true) */\n showOutro?: boolean\n}\n\nexport async function runWizard(opts: WizardOptions = {}): Promise<boolean> {\n if (!isInteractive())\n return false\n\n const agentLabel = opts.agent ? agents[opts.agent].displayName : null\n const skillsDir = opts.agent ? agents[opts.agent].skillsDir : '.claude/skills'\n const agentLine = agentLabel\n ? `\\n${styleText('gray', `Target agent: ${agentLabel}`)}`\n : ''\n\n p.note(\n `Your AI agent reads docs from its training data - but APIs change,\\n`\n + `versions drift, and patterns go stale. Skilld fixes this.\\n`\n + `\\n`\n + `It generates a ${styleText('bold', 'SKILL.md')} - a markdown reference card built from\\n`\n + `the ${styleText('bold', 'actual docs, issues, and release notes')} for the exact\\n`\n + `package versions in your project. Your agent reads this file\\n`\n + `every session - no hallucinated APIs.\\n`\n + `\\n`\n + `${styleText('bold', 'How it works:')}\\n`\n + ` 1. Fetch docs, issues, and types for your packages\\n`\n + ` 2. Optionally compress with an LLM into a concise cheat sheet\\n`\n + `\\n`\n + `${styleText('gray', `Example: \\`skilld add vue\\` creates ${skillsDir}/vue-skilld/SKILL.md\\nYour agent then knows the right APIs, gotchas, and patterns\\nfor your exact version.`)}${agentLine}`,\n 'Welcome to skilld',\n )\n\n const ghInstalled = hasGhCli()\n\n if (ghInstalled) {\n p.log.success(\n 'GitHub CLI detected — will use it to pull issues and discussions.',\n )\n }\n else {\n p.log.info(\n `${styleText('gray', 'GitHub CLI not installed — issues and discussions disabled.')}\\n`\n + ` Install later to enable: ${styleText('cyan', 'https://cli.github.com')}`,\n )\n }\n\n // Feature toggles\n const selected = await p.multiselect({\n message: 'What data sources should skills include?',\n options: [\n { label: 'Local search', value: 'search' as const, hint: 'query engine for `skilld search` across all skill docs' },\n { label: 'Release notes', value: 'releases' as const, hint: 'changelogs and migration notes per version' },\n { label: 'GitHub issues', value: 'issues' as const, hint: 'common bugs, workarounds, and solutions', disabled: !ghInstalled },\n { label: 'GitHub discussions', value: 'discussions' as const, hint: 'community Q&A and usage examples', disabled: !ghInstalled },\n ],\n initialValues: [\n ...Object.entries(defaultFeatures)\n .filter(([, v]) => v)\n .map(([k]) => k),\n ...(ghInstalled ? ['issues', 'discussions'] as const : []),\n ] as Array<keyof FeaturesConfig>,\n required: false,\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Setup cancelled')\n return false\n }\n\n const features: FeaturesConfig = {\n search: selected.includes('search'),\n issues: selected.includes('issues'),\n discussions: selected.includes('discussions'),\n releases: selected.includes('releases'),\n }\n\n // Enhancement model - optional, independent of target agent\n p.note(\n `An LLM can optionally summarize raw docs into a focused reference\\n`\n + `highlighting best practices, gotchas, and migrations.\\n`\n + `\\n`\n + `${styleText('bold', 'Without LLM:')} ~2 KB skill with package metadata, types, and links\\n`\n + `${styleText('bold', 'With LLM:')} ~5 KB skill with curated gotchas, patterns, and migration notes\\n`\n + `\\n`\n + `${styleText('bold', 'This is a one-time build step')} - it generates the SKILL.md, then your\\n`\n + `coding agent reads the result every session. Can be a different model.\\n`\n + `\\n`\n + `${styleText('gray', 'Works with API keys (ANTHROPIC_API_KEY, GEMINI_API_KEY, OPENAI_API_KEY)\\nor CLI tools (claude, gemini, codex).')}`,\n 'Enhancement model (optional)',\n )\n\n let modelId: OptimizeModel | undefined\n let skippedEnhancement = false\n let oauthJustConnected = false\n\n // Loop so user can connect OAuth then come back to pick a model\n while (true) {\n const allModels = process.env.SKILLD_NO_AGENTS ? [] : await getAvailableModels()\n\n if (allModels.length === 0) {\n p.log.warn(NO_MODELS_MESSAGE)\n }\n else if (oauthJustConnected) {\n p.log.step(`${allModels.length} models now available. Select one below.`)\n }\n else {\n // Show which providers were found by name (e.g. \"Anthropic via CLI, OpenAI via API key\")\n const providers = new Set<string>()\n for (const m of allModels) {\n const vendor = m.vendorGroup ?? m.providerName\n if (!m.id.startsWith('pi:'))\n providers.add(`${vendor} via CLI`)\n else if (m.hint?.includes('API key'))\n providers.add(`${vendor} via API key`)\n else if (m.hint?.includes('OAuth'))\n providers.add(`${vendor} via OAuth`)\n }\n if (providers.size > 0)\n p.log.success(`Found: ${[...providers].join(', ')}`)\n }\n\n const oauthProviders = getOAuthProviderList()\n const afterOptions = oauthProviders.length > 0\n ? [\n { label: '⚠ Connect OAuth provider...', value: '_connect', hint: 'may violate provider ToS' },\n { label: 'Skip enhancement', value: '_skip', hint: 'base skill with docs, issues, and types, add LLM later via `skilld config`' },\n ]\n : [\n { label: 'Skip enhancement', value: '_skip', hint: 'base skill with docs, issues, and types, add LLM later via `skilld config`' },\n ]\n\n const choice = await pickModel(allModels, {\n before: allModels.length > 0\n ? [{ label: 'Auto', value: '_auto', hint: 'picks best available model from connected providers' }]\n : [],\n after: afterOptions,\n })\n\n if (choice === null) {\n p.cancel('Setup cancelled')\n return false\n }\n\n if (choice === '_connect') {\n await wizardConnectProvider()\n oauthJustConnected = true\n continue\n }\n\n if (choice === '_skip') {\n skippedEnhancement = true\n break\n }\n if (choice === '_auto')\n break\n\n modelId = choice as OptimizeModel\n break\n }\n\n updateConfig({\n features,\n ...(modelId\n ? { model: modelId, skipLlm: false }\n : { model: undefined, skipLlm: skippedEnhancement }),\n })\n\n // Summary of what was saved\n const modelSummary = modelId\n ? getModelName(modelId)\n : skippedEnhancement\n ? 'none (raw docs)'\n : 'auto'\n const featureList = Object.entries(features).filter(([, v]) => v).map(([k]) => k).join(', ') || 'none'\n p.log.success(`Model: ${modelSummary} · Features: ${featureList}`)\n\n if (opts.showOutro !== false) {\n p.note(\n `Run ${styleText('cyan', 'skilld add <pkg>')} to generate skills for specific packages\\n`\n + `Run ${styleText('cyan', 'skilld')} to scan your project and pick packages interactively\\n`\n + `Run ${styleText('cyan', 'skilld config')} to change settings later`,\n 'Setup complete',\n )\n }\n return true\n}\n\nasync function wizardConnectProvider(): Promise<void> {\n p.note(OAUTH_NOTE, 'How OAuth works')\n\n const providers = getOAuthProviderList()\n const provider = await p.select({\n message: 'Connect provider',\n options: providers.map(pr => ({\n label: pr.name,\n value: pr.id,\n hint: pr.loggedIn ? 'connected' : undefined,\n })),\n })\n\n if (p.isCancel(provider))\n return\n\n const spinner = p.spinner()\n spinner.start('Connecting...')\n\n const success = await loginOAuthProvider(provider as string, {\n onAuth: (url, instructions) => {\n spinner.stop('Open this URL in your browser:')\n p.log.info(` ${styleText('cyan', url)}`)\n if (instructions)\n p.log.info(` ${styleText('gray', instructions)}`)\n spinner.start('Waiting for authentication...')\n },\n onPrompt: async (message, placeholder) => {\n const value = await p.text({ message, placeholder })\n if (p.isCancel(value))\n return ''\n return value as string\n },\n onProgress: msg => p.log.step(msg),\n }).catch((err: Error) => {\n spinner.stop(`Login failed: ${err.message}`)\n return false\n })\n\n spinner.stop()\n\n if (success) {\n const name = providers.find(pr => pr.id === provider)?.name ?? provider\n p.log.success(`Connected to ${name}`)\n }\n}\n\nexport const setupCommandDef = defineCommand({\n meta: {\n name: 'setup',\n description: 'Re-run the setup wizard to configure features and model',\n },\n args: {\n agent: sharedArgs.agent,\n },\n async run({ args }) {\n const agent = resolveAgent(args.agent)\n await runWizard({\n agent: agent && agent !== 'none' ? agent as AgentType : undefined,\n })\n },\n})\n"],"mappings":"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"}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { d as getSharedSkillsDir, l as getPackageDbPath, p as skillInternalDir, t as CACHE_DIR } from "./_chunks/paths.mjs";
|
|
3
|
-
import { L as updateConfig, M as hasCompletedWizard, N as hasConfig, P as readConfig, k as defaultFeatures } from "./_chunks/cache.mjs";
|
|
4
|
-
import { i as readPackageJsonSafe } from "./_chunks/package-json.mjs";
|
|
5
|
-
import { t as getCacheDir } from "./_chunks/version.mjs";
|
|
6
|
-
import { X as mapInsert, a as toStoragePackageName, c as fetchNpmRegistryMeta, i as resolveSkillName, o as fetchLatestVersion } from "./_chunks/sources.mjs";
|
|
7
2
|
import { a as targets, i as getAgentVersion, r as detectTargetAgent, t as detectInstalledAgents } from "./_chunks/detect.mjs";
|
|
8
3
|
import { a as getModelName, c as getOAuthProviderList, l as loginOAuthProvider, n as detectImportedPackages, r as getAvailableModels, u as logoutOAuthProvider } from "./_chunks/agent.mjs";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
4
|
+
import { h as timedSpinner, m as timeAgo, o as unlinkSkillFromAgents, u as formatSource } from "./_chunks/prompts.mjs";
|
|
5
|
+
import { f as getSharedSkillsDir, m as skillInternalDir, n as CACHE_DIR, u as getPackageDbPath } from "./_chunks/paths.mjs";
|
|
6
|
+
import { h as VERSION_RANGE_PREFIX_RE, n as COMMA_OR_WHITESPACE_RE } from "./_chunks/regex.mjs";
|
|
7
|
+
import { s as getCacheDir } from "./_chunks/prepare.mjs";
|
|
8
|
+
import { i as readPackageJsonSafe } from "./_chunks/package-json.mjs";
|
|
9
|
+
import { d as readConfig, l as hasCompletedWizard, m as updateConfig, o as defaultFeatures, u as hasConfig } from "./_chunks/cache.mjs";
|
|
10
|
+
import { n as isRunningInsideAgent, r as requireInteractive, t as isInteractive } from "./_chunks/env.mjs";
|
|
11
|
+
import { n as promptForAgent, r as resolveAgent } from "./_chunks/agent-prompt.mjs";
|
|
12
|
+
import { t as sharedArgs } from "./_chunks/args.mjs";
|
|
13
|
+
import { t as version } from "./_chunks/version.mjs";
|
|
14
|
+
import { a as relativeTime, i as introLine, n as getInstalledGenerators, r as getRepoHint, t as formatStatus } from "./_chunks/intro.mjs";
|
|
15
|
+
import { n as menuLoop, t as guard } from "./_chunks/menu.mjs";
|
|
16
|
+
import { n as hasPrepareHook, r as suggestPrepareHook } from "./_chunks/prepare-hook2.mjs";
|
|
17
|
+
import { n as OAUTH_NOTE, r as pickModel, t as NO_MODELS_MESSAGE } from "./_chunks/model-picker.mjs";
|
|
18
|
+
import { c as resolveSkillName, f as fetchNpmRegistryMeta, l as toStoragePackageName, n as semverGt, u as fetchLatestVersion } from "./_chunks/semver.mjs";
|
|
19
|
+
import { t as mapInsert } from "./_chunks/map.mjs";
|
|
11
20
|
import { l as removeLockEntry, o as parsePackages } from "./_chunks/lockfile.mjs";
|
|
12
|
-
import { n as semverGt } from "./_chunks/semver.mjs";
|
|
13
21
|
import { i as iterateSkills, n as getSkillsDir, r as isOutdated, t as getProjectState } from "./_chunks/skills.mjs";
|
|
14
|
-
import { t as runWizard } from "./_chunks/
|
|
22
|
+
import { t as runWizard } from "./_chunks/wizard2.mjs";
|
|
15
23
|
import "./_chunks/core.mjs";
|
|
16
24
|
import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
|
|
17
|
-
import {
|
|
18
|
-
import pLimit from "p-limit";
|
|
25
|
+
import { styleText } from "node:util";
|
|
19
26
|
import * as p from "@clack/prompts";
|
|
20
27
|
import { defineCommand, runMain } from "citty";
|
|
28
|
+
import pLimit from "p-limit";
|
|
29
|
+
import { join, resolve } from "pathe";
|
|
21
30
|
import logUpdate from "log-update";
|
|
22
31
|
async function configCommand() {
|
|
23
32
|
const initConfig = readConfig();
|
|
24
33
|
const agentId = initConfig.agent || detectTargetAgent() || void 0;
|
|
25
|
-
const cyan = (s) =>
|
|
34
|
+
const cyan = (s) => styleText("cyan", s);
|
|
26
35
|
const modelLabel = initConfig.skipLlm ? "skip" : initConfig.model ? cyan(getModelName(initConfig.model)) : "auto";
|
|
27
36
|
const agentLabel = agentId && targets[agentId] ? cyan(targets[agentId].displayName) : "auto-detect";
|
|
28
|
-
p.note(
|
|
37
|
+
p.note(styleText("gray", `Fetch docs → Enhance with ${modelLabel} → Install to ${agentLabel}`), "How skilld works");
|
|
29
38
|
await menuLoop({
|
|
30
39
|
message: "Settings",
|
|
31
40
|
options: () => {
|
|
@@ -135,7 +144,7 @@ async function configureOAuth() {
|
|
|
135
144
|
return getOAuthProviderList().map((pr) => ({
|
|
136
145
|
label: pr.name,
|
|
137
146
|
value: pr.id,
|
|
138
|
-
hint: pr.loggedIn ? "
|
|
147
|
+
hint: pr.loggedIn ? styleText("green", "connected") : "not connected"
|
|
139
148
|
}));
|
|
140
149
|
},
|
|
141
150
|
onSelect: async (providerId) => {
|
|
@@ -162,8 +171,8 @@ async function configureOAuth() {
|
|
|
162
171
|
const success = await loginOAuthProvider(providerId, {
|
|
163
172
|
onAuth: (url, instructions) => {
|
|
164
173
|
spinner.stop("Open this URL in your browser:");
|
|
165
|
-
p.log.info(`
|
|
166
|
-
if (instructions) p.log.info(`
|
|
174
|
+
p.log.info(` ${styleText("cyan", url)}`);
|
|
175
|
+
if (instructions) p.log.info(` ${styleText("gray", instructions)}`);
|
|
167
176
|
spinner.start("Waiting for authentication...");
|
|
168
177
|
},
|
|
169
178
|
onPrompt: async (message, placeholder) => {
|
|
@@ -343,7 +352,7 @@ const removeCommandDef = defineCommand({
|
|
|
343
352
|
packages: args.package ? [...new Set([args.package, ...args._ || []].map((s) => s.trim()).filter(Boolean).map((s) => {
|
|
344
353
|
const name = resolveSkillName(s);
|
|
345
354
|
if (!name) {
|
|
346
|
-
p.log.warn(`Cannot remove
|
|
355
|
+
p.log.warn(`Cannot remove ${styleText("cyan", s)}: curator/collection inputs are not addressable here.`);
|
|
347
356
|
return null;
|
|
348
357
|
}
|
|
349
358
|
return name;
|
|
@@ -409,9 +418,9 @@ function countRefDocs(skillDir) {
|
|
|
409
418
|
walk(refsDir);
|
|
410
419
|
return count;
|
|
411
420
|
}
|
|
412
|
-
const dim = (s) =>
|
|
413
|
-
const bold = (s) =>
|
|
414
|
-
const green = (s) =>
|
|
421
|
+
const dim = (s) => styleText("gray", s);
|
|
422
|
+
const bold = (s) => styleText("bold", s);
|
|
423
|
+
const green = (s) => styleText("green", s);
|
|
415
424
|
function getLastSynced() {
|
|
416
425
|
let latest = null;
|
|
417
426
|
for (const skill of iterateSkills()) if (skill.info?.syncedAt) {
|
|
@@ -581,8 +590,8 @@ function brandFrame(t, floor = 0, density = 0) {
|
|
|
581
590
|
async function brandLoader(work, minMs = 1500) {
|
|
582
591
|
if (process.env.SKILLD_EFFECT === "none") return work();
|
|
583
592
|
const name = "\x1B[1m\x1B[38;2;255;255;255mskilld\x1B[0m";
|
|
584
|
-
const verStr =
|
|
585
|
-
const status = "
|
|
593
|
+
const verStr = styleText("dim", `v${version}`);
|
|
594
|
+
const status = styleText("dim", "Setting up your environment");
|
|
586
595
|
const start = Date.now();
|
|
587
596
|
const sub = (raw) => raw.replace("%NAME%", name).replace("%VER%", verStr);
|
|
588
597
|
let done = false;
|
|
@@ -607,6 +616,7 @@ async function brandLoader(work, minMs = 1500) {
|
|
|
607
616
|
logUpdate.done();
|
|
608
617
|
return result;
|
|
609
618
|
}
|
|
619
|
+
const STATIC_REGEX_3 = /^[\^~>=<]/;
|
|
610
620
|
const _emit = process.emit;
|
|
611
621
|
process.emit = (event, ...args) => event === "warning" && args[0]?.name === "ExperimentalWarning" && args[0]?.message?.includes("SQLite") ? false : _emit.apply(process, [event, ...args]);
|
|
612
622
|
function deprecatedForwarder(oldName, newName, loader) {
|
|
@@ -619,7 +629,7 @@ function deprecatedForwarder(oldName, newName, loader) {
|
|
|
619
629
|
name: oldName
|
|
620
630
|
},
|
|
621
631
|
async run(ctx) {
|
|
622
|
-
console.warn(
|
|
632
|
+
console.warn(styleText("yellow", `⚠ \`skilld ${oldName}\` is deprecated. Use \`skilld ${newName}\` instead.`));
|
|
623
633
|
return original(ctx);
|
|
624
634
|
}
|
|
625
635
|
});
|
|
@@ -643,7 +653,11 @@ const SUBCOMMAND_NAMES = [
|
|
|
643
653
|
"prepare",
|
|
644
654
|
"author",
|
|
645
655
|
"publish",
|
|
646
|
-
"upload"
|
|
656
|
+
"upload",
|
|
657
|
+
"login",
|
|
658
|
+
"logout",
|
|
659
|
+
"whoami",
|
|
660
|
+
"pull"
|
|
647
661
|
];
|
|
648
662
|
runMain(defineCommand({
|
|
649
663
|
meta: {
|
|
@@ -653,8 +667,8 @@ runMain(defineCommand({
|
|
|
653
667
|
},
|
|
654
668
|
args: { agent: sharedArgs.agent },
|
|
655
669
|
subCommands: {
|
|
656
|
-
add: () => import("./_chunks/
|
|
657
|
-
update: () => import("./_chunks/
|
|
670
|
+
add: () => import("./_chunks/add.mjs").then((m) => m.addCommandDef),
|
|
671
|
+
update: () => import("./_chunks/update.mjs").then((m) => m.updateCommandDef),
|
|
658
672
|
info: () => infoCommandDef,
|
|
659
673
|
list: () => import("./_chunks/list.mjs").then((m) => m.listCommandDef),
|
|
660
674
|
config: () => configCommandDef,
|
|
@@ -664,9 +678,13 @@ runMain(defineCommand({
|
|
|
664
678
|
uninstall: () => import("./_chunks/uninstall.mjs").then((m) => m.uninstallCommandDef),
|
|
665
679
|
search: () => import("./_chunks/search.mjs").then((m) => m.searchCommandDef),
|
|
666
680
|
cache: () => import("./_chunks/cache2.mjs").then((m) => m.cacheCommandDef),
|
|
667
|
-
setup: () => import("./_chunks/
|
|
668
|
-
|
|
669
|
-
|
|
681
|
+
setup: () => import("./_chunks/wizard.mjs").then((m) => m.setupCommandDef),
|
|
682
|
+
login: () => import("./_chunks/login.mjs").then((m) => m.loginCommandDef),
|
|
683
|
+
logout: () => import("./_chunks/logout.mjs").then((m) => m.logoutCommandDef),
|
|
684
|
+
whoami: () => import("./_chunks/whoami.mjs").then((m) => m.whoamiCommandDef),
|
|
685
|
+
pull: () => import("./_chunks/pull.mjs").then((m) => m.pullCommandDef),
|
|
686
|
+
author: () => import("./_chunks/author.mjs").then((m) => m.authorGroupDef),
|
|
687
|
+
eject: deprecatedForwarder("eject", "author eject", () => import("./_chunks/eject.mjs").then((m) => m.ejectCommandDef)),
|
|
670
688
|
validate: deprecatedForwarder("validate", "author validate", () => import("./_chunks/validate.mjs").then((m) => m.validateCommandDef)),
|
|
671
689
|
assemble: deprecatedForwarder("assemble", "author assemble", () => import("./_chunks/assemble.mjs").then((m) => m.assembleCommandDef)),
|
|
672
690
|
publish: deprecatedForwarder("publish", "author publish", () => import("./_chunks/upload.mjs").then((m) => m.uploadCommandDef)),
|
|
@@ -692,7 +710,8 @@ runMain(defineCommand({
|
|
|
692
710
|
if (!hasCompletedWizard()) {
|
|
693
711
|
if (!await runWizard()) return;
|
|
694
712
|
}
|
|
695
|
-
p.log.info(
|
|
713
|
+
p.log.info(`No agent selected - skills export as portable PROMPT_*.md files.
|
|
714
|
+
Run ${styleText("cyan", "skilld add <pkg>")} to generate prompts for any package.\n Run ${styleText("cyan", "skilld config")} to set a target agent later.`);
|
|
696
715
|
return;
|
|
697
716
|
}
|
|
698
717
|
const agent = currentAgent;
|
|
@@ -733,9 +752,9 @@ runMain(defineCommand({
|
|
|
733
752
|
};
|
|
734
753
|
});
|
|
735
754
|
if (selfUpdate) {
|
|
736
|
-
const released = selfUpdate.releasedAt ?
|
|
755
|
+
const released = selfUpdate.releasedAt ? styleText("gray", ` · ${relativeTime(new Date(selfUpdate.releasedAt))}`) : "";
|
|
737
756
|
const cmd = `npx nypm add${realpathSync(process.argv[1]).startsWith(resolve(cwd, "node_modules")) ? "" : " -g"} skilld@${selfUpdate.latest}`;
|
|
738
|
-
p.note(
|
|
757
|
+
p.note(`${styleText("gray", version)} → ${styleText(["bold", "green"], selfUpdate.latest)}${released}\n${styleText("cyan", cmd)}`, styleText("yellow", "Update available"));
|
|
739
758
|
}
|
|
740
759
|
if (state.skills.length === 0) {
|
|
741
760
|
if (!hasCompletedWizard()) {
|
|
@@ -747,13 +766,13 @@ runMain(defineCommand({
|
|
|
747
766
|
const projectPkg = readPackageJsonSafe(join(cwd, "package.json"));
|
|
748
767
|
const hasPkgJson = !!projectPkg;
|
|
749
768
|
const projectName = projectPkg?.parsed.name;
|
|
750
|
-
const projectLabel = projectName ? `Generating skills for
|
|
769
|
+
const projectLabel = projectName ? `Generating skills for ${styleText("cyan", projectName)}` : "Generating skills for current directory";
|
|
751
770
|
p.log.step(projectLabel);
|
|
752
771
|
if (!hasPkgJson) p.log.warn("No package.json found - enter npm package names manually.\n For best results, run skilld inside a JS/TS project directory.");
|
|
753
772
|
if (state.shipped.length > 0) {
|
|
754
773
|
const totalShipped = state.shipped.reduce((sum, s) => sum + s.skills.length, 0);
|
|
755
774
|
const names = state.shipped.map((s) => s.packageName).join(", ");
|
|
756
|
-
p.log.info(
|
|
775
|
+
p.log.info(`${styleText("cyan", `${totalShipped} ready-to-use skill${totalShipped > 1 ? "s" : ""}`)} shipped by your dependencies: ${names}`);
|
|
757
776
|
}
|
|
758
777
|
p.log.info("Tip: Add skills for packages with complex APIs or frequent breaking changes - not every dependency needs one.");
|
|
759
778
|
let setupComplete = false;
|
|
@@ -761,7 +780,7 @@ runMain(defineCommand({
|
|
|
761
780
|
const shippedOption = state.shipped.length > 0 ? [{
|
|
762
781
|
label: "Install shipped skills",
|
|
763
782
|
value: "shipped",
|
|
764
|
-
hint:
|
|
783
|
+
hint: styleText("cyan", `${state.shipped.reduce((sum, s) => sum + s.skills.length, 0)} ready to use`)
|
|
765
784
|
}] : [];
|
|
766
785
|
const source = hasPkgJson ? await p.select({
|
|
767
786
|
message: "How should I find packages?",
|
|
@@ -793,13 +812,13 @@ runMain(defineCommand({
|
|
|
793
812
|
return;
|
|
794
813
|
}
|
|
795
814
|
if (source === "skip") {
|
|
796
|
-
p.log.info(
|
|
815
|
+
p.log.info(`Run ${styleText("cyan", "skilld add <pkg>")} or ${styleText("cyan", "skilld")} anytime to add skills.`);
|
|
797
816
|
return;
|
|
798
817
|
}
|
|
799
818
|
if (source === "shipped") {
|
|
800
819
|
const { handleShippedSkills: installShipped } = await import("./_chunks/skill-installer.mjs");
|
|
801
820
|
for (const pkg of state.shipped) {
|
|
802
|
-
const version = state.deps.get(pkg.packageName)?.replace(
|
|
821
|
+
const version = state.deps.get(pkg.packageName)?.replace(VERSION_RANGE_PREFIX_RE, "") || "0.0.0";
|
|
803
822
|
installShipped(pkg.packageName, version, cwd, agent, false);
|
|
804
823
|
for (const sk of pkg.skills) p.log.success(`Installed shipped skill: ${sk.skillName}`);
|
|
805
824
|
}
|
|
@@ -823,7 +842,7 @@ runMain(defineCommand({
|
|
|
823
842
|
p.log.warn("No packages entered");
|
|
824
843
|
continue;
|
|
825
844
|
}
|
|
826
|
-
selected = input.split(
|
|
845
|
+
selected = input.split(COMMA_OR_WHITESPACE_RE).map((s) => s.trim()).filter(Boolean);
|
|
827
846
|
if (selected.length === 0) {
|
|
828
847
|
p.log.warn("No valid packages entered");
|
|
829
848
|
continue;
|
|
@@ -879,7 +898,7 @@ runMain(defineCommand({
|
|
|
879
898
|
const choice = await p.multiselect({
|
|
880
899
|
message: `Select packages (${packages.length} found)`,
|
|
881
900
|
options: packages.map((name) => {
|
|
882
|
-
const ver = state.deps.get(name)?.replace(
|
|
901
|
+
const ver = state.deps.get(name)?.replace(STATIC_REGEX_3, "") || "";
|
|
883
902
|
const repo = getRepoHint(name, cwd);
|
|
884
903
|
const hint = sourceMap.get(name) === "preset" ? "nuxt module" : void 0;
|
|
885
904
|
const pad = " ".repeat(maxLen - name.length + 2);
|
|
@@ -889,7 +908,7 @@ runMain(defineCommand({
|
|
|
889
908
|
repo
|
|
890
909
|
].filter(Boolean).join(" ");
|
|
891
910
|
return {
|
|
892
|
-
label: meta ? `${name}${pad}
|
|
911
|
+
label: meta ? `${name}${pad}${styleText("gray", meta)}` : name,
|
|
893
912
|
value: name
|
|
894
913
|
};
|
|
895
914
|
}),
|
|
@@ -920,7 +939,7 @@ runMain(defineCommand({
|
|
|
920
939
|
const previewContent = readFileSync(previewPath, "utf-8");
|
|
921
940
|
const previewLines = previewContent.split("\n").slice(0, 20).join("\n").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").replace(/\x1B\].*?(?:\x07|\x1B\\)/g, "");
|
|
922
941
|
const fileSize = (Buffer.byteLength(previewContent) / 1024).toFixed(1);
|
|
923
|
-
p.note(
|
|
942
|
+
p.note(styleText("gray", `${previewLines}\n...`), `${targets[agent].skillsDir}/${previewSkill.name}/SKILL.md (${fileSize} KB)`);
|
|
924
943
|
}
|
|
925
944
|
}
|
|
926
945
|
const agentName = targets[agent].displayName;
|
|
@@ -936,10 +955,10 @@ runMain(defineCommand({
|
|
|
936
955
|
"amp": "Start a new Amp session.\nReads skill descriptions at startup, full content on invocation.",
|
|
937
956
|
"opencode": "Start a new OpenCode session.\nSkills are discovered automatically at startup.",
|
|
938
957
|
"roo": "Restart your editor. Roo reads skill descriptions at startup."
|
|
939
|
-
}[agent] ?? "" : `Skills are ready in ${targets[agent].skillsDir}/.\n
|
|
958
|
+
}[agent] ?? "" : `Skills are ready in ${targets[agent].skillsDir}/.\n${styleText("gray", `${agentName} was not detected on this machine.\nInstall it to use these skills, or run \`skilld config\` to change agents.`)}`;
|
|
940
959
|
const firstPkg = previewSkill?.info?.packageName || previewSkill?.name;
|
|
941
|
-
const trySuggestion = firstPkg ? `\n\n
|
|
942
|
-
p.note(`${verifyLine}${trySuggestion}\n\nRun
|
|
960
|
+
const trySuggestion = firstPkg ? `\n\n${styleText("cyan", "Try it:")} ask your agent "What are the gotchas or breaking changes in ${firstPkg}?"` : "";
|
|
961
|
+
p.note(`${verifyLine}${trySuggestion}\n\nRun ${styleText("cyan", "skilld info")} to see installed skills.\nRun ${styleText("cyan", "skilld")} again to add more, update, or search.`, `${agentName} - next steps`);
|
|
943
962
|
try {
|
|
944
963
|
await suggestPrepareHook(cwd);
|
|
945
964
|
} catch (err) {
|
|
@@ -950,11 +969,11 @@ runMain(defineCommand({
|
|
|
950
969
|
const status = formatStatus(state.synced.length, state.outdated.length);
|
|
951
970
|
p.log.info(status);
|
|
952
971
|
let needsPrepareHook = !hasPrepareHook(cwd);
|
|
953
|
-
if (needsPrepareHook) p.log.warn(
|
|
972
|
+
if (needsPrepareHook) p.log.warn(`${styleText("yellow", "No prepare hook.")} Skills won't auto-restore on ${styleText("cyan", "npm install")}.`);
|
|
954
973
|
if (state.shipped.length > 0) {
|
|
955
974
|
const totalSkills = state.shipped.reduce((sum, s) => sum + s.skills.length, 0);
|
|
956
975
|
const names = state.shipped.map((s) => s.packageName).join(", ");
|
|
957
|
-
p.log.info(
|
|
976
|
+
p.log.info(`${styleText("cyan", `${totalSkills} ready-to-use skill${totalSkills > 1 ? "s" : ""}`)} shipped by your dependencies: ${names}`);
|
|
958
977
|
}
|
|
959
978
|
const refreshState = async () => {
|
|
960
979
|
state = await getProjectState(cwd);
|
|
@@ -968,7 +987,7 @@ runMain(defineCommand({
|
|
|
968
987
|
opts.push({
|
|
969
988
|
label: "Install shipped skills",
|
|
970
989
|
value: "shipped",
|
|
971
|
-
hint:
|
|
990
|
+
hint: styleText("cyan", `${total} available`)
|
|
972
991
|
});
|
|
973
992
|
}
|
|
974
993
|
opts.push({
|
|
@@ -978,12 +997,12 @@ runMain(defineCommand({
|
|
|
978
997
|
if (state.outdated.length > 0) opts.push({
|
|
979
998
|
label: "Update skills",
|
|
980
999
|
value: "update",
|
|
981
|
-
hint:
|
|
1000
|
+
hint: styleText("yellow", `${state.outdated.length} outdated`)
|
|
982
1001
|
});
|
|
983
1002
|
if (needsPrepareHook) opts.push({
|
|
984
1003
|
label: "Setup prepare hook",
|
|
985
1004
|
value: "prepare-hook",
|
|
986
|
-
hint: "
|
|
1005
|
+
hint: styleText("yellow", "recommended")
|
|
987
1006
|
});
|
|
988
1007
|
opts.push({
|
|
989
1008
|
label: "Remove skills",
|
|
@@ -1022,7 +1041,7 @@ runMain(defineCommand({
|
|
|
1022
1041
|
for (const s of selected) {
|
|
1023
1042
|
if (seen.has(s.packageName)) continue;
|
|
1024
1043
|
seen.add(s.packageName);
|
|
1025
|
-
const version = state.deps.get(s.packageName)?.replace(
|
|
1044
|
+
const version = state.deps.get(s.packageName)?.replace(VERSION_RANGE_PREFIX_RE, "") || "0.0.0";
|
|
1026
1045
|
installShipped(s.packageName, version, cwd, agent, false);
|
|
1027
1046
|
}
|
|
1028
1047
|
p.log.success(`Installed ${selected.length} shipped skill${selected.length > 1 ? "s" : ""}`);
|
|
@@ -1061,7 +1080,7 @@ runMain(defineCommand({
|
|
|
1061
1080
|
placeholder: "vue nuxt pinia"
|
|
1062
1081
|
}));
|
|
1063
1082
|
if (!input) return;
|
|
1064
|
-
selected = input.split(
|
|
1083
|
+
selected = input.split(COMMA_OR_WHITESPACE_RE).map((s) => s.trim()).filter(Boolean);
|
|
1065
1084
|
if (selected.length === 0) return;
|
|
1066
1085
|
} else {
|
|
1067
1086
|
let usages;
|
|
@@ -1117,7 +1136,7 @@ runMain(defineCommand({
|
|
|
1117
1136
|
const choice = guard(await p.multiselect({
|
|
1118
1137
|
message: `Select packages your agent struggles with or that are new to you (${packages.length} found)`,
|
|
1119
1138
|
options: packages.map((name) => {
|
|
1120
|
-
const ver = state.deps.get(name)?.replace(
|
|
1139
|
+
const ver = state.deps.get(name)?.replace(STATIC_REGEX_3, "") || "";
|
|
1121
1140
|
const repo = getRepoHint(name, cwd);
|
|
1122
1141
|
const hint = sourceMap.get(name) === "preset" ? "nuxt module" : frameworks.has(name) ? "framework" : (usageMap.get(name)?.count ?? 0) >= 5 ? `${usageMap.get(name).count} imports` : void 0;
|
|
1123
1142
|
const pad = " ".repeat(maxLen - name.length + 2);
|
|
@@ -1127,7 +1146,7 @@ runMain(defineCommand({
|
|
|
1127
1146
|
repo
|
|
1128
1147
|
].filter(Boolean).join(" ");
|
|
1129
1148
|
return {
|
|
1130
|
-
label: meta ? `${name}${pad}
|
|
1149
|
+
label: meta ? `${name}${pad}${styleText("gray", meta)}` : name,
|
|
1131
1150
|
value: name
|
|
1132
1151
|
};
|
|
1133
1152
|
}),
|