skilld 1.7.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) 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 +737 -619
  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 +11 -8
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +77 -131
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +320 -54
  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 +7 -4
  20. package/dist/_chunks/detect.mjs +54 -44
  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 +2 -2
  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 +86 -371
  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 +31 -7
  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 +73 -0
  50. package/dist/_chunks/monorepo.mjs.map +1 -0
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +47 -0
  53. package/dist/_chunks/paths.mjs.map +1 -0
  54. package/dist/_chunks/pipeline.mjs +985 -0
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +2 -2
  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 +9 -8
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +784 -26
  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 +9 -8
  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 -4
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/{sources.mjs → semver.mjs} +1128 -838
  84. package/dist/_chunks/semver.mjs.map +1 -0
  85. package/dist/_chunks/skill-installer.mjs +2 -0
  86. package/dist/_chunks/skill-installer2.mjs +154 -0
  87. package/dist/_chunks/skill-installer2.mjs.map +1 -0
  88. package/dist/_chunks/skills.mjs +12 -12
  89. package/dist/_chunks/skills.mjs.map +1 -1
  90. package/dist/_chunks/store.mjs +107 -0
  91. package/dist/_chunks/store.mjs.map +1 -0
  92. package/dist/_chunks/sync.mjs +761 -1349
  93. package/dist/_chunks/sync.mjs.map +1 -1
  94. package/dist/_chunks/sync2.mjs +2 -3
  95. package/dist/_chunks/telemetry.mjs +26 -0
  96. package/dist/_chunks/telemetry.mjs.map +1 -0
  97. package/dist/_chunks/uninstall.mjs +15 -13
  98. package/dist/_chunks/uninstall.mjs.map +1 -1
  99. package/dist/_chunks/update.mjs +171 -0
  100. package/dist/_chunks/update.mjs.map +1 -0
  101. package/dist/_chunks/upload.mjs +4 -4
  102. package/dist/_chunks/validate.mjs +1 -1
  103. package/dist/_chunks/version.mjs +16 -27
  104. package/dist/_chunks/version.mjs.map +1 -1
  105. package/dist/_chunks/whoami.mjs +21 -0
  106. package/dist/_chunks/whoami.mjs.map +1 -0
  107. package/dist/_chunks/wizard.mjs +2 -190
  108. package/dist/_chunks/wizard2.mjs +200 -0
  109. package/dist/_chunks/wizard2.mjs.map +1 -0
  110. package/dist/cli.mjs +77 -59
  111. package/dist/cli.mjs.map +1 -1
  112. package/dist/prepare.mjs +5 -4
  113. package/dist/prepare.mjs.map +1 -1
  114. package/dist/retriv/worker.d.mts +5 -1
  115. package/dist/retriv/worker.d.mts.map +1 -1
  116. package/dist/retriv/worker.mjs +1 -1
  117. package/package.json +20 -29
  118. package/dist/_chunks/author-group.mjs +0 -17
  119. package/dist/_chunks/author-group.mjs.map +0 -1
  120. package/dist/_chunks/cli-helpers.mjs +0 -335
  121. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  122. package/dist/_chunks/cli-helpers2.mjs +0 -2
  123. package/dist/_chunks/config.mjs +0 -122
  124. package/dist/_chunks/config.mjs.map +0 -1
  125. package/dist/_chunks/index.d.mts +0 -151
  126. package/dist/_chunks/index.d.mts.map +0 -1
  127. package/dist/_chunks/index2.d.mts +0 -44
  128. package/dist/_chunks/index2.d.mts.map +0 -1
  129. package/dist/_chunks/index3.d.mts +0 -589
  130. package/dist/_chunks/index3.d.mts.map +0 -1
  131. package/dist/_chunks/prefix.mjs +0 -108
  132. package/dist/_chunks/prefix.mjs.map +0 -1
  133. package/dist/_chunks/retriv.mjs.map +0 -1
  134. package/dist/_chunks/setup.mjs +0 -17
  135. package/dist/_chunks/setup.mjs.map +0 -1
  136. package/dist/_chunks/shared.mjs +0 -503
  137. package/dist/_chunks/shared.mjs.map +0 -1
  138. package/dist/_chunks/skill.mjs +0 -329
  139. package/dist/_chunks/skill.mjs.map +0 -1
  140. package/dist/_chunks/sources.mjs.map +0 -1
  141. package/dist/_chunks/sync-registry.mjs +0 -59
  142. package/dist/_chunks/sync-registry.mjs.map +0 -1
  143. package/dist/_chunks/sync-shared.mjs +0 -2
  144. package/dist/_chunks/sync-shared2.mjs +0 -1020
  145. package/dist/_chunks/sync-shared2.mjs.map +0 -1
  146. package/dist/_chunks/types.d.mts +0 -88
  147. package/dist/_chunks/types.d.mts.map +0 -1
  148. package/dist/_chunks/wizard.mjs.map +0 -1
  149. package/dist/agent/index.d.mts +0 -346
  150. package/dist/agent/index.d.mts.map +0 -1
  151. package/dist/agent/index.mjs +0 -5
  152. package/dist/cache/index.d.mts +0 -2
  153. package/dist/cache/index.mjs +0 -4
  154. package/dist/index.d.mts +0 -5
  155. package/dist/index.mjs +0 -5
  156. package/dist/retriv/index.d.mts +0 -3
  157. package/dist/retriv/index.mjs +0 -2
  158. package/dist/sources/index.d.mts +0 -2
  159. package/dist/sources/index.mjs +0 -3
  160. package/dist/types.d.mts +0 -4
  161. 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,32 +1,40 @@
1
1
  #!/usr/bin/env node
2
- import { c as getOAuthProviderList, i as getAvailableModels, l as loginOAuthProvider, o as getModelName, t as detectImportedPackages, u as logoutOAuthProvider } from "./_chunks/agent.mjs";
3
- import { i as CACHE_DIR, s as getPackageDbPath, t as getCacheDir } from "./_chunks/version.mjs";
4
- import { i as readPackageJsonSafe } from "./_chunks/package-json.mjs";
5
- import "./_chunks/cache.mjs";
6
- import { n as getSharedSkillsDir, o as semverGt, r as mapInsert } from "./_chunks/shared.mjs";
7
- import { r as fetchNpmRegistryMeta, t as fetchLatestVersion } from "./_chunks/sources.mjs";
8
2
  import { a as targets, i as getAgentVersion, r as detectTargetAgent, t as detectInstalledAgents } from "./_chunks/detect.mjs";
9
- import { _ as timedSpinner, c as unlinkSkillFromAgents, f as formatSource, g as timeAgo } from "./_chunks/skill.mjs";
10
- import { a as readConfig, c as updateConfig, i as hasConfig, r as hasCompletedWizard, t as defaultFeatures } from "./_chunks/config.mjs";
11
- 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";
12
- import { o as removeLockEntry, r as parsePackages } from "./_chunks/lockfile.mjs";
3
+ import { a as getModelName, c as getOAuthProviderList, l as loginOAuthProvider, n as detectImportedPackages, r as getAvailableModels, u as logoutOAuthProvider } from "./_chunks/agent.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";
20
+ import { l as removeLockEntry, o as parsePackages } from "./_chunks/lockfile.mjs";
13
21
  import { i as iterateSkills, n as getSkillsDir, r as isOutdated, t as getProjectState } from "./_chunks/skills.mjs";
14
- import { n as resolveSkillName, r as toStoragePackageName } from "./_chunks/prefix.mjs";
15
- import { t as runWizard } from "./_chunks/wizard.mjs";
22
+ import { t as runWizard } from "./_chunks/wizard2.mjs";
16
23
  import "./_chunks/core.mjs";
17
- import { join, resolve } from "pathe";
18
24
  import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
19
- import pLimit from "p-limit";
25
+ import { styleText } from "node:util";
20
26
  import * as p from "@clack/prompts";
21
27
  import { defineCommand, runMain } from "citty";
28
+ import pLimit from "p-limit";
29
+ import { join, resolve } from "pathe";
22
30
  import logUpdate from "log-update";
23
31
  async function configCommand() {
24
32
  const initConfig = readConfig();
25
33
  const agentId = initConfig.agent || detectTargetAgent() || void 0;
26
- const cyan = (s) => `\x1B[36m${s}\x1B[90m`;
34
+ const cyan = (s) => styleText("cyan", s);
27
35
  const modelLabel = initConfig.skipLlm ? "skip" : initConfig.model ? cyan(getModelName(initConfig.model)) : "auto";
28
36
  const agentLabel = agentId && targets[agentId] ? cyan(targets[agentId].displayName) : "auto-detect";
29
- 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");
30
38
  await menuLoop({
31
39
  message: "Settings",
32
40
  options: () => {
@@ -136,7 +144,7 @@ async function configureOAuth() {
136
144
  return getOAuthProviderList().map((pr) => ({
137
145
  label: pr.name,
138
146
  value: pr.id,
139
- hint: pr.loggedIn ? "\x1B[32mconnected\x1B[0m" : "not connected"
147
+ hint: pr.loggedIn ? styleText("green", "connected") : "not connected"
140
148
  }));
141
149
  },
142
150
  onSelect: async (providerId) => {
@@ -163,8 +171,8 @@ async function configureOAuth() {
163
171
  const success = await loginOAuthProvider(providerId, {
164
172
  onAuth: (url, instructions) => {
165
173
  spinner.stop("Open this URL in your browser:");
166
- p.log.info(` \x1B[36m${url}\x1B[0m`);
167
- 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)}`);
168
176
  spinner.start("Waiting for authentication...");
169
177
  },
170
178
  onPrompt: async (message, placeholder) => {
@@ -344,7 +352,7 @@ const removeCommandDef = defineCommand({
344
352
  packages: args.package ? [...new Set([args.package, ...args._ || []].map((s) => s.trim()).filter(Boolean).map((s) => {
345
353
  const name = resolveSkillName(s);
346
354
  if (!name) {
347
- 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.`);
348
356
  return null;
349
357
  }
350
358
  return name;
@@ -393,7 +401,7 @@ async function countEmbeddings(packageName, version) {
393
401
  }
394
402
  }
395
403
  function countRefDocs(skillDir) {
396
- const refsDir = join(skillDir, ".skilld");
404
+ const refsDir = skillInternalDir(skillDir);
397
405
  if (!existsSync(refsDir)) return 0;
398
406
  let count = 0;
399
407
  const walk = (dir, depth = 0) => {
@@ -410,9 +418,9 @@ function countRefDocs(skillDir) {
410
418
  walk(refsDir);
411
419
  return count;
412
420
  }
413
- const dim = (s) => `\x1B[90m${s}\x1B[0m`;
414
- const bold = (s) => `\x1B[1m${s}\x1B[0m`;
415
- 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);
416
424
  function getLastSynced() {
417
425
  let latest = null;
418
426
  for (const skill of iterateSkills()) if (skill.info?.syncedAt) {
@@ -582,8 +590,8 @@ function brandFrame(t, floor = 0, density = 0) {
582
590
  async function brandLoader(work, minMs = 1500) {
583
591
  if (process.env.SKILLD_EFFECT === "none") return work();
584
592
  const name = "\x1B[1m\x1B[38;2;255;255;255mskilld\x1B[0m";
585
- const verStr = `\x1B[2mv${version}\x1B[0m`;
586
- 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");
587
595
  const start = Date.now();
588
596
  const sub = (raw) => raw.replace("%NAME%", name).replace("%VER%", verStr);
589
597
  let done = false;
@@ -608,6 +616,7 @@ async function brandLoader(work, minMs = 1500) {
608
616
  logUpdate.done();
609
617
  return result;
610
618
  }
619
+ const STATIC_REGEX_3 = /^[\^~>=<]/;
611
620
  const _emit = process.emit;
612
621
  process.emit = (event, ...args) => event === "warning" && args[0]?.name === "ExperimentalWarning" && args[0]?.message?.includes("SQLite") ? false : _emit.apply(process, [event, ...args]);
613
622
  function deprecatedForwarder(oldName, newName, loader) {
@@ -620,7 +629,7 @@ function deprecatedForwarder(oldName, newName, loader) {
620
629
  name: oldName
621
630
  },
622
631
  async run(ctx) {
623
- 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.`));
624
633
  return original(ctx);
625
634
  }
626
635
  });
@@ -644,7 +653,11 @@ const SUBCOMMAND_NAMES = [
644
653
  "prepare",
645
654
  "author",
646
655
  "publish",
647
- "upload"
656
+ "upload",
657
+ "login",
658
+ "logout",
659
+ "whoami",
660
+ "pull"
648
661
  ];
649
662
  runMain(defineCommand({
650
663
  meta: {
@@ -654,8 +667,8 @@ runMain(defineCommand({
654
667
  },
655
668
  args: { agent: sharedArgs.agent },
656
669
  subCommands: {
657
- add: () => import("./_chunks/sync2.mjs").then((m) => m.addCommandDef),
658
- 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),
659
672
  info: () => infoCommandDef,
660
673
  list: () => import("./_chunks/list.mjs").then((m) => m.listCommandDef),
661
674
  config: () => configCommandDef,
@@ -665,9 +678,13 @@ runMain(defineCommand({
665
678
  uninstall: () => import("./_chunks/uninstall.mjs").then((m) => m.uninstallCommandDef),
666
679
  search: () => import("./_chunks/search.mjs").then((m) => m.searchCommandDef),
667
680
  cache: () => import("./_chunks/cache2.mjs").then((m) => m.cacheCommandDef),
668
- setup: () => import("./_chunks/setup.mjs").then((m) => m.setupCommandDef),
669
- author: () => import("./_chunks/author-group.mjs").then((m) => m.authorGroupDef),
670
- 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)),
671
688
  validate: deprecatedForwarder("validate", "author validate", () => import("./_chunks/validate.mjs").then((m) => m.validateCommandDef)),
672
689
  assemble: deprecatedForwarder("assemble", "author assemble", () => import("./_chunks/assemble.mjs").then((m) => m.assembleCommandDef)),
673
690
  publish: deprecatedForwarder("publish", "author publish", () => import("./_chunks/upload.mjs").then((m) => m.uploadCommandDef)),
@@ -693,7 +710,8 @@ runMain(defineCommand({
693
710
  if (!hasCompletedWizard()) {
694
711
  if (!await runWizard()) return;
695
712
  }
696
- 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.`);
697
715
  return;
698
716
  }
699
717
  const agent = currentAgent;
@@ -734,9 +752,9 @@ runMain(defineCommand({
734
752
  };
735
753
  });
736
754
  if (selfUpdate) {
737
- 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))}`) : "";
738
756
  const cmd = `npx nypm add${realpathSync(process.argv[1]).startsWith(resolve(cwd, "node_modules")) ? "" : " -g"} skilld@${selfUpdate.latest}`;
739
- 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"));
740
758
  }
741
759
  if (state.skills.length === 0) {
742
760
  if (!hasCompletedWizard()) {
@@ -748,13 +766,13 @@ runMain(defineCommand({
748
766
  const projectPkg = readPackageJsonSafe(join(cwd, "package.json"));
749
767
  const hasPkgJson = !!projectPkg;
750
768
  const projectName = projectPkg?.parsed.name;
751
- 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";
752
770
  p.log.step(projectLabel);
753
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.");
754
772
  if (state.shipped.length > 0) {
755
773
  const totalShipped = state.shipped.reduce((sum, s) => sum + s.skills.length, 0);
756
774
  const names = state.shipped.map((s) => s.packageName).join(", ");
757
- 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}`);
758
776
  }
759
777
  p.log.info("Tip: Add skills for packages with complex APIs or frequent breaking changes - not every dependency needs one.");
760
778
  let setupComplete = false;
@@ -762,7 +780,7 @@ runMain(defineCommand({
762
780
  const shippedOption = state.shipped.length > 0 ? [{
763
781
  label: "Install shipped skills",
764
782
  value: "shipped",
765
- 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`)
766
784
  }] : [];
767
785
  const source = hasPkgJson ? await p.select({
768
786
  message: "How should I find packages?",
@@ -794,13 +812,13 @@ runMain(defineCommand({
794
812
  return;
795
813
  }
796
814
  if (source === "skip") {
797
- 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.`);
798
816
  return;
799
817
  }
800
818
  if (source === "shipped") {
801
- const { handleShippedSkills: installShipped } = await import("./_chunks/sync-shared.mjs");
819
+ const { handleShippedSkills: installShipped } = await import("./_chunks/skill-installer.mjs");
802
820
  for (const pkg of state.shipped) {
803
- 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";
804
822
  installShipped(pkg.packageName, version, cwd, agent, false);
805
823
  for (const sk of pkg.skills) p.log.success(`Installed shipped skill: ${sk.skillName}`);
806
824
  }
@@ -824,7 +842,7 @@ runMain(defineCommand({
824
842
  p.log.warn("No packages entered");
825
843
  continue;
826
844
  }
827
- selected = input.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
845
+ selected = input.split(COMMA_OR_WHITESPACE_RE).map((s) => s.trim()).filter(Boolean);
828
846
  if (selected.length === 0) {
829
847
  p.log.warn("No valid packages entered");
830
848
  continue;
@@ -880,7 +898,7 @@ runMain(defineCommand({
880
898
  const choice = await p.multiselect({
881
899
  message: `Select packages (${packages.length} found)`,
882
900
  options: packages.map((name) => {
883
- const ver = state.deps.get(name)?.replace(/^[\^~>=<]/, "") || "";
901
+ const ver = state.deps.get(name)?.replace(STATIC_REGEX_3, "") || "";
884
902
  const repo = getRepoHint(name, cwd);
885
903
  const hint = sourceMap.get(name) === "preset" ? "nuxt module" : void 0;
886
904
  const pad = " ".repeat(maxLen - name.length + 2);
@@ -890,7 +908,7 @@ runMain(defineCommand({
890
908
  repo
891
909
  ].filter(Boolean).join(" ");
892
910
  return {
893
- label: meta ? `${name}${pad}\x1B[90m${meta}\x1B[39m` : name,
911
+ label: meta ? `${name}${pad}${styleText("gray", meta)}` : name,
894
912
  value: name
895
913
  };
896
914
  }),
@@ -921,7 +939,7 @@ runMain(defineCommand({
921
939
  const previewContent = readFileSync(previewPath, "utf-8");
922
940
  const previewLines = previewContent.split("\n").slice(0, 20).join("\n").replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").replace(/\x1B\].*?(?:\x07|\x1B\\)/g, "");
923
941
  const fileSize = (Buffer.byteLength(previewContent) / 1024).toFixed(1);
924
- 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)`);
925
943
  }
926
944
  }
927
945
  const agentName = targets[agent].displayName;
@@ -937,10 +955,10 @@ runMain(defineCommand({
937
955
  "amp": "Start a new Amp session.\nReads skill descriptions at startup, full content on invocation.",
938
956
  "opencode": "Start a new OpenCode session.\nSkills are discovered automatically at startup.",
939
957
  "roo": "Restart your editor. Roo reads skill descriptions at startup."
940
- }[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.`)}`;
941
959
  const firstPkg = previewSkill?.info?.packageName || previewSkill?.name;
942
- const trySuggestion = firstPkg ? `\n\n\x1B[36mTry it:\x1B[0m ask your agent "What are the gotchas or breaking changes in ${firstPkg}?"` : "";
943
- 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`);
944
962
  try {
945
963
  await suggestPrepareHook(cwd);
946
964
  } catch (err) {
@@ -951,11 +969,11 @@ runMain(defineCommand({
951
969
  const status = formatStatus(state.synced.length, state.outdated.length);
952
970
  p.log.info(status);
953
971
  let needsPrepareHook = !hasPrepareHook(cwd);
954
- 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")}.`);
955
973
  if (state.shipped.length > 0) {
956
974
  const totalSkills = state.shipped.reduce((sum, s) => sum + s.skills.length, 0);
957
975
  const names = state.shipped.map((s) => s.packageName).join(", ");
958
- 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}`);
959
977
  }
960
978
  const refreshState = async () => {
961
979
  state = await getProjectState(cwd);
@@ -969,7 +987,7 @@ runMain(defineCommand({
969
987
  opts.push({
970
988
  label: "Install shipped skills",
971
989
  value: "shipped",
972
- hint: `\x1B[36m${total} available\x1B[0m`
990
+ hint: styleText("cyan", `${total} available`)
973
991
  });
974
992
  }
975
993
  opts.push({
@@ -979,12 +997,12 @@ runMain(defineCommand({
979
997
  if (state.outdated.length > 0) opts.push({
980
998
  label: "Update skills",
981
999
  value: "update",
982
- hint: `\x1B[33m${state.outdated.length} outdated\x1B[0m`
1000
+ hint: styleText("yellow", `${state.outdated.length} outdated`)
983
1001
  });
984
1002
  if (needsPrepareHook) opts.push({
985
1003
  label: "Setup prepare hook",
986
1004
  value: "prepare-hook",
987
- hint: "\x1B[33mrecommended\x1B[0m"
1005
+ hint: styleText("yellow", "recommended")
988
1006
  });
989
1007
  opts.push({
990
1008
  label: "Remove skills",
@@ -1018,12 +1036,12 @@ runMain(defineCommand({
1018
1036
  initialValues: allShipped
1019
1037
  }));
1020
1038
  if (selected.length === 0) return;
1021
- const { handleShippedSkills: installShipped } = await import("./_chunks/sync-shared.mjs");
1039
+ const { handleShippedSkills: installShipped } = await import("./_chunks/skill-installer.mjs");
1022
1040
  const seen = /* @__PURE__ */ new Set();
1023
1041
  for (const s of selected) {
1024
1042
  if (seen.has(s.packageName)) continue;
1025
1043
  seen.add(s.packageName);
1026
- 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";
1027
1045
  installShipped(s.packageName, version, cwd, agent, false);
1028
1046
  }
1029
1047
  p.log.success(`Installed ${selected.length} shipped skill${selected.length > 1 ? "s" : ""}`);
@@ -1062,7 +1080,7 @@ runMain(defineCommand({
1062
1080
  placeholder: "vue nuxt pinia"
1063
1081
  }));
1064
1082
  if (!input) return;
1065
- selected = input.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean);
1083
+ selected = input.split(COMMA_OR_WHITESPACE_RE).map((s) => s.trim()).filter(Boolean);
1066
1084
  if (selected.length === 0) return;
1067
1085
  } else {
1068
1086
  let usages;
@@ -1118,7 +1136,7 @@ runMain(defineCommand({
1118
1136
  const choice = guard(await p.multiselect({
1119
1137
  message: `Select packages your agent struggles with or that are new to you (${packages.length} found)`,
1120
1138
  options: packages.map((name) => {
1121
- const ver = state.deps.get(name)?.replace(/^[\^~>=<]/, "") || "";
1139
+ const ver = state.deps.get(name)?.replace(STATIC_REGEX_3, "") || "";
1122
1140
  const repo = getRepoHint(name, cwd);
1123
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;
1124
1142
  const pad = " ".repeat(maxLen - name.length + 2);
@@ -1128,7 +1146,7 @@ runMain(defineCommand({
1128
1146
  repo
1129
1147
  ].filter(Boolean).join(" ");
1130
1148
  return {
1131
- label: meta ? `${name}${pad}\x1B[90m${meta}\x1B[39m` : name,
1149
+ label: meta ? `${name}${pad}${styleText("gray", meta)}` : name,
1132
1150
  value: name
1133
1151
  };
1134
1152
  }),