skild 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +488 -405
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk15 from "chalk";
5
+ import chalk16 from "chalk";
6
6
  import { createRequire } from "module";
7
7
 
8
8
  // src/commands/install.ts
9
9
  import fs2 from "fs";
10
10
  import path2 from "path";
11
- import chalk2 from "chalk";
12
- import { deriveChildSource, fetchWithTimeout, installRegistrySkill, installSkill, isValidAlias, loadRegistryAuth, materializeSourceToTemp, resolveRegistryAlias, resolveRegistryUrl, SkildError, PLATFORMS } from "@skild/core";
11
+ import chalk3 from "chalk";
12
+ import { deriveChildSource, fetchWithTimeout, installRegistrySkill, installSkill, isValidAlias, loadRegistryAuth, materializeSourceToTemp, resolveRegistryAlias, resolveRegistryUrl, SkildError, PLATFORMS as PLATFORMS2 } from "@skild/core";
13
13
 
14
14
  // src/utils/logger.ts
15
15
  import chalk from "chalk";
@@ -71,63 +71,281 @@ var logger = {
71
71
  }
72
72
  };
73
73
 
74
- // src/utils/prompt.ts
74
+ // src/utils/interactive-select.ts
75
75
  import readline from "readline";
76
- async function promptLine(question, defaultValue) {
77
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
78
- try {
79
- const suffix = defaultValue ? ` (${defaultValue})` : "";
80
- const answer = await new Promise((resolve) => rl.question(`${question}${suffix}: `, resolve));
81
- const trimmed = answer.trim();
82
- return trimmed || defaultValue || "";
83
- } finally {
84
- rl.close();
76
+ import chalk2 from "chalk";
77
+ import { PLATFORMS } from "@skild/core";
78
+ var PLATFORM_DISPLAY = {
79
+ claude: { name: "Claude" },
80
+ codex: { name: "Codex" },
81
+ copilot: { name: "Copilot" },
82
+ antigravity: { name: "Antigravity" }
83
+ };
84
+ function buildSkillTree(skills) {
85
+ const allNode = {
86
+ id: "all",
87
+ name: "All Skills",
88
+ depth: 1,
89
+ children: [],
90
+ leafIndices: [],
91
+ isLeaf: false
92
+ };
93
+ for (let i = 0; i < skills.length; i++) {
94
+ const relPath = skills[i].relPath;
95
+ const parts = relPath === "." ? ["."] : relPath.split("/").filter(Boolean);
96
+ allNode.leafIndices.push(i);
97
+ let current = allNode;
98
+ for (let d = 0; d < parts.length; d++) {
99
+ const part = parts[d];
100
+ const nodeId = parts.slice(0, d + 1).join("/");
101
+ let child = current.children.find((c2) => c2.name === part);
102
+ if (!child) {
103
+ child = {
104
+ id: nodeId,
105
+ name: part,
106
+ depth: d + 2,
107
+ // +2 because allNode is depth 1
108
+ children: [],
109
+ leafIndices: [],
110
+ isLeaf: d === parts.length - 1
111
+ };
112
+ current.children.push(child);
113
+ }
114
+ child.leafIndices.push(i);
115
+ current = child;
116
+ }
85
117
  }
118
+ const root = { id: "", name: ".", depth: 0, children: [allNode], leafIndices: allNode.leafIndices.slice(), isLeaf: false };
119
+ return root;
86
120
  }
87
- async function promptPassword(question) {
88
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
89
- return promptLine(question);
121
+ function flattenTree(root) {
122
+ const result = [];
123
+ function walk(node) {
124
+ if (node.id !== "") {
125
+ result.push(node);
126
+ }
127
+ for (const child of node.children) {
128
+ walk(child);
129
+ }
130
+ }
131
+ for (const child of root.children) {
132
+ walk(child);
133
+ }
134
+ return result;
135
+ }
136
+ function getNodeState(node, selected) {
137
+ const total = node.leafIndices.length;
138
+ if (total === 0) return "none";
139
+ let count = 0;
140
+ for (const idx of node.leafIndices) {
141
+ if (selected.has(idx)) count++;
142
+ }
143
+ if (count === 0) return "none";
144
+ if (count === total) return "all";
145
+ return "partial";
146
+ }
147
+ async function interactiveTreeSelect(items, options) {
148
+ const { title, subtitle, buildTree, formatNode, defaultAll } = options;
149
+ const root = buildTree(items);
150
+ const flatNodes = flattenTree(root);
151
+ if (flatNodes.length === 0) return null;
152
+ const selected = /* @__PURE__ */ new Set();
153
+ if (defaultAll) {
154
+ for (let i = 0; i < items.length; i++) selected.add(i);
90
155
  }
156
+ let cursor = 0;
91
157
  const stdin = process.stdin;
92
158
  const stdout = process.stdout;
93
- stdout.write(`${question}: `);
159
+ if (!stdin.isTTY || !stdout.isTTY) {
160
+ return defaultAll ? Array.from(selected) : null;
161
+ }
94
162
  const wasRaw = Boolean(stdin.isRaw);
95
163
  stdin.setRawMode(true);
96
164
  stdin.resume();
97
165
  readline.emitKeypressEvents(stdin);
98
- const buf = [];
99
- return await new Promise((resolve, reject) => {
166
+ function render() {
167
+ stdout.write("\x1B[?25l");
168
+ const totalLines = flatNodes.length + 4;
169
+ stdout.write(`\x1B[${totalLines}A`);
170
+ stdout.write("\x1B[0J");
171
+ stdout.write(`
172
+ ${chalk2.bold.cyan(title)}
173
+ `);
174
+ stdout.write(`${chalk2.dim(subtitle)}
175
+
176
+ `);
177
+ for (let i = 0; i < flatNodes.length; i++) {
178
+ const node = flatNodes[i];
179
+ const state = getNodeState(node, selected);
180
+ const isCursor = i === cursor;
181
+ stdout.write(formatNode(node, state, isCursor) + "\n");
182
+ }
183
+ stdout.write("\n");
184
+ }
185
+ function initialRender() {
186
+ stdout.write(`
187
+ ${chalk2.bold.cyan(title)}
188
+ `);
189
+ stdout.write(`${chalk2.dim(subtitle)}
190
+
191
+ `);
192
+ for (let i = 0; i < flatNodes.length; i++) {
193
+ const node = flatNodes[i];
194
+ const state = getNodeState(node, selected);
195
+ const isCursor = i === cursor;
196
+ stdout.write(formatNode(node, state, isCursor) + "\n");
197
+ }
198
+ stdout.write("\n");
199
+ }
200
+ initialRender();
201
+ return new Promise((resolve) => {
100
202
  function cleanup() {
101
- stdin.off("keypress", onKeypress);
102
203
  stdin.setRawMode(wasRaw);
103
204
  stdin.pause();
205
+ stdin.removeListener("keypress", onKeypress);
206
+ stdout.write("\x1B[?25h");
104
207
  }
105
- function onKeypress(str, key) {
106
- if (key?.ctrl && key?.name === "c") {
107
- stdout.write("\n");
208
+ function onKeypress(_str, key) {
209
+ if (key.ctrl && key.name === "c") {
108
210
  cleanup();
109
- const err = new Error("Prompt cancelled");
110
- err.code = "PROMPT_CANCELLED";
111
- reject(err);
211
+ resolve(null);
112
212
  return;
113
213
  }
114
- if (key?.name === "return" || key?.name === "enter") {
115
- stdout.write("\n");
214
+ if (key.name === "return" || key.name === "enter") {
116
215
  cleanup();
117
- resolve(buf.join(""));
216
+ const result = Array.from(selected);
217
+ if (result.length === 0) {
218
+ resolve(null);
219
+ } else {
220
+ resolve(result);
221
+ }
118
222
  return;
119
223
  }
120
- if (key?.name === "backspace" || key?.name === "delete") {
121
- if (buf.length) buf.pop();
224
+ if (key.name === "up") {
225
+ cursor = (cursor - 1 + flatNodes.length) % flatNodes.length;
226
+ render();
227
+ return;
228
+ }
229
+ if (key.name === "down") {
230
+ cursor = (cursor + 1) % flatNodes.length;
231
+ render();
232
+ return;
233
+ }
234
+ if (key.name === "space") {
235
+ const node = flatNodes[cursor];
236
+ const state = getNodeState(node, selected);
237
+ if (state === "all") {
238
+ for (const idx of node.leafIndices) {
239
+ selected.delete(idx);
240
+ }
241
+ } else {
242
+ for (const idx of node.leafIndices) {
243
+ selected.add(idx);
244
+ }
245
+ }
246
+ render();
247
+ return;
248
+ }
249
+ if (key.name === "a") {
250
+ const allSelected = selected.size === items.length;
251
+ if (allSelected) {
252
+ selected.clear();
253
+ } else {
254
+ for (let i = 0; i < items.length; i++) selected.add(i);
255
+ }
256
+ render();
122
257
  return;
123
258
  }
124
- if (!str) return;
125
- if (key?.ctrl || key?.meta) return;
126
- buf.push(str);
127
259
  }
128
260
  stdin.on("keypress", onKeypress);
129
261
  });
130
262
  }
263
+ async function promptSkillsInteractive(skills, options = {}) {
264
+ if (skills.length === 0) return null;
265
+ const selectedIndices = await interactiveTreeSelect(skills, {
266
+ title: "Select skills to install",
267
+ subtitle: "\u2191\u2193 navigate \u2022 Space toggle \u2022 Enter confirm",
268
+ buildTree: buildSkillTree,
269
+ formatNode: (node, state, isCursor) => {
270
+ const indent = " ".repeat(node.depth - 1);
271
+ const checkbox = state === "all" ? chalk2.green("\u25CF") : state === "partial" ? chalk2.yellow("\u25D0") : chalk2.dim("\u25CB");
272
+ const name = isCursor ? chalk2.cyan.underline(node.name) : node.name;
273
+ const cursor = isCursor ? chalk2.cyan("\u203A ") : " ";
274
+ const count = node.leafIndices.length > 1 ? chalk2.dim(` (${node.leafIndices.length})`) : "";
275
+ let hint = "";
276
+ if (isCursor && node.leafIndices.length > 0) {
277
+ hint = state === "all" ? chalk2.dim(" \u2190 Space to deselect") : chalk2.dim(" \u2190 Space to select");
278
+ }
279
+ return `${cursor}${indent}${checkbox} ${name}${count}${hint}`;
280
+ },
281
+ defaultAll: options.defaultAll !== false
282
+ });
283
+ if (!selectedIndices || selectedIndices.length === 0) {
284
+ return null;
285
+ }
286
+ console.log(chalk2.green(`
287
+ \u2713 ${selectedIndices.length} skill${selectedIndices.length > 1 ? "s" : ""} selected
288
+ `));
289
+ return selectedIndices.map((i) => skills[i]);
290
+ }
291
+ async function promptPlatformsInteractive(options = {}) {
292
+ const platformItems = PLATFORMS.map((p) => ({ platform: p }));
293
+ const selectedIndices = await interactiveTreeSelect(platformItems, {
294
+ title: "Select target platforms",
295
+ subtitle: "\u2191\u2193 navigate \u2022 Space toggle \u2022 Enter confirm",
296
+ buildTree: (items) => {
297
+ const allNode = {
298
+ id: "all",
299
+ name: "All Platforms",
300
+ depth: 1,
301
+ children: [],
302
+ leafIndices: [],
303
+ isLeaf: false
304
+ };
305
+ for (let i = 0; i < items.length; i++) {
306
+ const p = items[i].platform;
307
+ allNode.children.push({
308
+ id: p,
309
+ name: p,
310
+ depth: 2,
311
+ children: [],
312
+ leafIndices: [i],
313
+ isLeaf: true
314
+ });
315
+ allNode.leafIndices.push(i);
316
+ }
317
+ const root = { id: "", name: ".", depth: 0, children: [allNode], leafIndices: allNode.leafIndices.slice(), isLeaf: false };
318
+ return root;
319
+ },
320
+ formatNode: (node, state, isCursor) => {
321
+ const indent = " ".repeat(node.depth - 1);
322
+ const checkbox = state === "all" ? chalk2.green("\u25CF") : state === "partial" ? chalk2.yellow("\u25D0") : chalk2.dim("\u25CB");
323
+ let displayName = node.name;
324
+ if (node.name !== "All Platforms") {
325
+ const platform = node.name;
326
+ const display = PLATFORM_DISPLAY[platform];
327
+ if (display) displayName = display.name;
328
+ }
329
+ const name = isCursor ? chalk2.cyan.underline(displayName) : displayName;
330
+ const cursor = isCursor ? chalk2.cyan("\u203A ") : " ";
331
+ const count = node.leafIndices.length > 1 ? chalk2.dim(` (${node.leafIndices.length})`) : "";
332
+ let hint = "";
333
+ if (isCursor && node.leafIndices.length > 0) {
334
+ hint = state === "all" ? chalk2.dim(" \u2190 Space to deselect") : chalk2.dim(" \u2190 Space to select");
335
+ }
336
+ return `${cursor}${indent}${checkbox} ${name}${count}${hint}`;
337
+ },
338
+ defaultAll: options.defaultAll !== false
339
+ });
340
+ if (!selectedIndices || selectedIndices.length === 0) {
341
+ return null;
342
+ }
343
+ const selected = selectedIndices.map((i) => PLATFORMS[i]);
344
+ console.log(chalk2.green(`
345
+ \u2713 Installing to ${selected.length} platform${selected.length > 1 ? "s" : ""}
346
+ `));
347
+ return selected;
348
+ }
131
349
 
132
350
  // src/commands/install-discovery.ts
133
351
  import fs from "fs";
@@ -230,220 +448,6 @@ function asDiscoveredSkills(discovered, toSuggestedSource, toMaterializedDir) {
230
448
  materializedDir: toMaterializedDir ? toMaterializedDir(d) : void 0
231
449
  }));
232
450
  }
233
- function buildSkillTree(found) {
234
- const root = { id: "", name: ".", children: [], leafIndices: [] };
235
- const byId = /* @__PURE__ */ new Map([["", root]]);
236
- for (let i = 0; i < found.length; i += 1) {
237
- const relPath = found[i].relPath;
238
- const parts = relPath === "." ? ["."] : relPath.split("/").filter(Boolean);
239
- let currentId = "";
240
- let current = root;
241
- current.leafIndices.push(i);
242
- for (const part of parts) {
243
- const nextId = currentId ? `${currentId}/${part}` : part;
244
- let node = byId.get(nextId);
245
- if (!node) {
246
- node = { id: nextId, name: part, children: [], leafIndices: [] };
247
- byId.set(nextId, node);
248
- current.children.push(node);
249
- }
250
- node.leafIndices.push(i);
251
- current = node;
252
- currentId = nextId;
253
- }
254
- }
255
- return root;
256
- }
257
- function getNodeState(node, selected) {
258
- const total = node.leafIndices.length;
259
- if (total === 0) return "none";
260
- let selectedCount = 0;
261
- for (const idx of node.leafIndices) {
262
- if (selected.has(idx)) selectedCount += 1;
263
- }
264
- if (selectedCount === 0) return "none";
265
- if (selectedCount === total) return "all";
266
- return "partial";
267
- }
268
- function renderSkillTree(root, selected) {
269
- const items = [];
270
- const stack = [];
271
- for (let i = root.children.length - 1; i >= 0; i -= 1) {
272
- stack.push({ node: root.children[i], depth: 0 });
273
- }
274
- while (stack.length) {
275
- const current = stack.pop();
276
- items.push(current);
277
- const children = current.node.children;
278
- for (let i = children.length - 1; i >= 0; i -= 1) {
279
- stack.push({ node: children[i], depth: current.depth + 1 });
280
- }
281
- }
282
- return items;
283
- }
284
- function parseSelectionInput(input, maxIndex) {
285
- const trimmed = input.trim().toLowerCase();
286
- if (!trimmed) return { command: "done" };
287
- if (["q", "quit", "exit", "cancel"].includes(trimmed)) return { command: "cancel" };
288
- if (["a", "all"].includes(trimmed)) return { command: "all" };
289
- if (["n", "none"].includes(trimmed)) return { command: "none" };
290
- if (["i", "invert"].includes(trimmed)) return { command: "invert" };
291
- const tokens = trimmed.split(/[,\s]+/).filter(Boolean);
292
- const indices = [];
293
- for (const token of tokens) {
294
- if (/^\d+$/.test(token)) {
295
- const value = Number(token);
296
- if (value < 1 || value > maxIndex) return null;
297
- indices.push(value);
298
- continue;
299
- }
300
- if (/^\d+-\d+$/.test(token)) {
301
- const [startRaw, endRaw] = token.split("-");
302
- const start = Number(startRaw);
303
- const end = Number(endRaw);
304
- if (!Number.isFinite(start) || !Number.isFinite(end) || start < 1 || end < 1 || start > maxIndex || end > maxIndex) {
305
- return null;
306
- }
307
- const from = Math.min(start, end);
308
- const to = Math.max(start, end);
309
- for (let i = from; i <= to; i += 1) indices.push(i);
310
- continue;
311
- }
312
- return null;
313
- }
314
- return { indices };
315
- }
316
- async function promptSkillSelection(found, options) {
317
- const root = buildSkillTree(found);
318
- const selected = /* @__PURE__ */ new Set();
319
- if (options.defaultAll) {
320
- for (let i = 0; i < found.length; i += 1) selected.add(i);
321
- }
322
- while (true) {
323
- console.log(chalk2.cyan("\nSelect skills to install"));
324
- console.log(chalk2.dim("Toggle by number. Commands: a=all, n=none, i=invert, enter=continue, q=cancel."));
325
- const display = renderSkillTree(root, selected);
326
- for (let i = 0; i < display.length; i += 1) {
327
- const item = display[i];
328
- const state = getNodeState(item.node, selected);
329
- const box = state === "all" ? "[x]" : state === "partial" ? "[-]" : "[ ]";
330
- const indent = " ".repeat(item.depth);
331
- const idx = String(i + 1).padStart(2, " ");
332
- console.log(`${idx} ${box} ${indent}${item.node.name}`);
333
- }
334
- const answer = await promptLine("Selection");
335
- const parsed = parseSelectionInput(answer, display.length);
336
- if (!parsed) {
337
- console.log(chalk2.yellow('Invalid selection. Use numbers like "1,3-5" or a/n/i.'));
338
- continue;
339
- }
340
- if (parsed.command === "done") break;
341
- if (parsed.command === "cancel") return null;
342
- if (parsed.command === "all") {
343
- selected.clear();
344
- for (let i = 0; i < found.length; i += 1) selected.add(i);
345
- continue;
346
- }
347
- if (parsed.command === "none") {
348
- selected.clear();
349
- continue;
350
- }
351
- if (parsed.command === "invert") {
352
- const next = /* @__PURE__ */ new Set();
353
- for (let i = 0; i < found.length; i += 1) {
354
- if (!selected.has(i)) next.add(i);
355
- }
356
- selected.clear();
357
- for (const idx of next) selected.add(idx);
358
- continue;
359
- }
360
- if (parsed.indices) {
361
- for (const index of parsed.indices) {
362
- const item = display[index - 1];
363
- if (!item) continue;
364
- const state = getNodeState(item.node, selected);
365
- if (state === "all") {
366
- for (const leaf of item.node.leafIndices) selected.delete(leaf);
367
- } else {
368
- for (const leaf of item.node.leafIndices) selected.add(leaf);
369
- }
370
- }
371
- }
372
- }
373
- if (selected.size === 0) return null;
374
- const selectedFound = [];
375
- for (let i = 0; i < found.length; i += 1) {
376
- if (selected.has(i)) selectedFound.push(found[i]);
377
- }
378
- return selectedFound;
379
- }
380
- async function promptPlatformSelection(defaultAll) {
381
- const selected = /* @__PURE__ */ new Set();
382
- if (defaultAll) {
383
- for (let i = 0; i < PLATFORMS.length; i += 1) selected.add(i);
384
- }
385
- while (true) {
386
- console.log(chalk2.cyan("\nSelect platforms to install to"));
387
- console.log(chalk2.dim("Toggle by number. Commands: a=all, n=none, i=invert, enter=continue, q=cancel."));
388
- for (let i = 0; i < PLATFORMS.length; i += 1) {
389
- const label = PLATFORMS[i];
390
- const box = selected.has(i) ? "[x]" : "[ ]";
391
- const idx = String(i + 1).padStart(2, " ");
392
- console.log(`${idx} ${box} ${label}`);
393
- }
394
- const answer = await promptLine("Selection");
395
- const parsed = parseSelectionInput(answer, PLATFORMS.length);
396
- if (!parsed) {
397
- console.log(chalk2.yellow('Invalid selection. Use numbers like "1,3-5" or a/n/i.'));
398
- continue;
399
- }
400
- if (parsed.command === "done") break;
401
- if (parsed.command === "cancel") return null;
402
- if (parsed.command === "all") {
403
- selected.clear();
404
- for (let i = 0; i < PLATFORMS.length; i += 1) selected.add(i);
405
- continue;
406
- }
407
- if (parsed.command === "none") {
408
- selected.clear();
409
- continue;
410
- }
411
- if (parsed.command === "invert") {
412
- const next = /* @__PURE__ */ new Set();
413
- for (let i = 0; i < PLATFORMS.length; i += 1) {
414
- if (!selected.has(i)) next.add(i);
415
- }
416
- selected.clear();
417
- for (const idx of next) selected.add(idx);
418
- continue;
419
- }
420
- if (parsed.indices) {
421
- for (const index of parsed.indices) {
422
- const idx = index - 1;
423
- if (idx < 0 || idx >= PLATFORMS.length) continue;
424
- if (selected.has(idx)) selected.delete(idx);
425
- else selected.add(idx);
426
- }
427
- }
428
- }
429
- if (selected.size === 0) return null;
430
- const chosen = [];
431
- for (let i = 0; i < PLATFORMS.length; i += 1) {
432
- if (selected.has(i)) chosen.push(PLATFORMS[i]);
433
- }
434
- return chosen;
435
- }
436
- function printSelectedSkills(found) {
437
- const names = found.map((skill) => skill.relPath);
438
- if (names.length === 0) return;
439
- const preview = names.slice(0, 20).map((name) => ` - ${name}`).join("\n");
440
- console.log(chalk2.dim(`
441
- Selected skills (${names.length}):`));
442
- console.log(preview);
443
- if (names.length > 20) {
444
- console.log(chalk2.dim(` ... and ${names.length - 20} more`));
445
- }
446
- }
447
451
  async function install(source, options = {}) {
448
452
  const scope = options.local ? "project" : "global";
449
453
  const auth = loadRegistryAuth();
@@ -459,41 +463,37 @@ async function install(source, options = {}) {
459
463
  if (requestedAll && options.target) {
460
464
  const message = "Invalid options: use either --all or --target, not both.";
461
465
  if (jsonOnly) printJson({ ok: false, error: message });
462
- else console.error(chalk2.red(message));
466
+ else console.error(chalk3.red(message));
463
467
  process.exitCode = 1;
464
468
  return;
465
469
  }
466
470
  let targets = [];
471
+ let deferPlatformSelection = false;
467
472
  if (requestedAll) {
468
- targets = [...PLATFORMS];
473
+ targets = [...PLATFORMS2];
469
474
  } else if (requestedTarget) {
470
475
  targets = [requestedTarget];
471
476
  } else if (yes) {
472
- targets = [...PLATFORMS];
477
+ targets = [...PLATFORMS2];
473
478
  } else if (interactive) {
474
- const selectedTargets = await promptPlatformSelection(true);
475
- if (!selectedTargets) {
476
- console.error(chalk2.red("No platforms selected."));
477
- process.exitCode = 1;
478
- return;
479
- }
480
- targets = selectedTargets;
479
+ deferPlatformSelection = true;
480
+ targets = [...PLATFORMS2];
481
481
  } else {
482
482
  targets = ["claude"];
483
483
  }
484
- const allPlatformsSelected = targets.length === PLATFORMS.length;
484
+ const allPlatformsSelected = targets.length === PLATFORMS2.length;
485
485
  let resolvedSource = source.trim();
486
486
  try {
487
487
  if (looksLikeAlias(resolvedSource)) {
488
488
  const registryUrl = resolveRegistryUrl(registryUrlForDeps);
489
489
  const resolved = await resolveRegistryAlias(registryUrl, resolvedSource);
490
- if (!jsonOnly) logger.info(`Resolved ${chalk2.cyan(resolvedSource)} \u2192 ${chalk2.cyan(resolved.spec)} (${resolved.type})`);
490
+ if (!jsonOnly) logger.info(`Resolved ${chalk3.cyan(resolvedSource)} \u2192 ${chalk3.cyan(resolved.spec)} (${resolved.type})`);
491
491
  resolvedSource = resolved.spec;
492
492
  }
493
493
  } catch (error) {
494
494
  const message = error instanceof SkildError ? error.message : error instanceof Error ? error.message : String(error);
495
495
  if (jsonOnly) printJson({ ok: false, error: message });
496
- else console.error(chalk2.red(message));
496
+ else console.error(chalk3.red(message));
497
497
  process.exitCode = 1;
498
498
  return;
499
499
  }
@@ -524,7 +524,7 @@ async function install(source, options = {}) {
524
524
  if (found.length > maxSkills) {
525
525
  const message = `Found more than ${maxSkills} skills. Increase --max-skills to proceed.`;
526
526
  if (jsonOnly) printJson({ ok: false, error: "TOO_MANY_SKILLS", message, source, resolvedSource, maxSkills });
527
- else console.error(chalk2.red(message));
527
+ else console.error(chalk3.red(message));
528
528
  process.exitCode = 1;
529
529
  return null;
530
530
  }
@@ -546,20 +546,29 @@ async function install(source, options = {}) {
546
546
  const headline = found.length === 1 ? `No SKILL.md found at root. Found 1 skill.
547
547
  ` : `No SKILL.md found at root. Found ${found.length} skills.
548
548
  `;
549
- console.log(chalk2.yellow(headline));
549
+ console.log(chalk3.yellow(headline));
550
550
  if (!interactive && !yes) {
551
- console.log(chalk2.dim(`Tip: rerun with ${chalk2.cyan("skild install <source> --recursive")} to install all.`));
551
+ console.log(chalk3.dim(`Tip: rerun with ${chalk3.cyan("skild install <source> --recursive")} to install all.`));
552
552
  process.exitCode = 1;
553
553
  return null;
554
554
  }
555
555
  if (!yes) {
556
- const selected = await promptSkillSelection(found, { defaultAll: true });
556
+ const selected = await promptSkillsInteractive(found, { defaultAll: true });
557
557
  if (!selected) {
558
- console.log(chalk2.red("No skills selected."));
558
+ console.log(chalk3.red("No skills selected."));
559
559
  process.exitCode = 1;
560
560
  return null;
561
561
  }
562
- printSelectedSkills(selected);
562
+ if (deferPlatformSelection) {
563
+ const selectedPlatforms = await promptPlatformsInteractive({ defaultAll: true });
564
+ if (!selectedPlatforms) {
565
+ console.log(chalk3.red("No platforms selected."));
566
+ process.exitCode = 1;
567
+ return null;
568
+ }
569
+ targets = selectedPlatforms;
570
+ deferPlatformSelection = false;
571
+ }
563
572
  effectiveRecursive = true;
564
573
  if (spinner) spinner.start();
565
574
  recursiveSkillCount = selected.length;
@@ -572,12 +581,25 @@ async function install(source, options = {}) {
572
581
  }
573
582
  try {
574
583
  const spinner = jsonOnly ? null : createSpinner(
575
- allPlatformsSelected ? `Installing ${chalk2.cyan(source)} to ${chalk2.dim("all platforms")} (${scope})...` : targets.length > 1 ? `Installing ${chalk2.cyan(source)} to ${chalk2.dim(`${targets.length} platforms`)} (${scope})...` : `Installing ${chalk2.cyan(source)} to ${chalk2.dim(targets[0])} (${scope})...`
584
+ allPlatformsSelected ? `Installing ${chalk3.cyan(source)} to ${chalk3.dim("all platforms")} (${scope})...` : targets.length > 1 ? `Installing ${chalk3.cyan(source)} to ${chalk3.dim(`${targets.length} platforms`)} (${scope})...` : `Installing ${chalk3.cyan(source)} to ${chalk3.dim(targets[0])} (${scope})...`
576
585
  );
577
586
  let cleanupMaterialized = null;
578
587
  let materializedRoot = null;
579
588
  try {
589
+ async function ensurePlatformSelection() {
590
+ if (!deferPlatformSelection) return true;
591
+ const selectedPlatforms = await promptPlatformsInteractive({ defaultAll: true });
592
+ if (!selectedPlatforms) {
593
+ console.log(chalk3.red("No platforms selected."));
594
+ process.exitCode = 1;
595
+ return false;
596
+ }
597
+ targets = selectedPlatforms;
598
+ deferPlatformSelection = false;
599
+ return true;
600
+ }
580
601
  if (resolvedSource.startsWith("@") && resolvedSource.includes("/")) {
602
+ if (!await ensurePlatformSelection()) return;
581
603
  await installOne(resolvedSource);
582
604
  } else {
583
605
  const maybeLocalRoot = path2.resolve(resolvedSource);
@@ -585,6 +607,7 @@ async function install(source, options = {}) {
585
607
  if (isLocal) {
586
608
  const hasSkillMd = fs2.existsSync(path2.join(maybeLocalRoot, "SKILL.md"));
587
609
  if (hasSkillMd) {
610
+ if (!await ensurePlatformSelection()) return;
588
611
  await installOne(resolvedSource);
589
612
  } else {
590
613
  const discovered = discoverSkillDirsWithHeuristics(maybeLocalRoot, { maxDepth, maxSkills });
@@ -594,7 +617,7 @@ async function install(source, options = {}) {
594
617
  printJson({ ok: false, error: "SKILL_MD_NOT_FOUND", message, source, resolvedSource });
595
618
  } else {
596
619
  if (spinner) spinner.stop();
597
- console.error(chalk2.red(message));
620
+ console.error(chalk3.red(message));
598
621
  }
599
622
  process.exitCode = 1;
600
623
  return;
@@ -602,9 +625,9 @@ async function install(source, options = {}) {
602
625
  const found = asDiscoveredSkills(discovered, (d) => path2.join(maybeLocalRoot, d.relPath));
603
626
  const selected = await resolveDiscoveredSelection(found, spinner);
604
627
  if (!selected) return;
605
- if (spinner) spinner.text = `Installing ${chalk2.cyan(source)} \u2014 discovered ${selected.length} skills...`;
628
+ if (spinner) spinner.text = `Installing ${chalk3.cyan(source)} \u2014 discovered ${selected.length} skills...`;
606
629
  for (const skill of selected) {
607
- if (spinner) spinner.text = `Installing ${chalk2.cyan(skill.relPath)} (${scope})...`;
630
+ if (spinner) spinner.text = `Installing ${chalk3.cyan(skill.relPath)} (${scope})...`;
608
631
  await installOne(skill.suggestedSource, skill.materializedDir);
609
632
  }
610
633
  }
@@ -623,7 +646,7 @@ async function install(source, options = {}) {
623
646
  printJson({ ok: false, error: "SKILL_MD_NOT_FOUND", message, source, resolvedSource });
624
647
  } else {
625
648
  if (spinner) spinner.stop();
626
- console.error(chalk2.red(message));
649
+ console.error(chalk3.red(message));
627
650
  }
628
651
  process.exitCode = 1;
629
652
  return;
@@ -635,9 +658,9 @@ async function install(source, options = {}) {
635
658
  );
636
659
  const selected = await resolveDiscoveredSelection(found, spinner);
637
660
  if (!selected) return;
638
- if (spinner) spinner.text = `Installing ${chalk2.cyan(source)} \u2014 discovered ${selected.length} skills...`;
661
+ if (spinner) spinner.text = `Installing ${chalk3.cyan(source)} \u2014 discovered ${selected.length} skills...`;
639
662
  for (const skill of selected) {
640
- if (spinner) spinner.text = `Installing ${chalk2.cyan(skill.relPath)} (${scope})...`;
663
+ if (spinner) spinner.text = `Installing ${chalk3.cyan(skill.relPath)} (${scope})...`;
641
664
  await installOne(skill.suggestedSource, skill.materializedDir);
642
665
  }
643
666
  }
@@ -669,42 +692,42 @@ async function install(source, options = {}) {
669
692
  if (errors.length === 0) {
670
693
  const displayName = results[0]?.canonicalName || results[0]?.name || source;
671
694
  spinner.succeed(
672
- effectiveRecursive ? `Installed ${chalk2.green(String(recursiveSkillCount ?? results.length))}${chalk2.dim(" skills")} to ${chalk2.dim(`${targets.length} platforms`)}` : targets.length > 1 ? `Installed ${chalk2.green(displayName)} to ${chalk2.dim(`${results.length} platforms`)}` : `Installed ${chalk2.green(displayName)} to ${chalk2.dim(results[0]?.installDir || "")}`
695
+ effectiveRecursive ? `Installed ${chalk3.green(String(recursiveSkillCount ?? results.length))}${chalk3.dim(" skills")} to ${chalk3.dim(`${targets.length} platforms`)}` : targets.length > 1 ? `Installed ${chalk3.green(displayName)} to ${chalk3.dim(`${results.length} platforms`)}` : `Installed ${chalk3.green(displayName)} to ${chalk3.dim(results[0]?.installDir || "")}`
673
696
  );
674
697
  } else {
675
698
  const attempted = results.length + errors.length;
676
699
  spinner.fail(
677
- effectiveRecursive ? `Install had failures (${errors.length}/${attempted} installs failed)` : `Failed to install ${chalk2.red(source)} to ${errors.length}/${targets.length} platforms`
700
+ effectiveRecursive ? `Install had failures (${errors.length}/${attempted} installs failed)` : `Failed to install ${chalk3.red(source)} to ${errors.length}/${targets.length} platforms`
678
701
  );
679
702
  process.exitCode = 1;
680
- if (!effectiveRecursive && targets.length === 1 && errors[0]) console.error(chalk2.red(errors[0].error));
703
+ if (!effectiveRecursive && targets.length === 1 && errors[0]) console.error(chalk3.red(errors[0].error));
681
704
  }
682
705
  if (!effectiveRecursive && targets.length === 1 && results[0]) {
683
706
  const record = results[0];
684
707
  if (record.hasSkillMd) logger.installDetail("SKILL.md found \u2713");
685
708
  else logger.installDetail("Warning: No SKILL.md found", true);
686
709
  if (record.skill?.validation && !record.skill.validation.ok) {
687
- logger.installDetail(`Validation: ${chalk2.yellow("failed")} (${record.skill.validation.issues.length} issues)`, true);
710
+ logger.installDetail(`Validation: ${chalk3.yellow("failed")} (${record.skill.validation.issues.length} issues)`, true);
688
711
  } else if (record.skill?.validation?.ok) {
689
- logger.installDetail(`Validation: ${chalk2.green("ok")}`);
712
+ logger.installDetail(`Validation: ${chalk3.green("ok")}`);
690
713
  }
691
714
  } else if (effectiveRecursive || targets.length > 1) {
692
715
  for (const r of results.slice(0, 60)) {
693
716
  const displayName = r.canonicalName || r.name;
694
- const suffix = r.hasSkillMd ? chalk2.green("\u2713") : chalk2.yellow("\u26A0");
695
- console.log(` ${suffix} ${chalk2.cyan(displayName)} \u2192 ${chalk2.dim(r.platform)}`);
717
+ const suffix = r.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
718
+ console.log(` ${suffix} ${chalk3.cyan(displayName)} \u2192 ${chalk3.dim(r.platform)}`);
696
719
  }
697
- if (results.length > 60) console.log(chalk2.dim(` ... and ${results.length - 60} more`));
720
+ if (results.length > 60) console.log(chalk3.dim(` ... and ${results.length - 60} more`));
698
721
  if (errors.length) {
699
- console.log(chalk2.yellow("\nFailures:"));
700
- for (const e of errors) console.log(chalk2.yellow(` - ${e.platform}: ${e.error}`));
722
+ console.log(chalk3.yellow("\nFailures:"));
723
+ for (const e of errors) console.log(chalk3.yellow(` - ${e.platform}: ${e.error}`));
701
724
  }
702
725
  process.exitCode = errors.length ? 1 : 0;
703
726
  }
704
727
  } catch (error) {
705
728
  const message = error instanceof SkildError ? error.message : error instanceof Error ? error.message : String(error);
706
729
  if (jsonOnly) printJson({ ok: false, error: message });
707
- else console.error(chalk2.red(message));
730
+ else console.error(chalk3.red(message));
708
731
  process.exitCode = 1;
709
732
  }
710
733
  }
@@ -740,8 +763,8 @@ async function reportDownload(record, registryOverride) {
740
763
  }
741
764
 
742
765
  // src/commands/list.ts
743
- import chalk3 from "chalk";
744
- import { PLATFORMS as PLATFORMS2, listAllSkills, listSkills } from "@skild/core";
766
+ import chalk4 from "chalk";
767
+ import { PLATFORMS as PLATFORMS3, listAllSkills, listSkills } from "@skild/core";
745
768
  function isSkillset(skill) {
746
769
  return Boolean(skill.record?.skillset || skill.record?.skill?.frontmatter?.skillset);
747
770
  }
@@ -756,10 +779,10 @@ function buildNameToDisplay(skills) {
756
779
  return mapping;
757
780
  }
758
781
  function statusIcon(skill) {
759
- return skill.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
782
+ return skill.hasSkillMd ? chalk4.green("\u2713") : chalk4.yellow("\u26A0");
760
783
  }
761
784
  function missingSkillMdLabel(skill) {
762
- return skill.hasSkillMd ? "" : chalk3.yellow(" (missing SKILL.md)");
785
+ return skill.hasSkillMd ? "" : chalk4.yellow(" (missing SKILL.md)");
763
786
  }
764
787
  function formatDepName(dep, nameToDisplay) {
765
788
  return dep.canonicalName || nameToDisplay.get(dep.name) || dep.name;
@@ -784,62 +807,62 @@ function summarizeDeps(record) {
784
807
  return `deps: ${byType.total}${parts.length ? ` (${parts.join(", ")})` : ""}`;
785
808
  }
786
809
  function printSkillsetSection(skills, nameToDisplay, options) {
787
- console.log(chalk3.bold(` Skillsets (${skills.length})`));
810
+ console.log(chalk4.bold(` Skillsets (${skills.length})`));
788
811
  if (skills.length === 0) {
789
- console.log(chalk3.dim(" (none)"));
812
+ console.log(chalk4.dim(" (none)"));
790
813
  return;
791
814
  }
792
815
  for (const s of skills) {
793
- const label = `${chalk3.cyan(getDisplayName(s))}${chalk3.dim(" (skillset)")}${missingSkillMdLabel(s)}`;
816
+ const label = `${chalk4.cyan(getDisplayName(s))}${chalk4.dim(" (skillset)")}${missingSkillMdLabel(s)}`;
794
817
  console.log(` ${statusIcon(s)} ${label}`);
795
818
  const summary = summarizeDeps(s.record);
796
- if (summary) console.log(chalk3.dim(` ${summary}`));
819
+ if (summary) console.log(chalk4.dim(` ${summary}`));
797
820
  if (options.verbose) {
798
821
  const deps = (s.record?.installedDependencies || []).slice().sort((a, b) => a.name.localeCompare(b.name));
799
822
  if (deps.length) {
800
- console.log(chalk3.dim(` includes (${deps.length}):`));
823
+ console.log(chalk4.dim(` includes (${deps.length}):`));
801
824
  for (const dep of deps) {
802
825
  const depName = formatDepName(dep, nameToDisplay);
803
- console.log(chalk3.dim(` - ${depName} [${dep.sourceType}]`));
826
+ console.log(chalk4.dim(` - ${depName} [${dep.sourceType}]`));
804
827
  }
805
828
  }
806
829
  }
807
- if (options.paths || !s.hasSkillMd) console.log(chalk3.dim(` path: ${s.installDir}`));
830
+ if (options.paths || !s.hasSkillMd) console.log(chalk4.dim(` path: ${s.installDir}`));
808
831
  }
809
832
  }
810
833
  function printSkillsSection(skills, options) {
811
- console.log(chalk3.bold(` Skills (${skills.length})`));
834
+ console.log(chalk4.bold(` Skills (${skills.length})`));
812
835
  if (skills.length === 0) {
813
- console.log(chalk3.dim(" (none)"));
836
+ console.log(chalk4.dim(" (none)"));
814
837
  return;
815
838
  }
816
839
  for (const s of skills) {
817
- const label = `${chalk3.cyan(getDisplayName(s))}${missingSkillMdLabel(s)}`;
840
+ const label = `${chalk4.cyan(getDisplayName(s))}${missingSkillMdLabel(s)}`;
818
841
  console.log(` ${statusIcon(s)} ${label}`);
819
- if (options.paths || !s.hasSkillMd) console.log(chalk3.dim(` path: ${s.installDir}`));
842
+ if (options.paths || !s.hasSkillMd) console.log(chalk4.dim(` path: ${s.installDir}`));
820
843
  }
821
844
  }
822
845
  function printDependenciesSection(skills, nameToDisplay, options) {
823
- console.log(chalk3.bold(` Dependencies (${skills.length})`));
846
+ console.log(chalk4.bold(` Dependencies (${skills.length})`));
824
847
  if (skills.length === 0) {
825
- console.log(chalk3.dim(" (none)"));
848
+ console.log(chalk4.dim(" (none)"));
826
849
  return;
827
850
  }
828
851
  for (const s of skills) {
829
852
  const dependedBy = (s.record?.dependedBy || []).map((name) => nameToDisplay.get(name) || name).sort((a, b) => a.localeCompare(b));
830
- const requiredBy = dependedBy.length ? chalk3.dim(` \u2190 required by: ${dependedBy.join(", ")}`) : "";
831
- const label = `${chalk3.cyan(getDisplayName(s))}${missingSkillMdLabel(s)}${requiredBy}`;
853
+ const requiredBy = dependedBy.length ? chalk4.dim(` \u2190 required by: ${dependedBy.join(", ")}`) : "";
854
+ const label = `${chalk4.cyan(getDisplayName(s))}${missingSkillMdLabel(s)}${requiredBy}`;
832
855
  console.log(` ${statusIcon(s)} ${label}`);
833
- if (options.paths || !s.hasSkillMd) console.log(chalk3.dim(` path: ${s.installDir}`));
856
+ if (options.paths || !s.hasSkillMd) console.log(chalk4.dim(` path: ${s.installDir}`));
834
857
  }
835
858
  }
836
859
  function printPlatform(skills, platform, scope, options) {
837
- console.log(chalk3.bold(`
860
+ console.log(chalk4.bold(`
838
861
  \u{1F4E6} Installed Skills \u2014 ${platform} (${scope})
839
862
  `));
840
863
  if (skills.length === 0) {
841
- console.log(chalk3.dim(" No skills installed."));
842
- console.log(chalk3.dim(` Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
864
+ console.log(chalk4.dim(" No skills installed."));
865
+ console.log(chalk4.dim(` Use ${chalk4.cyan("skild install <source>")} to install a skill.`));
843
866
  return;
844
867
  }
845
868
  const nameToDisplay = buildNameToDisplay(skills);
@@ -873,11 +896,11 @@ async function list(options = {}) {
873
896
  return;
874
897
  }
875
898
  if (allSkills.length === 0) {
876
- console.log(chalk3.dim("No skills installed."));
877
- console.log(chalk3.dim(`Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
899
+ console.log(chalk4.dim("No skills installed."));
900
+ console.log(chalk4.dim(`Use ${chalk4.cyan("skild install <source>")} to install a skill.`));
878
901
  return;
879
902
  }
880
- for (const p of PLATFORMS2) {
903
+ for (const p of PLATFORMS3) {
881
904
  const platformSkills = allSkills.filter((s) => s.platform === p).sort((a, b) => a.name.localeCompare(b.name));
882
905
  if (platformSkills.length === 0) continue;
883
906
  printPlatform(platformSkills, p, scope, { paths, verbose });
@@ -885,7 +908,7 @@ async function list(options = {}) {
885
908
  }
886
909
 
887
910
  // src/commands/info.ts
888
- import chalk4 from "chalk";
911
+ import chalk5 from "chalk";
889
912
  import { canonicalNameToInstallDirName, getSkillInfo, SkildError as SkildError2 } from "@skild/core";
890
913
  async function info(skill, options = {}) {
891
914
  const platform = options.target || "claude";
@@ -898,22 +921,22 @@ async function info(skill, options = {}) {
898
921
  return;
899
922
  }
900
923
  const displayName = record.canonicalName || record.name;
901
- console.log(chalk4.bold(`
902
- ${chalk4.cyan(displayName)}
924
+ console.log(chalk5.bold(`
925
+ ${chalk5.cyan(displayName)}
903
926
  `));
904
- console.log(` ${chalk4.dim("Path:")} ${record.installDir}`);
905
- console.log(` ${chalk4.dim("Source:")} ${record.source}`);
906
- console.log(` ${chalk4.dim("Target:")} ${record.platform} (${record.scope})`);
907
- console.log(` ${chalk4.dim("Installed:")} ${record.installedAt}`);
908
- if (record.updatedAt) console.log(` ${chalk4.dim("Updated:")} ${record.updatedAt}`);
909
- console.log(` ${chalk4.dim("Hash:")} ${record.contentHash}`);
910
- console.log(` ${chalk4.dim("SKILL.md:")} ${record.hasSkillMd ? chalk4.green("yes") : chalk4.yellow("no")}`);
927
+ console.log(` ${chalk5.dim("Path:")} ${record.installDir}`);
928
+ console.log(` ${chalk5.dim("Source:")} ${record.source}`);
929
+ console.log(` ${chalk5.dim("Target:")} ${record.platform} (${record.scope})`);
930
+ console.log(` ${chalk5.dim("Installed:")} ${record.installedAt}`);
931
+ if (record.updatedAt) console.log(` ${chalk5.dim("Updated:")} ${record.updatedAt}`);
932
+ console.log(` ${chalk5.dim("Hash:")} ${record.contentHash}`);
933
+ console.log(` ${chalk5.dim("SKILL.md:")} ${record.hasSkillMd ? chalk5.green("yes") : chalk5.yellow("no")}`);
911
934
  const validation = record.skill?.validation;
912
935
  if (validation) {
913
- console.log(` ${chalk4.dim("Validate:")} ${validation.ok ? chalk4.green("ok") : chalk4.red("failed")}`);
936
+ console.log(` ${chalk5.dim("Validate:")} ${validation.ok ? chalk5.green("ok") : chalk5.red("failed")}`);
914
937
  if (!validation.ok) {
915
938
  for (const issue of validation.issues) {
916
- const color = issue.level === "error" ? chalk4.red : chalk4.yellow;
939
+ const color = issue.level === "error" ? chalk5.red : chalk5.yellow;
917
940
  console.log(` - ${color(issue.level)}: ${issue.message}`);
918
941
  }
919
942
  }
@@ -921,20 +944,20 @@ ${chalk4.cyan(displayName)}
921
944
  console.log("");
922
945
  } catch (error) {
923
946
  const message = error instanceof SkildError2 ? error.message : error instanceof Error ? error.message : String(error);
924
- console.error(chalk4.red(message));
947
+ console.error(chalk5.red(message));
925
948
  process.exitCode = 1;
926
949
  }
927
950
  }
928
951
 
929
952
  // src/commands/uninstall.ts
930
- import chalk5 from "chalk";
953
+ import chalk6 from "chalk";
931
954
  import { canonicalNameToInstallDirName as canonicalNameToInstallDirName2, uninstallSkill, SkildError as SkildError3 } from "@skild/core";
932
955
  async function uninstall(skill, options = {}) {
933
956
  const platform = options.target || "claude";
934
957
  const scope = options.local ? "project" : "global";
935
958
  const canonical = skill.trim();
936
959
  const resolvedName = canonical.startsWith("@") && canonical.includes("/") ? canonicalNameToInstallDirName2(canonical) : canonical;
937
- const spinner = createSpinner(`Uninstalling ${chalk5.cyan(canonical)} from ${chalk5.dim(platform)} (${scope})...`);
960
+ const spinner = createSpinner(`Uninstalling ${chalk6.cyan(canonical)} from ${chalk6.dim(platform)} (${scope})...`);
938
961
  try {
939
962
  uninstallSkill(resolvedName, {
940
963
  platform,
@@ -942,40 +965,40 @@ async function uninstall(skill, options = {}) {
942
965
  allowMissingMetadata: Boolean(options.force),
943
966
  withDeps: Boolean(options.withDeps)
944
967
  });
945
- spinner.succeed(`Uninstalled ${chalk5.green(canonical)}`);
968
+ spinner.succeed(`Uninstalled ${chalk6.green(canonical)}`);
946
969
  } catch (error) {
947
- spinner.fail(`Failed to uninstall ${chalk5.red(canonical)}`);
970
+ spinner.fail(`Failed to uninstall ${chalk6.red(canonical)}`);
948
971
  const message = error instanceof SkildError3 ? error.message : error instanceof Error ? error.message : String(error);
949
- console.error(chalk5.red(message));
972
+ console.error(chalk6.red(message));
950
973
  process.exitCode = 1;
951
974
  }
952
975
  }
953
976
 
954
977
  // src/commands/update.ts
955
- import chalk6 from "chalk";
978
+ import chalk7 from "chalk";
956
979
  import { canonicalNameToInstallDirName as canonicalNameToInstallDirName3, updateSkill, SkildError as SkildError4 } from "@skild/core";
957
980
  async function update(skill, options = {}) {
958
981
  const platform = options.target || "claude";
959
982
  const scope = options.local ? "project" : "global";
960
983
  const label = skill ? skill : "all skills";
961
984
  const resolvedName = skill && skill.trim().startsWith("@") && skill.includes("/") ? canonicalNameToInstallDirName3(skill.trim()) : skill;
962
- const spinner = createSpinner(`Updating ${chalk6.cyan(label)} on ${chalk6.dim(platform)} (${scope})...`);
985
+ const spinner = createSpinner(`Updating ${chalk7.cyan(label)} on ${chalk7.dim(platform)} (${scope})...`);
963
986
  try {
964
987
  const results = await updateSkill(resolvedName, { platform, scope });
965
- spinner.succeed(`Updated ${chalk6.green(results.length.toString())} skill(s).`);
988
+ spinner.succeed(`Updated ${chalk7.green(results.length.toString())} skill(s).`);
966
989
  if (options.json) {
967
990
  console.log(JSON.stringify(results, null, 2));
968
991
  }
969
992
  } catch (error) {
970
- spinner.fail(`Failed to update ${chalk6.red(label)}`);
993
+ spinner.fail(`Failed to update ${chalk7.red(label)}`);
971
994
  const message = error instanceof SkildError4 ? error.message : error instanceof Error ? error.message : String(error);
972
- console.error(chalk6.red(message));
995
+ console.error(chalk7.red(message));
973
996
  process.exitCode = 1;
974
997
  }
975
998
  }
976
999
 
977
1000
  // src/commands/validate.ts
978
- import chalk7 from "chalk";
1001
+ import chalk8 from "chalk";
979
1002
  import { canonicalNameToInstallDirName as canonicalNameToInstallDirName4, validateSkill } from "@skild/core";
980
1003
  async function validate(target, options = {}) {
981
1004
  const platform = options.target || "claude";
@@ -989,42 +1012,102 @@ async function validate(target, options = {}) {
989
1012
  return;
990
1013
  }
991
1014
  if (result.ok) {
992
- console.log(chalk7.green("\u2713"), "Valid skill");
993
- if (result.frontmatter?.name) console.log(chalk7.dim(` name: ${result.frontmatter.name}`));
1015
+ console.log(chalk8.green("\u2713"), "Valid skill");
1016
+ if (result.frontmatter?.name) console.log(chalk8.dim(` name: ${result.frontmatter.name}`));
994
1017
  return;
995
1018
  }
996
- console.error(chalk7.red("\u2717"), "Invalid skill");
1019
+ console.error(chalk8.red("\u2717"), "Invalid skill");
997
1020
  for (const issue of result.issues) {
998
- const color = issue.level === "error" ? chalk7.red : chalk7.yellow;
1021
+ const color = issue.level === "error" ? chalk8.red : chalk8.yellow;
999
1022
  console.error(` - ${color(issue.level)}: ${issue.message}`);
1000
1023
  }
1001
1024
  process.exitCode = 1;
1002
1025
  }
1003
1026
 
1004
1027
  // src/commands/init.ts
1005
- import chalk8 from "chalk";
1028
+ import chalk9 from "chalk";
1006
1029
  import { initSkill, SkildError as SkildError5 } from "@skild/core";
1007
1030
  async function init(name, options = {}) {
1008
- const spinner = createSpinner(`Initializing ${chalk8.cyan(name)}...`);
1031
+ const spinner = createSpinner(`Initializing ${chalk9.cyan(name)}...`);
1009
1032
  try {
1010
1033
  const createdDir = initSkill(name, {
1011
1034
  dir: options.dir,
1012
1035
  description: options.description,
1013
1036
  force: Boolean(options.force)
1014
1037
  });
1015
- spinner.succeed(`Created ${chalk8.green(name)} at ${chalk8.dim(createdDir)}`);
1016
- console.log(chalk8.dim(`Next: cd ${createdDir} && skild validate .`));
1038
+ spinner.succeed(`Created ${chalk9.green(name)} at ${chalk9.dim(createdDir)}`);
1039
+ console.log(chalk9.dim(`Next: cd ${createdDir} && skild validate .`));
1017
1040
  } catch (error) {
1018
- spinner.fail(`Failed to init ${chalk8.red(name)}`);
1041
+ spinner.fail(`Failed to init ${chalk9.red(name)}`);
1019
1042
  const message = error instanceof SkildError5 ? error.message : error instanceof Error ? error.message : String(error);
1020
- console.error(chalk8.red(message));
1043
+ console.error(chalk9.red(message));
1021
1044
  process.exitCode = 1;
1022
1045
  }
1023
1046
  }
1024
1047
 
1025
1048
  // src/commands/signup.ts
1026
- import chalk9 from "chalk";
1049
+ import chalk10 from "chalk";
1027
1050
  import { fetchWithTimeout as fetchWithTimeout2, resolveRegistryUrl as resolveRegistryUrl2, SkildError as SkildError6 } from "@skild/core";
1051
+
1052
+ // src/utils/prompt.ts
1053
+ import readline2 from "readline";
1054
+ async function promptLine(question, defaultValue) {
1055
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
1056
+ try {
1057
+ const suffix = defaultValue ? ` (${defaultValue})` : "";
1058
+ const answer = await new Promise((resolve) => rl.question(`${question}${suffix}: `, resolve));
1059
+ const trimmed = answer.trim();
1060
+ return trimmed || defaultValue || "";
1061
+ } finally {
1062
+ rl.close();
1063
+ }
1064
+ }
1065
+ async function promptPassword(question) {
1066
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
1067
+ return promptLine(question);
1068
+ }
1069
+ const stdin = process.stdin;
1070
+ const stdout = process.stdout;
1071
+ stdout.write(`${question}: `);
1072
+ const wasRaw = Boolean(stdin.isRaw);
1073
+ stdin.setRawMode(true);
1074
+ stdin.resume();
1075
+ readline2.emitKeypressEvents(stdin);
1076
+ const buf = [];
1077
+ return await new Promise((resolve, reject) => {
1078
+ function cleanup() {
1079
+ stdin.off("keypress", onKeypress);
1080
+ stdin.setRawMode(wasRaw);
1081
+ stdin.pause();
1082
+ }
1083
+ function onKeypress(str, key) {
1084
+ if (key?.ctrl && key?.name === "c") {
1085
+ stdout.write("\n");
1086
+ cleanup();
1087
+ const err = new Error("Prompt cancelled");
1088
+ err.code = "PROMPT_CANCELLED";
1089
+ reject(err);
1090
+ return;
1091
+ }
1092
+ if (key?.name === "return" || key?.name === "enter") {
1093
+ stdout.write("\n");
1094
+ cleanup();
1095
+ resolve(buf.join(""));
1096
+ return;
1097
+ }
1098
+ if (key?.name === "backspace" || key?.name === "delete") {
1099
+ if (buf.length) buf.pop();
1100
+ return;
1101
+ }
1102
+ if (!str) return;
1103
+ if (key?.ctrl || key?.meta) return;
1104
+ buf.push(str);
1105
+ }
1106
+ stdin.on("keypress", onKeypress);
1107
+ });
1108
+ }
1109
+
1110
+ // src/commands/signup.ts
1028
1111
  async function signup(options) {
1029
1112
  const registry = resolveRegistryUrl2(options.registry);
1030
1113
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
@@ -1032,7 +1115,7 @@ async function signup(options) {
1032
1115
  const handle = options.handle?.trim() || "";
1033
1116
  const password = options.password || "";
1034
1117
  if ((!email || !handle || !password) && (!interactive || options.json)) {
1035
- console.error(chalk9.red("Missing signup fields. Use --email/--handle/--password, or run `skild signup` interactively."));
1118
+ console.error(chalk10.red("Missing signup fields. Use --email/--handle/--password, or run `skild signup` interactively."));
1036
1119
  process.exitCode = 1;
1037
1120
  return;
1038
1121
  }
@@ -1067,13 +1150,13 @@ async function signup(options) {
1067
1150
  );
1068
1151
  text = await res.text();
1069
1152
  if (!res.ok) {
1070
- console.error(chalk9.red(`Signup failed (${res.status}): ${text}`));
1153
+ console.error(chalk10.red(`Signup failed (${res.status}): ${text}`));
1071
1154
  process.exitCode = 1;
1072
1155
  return;
1073
1156
  }
1074
1157
  } catch (error) {
1075
1158
  const message = error instanceof SkildError6 ? error.message : error instanceof Error ? error.message : String(error);
1076
- console.error(chalk9.red(`Signup failed: ${message}`));
1159
+ console.error(chalk10.red(`Signup failed: ${message}`));
1077
1160
  process.exitCode = 1;
1078
1161
  return;
1079
1162
  }
@@ -1081,29 +1164,29 @@ async function signup(options) {
1081
1164
  console.log(text || JSON.stringify({ ok: true }, null, 2));
1082
1165
  return;
1083
1166
  }
1084
- console.log(chalk9.green("Signup successful."));
1167
+ console.log(chalk10.green("Signup successful."));
1085
1168
  try {
1086
1169
  const parsed = JSON.parse(text);
1087
1170
  if (parsed.verification?.requiredForPublish) {
1088
1171
  if (parsed.verification.mode === "log") {
1089
- console.log(chalk9.dim("Dev mode: email sending is disabled. Check the registry dev logs for the verification link."));
1172
+ console.log(chalk10.dim("Dev mode: email sending is disabled. Check the registry dev logs for the verification link."));
1090
1173
  } else if (parsed.verification.sent) {
1091
- console.log(chalk9.dim("Verification email sent. Check your inbox (and spam)."));
1174
+ console.log(chalk10.dim("Verification email sent. Check your inbox (and spam)."));
1092
1175
  } else {
1093
- console.log(chalk9.yellow("Verification email was not sent. You may need to resend from the Skild Hub."));
1176
+ console.log(chalk10.yellow("Verification email was not sent. You may need to resend from the Skild Hub."));
1094
1177
  }
1095
- console.log(chalk9.dim(`Verify/resend in Skild Hub: ${(parsed.verification.consoleUrl || "https://hub.skild.sh").replace(/\/+$/, "")}/verify-email/request`));
1178
+ console.log(chalk10.dim(`Verify/resend in Skild Hub: ${(parsed.verification.consoleUrl || "https://hub.skild.sh").replace(/\/+$/, "")}/verify-email/request`));
1096
1179
  } else if (parsed.verification) {
1097
- console.log(chalk9.dim("Email verification is recommended. Publishing may be restricted in the future."));
1098
- console.log(chalk9.dim(`Verify/resend in Skild Hub: ${(parsed.verification.consoleUrl || "https://hub.skild.sh").replace(/\/+$/, "")}/verify-email/request`));
1180
+ console.log(chalk10.dim("Email verification is recommended. Publishing may be restricted in the future."));
1181
+ console.log(chalk10.dim(`Verify/resend in Skild Hub: ${(parsed.verification.consoleUrl || "https://hub.skild.sh").replace(/\/+$/, "")}/verify-email/request`));
1099
1182
  }
1100
1183
  } catch {
1101
1184
  }
1102
- console.log(chalk9.dim("Next: run `skild login`"));
1185
+ console.log(chalk10.dim("Next: run `skild login`"));
1103
1186
  }
1104
1187
 
1105
1188
  // src/commands/login.ts
1106
- import chalk10 from "chalk";
1189
+ import chalk11 from "chalk";
1107
1190
  import { fetchWithTimeout as fetchWithTimeout3, resolveRegistryUrl as resolveRegistryUrl3, saveRegistryAuth, SkildError as SkildError7 } from "@skild/core";
1108
1191
  async function login(options) {
1109
1192
  const registry = resolveRegistryUrl3(options.registry);
@@ -1111,7 +1194,7 @@ async function login(options) {
1111
1194
  const handleOrEmail = options.handleOrEmail?.trim() || "";
1112
1195
  const password = options.password || "";
1113
1196
  if ((!handleOrEmail || !password) && (!interactive || options.json)) {
1114
- console.error(chalk10.red("Missing credentials. Use --handle-or-email and --password, or run `skild login` interactively."));
1197
+ console.error(chalk11.red("Missing credentials. Use --handle-or-email and --password, or run `skild login` interactively."));
1115
1198
  process.exitCode = 1;
1116
1199
  return;
1117
1200
  }
@@ -1146,13 +1229,13 @@ async function login(options) {
1146
1229
  );
1147
1230
  text = await res.text();
1148
1231
  if (!res.ok) {
1149
- console.error(chalk10.red(`Login failed (${res.status}): ${text}`));
1232
+ console.error(chalk11.red(`Login failed (${res.status}): ${text}`));
1150
1233
  process.exitCode = 1;
1151
1234
  return;
1152
1235
  }
1153
1236
  } catch (error) {
1154
1237
  const message = error instanceof SkildError7 ? error.message : error instanceof Error ? error.message : String(error);
1155
- console.error(chalk10.red(`Login failed: ${message}`));
1238
+ console.error(chalk11.red(`Login failed: ${message}`));
1156
1239
  process.exitCode = 1;
1157
1240
  return;
1158
1241
  }
@@ -1168,28 +1251,28 @@ async function login(options) {
1168
1251
  console.log(JSON.stringify({ ok: true, publisher: json.publisher }, null, 2));
1169
1252
  return;
1170
1253
  }
1171
- console.log(chalk10.green(`Logged in as ${chalk10.cyan(json.publisher.handle)}.`));
1254
+ console.log(chalk11.green(`Logged in as ${chalk11.cyan(json.publisher.handle)}.`));
1172
1255
  if (json.publisher.emailVerified === false) {
1173
- console.log(chalk10.yellow("Email not verified. Publishing may be restricted by server policy."));
1174
- console.log(chalk10.dim("Open the Skild Hub to verify: https://hub.skild.sh/verify-email/request"));
1256
+ console.log(chalk11.yellow("Email not verified. Publishing may be restricted by server policy."));
1257
+ console.log(chalk11.dim("Open the Skild Hub to verify: https://hub.skild.sh/verify-email/request"));
1175
1258
  }
1176
1259
  }
1177
1260
 
1178
1261
  // src/commands/logout.ts
1179
- import chalk11 from "chalk";
1262
+ import chalk12 from "chalk";
1180
1263
  import { clearRegistryAuth } from "@skild/core";
1181
1264
  async function logout() {
1182
1265
  clearRegistryAuth();
1183
- console.log(chalk11.green("Logged out."));
1266
+ console.log(chalk12.green("Logged out."));
1184
1267
  }
1185
1268
 
1186
1269
  // src/commands/whoami.ts
1187
- import chalk12 from "chalk";
1270
+ import chalk13 from "chalk";
1188
1271
  import { fetchWithTimeout as fetchWithTimeout4, loadRegistryAuth as loadRegistryAuth2, resolveRegistryUrl as resolveRegistryUrl4, SkildError as SkildError8 } from "@skild/core";
1189
1272
  async function whoami() {
1190
1273
  const auth = loadRegistryAuth2();
1191
1274
  if (!auth) {
1192
- console.error(chalk12.red("Not logged in. Run `skild login` first."));
1275
+ console.error(chalk13.red("Not logged in. Run `skild login` first."));
1193
1276
  process.exitCode = 1;
1194
1277
  return;
1195
1278
  }
@@ -1202,16 +1285,16 @@ async function whoami() {
1202
1285
  );
1203
1286
  const text = await res.text();
1204
1287
  if (!res.ok) {
1205
- console.error(chalk12.red(`whoami failed (${res.status}): ${text}`));
1288
+ console.error(chalk13.red(`whoami failed (${res.status}): ${text}`));
1206
1289
  process.exitCode = 1;
1207
1290
  return;
1208
1291
  }
1209
1292
  const json = JSON.parse(text);
1210
- console.log(chalk12.cyan(json.publisher.handle));
1293
+ console.log(chalk13.cyan(json.publisher.handle));
1211
1294
  } catch (error) {
1212
1295
  const message = error instanceof SkildError8 ? error.message : error instanceof Error ? error.message : String(error);
1213
- console.error(chalk12.red(`whoami failed: ${message}`));
1214
- console.error(chalk12.dim("Tip: if you previously logged into a local registry, run `skild logout` then `skild login`."));
1296
+ console.error(chalk13.red(`whoami failed: ${message}`));
1297
+ console.error(chalk13.dim("Tip: if you previously logged into a local registry, run `skild logout` then `skild login`."));
1215
1298
  process.exitCode = 1;
1216
1299
  }
1217
1300
  }
@@ -1222,7 +1305,7 @@ import os from "os";
1222
1305
  import path3 from "path";
1223
1306
  import crypto from "crypto";
1224
1307
  import * as tar from "tar";
1225
- import chalk13 from "chalk";
1308
+ import chalk14 from "chalk";
1226
1309
  import { assertValidAlias, fetchWithTimeout as fetchWithTimeout5, loadRegistryAuth as loadRegistryAuth3, normalizeAlias, resolveRegistryUrl as resolveRegistryUrl5, SkildError as SkildError9, splitCanonicalName, validateSkillDir } from "@skild/core";
1227
1310
  function sha256Hex(buf) {
1228
1311
  const h = crypto.createHash("sha256");
@@ -1238,15 +1321,15 @@ async function publish(options = {}) {
1238
1321
  const registry = resolveRegistryUrl5(options.registry || auth?.registryUrl);
1239
1322
  const token = auth?.token;
1240
1323
  if (!token) {
1241
- console.error(chalk13.red("Not logged in. Run `skild login` first."));
1324
+ console.error(chalk14.red("Not logged in. Run `skild login` first."));
1242
1325
  process.exitCode = 1;
1243
1326
  return;
1244
1327
  }
1245
1328
  const dir = path3.resolve(options.dir || process.cwd());
1246
1329
  const validation = validateSkillDir(dir);
1247
1330
  if (!validation.ok) {
1248
- console.error(chalk13.red("Skill validation failed:"));
1249
- for (const issue of validation.issues) console.error(chalk13.red(`- ${issue.message}`));
1331
+ console.error(chalk14.red("Skill validation failed:"));
1332
+ for (const issue of validation.issues) console.error(chalk14.red(`- ${issue.message}`));
1250
1333
  process.exitCode = 1;
1251
1334
  return;
1252
1335
  }
@@ -1260,14 +1343,14 @@ async function publish(options = {}) {
1260
1343
  const skillset = fm.skillset === true;
1261
1344
  const dependencies = Array.isArray(fm.dependencies) ? fm.dependencies : [];
1262
1345
  if (!name) {
1263
- console.error(chalk13.red("Missing name. Provide SKILL.md frontmatter.name or --name."));
1346
+ console.error(chalk14.red("Missing name. Provide SKILL.md frontmatter.name or --name."));
1264
1347
  process.exitCode = 1;
1265
1348
  return;
1266
1349
  }
1267
1350
  if (!name.startsWith("@")) {
1268
1351
  const seg = name.trim();
1269
1352
  if (!/^[a-z0-9][a-z0-9-]{1,63}$/.test(seg)) {
1270
- console.error(chalk13.red("Invalid name. Use @publisher/skill or a simple skill name (lowercase letters/digits/dashes)."));
1353
+ console.error(chalk14.red("Invalid name. Use @publisher/skill or a simple skill name (lowercase letters/digits/dashes)."));
1271
1354
  process.exitCode = 1;
1272
1355
  return;
1273
1356
  }
@@ -1278,26 +1361,26 @@ async function publish(options = {}) {
1278
1361
  );
1279
1362
  const meText = await meRes.text();
1280
1363
  if (!meRes.ok) {
1281
- console.error(chalk13.red(`Failed to infer publisher scope (${meRes.status}): ${meText}`));
1364
+ console.error(chalk14.red(`Failed to infer publisher scope (${meRes.status}): ${meText}`));
1282
1365
  process.exitCode = 1;
1283
1366
  return;
1284
1367
  }
1285
1368
  const meJson = JSON.parse(meText);
1286
1369
  const handle = String(meJson?.publisher?.handle || "").trim().toLowerCase();
1287
1370
  if (!handle) {
1288
- console.error(chalk13.red("Failed to infer publisher scope from registry response."));
1371
+ console.error(chalk14.red("Failed to infer publisher scope from registry response."));
1289
1372
  process.exitCode = 1;
1290
1373
  return;
1291
1374
  }
1292
1375
  name = `@${handle}/${seg}`;
1293
1376
  }
1294
1377
  if (!/^@[a-z0-9][a-z0-9-]{1,31}\/[a-z0-9][a-z0-9-]{1,63}$/.test(name)) {
1295
- console.error(chalk13.red("Invalid publish name. Expected @publisher/skill (lowercase letters/digits/dashes)."));
1378
+ console.error(chalk14.red("Invalid publish name. Expected @publisher/skill (lowercase letters/digits/dashes)."));
1296
1379
  process.exitCode = 1;
1297
1380
  return;
1298
1381
  }
1299
1382
  if (!version2) {
1300
- console.error(chalk13.red("Missing version. Provide semver like 1.2.3 via SKILL.md frontmatter or --skill-version."));
1383
+ console.error(chalk14.red("Missing version. Provide semver like 1.2.3 via SKILL.md frontmatter or --skill-version."));
1301
1384
  process.exitCode = 1;
1302
1385
  return;
1303
1386
  }
@@ -1306,12 +1389,12 @@ async function publish(options = {}) {
1306
1389
  assertValidAlias(alias);
1307
1390
  } catch (error) {
1308
1391
  const message = error instanceof SkildError9 ? error.message : error instanceof Error ? error.message : String(error);
1309
- console.error(chalk13.red(message));
1392
+ console.error(chalk14.red(message));
1310
1393
  process.exitCode = 1;
1311
1394
  return;
1312
1395
  }
1313
1396
  }
1314
- const spinner = createSpinner(`Publishing ${chalk13.cyan(`${name}@${version2}`)} to ${chalk13.dim(registry)}...`);
1397
+ const spinner = createSpinner(`Publishing ${chalk14.cyan(`${name}@${version2}`)} to ${chalk14.dim(registry)}...`);
1315
1398
  const tempDir = fs3.mkdtempSync(path3.join(os.tmpdir(), "skild-publish-"));
1316
1399
  const tarballPath = path3.join(tempDir, "skill.tgz");
1317
1400
  try {
@@ -1348,12 +1431,12 @@ async function publish(options = {}) {
1348
1431
  const text = await res.text();
1349
1432
  if (!res.ok) {
1350
1433
  spinner.fail(`Publish failed (${res.status})`);
1351
- console.error(chalk13.red(text));
1434
+ console.error(chalk14.red(text));
1352
1435
  process.exitCode = 1;
1353
1436
  return;
1354
1437
  }
1355
1438
  if (alias) {
1356
- spinner.text = `Publishing ${chalk13.cyan(`${name}@${version2}`)} \u2014 setting alias ${chalk13.cyan(alias)}...`;
1439
+ spinner.text = `Publishing ${chalk14.cyan(`${name}@${version2}`)} \u2014 setting alias ${chalk14.cyan(alias)}...`;
1357
1440
  const aliasRes = await fetchWithTimeout5(
1358
1441
  `${registry}/publisher/skills/${encodeURIComponent(scope)}/${encodeURIComponent(skillName)}/alias`,
1359
1442
  {
@@ -1369,7 +1452,7 @@ async function publish(options = {}) {
1369
1452
  const aliasText = await aliasRes.text();
1370
1453
  if (!aliasRes.ok) {
1371
1454
  spinner.fail(`Failed to set alias (${aliasRes.status})`);
1372
- console.error(chalk13.red(aliasText));
1455
+ console.error(chalk14.red(aliasText));
1373
1456
  process.exitCode = 1;
1374
1457
  return;
1375
1458
  }
@@ -1378,18 +1461,18 @@ async function publish(options = {}) {
1378
1461
  console.log(text);
1379
1462
  return;
1380
1463
  }
1381
- const suffix = alias ? ` (alias: ${chalk13.cyan(alias)})` : "";
1382
- spinner.succeed(`Published ${chalk13.green(`${name}@${version2}`)}${suffix} (sha256:${integrity.slice(0, 12)}\u2026)`);
1464
+ const suffix = alias ? ` (alias: ${chalk14.cyan(alias)})` : "";
1465
+ spinner.succeed(`Published ${chalk14.green(`${name}@${version2}`)}${suffix} (sha256:${integrity.slice(0, 12)}\u2026)`);
1383
1466
  try {
1384
1467
  const parsed = JSON.parse(text);
1385
1468
  const warnings = Array.isArray(parsed.warnings) ? parsed.warnings.map(String).filter(Boolean) : [];
1386
- for (const w of warnings) console.warn(chalk13.yellow(`Warning: ${w}`));
1469
+ for (const w of warnings) console.warn(chalk14.yellow(`Warning: ${w}`));
1387
1470
  } catch {
1388
1471
  }
1389
1472
  } catch (error) {
1390
1473
  spinner.fail("Publish failed");
1391
1474
  const message = error instanceof SkildError9 ? error.message : error instanceof Error ? error.message : String(error);
1392
- console.error(chalk13.red(message));
1475
+ console.error(chalk14.red(message));
1393
1476
  process.exitCode = 1;
1394
1477
  } finally {
1395
1478
  fs3.rmSync(tempDir, { recursive: true, force: true });
@@ -1397,7 +1480,7 @@ async function publish(options = {}) {
1397
1480
  }
1398
1481
 
1399
1482
  // src/commands/search.ts
1400
- import chalk14 from "chalk";
1483
+ import chalk15 from "chalk";
1401
1484
  import { resolveRegistryUrl as resolveRegistryUrl6, searchRegistrySkills, SkildError as SkildError10 } from "@skild/core";
1402
1485
  async function search(query, options = {}) {
1403
1486
  const registryUrl = resolveRegistryUrl6(options.registry);
@@ -1409,39 +1492,39 @@ async function search(query, options = {}) {
1409
1492
  return;
1410
1493
  }
1411
1494
  if (!skills.length) {
1412
- console.log(chalk14.dim("No results."));
1495
+ console.log(chalk15.dim("No results."));
1413
1496
  return;
1414
1497
  }
1415
- console.log(chalk14.bold(`
1416
- \u{1F50E} Results (${skills.length}) \u2014 ${chalk14.dim(registryUrl)}
1498
+ console.log(chalk15.bold(`
1499
+ \u{1F50E} Results (${skills.length}) \u2014 ${chalk15.dim(registryUrl)}
1417
1500
  `));
1418
1501
  for (const s of skills) {
1419
1502
  const name = String(s.name || "").trim();
1420
1503
  const desc = String(s.description || "").trim();
1421
1504
  if (!name) continue;
1422
- console.log(` ${chalk14.cyan(name)}${desc ? chalk14.dim(` \u2014 ${desc}`) : ""}`);
1505
+ console.log(` ${chalk15.cyan(name)}${desc ? chalk15.dim(` \u2014 ${desc}`) : ""}`);
1423
1506
  }
1424
1507
  } catch (error) {
1425
1508
  const message = error instanceof SkildError10 ? error.message : error instanceof Error ? error.message : String(error);
1426
- console.error(chalk14.red(message));
1509
+ console.error(chalk15.red(message));
1427
1510
  process.exitCode = 1;
1428
1511
  }
1429
1512
  }
1430
1513
 
1431
1514
  // src/index.ts
1432
- import { PLATFORMS as PLATFORMS3 } from "@skild/core";
1515
+ import { PLATFORMS as PLATFORMS4 } from "@skild/core";
1433
1516
  var require2 = createRequire(import.meta.url);
1434
1517
  var { version } = require2("../package.json");
1435
1518
  var program = new Command();
1436
1519
  program.name("skild").description("The npm for Agent Skills \u2014 Discover, install, manage, and publish AI Agent Skills with ease.").version(version);
1437
- program.command("install <source>").alias("i").description("Install a Skill from a Git URL, degit shorthand, or local directory").option("-t, --target <platform>", `Target platform: ${PLATFORMS3.join(", ")}`).option("--all", `Install to all platforms: ${PLATFORMS3.join(", ")}`).option("--recursive", "If source is a multi-skill directory/repo, install all discovered skills").option("-y, --yes", "Skip confirmation prompts (assume yes)").option("--depth <n>", "Max directory depth to scan for SKILL.md (default: 6)", "6").option("--max-skills <n>", "Max discovered skills to install (default: 200)", "200").option("-l, --local", "Install to project-level directory instead of global").option("-f, --force", "Overwrite existing installation").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--json", "Output JSON").action(async (source, options) => {
1520
+ program.command("install <source>").alias("i").description("Install a Skill from a Git URL, degit shorthand, or local directory").option("-t, --target <platform>", `Target platform: ${PLATFORMS4.join(", ")}`).option("--all", `Install to all platforms: ${PLATFORMS4.join(", ")}`).option("--recursive", "If source is a multi-skill directory/repo, install all discovered skills").option("-y, --yes", "Skip confirmation prompts (assume yes)").option("--depth <n>", "Max directory depth to scan for SKILL.md (default: 6)", "6").option("--max-skills <n>", "Max discovered skills to install (default: 200)", "200").option("-l, --local", "Install to project-level directory instead of global").option("-f, --force", "Overwrite existing installation").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--json", "Output JSON").action(async (source, options) => {
1438
1521
  await install(source, options);
1439
1522
  });
1440
- program.command("list").alias("ls").description("List installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS3.join(", ")} (optional; omit to list all)`).option("-l, --local", "List project-level directory instead of global").option("--paths", "Show install paths").option("--verbose", "Show skillset dependency details").option("--json", "Output JSON").action(async (options) => list(options));
1441
- program.command("info <skill>").description("Show installed Skill details").option("-t, --target <platform>", `Target platform: ${PLATFORMS3.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => info(skill, options));
1442
- program.command("uninstall <skill>").alias("rm").description("Uninstall a Skill").option("-t, --target <platform>", `Target platform: ${PLATFORMS3.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("-f, --force", "Uninstall even if metadata is missing").option("--with-deps", "Uninstall dependencies that are only required by this skill").action(async (skill, options) => uninstall(skill, options));
1443
- program.command("update [skill]").alias("up").description("Update one or all installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS3.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => update(skill, options));
1444
- program.command("validate [target]").alias("v").description("Validate a Skill folder (path) or an installed Skill name").option("-t, --target <platform>", `Target platform: ${PLATFORMS3.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (target, options) => validate(target, options));
1523
+ program.command("list").alias("ls").description("List installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS4.join(", ")} (optional; omit to list all)`).option("-l, --local", "List project-level directory instead of global").option("--paths", "Show install paths").option("--verbose", "Show skillset dependency details").option("--json", "Output JSON").action(async (options) => list(options));
1524
+ program.command("info <skill>").description("Show installed Skill details").option("-t, --target <platform>", `Target platform: ${PLATFORMS4.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => info(skill, options));
1525
+ program.command("uninstall <skill>").alias("rm").description("Uninstall a Skill").option("-t, --target <platform>", `Target platform: ${PLATFORMS4.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("-f, --force", "Uninstall even if metadata is missing").option("--with-deps", "Uninstall dependencies that are only required by this skill").action(async (skill, options) => uninstall(skill, options));
1526
+ program.command("update [skill]").alias("up").description("Update one or all installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS4.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => update(skill, options));
1527
+ program.command("validate [target]").alias("v").description("Validate a Skill folder (path) or an installed Skill name").option("-t, --target <platform>", `Target platform: ${PLATFORMS4.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (target, options) => validate(target, options));
1445
1528
  program.command("init <name>").description("Create a new Skill project").option("--dir <path>", "Target directory (defaults to <name>)").option("--description <text>", "Skill description").option("-f, --force", "Overwrite target directory if it exists").action(async (name, options) => init(name, options));
1446
1529
  program.command("signup").description("Create a publisher account in the registry (no GitHub required)").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--email <email>", "Email (optional; will prompt)").option("--handle <handle>", "Publisher handle (owns @handle/* scope) (optional; will prompt)").option("--password <password>", "Password (optional; will prompt)").option("--json", "Output JSON").action(async (options) => signup(options));
1447
1530
  program.command("login").description("Login to a registry and store an access token locally").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--handle-or-email <value>", "Handle or email (optional; will prompt)").option("--password <password>", "Password (optional; will prompt)").option("--token-name <name>", "Token label").option("--json", "Output JSON").action(async (options) => login(options));
@@ -1450,7 +1533,7 @@ program.command("whoami").description("Show current registry identity").action(a
1450
1533
  program.command("publish").description("Publish a Skill directory to the registry (hosted tarball)").option("--dir <path>", "Skill directory (defaults to cwd)").option("--name <@publisher/skill>", "Override skill name (defaults to SKILL.md frontmatter)").option("--skill-version <semver>", "Override version (defaults to SKILL.md frontmatter)").option("--alias <alias>", "Optional short identifier (global unique) for `skild install <alias>`").option("--description <text>", "Override description (defaults to SKILL.md frontmatter)").option("--targets <list>", "Comma-separated target platforms metadata (optional)").option("--tag <tag>", "Dist-tag (default: latest)", "latest").option("--registry <url>", "Registry base URL (defaults to saved login)").option("--json", "Output JSON").action(async (options) => publish(options));
1451
1534
  program.command("search <query>").description("Search Skills in the registry").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--limit <n>", "Max results (default: 50)", "50").option("--json", "Output JSON").action(async (query, options) => search(query, options));
1452
1535
  program.action(() => {
1453
- console.log(chalk15.bold("\n\u{1F6E1}\uFE0F skild \u2014 Get your agents skilled.\n"));
1536
+ console.log(chalk16.bold("\n\u{1F6E1}\uFE0F skild \u2014 Get your agents skilled.\n"));
1454
1537
  program.outputHelp();
1455
1538
  });
1456
1539
  var argv = process.argv.slice();