skillio 0.1.9 → 0.1.10
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 +229 -117
- package/dist/shared/chunk-eq7h491z.js +113 -0
- package/dist/shared/chunk-s3421yr2.js +27 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
__require,
|
|
4
|
+
cyan,
|
|
5
|
+
detectColorSupport,
|
|
6
|
+
green,
|
|
7
|
+
red,
|
|
8
|
+
setColorEnabled,
|
|
9
|
+
yellow
|
|
10
|
+
} from "./shared/chunk-s3421yr2.js";
|
|
4
11
|
|
|
5
12
|
// src/cli.ts
|
|
6
|
-
import { createRequire
|
|
13
|
+
import { createRequire } from "node:module";
|
|
7
14
|
|
|
8
15
|
// node_modules/citty/dist/_chunks/libs/scule.mjs
|
|
9
16
|
var NUMBER_CHAR_RE = /\d/;
|
|
@@ -222,7 +229,7 @@ var noColor = /* @__PURE__ */ (() => {
|
|
|
222
229
|
})();
|
|
223
230
|
var _c = (c, r = 39) => (t) => noColor ? t : `\x1B[${c}m${t}\x1B[${r}m`;
|
|
224
231
|
var bold = /* @__PURE__ */ _c(1, 22);
|
|
225
|
-
var
|
|
232
|
+
var cyan2 = /* @__PURE__ */ _c(36);
|
|
226
233
|
var gray = /* @__PURE__ */ _c(90);
|
|
227
234
|
var underline = /* @__PURE__ */ _c(4, 24);
|
|
228
235
|
function parseArgs(rawArgs, argsDef) {
|
|
@@ -274,7 +281,7 @@ function parseArgs(rawArgs, argsDef) {
|
|
|
274
281
|
const argument = parsedArgsProxy[arg.name];
|
|
275
282
|
const options = arg.options || [];
|
|
276
283
|
if (argument !== undefined && options.length > 0 && !options.includes(argument))
|
|
277
|
-
throw new CLIError(`Invalid value for argument: ${
|
|
284
|
+
throw new CLIError(`Invalid value for argument: ${cyan2(`--${arg.name}`)} (${cyan2(argument)}). Expected one of: ${options.map((o) => cyan2(o)).join(", ")}.`, "EARG");
|
|
278
285
|
} else if (arg.required && parsedArgsProxy[arg.name] === undefined)
|
|
279
286
|
throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
|
|
280
287
|
return parsedArgsProxy;
|
|
@@ -319,7 +326,7 @@ async function runCommand(cmd, opts) {
|
|
|
319
326
|
if (explicitName) {
|
|
320
327
|
const subCommand = await _findSubCommand(subCommands, explicitName);
|
|
321
328
|
if (!subCommand)
|
|
322
|
-
throw new CLIError(`Unknown command ${
|
|
329
|
+
throw new CLIError(`Unknown command ${cyan2(explicitName)}`, "E_UNKNOWN_COMMAND");
|
|
323
330
|
await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
|
|
324
331
|
} else {
|
|
325
332
|
const defaultSubCommand = await resolveValue(cmd.default);
|
|
@@ -328,7 +335,7 @@ async function runCommand(cmd, opts) {
|
|
|
328
335
|
throw new CLIError(`Cannot specify both 'run' and 'default' on the same command.`, "E_DEFAULT_CONFLICT");
|
|
329
336
|
const subCommand = await _findSubCommand(subCommands, defaultSubCommand);
|
|
330
337
|
if (!subCommand)
|
|
331
|
-
throw new CLIError(`Default sub command ${
|
|
338
|
+
throw new CLIError(`Default sub command ${cyan2(defaultSubCommand)} not found in subCommands.`, "E_UNKNOWN_COMMAND");
|
|
332
339
|
await runCommand(subCommand, { rawArgs: opts.rawArgs });
|
|
333
340
|
} else if (!cmd.run)
|
|
334
341
|
throw new CLIError(`No command specified.`, "E_NO_COMMAND");
|
|
@@ -432,15 +439,15 @@ async function renderUsage(cmd, parent) {
|
|
|
432
439
|
if (arg.type === "positional") {
|
|
433
440
|
const name = arg.name.toUpperCase();
|
|
434
441
|
const isRequired = arg.required !== false && arg.default === undefined;
|
|
435
|
-
posLines.push([
|
|
442
|
+
posLines.push([cyan2(name + renderValueHint(arg)), renderDescription(arg, isRequired)]);
|
|
436
443
|
usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
|
|
437
444
|
} else {
|
|
438
445
|
const isRequired = arg.required === true && arg.default === undefined;
|
|
439
446
|
const argStr = [...(arg.alias || []).map((a) => `-${a}`), `--${arg.name}`].join(", ") + renderValueHint(arg);
|
|
440
|
-
argLines.push([
|
|
447
|
+
argLines.push([cyan2(argStr), renderDescription(arg, isRequired)]);
|
|
441
448
|
if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
|
|
442
449
|
const negativeArgStr = [...(arg.alias || []).map((a) => `--no-${a}`), `--no-${arg.name}`].join(", ");
|
|
443
|
-
argLines.push([
|
|
450
|
+
argLines.push([cyan2(negativeArgStr), [arg.negativeDescription, isRequired ? gray("(Required)") : ""].filter(Boolean).join(" ")]);
|
|
444
451
|
}
|
|
445
452
|
if (isRequired)
|
|
446
453
|
usageLine.push(`--${arg.name}` + renderValueHint(arg));
|
|
@@ -454,7 +461,7 @@ async function renderUsage(cmd, parent) {
|
|
|
454
461
|
continue;
|
|
455
462
|
const aliases = toArray(meta?.alias);
|
|
456
463
|
const label = [name, ...aliases].join(", ");
|
|
457
|
-
commandsLines.push([
|
|
464
|
+
commandsLines.push([cyan2(label), meta?.description || ""]);
|
|
458
465
|
commandNames.push(name, ...aliases);
|
|
459
466
|
}
|
|
460
467
|
usageLine.push(commandNames.join("|"));
|
|
@@ -463,7 +470,7 @@ async function renderUsage(cmd, parent) {
|
|
|
463
470
|
const version = cmdMeta.version || parentMeta.version;
|
|
464
471
|
usageLines.push(gray(`${cmdMeta.description} (${commandName + (version ? ` v${version}` : "")})`), "");
|
|
465
472
|
const hasOptions = argLines.length > 0 || posLines.length > 0;
|
|
466
|
-
usageLines.push(`${underline(bold("USAGE"))} ${
|
|
473
|
+
usageLines.push(`${underline(bold("USAGE"))} ${cyan2(`${commandName}${hasOptions ? " [OPTIONS]" : ""} ${usageLine.join(" ")}`)}`, "");
|
|
467
474
|
if (posLines.length > 0) {
|
|
468
475
|
usageLines.push(underline(bold("ARGUMENTS")), "");
|
|
469
476
|
usageLines.push(formatLineColumns(posLines, " "));
|
|
@@ -477,7 +484,7 @@ async function renderUsage(cmd, parent) {
|
|
|
477
484
|
if (commandsLines.length > 0) {
|
|
478
485
|
usageLines.push(underline(bold("COMMANDS")), "");
|
|
479
486
|
usageLines.push(formatLineColumns(commandsLines, " "));
|
|
480
|
-
usageLines.push("", `Use ${
|
|
487
|
+
usageLines.push("", `Use ${cyan2(`${commandName} <command> --help`)} for more information about a command.`);
|
|
481
488
|
}
|
|
482
489
|
return usageLines.filter((l) => typeof l === "string").join(`
|
|
483
490
|
`);
|
|
@@ -577,29 +584,6 @@ function removeSkillFromLock(path, skill) {
|
|
|
577
584
|
return { removed: true };
|
|
578
585
|
}
|
|
579
586
|
|
|
580
|
-
// src/utils/ansi.ts
|
|
581
|
-
var enabled = false;
|
|
582
|
-
function setColorEnabled(value) {
|
|
583
|
-
enabled = value;
|
|
584
|
-
}
|
|
585
|
-
function detectColorSupport() {
|
|
586
|
-
if (process.env.NO_COLOR)
|
|
587
|
-
return false;
|
|
588
|
-
return Boolean(process.stdout.isTTY);
|
|
589
|
-
}
|
|
590
|
-
function green(s) {
|
|
591
|
-
return enabled ? `\x1B[32m${s}\x1B[0m` : s;
|
|
592
|
-
}
|
|
593
|
-
function yellow(s) {
|
|
594
|
-
return enabled ? `\x1B[33m${s}\x1B[0m` : s;
|
|
595
|
-
}
|
|
596
|
-
function red(s) {
|
|
597
|
-
return enabled ? `\x1B[31m${s}\x1B[0m` : s;
|
|
598
|
-
}
|
|
599
|
-
function cyan2(s) {
|
|
600
|
-
return enabled ? `\x1B[36m${s}\x1B[0m` : s;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
587
|
// src/utils/discover-skills.ts
|
|
604
588
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, statSync } from "node:fs";
|
|
605
589
|
import { homedir as homedir3 } from "node:os";
|
|
@@ -705,23 +689,28 @@ var costCommand = defineCommand({
|
|
|
705
689
|
const rows = sortRows([...map.values()]);
|
|
706
690
|
const total = rows.reduce((acc, r) => acc + (r.frontmatterTokens ?? 0), 0);
|
|
707
691
|
const { message, paint } = classify(total);
|
|
708
|
-
console.log(args.global ? "Global" : "Local");
|
|
709
692
|
console.log("");
|
|
693
|
+
console.log(args.global ? "Global" : "Local");
|
|
710
694
|
if (rows.length === 0) {
|
|
711
695
|
console.log(`No skills in ${lockPath}`);
|
|
712
696
|
return;
|
|
713
697
|
}
|
|
714
698
|
const nameWidth = Math.max(...rows.map((r) => r.name.length));
|
|
699
|
+
const tokenWidth = Math.max(...rows.map((r) => r.status === "ok" ? `~${r.frontmatterTokens} tok`.length : r.status === "missing" ? "~? tok".length : "(no frontmatter)".length));
|
|
715
700
|
for (const r of rows) {
|
|
716
|
-
let
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
701
|
+
let tokenCell;
|
|
702
|
+
let suffix = "";
|
|
703
|
+
if (r.status === "ok") {
|
|
704
|
+
tokenCell = `~${r.frontmatterTokens} tok`;
|
|
705
|
+
} else if (r.status === "missing") {
|
|
706
|
+
tokenCell = "~? tok";
|
|
707
|
+
suffix = ` ${red("missing")}`;
|
|
708
|
+
} else {
|
|
709
|
+
tokenCell = "(no frontmatter)";
|
|
710
|
+
}
|
|
711
|
+
const namePad = " ".repeat(nameWidth - r.name.length);
|
|
712
|
+
const tokenPad = " ".repeat(Math.max(0, tokenWidth - tokenCell.length));
|
|
713
|
+
console.log(`${cyan(r.name)}${namePad} ${tokenCell}${tokenPad}${suffix}`);
|
|
725
714
|
}
|
|
726
715
|
console.log("");
|
|
727
716
|
console.log(`Total: ~${total} tok across ${rows.length} skills ${paint(message)}`);
|
|
@@ -729,8 +718,6 @@ var costCommand = defineCommand({
|
|
|
729
718
|
});
|
|
730
719
|
|
|
731
720
|
// src/commands/list.ts
|
|
732
|
-
import { existsSync as existsSync4 } from "node:fs";
|
|
733
|
-
import { dirname as dirname4, join as join4, resolve as resolve3 } from "node:path";
|
|
734
721
|
function bySource(records) {
|
|
735
722
|
const claudeNames = records.filter((r) => r.sources.includes(".claude")).map((r) => r.name).sort();
|
|
736
723
|
const agentsNames = records.filter((r) => r.sources.includes(".agents")).map((r) => r.name).sort();
|
|
@@ -757,12 +744,6 @@ function bySource(records) {
|
|
|
757
744
|
}
|
|
758
745
|
};
|
|
759
746
|
}
|
|
760
|
-
function agentsDirExists(isGlobal, lockPath) {
|
|
761
|
-
if (isGlobal) {
|
|
762
|
-
return existsSync4(join4(process.env.HOME ?? "", ".agents", "skills"));
|
|
763
|
-
}
|
|
764
|
-
return existsSync4(join4(dirname4(resolve3(lockPath)), ".agents", "skills"));
|
|
765
|
-
}
|
|
766
747
|
var listCommand = defineCommand({
|
|
767
748
|
meta: { description: "List skills per source with totals and lock-vs-disk diff" },
|
|
768
749
|
args: {
|
|
@@ -773,38 +754,34 @@ var listCommand = defineCommand({
|
|
|
773
754
|
const map = discoverSkills({ isGlobal: args.global, cwd: process.cwd(), lockPath });
|
|
774
755
|
const records = [...map.values()];
|
|
775
756
|
const rows = bySource(records);
|
|
776
|
-
const showAgents = agentsDirExists(args.global, lockPath) || rows.agents.names.length > 0;
|
|
777
757
|
const claudeNames = rows.claude.names;
|
|
778
758
|
const agentsNames = rows.agents.names;
|
|
779
759
|
const lockNames = rows.lock.names;
|
|
780
760
|
const lockOnly = lockNames.filter((n) => !claudeNames.includes(n) && !agentsNames.includes(n));
|
|
781
761
|
const claudeNotInLock = claudeNames.filter((n) => !lockNames.includes(n));
|
|
782
762
|
const agentsNotInLock = agentsNames.filter((n) => !lockNames.includes(n));
|
|
783
|
-
const sourceRows = [rows.claude];
|
|
784
|
-
if (showAgents)
|
|
785
|
-
sourceRows.push(rows.agents);
|
|
786
|
-
sourceRows.push(rows.lock);
|
|
763
|
+
const sourceRows = [rows.claude, rows.agents, rows.lock];
|
|
787
764
|
const labelWidth = Math.max(...sourceRows.map((r) => r.label.length));
|
|
788
|
-
const countCells = sourceRows.map((r) =>
|
|
765
|
+
const countCells = sourceRows.map((r) => `${r.names.length} skill${r.names.length === 1 ? "" : "s"}`);
|
|
789
766
|
const countWidth = Math.max(...countCells.map((c) => c.length));
|
|
790
767
|
for (let i = 0;i < sourceRows.length; i++) {
|
|
791
768
|
const row = sourceRows[i];
|
|
792
769
|
if (!row)
|
|
793
770
|
continue;
|
|
794
771
|
const countCell = countCells[i] ?? "";
|
|
795
|
-
const namesText = row.names.length ? row.names.map(
|
|
772
|
+
const namesText = row.names.length ? row.names.map(cyan).join(" ") : "";
|
|
796
773
|
const line = `${row.label.padEnd(labelWidth)} : ${countCell.padEnd(countWidth)}${namesText ? ` : ${namesText}` : ""}`;
|
|
797
774
|
console.log(line.trimEnd());
|
|
798
775
|
}
|
|
799
776
|
const diffs = [];
|
|
800
777
|
if (lockOnly.length) {
|
|
801
|
-
diffs.push(`skills-lock.json has ${lockOnly.length} skill${lockOnly.length === 1 ? "" : "s"} missing on disk: ${lockOnly.map(
|
|
778
|
+
diffs.push(`skills-lock.json has ${lockOnly.length} skill${lockOnly.length === 1 ? "" : "s"} missing on disk: ${lockOnly.map(cyan).join(", ")}`);
|
|
802
779
|
}
|
|
803
780
|
if (claudeNotInLock.length) {
|
|
804
|
-
diffs.push(`.claude/skills has ${claudeNotInLock.length} skill${claudeNotInLock.length === 1 ? "" : "s"} not in lock: ${claudeNotInLock.map(
|
|
781
|
+
diffs.push(`.claude/skills has ${claudeNotInLock.length} skill${claudeNotInLock.length === 1 ? "" : "s"} not in lock: ${claudeNotInLock.map(cyan).join(", ")}`);
|
|
805
782
|
}
|
|
806
783
|
if (agentsNotInLock.length) {
|
|
807
|
-
diffs.push(`.agents/skills has ${agentsNotInLock.length} skill${agentsNotInLock.length === 1 ? "" : "s"} not in lock: ${agentsNotInLock.map(
|
|
784
|
+
diffs.push(`.agents/skills has ${agentsNotInLock.length} skill${agentsNotInLock.length === 1 ? "" : "s"} not in lock: ${agentsNotInLock.map(cyan).join(", ")}`);
|
|
808
785
|
}
|
|
809
786
|
if (diffs.length) {
|
|
810
787
|
console.log("");
|
|
@@ -815,9 +792,9 @@ var listCommand = defineCommand({
|
|
|
815
792
|
});
|
|
816
793
|
|
|
817
794
|
// src/commands/remove.ts
|
|
818
|
-
import { existsSync as
|
|
795
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
819
796
|
import { homedir as homedir4 } from "node:os";
|
|
820
|
-
import { dirname as dirname5, join as
|
|
797
|
+
import { dirname as dirname5, join as join5, resolve as resolve5 } from "node:path";
|
|
821
798
|
|
|
822
799
|
// src/utils/confirm.ts
|
|
823
800
|
import { createInterface } from "node:readline/promises";
|
|
@@ -837,15 +814,15 @@ async function confirm(question, opts = {}) {
|
|
|
837
814
|
}
|
|
838
815
|
|
|
839
816
|
// src/utils/fs-rm.ts
|
|
840
|
-
import { existsSync as
|
|
841
|
-
import { join as
|
|
817
|
+
import { existsSync as existsSync4, lstatSync, readdirSync as readdirSync2, rmSync } from "node:fs";
|
|
818
|
+
import { join as join4, resolve as resolve3 } from "node:path";
|
|
842
819
|
function isInside(target, root) {
|
|
843
|
-
const t =
|
|
844
|
-
const r =
|
|
820
|
+
const t = resolve3(target);
|
|
821
|
+
const r = resolve3(root);
|
|
845
822
|
return t === r || t.startsWith(`${r}/`);
|
|
846
823
|
}
|
|
847
824
|
function countFiles(path) {
|
|
848
|
-
if (!
|
|
825
|
+
if (!existsSync4(path))
|
|
849
826
|
return 0;
|
|
850
827
|
const stat = lstatSync(path);
|
|
851
828
|
if (stat.isFile())
|
|
@@ -854,7 +831,7 @@ function countFiles(path) {
|
|
|
854
831
|
return 0;
|
|
855
832
|
let n = 0;
|
|
856
833
|
for (const entry of readdirSync2(path)) {
|
|
857
|
-
n += countFiles(
|
|
834
|
+
n += countFiles(join4(path, entry));
|
|
858
835
|
}
|
|
859
836
|
return n;
|
|
860
837
|
}
|
|
@@ -863,22 +840,35 @@ function rmSkillDir(path, opts) {
|
|
|
863
840
|
if (!safe) {
|
|
864
841
|
throw new Error(`Refusing to delete: "${path}" is outside allowed roots`);
|
|
865
842
|
}
|
|
866
|
-
if (!
|
|
843
|
+
if (!existsSync4(path))
|
|
867
844
|
return { removed: false, fileCount: 0 };
|
|
868
845
|
const fileCount = countFiles(path);
|
|
869
846
|
rmSync(path, { recursive: true, force: true });
|
|
870
847
|
return { removed: true, fileCount };
|
|
871
848
|
}
|
|
872
849
|
|
|
850
|
+
// src/utils/git.ts
|
|
851
|
+
import { spawnSync } from "node:child_process";
|
|
852
|
+
import { dirname as dirname4, resolve as resolve4 } from "node:path";
|
|
853
|
+
function isTrackedByGit(path) {
|
|
854
|
+
const abs = resolve4(path);
|
|
855
|
+
const cwd = dirname4(abs);
|
|
856
|
+
const r = spawnSync("git", ["ls-files", "--error-unmatch", abs], {
|
|
857
|
+
cwd,
|
|
858
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
859
|
+
});
|
|
860
|
+
return r.status === 0;
|
|
861
|
+
}
|
|
862
|
+
|
|
873
863
|
// src/commands/remove.ts
|
|
874
|
-
var q = (name) => `"${
|
|
864
|
+
var q = (name) => `"${cyan(name)}"`;
|
|
875
865
|
function buildTarget(name, isGlobal, lockPath) {
|
|
876
866
|
const lock = readLock(lockPath);
|
|
877
867
|
const inLock = Object.hasOwn(lock.skills, name);
|
|
878
|
-
const baseClaude = isGlobal ?
|
|
879
|
-
const baseAgents = isGlobal ?
|
|
880
|
-
const claudeDir =
|
|
881
|
-
const agentsDir =
|
|
868
|
+
const baseClaude = isGlobal ? join5(homedir4(), ".claude", "skills") : join5(dirname5(resolve5(lockPath)), ".claude", "skills");
|
|
869
|
+
const baseAgents = isGlobal ? join5(homedir4(), ".agents", "skills") : join5(dirname5(resolve5(lockPath)), ".agents", "skills");
|
|
870
|
+
const claudeDir = existsSync5(join5(baseClaude, name)) ? join5(baseClaude, name) : undefined;
|
|
871
|
+
const agentsDir = existsSync5(join5(baseAgents, name)) ? join5(baseAgents, name) : undefined;
|
|
882
872
|
return { name, inLock, claudeDir, agentsDir };
|
|
883
873
|
}
|
|
884
874
|
function fileCount(dir) {
|
|
@@ -892,17 +882,21 @@ function fileCount(dir) {
|
|
|
892
882
|
n++;
|
|
893
883
|
else if (stat.isDirectory())
|
|
894
884
|
for (const e of readdirSync3(cur))
|
|
895
|
-
stack.push(
|
|
885
|
+
stack.push(join5(cur, e));
|
|
896
886
|
}
|
|
897
887
|
return n;
|
|
898
888
|
}
|
|
899
|
-
function printPlan(plan) {
|
|
889
|
+
function printPlan(plan, lockTracked) {
|
|
900
890
|
const { target } = plan;
|
|
901
891
|
console.log(`Will remove ${q(target.name)}:`);
|
|
902
|
-
if (target.inLock)
|
|
903
|
-
|
|
904
|
-
|
|
892
|
+
if (target.inLock) {
|
|
893
|
+
if (lockTracked)
|
|
894
|
+
console.log(" - skills-lock.json (skipped: git-tracked; use --force-lock)");
|
|
895
|
+
else
|
|
896
|
+
console.log(" - skills-lock.json");
|
|
897
|
+
} else {
|
|
905
898
|
console.log(" - skills-lock.json (not in lock)");
|
|
899
|
+
}
|
|
906
900
|
if (target.claudeDir)
|
|
907
901
|
console.log(` - .claude/skills/${target.name}/ (${plan.claudeFileCount} files)`);
|
|
908
902
|
else
|
|
@@ -917,10 +911,15 @@ var removeCommand = defineCommand({
|
|
|
917
911
|
args: {
|
|
918
912
|
global: { type: "boolean", alias: "g", default: false, description: "Use global scope" },
|
|
919
913
|
"dry-run": { type: "boolean", default: false, description: "Print plan, do not delete" },
|
|
920
|
-
yes: { type: "boolean", alias: "y", default: false, description: "Skip confirmation prompt" }
|
|
914
|
+
yes: { type: "boolean", alias: "y", default: false, description: "Skip confirmation prompt" },
|
|
915
|
+
"force-lock": {
|
|
916
|
+
type: "boolean",
|
|
917
|
+
default: false,
|
|
918
|
+
description: "Modify skills-lock.json even if it is git-tracked"
|
|
919
|
+
}
|
|
921
920
|
},
|
|
922
921
|
async run({ args }) {
|
|
923
|
-
const { global: isGlobal, "dry-run": dryRun, yes } = args;
|
|
922
|
+
const { global: isGlobal, "dry-run": dryRun, yes, "force-lock": forceLock } = args;
|
|
924
923
|
const subcmdIdx = process.argv.findIndex((a) => a === "remove" || a === "rm");
|
|
925
924
|
const names = process.argv.slice(subcmdIdx + 1).filter((a) => !a.startsWith("-"));
|
|
926
925
|
if (names.length === 0) {
|
|
@@ -940,10 +939,14 @@ var removeCommand = defineCommand({
|
|
|
940
939
|
claudeFileCount: t.claudeDir ? fileCount(t.claudeDir) : undefined,
|
|
941
940
|
agentsFileCount: t.agentsDir ? fileCount(t.agentsDir) : undefined
|
|
942
941
|
}));
|
|
942
|
+
const lockTracked = !forceLock && isTrackedByGit(lockPath);
|
|
943
943
|
for (const p of plans) {
|
|
944
|
-
printPlan(p);
|
|
944
|
+
printPlan(p, lockTracked);
|
|
945
945
|
console.log("");
|
|
946
946
|
}
|
|
947
|
+
if (lockTracked && plans.some((p) => p.target.inLock)) {
|
|
948
|
+
console.error(red("Skipping skills-lock.json (tracked by git; pass --force-lock to override)"));
|
|
949
|
+
}
|
|
947
950
|
if (dryRun)
|
|
948
951
|
return;
|
|
949
952
|
if (!yes) {
|
|
@@ -953,15 +956,16 @@ var removeCommand = defineCommand({
|
|
|
953
956
|
process.exit(1);
|
|
954
957
|
}
|
|
955
958
|
}
|
|
956
|
-
const allowedRoots = [
|
|
957
|
-
isGlobal ? homedir4() : dirname5(resolve5(lockPath)),
|
|
958
|
-
homedir4()
|
|
959
|
-
];
|
|
959
|
+
const allowedRoots = [isGlobal ? homedir4() : dirname5(resolve5(lockPath)), homedir4()];
|
|
960
960
|
for (const { target } of plans) {
|
|
961
961
|
if (target.inLock) {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
962
|
+
if (lockTracked) {
|
|
963
|
+
console.log(`Skipped skills-lock.json (git-tracked) for ${q(target.name)}`);
|
|
964
|
+
} else {
|
|
965
|
+
const r = removeSkillFromLock(lockPath, target.name);
|
|
966
|
+
if (r.removed)
|
|
967
|
+
console.log(`Removed ${q(target.name)} from skills-lock.json`);
|
|
968
|
+
}
|
|
965
969
|
} else {
|
|
966
970
|
console.log(`Skipped skills-lock.json (not in lock)`);
|
|
967
971
|
}
|
|
@@ -982,12 +986,91 @@ var removeCommand = defineCommand({
|
|
|
982
986
|
});
|
|
983
987
|
|
|
984
988
|
// src/commands/usage.ts
|
|
985
|
-
import { existsSync as
|
|
986
|
-
import { join as
|
|
989
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
990
|
+
import { join as join9 } from "node:path";
|
|
987
991
|
|
|
988
992
|
// src/readers/claude.ts
|
|
989
993
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
990
994
|
|
|
995
|
+
// src/utils/codex-cmd.ts
|
|
996
|
+
var READ_LIKE = new Set(["cat", "sed", "head", "tail", "bat", "batcat", "less", "more"]);
|
|
997
|
+
var SKILL_PATH_RE = /[^\s'"`]*\/([^\s'"`/]+)\/SKILL\.md/g;
|
|
998
|
+
function stripHeredocs(s) {
|
|
999
|
+
return s.replace(/<<-?\s*['"]?(\w+)['"]?[\s\S]*?\n[\t ]*\1\s*(?:\n|$)/g, "");
|
|
1000
|
+
}
|
|
1001
|
+
function splitTopLevel(s) {
|
|
1002
|
+
const out = [];
|
|
1003
|
+
let buf = "";
|
|
1004
|
+
let i = 0;
|
|
1005
|
+
let inSingle = false;
|
|
1006
|
+
let inDouble = false;
|
|
1007
|
+
let inBacktick = false;
|
|
1008
|
+
while (i < s.length) {
|
|
1009
|
+
const c = s[i];
|
|
1010
|
+
const next = s[i + 1];
|
|
1011
|
+
if (!inDouble && !inBacktick && c === "'") {
|
|
1012
|
+
inSingle = !inSingle;
|
|
1013
|
+
buf += c;
|
|
1014
|
+
i++;
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (!inSingle && !inBacktick && c === '"') {
|
|
1018
|
+
inDouble = !inDouble;
|
|
1019
|
+
buf += c;
|
|
1020
|
+
i++;
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
if (!inSingle && !inDouble && c === "`") {
|
|
1024
|
+
inBacktick = !inBacktick;
|
|
1025
|
+
buf += c;
|
|
1026
|
+
i++;
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
if (!inSingle && !inDouble && !inBacktick) {
|
|
1030
|
+
if (c === "&" && next === "&" || c === "|" && next === "|") {
|
|
1031
|
+
out.push(buf);
|
|
1032
|
+
buf = "";
|
|
1033
|
+
i += 2;
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
if (c === ";" || c === "|") {
|
|
1037
|
+
out.push(buf);
|
|
1038
|
+
buf = "";
|
|
1039
|
+
i++;
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
buf += c;
|
|
1044
|
+
i++;
|
|
1045
|
+
}
|
|
1046
|
+
out.push(buf);
|
|
1047
|
+
return out;
|
|
1048
|
+
}
|
|
1049
|
+
function hasRedirect(segment) {
|
|
1050
|
+
return /(?<![<2])>>?|&>>?/.test(segment);
|
|
1051
|
+
}
|
|
1052
|
+
function extractSkillReadsFromCmd(cmd) {
|
|
1053
|
+
const stripped = stripHeredocs(cmd);
|
|
1054
|
+
const segments = splitTopLevel(stripped);
|
|
1055
|
+
const found = new Set;
|
|
1056
|
+
for (const seg of segments) {
|
|
1057
|
+
if (hasRedirect(seg))
|
|
1058
|
+
continue;
|
|
1059
|
+
const trimmed = seg.trimStart();
|
|
1060
|
+
const firstTokenMatch = trimmed.match(/^(\S+)/);
|
|
1061
|
+
if (!firstTokenMatch)
|
|
1062
|
+
continue;
|
|
1063
|
+
const firstToken = firstTokenMatch[1] ?? "";
|
|
1064
|
+
if (!READ_LIKE.has(firstToken))
|
|
1065
|
+
continue;
|
|
1066
|
+
for (const m of seg.matchAll(SKILL_PATH_RE)) {
|
|
1067
|
+
if (m[1])
|
|
1068
|
+
found.add(m[1]);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
return [...found];
|
|
1072
|
+
}
|
|
1073
|
+
|
|
991
1074
|
// src/utils/walk.ts
|
|
992
1075
|
function walk(value, visit) {
|
|
993
1076
|
visit(value);
|
|
@@ -1061,12 +1144,7 @@ function extractCodexActivations(entry) {
|
|
|
1061
1144
|
const cmd = parsed?.cmd;
|
|
1062
1145
|
if (typeof cmd !== "string")
|
|
1063
1146
|
return [];
|
|
1064
|
-
|
|
1065
|
-
for (const m of cmd.matchAll(/(?:^|['"\s])([^'"\s]+\/SKILL\.md)(?=$|['"\s])/g)) {
|
|
1066
|
-
if (m[1])
|
|
1067
|
-
paths.add(m[1]);
|
|
1068
|
-
}
|
|
1069
|
-
return [...paths].map(skillNameFromPath).filter((s) => s !== null);
|
|
1147
|
+
return extractSkillReadsFromCmd(cmd);
|
|
1070
1148
|
}
|
|
1071
1149
|
return [];
|
|
1072
1150
|
}
|
|
@@ -1113,23 +1191,45 @@ function extractCodexMentions(entry) {
|
|
|
1113
1191
|
return [...seen];
|
|
1114
1192
|
}
|
|
1115
1193
|
|
|
1194
|
+
// src/utils/claude-entry.ts
|
|
1195
|
+
function isUserTurnEntry(entry) {
|
|
1196
|
+
if (typeof entry !== "object" || entry === null)
|
|
1197
|
+
return false;
|
|
1198
|
+
const e = entry;
|
|
1199
|
+
if (e.type !== "user")
|
|
1200
|
+
return false;
|
|
1201
|
+
const msg = e.message;
|
|
1202
|
+
if (!msg || msg.role !== "user")
|
|
1203
|
+
return false;
|
|
1204
|
+
const content = msg.content;
|
|
1205
|
+
if (typeof content === "string")
|
|
1206
|
+
return true;
|
|
1207
|
+
if (!Array.isArray(content))
|
|
1208
|
+
return false;
|
|
1209
|
+
return content.some((c) => {
|
|
1210
|
+
if (typeof c !== "object" || c === null)
|
|
1211
|
+
return false;
|
|
1212
|
+
return c.type === "text";
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1116
1216
|
// src/utils/expand-home.ts
|
|
1117
1217
|
import { homedir as homedir5 } from "node:os";
|
|
1118
|
-
import { join as
|
|
1218
|
+
import { join as join6, resolve as resolve6 } from "node:path";
|
|
1119
1219
|
function expandHome(p) {
|
|
1120
1220
|
if (p === "~")
|
|
1121
1221
|
return homedir5();
|
|
1122
1222
|
if (p.startsWith("~/"))
|
|
1123
|
-
return
|
|
1223
|
+
return join6(homedir5(), p.slice(2));
|
|
1124
1224
|
return resolve6(p);
|
|
1125
1225
|
}
|
|
1126
1226
|
|
|
1127
1227
|
// src/utils/jsonl.ts
|
|
1128
1228
|
import { readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync2 } from "node:fs";
|
|
1129
|
-
import { join as
|
|
1229
|
+
import { join as join7 } from "node:path";
|
|
1130
1230
|
function* findJsonlFiles(dir, since) {
|
|
1131
1231
|
for (const item of readdirSync3(dir, { withFileTypes: true })) {
|
|
1132
|
-
const path =
|
|
1232
|
+
const path = join7(dir, item.name);
|
|
1133
1233
|
if (item.isDirectory()) {
|
|
1134
1234
|
yield* findJsonlFiles(path, since);
|
|
1135
1235
|
} else if (item.isFile() && item.name.endsWith(".jsonl")) {
|
|
@@ -1183,6 +1283,8 @@ function readClaudeUsage(options) {
|
|
|
1183
1283
|
sessionAttr.set(cur, (sessionAttr.get(cur) ?? 0) + 1);
|
|
1184
1284
|
}
|
|
1185
1285
|
prevSkill = cur;
|
|
1286
|
+
} else if (isUserTurnEntry(entry)) {
|
|
1287
|
+
prevSkill = null;
|
|
1186
1288
|
}
|
|
1187
1289
|
}
|
|
1188
1290
|
if (options.mode === "activations" || options.mode === "merged") {
|
|
@@ -1214,12 +1316,12 @@ function readClaudeUsage(options) {
|
|
|
1214
1316
|
}
|
|
1215
1317
|
|
|
1216
1318
|
// src/readers/codex.ts
|
|
1217
|
-
import { existsSync as
|
|
1319
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
|
|
1218
1320
|
|
|
1219
1321
|
// src/utils/scope.ts
|
|
1220
|
-
import { existsSync as
|
|
1322
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
1221
1323
|
import { homedir as homedir6 } from "node:os";
|
|
1222
|
-
import { dirname as dirname6, join as
|
|
1324
|
+
import { dirname as dirname6, join as join8 } from "node:path";
|
|
1223
1325
|
function detectScope(opts) {
|
|
1224
1326
|
const home = opts.home ?? homedir6();
|
|
1225
1327
|
if (opts.global || opts.rootOverride)
|
|
@@ -1239,7 +1341,7 @@ function encodeClaudeProjectDir(absPath) {
|
|
|
1239
1341
|
function findGitRoot(start) {
|
|
1240
1342
|
let dir = start;
|
|
1241
1343
|
while (true) {
|
|
1242
|
-
if (
|
|
1344
|
+
if (existsSync6(join8(dir, ".git")))
|
|
1243
1345
|
return dir;
|
|
1244
1346
|
const parent = dirname6(dir);
|
|
1245
1347
|
if (parent === dir)
|
|
@@ -1312,7 +1414,7 @@ function readCodexMentions(options) {
|
|
|
1312
1414
|
const historyPath = expandHome(options.history ?? "~/.codex/history.jsonl");
|
|
1313
1415
|
const counts = new Map;
|
|
1314
1416
|
let linesRead = 0;
|
|
1315
|
-
if (!
|
|
1417
|
+
if (!existsSync7(historyPath))
|
|
1316
1418
|
return { counts, filesRead: 0, linesRead: 0 };
|
|
1317
1419
|
for (const line of readFileSync6(historyPath, "utf8").split(`
|
|
1318
1420
|
`)) {
|
|
@@ -1364,7 +1466,7 @@ function pad(n, width) {
|
|
|
1364
1466
|
return String(n).padStart(width);
|
|
1365
1467
|
}
|
|
1366
1468
|
function formatUsageRow(row) {
|
|
1367
|
-
return `${pad(row.count, row.countWidth)} ${
|
|
1469
|
+
return `${pad(row.count, row.countWidth)} ${cyan(row.name)}`;
|
|
1368
1470
|
}
|
|
1369
1471
|
function parseAgents(agent) {
|
|
1370
1472
|
if (!agent)
|
|
@@ -1420,8 +1522,8 @@ async function runUsage(args) {
|
|
|
1420
1522
|
cwd: process.cwd()
|
|
1421
1523
|
});
|
|
1422
1524
|
const claudeProjectsRoot = expandHome("~/.claude/projects");
|
|
1423
|
-
const claudeRoot = args.root ?? (scope.projectRoot ?
|
|
1424
|
-
const claudeRootMissing = !args.root && !!scope.projectRoot && !
|
|
1525
|
+
const claudeRoot = args.root ?? (scope.projectRoot ? join9(claudeProjectsRoot, encodeClaudeProjectDir(scope.projectRoot)) : claudeProjectsRoot);
|
|
1526
|
+
const claudeRootMissing = !args.root && !!scope.projectRoot && !existsSync8(claudeRoot);
|
|
1425
1527
|
const lockPath = getLockPath(args.global);
|
|
1426
1528
|
const skillUniverse = discoverSkills({
|
|
1427
1529
|
isGlobal: args.global,
|
|
@@ -1451,7 +1553,7 @@ async function runUsage(args) {
|
|
|
1451
1553
|
stats = { filesRead: result.filesRead, linesRead: result.linesRead };
|
|
1452
1554
|
}
|
|
1453
1555
|
const universeNames = new Set([...skillUniverse.keys(), ...counts.keys()]);
|
|
1454
|
-
const
|
|
1556
|
+
const allRows = [...universeNames].map((name) => {
|
|
1455
1557
|
const rec = skillUniverse.get(name);
|
|
1456
1558
|
return {
|
|
1457
1559
|
name,
|
|
@@ -1460,6 +1562,7 @@ async function runUsage(args) {
|
|
|
1460
1562
|
status: rec?.status ?? "ok"
|
|
1461
1563
|
};
|
|
1462
1564
|
});
|
|
1565
|
+
const rows = allRows.filter((r) => r.count > 0);
|
|
1463
1566
|
rows.sort((a, b) => {
|
|
1464
1567
|
const aOk = a.status === "ok";
|
|
1465
1568
|
const bOk = b.status === "ok";
|
|
@@ -1488,6 +1591,7 @@ async function runUsage(args) {
|
|
|
1488
1591
|
}
|
|
1489
1592
|
const periodLabel = args.since ? `since ${args.since}` : args.period ?? "all";
|
|
1490
1593
|
const scopeHeader = scope.global ? "Global" : "Local";
|
|
1594
|
+
console.log("");
|
|
1491
1595
|
console.log(scopeHeader);
|
|
1492
1596
|
const distinct = new Set;
|
|
1493
1597
|
let grandActivations = 0;
|
|
@@ -1524,12 +1628,12 @@ var usageCommand = defineCommand({
|
|
|
1524
1628
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1525
1629
|
import { get } from "node:https";
|
|
1526
1630
|
import { homedir as homedir7 } from "node:os";
|
|
1527
|
-
import { dirname as dirname7, join as
|
|
1631
|
+
import { dirname as dirname7, join as join10 } from "node:path";
|
|
1528
1632
|
var PKG = "skillio";
|
|
1529
1633
|
var TTL_MS = 24 * 60 * 60 * 1000;
|
|
1530
1634
|
var FETCH_TIMEOUT_MS = 1500;
|
|
1531
1635
|
function getCachePath() {
|
|
1532
|
-
return
|
|
1636
|
+
return join10(homedir7(), ".cache", "skillio", "version.json");
|
|
1533
1637
|
}
|
|
1534
1638
|
function compareVersions(a, b) {
|
|
1535
1639
|
const pa = a.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
@@ -1607,7 +1711,7 @@ Run: npm i -g skillio
|
|
|
1607
1711
|
}
|
|
1608
1712
|
|
|
1609
1713
|
// src/cli.ts
|
|
1610
|
-
var { version } =
|
|
1714
|
+
var { version } = createRequire(import.meta.url)("../package.json");
|
|
1611
1715
|
function mergeAgentArgs(argv) {
|
|
1612
1716
|
const out = [];
|
|
1613
1717
|
const values = [];
|
|
@@ -1739,6 +1843,14 @@ var main = defineCommand({
|
|
|
1739
1843
|
async run({ args }) {
|
|
1740
1844
|
if (hasSubcommand(process.argv))
|
|
1741
1845
|
return;
|
|
1846
|
+
const interactive = process.stdout.isTTY && process.stdin.isTTY;
|
|
1847
|
+
if (interactive) {
|
|
1848
|
+
const { runPicker } = await import("./shared/chunk-eq7h491z.js");
|
|
1849
|
+
const status = await runPicker({
|
|
1850
|
+
global: args.global ?? false
|
|
1851
|
+
});
|
|
1852
|
+
process.exit(status);
|
|
1853
|
+
}
|
|
1742
1854
|
await costCommand.run?.({
|
|
1743
1855
|
args,
|
|
1744
1856
|
cmd: costCommand,
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cyan
|
|
3
|
+
} from "./chunk-s3421yr2.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/picker.ts
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
// src/utils/prompt.ts
|
|
9
|
+
import { emitKeypressEvents } from "node:readline";
|
|
10
|
+
async function select(params) {
|
|
11
|
+
const input = params.input ?? process.stdin;
|
|
12
|
+
const output = params.output ?? process.stdout;
|
|
13
|
+
if (!input.isTTY || !output.isTTY)
|
|
14
|
+
return null;
|
|
15
|
+
let cursor = 0;
|
|
16
|
+
const total = params.options.length;
|
|
17
|
+
function render() {
|
|
18
|
+
output.write(`${params.title}
|
|
19
|
+
`);
|
|
20
|
+
for (let i = 0;i < total; i++) {
|
|
21
|
+
const opt = params.options[i];
|
|
22
|
+
if (!opt)
|
|
23
|
+
continue;
|
|
24
|
+
const marker = i === cursor ? cyan(">") : " ";
|
|
25
|
+
output.write(`${marker} ${opt.label}
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function clear() {
|
|
30
|
+
output.write(`\x1B[${total + 1}A\x1B[J`);
|
|
31
|
+
}
|
|
32
|
+
emitKeypressEvents(input);
|
|
33
|
+
if (input.setRawMode)
|
|
34
|
+
input.setRawMode(true);
|
|
35
|
+
input.resume();
|
|
36
|
+
render();
|
|
37
|
+
return await new Promise((resolve) => {
|
|
38
|
+
const onKey = (_str, key) => {
|
|
39
|
+
if (key.ctrl && key.name === "c") {
|
|
40
|
+
cleanup();
|
|
41
|
+
resolve(null);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (key.name === "escape" || key.name === "q") {
|
|
45
|
+
cleanup();
|
|
46
|
+
resolve(null);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (key.name === "up" && cursor > 0) {
|
|
50
|
+
cursor--;
|
|
51
|
+
clear();
|
|
52
|
+
render();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (key.name === "down" && cursor < total - 1) {
|
|
56
|
+
cursor++;
|
|
57
|
+
clear();
|
|
58
|
+
render();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (key.name === "return") {
|
|
62
|
+
cleanup();
|
|
63
|
+
const chosen = params.options[cursor]?.value ?? null;
|
|
64
|
+
resolve(chosen);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function onSigterm() {
|
|
69
|
+
cleanup();
|
|
70
|
+
resolve(null);
|
|
71
|
+
}
|
|
72
|
+
function cleanup() {
|
|
73
|
+
input.removeListener("keypress", onKey);
|
|
74
|
+
process.removeListener("SIGTERM", onSigterm);
|
|
75
|
+
if (input.setRawMode)
|
|
76
|
+
input.setRawMode(false);
|
|
77
|
+
input.pause();
|
|
78
|
+
}
|
|
79
|
+
process.once("SIGTERM", onSigterm);
|
|
80
|
+
input.on("keypress", onKey);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/commands/picker.ts
|
|
85
|
+
async function runPicker(args) {
|
|
86
|
+
const choice = await select({
|
|
87
|
+
title: "skillio — pick a command",
|
|
88
|
+
options: [
|
|
89
|
+
{ value: "usage", label: "usage — count of skill invocations" },
|
|
90
|
+
{ value: "cost", label: "cost — per-skill ambient tokens" },
|
|
91
|
+
{ value: "list", label: "list — installed skills per source" },
|
|
92
|
+
{ value: "quit", label: "quit" }
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
if (choice === null || choice === "quit")
|
|
96
|
+
return 0;
|
|
97
|
+
const cliPath = process.argv[1];
|
|
98
|
+
if (!cliPath) {
|
|
99
|
+
console.error("skillio: cannot resolve CLI path (process.argv[1] missing)");
|
|
100
|
+
return 1;
|
|
101
|
+
}
|
|
102
|
+
const argv = [choice];
|
|
103
|
+
if (args.global)
|
|
104
|
+
argv.push("-g");
|
|
105
|
+
const r = spawnSync(process.execPath, [cliPath, ...argv], {
|
|
106
|
+
stdio: "inherit",
|
|
107
|
+
env: process.env
|
|
108
|
+
});
|
|
109
|
+
return r.status ?? 0;
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
runPicker
|
|
113
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/utils/ansi.ts
|
|
5
|
+
var enabled = false;
|
|
6
|
+
function setColorEnabled(value) {
|
|
7
|
+
enabled = value;
|
|
8
|
+
}
|
|
9
|
+
function detectColorSupport() {
|
|
10
|
+
if (process.env.NO_COLOR)
|
|
11
|
+
return false;
|
|
12
|
+
return Boolean(process.stdout.isTTY);
|
|
13
|
+
}
|
|
14
|
+
function green(s) {
|
|
15
|
+
return enabled ? `\x1B[32m${s}\x1B[0m` : s;
|
|
16
|
+
}
|
|
17
|
+
function yellow(s) {
|
|
18
|
+
return enabled ? `\x1B[33m${s}\x1B[0m` : s;
|
|
19
|
+
}
|
|
20
|
+
function red(s) {
|
|
21
|
+
return enabled ? `\x1B[31m${s}\x1B[0m` : s;
|
|
22
|
+
}
|
|
23
|
+
function cyan(s) {
|
|
24
|
+
return enabled ? `\x1B[36m${s}\x1B[0m` : s;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { __require, setColorEnabled, detectColorSupport, green, yellow, red, cyan };
|