skillio 0.1.13 → 0.1.15
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/README.md +15 -14
- package/dist/cli.js +197 -169
- package/dist/shared/chunk-dwrjph29.js +252 -0
- package/dist/shared/chunk-nkpp3h85.js +153 -0
- package/package.json +1 -1
- package/dist/shared/chunk-2gt0ysd1.js +0 -316
- package/dist/shared/chunk-ajnqh9j9.js +0 -86
package/README.md
CHANGED
|
@@ -78,15 +78,16 @@ skillio # equivalent
|
|
|
78
78
|
# subcommands
|
|
79
79
|
skl ls # list skills per source with diffs
|
|
80
80
|
skl cost # ambient ballast cost (frontmatter tokens) per skill
|
|
81
|
-
skl
|
|
81
|
+
skl cs # alias for cost (also: cst)
|
|
82
82
|
skl usage # consumption: usage count × frontmatter tokens
|
|
83
83
|
skl usg # alias for usage
|
|
84
|
-
skl rm brainstorming #
|
|
85
|
-
skl rm brainstorming writing-plans # remove multiple
|
|
86
|
-
skl rm
|
|
87
|
-
skl rm --yes brainstorming # skip
|
|
88
|
-
skl rm --
|
|
89
|
-
skl rm --
|
|
84
|
+
skl rm brainstorming # colored plan, Proceed? [y/n], then Clean lock? [y/n]
|
|
85
|
+
skl rm brainstorming writing-plans # remove multiple, one pair of prompts
|
|
86
|
+
skl rm . # remove all skills in scope
|
|
87
|
+
skl rm --yes brainstorming # skip both prompts
|
|
88
|
+
skl rm brainstorming --lock-only # only the lock entry (alias --lo)
|
|
89
|
+
skl rm brainstorming --agents-only # only .agents/skills (alias --ao)
|
|
90
|
+
skl rm brainstorming --claude-only # only .claude/skills (alias --co)
|
|
90
91
|
|
|
91
92
|
# scope flags
|
|
92
93
|
skl -g # force global scope on any subcommand
|
|
@@ -158,7 +159,7 @@ skillio list # local skills-lock.json
|
|
|
158
159
|
skillio list --global # ~/.agents/.skill-lock.json
|
|
159
160
|
```
|
|
160
161
|
|
|
161
|
-
### `skillio cost` / `
|
|
162
|
+
### `skillio cost` / `cs`
|
|
162
163
|
|
|
163
164
|
```sh
|
|
164
165
|
skillio cost # local: per-skill frontmatter tokens with verdict
|
|
@@ -168,14 +169,14 @@ skillio cost --global # same, against ~/.agents/.skill-lock.json
|
|
|
168
169
|
### `skillio remove` / `rm`
|
|
169
170
|
|
|
170
171
|
```sh
|
|
171
|
-
skillio remove <skill-name> #
|
|
172
|
+
skillio remove <skill-name> # colored plan/summary, two prompts (disk, then lock)
|
|
172
173
|
skillio remove <skill-one> <skill-two>
|
|
173
|
-
skillio remove
|
|
174
|
-
skillio remove --
|
|
175
|
-
skillio remove --
|
|
174
|
+
skillio remove . # remove all skills in scope
|
|
175
|
+
skillio remove --lock-only <skill-name> # only the lock entry; keep on disk (alias --lo)
|
|
176
|
+
skillio remove --agents-only <skill-name> # only .agents/skills; keep .claude/skills and lock (alias --ao)
|
|
177
|
+
skillio remove --claude-only <skill-name> # only .claude/skills; keep .agents/skills and lock (alias --co)
|
|
176
178
|
skillio remove --global <skill-name>
|
|
177
|
-
skillio remove --
|
|
178
|
-
skillio remove --yes <skill-name> # skip confirmation prompt
|
|
179
|
+
skillio remove --yes <skill-name> # skip both confirmation prompts
|
|
179
180
|
```
|
|
180
181
|
|
|
181
182
|
### Shell completion
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
__require,
|
|
4
|
+
countLockLinesToRemove,
|
|
4
5
|
cyan,
|
|
5
6
|
detectColorSupport,
|
|
6
7
|
discoverSkills,
|
|
7
8
|
getLockPath,
|
|
8
9
|
green,
|
|
9
|
-
promptText,
|
|
10
10
|
readLock,
|
|
11
11
|
red,
|
|
12
12
|
removeSkillFromLock,
|
|
13
13
|
setColorEnabled,
|
|
14
14
|
yellow
|
|
15
|
-
} from "./shared/chunk-
|
|
15
|
+
} from "./shared/chunk-nkpp3h85.js";
|
|
16
16
|
|
|
17
17
|
// src/cli.ts
|
|
18
18
|
import { createRequire } from "node:module";
|
|
@@ -568,7 +568,7 @@ _skillio_completions() {
|
|
|
568
568
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
569
569
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
570
570
|
|
|
571
|
-
local cmds="list ls remove rm cost
|
|
571
|
+
local cmds="list ls remove rm cost cs cst usage us usg completion"
|
|
572
572
|
if [ "\${COMP_CWORD}" -eq 1 ]; then
|
|
573
573
|
COMPREPLY=( $(compgen -W "\${cmds} -h --help -v --version" -- "\${cur}") )
|
|
574
574
|
return 0
|
|
@@ -578,7 +578,7 @@ _skillio_completions() {
|
|
|
578
578
|
case "\${sub}" in
|
|
579
579
|
rm|remove)
|
|
580
580
|
if [[ "\${cur}" == -* ]]; then
|
|
581
|
-
COMPREPLY=( $(compgen -W "-g --global --
|
|
581
|
+
COMPREPLY=( $(compgen -W "-g --global -y --yes --lock-only --lo --agents-only --ao --claude-only --co -h --help" -- "\${cur}") )
|
|
582
582
|
else
|
|
583
583
|
local names
|
|
584
584
|
local scope=""
|
|
@@ -609,7 +609,7 @@ _skillio() {
|
|
|
609
609
|
'remove:Delete on-disk skill dirs'
|
|
610
610
|
'rm:Alias for remove'
|
|
611
611
|
'cost:Show ambient ballast cost'
|
|
612
|
-
'
|
|
612
|
+
'cs:Alias for cost'
|
|
613
613
|
'cst:Alias for cost'
|
|
614
614
|
'usage:Show skill usage'
|
|
615
615
|
'us:Alias for usage'
|
|
@@ -626,11 +626,10 @@ _skillio() {
|
|
|
626
626
|
if [[ \${words[CURRENT]} == -* ]]; then
|
|
627
627
|
_values 'flag' \\
|
|
628
628
|
'-g[global scope]' '--global[global scope]' \\
|
|
629
|
-
'--all[remove every skill in scope]' \\
|
|
630
|
-
'--dry-run[print plan without deleting]' \\
|
|
631
629
|
'-y[skip confirmation]' '--yes[skip confirmation]' \\
|
|
632
|
-
'--
|
|
633
|
-
'--
|
|
630
|
+
'--lock-only[only remove lock entry]' '--lo[alias for --lock-only]' \\
|
|
631
|
+
'--agents-only[only remove from .agents/skills]' '--ao[alias for --agents-only]' \\
|
|
632
|
+
'--claude-only[only remove from .claude/skills]' '--co[alias for --claude-only]'
|
|
634
633
|
else
|
|
635
634
|
local scope=""
|
|
636
635
|
for w in \${words[@]}; do
|
|
@@ -671,18 +670,20 @@ function __skillio_using_subcommand
|
|
|
671
670
|
test "$cmd[2]" = "$argv[1]"
|
|
672
671
|
end
|
|
673
672
|
|
|
674
|
-
complete -c skl -n __skillio_needs_command -a 'list ls remove rm cost
|
|
675
|
-
complete -c skillio -n __skillio_needs_command -a 'list ls remove rm cost
|
|
673
|
+
complete -c skl -n __skillio_needs_command -a 'list ls remove rm cost cs cst usage us usg completion'
|
|
674
|
+
complete -c skillio -n __skillio_needs_command -a 'list ls remove rm cost cs cst usage us usg completion'
|
|
676
675
|
|
|
677
676
|
for sub in rm remove
|
|
678
677
|
complete -c skl -n "__skillio_using_subcommand $sub" -f -a '(__skillio_skill_names)'
|
|
679
678
|
complete -c skillio -n "__skillio_using_subcommand $sub" -f -a '(__skillio_skill_names)'
|
|
680
679
|
complete -c skl -n "__skillio_using_subcommand $sub" -s g -l global -d 'Use global scope'
|
|
681
|
-
complete -c skl -n "__skillio_using_subcommand $sub" -l all -d 'Remove every skill in scope'
|
|
682
|
-
complete -c skl -n "__skillio_using_subcommand $sub" -l dry-run -d 'Print plan without deleting'
|
|
683
680
|
complete -c skl -n "__skillio_using_subcommand $sub" -s y -l yes -d 'Skip confirmation prompt'
|
|
684
|
-
complete -c skl -n "__skillio_using_subcommand $sub" -l
|
|
685
|
-
complete -c skl -n "__skillio_using_subcommand $sub" -l
|
|
681
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l lock-only -d 'Only remove lock entry'
|
|
682
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l lo -d 'Alias for --lock-only'
|
|
683
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l agents-only -d 'Only remove from .agents/skills'
|
|
684
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l ao -d 'Alias for --agents-only'
|
|
685
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l claude-only -d 'Only remove from .claude/skills'
|
|
686
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l co -d 'Alias for --claude-only'
|
|
686
687
|
end
|
|
687
688
|
|
|
688
689
|
for sub in completion
|
|
@@ -881,13 +882,9 @@ var listCommand = defineCommand({
|
|
|
881
882
|
const claudeNames = rows.claude.names.map((n) => n.name);
|
|
882
883
|
const agentsNames = rows.agents.names.map((n) => n.name);
|
|
883
884
|
const lockNames = rows.lock.names.map((n) => n.name);
|
|
884
|
-
const lockOnly = lockNames.filter((n) => !claudeNames.includes(n) && !agentsNames.includes(n));
|
|
885
885
|
const claudeNotInLock = claudeNames.filter((n) => !lockNames.includes(n));
|
|
886
886
|
const agentsNotInLock = agentsNames.filter((n) => !lockNames.includes(n));
|
|
887
887
|
const diffs = [];
|
|
888
|
-
if (lockOnly.length) {
|
|
889
|
-
diffs.push(`skills-lock.json has ${lockOnly.length} skill${lockOnly.length === 1 ? "" : "s"} missing on disk: ${lockOnly.map(cyan).join(", ")}`);
|
|
890
|
-
}
|
|
891
888
|
if (claudeNotInLock.length) {
|
|
892
889
|
diffs.push(`.claude/skills has ${claudeNotInLock.length} skill${claudeNotInLock.length === 1 ? "" : "s"} not in lock: ${claudeNotInLock.map(cyan).join(", ")}`);
|
|
893
890
|
}
|
|
@@ -903,7 +900,7 @@ var listCommand = defineCommand({
|
|
|
903
900
|
});
|
|
904
901
|
|
|
905
902
|
// src/commands/remove.ts
|
|
906
|
-
import { existsSync as existsSync3 } from "node:fs";
|
|
903
|
+
import { existsSync as existsSync3, lstatSync as lstatSync3 } from "node:fs";
|
|
907
904
|
import { homedir as homedir2 } from "node:os";
|
|
908
905
|
import { dirname as dirname2, join as join3, resolve as resolve3 } from "node:path";
|
|
909
906
|
|
|
@@ -916,13 +913,13 @@ async function confirm(question, opts = {}) {
|
|
|
916
913
|
const { createInterface } = await import("node:readline/promises");
|
|
917
914
|
const rl = createInterface({ input, output });
|
|
918
915
|
try {
|
|
919
|
-
const answer = (await rl.question(`${question} [y/
|
|
916
|
+
const answer = (await rl.question(`${question} [y/n] `)).trim().toLowerCase();
|
|
920
917
|
return answer === "y" || answer === "yes";
|
|
921
918
|
} finally {
|
|
922
919
|
rl.close();
|
|
923
920
|
}
|
|
924
921
|
}
|
|
925
|
-
output.write(`${question} [y/
|
|
922
|
+
output.write(`${question} [y/n] `);
|
|
926
923
|
emitKeypressEvents(input);
|
|
927
924
|
if (input.setRawMode)
|
|
928
925
|
input.setRawMode(true);
|
|
@@ -969,6 +966,26 @@ async function confirm(question, opts = {}) {
|
|
|
969
966
|
input.on("keypress", onKey);
|
|
970
967
|
});
|
|
971
968
|
}
|
|
969
|
+
function createConfirmer(opts = {}) {
|
|
970
|
+
const input = opts.input ?? process.stdin;
|
|
971
|
+
const output = opts.output ?? process.stdout;
|
|
972
|
+
if (input.isTTY && output.isTTY) {
|
|
973
|
+
return (question) => confirm(question, { input, output });
|
|
974
|
+
}
|
|
975
|
+
let queue;
|
|
976
|
+
return async (question) => {
|
|
977
|
+
if (queue === undefined) {
|
|
978
|
+
let raw = "";
|
|
979
|
+
for await (const chunk of input)
|
|
980
|
+
raw += chunk;
|
|
981
|
+
queue = raw.split(`
|
|
982
|
+
`);
|
|
983
|
+
}
|
|
984
|
+
output.write(`${question} [y/n] `);
|
|
985
|
+
const line = (queue.shift() ?? "").trim().toLowerCase();
|
|
986
|
+
return line === "y" || line === "yes";
|
|
987
|
+
};
|
|
988
|
+
}
|
|
972
989
|
|
|
973
990
|
// src/utils/fs-rm.ts
|
|
974
991
|
import { existsSync as existsSync2, lstatSync as lstatSync2, readdirSync, rmSync } from "node:fs";
|
|
@@ -992,6 +1009,21 @@ function countFiles(path) {
|
|
|
992
1009
|
}
|
|
993
1010
|
return n;
|
|
994
1011
|
}
|
|
1012
|
+
function countFoldersAndFiles(dir) {
|
|
1013
|
+
let folders = 0;
|
|
1014
|
+
let files = 0;
|
|
1015
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1016
|
+
if (entry.isDirectory()) {
|
|
1017
|
+
folders++;
|
|
1018
|
+
const nested = countFoldersAndFiles(join2(dir, entry.name));
|
|
1019
|
+
folders += nested.folders;
|
|
1020
|
+
files += nested.files;
|
|
1021
|
+
} else {
|
|
1022
|
+
files++;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return { folders, files };
|
|
1026
|
+
}
|
|
995
1027
|
function rmSkillDir(path, opts) {
|
|
996
1028
|
const safe = opts.allowedRoots.some((root) => isInside(path, root));
|
|
997
1029
|
if (!safe) {
|
|
@@ -1005,103 +1037,136 @@ function rmSkillDir(path, opts) {
|
|
|
1005
1037
|
}
|
|
1006
1038
|
|
|
1007
1039
|
// src/commands/remove.ts
|
|
1008
|
-
|
|
1040
|
+
function buildLocation(dir) {
|
|
1041
|
+
if (!existsSync3(dir))
|
|
1042
|
+
return { kind: "missing", folders: 0, files: 0 };
|
|
1043
|
+
if (lstatSync3(dir).isSymbolicLink())
|
|
1044
|
+
return { kind: "symlink", folders: 0, files: 0 };
|
|
1045
|
+
const { folders, files } = countFoldersAndFiles(dir);
|
|
1046
|
+
return { kind: "real", folders, files };
|
|
1047
|
+
}
|
|
1048
|
+
function rootFor2(base, isGlobal, lockPath) {
|
|
1049
|
+
return isGlobal ? join3(homedir2(), base, "skills") : join3(dirname2(resolve3(lockPath)), base, "skills");
|
|
1050
|
+
}
|
|
1009
1051
|
function buildTarget(name, isGlobal, lockPath) {
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1052
|
+
const agentsDir = join3(rootFor2(".agents", isGlobal, lockPath), name);
|
|
1053
|
+
const claudeDir = join3(rootFor2(".claude", isGlobal, lockPath), name);
|
|
1054
|
+
return {
|
|
1055
|
+
name,
|
|
1056
|
+
agentsDir,
|
|
1057
|
+
claudeDir,
|
|
1058
|
+
agents: buildLocation(agentsDir),
|
|
1059
|
+
claude: buildLocation(claudeDir)
|
|
1060
|
+
};
|
|
1017
1061
|
}
|
|
1018
1062
|
function collectAllTargets(isGlobal, lockPath) {
|
|
1019
1063
|
const map = discoverSkills({ isGlobal, cwd: process.cwd(), lockPath });
|
|
1020
1064
|
return [...map.keys()].sort().map((name) => buildTarget(name, isGlobal, lockPath));
|
|
1021
1065
|
}
|
|
1022
|
-
function
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1066
|
+
function plural(n, word) {
|
|
1067
|
+
return `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
1068
|
+
}
|
|
1069
|
+
function header(targets, verb) {
|
|
1070
|
+
const names = targets.map((t) => red(t.name)).join(" ");
|
|
1071
|
+
return `${plural(targets.length, "skill")} ${names} ${verb}`;
|
|
1072
|
+
}
|
|
1073
|
+
function aggregateLocations(infos) {
|
|
1074
|
+
let folders = 0;
|
|
1075
|
+
let files = 0;
|
|
1076
|
+
let symlinks = 0;
|
|
1077
|
+
for (const info of infos) {
|
|
1078
|
+
if (info.kind === "real") {
|
|
1079
|
+
folders += info.folders;
|
|
1080
|
+
files += info.files;
|
|
1081
|
+
} else if (info.kind === "symlink") {
|
|
1082
|
+
symlinks += 1;
|
|
1083
|
+
}
|
|
1034
1084
|
}
|
|
1035
|
-
return
|
|
1085
|
+
return { folders, files, symlinks, found: infos.some((i) => i.kind !== "missing") };
|
|
1036
1086
|
}
|
|
1037
|
-
function
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1040
|
-
if (
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1087
|
+
function diskLine(label, singleName, infos, variant) {
|
|
1088
|
+
const displayLabel = singleName ? `${label}/${singleName}/` : label;
|
|
1089
|
+
const agg = aggregateLocations(infos);
|
|
1090
|
+
if (!agg.found)
|
|
1091
|
+
return ` ${displayLabel} (not found)`;
|
|
1092
|
+
const parts = [];
|
|
1093
|
+
if (agg.folders > 0 || agg.files > 0) {
|
|
1094
|
+
const text = `${plural(agg.folders, "folder")}, ${plural(agg.files, "file")}`;
|
|
1095
|
+
parts.push(variant === "summary" ? red(text) : green(text));
|
|
1096
|
+
}
|
|
1097
|
+
if (agg.symlinks > 0) {
|
|
1098
|
+
const text = plural(agg.symlinks, "symlink");
|
|
1099
|
+
parts.push(variant === "summary" ? red(text) : yellow(text));
|
|
1100
|
+
}
|
|
1101
|
+
return ` ${displayLabel} (${parts.join(", ")})`;
|
|
1102
|
+
}
|
|
1103
|
+
function lockLine(n, variant) {
|
|
1104
|
+
const label = "skills-lock.json";
|
|
1105
|
+
if (n === 0)
|
|
1106
|
+
return ` ${label} (not in lock)`;
|
|
1107
|
+
if (variant === "kept")
|
|
1108
|
+
return ` ${green(`${label} (${plural(n, "line")} kept)`)}`;
|
|
1109
|
+
return ` ${red(`${label} (${plural(n, "line")})`)}`;
|
|
1110
|
+
}
|
|
1111
|
+
function printBlock(targets, scope, verb, lockLinesToRemove, diskVariant, lockVariant) {
|
|
1112
|
+
console.log(header(targets, verb));
|
|
1113
|
+
const singleName = targets.length === 1 ? targets[0]?.name : undefined;
|
|
1114
|
+
if (scope === "all" || scope === "agents-only") {
|
|
1115
|
+
console.log(diskLine(".agents/skills", singleName, targets.map((t) => t.agents), diskVariant));
|
|
1116
|
+
}
|
|
1117
|
+
if (scope === "all" || scope === "claude-only") {
|
|
1118
|
+
console.log(diskLine(".claude/skills", singleName, targets.map((t) => t.claude), diskVariant));
|
|
1119
|
+
}
|
|
1120
|
+
if (scope === "all" || scope === "lock-only") {
|
|
1121
|
+
console.log(lockLine(lockLinesToRemove, lockVariant));
|
|
1058
1122
|
}
|
|
1059
|
-
if (target.claudeDir)
|
|
1060
|
-
console.log(` - .claude/skills/${target.name}/ (${plan.claudeFileCount} files)`);
|
|
1061
|
-
else
|
|
1062
|
-
console.log(" - .claude/skills/ (not found)");
|
|
1063
|
-
if (target.agentsDir)
|
|
1064
|
-
console.log(` - .agents/skills/${target.name}/ (${plan.agentsFileCount} files)`);
|
|
1065
|
-
else
|
|
1066
|
-
console.log(" - .agents/skills/ (not found)");
|
|
1067
1123
|
}
|
|
1068
1124
|
var removeCommand = defineCommand({
|
|
1069
1125
|
meta: {
|
|
1070
|
-
description: "Remove one or more skills from on-disk dirs
|
|
1126
|
+
description: "Remove one or more skills from on-disk dirs and/or skills-lock.json"
|
|
1071
1127
|
},
|
|
1072
1128
|
args: {
|
|
1073
1129
|
global: { type: "boolean", alias: "g", default: false, description: "Use global scope" },
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
all: { type: "boolean", default: false, description: "Remove every skill in scope" },
|
|
1077
|
-
"force-lock": {
|
|
1130
|
+
yes: { type: "boolean", alias: "y", default: false, description: "Skip confirmation prompts" },
|
|
1131
|
+
"lock-only": {
|
|
1078
1132
|
type: "boolean",
|
|
1133
|
+
alias: "lo",
|
|
1079
1134
|
default: false,
|
|
1080
|
-
description: "
|
|
1135
|
+
description: "Only remove the skills-lock.json entry; keep on-disk directories"
|
|
1081
1136
|
},
|
|
1082
|
-
"
|
|
1137
|
+
"agents-only": {
|
|
1083
1138
|
type: "boolean",
|
|
1139
|
+
alias: "ao",
|
|
1084
1140
|
default: false,
|
|
1085
|
-
description: "
|
|
1141
|
+
description: "Only remove from .agents/skills; keep .claude/skills and the lock entry"
|
|
1142
|
+
},
|
|
1143
|
+
"claude-only": {
|
|
1144
|
+
type: "boolean",
|
|
1145
|
+
alias: "co",
|
|
1146
|
+
default: false,
|
|
1147
|
+
description: "Only remove from .claude/skills; keep .agents/skills and the lock entry"
|
|
1086
1148
|
}
|
|
1087
1149
|
},
|
|
1088
1150
|
async run({ args }) {
|
|
1089
1151
|
const {
|
|
1090
1152
|
global: isGlobal,
|
|
1091
|
-
"dry-run": dryRun,
|
|
1092
1153
|
yes,
|
|
1093
|
-
|
|
1094
|
-
"
|
|
1095
|
-
"
|
|
1154
|
+
"lock-only": lockOnly,
|
|
1155
|
+
"agents-only": agentsOnly,
|
|
1156
|
+
"claude-only": claudeOnly
|
|
1096
1157
|
} = args;
|
|
1097
|
-
|
|
1098
|
-
|
|
1158
|
+
const onlyFlagCount = [lockOnly, agentsOnly, claudeOnly].filter(Boolean).length;
|
|
1159
|
+
if (onlyFlagCount > 1) {
|
|
1160
|
+
console.error("--lock-only, --agents-only, and --claude-only are mutually exclusive");
|
|
1099
1161
|
process.exit(1);
|
|
1100
1162
|
}
|
|
1163
|
+
const scope = lockOnly ? "lock-only" : agentsOnly ? "agents-only" : claudeOnly ? "claude-only" : "all";
|
|
1101
1164
|
const subcmdIdx = process.argv.findIndex((a) => a === "remove" || a === "rm");
|
|
1102
|
-
const
|
|
1165
|
+
const rawNames = process.argv.slice(subcmdIdx + 1).filter((a) => !a.startsWith("-"));
|
|
1166
|
+
const all = rawNames.includes(".");
|
|
1167
|
+
const names = rawNames.filter((n) => n !== ".");
|
|
1103
1168
|
if (all && names.length > 0) {
|
|
1104
|
-
console.error("
|
|
1169
|
+
console.error('"." (all skills) is mutually exclusive with positional skill names');
|
|
1105
1170
|
process.exit(1);
|
|
1106
1171
|
}
|
|
1107
1172
|
if (!all && names.length === 0) {
|
|
@@ -1114,83 +1179,47 @@ var removeCommand = defineCommand({
|
|
|
1114
1179
|
console.log("No skills to remove in scope.");
|
|
1115
1180
|
return;
|
|
1116
1181
|
}
|
|
1117
|
-
const
|
|
1182
|
+
const lockNames = new Set(Object.keys(readLock(lockPath).skills));
|
|
1183
|
+
const orphan = targets.filter((t) => t.agents.kind === "missing" && t.claude.kind === "missing" && !lockNames.has(t.name));
|
|
1118
1184
|
if (orphan.length) {
|
|
1119
1185
|
for (const o of orphan)
|
|
1120
|
-
console.log(
|
|
1186
|
+
console.log(`"${o.name}" is not in lock or on disk`);
|
|
1121
1187
|
process.exit(1);
|
|
1122
1188
|
}
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
for (const p of plans) {
|
|
1129
|
-
printPlan(p, modifyLock, lockOnly);
|
|
1130
|
-
console.log("");
|
|
1131
|
-
}
|
|
1132
|
-
if (dryRun)
|
|
1133
|
-
return;
|
|
1134
|
-
if (all) {
|
|
1135
|
-
const subject = lockOnly ? `ALL ${plans.length} lock entries (disk preserved)` : `ALL ${plans.length} skills`;
|
|
1136
|
-
const interactive = process.stdin.isTTY && process.stdout.isTTY;
|
|
1137
|
-
if (interactive) {
|
|
1138
|
-
const phrase = await promptText(`This will remove ${subject}. Type "all" to confirm:`);
|
|
1139
|
-
if (phrase !== "all") {
|
|
1140
|
-
console.log("Aborted");
|
|
1141
|
-
process.exit(1);
|
|
1142
|
-
}
|
|
1143
|
-
} else if (!yes) {
|
|
1144
|
-
const ok = await confirm(`Remove ${subject}?`);
|
|
1145
|
-
if (!ok) {
|
|
1146
|
-
console.log("Aborted");
|
|
1147
|
-
process.exit(1);
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
} else if (!yes) {
|
|
1151
|
-
const ok = await confirm("Proceed?");
|
|
1189
|
+
const lockLinesToRemove = countLockLinesToRemove(lockPath, targets.map((t) => t.name));
|
|
1190
|
+
printBlock(targets, scope, "will be removed from:", lockLinesToRemove, "plan", "removed");
|
|
1191
|
+
const ask = createConfirmer();
|
|
1192
|
+
if (!yes) {
|
|
1193
|
+
const ok = await ask("Proceed?");
|
|
1152
1194
|
if (!ok) {
|
|
1153
1195
|
console.log("Aborted");
|
|
1154
1196
|
process.exit(1);
|
|
1155
1197
|
}
|
|
1156
1198
|
}
|
|
1157
1199
|
const allowedRoots = [isGlobal ? homedir2() : dirname2(resolve3(lockPath)), homedir2()];
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
else
|
|
1178
|
-
console.log("Skipped .agents/skills (not found)");
|
|
1179
|
-
continue;
|
|
1180
|
-
}
|
|
1181
|
-
if (target.claudeDir) {
|
|
1182
|
-
const r = rmSkillDir(target.claudeDir, { allowedRoots });
|
|
1183
|
-
console.log(`Removed ${q(target.name)} from .claude/skills (${r.fileCount} files)`);
|
|
1184
|
-
} else {
|
|
1185
|
-
console.log("Skipped .claude/skills (not found)");
|
|
1186
|
-
}
|
|
1187
|
-
if (target.agentsDir) {
|
|
1188
|
-
const r = rmSkillDir(target.agentsDir, { allowedRoots });
|
|
1189
|
-
console.log(`Removed ${q(target.name)} from .agents/skills (${r.fileCount} files)`);
|
|
1190
|
-
} else {
|
|
1191
|
-
console.log("Skipped .agents/skills (not found)");
|
|
1200
|
+
if (scope === "all" || scope === "agents-only") {
|
|
1201
|
+
for (const t of targets)
|
|
1202
|
+
rmSkillDir(t.agentsDir, { allowedRoots });
|
|
1203
|
+
}
|
|
1204
|
+
if (scope === "all" || scope === "claude-only") {
|
|
1205
|
+
for (const t of targets)
|
|
1206
|
+
rmSkillDir(t.claudeDir, { allowedRoots });
|
|
1207
|
+
}
|
|
1208
|
+
let lockCleaned = false;
|
|
1209
|
+
if (scope === "lock-only") {
|
|
1210
|
+
for (const t of targets)
|
|
1211
|
+
removeSkillFromLock(lockPath, t.name);
|
|
1212
|
+
lockCleaned = true;
|
|
1213
|
+
} else if (scope === "all" && lockLinesToRemove > 0) {
|
|
1214
|
+
const cleanLock = yes || await ask(`Clean skills-lock.json (${plural(lockLinesToRemove, "line")})?`);
|
|
1215
|
+
if (cleanLock) {
|
|
1216
|
+
for (const t of targets)
|
|
1217
|
+
removeSkillFromLock(lockPath, t.name);
|
|
1218
|
+
lockCleaned = true;
|
|
1192
1219
|
}
|
|
1193
1220
|
}
|
|
1221
|
+
console.log("");
|
|
1222
|
+
printBlock(targets, scope, "removed from:", lockLinesToRemove, "summary", lockCleaned ? "removed" : "kept");
|
|
1194
1223
|
}
|
|
1195
1224
|
});
|
|
1196
1225
|
|
|
@@ -1962,7 +1991,7 @@ var SUBCOMMAND_NAMES = new Set([
|
|
|
1962
1991
|
"remove",
|
|
1963
1992
|
"rm",
|
|
1964
1993
|
"cost",
|
|
1965
|
-
"
|
|
1994
|
+
"cs",
|
|
1966
1995
|
"cst",
|
|
1967
1996
|
"usage",
|
|
1968
1997
|
"us",
|
|
@@ -1999,8 +2028,8 @@ function printRootHelp() {
|
|
|
1999
2028
|
"COMMANDS",
|
|
2000
2029
|
"",
|
|
2001
2030
|
" list, ls List skills per source: install type, lock orphans, disk/lock diff",
|
|
2002
|
-
" remove, rm Delete on-disk skill dirs
|
|
2003
|
-
" cost,
|
|
2031
|
+
" remove, rm Delete on-disk skill dirs and/or skills-lock.json (interactive)",
|
|
2032
|
+
" cost, cs, cst Show ambient ballast cost (per-skill frontmatter tokens) sorted desc",
|
|
2004
2033
|
" usage, us, usg Show skill usage × cost (consumption) with missed rows",
|
|
2005
2034
|
" completion Print shell completion script (bash, zsh, fish)"
|
|
2006
2035
|
];
|
|
@@ -2023,31 +2052,30 @@ function isRemoveHelp(argv) {
|
|
|
2023
2052
|
}
|
|
2024
2053
|
function printRemoveHelp() {
|
|
2025
2054
|
const lines = [
|
|
2026
|
-
"Remove skills from on-disk dirs
|
|
2055
|
+
"Remove skills from on-disk dirs and/or skills-lock.json.",
|
|
2027
2056
|
"",
|
|
2028
2057
|
"USAGE skillio remove [SKILL...] [OPTIONS]",
|
|
2029
2058
|
" skillio rm [SKILL...] [OPTIONS]",
|
|
2030
2059
|
"",
|
|
2031
2060
|
"ARGUMENTS",
|
|
2032
2061
|
"",
|
|
2033
|
-
|
|
2062
|
+
' SKILL... One or more skill names. Use "." to target every skill in scope.',
|
|
2034
2063
|
"",
|
|
2035
2064
|
"OPTIONS",
|
|
2036
2065
|
"",
|
|
2037
|
-
" -g, --global
|
|
2038
|
-
"
|
|
2039
|
-
" --
|
|
2040
|
-
"
|
|
2041
|
-
" --
|
|
2042
|
-
" --lock-only Remove only the lock entry; keep on-disk directories",
|
|
2066
|
+
" -g, --global Use global scope (default: false)",
|
|
2067
|
+
" -y, --yes Skip confirmation prompts",
|
|
2068
|
+
" --lock-only Only remove the skills-lock.json entry (alias --lo)",
|
|
2069
|
+
" --agents-only Only remove from .agents/skills (alias --ao)",
|
|
2070
|
+
" --claude-only Only remove from .claude/skills (alias --co)",
|
|
2043
2071
|
"",
|
|
2044
2072
|
"EXAMPLES",
|
|
2045
2073
|
"",
|
|
2046
2074
|
" skillio rm brainstorming",
|
|
2047
2075
|
" skillio rm brainstorming writing-plans --yes",
|
|
2048
|
-
" skillio rm
|
|
2049
|
-
" skillio rm --
|
|
2050
|
-
" skillio rm --lock-only
|
|
2076
|
+
" skillio rm .",
|
|
2077
|
+
" skillio rm brainstorming --agents-only",
|
|
2078
|
+
" skillio rm brainstorming --lock-only"
|
|
2051
2079
|
];
|
|
2052
2080
|
console.log(lines.join(`
|
|
2053
2081
|
`));
|
|
@@ -2097,7 +2125,7 @@ var main = defineCommand({
|
|
|
2097
2125
|
return;
|
|
2098
2126
|
const interactive = process.stdout.isTTY && process.stdin.isTTY;
|
|
2099
2127
|
if (interactive) {
|
|
2100
|
-
const { runPicker } = await import("./shared/chunk-
|
|
2128
|
+
const { runPicker } = await import("./shared/chunk-dwrjph29.js");
|
|
2101
2129
|
const status = await runPicker({
|
|
2102
2130
|
global: args.global ?? false
|
|
2103
2131
|
});
|
|
@@ -2115,7 +2143,7 @@ var main = defineCommand({
|
|
|
2115
2143
|
remove: removeCommand,
|
|
2116
2144
|
rm: removeCommand,
|
|
2117
2145
|
cost: costCommand,
|
|
2118
|
-
|
|
2146
|
+
cs: costCommand,
|
|
2119
2147
|
cst: costCommand,
|
|
2120
2148
|
usage: usageCommand,
|
|
2121
2149
|
us: usageCommand,
|