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.
Files changed (156) hide show
  1. package/dist/_chunks/add.mjs +66 -0
  2. package/dist/_chunks/add.mjs.map +1 -0
  3. package/dist/_chunks/agent-prompt.mjs +88 -0
  4. package/dist/_chunks/agent-prompt.mjs.map +1 -0
  5. package/dist/_chunks/agent.mjs +81 -57
  6. package/dist/_chunks/agent.mjs.map +1 -1
  7. package/dist/_chunks/args.mjs +42 -0
  8. package/dist/_chunks/args.mjs.map +1 -0
  9. package/dist/_chunks/assemble.mjs +10 -7
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +33 -17
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +143 -183
  14. package/dist/_chunks/cache.mjs.map +1 -1
  15. package/dist/_chunks/cache2.mjs +7 -6
  16. package/dist/_chunks/cache2.mjs.map +1 -1
  17. package/dist/_chunks/client.mjs +117 -0
  18. package/dist/_chunks/client.mjs.map +1 -0
  19. package/dist/_chunks/core.mjs +5 -5
  20. package/dist/_chunks/detect.mjs +53 -43
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/eject.mjs +69 -0
  23. package/dist/_chunks/eject.mjs.map +1 -0
  24. package/dist/_chunks/embedding-cache2.mjs +1 -1
  25. package/dist/_chunks/env.mjs +19 -0
  26. package/dist/_chunks/env.mjs.map +1 -0
  27. package/dist/_chunks/install-many.mjs +376 -0
  28. package/dist/_chunks/install-many.mjs.map +1 -0
  29. package/dist/_chunks/install.mjs +81 -326
  30. package/dist/_chunks/install.mjs.map +1 -1
  31. package/dist/_chunks/intro.mjs +63 -0
  32. package/dist/_chunks/intro.mjs.map +1 -0
  33. package/dist/_chunks/list.mjs +2 -2
  34. package/dist/_chunks/list.mjs.map +1 -1
  35. package/dist/_chunks/lockfile.mjs +3 -2
  36. package/dist/_chunks/lockfile.mjs.map +1 -1
  37. package/dist/_chunks/login.mjs +233 -0
  38. package/dist/_chunks/login.mjs.map +1 -0
  39. package/dist/_chunks/logout.mjs +27 -0
  40. package/dist/_chunks/logout.mjs.map +1 -0
  41. package/dist/_chunks/map.mjs +11 -0
  42. package/dist/_chunks/map.mjs.map +1 -0
  43. package/dist/_chunks/markdown.mjs +79 -54
  44. package/dist/_chunks/markdown.mjs.map +1 -1
  45. package/dist/_chunks/menu.mjs +33 -0
  46. package/dist/_chunks/menu.mjs.map +1 -0
  47. package/dist/_chunks/model-picker.mjs +61 -0
  48. package/dist/_chunks/model-picker.mjs.map +1 -0
  49. package/dist/_chunks/monorepo.mjs +4 -2
  50. package/dist/_chunks/monorepo.mjs.map +1 -1
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +3 -5
  53. package/dist/_chunks/paths.mjs.map +1 -1
  54. package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +1 -1
  57. package/dist/_chunks/portable.mjs +151 -0
  58. package/dist/_chunks/portable.mjs.map +1 -0
  59. package/dist/_chunks/prepare-hook.mjs +2 -0
  60. package/dist/_chunks/prepare-hook2.mjs +61 -0
  61. package/dist/_chunks/prepare-hook2.mjs.map +1 -0
  62. package/dist/_chunks/prepare.mjs +47 -3
  63. package/dist/_chunks/prepare.mjs.map +1 -1
  64. package/dist/_chunks/prepare2.mjs +7 -6
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +484 -74
  67. package/dist/_chunks/prompts.mjs.map +1 -1
  68. package/dist/_chunks/pull.mjs +219 -0
  69. package/dist/_chunks/pull.mjs.map +1 -0
  70. package/dist/_chunks/regex.mjs +19 -0
  71. package/dist/_chunks/regex.mjs.map +1 -0
  72. package/dist/_chunks/retriv.mjs +2 -171
  73. package/dist/_chunks/retriv2.mjs +159 -0
  74. package/dist/_chunks/retriv2.mjs.map +1 -0
  75. package/dist/_chunks/sanitize.mjs +12 -9
  76. package/dist/_chunks/sanitize.mjs.map +1 -1
  77. package/dist/_chunks/search-helpers.mjs +8 -6
  78. package/dist/_chunks/search-helpers.mjs.map +1 -1
  79. package/dist/_chunks/search-interactive.mjs +23 -20
  80. package/dist/_chunks/search-interactive.mjs.map +1 -1
  81. package/dist/_chunks/search.mjs +3 -3
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/semver.mjs +2755 -1
  84. package/dist/_chunks/semver.mjs.map +1 -1
  85. package/dist/_chunks/skill-installer2.mjs +10 -11
  86. package/dist/_chunks/skill-installer2.mjs.map +1 -1
  87. package/dist/_chunks/skills.mjs +6 -7
  88. package/dist/_chunks/skills.mjs.map +1 -1
  89. package/dist/_chunks/store.mjs +107 -0
  90. package/dist/_chunks/store.mjs.map +1 -0
  91. package/dist/_chunks/sync.mjs +411 -910
  92. package/dist/_chunks/sync.mjs.map +1 -1
  93. package/dist/_chunks/sync2.mjs +2 -5
  94. package/dist/_chunks/telemetry.mjs +26 -0
  95. package/dist/_chunks/telemetry.mjs.map +1 -0
  96. package/dist/_chunks/uninstall.mjs +12 -9
  97. package/dist/_chunks/uninstall.mjs.map +1 -1
  98. package/dist/_chunks/update.mjs +171 -0
  99. package/dist/_chunks/update.mjs.map +1 -0
  100. package/dist/_chunks/upload.mjs +3 -3
  101. package/dist/_chunks/validate.mjs +1 -1
  102. package/dist/_chunks/version.mjs +16 -17
  103. package/dist/_chunks/version.mjs.map +1 -1
  104. package/dist/_chunks/whoami.mjs +21 -0
  105. package/dist/_chunks/whoami.mjs.map +1 -0
  106. package/dist/_chunks/wizard.mjs +2 -190
  107. package/dist/_chunks/wizard2.mjs +200 -0
  108. package/dist/_chunks/wizard2.mjs.map +1 -0
  109. package/dist/cli.mjs +72 -53
  110. package/dist/cli.mjs.map +1 -1
  111. package/dist/prepare.mjs +4 -3
  112. package/dist/prepare.mjs.map +1 -1
  113. package/dist/retriv/worker.d.mts +5 -1
  114. package/dist/retriv/worker.d.mts.map +1 -1
  115. package/dist/retriv/worker.mjs +1 -1
  116. package/package.json +19 -28
  117. package/dist/_chunks/author-group.mjs +0 -17
  118. package/dist/_chunks/author-group.mjs.map +0 -1
  119. package/dist/_chunks/cli-helpers.mjs +0 -335
  120. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  121. package/dist/_chunks/cli-helpers2.mjs +0 -2
  122. package/dist/_chunks/index.d.mts +0 -344
  123. package/dist/_chunks/index.d.mts.map +0 -1
  124. package/dist/_chunks/index2.d.mts +0 -279
  125. package/dist/_chunks/index2.d.mts.map +0 -1
  126. package/dist/_chunks/index3.d.mts +0 -44
  127. package/dist/_chunks/index3.d.mts.map +0 -1
  128. package/dist/_chunks/index4.d.mts +0 -553
  129. package/dist/_chunks/index4.d.mts.map +0 -1
  130. package/dist/_chunks/package-registry.mjs +0 -465
  131. package/dist/_chunks/package-registry.mjs.map +0 -1
  132. package/dist/_chunks/retriv.mjs.map +0 -1
  133. package/dist/_chunks/setup.mjs +0 -17
  134. package/dist/_chunks/setup.mjs.map +0 -1
  135. package/dist/_chunks/sources.mjs +0 -2654
  136. package/dist/_chunks/sources.mjs.map +0 -1
  137. package/dist/_chunks/sync-pipeline.mjs.map +0 -1
  138. package/dist/_chunks/sync-registry.mjs +0 -65
  139. package/dist/_chunks/sync-registry.mjs.map +0 -1
  140. package/dist/_chunks/types.d.mts +0 -76
  141. package/dist/_chunks/types.d.mts.map +0 -1
  142. package/dist/_chunks/types2.d.mts +0 -88
  143. package/dist/_chunks/types2.d.mts.map +0 -1
  144. package/dist/_chunks/wizard.mjs.map +0 -1
  145. package/dist/agent/index.d.mts +0 -2
  146. package/dist/agent/index.mjs +0 -4
  147. package/dist/cache/index.d.mts +0 -2
  148. package/dist/cache/index.mjs +0 -5
  149. package/dist/index.d.mts +0 -6
  150. package/dist/index.mjs +0 -6
  151. package/dist/retriv/index.d.mts +0 -3
  152. package/dist/retriv/index.mjs +0 -2
  153. package/dist/sources/index.d.mts +0 -3
  154. package/dist/sources/index.mjs +0 -3
  155. package/dist/types.d.mts +0 -4
  156. 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 { _ as timedSpinner, c as unlinkSkillFromAgents, f as formatSource, g as timeAgo } from "./_chunks/prompts.mjs";
10
- import { C as version, S as suggestPrepareHook, _ as promptForAgent, a as formatStatus, b as resolveAgent, c as getRepoHint, d as hasPrepareHook, f as introLine, g as pickModel, h as menuLoop, m as isRunningInsideAgent, n as NO_MODELS_MESSAGE, o as getInstalledGenerators, p as isInteractive, r as OAUTH_NOTE, u as guard, v as relativeTime, x as sharedArgs, y as requireInteractive } from "./_chunks/cli-helpers.mjs";
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/wizard.mjs";
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 { join, resolve } from "pathe";
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) => `\x1B[36m${s}\x1B[90m`;
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(`\x1B[90mFetch docs → Enhance with ${modelLabel} → Install to ${agentLabel}\x1B[0m`, "How skilld works");
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 ? "\x1B[32mconnected\x1B[0m" : "not connected"
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(` \x1B[36m${url}\x1B[0m`);
166
- if (instructions) p.log.info(` \x1B[90m${instructions}\x1B[0m`);
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 \x1B[36m${s}\x1B[0m: curator/collection inputs are not addressable here.`);
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) => `\x1B[90m${s}\x1B[0m`;
413
- const bold = (s) => `\x1B[1m${s}\x1B[0m`;
414
- const green = (s) => `\x1B[32m${s}\x1B[0m`;
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 = `\x1B[2mv${version}\x1B[0m`;
585
- const status = "\x1B[2mSetting up your environment\x1B[0m";
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(`\x1B[33m⚠ \`skilld ${oldName}\` is deprecated. Use \`skilld ${newName}\` instead.\x1B[0m`);
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/sync2.mjs").then((m) => m.addCommandDef),
657
- update: () => import("./_chunks/sync2.mjs").then((m) => m.updateCommandDef),
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/setup.mjs").then((m) => m.setupCommandDef),
668
- author: () => import("./_chunks/author-group.mjs").then((m) => m.authorGroupDef),
669
- eject: deprecatedForwarder("eject", "author eject", () => import("./_chunks/sync2.mjs").then((m) => m.ejectCommandDef)),
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("No agent selected - skills export as portable PROMPT_*.md files.\n Run \x1B[36mskilld add <pkg>\x1B[0m to generate prompts for any package.\n Run \x1B[36mskilld config\x1B[0m to set a target agent later.");
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 ? `\x1B[90m · ${relativeTime(new Date(selfUpdate.releasedAt))}\x1B[0m` : "";
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(`\x1B[90m${version}\x1B[0m\x1B[1m\x1B[32m${selfUpdate.latest}\x1B[0m${released}\n\x1B[36m${cmd}\x1B[0m`, "\x1B[33mUpdate available\x1B[0m");
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 \x1B[36m${projectName}\x1B[0m` : "Generating skills for current directory";
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(`\x1B[36m${totalShipped} ready-to-use skill${totalShipped > 1 ? "s" : ""}\x1B[0m shipped by your dependencies: ${names}`);
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: `\x1B[36m${state.shipped.reduce((sum, s) => sum + s.skills.length, 0)} ready to use\x1B[0m`
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("Run \x1B[36mskilld add <pkg>\x1B[0m or \x1B[36mskilld\x1B[0m anytime to add skills.");
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(/^[\^~>=<]+/, "") || "0.0.0";
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(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
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}\x1B[90m${meta}\x1B[39m` : name,
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(`\x1B[90m${previewLines}\n...\x1B[0m`, `${targets[agent].skillsDir}/${previewSkill.name}/SKILL.md (${fileSize} KB)`);
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\x1B[90m${agentName} was not detected on this machine.\nInstall it to use these skills, or run \`skilld config\` to change agents.\x1B[0m`;
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\x1B[36mTry it:\x1B[0m ask your agent "What are the gotchas or breaking changes in ${firstPkg}?"` : "";
942
- p.note(`${verifyLine}${trySuggestion}\n\nRun \x1B[36mskilld info\x1B[0m to see installed skills.\nRun \x1B[36mskilld\x1B[0m again to add more, update, or search.`, `${agentName} - next steps`);
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(`\x1B[33mNo prepare hook.\x1B[0m Skills won't auto-restore on \x1B[36mnpm install\x1B[0m.`);
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(`\x1B[36m${totalSkills} ready-to-use skill${totalSkills > 1 ? "s" : ""}\x1B[0m shipped by your dependencies: ${names}`);
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: `\x1B[36m${total} available\x1B[0m`
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: `\x1B[33m${state.outdated.length} outdated\x1B[0m`
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: "\x1B[33mrecommended\x1B[0m"
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(/^[\^~>=<]+/, "") || "0.0.0";
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(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
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}\x1B[90m${meta}\x1B[39m` : name,
1149
+ label: meta ? `${name}${pad}${styleText("gray", meta)}` : name,
1131
1150
  value: name
1132
1151
  };
1133
1152
  }),