skillmds 1.3.8 → 1.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -36,39 +36,622 @@ import {
36
36
  // src/index.ts
37
37
  import { Command as Command13 } from "commander";
38
38
  import { readFileSync as readFileSync3 } from "fs";
39
- import pc15 from "picocolors";
39
+ import pc17 from "picocolors";
40
40
 
41
41
  // src/commands/lint.ts
42
42
  import { Command } from "commander";
43
43
  import { writeFileSync } from "fs";
44
44
  import { homedir as homedir2 } from "os";
45
45
  import { resolve as resolve2 } from "path";
46
+ import pc4 from "picocolors";
47
+
48
+ // src/prompts.ts
49
+ import { ConfirmPrompt, MultiSelectPrompt, PasswordPrompt, SelectPrompt, TextPrompt, block } from "@clack/core";
46
50
  import pc2 from "picocolors";
47
- import * as p from "@clack/prompts";
51
+
52
+ // src/brand.ts
53
+ import pc from "picocolors";
54
+
55
+ // src/env.ts
56
+ function detectHostAgent(env = process.env) {
57
+ if (env.CLAUDECODE) return "claude-code";
58
+ if (env.CURSOR_AGENT || env.CURSOR_EXTENSION_HOST_ROLE === "agent-exec") return "cursor";
59
+ if (env.CODEX_SANDBOX || env.CODEX_THREAD_ID) return "codex";
60
+ if (env.GEMINI_CLI) return "gemini-cli";
61
+ if (env.CI && env.CI !== "false" && env.CI !== "0") return "ci";
62
+ return null;
63
+ }
64
+ var realTerminal = () => ({
65
+ stdinTTY: Boolean(process.stdin.isTTY),
66
+ stdoutTTY: Boolean(process.stdout.isTTY),
67
+ env: process.env
68
+ });
69
+ function isInteractive(flags, term = realTerminal()) {
70
+ if (flags.yes || flags.json) return false;
71
+ if (!term.stdinTTY || !term.stdoutTTY) return false;
72
+ return detectHostAgent(term.env) === null;
73
+ }
74
+ function scopesFor(flags) {
75
+ return flags.global && !flags.project ? [true] : flags.project && !flags.global ? [false] : [false, true];
76
+ }
77
+ function nonInteractiveHint(flags) {
78
+ return `Interactive prompt required but stdin is not a terminal. Nothing was changed. Re-run with ${flags} to run non-interactively.`;
79
+ }
80
+ function promptIf(flags, prompt) {
81
+ const term = { stdinTTY: Boolean(process.stdin.isTTY), stdoutTTY: Boolean(process.stdout.isTTY), env: flags.env ?? process.env };
82
+ return isInteractive(flags, term) ? { prompt } : {};
83
+ }
84
+
85
+ // src/brand.ts
86
+ function unicodeSupported(env = process.env, platform = process.platform) {
87
+ if (platform !== "win32") return env.TERM !== "linux";
88
+ return Boolean(env.CI) || Boolean(env.WT_SESSION) || Boolean(env.TERMINUS_SUBLIME) || env.ConEmuTask === "{cmd::Cmder}" || env.TERM_PROGRAM === "Terminus-Sublime" || env.TERM_PROGRAM === "vscode" || env.TERM === "xterm-256color" || env.TERM === "alacritty" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
89
+ }
90
+ function truecolor(env = process.env) {
91
+ if (/^(truecolor|24bit)$/i.test(env.COLORTERM ?? "")) return true;
92
+ if (env.WT_SESSION || env.KITTY_WINDOW_ID) return true;
93
+ if (/^(vscode|iTerm\.app|WezTerm|Hyper|ghostty)$/.test(env.TERM_PROGRAM ?? "")) return true;
94
+ return /(truecolor|24bit|direct|kitty|ghostty)/i.test(env.TERM ?? "");
95
+ }
96
+ function orange(text2, env = process.env, colour = pc.isColorSupported) {
97
+ if (!colour) return text2;
98
+ const open = truecolor(env) ? "\x1B[38;2;214;83;41m" : "\x1B[38;5;166m";
99
+ return `${open}${text2}\x1B[39m`;
100
+ }
101
+ function canAnimate(stream, env = process.env) {
102
+ return Boolean(stream.isTTY) && detectHostAgent(env) === null && env.TERM !== "dumb" && unicodeSupported(env);
103
+ }
104
+ var SPINNERS = {
105
+ drop: { frames: [" ", "\u2580 ", "\u2584 ", "\u2584\u2580", "\u2584\u2580", "\u2584\u2580", "\u2584\u2580", "\u2584\u2580", " "], interval: 90 },
106
+ hop: { frames: ["\u2584\u2580", "\u2580\u2584"], interval: 240 },
107
+ walk: { frames: ["\u2584\u2580 ", " \u2584\u2580 ", " \u2584\u2580", " \u2584", " ", "\u2580 "], interval: 110 }
108
+ };
109
+ var ASCII_SPINNER = { frames: ["\u2022", "o", "O", "0"], interval: 120 };
110
+ async function waitFor(kind, message, work, opts = {}) {
111
+ const stream = opts.stream ?? process.stderr;
112
+ const env = opts.env ?? process.env;
113
+ const job = typeof work === "function" ? work() : work;
114
+ const show = !opts.json && canAnimate(stream, env) && canAnimate(opts.also ?? process.stdout, env);
115
+ if (!show) return job;
116
+ const { frames, interval } = SPINNERS[kind];
117
+ const text2 = message.replace(/[.…]+$/, "");
118
+ let i = 0;
119
+ const draw = () => stream.write(`\r\x1B[2K${orange(frames[i++ % frames.length], env)} ${text2}\u2026`);
120
+ stream.write("\x1B[?25l");
121
+ draw();
122
+ const timer = setInterval(draw, interval);
123
+ const restore = () => stream.write("\x1B[?25h");
124
+ process.once("exit", restore);
125
+ try {
126
+ return await job;
127
+ } finally {
128
+ clearInterval(timer);
129
+ stream.write("\r\x1B[2K\x1B[?25h");
130
+ process.removeListener("exit", restore);
131
+ }
132
+ }
133
+ var LETTERS = [
134
+ { x: 0, rows: { 3: ".########", 4: "#########", 5: "##.......", 6: "########.", 7: ".########", 8: ".......##", 9: "#########", 10: "########." } },
135
+ // s
136
+ { x: 10, rows: { 0: "##", 1: "##", 2: "##", 3: "##...##", 4: "##..##", 5: "##.##", 6: "####", 7: "####", 8: "##.##", 9: "##..##", 10: "##...##" } },
137
+ // k
138
+ { x: 18, rows: { 0: "##", 1: "##", 3: "##", 4: "##", 5: "##", 6: "##", 7: "##", 8: "##", 9: "##", 10: "##" } },
139
+ // i
140
+ { x: 21, rows: Object.fromEntries([...Array(11).keys()].map((r) => [r, "##"])) },
141
+ // l
142
+ { x: 24, rows: Object.fromEntries([...Array(11).keys()].map((r) => [r, "##"])) },
143
+ // l
144
+ { x: 28, md: true, rows: { 3: ".#########", 4: "##########", 5: "##...##...##", 6: "##...##...##", 7: "##...##...##", 8: "##...##...##", 9: "##...##...##", 10: "##...##...##" } },
145
+ // m
146
+ { x: 41, md: true, rows: { 0: "......##", 1: "......##", 2: "......##", 3: ".#######", 4: "########", 5: "##....##", 6: "##....##", 7: "##....##", 8: "##....##", 9: "######", 10: "######" } }
147
+ // d
148
+ ];
149
+ var WORDMARK_WIDTH = 54;
150
+ var CANVAS_ROWS = 12;
151
+ var SQUARES = [{ x: 50, y: 10 }, { x: 52, y: 8 }];
152
+ function wordmarkLines(squares = SQUARES, paint = (s2) => orange(s2)) {
153
+ const grid = [...Array(CANVAS_ROWS)].map(() => Array(WORDMARK_WIDTH).fill(null));
154
+ for (const L of LETTERS) {
155
+ for (const [r, row] of Object.entries(L.rows)) {
156
+ [...row].forEach((c, i) => {
157
+ if (c === "#") grid[Number(r) + 1][L.x + i] = L.md ? "md" : "ink";
158
+ });
159
+ }
160
+ }
161
+ for (const sq of squares) {
162
+ for (let dy = 0; dy < 2; dy++) for (let dx = 0; dx < 2; dx++) {
163
+ const y = Math.round(sq.y) + dy, x = Math.round(sq.x) + dx;
164
+ if (y >= 0 && y < CANVAS_ROWS && x >= 0 && x < WORDMARK_WIDTH) grid[y][x] = "md";
165
+ }
166
+ }
167
+ const lines = [];
168
+ for (let r = 0; r < CANVAS_ROWS; r += 2) {
169
+ let line = "";
170
+ let run2 = "";
171
+ let runMd = false;
172
+ const flush = () => {
173
+ if (run2) line += runMd ? paint(run2) : run2;
174
+ run2 = "";
175
+ };
176
+ let end = WORDMARK_WIDTH;
177
+ while (end > 0 && !grid[r][end - 1] && !grid[r + 1][end - 1]) end--;
178
+ for (let x = 0; x < end; x++) {
179
+ const top = grid[r][x], bottom = grid[r + 1][x];
180
+ const md = (top ?? bottom) === "md";
181
+ const ch = top && bottom ? "\u2588" : top ? "\u2580" : bottom ? "\u2584" : " ";
182
+ if (ch !== " " && md !== runMd) flush();
183
+ if (ch !== " ") runMd = md;
184
+ run2 += ch;
185
+ }
186
+ flush();
187
+ lines.push(line);
188
+ }
189
+ return lines;
190
+ }
191
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
192
+ var easeIn = (t) => t * t;
193
+ async function playLogo(opts = {}) {
194
+ const out = opts.out ?? process.stdout;
195
+ const input = opts.input ?? process.stdin;
196
+ const env = opts.env ?? process.env;
197
+ const indent = opts.indent ?? " ";
198
+ const animate = opts.animate ?? (canAnimate(out, env) && pc.isColorSupported && Boolean(input.isTTY));
199
+ const show = (lines) => lines.map((l) => l ? indent + l : "").join("\n");
200
+ if (!animate) {
201
+ out.write(`${show(wordmarkLines())}
202
+ `);
203
+ return;
204
+ }
205
+ let skipped = false;
206
+ const onKey = (key) => {
207
+ skipped = true;
208
+ if (key.toString() === "") {
209
+ out.write("\x1B[?25h\n");
210
+ process.exit(130);
211
+ }
212
+ };
213
+ const restoreCursor = () => out.write("\x1B[?25h");
214
+ out.write("\x1B[?25l");
215
+ process.once("exit", restoreCursor);
216
+ input.setRawMode?.(true);
217
+ input.on("data", onKey);
218
+ input.resume();
219
+ let drawn = 0;
220
+ const paint = (squares) => {
221
+ const lines = wordmarkLines(squares);
222
+ out.write(`${drawn ? `\x1B[${drawn}A` : ""}${lines.map((l) => `\x1B[2K${l ? indent + l : ""}`).join("\n")}
223
+ `);
224
+ drawn = lines.length;
225
+ };
226
+ try {
227
+ paint([]);
228
+ await sleep(160);
229
+ const [first, second] = SQUARES;
230
+ for (const [n, target] of [first, second].entries()) {
231
+ const landed = n === 0 ? [] : [first];
232
+ const steps = 9;
233
+ for (let s2 = 0; s2 <= steps && !skipped; s2++) {
234
+ paint([...landed, { x: target.x, y: -2 + (target.y + 2) * easeIn(s2 / steps) }]);
235
+ await sleep(22);
236
+ }
237
+ if (skipped) break;
238
+ paint([...landed, { x: target.x, y: target.y - 1 }]);
239
+ await sleep(40);
240
+ paint([...landed, target]);
241
+ await sleep(90);
242
+ }
243
+ } finally {
244
+ paint(SQUARES);
245
+ input.removeListener("data", onKey);
246
+ input.setRawMode?.(false);
247
+ input.pause();
248
+ out.write("\x1B[?25h");
249
+ process.removeListener("exit", restoreCursor);
250
+ }
251
+ }
252
+ function brandWord(env = process.env, colour = pc.isColorSupported) {
253
+ return `${colour ? pc.bold("skill") : "skill"}${colour ? pc.bold(orange("md", env, colour)) : "md"}`;
254
+ }
255
+
256
+ // src/prompts.ts
257
+ import { isCancel } from "@clack/core";
258
+ var unicode = unicodeSupported();
259
+ var s = (c, fallback) => unicode ? c : fallback;
260
+ var S_STEP_ACTIVE = s("\u25C6", "*");
261
+ var S_STEP_CANCEL = s("\u25A0", "x");
262
+ var S_STEP_ERROR = s("\u25B2", "x");
263
+ var S_STEP_SUBMIT = s("\u25C7", "o");
264
+ var S_BAR_START = s("\u250C", "T");
265
+ var S_BAR = s("\u2502", "|");
266
+ var S_BAR_END = s("\u2514", "\u2014");
267
+ var S_RADIO_ACTIVE = s("\u25CF", ">");
268
+ var S_RADIO_INACTIVE = s("\u25CB", " ");
269
+ var S_CHECKBOX_ACTIVE = s("\u25FB", "[\u2022]");
270
+ var S_CHECKBOX_SELECTED = s("\u25FC", "[+]");
271
+ var S_CHECKBOX_INACTIVE = s("\u25FB", "[ ]");
272
+ var S_PASSWORD_MASK = s("\u25AA", "\u2022");
273
+ var S_BAR_H = s("\u2500", "-");
274
+ var S_CORNER_TOP_RIGHT = s("\u256E", "+");
275
+ var S_CONNECT_LEFT = s("\u251C", "+");
276
+ var S_CORNER_BOTTOM_RIGHT = s("\u256F", "+");
277
+ var S_INFO = s("\u25CF", "\u2022");
278
+ var S_SUCCESS = s("\u25C6", "*");
279
+ var S_WARN = s("\u25B2", "!");
280
+ var S_ERROR = s("\u25A0", "x");
281
+ var accent = (text2) => orange(text2);
282
+ var bar = pc2.gray(S_BAR);
283
+ var symbol = (state) => {
284
+ switch (state) {
285
+ case "initial":
286
+ case "active":
287
+ return accent(S_STEP_ACTIVE);
288
+ case "cancel":
289
+ return pc2.red(S_STEP_CANCEL);
290
+ case "error":
291
+ return pc2.yellow(S_STEP_ERROR);
292
+ case "submit":
293
+ return accent(S_STEP_SUBMIT);
294
+ }
295
+ };
296
+ var skipLead = false;
297
+ function startFrameAfterLogo() {
298
+ skipLead = true;
299
+ }
300
+ var lead = () => {
301
+ if (skipLead) {
302
+ skipLead = false;
303
+ return "";
304
+ }
305
+ return `${bar}
306
+ `;
307
+ };
308
+ var hint = (text2) => text2 ? ` ${pc2.dim(text2)}` : "";
309
+ var keys = (text2) => pc2.dim(text2);
310
+ function limitOptions(params) {
311
+ const { cursor, options, style } = params;
312
+ const outputMaxItems = Math.max((process.stdout.rows ?? 24) - 4, 0);
313
+ const maxItems = Math.min(outputMaxItems, Math.max(params.maxItems ?? Infinity, 5));
314
+ let window = 0;
315
+ if (cursor >= window + maxItems - 3) window = Math.max(Math.min(cursor - maxItems + 3, options.length - maxItems), 0);
316
+ else if (cursor < window + 2) window = Math.max(cursor - 2, 0);
317
+ const topEllipsis = maxItems < options.length && window > 0;
318
+ const bottomEllipsis = maxItems < options.length && window + maxItems < options.length;
319
+ return options.slice(window, window + maxItems).map((option, i, arr) => i === 0 && topEllipsis || i === arr.length - 1 && bottomEllipsis ? pc2.dim("...") : style(option, i + window === cursor));
320
+ }
321
+ var text = (opts) => {
322
+ const top = lead();
323
+ return new TextPrompt({
324
+ validate: opts.validate,
325
+ placeholder: opts.placeholder,
326
+ defaultValue: opts.defaultValue,
327
+ initialValue: opts.initialValue,
328
+ render() {
329
+ const title = `${top}${symbol(this.state)} ${opts.message}
330
+ `;
331
+ const placeholder = opts.placeholder ? pc2.inverse(opts.placeholder[0]) + pc2.dim(opts.placeholder.slice(1)) : pc2.inverse(pc2.hidden("_"));
332
+ const value = !this.value ? placeholder : this.valueWithCursor;
333
+ switch (this.state) {
334
+ case "error":
335
+ return `${title.trim()}
336
+ ${pc2.yellow(S_BAR)} ${value}
337
+ ${pc2.yellow(S_BAR_END)} ${pc2.yellow(this.error)}
338
+ `;
339
+ case "submit":
340
+ return `${title}${bar} ${pc2.dim(this.value || opts.placeholder || "")}`;
341
+ case "cancel":
342
+ return `${title}${bar} ${pc2.strikethrough(pc2.dim(this.value ?? ""))}${this.value?.trim() ? `
343
+ ${bar}` : ""}`;
344
+ default:
345
+ return `${title}${bar} ${value}
346
+ ${pc2.gray(S_BAR_END)}
347
+ `;
348
+ }
349
+ }
350
+ }).prompt();
351
+ };
352
+ var password = (opts) => {
353
+ const top = lead();
354
+ return new PasswordPrompt({
355
+ validate: opts.validate,
356
+ mask: opts.mask ?? S_PASSWORD_MASK,
357
+ render() {
358
+ const title = `${top}${symbol(this.state)} ${opts.message}
359
+ `;
360
+ const masked = this.masked;
361
+ switch (this.state) {
362
+ case "error":
363
+ return `${title.trim()}
364
+ ${pc2.yellow(S_BAR)} ${masked}
365
+ ${pc2.yellow(S_BAR_END)} ${pc2.yellow(this.error)}
366
+ `;
367
+ case "submit":
368
+ return `${title}${bar} ${pc2.dim(masked)}`;
369
+ case "cancel":
370
+ return `${title}${bar} ${pc2.strikethrough(pc2.dim(masked ?? ""))}${masked ? `
371
+ ${bar}` : ""}`;
372
+ default:
373
+ return `${title}${bar} ${this.valueWithCursor}
374
+ ${pc2.gray(S_BAR_END)}
375
+ `;
376
+ }
377
+ }
378
+ }).prompt();
379
+ };
380
+ var confirm = (opts) => {
381
+ const active = opts.active ?? "Yes";
382
+ const inactive = opts.inactive ?? "No";
383
+ const top = lead();
384
+ return new ConfirmPrompt({
385
+ active,
386
+ inactive,
387
+ initialValue: opts.initialValue ?? true,
388
+ render() {
389
+ const title = `${top}${symbol(this.state)} ${opts.message}
390
+ `;
391
+ const value = this.value ? active : inactive;
392
+ switch (this.state) {
393
+ case "submit":
394
+ return `${title}${bar} ${pc2.dim(value)}`;
395
+ case "cancel":
396
+ return `${title}${bar} ${pc2.strikethrough(pc2.dim(value))}
397
+ ${bar}`;
398
+ default: {
399
+ const on = (label2) => `${accent(S_RADIO_ACTIVE)} ${label2}`;
400
+ const off = (label2) => `${pc2.dim(S_RADIO_INACTIVE)} ${pc2.dim(label2)}`;
401
+ return `${title}${bar} ${this.value ? on(active) : off(active)} ${pc2.dim("/")} ${!this.value ? on(inactive) : off(inactive)}
402
+ ${pc2.gray(S_BAR_END)}
403
+ `;
404
+ }
405
+ }
406
+ }
407
+ }).prompt();
408
+ };
409
+ var select = (opts) => {
410
+ const opt = (option, state) => {
411
+ const label2 = option.label ?? String(option.value);
412
+ switch (state) {
413
+ case "selected":
414
+ return pc2.dim(label2);
415
+ case "active":
416
+ return `${accent(S_RADIO_ACTIVE)} ${label2}${hint(option.hint)}`;
417
+ case "cancelled":
418
+ return pc2.strikethrough(pc2.dim(label2));
419
+ default:
420
+ return `${pc2.dim(S_RADIO_INACTIVE)} ${pc2.dim(label2)}`;
421
+ }
422
+ };
423
+ const top = lead();
424
+ return new SelectPrompt({
425
+ options: opts.options,
426
+ initialValue: opts.initialValue,
427
+ render() {
428
+ const title = `${top}${symbol(this.state)} ${opts.message}
429
+ `;
430
+ switch (this.state) {
431
+ case "submit":
432
+ return `${title}${bar} ${opt(this.options[this.cursor], "selected")}`;
433
+ case "cancel":
434
+ return `${title}${bar} ${opt(this.options[this.cursor], "cancelled")}
435
+ ${bar}`;
436
+ default:
437
+ return `${title}${bar} ${limitOptions({
438
+ cursor: this.cursor,
439
+ options: this.options,
440
+ maxItems: opts.maxItems,
441
+ style: (item, isActive) => opt(item, isActive ? "active" : "inactive")
442
+ }).join(`
443
+ ${bar} `)}
444
+ ${pc2.gray(S_BAR_END)} ${keys("\u2191/\u2193 to move \xB7 enter to choose")}
445
+ `;
446
+ }
447
+ }
448
+ }).prompt();
449
+ };
450
+ var multiselect = (opts) => {
451
+ const opt = (option, state) => {
452
+ const label2 = option.label ?? String(option.value);
453
+ switch (state) {
454
+ case "active":
455
+ return `${accent(S_CHECKBOX_ACTIVE)} ${label2}${hint(option.hint)}`;
456
+ case "selected":
457
+ return `${accent(S_CHECKBOX_SELECTED)} ${pc2.dim(label2)}`;
458
+ case "cancelled":
459
+ return pc2.strikethrough(pc2.dim(label2));
460
+ case "active-selected":
461
+ return `${accent(S_CHECKBOX_SELECTED)} ${label2}${hint(option.hint)}`;
462
+ case "submitted":
463
+ return pc2.dim(label2);
464
+ default:
465
+ return `${pc2.dim(S_CHECKBOX_INACTIVE)} ${pc2.dim(label2)}`;
466
+ }
467
+ };
468
+ const top = lead();
469
+ return new MultiSelectPrompt({
470
+ options: opts.options,
471
+ initialValues: opts.initialValues,
472
+ required: opts.required ?? true,
473
+ cursorAt: opts.cursorAt,
474
+ validate(selected) {
475
+ if (this.required && selected.length === 0) {
476
+ return `Please select at least one option.
477
+ ${pc2.reset(pc2.dim("Press space to select, enter to confirm"))}`;
478
+ }
479
+ },
480
+ render() {
481
+ const title = `${top}${symbol(this.state)} ${opts.message}
482
+ `;
483
+ const styleOption = (option, isActive) => {
484
+ const selected = this.value.includes(option.value);
485
+ if (isActive && selected) return opt(option, "active-selected");
486
+ if (selected) return opt(option, "selected");
487
+ return opt(option, isActive ? "active" : "inactive");
488
+ };
489
+ const list = (edge) => limitOptions({
490
+ options: this.options,
491
+ cursor: this.cursor,
492
+ maxItems: opts.maxItems,
493
+ style: styleOption
494
+ }).join(`
495
+ ${edge} `);
496
+ switch (this.state) {
497
+ case "submit":
498
+ return `${title}${bar} ${this.options.filter(({ value }) => this.value.includes(value)).map((o) => opt(o, "submitted")).join(pc2.dim(", ")) || pc2.dim("none")}`;
499
+ case "cancel": {
500
+ const label2 = this.options.filter(({ value }) => this.value.includes(value)).map((o) => opt(o, "cancelled")).join(pc2.dim(", "));
501
+ return `${title}${bar} ${label2.trim() ? `${label2}
502
+ ${bar}` : ""}`;
503
+ }
504
+ case "error": {
505
+ const footer = this.error.split("\n").map((ln, i) => i === 0 ? `${pc2.yellow(S_BAR_END)} ${pc2.yellow(ln)}` : ` ${ln}`).join("\n");
506
+ return `${title}${pc2.yellow(S_BAR)} ${list(pc2.yellow(S_BAR))}
507
+ ${footer}
508
+ `;
509
+ }
510
+ default:
511
+ return `${title}${bar} ${list(bar)}
512
+ ${pc2.gray(S_BAR_END)} ${keys("space to select \xB7 enter to confirm")}
513
+ `;
514
+ }
515
+ }
516
+ }).prompt();
517
+ };
518
+ var strip = (str) => str.replace(ansiRegex(), "");
519
+ var note = (message = "", title = "") => {
520
+ const lines = `
521
+ ${message}
522
+ `.split("\n");
523
+ const titleLen = strip(title).length;
524
+ const len = Math.max(lines.reduce((max, ln) => Math.max(max, strip(ln).length), 0), titleLen) + 2;
525
+ const msg2 = lines.map((ln) => `${bar} ${pc2.dim(ln)}${" ".repeat(len - strip(ln).length)}${bar}`).join("\n");
526
+ process.stdout.write(
527
+ `${lead()}${accent(S_STEP_SUBMIT)} ${pc2.reset(title)} ${pc2.gray(S_BAR_H.repeat(Math.max(len - titleLen - 1, 1)) + S_CORNER_TOP_RIGHT)}
528
+ ${msg2}
529
+ ${pc2.gray(S_CONNECT_LEFT + S_BAR_H.repeat(len + 2) + S_CORNER_BOTTOM_RIGHT)}
530
+ `
531
+ );
532
+ };
533
+ var cancel = (message = "") => {
534
+ process.stdout.write(`${pc2.gray(S_BAR_END)} ${pc2.red(message)}
535
+
536
+ `);
537
+ };
538
+ var intro = (title = "") => {
539
+ skipLead = false;
540
+ process.stdout.write(`${pc2.gray(S_BAR_START)} ${title}
541
+ `);
542
+ };
543
+ var outro = (message = "") => {
544
+ process.stdout.write(`${bar}
545
+ ${pc2.gray(S_BAR_END)} ${message}
546
+
547
+ `);
548
+ };
549
+ var log = {
550
+ message: (message = "", { symbol: mark = bar } = {}) => {
551
+ const top = lead().replace(/\n$/, "");
552
+ const parts = top ? [top] : [];
553
+ if (message) {
554
+ const [first, ...rest] = message.split("\n");
555
+ parts.push(`${mark} ${first}`, ...rest.map((ln) => `${bar} ${ln}`));
556
+ }
557
+ process.stdout.write(`${parts.join("\n")}
558
+ `);
559
+ },
560
+ info: (message) => log.message(message, { symbol: accent(S_INFO) }),
561
+ success: (message) => log.message(message, { symbol: pc2.green(S_SUCCESS) }),
562
+ step: (message) => log.message(message, { symbol: accent(S_STEP_SUBMIT) }),
563
+ warn: (message) => log.message(message, { symbol: pc2.yellow(S_WARN) }),
564
+ warning: (message) => log.warn(message),
565
+ error: (message) => log.message(message, { symbol: pc2.red(S_ERROR) })
566
+ };
567
+ var spinner = (kind = "drop") => {
568
+ const { frames, interval } = unicode ? SPINNERS[kind] : ASCII_SPINNER;
569
+ let unblock = () => {
570
+ };
571
+ let loop;
572
+ let active = false;
573
+ let message = "";
574
+ const handleExit = (code) => {
575
+ if (active) stop(code > 1 ? "Something went wrong" : "Canceled", code);
576
+ };
577
+ const onError = () => handleExit(2);
578
+ const onSignal = () => handleExit(1);
579
+ const registerHooks = () => {
580
+ process.on("uncaughtExceptionMonitor", onError);
581
+ process.on("unhandledRejection", onError);
582
+ process.on("SIGINT", onSignal);
583
+ process.on("SIGTERM", onSignal);
584
+ process.on("exit", handleExit);
585
+ };
586
+ const clearHooks = () => {
587
+ process.removeListener("uncaughtExceptionMonitor", onError);
588
+ process.removeListener("unhandledRejection", onError);
589
+ process.removeListener("SIGINT", onSignal);
590
+ process.removeListener("SIGTERM", onSignal);
591
+ process.removeListener("exit", handleExit);
592
+ };
593
+ const start = (msg2 = "") => {
594
+ active = true;
595
+ unblock = block();
596
+ message = msg2.replace(/[.…]+$/, "");
597
+ process.stdout.write(lead());
598
+ let i = 0;
599
+ const draw = () => {
600
+ process.stdout.write(`\r\x1B[J${accent(frames[i])} ${message}\u2026`);
601
+ i = (i + 1) % frames.length;
602
+ };
603
+ process.stdout.write("\x1B[?25l");
604
+ registerHooks();
605
+ draw();
606
+ loop = setInterval(draw, interval);
607
+ };
608
+ const stop = (msg2 = "", code = 0) => {
609
+ message = msg2 || message;
610
+ active = false;
611
+ if (loop) clearInterval(loop);
612
+ const mark = code === 0 ? pc2.green(S_STEP_SUBMIT) : code === 1 ? pc2.red(S_STEP_CANCEL) : pc2.red(S_STEP_ERROR);
613
+ process.stdout.write(`\r\x1B[J${mark} ${message}
614
+ \x1B[?25h`);
615
+ clearHooks();
616
+ unblock();
617
+ };
618
+ return { start, stop, message: (msg2 = "") => {
619
+ message = msg2 || message;
620
+ } };
621
+ };
622
+ function ansiRegex() {
623
+ const pattern = [
624
+ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
625
+ "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"
626
+ ].join("|");
627
+ return new RegExp(pattern, "g");
628
+ }
629
+
630
+ // src/commands/lint.ts
48
631
  import { lint, toJson, toSarif, toGithub } from "@skillmds/core";
49
632
 
50
633
  // src/ui.ts
51
634
  import { homedir } from "os";
52
635
  import { relative, resolve, sep } from "path";
53
- import pc from "picocolors";
54
- var decorate = (text3, kind) => {
636
+ import pc3 from "picocolors";
637
+ var decorate = (text2, kind) => {
55
638
  switch (kind) {
56
639
  case "error":
57
- return pc.red(text3);
640
+ return pc3.red(text2);
58
641
  case "warn":
59
- return pc.yellow(text3);
642
+ return pc3.yellow(text2);
60
643
  case "info":
61
- return pc.cyan(text3);
644
+ return pc3.cyan(text2);
62
645
  case "ok":
63
- return pc.green(text3);
646
+ return pc3.green(text2);
64
647
  case "dim":
65
- return pc.dim(text3);
648
+ return pc3.dim(text2);
66
649
  }
67
650
  };
68
651
  var SEV_COLOR = {
69
- error: pc.red,
70
- warn: pc.yellow,
71
- info: pc.cyan
652
+ error: pc3.red,
653
+ warn: pc3.yellow,
654
+ info: pc3.cyan
72
655
  };
73
656
  var GLYPH = {
74
657
  error: "\u2716",
@@ -84,7 +667,7 @@ var SEV_ORDER = ["error", "warn", "info"];
84
667
  function chips(result) {
85
668
  const bySev = { error: [], warn: [], info: [] };
86
669
  for (const d of result.diagnostics) bySev[d.severity].push(d.id);
87
- return SEV_ORDER.filter((s) => bySev[s].length).map((s) => `${GLYPH[s]} ${SEV_COLOR[s](bySev[s].join(" "))}`).join(" ");
670
+ return SEV_ORDER.filter((s2) => bySev[s2].length).map((s2) => `${GLYPH[s2]} ${SEV_COLOR[s2](bySev[s2].join(" "))}`).join(" ");
88
671
  }
89
672
  var SEC_LABEL = {
90
673
  network_calls: "Calls Network",
@@ -92,7 +675,7 @@ var SEC_LABEL = {
92
675
  reads_secrets: "Reads Secrets"
93
676
  };
94
677
  var titleCase = (flag) => flag.split("_").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
95
- var scoreColor = (s) => s >= 80 ? pc.green : s >= 50 ? pc.yellow : pc.red;
678
+ var scoreColor = (s2) => s2 >= 80 ? pc3.green : s2 >= 50 ? pc3.yellow : pc3.red;
96
679
  function label(file) {
97
680
  const parts = file.split(/[\\/]/).filter(Boolean);
98
681
  const i = parts.lastIndexOf("SKILL.md");
@@ -103,27 +686,27 @@ function securityFlags(result) {
103
686
  }
104
687
  function secLabels(result) {
105
688
  const flags = securityFlags(result);
106
- return flags.map((f) => pc.magenta(`${SEC_GLYPH} ${SEC_LABEL[f] ?? titleCase(f)}`)).join(" ");
689
+ return flags.map((f) => pc3.magenta(`${SEC_GLYPH} ${SEC_LABEL[f] ?? titleCase(f)}`)).join(" ");
107
690
  }
108
691
  function statusDot(result) {
109
- if (!result.ok) return pc.red("\u25CF");
692
+ if (!result.ok) return pc3.red("\u25CF");
110
693
  const attention = result.diagnostics.some((d) => d.severity === "warn") || securityFlags(result).length > 0;
111
- return attention ? pc.yellow("\u25CF") : pc.green("\u25CF");
694
+ return attention ? pc3.yellow("\u25CF") : pc3.green("\u25CF");
112
695
  }
113
696
  function failureBlock(file, result) {
114
- const lines = [`${pc.red(GLYPH.error)} ${pc.bold(label(file))}`];
697
+ const lines = [`${pc3.red(GLYPH.error)} ${pc3.bold(label(file))}`];
115
698
  for (const d of result.diagnostics.filter((x) => x.severity === "error")) {
116
- const loc = d.line !== void 0 ? pc.dim(`:${d.line}`) : "";
699
+ const loc = d.line !== void 0 ? pc3.dim(`:${d.line}`) : "";
117
700
  lines.push(` ${SEV_COLOR.error(d.id)}${loc} ${d.message}`);
118
701
  }
119
- lines.push(` ${pc.dim(file)}`);
702
+ lines.push(` ${pc3.dim(file)}`);
120
703
  return lines.join("\n");
121
704
  }
122
705
  function renderOne(file, result) {
123
- const status = result.ok ? pc.green("\u25CF PASS") : pc.red("\u25CF FAIL");
124
- const out = [`${status} ${pc.bold(label(file))} ${pc.dim("quality")} ${scoreColor(result.score)(`${result.score}/100`)}`];
706
+ const status = result.ok ? pc3.green("\u25CF PASS") : pc3.red("\u25CF FAIL");
707
+ const out = [`${status} ${pc3.bold(label(file))} ${pc3.dim("quality")} ${scoreColor(result.score)(`${result.score}/100`)}`];
125
708
  for (const d of result.diagnostics) {
126
- const loc = d.line !== void 0 ? pc.dim(`:${d.line}`) : "";
709
+ const loc = d.line !== void 0 ? pc3.dim(`:${d.line}`) : "";
127
710
  out.push(` ${GLYPH[d.severity]} ${SEV_COLOR[d.severity](d.id)}${loc} ${d.message}`);
128
711
  }
129
712
  const sec = secLabels(result);
@@ -147,32 +730,32 @@ function renderMany(results) {
147
730
  const failed = results.filter((r) => !r.result.ok).length;
148
731
  const warned = results.filter((r) => r.result.ok && r.result.diagnostics.some((d) => d.severity === "warn")).length;
149
732
  const clean = results.length - failed - warned;
150
- const avg = Math.round(results.reduce((s, r) => s + r.result.score, 0) / results.length);
733
+ const avg = Math.round(results.reduce((s2, r) => s2 + r.result.score, 0) / results.length);
151
734
  out.push("");
152
- const parts = [pc.green(`${clean} clean`)];
153
- if (warned) parts.push(pc.yellow(`${warned} warn`));
154
- if (failed) parts.push(pc.red(`${failed} fail`));
155
- out.push(`${parts.join(pc.dim(" \xB7 "))} ${pc.dim("avg score")} ${scoreColor(avg)(`${avg}/100`)}`);
156
- if (anySec) out.push(pc.dim(`${SEC_GLYPH} = risky behaviour, factored into the score alongside spec correctness and completeness`));
735
+ const parts = [pc3.green(`${clean} clean`)];
736
+ if (warned) parts.push(pc3.yellow(`${warned} warn`));
737
+ if (failed) parts.push(pc3.red(`${failed} fail`));
738
+ out.push(`${parts.join(pc3.dim(" \xB7 "))} ${pc3.dim("avg score")} ${scoreColor(avg)(`${avg}/100`)}`);
739
+ if (anySec) out.push(pc3.dim(`${SEC_GLYPH} = risky behaviour, factored into the score alongside spec correctness and completeness`));
157
740
  const fails = results.filter((r) => !r.result.ok);
158
741
  if (fails.length) {
159
742
  out.push("");
160
- out.push(pc.red(pc.bold(`Failed (${fails.length}):`)));
743
+ out.push(pc3.red(pc3.bold(`Failed (${fails.length}):`)));
161
744
  for (const f of fails.slice(0, 25)) out.push(failureBlock(f.file, f.result));
162
- if (fails.length > 25) out.push(pc.dim(` \u2026and ${fails.length - 25} more \u2014 run with --errors-only to see all`));
745
+ if (fails.length > 25) out.push(pc3.dim(` \u2026and ${fails.length - 25} more \u2014 run with --errors-only to see all`));
163
746
  }
164
747
  return out.join("\n");
165
748
  }
166
749
  function renderFailuresView(results) {
167
750
  const fails = results.filter((r) => !r.result.ok);
168
- if (!fails.length) return pc.green(`${GLYPH.ok} No failures across ${results.length} skill${results.length === 1 ? "" : "s"}.`);
751
+ if (!fails.length) return pc3.green(`${GLYPH.ok} No failures across ${results.length} skill${results.length === 1 ? "" : "s"}.`);
169
752
  const out = fails.map((f) => failureBlock(f.file, f.result));
170
753
  out.push("");
171
- out.push(`${pc.red(`${fails.length} failed`)} ${pc.dim(`of ${results.length}`)}`);
754
+ out.push(`${pc3.red(`${fails.length} failed`)} ${pc3.dim(`of ${results.length}`)}`);
172
755
  return out.join("\n");
173
756
  }
174
757
  function renderReport(results, opts = {}) {
175
- if (results.length === 0) return pc.dim("No skills found.");
758
+ if (results.length === 0) return pc3.dim("No skills found.");
176
759
  if (opts.errorsOnly) return renderFailuresView(results);
177
760
  if (results.length === 1) return renderOne(results[0].file, results[0].result);
178
761
  return renderMany(results);
@@ -186,11 +769,11 @@ function exitCodeFor(results, policy = {}) {
186
769
  }
187
770
  return 0;
188
771
  }
189
- function shortPath(p7, ctx = {}) {
772
+ function shortPath(p, ctx = {}) {
190
773
  const home = resolve(ctx.home ?? homedir());
191
774
  const cwd = resolve(ctx.cwd ?? process.cwd());
192
- const abs = resolve(p7);
193
- const norm = (s) => s.split(sep).join("/");
775
+ const abs = resolve(p);
776
+ const norm = (s2) => s2.split(sep).join("/");
194
777
  if (abs === cwd) return ".";
195
778
  if (abs.startsWith(cwd + sep)) return `./${norm(relative(cwd, abs))}`;
196
779
  if (abs === home) return "~";
@@ -200,20 +783,20 @@ function shortPath(p7, ctx = {}) {
200
783
  var SGR = /\x1b\[[0-9;]*m/g;
201
784
  var SGR_AT = /\x1b\[[0-9;]*m/y;
202
785
  var RESET = "\x1B[0m";
203
- function stripAnsi(s) {
204
- return s.replace(SGR, "");
786
+ function stripAnsi(s2) {
787
+ return s2.replace(SGR, "");
205
788
  }
206
- var visible = (s) => stripAnsi(s).length;
207
- function truncateVisible(s, max) {
789
+ var visible = (s2) => stripAnsi(s2).length;
790
+ function truncateVisible(s2, max) {
208
791
  if (max <= 0) return "";
209
- if (visible(s) <= max) return s;
792
+ if (visible(s2) <= max) return s2;
210
793
  let out = "";
211
794
  let shown = 0;
212
795
  let open = false;
213
- for (let i = 0; i < s.length && shown < max - 1; ) {
214
- if (s[i] === "\x1B") {
796
+ for (let i = 0; i < s2.length && shown < max - 1; ) {
797
+ if (s2[i] === "\x1B") {
215
798
  SGR_AT.lastIndex = i;
216
- const m = SGR_AT.exec(s);
799
+ const m = SGR_AT.exec(s2);
217
800
  if (m) {
218
801
  out += m[0];
219
802
  open = m[0] !== RESET && m[0] !== "\x1B[m";
@@ -221,7 +804,7 @@ function truncateVisible(s, max) {
221
804
  continue;
222
805
  }
223
806
  }
224
- out += s[i];
807
+ out += s2[i];
225
808
  shown++;
226
809
  i++;
227
810
  }
@@ -252,7 +835,7 @@ function renderInstallSummary(i, ctx = {}) {
252
835
  const width = termWidth(ctx.width);
253
836
  const src = i.source.startsWith("local:") ? `local:${shortPath(i.source.slice(6), ctx)}` : i.source;
254
837
  const head = truncateVisible(
255
- pc.green(`${GLYPH.ok} ${i.name}`) + pc.dim(` score ${i.score}${i.flags.length ? ` ${i.flags.join(", ")}` : ""} from ${src}`),
838
+ pc3.green(`${GLYPH.ok} ${i.name}`) + pc3.dim(` score ${i.score}${i.flags.length ? ` ${i.flags.join(", ")}` : ""} from ${src}`),
256
839
  width
257
840
  );
258
841
  const byPath = /* @__PURE__ */ new Map();
@@ -261,13 +844,13 @@ function renderInstallSummary(i, ctx = {}) {
261
844
  if (e) e.agents.push(t.agent);
262
845
  else byPath.set(t.path, { agents: [t.agent], mode: t.mode });
263
846
  }
264
- const rows = [...byPath.entries()].map(([path, e]) => [pc.cyan(e.agents.join(", ")), pc.dim(e.mode), shortPath(path, ctx)]);
265
- const body = rows.length ? table(rows, { width, indent: " " }) : truncateVisible(pc.dim(` ${shortPath(i.canonical, ctx)} canonical only`), width);
266
- const skipped = i.skipped.map((s) => truncateVisible(pc.dim(` ${GLYPH.skip} ${s.agent}: ${s.reason}`), width));
267
- const replaced = i.replaced ? [truncateVisible(pc.yellow(` ${GLYPH.replaced} replaced previous install (${i.replaced === "untracked" ? "untracked directory" : i.replaced})`), width)] : [];
847
+ const rows = [...byPath.entries()].map(([path, e]) => [pc3.cyan(e.agents.join(", ")), pc3.dim(e.mode), shortPath(path, ctx)]);
848
+ const body = rows.length ? table(rows, { width, indent: " " }) : truncateVisible(pc3.dim(` ${shortPath(i.canonical, ctx)} canonical only`), width);
849
+ const skipped = i.skipped.map((s2) => truncateVisible(pc3.dim(` ${GLYPH.skip} ${s2.agent}: ${s2.reason}`), width));
850
+ const replaced = i.replaced ? [truncateVisible(pc3.yellow(` ${GLYPH.replaced} replaced previous install (${i.replaced === "untracked" ? "untracked directory" : i.replaced})`), width)] : [];
268
851
  return [head, body, ...skipped, ...replaced].join("\n");
269
852
  }
270
- var banner = () => pc.bgCyan(pc.black(" skillmd "));
853
+ var banner = () => brandWord();
271
854
 
272
855
  // src/commands/lint.ts
273
856
  function applyLicenseFix(raw) {
@@ -312,23 +895,23 @@ function lintCommand() {
312
895
  return new Command("lint").description("Validate SKILL.md file(s) against the spec and report a quality score").argument("[target]", "local path or GitHub source", ".").option("--format <fmt>", "text | json | sarif | github", "text").option("--strict", "treat warnings as errors").option("--fail-on-warning", "exit non-zero when warnings exist").option("--fix", "apply safe automatic fixes (e.g. add missing license)").option("--errors-only", "show only skills that failed").action(async (target, opts) => {
313
896
  const ui = Boolean(process.stdout.isTTY) && opts.format === "text";
314
897
  if (resolve2(target) === homedir2()) {
315
- process.stderr.write(pc2.yellow(`Warning: scanning your entire home directory. Pass a narrower path, e.g. skillmd lint ./my-skill
898
+ process.stderr.write(pc4.yellow(`Warning: scanning your entire home directory. Pass a narrower path, e.g. skillmd lint ./my-skill
316
899
  `));
317
900
  }
318
901
  if (ui) {
319
- p.intro(pc2.bgCyan(pc2.black(" skillmd lint ")));
320
- const s = p.spinner();
321
- s.start(`Scanning ${target}`);
902
+ intro(`${brandWord()} ${pc4.dim("lint")}`);
903
+ const s2 = spinner("walk");
904
+ s2.start(`Scanning ${target}`);
322
905
  try {
323
906
  const run3 = await runLint(target, opts);
324
- s.stop(`Scanned ${run3.results.length} skill${run3.results.length === 1 ? "" : "s"}`);
907
+ s2.stop(`Scanned ${run3.results.length} skill${run3.results.length === 1 ? "" : "s"}`);
325
908
  console.log(run3.output);
326
909
  const failed = run3.results.filter((r) => !r.result.ok).length;
327
- p.outro(failed === 0 ? pc2.green("All good") : pc2.red(`${failed} skill${failed === 1 ? "" : "s"} failed \u2014 details above`));
910
+ outro(failed === 0 ? pc4.green("All good") : pc4.red(`${failed} skill${failed === 1 ? "" : "s"} failed \u2014 details above`));
328
911
  process.exitCode = run3.exitCode;
329
912
  } catch (err) {
330
- s.stop(pc2.red("No skills found"));
331
- p.outro(err instanceof Error ? err.message : String(err));
913
+ s2.stop(pc4.red("No skills found"));
914
+ outro(err instanceof Error ? err.message : String(err));
332
915
  process.exitCode = 1;
333
916
  }
334
917
  return;
@@ -344,7 +927,7 @@ function lintCommand() {
344
927
  // src/commands/scan.ts
345
928
  import { Command as Command2 } from "commander";
346
929
  import { scanSecurity, parseSkillMd } from "@skillmds/core";
347
- import pc3 from "picocolors";
930
+ import pc5 from "picocolors";
348
931
  async function runScan(target, flags) {
349
932
  const resolved = await resolveSource(target);
350
933
  const deny = new Set(flags.deny ?? []);
@@ -363,11 +946,11 @@ async function runScan(target, flags) {
363
946
  const lines = [];
364
947
  for (const e of entries) {
365
948
  const flagStr = e.security.flags.join(", ");
366
- const head = e.denied.length ? pc3.red(`DENY ${e.file}`) : pc3.green(`OK ${e.file}`);
367
- lines.push(`${head} ${pc3.dim(flagStr)}`);
949
+ const head = e.denied.length ? pc5.red(`DENY ${e.file}`) : pc5.green(`OK ${e.file}`);
950
+ lines.push(`${head} ${pc5.dim(flagStr)}`);
368
951
  for (const f of e.security.findings) {
369
- const mark = deny.has(f.flag) ? pc3.red(f.flag) : pc3.yellow(f.flag);
370
- lines.push(` ${mark} :${f.line} ${pc3.dim(f.snippet)}`);
952
+ const mark = deny.has(f.flag) ? pc5.red(f.flag) : pc5.yellow(f.flag);
953
+ lines.push(` ${mark} :${f.line} ${pc5.dim(f.snippet)}`);
371
954
  }
372
955
  }
373
956
  output = lines.join("\n");
@@ -385,7 +968,7 @@ function scanCommand() {
385
968
  // src/commands/rules.ts
386
969
  import { Command as Command3 } from "commander";
387
970
  import { RULES } from "@skillmds/core";
388
- import pc4 from "picocolors";
971
+ import pc6 from "picocolors";
389
972
  function rulesCommand() {
390
973
  return new Command3("rules").description("List lint rules, or show detail for one rule id").argument("[id]", "a rule id, e.g. SK010").option("--json", "machine-readable output").action((id, opts) => {
391
974
  const list = id ? RULES.filter((r) => r.id.toLowerCase() === id.toLowerCase()) : RULES;
@@ -398,9 +981,9 @@ function rulesCommand() {
398
981
  console.log(JSON.stringify(list.map((r) => ({ id: r.id, severity: r.severity, description: r.description })), null, 2));
399
982
  return;
400
983
  }
401
- const badge = (sev) => sev === "error" ? pc4.bgRed(pc4.white(" error ")) : sev === "warn" ? pc4.bgYellow(pc4.black(" warn ")) : pc4.bgCyan(pc4.black(" info "));
402
- console.log(pc4.bold("\nLint rules\n"));
403
- for (const r of list) console.log(` ${pc4.bold(r.id)} ${badge(r.severity)} ${r.description}`);
984
+ const badge = (sev) => sev === "error" ? pc6.bgRed(pc6.white(" error ")) : sev === "warn" ? pc6.bgYellow(pc6.black(" warn ")) : pc6.bgCyan(pc6.black(" info "));
985
+ console.log(pc6.bold("\nLint rules\n"));
986
+ for (const r of list) console.log(` ${pc6.bold(r.id)} ${badge(r.severity)} ${r.description}`);
404
987
  console.log("");
405
988
  });
406
989
  }
@@ -410,40 +993,7 @@ import { Command as Command4 } from "commander";
410
993
  import { mkdirSync, writeFileSync as writeFileSync2, existsSync } from "fs";
411
994
  import { join } from "path";
412
995
  import { slugify } from "@skillmds/core";
413
- import * as p2 from "@clack/prompts";
414
- import pc5 from "picocolors";
415
-
416
- // src/env.ts
417
- function detectHostAgent(env = process.env) {
418
- if (env.CLAUDECODE) return "claude-code";
419
- if (env.CURSOR_AGENT || env.CURSOR_EXTENSION_HOST_ROLE === "agent-exec") return "cursor";
420
- if (env.CODEX_SANDBOX || env.CODEX_THREAD_ID) return "codex";
421
- if (env.GEMINI_CLI) return "gemini-cli";
422
- if (env.CI && env.CI !== "false" && env.CI !== "0") return "ci";
423
- return null;
424
- }
425
- var realTerminal = () => ({
426
- stdinTTY: Boolean(process.stdin.isTTY),
427
- stdoutTTY: Boolean(process.stdout.isTTY),
428
- env: process.env
429
- });
430
- function isInteractive(flags, term = realTerminal()) {
431
- if (flags.yes || flags.json) return false;
432
- if (!term.stdinTTY || !term.stdoutTTY) return false;
433
- return detectHostAgent(term.env) === null;
434
- }
435
- function scopesFor(flags) {
436
- return flags.global && !flags.project ? [true] : flags.project && !flags.global ? [false] : [false, true];
437
- }
438
- function nonInteractiveHint(flags) {
439
- return `Interactive prompt required but stdin is not a terminal. Nothing was changed. Re-run with ${flags} to run non-interactively.`;
440
- }
441
- function promptIf(flags, prompt) {
442
- const term = { stdinTTY: Boolean(process.stdin.isTTY), stdoutTTY: Boolean(process.stdout.isTTY), env: flags.env ?? process.env };
443
- return isInteractive(flags, term) ? { prompt } : {};
444
- }
445
-
446
- // src/commands/init.ts
996
+ import pc7 from "picocolors";
447
997
  function skillTemplate(name, description, license) {
448
998
  const desc = description.trim() || `A skill that helps agents with ${name}.`;
449
999
  return `---
@@ -480,8 +1030,8 @@ function initSkill(name, opts = {}) {
480
1030
  return file;
481
1031
  }
482
1032
  var defaultInitDeps = (flags) => promptIf(flags, async () => {
483
- const answer = await p2.text({ message: "Skill name?", placeholder: "my-skill" });
484
- return p2.isCancel(answer) ? null : answer;
1033
+ const answer = await text({ message: "Skill name?", placeholder: "my-skill" });
1034
+ return isCancel(answer) ? null : answer;
485
1035
  });
486
1036
  function finish(flags, result, doc) {
487
1037
  return flags.json ? { ...result, output: JSON.stringify(doc, null, 2) } : result;
@@ -491,22 +1041,22 @@ async function runInit(nameArg, flags, deps = defaultInitDeps(flags)) {
491
1041
  if (!name) {
492
1042
  if (!deps.prompt) {
493
1043
  const error = nonInteractiveHint("a name argument or --name <name>");
494
- return finish(flags, { exitCode: 1, output: pc5.red(error) }, { ok: false, error });
1044
+ return finish(flags, { exitCode: 1, output: pc7.red(error) }, { ok: false, error });
495
1045
  }
496
1046
  const answer = await deps.prompt();
497
- if (answer === null) return finish(flags, { exitCode: 0, output: pc5.dim("Cancelled.") }, { ok: false, cancelled: true });
1047
+ if (answer === null) return finish(flags, { exitCode: 0, output: pc7.dim("Cancelled.") }, { ok: false, cancelled: true });
498
1048
  name = answer;
499
1049
  }
500
1050
  if (!name) {
501
1051
  const error = "A skill name is required (pass a name or --name).";
502
- return finish(flags, { exitCode: 1, output: pc5.red(error) }, { ok: false, error });
1052
+ return finish(flags, { exitCode: 1, output: pc7.red(error) }, { ok: false, error });
503
1053
  }
504
1054
  try {
505
1055
  const file = initSkill(name, { dir: flags.dir, description: flags.description, license: flags.license });
506
1056
  return { exitCode: 0, file, output: flags.json ? JSON.stringify({ ok: true, file }, null, 2) : `Created ${file}` };
507
1057
  } catch (e) {
508
1058
  const msg2 = e instanceof Error ? e.message : String(e);
509
- return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error: msg2 }, null, 2) : pc5.red(msg2) };
1059
+ return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error: msg2 }, null, 2) : pc7.red(msg2) };
510
1060
  }
511
1061
  }
512
1062
  function initCommand() {
@@ -519,7 +1069,7 @@ function initCommand() {
519
1069
 
520
1070
  // src/commands/search.ts
521
1071
  import { Command as Command5 } from "commander";
522
- import pc6 from "picocolors";
1072
+ import pc8 from "picocolors";
523
1073
  var MAX_LINE_WIDTH = 100;
524
1074
  function formatStars(n) {
525
1075
  if (n >= 1e6) {
@@ -532,19 +1082,19 @@ function formatStars(n) {
532
1082
  }
533
1083
  return String(n);
534
1084
  }
535
- function truncate(text3, width) {
536
- if (text3.length <= width) return text3;
1085
+ function truncate(text2, width) {
1086
+ if (text2.length <= width) return text2;
537
1087
  if (width <= 1) return "\u2026";
538
- return `${text3.slice(0, width - 1).trimEnd()}\u2026`;
1088
+ return `${text2.slice(0, width - 1).trimEnd()}\u2026`;
539
1089
  }
540
1090
  function formatSearchResult(item, width = process.stdout.columns ?? 80) {
541
- const stars = item.repo_stars != null ? pc6.dim(`\u2605 ${formatStars(item.repo_stars)}`) : "";
542
- const check = item.verified ? pc6.green("\u2713") : "";
543
- const pack = item.type === "pack" ? pc6.dim("[pack]") : "";
544
- const head = [pc6.bold(safeText(item.slug, 200)), stars, check, pack].filter(Boolean).join(" ");
1091
+ const stars = item.repo_stars != null ? pc8.dim(`\u2605 ${formatStars(item.repo_stars)}`) : "";
1092
+ const check = item.verified ? pc8.green("\u2713") : "";
1093
+ const pack = item.type === "pack" ? pc8.dim("[pack]") : "";
1094
+ const head = [pc8.bold(safeText(item.slug, 200)), stars, check, pack].filter(Boolean).join(" ");
545
1095
  const indent = " ";
546
1096
  const lineWidth = Math.max(10, Math.min(width, MAX_LINE_WIDTH) - indent.length);
547
- const desc = `${indent}${pc6.dim(truncate(safeText(item.description ?? ""), lineWidth))}`;
1097
+ const desc = `${indent}${pc8.dim(truncate(safeText(item.description ?? ""), lineWidth))}`;
548
1098
  return `${head}
549
1099
  ${desc}`;
550
1100
  }
@@ -558,63 +1108,63 @@ async function runSearch(query, flags) {
558
1108
  const r = await api(`/api/search?${params}`);
559
1109
  const items = r.items ?? [];
560
1110
  if (flags.json) return { items, output: JSON.stringify(items, null, 2) };
561
- const lines = items.map((s) => formatSearchResult(s));
1111
+ const lines = items.map((s2) => formatSearchResult(s2));
562
1112
  return { items, output: lines.join("\n\n") || "No skills found." };
563
1113
  }
564
1114
  function searchCommand() {
565
1115
  return new Command5("search").description("Search the SkillMD registry").argument("<query>", "search terms").option("--category <slug>", "filter by category").option("--verified", "only verified skills").option("--type <type>", "single | pack").option("--min-rating <n>", "minimum average rating (0-5)").option("--limit <n>", "max results", "20").option("--json", "machine-readable output").action(async (query, opts, cmd) => {
566
1116
  const merged = { ...cmd.parent?.opts(), ...opts };
567
- const run2 = await runSearch(query, merged);
1117
+ const run2 = await waitFor("hop", `Searching for ${query}`, runSearch(query, merged), { json: Boolean(merged.json) });
568
1118
  console.log(run2.output);
569
1119
  });
570
1120
  }
571
1121
 
572
1122
  // src/commands/info.ts
573
1123
  import { Command as Command6 } from "commander";
574
- import pc7 from "picocolors";
1124
+ import pc9 from "picocolors";
575
1125
  async function runInfo(slug, flags, deps = {}) {
576
1126
  const [owner, name] = slug.split("/");
577
1127
  if (!owner || !name || slug.split("/").length !== 2) {
578
- return { ok: false, exitCode: 1, output: pc7.red("Expected owner/name, e.g. anthropic/pdf") };
1128
+ return { ok: false, exitCode: 1, output: pc9.red("Expected owner/name, e.g. anthropic/pdf") };
579
1129
  }
580
1130
  const api = deps.api ?? createClient(flags).api;
581
- let s;
1131
+ let s2;
582
1132
  try {
583
- s = await api(`/api/skills/${owner}/${name}`);
1133
+ s2 = await api(`/api/skills/${owner}/${name}`);
584
1134
  } catch (err) {
585
1135
  const message = err instanceof Error ? err.message : String(err);
586
1136
  if (/^SkillMD API 404 /.test(message)) {
587
- return { ok: false, exitCode: 1, output: pc7.red(`Skill not found on the registry: ${slug}`) };
1137
+ return { ok: false, exitCode: 1, output: pc9.red(`Skill not found on the registry: ${slug}`) };
588
1138
  }
589
- return { ok: false, exitCode: 1, output: pc7.red(`Could not reach the SkillMD registry: ${message}`) };
1139
+ return { ok: false, exitCode: 1, output: pc9.red(`Could not reach the SkillMD registry: ${message}`) };
590
1140
  }
591
- if (flags.json) return { ok: true, exitCode: 0, output: JSON.stringify(s, null, 2), skill: s };
592
- const slugTxt = safeText(s.slug, 200);
1141
+ if (flags.json) return { ok: true, exitCode: 0, output: JSON.stringify(s2, null, 2), skill: s2 };
1142
+ const slugTxt = safeText(s2.slug, 200);
593
1143
  const lines = [];
594
1144
  lines.push(
595
- `${pc7.bold(slugTxt)} ${pc7.dim(`[${safeText(s.type ?? "single", 40)}]`)} ${s.verified ? pc7.green("\u2713 verified") : pc7.yellow("unverified")}`
1145
+ `${pc9.bold(slugTxt)} ${pc9.dim(`[${safeText(s2.type ?? "single", 40)}]`)} ${s2.verified ? pc9.green("\u2713 verified") : pc9.yellow("unverified")}`
596
1146
  );
597
- lines.push(` ${safeText(s.description)}`);
1147
+ lines.push(` ${safeText(s2.description)}`);
598
1148
  lines.push(
599
- pc7.dim(
600
- ` category: ${safeText(s.category ?? "-", 100) || "-"} \xB7 rating: ${s.avg_rating != null ? s.avg_rating.toFixed(1) : "-"} (${s.rating_count ?? 0}) \xB7 installs: ${s.install_count ?? 0}`
1149
+ pc9.dim(
1150
+ ` category: ${safeText(s2.category ?? "-", 100) || "-"} \xB7 rating: ${s2.avg_rating != null ? s2.avg_rating.toFixed(1) : "-"} (${s2.rating_count ?? 0}) \xB7 installs: ${s2.install_count ?? 0}`
601
1151
  )
602
1152
  );
603
- const securityFlags2 = (s.security_flags ?? []).map((f) => safeText(f, 60)).filter(Boolean);
1153
+ const securityFlags2 = (s2.security_flags ?? []).map((f) => safeText(f, 60)).filter(Boolean);
604
1154
  lines.push(
605
- pc7.dim(` security: ${securityFlags2.join(", ") || "unscanned"} \xB7 license: ${safeText(s.provenance?.license ?? s.license ?? "unknown", 100) || "unknown"}`)
1155
+ pc9.dim(` security: ${securityFlags2.join(", ") || "unscanned"} \xB7 license: ${safeText(s2.provenance?.license ?? s2.license ?? "unknown", 100) || "unknown"}`)
606
1156
  );
607
- const sourceRepo = safeText(s.provenance?.source_repo ?? s.source_repo, 300);
608
- const commitSha = safeText(s.provenance?.commit_sha ?? s.commit_sha, 100);
609
- if (sourceRepo) lines.push(pc7.dim(` source: ${sourceRepo}${commitSha ? ` @ ${commitSha.slice(0, 8)}` : ""}`));
610
- lines.push(pc7.dim(` page: https://skillmd.com/skills/${slugTxt}`));
611
- lines.push(pc7.dim(` install: ${safeText(s.install?.cli, 300) || `npx get-skill add ${slugTxt}`}`));
612
- return { ok: true, exitCode: 0, output: lines.join("\n"), skill: s };
1157
+ const sourceRepo = safeText(s2.provenance?.source_repo ?? s2.source_repo, 300);
1158
+ const commitSha = safeText(s2.provenance?.commit_sha ?? s2.commit_sha, 100);
1159
+ if (sourceRepo) lines.push(pc9.dim(` source: ${sourceRepo}${commitSha ? ` @ ${commitSha.slice(0, 8)}` : ""}`));
1160
+ lines.push(pc9.dim(` page: https://skillmd.com/skills/${slugTxt}`));
1161
+ lines.push(pc9.dim(` install: ${safeText(s2.install?.cli, 300) || `npx get-skill add ${slugTxt}`}`));
1162
+ return { ok: true, exitCode: 0, output: lines.join("\n"), skill: s2 };
613
1163
  }
614
1164
  function infoCommand() {
615
1165
  return new Command6("info").description("Show registry details for a skill: verification, security flags, provenance, rating").argument("<slug>", "owner/name, e.g. anthropic/pdf").action(async (slug, _opts, cmd) => {
616
1166
  const flags = { ...cmd.parent?.opts() };
617
- const run2 = await runInfo(slug, flags);
1167
+ const run2 = await waitFor("drop", `Fetching ${slug}`, runInfo(slug, flags), { json: flags.json });
618
1168
  if (run2.output) (run2.ok ? console.log : console.error)(run2.output);
619
1169
  process.exitCode = run2.exitCode;
620
1170
  });
@@ -623,9 +1173,8 @@ function infoCommand() {
623
1173
  // src/commands/add.ts
624
1174
  import { Command as Command7, Option } from "commander";
625
1175
  import { homedir as homedir4 } from "os";
626
- import * as p3 from "@clack/prompts";
627
1176
  import { dirname as dirname2, resolve as resolve3 } from "path";
628
- import pc8 from "picocolors";
1177
+ import pc10 from "picocolors";
629
1178
  import { lint as lint2, parseSkillMd as parseSkillMd2 } from "@skillmds/core";
630
1179
 
631
1180
  // src/claudePlugin.ts
@@ -669,7 +1218,7 @@ function exec(deps) {
669
1218
  });
670
1219
  }
671
1220
  function marketplacePluginName(owner, slug) {
672
- const clean = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1221
+ const clean = (s2) => s2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
673
1222
  const base = clean(slug) || "plugin";
674
1223
  return owner.toLowerCase() === "skillmd" ? base : `${clean(owner)}-${base}`;
675
1224
  }
@@ -707,21 +1256,21 @@ ${r.stderr}`;
707
1256
  }
708
1257
  function msg(e) {
709
1258
  if (e && typeof e === "object" && "stderr" in e) {
710
- const s = String(e.stderr ?? "").trim();
711
- if (s) return s.split(/\r?\n/)[0];
1259
+ const s2 = String(e.stderr ?? "").trim();
1260
+ if (s2) return s2.split(/\r?\n/)[0];
712
1261
  }
713
1262
  return e instanceof Error ? e.message.split(/\r?\n/)[0] : String(e);
714
1263
  }
715
1264
  var SITE_URL = "https://skillmd.com";
716
1265
  function readJson(path) {
717
- let text3;
1266
+ let text2;
718
1267
  try {
719
- text3 = readFileSync(path, "utf8");
1268
+ text2 = readFileSync(path, "utf8");
720
1269
  } catch {
721
1270
  return "absent";
722
1271
  }
723
1272
  try {
724
- const v = JSON.parse(text3);
1273
+ const v = JSON.parse(text2);
725
1274
  return v && typeof v === "object" && !Array.isArray(v) ? v : "unparsable";
726
1275
  } catch {
727
1276
  return "unparsable";
@@ -812,7 +1361,7 @@ async function installPluginNatively(owner, slug, deps = {}) {
812
1361
  const plugins = obj(installedDoc.plugins);
813
1362
  const prior = Array.isArray(plugins[qualified]) ? plugins[qualified] : [];
814
1363
  plugins[qualified] = [
815
- ...prior.filter((p7) => p7?.scope !== "user"),
1364
+ ...prior.filter((p) => p?.scope !== "user"),
816
1365
  { scope: "user", installPath, version: version2, installedAt: now, lastUpdated: now }
817
1366
  ];
818
1367
  installedDoc.plugins = plugins;
@@ -831,22 +1380,22 @@ async function installPluginNatively(owner, slug, deps = {}) {
831
1380
  }
832
1381
 
833
1382
  // src/commands/add.ts
834
- var infoNotice = (text3) => ({ text: text3, style: "info" });
835
- var warnNotice = (text3) => ({ text: text3, style: "warn" });
836
- var skipNotice = (text3) => ({ text: text3, style: "skip" });
837
- var replacedNotice = (text3) => ({ text: text3, style: "warn", suppressInSummary: true });
1383
+ var infoNotice = (text2) => ({ text: text2, style: "info" });
1384
+ var warnNotice = (text2) => ({ text: text2, style: "warn" });
1385
+ var skipNotice = (text2) => ({ text: text2, style: "skip" });
1386
+ var replacedNotice = (text2) => ({ text: text2, style: "warn", suppressInSummary: true });
838
1387
  function noticeLine(n) {
839
1388
  switch (n.style) {
840
1389
  case "info":
841
- return pc8.dim(`${GLYPH.info} ${n.text}`);
1390
+ return pc10.dim(`${GLYPH.info} ${n.text}`);
842
1391
  case "skip":
843
- return pc8.dim(`${GLYPH.skip} ${n.text}`);
1392
+ return pc10.dim(`${GLYPH.skip} ${n.text}`);
844
1393
  case "warn":
845
- return pc8.yellow(`${GLYPH.warn} ${n.text}`);
1394
+ return pc10.yellow(`${GLYPH.warn} ${n.text}`);
846
1395
  }
847
1396
  }
848
1397
  async function promptScopeInteractive(ctx) {
849
- const choice = await p3.select({
1398
+ const choice = await select({
850
1399
  message: "Installation scope",
851
1400
  initialValue: ctx.suggestGlobal,
852
1401
  options: [
@@ -854,7 +1403,7 @@ async function promptScopeInteractive(ctx) {
854
1403
  { value: true, label: "Global", hint: "install in your home directory (available across all projects)" }
855
1404
  ]
856
1405
  });
857
- return p3.isCancel(choice) ? null : choice;
1406
+ return isCancel(choice) ? null : choice;
858
1407
  }
859
1408
  function agentsPromptMessage(managed) {
860
1409
  return managed ? `Claude Code already has ${managed} as a plugin. Which other agents should get its skills too?` : "Which agents do you want to install to?";
@@ -862,13 +1411,13 @@ function agentsPromptMessage(managed) {
862
1411
  async function promptAgentsInteractive(ctx) {
863
1412
  if (ctx.detected.length < 2) return ctx.detected;
864
1413
  const remembered = (readConfig().lastAgents ?? []).filter((id) => ctx.detected.includes(id));
865
- const picked = await p3.multiselect({
1414
+ const picked = await multiselect({
866
1415
  message: agentsPromptMessage(ctx.managed),
867
1416
  options: ctx.detected.map((id) => ({ value: id, label: id, hint: ctx.dirFor(id) })),
868
1417
  initialValues: remembered.length ? remembered : ctx.detected,
869
1418
  required: true
870
1419
  });
871
- return p3.isCancel(picked) ? null : picked;
1420
+ return isCancel(picked) ? null : picked;
872
1421
  }
873
1422
  function unverifiedFilesNote(n) {
874
1423
  const [f, it] = n === 1 ? ["file", "it"] : ["files", "them"];
@@ -1144,7 +1693,7 @@ function finish2(flags, outcome) {
1144
1693
  };
1145
1694
  }
1146
1695
  case "list": {
1147
- const human = outcome.skills.length ? outcome.skills.map((s) => `${pc8.bold(s.name)} ${pc8.dim(s.description)}`).join("\n") : "No skills found.";
1696
+ const human = outcome.skills.length ? outcome.skills.map((s2) => `${pc10.bold(s2.name)} ${pc10.dim(s2.description)}`).join("\n") : "No skills found.";
1148
1697
  return { written: [], blocked: [], exitCode: 0, output: json ? JSON.stringify({ ok: true, skills: outcome.skills }, null, 2) : human };
1149
1698
  }
1150
1699
  case "cancel": {
@@ -1154,7 +1703,7 @@ function finish2(flags, outcome) {
1154
1703
  blocked: [],
1155
1704
  exitCode: 0,
1156
1705
  cancelled: true,
1157
- output: json ? JSON.stringify(doc, null, 2) : pc8.dim("Installation cancelled \u2014 nothing was installed.")
1706
+ output: json ? JSON.stringify(doc, null, 2) : pc10.dim("Installation cancelled \u2014 nothing was installed.")
1158
1707
  };
1159
1708
  }
1160
1709
  case "fail": {
@@ -1164,7 +1713,7 @@ function finish2(flags, outcome) {
1164
1713
  if (warnings.length) doc.warnings = warnings;
1165
1714
  const human = [
1166
1715
  ...(outcome.notices ?? []).map(noticeLine),
1167
- ...outcome.blocked?.length ? outcome.blocked.map((b) => pc8.red(`${GLYPH.blocked} ${b.name} blocked \u2014 ${b.reason}`)) : [pc8.red(outcome.error)]
1716
+ ...outcome.blocked?.length ? outcome.blocked.map((b) => pc10.red(`${GLYPH.blocked} ${b.name} blocked \u2014 ${b.reason}`)) : [pc10.red(outcome.error)]
1168
1717
  ].join("\n");
1169
1718
  return { written: [], blocked: outcome.blocked ?? [], exitCode: 1, output: json ? JSON.stringify(doc, null, 2) : human };
1170
1719
  }
@@ -1174,7 +1723,7 @@ function renderHuman(notices, records, paths) {
1174
1723
  const lines = notices.map(noticeLine);
1175
1724
  for (const r of records) {
1176
1725
  if (r.kind === "blocked") {
1177
- lines.push(pc8.red(r.message));
1726
+ lines.push(pc10.red(r.message));
1178
1727
  continue;
1179
1728
  }
1180
1729
  const { doc } = r;
@@ -1386,14 +1935,14 @@ function addCommand() {
1386
1935
  });
1387
1936
  }
1388
1937
  var clackUI = {
1389
- intro: (m) => p3.intro(m),
1390
- spinner: () => p3.spinner(),
1391
- message: (m) => p3.log.message(m),
1392
- outro: (m) => p3.outro(m),
1393
- cancel: (m) => p3.cancel(m),
1938
+ intro: (m) => intro(m),
1939
+ spinner: () => spinner("drop"),
1940
+ message: (m) => log.message(m),
1941
+ outro: (m) => outro(m),
1942
+ cancel: (m) => cancel(m),
1394
1943
  confirm: async (m) => {
1395
- const answer = await p3.confirm({ message: m, initialValue: true });
1396
- return p3.isCancel(answer) ? null : answer;
1944
+ const answer = await confirm({ message: m, initialValue: true });
1945
+ return isCancel(answer) ? null : answer;
1397
1946
  }
1398
1947
  };
1399
1948
  var FIND_SKILLS = "skillmd/find-skills";
@@ -1422,7 +1971,7 @@ async function offerFindSkills(source, flags, run2, ui, deps) {
1422
1971
  project: !global,
1423
1972
  agent: run2.agents
1424
1973
  }, deps);
1425
- ui.message(r.exitCode === 0 ? `${pc8.green(GLYPH.ok)} find-skills added` : pc8.yellow(`${GLYPH.warn} find-skills could not be added. Try later: npx get-skill add ${FIND_SKILLS}`));
1974
+ ui.message(r.exitCode === 0 ? `${pc10.green(GLYPH.ok)} find-skills added` : pc10.yellow(`${GLYPH.warn} find-skills could not be added. Try later: npx get-skill add ${FIND_SKILLS}`));
1426
1975
  }
1427
1976
  async function runAddWithUI(source, flags, opts = {}) {
1428
1977
  const term = opts.term ?? { ...realTerminal(), env: flags.env ?? process.env };
@@ -1439,14 +1988,14 @@ async function runAddWithUI(source, flags, opts = {}) {
1439
1988
  // this spread.
1440
1989
  ...base,
1441
1990
  resolve: async (arg, f) => {
1442
- const s = ui.spinner();
1443
- s.start(`Resolving ${arg}`);
1991
+ const s2 = ui.spinner();
1992
+ s2.start(`Resolving ${arg}`);
1444
1993
  try {
1445
1994
  const c = await base.resolve(arg, f);
1446
- s.stop(`${c.length} skill${c.length === 1 ? "" : "s"} found`);
1995
+ s2.stop(`${c.length} skill${c.length === 1 ? "" : "s"} found`);
1447
1996
  return c;
1448
1997
  } catch (e) {
1449
- s.stop(pc8.red("Could not resolve the source"));
1998
+ s2.stop(pc10.red("Could not resolve the source"));
1450
1999
  throw e;
1451
2000
  }
1452
2001
  }
@@ -1457,10 +2006,10 @@ async function runAddWithUI(source, flags, opts = {}) {
1457
2006
  }
1458
2007
  ui.message(run2.output);
1459
2008
  await offerFindSkills(source, flags, run2, ui, base);
1460
- ui.outro(run2.exitCode === 0 ? `Done. Run ${pc8.cyan("npx get-skill list")} to see everything installed.` : pc8.red("Some skills were not installed."));
2009
+ ui.outro(run2.exitCode === 0 ? `Done. Run ${pc10.cyan("npx get-skill list")} to see everything installed.` : pc10.red("Some skills were not installed."));
1461
2010
  return { run: run2, printed: true };
1462
2011
  } catch (e) {
1463
- ui.outro(pc8.red("Nothing was installed."));
2012
+ ui.outro(pc10.red("Nothing was installed."));
1464
2013
  throw e;
1465
2014
  }
1466
2015
  }
@@ -1469,20 +2018,20 @@ async function runAddWithUI(source, flags, opts = {}) {
1469
2018
  import { Command as Command8 } from "commander";
1470
2019
  import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
1471
2020
  import { join as join4 } from "path";
1472
- import pc9 from "picocolors";
2021
+ import pc11 from "picocolors";
1473
2022
  import { parseSkillMd as parseSkillMd3 } from "@skillmds/core";
1474
2023
  function runList(flags = {}) {
1475
2024
  const scopes = scopesFor(flags);
1476
2025
  let items = [];
1477
2026
  for (const global of scopes) {
1478
- for (const s of listInstalled({ global, cwd: flags.cwd, home: flags.home })) {
1479
- const md = join4(s.path, "SKILL.md");
2027
+ for (const s2 of listInstalled({ global, cwd: flags.cwd, home: flags.home })) {
2028
+ const md = join4(s2.path, "SKILL.md");
1480
2029
  let description = "";
1481
2030
  if (existsSync3(md)) {
1482
2031
  const parsed = parseSkillMd3(readFileSync2(md, "utf8"));
1483
2032
  description = "error" in parsed ? `(invalid SKILL.md \u2014 ${parsed.error})` : parsed.description;
1484
2033
  }
1485
- items.push({ ...s, description: safeText(description, 80) });
2034
+ items.push({ ...s2, description: safeText(description, 80) });
1486
2035
  }
1487
2036
  }
1488
2037
  if (flags.agent?.length) items = items.filter((i) => i.agents.some((a) => flags.agent.includes(a)));
@@ -1490,13 +2039,13 @@ function runList(flags = {}) {
1490
2039
  if (flags.json) {
1491
2040
  return { items, output: JSON.stringify(items.map(({ name, scope, path, agents, source, mode, tracked, description }) => ({ name, scope, path, agents, source: source ?? null, mode, tracked, description })), null, 2) };
1492
2041
  }
1493
- if (items.length === 0) return { items, output: pc9.dim("No installed skills found. Install one with `npx get-skill add owner/name`.") };
2042
+ if (items.length === 0) return { items, output: pc11.dim("No installed skills found. Install one with `npx get-skill add owner/name`.") };
1494
2043
  const w = Math.max(...items.map((i) => i.name.length), 4);
1495
2044
  const lines = items.map((i) => {
1496
- const tag = i.tracked ? pc9.dim(i.source ?? "") : pc9.yellow("untracked");
2045
+ const tag = i.tracked ? pc11.dim(i.source ?? "") : pc11.yellow("untracked");
1497
2046
  const modes = [...new Set(Object.values(i.mode))].join("/");
1498
- return `${pc9.bold(i.name.padEnd(w))} ${pc9.cyan(i.scope.padEnd(7))} ${i.agents.join(", ").padEnd(24)} ${pc9.dim(modes.padEnd(9))} ${tag}
1499
- ${" ".repeat(w + 2)}${pc9.dim(i.description)}`;
2047
+ return `${pc11.bold(i.name.padEnd(w))} ${pc11.cyan(i.scope.padEnd(7))} ${i.agents.join(", ").padEnd(24)} ${pc11.dim(modes.padEnd(9))} ${tag}
2048
+ ${" ".repeat(w + 2)}${pc11.dim(i.description)}`;
1500
2049
  });
1501
2050
  return { items, output: lines.join("\n") };
1502
2051
  }
@@ -1510,16 +2059,15 @@ function listCommand() {
1510
2059
  import { Command as Command9 } from "commander";
1511
2060
  import { rmSync } from "fs";
1512
2061
  import { join as join5, resolve as resolve4 } from "path";
1513
- import * as p4 from "@clack/prompts";
1514
- import pc10 from "picocolors";
2062
+ import pc12 from "picocolors";
1515
2063
  var defaultDeps = (flags) => isInteractive(flags) ? {
1516
2064
  confirm: async (msg2) => {
1517
- const a = await p4.confirm({ message: msg2, initialValue: false });
1518
- return !p4.isCancel(a) && a;
2065
+ const a = await confirm({ message: msg2, initialValue: false });
2066
+ return !isCancel(a) && a;
1519
2067
  },
1520
2068
  pick: async ({ names }) => {
1521
- const a = await p4.multiselect({ message: "Which skills do you want to remove?", options: names.map((n) => ({ value: n, label: n })), required: true });
1522
- return p4.isCancel(a) ? null : a;
2069
+ const a = await multiselect({ message: "Which skills do you want to remove?", options: names.map((n) => ({ value: n, label: n })), required: true });
2070
+ return isCancel(a) ? null : a;
1523
2071
  }
1524
2072
  } : {};
1525
2073
  function finish3(flags, result, doc) {
@@ -1532,32 +2080,32 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
1532
2080
  const lines = [];
1533
2081
  if (flags.all && names.length) {
1534
2082
  const error = "--all cannot be combined with skill names";
1535
- return finish3(flags, { removed: [], exitCode: 1, output: pc10.red(error) }, { ok: false, error });
2083
+ return finish3(flags, { removed: [], exitCode: 1, output: pc12.red(error) }, { ok: false, error });
1536
2084
  }
1537
2085
  const perScope = scopes.map((scope) => ({ scope, installed: listInstalled(scope) }));
1538
- const allNames = [...new Set(perScope.flatMap((s) => s.installed.map((i) => i.name)))];
2086
+ const allNames = [...new Set(perScope.flatMap((s2) => s2.installed.map((i) => i.name)))];
1539
2087
  const nothingInstalled = `No installed skills found in ${where} scope.`;
1540
2088
  let targets = names;
1541
2089
  if (flags.all) {
1542
2090
  if (allNames.length === 0) {
1543
- return finish3(flags, { removed: [], exitCode: 1, output: pc10.dim(nothingInstalled) }, { ok: false, error: nothingInstalled });
2091
+ return finish3(flags, { removed: [], exitCode: 1, output: pc12.dim(nothingInstalled) }, { ok: false, error: nothingInstalled });
1544
2092
  }
1545
2093
  targets = allNames;
1546
2094
  } else if (targets.length === 0) {
1547
2095
  if (!deps.pick) {
1548
2096
  const error = "Give one or more skill names, or --all.";
1549
- return finish3(flags, { removed: [], exitCode: 1, output: pc10.red(`${error} `) + pc10.dim(nonInteractiveHint("skill names and -y")) }, { ok: false, error });
2097
+ return finish3(flags, { removed: [], exitCode: 1, output: pc12.red(`${error} `) + pc12.dim(nonInteractiveHint("skill names and -y")) }, { ok: false, error });
1550
2098
  }
1551
2099
  if (allNames.length === 0) {
1552
- return finish3(flags, { removed: [], exitCode: 1, output: pc10.dim(nothingInstalled) }, { ok: false, error: nothingInstalled });
2100
+ return finish3(flags, { removed: [], exitCode: 1, output: pc12.dim(nothingInstalled) }, { ok: false, error: nothingInstalled });
1553
2101
  }
1554
2102
  const picked = await deps.pick({ names: allNames });
1555
- if (!picked) return finish3(flags, { removed: [], exitCode: 0, cancelled: true, output: pc10.dim("Nothing removed.") }, { ok: true, removed: [], cancelled: true });
2103
+ if (!picked) return finish3(flags, { removed: [], exitCode: 0, cancelled: true, output: pc12.dim("Nothing removed.") }, { ok: true, removed: [], cancelled: true });
1556
2104
  targets = picked;
1557
2105
  }
1558
2106
  const known = targets.filter((n) => allNames.includes(n));
1559
2107
  const missing = targets.filter((n) => !known.includes(n));
1560
- for (const n of missing) lines.push(pc10.yellow(`- ${n} not installed (${where} scope)`));
2108
+ for (const n of missing) lines.push(pc12.yellow(`- ${n} not installed (${where} scope)`));
1561
2109
  if (known.length === 0) {
1562
2110
  const output = lines.join("\n");
1563
2111
  return finish3(flags, { removed: [], exitCode: 1, output }, { ok: false, error: `not installed: ${missing.join(", ")}`, missing });
@@ -1567,17 +2115,17 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
1567
2115
  const ok = deps.confirm ? await deps.confirm(`Remove ${known.length} skill${known.length === 1 ? "" : "s"} (${known.join(", ")}) ${what} in ${where} scope?`) : null;
1568
2116
  if (ok === null) {
1569
2117
  const error = nonInteractiveHint("-y");
1570
- return finish3(flags, { removed: [], exitCode: 1, output: pc10.red(error) }, { ok: false, error });
2118
+ return finish3(flags, { removed: [], exitCode: 1, output: pc12.red(error) }, { ok: false, error });
1571
2119
  }
1572
- if (!ok) return finish3(flags, { removed: [], exitCode: 0, cancelled: true, output: pc10.dim("Nothing removed.") }, { ok: true, removed: [], cancelled: true });
2120
+ if (!ok) return finish3(flags, { removed: [], exitCode: 0, cancelled: true, output: pc12.dim("Nothing removed.") }, { ok: true, removed: [], cancelled: true });
1573
2121
  }
1574
2122
  const removed = [];
1575
2123
  const skipped = [];
1576
2124
  let changed = 0;
1577
2125
  for (const name of known) {
1578
2126
  for (const { scope, installed } of perScope) {
1579
- if (!installed.some((s) => s.name === name)) continue;
1580
- const tag = scopes.length > 1 ? pc10.dim(` [${scopeLabel(scope)}]`) : "";
2127
+ if (!installed.some((s2) => s2.name === name)) continue;
2128
+ const tag = scopes.length > 1 ? pc12.dim(` [${scopeLabel(scope)}]`) : "";
1581
2129
  if (flags.agent?.length) {
1582
2130
  const lock = readLock({ global: Boolean(scope.global), cwd: scope.cwd, home: scope.home });
1583
2131
  const entry = lock.skills[name];
@@ -1588,11 +2136,11 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
1588
2136
  try {
1589
2137
  dir = agentDir(a, scope);
1590
2138
  } catch (e) {
1591
- lines.push(pc10.yellow(`- ${a}: ${e instanceof Error ? e.message : String(e)}`));
2139
+ lines.push(pc12.yellow(`- ${a}: ${e instanceof Error ? e.message : String(e)}`));
1592
2140
  continue;
1593
2141
  }
1594
2142
  if (resolve4(dir) === canonRoot || entry?.mode[a] === "canonical") {
1595
- lines.push(pc10.dim(`${GLYPH.skip} ${name}: ${a} reads the canonical copy directly \u2014 unlinking is a no-op (use remove without -a to delete the skill)`));
2143
+ lines.push(pc12.dim(`${GLYPH.skip} ${name}: ${a} reads the canonical copy directly \u2014 unlinking is a no-op (use remove without -a to delete the skill)`));
1596
2144
  skipped.push({ skill: name, agent: a, scope: scopeLabel(scope), reason: "reads the canonical copy directly" });
1597
2145
  acted = true;
1598
2146
  continue;
@@ -1602,17 +2150,17 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
1602
2150
  rmSync(pth, { recursive: true, force: true });
1603
2151
  removed.push(pth);
1604
2152
  acted = true;
1605
- lines.push(pc10.green(`${GLYPH.ok} removed ${name} from ${a}`) + tag);
2153
+ lines.push(pc12.green(`${GLYPH.ok} removed ${name} from ${a}`) + tag);
1606
2154
  }
1607
2155
  }
1608
- if (!acted) lines.push(pc10.yellow(`- ${name} is not linked into ${flags.agent.join(", ")}`) + tag);
2156
+ if (!acted) lines.push(pc12.yellow(`- ${name} is not linked into ${flags.agent.join(", ")}`) + tag);
1609
2157
  if (entry) {
1610
2158
  const left = entry.agents.filter((a) => !flags.agent.includes(a));
1611
2159
  if (left.length) upsertEntry({ global: Boolean(scope.global), cwd: scope.cwd, home: scope.home }, name, { ...entry, agents: left, mode: Object.fromEntries(Object.entries(entry.mode).filter(([a]) => left.includes(a))) });
1612
2160
  else {
1613
2161
  const r2 = uninstallSkill(name, scope);
1614
2162
  removed.push(...r2.removed);
1615
- lines.push(pc10.dim(` (no agents left \u2014 removed the canonical copy too)`));
2163
+ lines.push(pc12.dim(` (no agents left \u2014 removed the canonical copy too)`));
1616
2164
  }
1617
2165
  }
1618
2166
  if (acted) changed++;
@@ -1621,7 +2169,7 @@ async function runRemove(names, flags, deps = defaultDeps(flags)) {
1621
2169
  const r = uninstallSkill(name, scope);
1622
2170
  removed.push(...r.removed);
1623
2171
  changed++;
1624
- lines.push(pc10.green(`${GLYPH.ok} removed ${name}`) + tag + pc10.dim(` (${r.removed.length} path${r.removed.length === 1 ? "" : "s"}${r.untracked ? ", untracked" : ""})`));
2172
+ lines.push(pc12.green(`${GLYPH.ok} removed ${name}`) + tag + pc12.dim(` (${r.removed.length} path${r.removed.length === 1 ? "" : "s"}${r.untracked ? ", untracked" : ""})`));
1625
2173
  }
1626
2174
  }
1627
2175
  const exitCode = changed ? 0 : 1;
@@ -1639,7 +2187,7 @@ function removeCommand() {
1639
2187
 
1640
2188
  // src/commands/update.ts
1641
2189
  import { Command as Command10 } from "commander";
1642
- import pc11 from "picocolors";
2190
+ import pc13 from "picocolors";
1643
2191
  import { lint as lint3 } from "@skillmds/core";
1644
2192
  function pickSkillTree(files, want) {
1645
2193
  const norm = files.map((f) => ({ path: f.path.replace(/\\/g, "/"), contents: f.contents }));
@@ -1702,64 +2250,64 @@ async function runUpdate(names, flags, deps = defaultUpdateDeps) {
1702
2250
  for (const global of scopes) {
1703
2251
  const scope = { global, cwd: flags.cwd, home: flags.home };
1704
2252
  const lock = readLock(scope);
1705
- const installed = listInstalled(scope).filter((s) => names.length === 0 || names.includes(s.name));
1706
- for (const s of installed) {
1707
- seen.add(s.name);
1708
- const label2 = `${s.name}${scopes.length > 1 ? pc11.dim(` [${s.scope}]`) : ""}`;
1709
- const entry = lock.skills[s.name];
2253
+ const installed = listInstalled(scope).filter((s2) => names.length === 0 || names.includes(s2.name));
2254
+ for (const s2 of installed) {
2255
+ seen.add(s2.name);
2256
+ const label2 = `${s2.name}${scopes.length > 1 ? pc13.dim(` [${s2.scope}]`) : ""}`;
2257
+ const entry = lock.skills[s2.name];
1710
2258
  if (!entry) {
1711
- lines.push(pc11.dim(`- ${label2} untracked \u2014 reinstall with \`npx get-skill add\` to track updates`));
2259
+ lines.push(pc13.dim(`- ${label2} untracked \u2014 reinstall with \`npx get-skill add\` to track updates`));
1712
2260
  continue;
1713
2261
  }
1714
2262
  if (entry.source.startsWith("local:")) {
1715
- lines.push(pc11.dim(`- ${label2} local source \u2014 not auto-updated`));
2263
+ lines.push(pc13.dim(`- ${label2} local source \u2014 not auto-updated`));
1716
2264
  continue;
1717
2265
  }
1718
2266
  try {
1719
- const latest = await deps.fetchLatest(entry.source, flags, s.name);
2267
+ const latest = await deps.fetchLatest(entry.source, flags, s2.name);
1720
2268
  if (!latest) {
1721
- failed.push(s.name);
1722
- lines.push(pc11.red(`${GLYPH.blocked} ${label2} no longer available upstream (${entry.source})`));
2269
+ failed.push(s2.name);
2270
+ lines.push(pc13.red(`${GLYPH.blocked} ${label2} no longer available upstream (${entry.source})`));
1723
2271
  continue;
1724
2272
  }
1725
2273
  if (entry.source.startsWith("registry:") && latest.commit_sha && entry.commit_sha && latest.commit_sha === entry.commit_sha) {
1726
- lines.push(pc11.dim(`- ${label2} up to date`));
2274
+ lines.push(pc13.dim(`- ${label2} up to date`));
1727
2275
  continue;
1728
2276
  }
1729
2277
  if (digestOf(latest.files) === entry.digest) {
1730
- lines.push(pc11.dim(`- ${label2} up to date`));
2278
+ lines.push(pc13.dim(`- ${label2} up to date`));
1731
2279
  continue;
1732
2280
  }
1733
2281
  if (flags.check) {
1734
- available.push(s.name);
1735
- lines.push(pc11.yellow(`\u2191 ${label2} update available`));
2282
+ available.push(s2.name);
2283
+ lines.push(pc13.yellow(`\u2191 ${label2} update available`));
1736
2284
  continue;
1737
2285
  }
1738
2286
  const md = latest.files.find((f) => f.path === "SKILL.md");
1739
2287
  const raw = md ? typeof md.contents === "string" ? md.contents : md.contents.toString("utf8") : "";
1740
- const result = lint3(raw, { slug: s.name });
2288
+ const result = lint3(raw, { slug: s2.name });
1741
2289
  if (!result.ok) {
1742
- failed.push(s.name);
1743
- lines.push(pc11.red(`${GLYPH.blocked} ${label2} update failed lint (${result.diagnostics.filter((d) => d.severity === "error").map((d) => d.id).join(", ")}) \u2014 kept the installed version`));
2290
+ failed.push(s2.name);
2291
+ lines.push(pc13.red(`${GLYPH.blocked} ${label2} update failed lint (${result.diagnostics.filter((d) => d.severity === "error").map((d) => d.id).join(", ")}) \u2014 kept the installed version`));
1744
2292
  continue;
1745
2293
  }
1746
- await installSkill({ name: s.name, files: latest.files, source: entry.source, commit_sha: latest.commit_sha, scope, agents: entry.agents, explicitAgents: true, mode: Object.values(entry.mode).includes("copy") ? "copy" : "link" });
1747
- updated.push(s.name);
1748
- lines.push(pc11.green(`${GLYPH.ok} ${label2} updated`));
2294
+ await installSkill({ name: s2.name, files: latest.files, source: entry.source, commit_sha: latest.commit_sha, scope, agents: entry.agents, explicitAgents: true, mode: Object.values(entry.mode).includes("copy") ? "copy" : "link" });
2295
+ updated.push(s2.name);
2296
+ lines.push(pc13.green(`${GLYPH.ok} ${label2} updated`));
1749
2297
  } catch (e) {
1750
- failed.push(s.name);
1751
- lines.push(pc11.red(`${GLYPH.blocked} ${label2} ${e instanceof Error ? e.message : String(e)}`));
2298
+ failed.push(s2.name);
2299
+ lines.push(pc13.red(`${GLYPH.blocked} ${label2} ${e instanceof Error ? e.message : String(e)}`));
1752
2300
  }
1753
2301
  }
1754
2302
  }
1755
2303
  for (const n of names) {
1756
2304
  if (seen.has(n)) continue;
1757
2305
  failed.push(n);
1758
- lines.push(pc11.yellow(`- ${n} not installed`));
2306
+ lines.push(pc13.yellow(`- ${n} not installed`));
1759
2307
  }
1760
2308
  const exitCode = failed.length ? 1 : 0;
1761
2309
  if (flags.json) return { updated, available, failed, exitCode, output: JSON.stringify({ ok: exitCode === 0, updated: [...new Set(updated)], available: [...new Set(available)], failed: [...new Set(failed)] }, null, 2) };
1762
- if (lines.length === 0) lines.push(pc11.dim("No installed skills found."));
2310
+ if (lines.length === 0) lines.push(pc13.dim("No installed skills found."));
1763
2311
  return { updated, available, failed, exitCode, output: lines.join("\n") };
1764
2312
  }
1765
2313
  function scopeOptions(cmd) {
@@ -1767,14 +2315,16 @@ function scopeOptions(cmd) {
1767
2315
  }
1768
2316
  function updateCommand() {
1769
2317
  return scopeOptions(new Command10("update").description("Update installed skills from the source recorded in the lock file (re-lints before writing)").argument("[names...]", "specific skills (default: all tracked)").option("--check", "only report which skills have updates")).action(async (names, opts, cmd) => {
1770
- const run2 = await runUpdate(names, { ...cmd.parent?.opts(), ...opts });
2318
+ const flags = { ...cmd.parent?.opts(), ...opts };
2319
+ const run2 = await waitFor("walk", flags.check ? "Checking for updates" : "Updating skills", runUpdate(names, flags), { json: flags.json });
1771
2320
  console.log(run2.output);
1772
2321
  process.exitCode = run2.exitCode;
1773
2322
  });
1774
2323
  }
1775
2324
  function checkCommand() {
1776
2325
  return scopeOptions(new Command10("check").description("Report installed skills that have updates (alias of `update --check`)").argument("[names...]", "specific skills (default: all tracked)")).action(async (names, opts, cmd) => {
1777
- const run2 = await runUpdate(names, { ...cmd.parent?.opts(), ...opts, check: true });
2326
+ const flags = { ...cmd.parent?.opts(), ...opts, check: true };
2327
+ const run2 = await waitFor("walk", "Checking for updates", runUpdate(names, flags), { json: flags.json });
1778
2328
  console.log(run2.output);
1779
2329
  process.exitCode = run2.exitCode;
1780
2330
  });
@@ -1782,7 +2332,7 @@ function checkCommand() {
1782
2332
 
1783
2333
  // src/commands/publish.ts
1784
2334
  import { Command as Command11 } from "commander";
1785
- import pc12 from "picocolors";
2335
+ import pc14 from "picocolors";
1786
2336
  import { lint as lint4, toText } from "@skillmds/core";
1787
2337
  var defaultDeps2 = {
1788
2338
  resolve: resolveSource,
@@ -1806,25 +2356,25 @@ async function runPublish(target, flags, deps = defaultDeps2) {
1806
2356
  const report = toText([{ file: src.path, result }], { decorate });
1807
2357
  if (!result.ok) {
1808
2358
  return { result, published: false, exitCode: 1, output: `${report}
1809
- ${pc12.red("\u2717 Refusing to publish: fix the errors above.")}` };
2359
+ ${pc14.red("\u2717 Refusing to publish: fix the errors above.")}` };
1810
2360
  }
1811
2361
  const hasWarn = result.diagnostics.some((d) => d.severity === "warn");
1812
2362
  if (hasWarn && !flags.force) {
1813
2363
  return { result, published: false, exitCode: 1, output: `${report}
1814
- ${pc12.yellow("\u2717 Warnings present. Re-run with --force to publish anyway.")}` };
2364
+ ${pc14.yellow("\u2717 Warnings present. Re-run with --force to publish anyway.")}` };
1815
2365
  }
1816
2366
  if (flags.dryRun) {
1817
2367
  return { result, published: false, exitCode: 0, output: `${report}
1818
- ${pc12.green("\u2713 Dry run: would publish.")}` };
2368
+ ${pc14.green("\u2713 Dry run: would publish.")}` };
1819
2369
  }
1820
2370
  const res = await deps.submit({ content: src.raw, type: flags.type ?? "single" }, flags);
1821
2371
  return { result, published: true, slug: res.slug, exitCode: 0, output: `${report}
1822
- ${pc12.green(`\u2713 Published ${res.slug ?? src.slug} (status: ${res.status ?? "pending"})`)}` };
2372
+ ${pc14.green(`\u2713 Published ${res.slug ?? src.slug} (status: ${res.status ?? "pending"})`)}` };
1823
2373
  }
1824
2374
  function publishCommand() {
1825
2375
  return new Command11("publish").alias("submit").description("Publish a skill to the registry (refuses to publish on lint errors)").argument("[target]", "local path to the skill", ".").option("--type <type>", "single | pack", "single").option("--force", "publish despite warnings (never bypasses errors)").option("--dry-run", "lint only; do not publish").action(async (target, opts, cmd) => {
1826
2376
  const merged = { ...cmd.parent?.opts(), ...opts };
1827
- const run2 = await runPublish(target, merged);
2377
+ const run2 = await waitFor("walk", merged.dryRun ? "Checking" : "Publishing", runPublish(target, merged));
1828
2378
  console.log(run2.output);
1829
2379
  process.exitCode = run2.exitCode;
1830
2380
  });
@@ -1832,11 +2382,10 @@ function publishCommand() {
1832
2382
 
1833
2383
  // src/commands/login.ts
1834
2384
  import { Command as Command12 } from "commander";
1835
- import * as p5 from "@clack/prompts";
1836
- import pc13 from "picocolors";
2385
+ import pc15 from "picocolors";
1837
2386
  var defaultLoginDeps = (flags) => promptIf(flags, async () => {
1838
- const answer = await p5.password({ message: "Paste your SkillMD token (from your account page)" });
1839
- return p5.isCancel(answer) ? null : answer;
2387
+ const answer = await password({ message: "Paste your SkillMD token (from your account page)" });
2388
+ return isCancel(answer) ? null : answer;
1840
2389
  });
1841
2390
  function finish4(flags, result, doc) {
1842
2391
  return flags.json ? { ...result, output: JSON.stringify(doc, null, 2) } : result;
@@ -1847,15 +2396,15 @@ async function runLogin(flags, deps = defaultLoginDeps(flags)) {
1847
2396
  if (!token) {
1848
2397
  if (!deps.prompt) {
1849
2398
  const error = nonInteractiveHint("--token <token> (or set SKILLMD_TOKEN)");
1850
- return finish4(flags, { exitCode: 1, output: pc13.red(error) }, { ok: false, error });
2399
+ return finish4(flags, { exitCode: 1, output: pc15.red(error) }, { ok: false, error });
1851
2400
  }
1852
2401
  const answer = await deps.prompt();
1853
- if (answer === null) return finish4(flags, { exitCode: 0, output: pc13.dim("Cancelled.") }, { ok: false, cancelled: true });
2402
+ if (answer === null) return finish4(flags, { exitCode: 0, output: pc15.dim("Cancelled.") }, { ok: false, cancelled: true });
1854
2403
  token = answer;
1855
2404
  }
1856
2405
  if (!token) {
1857
2406
  const error = "A token is required.";
1858
- return finish4(flags, { exitCode: 1, output: pc13.red(error) }, { ok: false, error });
2407
+ return finish4(flags, { exitCode: 1, output: pc15.red(error) }, { ok: false, error });
1859
2408
  }
1860
2409
  const cfg = readConfig(flags.home);
1861
2410
  let host;
@@ -1863,7 +2412,7 @@ async function runLogin(flags, deps = defaultLoginDeps(flags)) {
1863
2412
  host = hostOf(resolveApi({ api: flags.api, insecureHttp: flags.insecureHttp }, { env, config: { ...cfg, api: flags.api ?? cfg.api } }));
1864
2413
  } catch (e) {
1865
2414
  const msg2 = e instanceof Error ? e.message : String(e);
1866
- return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error: msg2 }, null, 2) : pc13.red(msg2) };
2415
+ return { exitCode: 1, output: flags.json ? JSON.stringify({ ok: false, error: msg2 }, null, 2) : pc15.red(msg2) };
1867
2416
  }
1868
2417
  cfg.token = token;
1869
2418
  if (flags.api) cfg.api = flags.api;
@@ -1902,11 +2451,10 @@ function logoutCommand() {
1902
2451
  }
1903
2452
 
1904
2453
  // src/commands/interactive.ts
1905
- import * as p6 from "@clack/prompts";
1906
- import pc14 from "picocolors";
2454
+ import pc16 from "picocolors";
1907
2455
  function bail(v) {
1908
- if (p6.isCancel(v)) {
1909
- p6.cancel("Cancelled.");
2456
+ if (isCancel(v)) {
2457
+ cancel("Cancelled.");
1910
2458
  return true;
1911
2459
  }
1912
2460
  return false;
@@ -1914,7 +2462,7 @@ function bail(v) {
1914
2462
  async function browseSearchResults(items) {
1915
2463
  const cols = process.stdout.columns ?? 80;
1916
2464
  for (; ; ) {
1917
- const picked = await p6.select({
2465
+ const picked = await select({
1918
2466
  message: "Search results",
1919
2467
  options: [
1920
2468
  ...items.map((item2) => {
@@ -1922,7 +2470,7 @@ async function browseSearchResults(items) {
1922
2470
  const checkTxt = item2.verified ? " \u2713" : "";
1923
2471
  const slugTxt = safeText(item2.slug, 200);
1924
2472
  const plainLabel = `${slugTxt}${starsTxt}${checkTxt}`;
1925
- const label2 = `${pc14.bold(slugTxt)}${starsTxt ? pc14.dim(starsTxt) : ""}${checkTxt ? pc14.green(checkTxt) : ""}`;
2473
+ const label2 = `${pc16.bold(slugTxt)}${starsTxt ? pc16.dim(starsTxt) : ""}${checkTxt ? pc16.green(checkTxt) : ""}`;
1926
2474
  const hintWidth = Math.max(10, cols - plainLabel.length - 6);
1927
2475
  return {
1928
2476
  value: item2.slug,
@@ -1933,7 +2481,7 @@ async function browseSearchResults(items) {
1933
2481
  { value: "__back", label: "\u2190 Back to menu" }
1934
2482
  ]
1935
2483
  });
1936
- if (p6.isCancel(picked) || picked === "__back") return;
2484
+ if (isCancel(picked) || picked === "__back") return;
1937
2485
  const item = items.find((i) => i.slug === picked);
1938
2486
  if (!item) continue;
1939
2487
  await browseOneResult(item);
@@ -1944,12 +2492,12 @@ async function browseOneResult(item) {
1944
2492
  const slugTxt = safeText(item.slug, 200);
1945
2493
  const meta = [
1946
2494
  starsTxt,
1947
- item.verified ? pc14.green("\u2713 verified") : "unverified",
2495
+ item.verified ? pc16.green("\u2713 verified") : "unverified",
1948
2496
  item.type === "pack" ? "pack" : ""
1949
2497
  ].filter(Boolean).join(" \xB7 ");
1950
- p6.note([safeText(item.description ?? ""), pc14.dim(meta)].join("\n"), slugTxt);
2498
+ note([safeText(item.description ?? ""), pc16.dim(meta)].join("\n"), slugTxt);
1951
2499
  for (; ; ) {
1952
- const action = await p6.select({
2500
+ const action = await select({
1953
2501
  message: "What next?",
1954
2502
  options: [
1955
2503
  { value: "project", label: "Install to this project" },
@@ -1958,26 +2506,31 @@ async function browseOneResult(item) {
1958
2506
  { value: "back", label: "\u2190 Back to results" }
1959
2507
  ]
1960
2508
  });
1961
- if (p6.isCancel(action) || action === "back") return;
2509
+ if (isCancel(action) || action === "back") return;
1962
2510
  if (action === "url") {
1963
- p6.log.message(pc14.dim(`https://skillmd.com/skills/${slugTxt}`));
2511
+ log.message(pc16.dim(`https://skillmd.com/skills/${slugTxt}`));
1964
2512
  continue;
1965
2513
  }
1966
- p6.log.step(`Installing ${slugTxt}\u2026`);
2514
+ log.step(`Installing ${slugTxt}\u2026`);
1967
2515
  try {
1968
2516
  const run2 = await runAdd(item.slug, action === "global" ? { global: true } : { project: true });
1969
2517
  console.log(run2.output);
1970
- if (run2.exitCode === 0) p6.log.success("Installed.");
1971
- else p6.log.warn("Not installed.");
2518
+ if (run2.exitCode === 0) log.success("Installed.");
2519
+ else log.warn("Not installed.");
1972
2520
  } catch (err) {
1973
- p6.log.error(err instanceof Error ? err.message : String(err));
2521
+ log.error(err instanceof Error ? err.message : String(err));
1974
2522
  }
1975
2523
  }
1976
2524
  }
1977
- async function runInteractive() {
1978
- p6.intro(banner());
2525
+ async function runInteractive(opts = {}) {
2526
+ console.log();
2527
+ await playLogo();
2528
+ console.log(`
2529
+ ${pc16.dim("Teach your agent anything.")}${opts.version ? ` ${pc16.dim(`v${opts.version}`)}` : ""}
2530
+ `);
2531
+ startFrameAfterLogo();
1979
2532
  for (; ; ) {
1980
- const action = await p6.select({
2533
+ const action = await select({
1981
2534
  message: "What would you like to do?",
1982
2535
  options: [
1983
2536
  { value: "lint", label: "Lint a skill", hint: "validate a SKILL.md" },
@@ -1996,66 +2549,66 @@ async function runInteractive() {
1996
2549
  switch (action) {
1997
2550
  case "lint":
1998
2551
  case "scan": {
1999
- const path = await p6.text({ message: "Path to a skill or folder", placeholder: ".", defaultValue: "." });
2552
+ const path = await text({ message: "Path to a skill or folder", placeholder: ".", defaultValue: "." });
2000
2553
  if (bail(path)) break;
2001
2554
  const target = String(path || ".");
2002
- const s = p6.spinner();
2003
- s.start(action === "lint" ? "Linting" : "Scanning");
2555
+ const s2 = spinner("walk");
2556
+ s2.start(action === "lint" ? "Linting" : "Scanning");
2004
2557
  try {
2005
2558
  const run2 = action === "lint" ? await runLint(target, { format: "text" }) : await runScan(target, { format: "text" });
2006
- s.stop("Done");
2559
+ s2.stop("Done");
2007
2560
  console.log(run2.output);
2008
2561
  process.exitCode = run2.exitCode;
2009
2562
  } catch (err) {
2010
- s.stop(pc14.red(err instanceof Error ? err.message : String(err)));
2563
+ s2.stop(pc16.red(err instanceof Error ? err.message : String(err)));
2011
2564
  process.exitCode = 1;
2012
2565
  }
2013
2566
  break;
2014
2567
  }
2015
2568
  case "search": {
2016
- const query = await p6.text({ message: "Search the registry for" });
2569
+ const query = await text({ message: "Search the registry for" });
2017
2570
  if (bail(query)) break;
2018
- const verified = await p6.confirm({ message: "Verified skills only?", initialValue: false });
2571
+ const verified = await confirm({ message: "Verified skills only?", initialValue: false });
2019
2572
  if (bail(verified)) break;
2020
- const s = p6.spinner();
2021
- s.start("Searching");
2573
+ const s2 = spinner("hop");
2574
+ s2.start(`Searching for ${safeText(String(query))}`);
2022
2575
  try {
2023
2576
  const run2 = await runSearch(String(query), { verified: Boolean(verified), limit: "20" });
2024
- s.stop(`${run2.items.length} result${run2.items.length === 1 ? "" : "s"}`);
2577
+ s2.stop(`${run2.items.length} result${run2.items.length === 1 ? "" : "s"}`);
2025
2578
  if (run2.items.length === 0) {
2026
- p6.log.info("No results.");
2579
+ log.info("No results.");
2027
2580
  break;
2028
2581
  }
2029
2582
  await browseSearchResults(run2.items);
2030
2583
  } catch (err) {
2031
- s.stop(pc14.red(err instanceof Error ? err.message : String(err)));
2584
+ s2.stop(pc16.red(err instanceof Error ? err.message : String(err)));
2032
2585
  process.exitCode = 1;
2033
2586
  }
2034
2587
  break;
2035
2588
  }
2036
2589
  case "init": {
2037
- const name = await p6.text({ message: "Skill name", placeholder: "my-skill" });
2590
+ const name = await text({ message: "Skill name", placeholder: "my-skill" });
2038
2591
  if (bail(name)) break;
2039
- const description = await p6.text({ message: "One-line description", placeholder: "What this skill helps an agent do" });
2592
+ const description = await text({ message: "One-line description", placeholder: "What this skill helps an agent do" });
2040
2593
  if (bail(description)) break;
2041
2594
  try {
2042
2595
  const file = initSkill(String(name), { description: String(description || "") });
2043
- p6.log.success(`Created ${pc14.bold(file)}`);
2596
+ log.success(`Created ${pc16.bold(file)}`);
2044
2597
  } catch (err) {
2045
- p6.log.error(err instanceof Error ? err.message : String(err));
2598
+ log.error(err instanceof Error ? err.message : String(err));
2046
2599
  process.exitCode = 1;
2047
2600
  }
2048
2601
  break;
2049
2602
  }
2050
2603
  case "install": {
2051
- const src = await p6.text({ message: "Skill source", placeholder: "owner/name, https://github.com/\u2026, or ./path" });
2604
+ const src = await text({ message: "Skill source", placeholder: "owner/name, https://github.com/\u2026, or ./path" });
2052
2605
  if (bail(src)) break;
2053
2606
  try {
2054
2607
  const run2 = await runAdd(String(src), {});
2055
2608
  console.log(run2.output);
2056
2609
  process.exitCode = run2.exitCode;
2057
2610
  } catch (err) {
2058
- p6.log.error(err instanceof Error ? err.message : String(err));
2611
+ log.error(err instanceof Error ? err.message : String(err));
2059
2612
  process.exitCode = 1;
2060
2613
  }
2061
2614
  break;
@@ -2065,12 +2618,16 @@ async function runInteractive() {
2065
2618
  break;
2066
2619
  }
2067
2620
  case "update": {
2621
+ const s2 = spinner("walk");
2622
+ s2.start("Updating installed skills");
2068
2623
  try {
2069
2624
  const run2 = await runUpdate([], {});
2625
+ const n = new Set(run2.updated).size;
2626
+ s2.stop(n ? `Updated ${n} skill${n === 1 ? "" : "s"}` : "Done", run2.exitCode === 0 ? 0 : 2);
2070
2627
  console.log(run2.output);
2071
2628
  process.exitCode = run2.exitCode;
2072
2629
  } catch (err) {
2073
- p6.log.error(err instanceof Error ? err.message : String(err));
2630
+ s2.stop(pc16.red(err instanceof Error ? err.message : String(err)), 2);
2074
2631
  process.exitCode = 1;
2075
2632
  }
2076
2633
  break;
@@ -2081,23 +2638,23 @@ async function runInteractive() {
2081
2638
  console.log(run2.output);
2082
2639
  process.exitCode = run2.exitCode;
2083
2640
  } catch (err) {
2084
- p6.log.error(err instanceof Error ? err.message : String(err));
2641
+ log.error(err instanceof Error ? err.message : String(err));
2085
2642
  process.exitCode = 1;
2086
2643
  }
2087
2644
  break;
2088
2645
  }
2089
2646
  case "help": {
2090
- p6.note(
2647
+ note(
2091
2648
  [
2092
- `${pc14.bold("lint")} [path] validate SKILL.md + quality score`,
2093
- `${pc14.bold("scan")} [path] security scan`,
2094
- `${pc14.bold("search")} <query> search the registry`,
2095
- `${pc14.bold("add")} <source> install a skill (lints first)`,
2096
- `${pc14.bold("info")} <slug> registry details for a skill`,
2097
- `${pc14.bold("init")} [name] scaffold a new skill`,
2098
- `${pc14.bold("list / remove / update")} manage installed skills`,
2099
- `${pc14.bold("publish")} [path] publish (fails on lint errors)`,
2100
- `${pc14.bold("rules / login")}`
2649
+ `${pc16.bold("lint")} [path] validate SKILL.md + quality score`,
2650
+ `${pc16.bold("scan")} [path] security scan`,
2651
+ `${pc16.bold("search")} <query> search the registry`,
2652
+ `${pc16.bold("add")} <source> install a skill (lints first)`,
2653
+ `${pc16.bold("info")} <slug> registry details for a skill`,
2654
+ `${pc16.bold("init")} [name] scaffold a new skill`,
2655
+ `${pc16.bold("list / remove / update")} manage installed skills`,
2656
+ `${pc16.bold("publish")} [path] publish (fails on lint errors)`,
2657
+ `${pc16.bold("rules / login")}`
2101
2658
  ].join("\n"),
2102
2659
  "Commands (run: skillmd <command>)"
2103
2660
  );
@@ -2105,7 +2662,7 @@ async function runInteractive() {
2105
2662
  }
2106
2663
  }
2107
2664
  }
2108
- p6.outro(pc14.dim("skillmd.com"));
2665
+ outro(pc16.dim("skillmd.com"));
2109
2666
  }
2110
2667
 
2111
2668
  // src/index.ts
@@ -2135,7 +2692,7 @@ Docs: https://skillmd.com/docs/cli`);
2135
2692
  program.hook("preAction", (thisCmd) => {
2136
2693
  const opts = thisCmd.opts();
2137
2694
  if (opts.token && process.stderr.isTTY) {
2138
- console.error(pc15.yellow("\u26A0 --token is visible in your shell history and process list; prefer `npx get-skill login` or SKILLMD_TOKEN."));
2695
+ console.error(pc17.yellow("\u26A0 --token is visible in your shell history and process list; prefer `npx get-skill login` or SKILLMD_TOKEN."));
2139
2696
  }
2140
2697
  });
2141
2698
  program.addCommand(lintCommand());
@@ -2154,7 +2711,7 @@ program.addCommand(loginCommand());
2154
2711
  program.addCommand(logoutCommand());
2155
2712
  if (process.argv.slice(2).length === 0) {
2156
2713
  if (process.stdout.isTTY) {
2157
- await runInteractive();
2714
+ await runInteractive({ version });
2158
2715
  process.exit(process.exitCode ?? 0);
2159
2716
  }
2160
2717
  program.outputHelp();