skillio 0.1.11 → 0.1.13
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 +41 -10
- package/dist/cli.js +329 -38
- package/dist/shared/chunk-2gt0ysd1.js +316 -0
- package/dist/shared/chunk-ajnqh9j9.js +86 -0
- package/package.json +3 -1
- package/dist/shared/chunk-0qvp6v8g.js +0 -138
- package/dist/shared/chunk-j9jc4e4c.js +0 -163
package/dist/cli.js
CHANGED
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
discoverSkills,
|
|
7
7
|
getLockPath,
|
|
8
8
|
green,
|
|
9
|
+
promptText,
|
|
9
10
|
readLock,
|
|
10
11
|
red,
|
|
11
12
|
removeSkillFromLock,
|
|
12
13
|
setColorEnabled,
|
|
13
14
|
yellow
|
|
14
|
-
} from "./shared/chunk-
|
|
15
|
+
} from "./shared/chunk-2gt0ysd1.js";
|
|
15
16
|
|
|
16
17
|
// src/cli.ts
|
|
17
18
|
import { createRequire } from "node:module";
|
|
@@ -558,6 +559,167 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
558
559
|
return [`--${long}`, `-${short}`];
|
|
559
560
|
}
|
|
560
561
|
|
|
562
|
+
// src/commands/completion.ts
|
|
563
|
+
var BASH = `# skillio bash completion
|
|
564
|
+
# Install: source <(skl completion bash)
|
|
565
|
+
_skillio_completions() {
|
|
566
|
+
local cur prev words cword
|
|
567
|
+
COMPREPLY=()
|
|
568
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
569
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
570
|
+
|
|
571
|
+
local cmds="list ls remove rm cost co cst usage us usg completion"
|
|
572
|
+
if [ "\${COMP_CWORD}" -eq 1 ]; then
|
|
573
|
+
COMPREPLY=( $(compgen -W "\${cmds} -h --help -v --version" -- "\${cur}") )
|
|
574
|
+
return 0
|
|
575
|
+
fi
|
|
576
|
+
|
|
577
|
+
local sub="\${COMP_WORDS[1]}"
|
|
578
|
+
case "\${sub}" in
|
|
579
|
+
rm|remove)
|
|
580
|
+
if [[ "\${cur}" == -* ]]; then
|
|
581
|
+
COMPREPLY=( $(compgen -W "-g --global --all --dry-run -y --yes --force-lock --lock-only -h --help" -- "\${cur}") )
|
|
582
|
+
else
|
|
583
|
+
local names
|
|
584
|
+
local scope=""
|
|
585
|
+
for w in "\${COMP_WORDS[@]}"; do
|
|
586
|
+
if [ "\${w}" = "-g" ] || [ "\${w}" = "--global" ]; then scope="-g"; fi
|
|
587
|
+
done
|
|
588
|
+
names="$(skl list --names \${scope} 2>/dev/null)"
|
|
589
|
+
COMPREPLY=( $(compgen -W "\${names}" -- "\${cur}") )
|
|
590
|
+
fi
|
|
591
|
+
return 0
|
|
592
|
+
;;
|
|
593
|
+
completion)
|
|
594
|
+
COMPREPLY=( $(compgen -W "bash zsh fish" -- "\${cur}") )
|
|
595
|
+
return 0
|
|
596
|
+
;;
|
|
597
|
+
esac
|
|
598
|
+
}
|
|
599
|
+
complete -F _skillio_completions skl
|
|
600
|
+
complete -F _skillio_completions skillio
|
|
601
|
+
`;
|
|
602
|
+
var ZSH = `# skillio zsh completion
|
|
603
|
+
# Install: source <(skl completion zsh)
|
|
604
|
+
_skillio() {
|
|
605
|
+
local -a cmds
|
|
606
|
+
cmds=(
|
|
607
|
+
'list:List skills per source'
|
|
608
|
+
'ls:Alias for list'
|
|
609
|
+
'remove:Delete on-disk skill dirs'
|
|
610
|
+
'rm:Alias for remove'
|
|
611
|
+
'cost:Show ambient ballast cost'
|
|
612
|
+
'co:Alias for cost'
|
|
613
|
+
'cst:Alias for cost'
|
|
614
|
+
'usage:Show skill usage'
|
|
615
|
+
'us:Alias for usage'
|
|
616
|
+
'usg:Alias for usage'
|
|
617
|
+
'completion:Print shell completion script'
|
|
618
|
+
)
|
|
619
|
+
if (( CURRENT == 2 )); then
|
|
620
|
+
_describe 'command' cmds
|
|
621
|
+
return
|
|
622
|
+
fi
|
|
623
|
+
local sub=\${words[2]}
|
|
624
|
+
case $sub in
|
|
625
|
+
rm|remove)
|
|
626
|
+
if [[ \${words[CURRENT]} == -* ]]; then
|
|
627
|
+
_values 'flag' \\
|
|
628
|
+
'-g[global scope]' '--global[global scope]' \\
|
|
629
|
+
'--all[remove every skill in scope]' \\
|
|
630
|
+
'--dry-run[print plan without deleting]' \\
|
|
631
|
+
'-y[skip confirmation]' '--yes[skip confirmation]' \\
|
|
632
|
+
'--force-lock[also remove lock entry]' \\
|
|
633
|
+
'--lock-only[remove only lock entry, keep disk]'
|
|
634
|
+
else
|
|
635
|
+
local scope=""
|
|
636
|
+
for w in \${words[@]}; do
|
|
637
|
+
if [[ $w == "-g" || $w == "--global" ]]; then scope="-g"; fi
|
|
638
|
+
done
|
|
639
|
+
local -a names
|
|
640
|
+
names=(\${(f)"$(skl list --names $scope 2>/dev/null)"})
|
|
641
|
+
compadd -- $names
|
|
642
|
+
fi
|
|
643
|
+
;;
|
|
644
|
+
completion)
|
|
645
|
+
_values 'shell' bash zsh fish
|
|
646
|
+
;;
|
|
647
|
+
esac
|
|
648
|
+
}
|
|
649
|
+
compdef _skillio skl skillio
|
|
650
|
+
`;
|
|
651
|
+
var FISH = `# skillio fish completion
|
|
652
|
+
# Install: skl completion fish | source
|
|
653
|
+
function __skillio_skill_names
|
|
654
|
+
set -l scope ""
|
|
655
|
+
for w in (commandline -opc)
|
|
656
|
+
if test "$w" = "-g" -o "$w" = "--global"
|
|
657
|
+
set scope "-g"
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
skl list --names $scope 2>/dev/null
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
function __skillio_needs_command
|
|
664
|
+
set -l cmd (commandline -opc)
|
|
665
|
+
test (count $cmd) -le 1
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
function __skillio_using_subcommand
|
|
669
|
+
set -l cmd (commandline -opc)
|
|
670
|
+
if test (count $cmd) -lt 2; return 1; end
|
|
671
|
+
test "$cmd[2]" = "$argv[1]"
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
complete -c skl -n __skillio_needs_command -a 'list ls remove rm cost co cst usage us usg completion'
|
|
675
|
+
complete -c skillio -n __skillio_needs_command -a 'list ls remove rm cost co cst usage us usg completion'
|
|
676
|
+
|
|
677
|
+
for sub in rm remove
|
|
678
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -f -a '(__skillio_skill_names)'
|
|
679
|
+
complete -c skillio -n "__skillio_using_subcommand $sub" -f -a '(__skillio_skill_names)'
|
|
680
|
+
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
|
+
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 force-lock -d 'Also remove lock entry'
|
|
685
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -l lock-only -d 'Remove only lock entry, keep disk'
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
for sub in completion
|
|
689
|
+
complete -c skl -n "__skillio_using_subcommand $sub" -f -a 'bash zsh fish'
|
|
690
|
+
complete -c skillio -n "__skillio_using_subcommand $sub" -f -a 'bash zsh fish'
|
|
691
|
+
end
|
|
692
|
+
`;
|
|
693
|
+
var completionCommand = defineCommand({
|
|
694
|
+
meta: {
|
|
695
|
+
description: "Print shell completion script (bash, zsh, fish)"
|
|
696
|
+
},
|
|
697
|
+
args: {
|
|
698
|
+
shell: {
|
|
699
|
+
type: "positional",
|
|
700
|
+
required: true,
|
|
701
|
+
description: "Target shell: bash, zsh, or fish"
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
run({ args }) {
|
|
705
|
+
const shell = String(args.shell ?? "");
|
|
706
|
+
switch (shell) {
|
|
707
|
+
case "bash":
|
|
708
|
+
process.stdout.write(BASH);
|
|
709
|
+
return;
|
|
710
|
+
case "zsh":
|
|
711
|
+
process.stdout.write(ZSH);
|
|
712
|
+
return;
|
|
713
|
+
case "fish":
|
|
714
|
+
process.stdout.write(FISH);
|
|
715
|
+
return;
|
|
716
|
+
default:
|
|
717
|
+
console.error(`unknown shell: ${shell || "(none)"} — supported: bash, zsh, fish`);
|
|
718
|
+
process.exit(1);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
|
|
561
723
|
// src/commands/cost.ts
|
|
562
724
|
function classify(total) {
|
|
563
725
|
if (total < 1000)
|
|
@@ -608,7 +770,7 @@ var costCommand = defineCommand({
|
|
|
608
770
|
console.log(`${cyan(r.name)}${namePad} ${tokenCell}${tokenPad}${suffix}`);
|
|
609
771
|
}
|
|
610
772
|
console.log("");
|
|
611
|
-
console.log(`Total: ~${total} tok across ${rows.length} skills ${paint(message)}`);
|
|
773
|
+
console.log(`Total: ~${total} tok across ${rows.length} skills ${paint(message)} · method: chars/4, yaml-frontmatter`);
|
|
612
774
|
}
|
|
613
775
|
});
|
|
614
776
|
|
|
@@ -634,7 +796,7 @@ function paintDisk(n) {
|
|
|
634
796
|
return green(n.name);
|
|
635
797
|
return cyan(n.name);
|
|
636
798
|
}
|
|
637
|
-
function bySource(records, roots) {
|
|
799
|
+
function bySource(records, roots, lockLabel) {
|
|
638
800
|
const claudeRecords = records.filter((r) => r.sources.includes(".claude"));
|
|
639
801
|
const agentsRecords = records.filter((r) => r.sources.includes(".agents"));
|
|
640
802
|
const lockRecords = records.filter((r) => r.sources.includes("lock"));
|
|
@@ -644,13 +806,18 @@ function bySource(records, roots) {
|
|
|
644
806
|
return {
|
|
645
807
|
agents: { label: ".agents/skills", names: agentsNames, totalCount: agentsNames.length },
|
|
646
808
|
claude: { label: ".claude/skills", names: claudeNames, totalCount: claudeNames.length },
|
|
647
|
-
lock: { label:
|
|
809
|
+
lock: { label: lockLabel, names: lockNames, totalCount: lockNames.length }
|
|
648
810
|
};
|
|
649
811
|
}
|
|
650
812
|
var listCommand = defineCommand({
|
|
651
813
|
meta: { description: "List skills per source with install-type coloring and lock orphan filter" },
|
|
652
814
|
args: {
|
|
653
|
-
global: { type: "boolean", alias: "g", default: false, description: "Use global scope" }
|
|
815
|
+
global: { type: "boolean", alias: "g", default: false, description: "Use global scope" },
|
|
816
|
+
names: {
|
|
817
|
+
type: "boolean",
|
|
818
|
+
default: false,
|
|
819
|
+
description: "Print one skill name per line (no header, no colors) — for completion scripts"
|
|
820
|
+
}
|
|
654
821
|
},
|
|
655
822
|
run({ args }) {
|
|
656
823
|
const lockPath = getLockPath(args.global);
|
|
@@ -661,7 +828,21 @@ var listCommand = defineCommand({
|
|
|
661
828
|
claude: rootFor(args.global, lockPath, ".claude"),
|
|
662
829
|
agents: rootFor(args.global, lockPath, ".agents")
|
|
663
830
|
};
|
|
664
|
-
const
|
|
831
|
+
const lockLabel = args.global ? ".agents/.skill-lock.json" : "skills-lock.json";
|
|
832
|
+
const rows = bySource(records, roots, lockLabel);
|
|
833
|
+
if (args.names) {
|
|
834
|
+
const all = new Set;
|
|
835
|
+
for (const n of rows.agents.names)
|
|
836
|
+
all.add(n.name);
|
|
837
|
+
for (const n of rows.claude.names)
|
|
838
|
+
all.add(n.name);
|
|
839
|
+
for (const n of rows.lock.names)
|
|
840
|
+
all.add(n.name);
|
|
841
|
+
for (const name of [...all].sort())
|
|
842
|
+
console.log(name);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
console.log(args.global ? "Global" : "Local");
|
|
665
846
|
const claudeSet = new Set(rows.claude.names.map((n) => n.name));
|
|
666
847
|
const agentsSet = new Set(rows.agents.names.map((n) => n.name));
|
|
667
848
|
const orphans = rows.lock.names.filter((n) => !claudeSet.has(n.name) && !agentsSet.has(n.name));
|
|
@@ -676,7 +857,13 @@ var listCommand = defineCommand({
|
|
|
676
857
|
},
|
|
677
858
|
{
|
|
678
859
|
row: rows.lock,
|
|
679
|
-
render: () =>
|
|
860
|
+
render: () => {
|
|
861
|
+
if (rows.lock.totalCount === 0)
|
|
862
|
+
return "";
|
|
863
|
+
if (orphans.length === 0)
|
|
864
|
+
return green("All skills onboard!");
|
|
865
|
+
return orphans.map((n) => red(n.name)).join(" ");
|
|
866
|
+
}
|
|
680
867
|
}
|
|
681
868
|
];
|
|
682
869
|
const labelWidth = Math.max(...sourceRows.map((r) => r.row.label.length));
|
|
@@ -847,17 +1034,28 @@ function fileCount(dir) {
|
|
|
847
1034
|
}
|
|
848
1035
|
return n;
|
|
849
1036
|
}
|
|
850
|
-
function printPlan(plan, modifyLock) {
|
|
1037
|
+
function printPlan(plan, modifyLock, lockOnly) {
|
|
851
1038
|
const { target } = plan;
|
|
852
1039
|
console.log(`Will remove ${q(target.name)}:`);
|
|
853
1040
|
if (target.inLock) {
|
|
854
|
-
if (modifyLock)
|
|
1041
|
+
if (lockOnly || modifyLock)
|
|
855
1042
|
console.log(" - skills-lock.json");
|
|
856
1043
|
else
|
|
857
1044
|
console.log(" - skills-lock.json (kept; use --force-lock to remove lock entry)");
|
|
858
1045
|
} else {
|
|
859
1046
|
console.log(" - skills-lock.json (not in lock)");
|
|
860
1047
|
}
|
|
1048
|
+
if (lockOnly) {
|
|
1049
|
+
if (target.claudeDir)
|
|
1050
|
+
console.log(` - .claude/skills/${target.name}/ (kept; --lock-only)`);
|
|
1051
|
+
else
|
|
1052
|
+
console.log(" - .claude/skills/ (not found)");
|
|
1053
|
+
if (target.agentsDir)
|
|
1054
|
+
console.log(` - .agents/skills/${target.name}/ (kept; --lock-only)`);
|
|
1055
|
+
else
|
|
1056
|
+
console.log(" - .agents/skills/ (not found)");
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
861
1059
|
if (target.claudeDir)
|
|
862
1060
|
console.log(` - .claude/skills/${target.name}/ (${plan.claudeFileCount} files)`);
|
|
863
1061
|
else
|
|
@@ -880,10 +1078,26 @@ var removeCommand = defineCommand({
|
|
|
880
1078
|
type: "boolean",
|
|
881
1079
|
default: false,
|
|
882
1080
|
description: "Also remove entry from skills-lock.json (default is to keep lock untouched)"
|
|
1081
|
+
},
|
|
1082
|
+
"lock-only": {
|
|
1083
|
+
type: "boolean",
|
|
1084
|
+
default: false,
|
|
1085
|
+
description: "Remove only the skills-lock.json entry; keep on-disk directories"
|
|
883
1086
|
}
|
|
884
1087
|
},
|
|
885
1088
|
async run({ args }) {
|
|
886
|
-
const {
|
|
1089
|
+
const {
|
|
1090
|
+
global: isGlobal,
|
|
1091
|
+
"dry-run": dryRun,
|
|
1092
|
+
yes,
|
|
1093
|
+
all,
|
|
1094
|
+
"force-lock": modifyLock,
|
|
1095
|
+
"lock-only": lockOnly
|
|
1096
|
+
} = args;
|
|
1097
|
+
if (lockOnly && modifyLock) {
|
|
1098
|
+
console.error("--lock-only is mutually exclusive with --force-lock");
|
|
1099
|
+
process.exit(1);
|
|
1100
|
+
}
|
|
887
1101
|
const subcmdIdx = process.argv.findIndex((a) => a === "remove" || a === "rm");
|
|
888
1102
|
const names = process.argv.slice(subcmdIdx + 1).filter((a) => !a.startsWith("-"));
|
|
889
1103
|
if (all && names.length > 0) {
|
|
@@ -912,14 +1126,29 @@ var removeCommand = defineCommand({
|
|
|
912
1126
|
agentsFileCount: t.agentsDir ? fileCount(t.agentsDir) : undefined
|
|
913
1127
|
}));
|
|
914
1128
|
for (const p of plans) {
|
|
915
|
-
printPlan(p, modifyLock);
|
|
1129
|
+
printPlan(p, modifyLock, lockOnly);
|
|
916
1130
|
console.log("");
|
|
917
1131
|
}
|
|
918
1132
|
if (dryRun)
|
|
919
1133
|
return;
|
|
920
|
-
if (
|
|
921
|
-
const
|
|
922
|
-
const
|
|
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?");
|
|
923
1152
|
if (!ok) {
|
|
924
1153
|
console.log("Aborted");
|
|
925
1154
|
process.exit(1);
|
|
@@ -928,7 +1157,7 @@ var removeCommand = defineCommand({
|
|
|
928
1157
|
const allowedRoots = [isGlobal ? homedir2() : dirname2(resolve3(lockPath)), homedir2()];
|
|
929
1158
|
for (const { target } of plans) {
|
|
930
1159
|
if (target.inLock) {
|
|
931
|
-
if (modifyLock) {
|
|
1160
|
+
if (lockOnly || modifyLock) {
|
|
932
1161
|
const r = removeSkillFromLock(lockPath, target.name);
|
|
933
1162
|
if (r.removed)
|
|
934
1163
|
console.log(`Removed ${q(target.name)} from skills-lock.json`);
|
|
@@ -938,6 +1167,17 @@ var removeCommand = defineCommand({
|
|
|
938
1167
|
} else {
|
|
939
1168
|
console.log(`Skipped skills-lock.json (not in lock)`);
|
|
940
1169
|
}
|
|
1170
|
+
if (lockOnly) {
|
|
1171
|
+
if (target.claudeDir)
|
|
1172
|
+
console.log(`Kept .claude/skills/${target.name}/ (--lock-only)`);
|
|
1173
|
+
else
|
|
1174
|
+
console.log("Skipped .claude/skills (not found)");
|
|
1175
|
+
if (target.agentsDir)
|
|
1176
|
+
console.log(`Kept .agents/skills/${target.name}/ (--lock-only)`);
|
|
1177
|
+
else
|
|
1178
|
+
console.log("Skipped .agents/skills (not found)");
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
941
1181
|
if (target.claudeDir) {
|
|
942
1182
|
const r = rmSkillDir(target.claudeDir, { allowedRoots });
|
|
943
1183
|
console.log(`Removed ${q(target.name)} from .claude/skills (${r.fileCount} files)`);
|
|
@@ -1138,7 +1378,7 @@ function extractClaudeMentions(entry) {
|
|
|
1138
1378
|
}
|
|
1139
1379
|
for (const m of node.matchAll(/\bsuperpowers:([a-z0-9-]+)\b/g)) {
|
|
1140
1380
|
if (m[1] !== undefined)
|
|
1141
|
-
seen.add(
|
|
1381
|
+
seen.add(m[1]);
|
|
1142
1382
|
}
|
|
1143
1383
|
});
|
|
1144
1384
|
return [...seen];
|
|
@@ -1209,7 +1449,7 @@ function* findJsonlFiles(dir, since) {
|
|
|
1209
1449
|
}
|
|
1210
1450
|
function isRecentEntry(entry, since) {
|
|
1211
1451
|
if (typeof entry !== "object" || entry === null)
|
|
1212
|
-
return
|
|
1452
|
+
return false;
|
|
1213
1453
|
const e = entry;
|
|
1214
1454
|
if (typeof e.timestamp === "string") {
|
|
1215
1455
|
const d = new Date(e.timestamp);
|
|
@@ -1217,7 +1457,7 @@ function isRecentEntry(entry, since) {
|
|
|
1217
1457
|
}
|
|
1218
1458
|
if (typeof e.ts === "number")
|
|
1219
1459
|
return new Date(e.ts * 1000) >= since;
|
|
1220
|
-
return
|
|
1460
|
+
return false;
|
|
1221
1461
|
}
|
|
1222
1462
|
|
|
1223
1463
|
// src/readers/claude.ts
|
|
@@ -1232,6 +1472,7 @@ function readClaudeUsage(options) {
|
|
|
1232
1472
|
let prevSkill = null;
|
|
1233
1473
|
const sessionAttr = new Map;
|
|
1234
1474
|
const sessionAct = new Map;
|
|
1475
|
+
const sessionMen = new Map;
|
|
1235
1476
|
for (const line of readFileSync2(file, "utf8").split(`
|
|
1236
1477
|
`)) {
|
|
1237
1478
|
if (!line.trim())
|
|
@@ -1263,7 +1504,7 @@ function readClaudeUsage(options) {
|
|
|
1263
1504
|
}
|
|
1264
1505
|
if (options.mode === "mentions") {
|
|
1265
1506
|
for (const skill of extractClaudeMentions(entry)) {
|
|
1266
|
-
|
|
1507
|
+
sessionMen.set(skill, (sessionMen.get(skill) ?? 0) + 1);
|
|
1267
1508
|
}
|
|
1268
1509
|
}
|
|
1269
1510
|
}
|
|
@@ -1273,6 +1514,9 @@ function readClaudeUsage(options) {
|
|
|
1273
1514
|
} else if (options.mode === "activations") {
|
|
1274
1515
|
for (const [k, v] of sessionAct)
|
|
1275
1516
|
counts.set(k, (counts.get(k) ?? 0) + v);
|
|
1517
|
+
} else if (options.mode === "mentions") {
|
|
1518
|
+
for (const [k, v] of sessionMen)
|
|
1519
|
+
counts.set(k, (counts.get(k) ?? 0) + v);
|
|
1276
1520
|
} else if (options.mode === "merged") {
|
|
1277
1521
|
const keys = new Set([...sessionAttr.keys(), ...sessionAct.keys()]);
|
|
1278
1522
|
for (const k of keys) {
|
|
@@ -1410,19 +1654,21 @@ var SECOND_MS = 1000;
|
|
|
1410
1654
|
var MINUTE_MS = 60 * SECOND_MS;
|
|
1411
1655
|
var HOUR_MS = 60 * MINUTE_MS;
|
|
1412
1656
|
var DAY_MS = 24 * HOUR_MS;
|
|
1657
|
+
var MONTH_MS = 30 * DAY_MS;
|
|
1413
1658
|
var UNITS_MS = {
|
|
1414
1659
|
s: SECOND_MS,
|
|
1415
1660
|
m: MINUTE_MS,
|
|
1416
1661
|
h: HOUR_MS,
|
|
1417
1662
|
d: DAY_MS,
|
|
1418
|
-
w: 7 * DAY_MS
|
|
1663
|
+
w: 7 * DAY_MS,
|
|
1664
|
+
mo: MONTH_MS
|
|
1419
1665
|
};
|
|
1420
1666
|
function parsePeriod(period) {
|
|
1421
1667
|
if (period === "all")
|
|
1422
1668
|
return Number.POSITIVE_INFINITY;
|
|
1423
|
-
const match = period.match(/^(\d+)([smhdw])$/);
|
|
1669
|
+
const match = period.match(/^(\d+)(mo|[smhdw])$/);
|
|
1424
1670
|
if (!match) {
|
|
1425
|
-
throw new Error(`Invalid period: "${period}". Use values like 60s, 30m, 24h, 30d, 2w, all.`);
|
|
1671
|
+
throw new Error(`Invalid period: "${period}". Use values like 60s, 30m, 24h, 30d, 2w, 6mo, all.`);
|
|
1426
1672
|
}
|
|
1427
1673
|
const unit = UNITS_MS[match[2] ?? ""] ?? 0;
|
|
1428
1674
|
return Number(match[1]) * unit;
|
|
@@ -1433,7 +1679,8 @@ function pad(n, width) {
|
|
|
1433
1679
|
return String(n).padStart(width);
|
|
1434
1680
|
}
|
|
1435
1681
|
function formatUsageRow(row) {
|
|
1436
|
-
|
|
1682
|
+
const suffix = row.installed === false ? ` ${red("(missing)")}` : "";
|
|
1683
|
+
return `${pad(row.count, row.countWidth)} ${cyan(row.name)}${suffix}`;
|
|
1437
1684
|
}
|
|
1438
1685
|
function parseAgents(agent) {
|
|
1439
1686
|
if (!agent)
|
|
@@ -1457,7 +1704,7 @@ var usageArgs = {
|
|
|
1457
1704
|
type: "string",
|
|
1458
1705
|
alias: "p",
|
|
1459
1706
|
default: "all",
|
|
1460
|
-
description: "60s, 30m, 24h, 30d, 2w, all"
|
|
1707
|
+
description: "60s, 30m, 24h, 30d, 2w, 6mo, all"
|
|
1461
1708
|
},
|
|
1462
1709
|
since: { type: "string", description: "yyyy-mm-dd, overrides --period" },
|
|
1463
1710
|
mode: {
|
|
@@ -1526,15 +1773,13 @@ async function runUsage(args) {
|
|
|
1526
1773
|
name,
|
|
1527
1774
|
count: counts.get(name) ?? 0,
|
|
1528
1775
|
tokens: rec?.frontmatterTokens,
|
|
1529
|
-
|
|
1776
|
+
installed: rec !== undefined && rec.status !== "missing"
|
|
1530
1777
|
};
|
|
1531
1778
|
});
|
|
1532
1779
|
const rows = allRows.filter((r) => r.count > 0);
|
|
1533
1780
|
rows.sort((a, b) => {
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
if (aOk !== bOk)
|
|
1537
|
-
return aOk ? -1 : 1;
|
|
1781
|
+
if (a.installed !== b.installed)
|
|
1782
|
+
return a.installed ? -1 : 1;
|
|
1538
1783
|
if (b.count !== a.count)
|
|
1539
1784
|
return b.count - a.count;
|
|
1540
1785
|
return a.name.localeCompare(b.name);
|
|
@@ -1550,7 +1795,8 @@ async function runUsage(args) {
|
|
|
1550
1795
|
skill: r.name,
|
|
1551
1796
|
count: r.count,
|
|
1552
1797
|
tokensPerSkill: r.tokens ?? null,
|
|
1553
|
-
consumption: (r.tokens ?? 0) * r.count
|
|
1798
|
+
consumption: (r.tokens ?? 0) * r.count,
|
|
1799
|
+
installed: r.installed
|
|
1554
1800
|
}))
|
|
1555
1801
|
}));
|
|
1556
1802
|
console.log(JSON.stringify(output.length === 1 ? output[0] : output, null, 2));
|
|
@@ -1569,7 +1815,7 @@ async function runUsage(args) {
|
|
|
1569
1815
|
continue;
|
|
1570
1816
|
const countWidth = Math.max(...rows.map((r) => String(r.count).length));
|
|
1571
1817
|
for (const r of rows) {
|
|
1572
|
-
console.log(formatUsageRow({ count: r.count, name: r.name, countWidth }));
|
|
1818
|
+
console.log(formatUsageRow({ count: r.count, name: r.name, countWidth, installed: r.installed }));
|
|
1573
1819
|
distinct.add(r.name);
|
|
1574
1820
|
}
|
|
1575
1821
|
grandActivations += activations;
|
|
@@ -1720,7 +1966,8 @@ var SUBCOMMAND_NAMES = new Set([
|
|
|
1720
1966
|
"cst",
|
|
1721
1967
|
"usage",
|
|
1722
1968
|
"us",
|
|
1723
|
-
"usg"
|
|
1969
|
+
"usg",
|
|
1970
|
+
"completion"
|
|
1724
1971
|
]);
|
|
1725
1972
|
function reorderRootFlagsToSubcommand(argv) {
|
|
1726
1973
|
const tail = argv.slice(2);
|
|
@@ -1746,15 +1993,16 @@ function printRootHelp() {
|
|
|
1746
1993
|
" -h, --help Show this help and exit",
|
|
1747
1994
|
" -v, --version Show version and exit",
|
|
1748
1995
|
" -g, --global Use global scope (default: false)",
|
|
1749
|
-
" -p, --period Period for `usage`: 60s, 30m, 24h, 30d, 2w, all (default: all)",
|
|
1996
|
+
" -p, --period Period for `usage`: 60s, 30m, 24h, 30d, 2w, 6mo, all (default: all)",
|
|
1750
1997
|
" -a, --agent Agent for `usage`: claude-code, codex (default: both)",
|
|
1751
1998
|
"",
|
|
1752
1999
|
"COMMANDS",
|
|
1753
2000
|
"",
|
|
1754
|
-
" list, ls List skills per source
|
|
1755
|
-
" remove, rm
|
|
2001
|
+
" list, ls List skills per source: install type, lock orphans, disk/lock diff",
|
|
2002
|
+
" remove, rm Delete on-disk skill dirs; lock kept unless --force-lock",
|
|
1756
2003
|
" cost, co, cst Show ambient ballast cost (per-skill frontmatter tokens) sorted desc",
|
|
1757
|
-
" usage, us, usg Show skill usage × cost (consumption) with missed rows"
|
|
2004
|
+
" usage, us, usg Show skill usage × cost (consumption) with missed rows",
|
|
2005
|
+
" completion Print shell completion script (bash, zsh, fish)"
|
|
1758
2006
|
];
|
|
1759
2007
|
console.log(lines.join(`
|
|
1760
2008
|
`));
|
|
@@ -1766,6 +2014,44 @@ function isRootHelp(argv) {
|
|
|
1766
2014
|
return false;
|
|
1767
2015
|
return args.includes("--help") || args.includes("-h");
|
|
1768
2016
|
}
|
|
2017
|
+
function isRemoveHelp(argv) {
|
|
2018
|
+
const args = argv.slice(2);
|
|
2019
|
+
const first = args[0];
|
|
2020
|
+
if (first !== "remove" && first !== "rm")
|
|
2021
|
+
return false;
|
|
2022
|
+
return args.includes("--help") || args.includes("-h");
|
|
2023
|
+
}
|
|
2024
|
+
function printRemoveHelp() {
|
|
2025
|
+
const lines = [
|
|
2026
|
+
"Remove skills from on-disk dirs (lock preserved unless --force-lock).",
|
|
2027
|
+
"",
|
|
2028
|
+
"USAGE skillio remove [SKILL...] [OPTIONS]",
|
|
2029
|
+
" skillio rm [SKILL...] [OPTIONS]",
|
|
2030
|
+
"",
|
|
2031
|
+
"ARGUMENTS",
|
|
2032
|
+
"",
|
|
2033
|
+
" SKILL... One or more skill names. Use --all to target every skill in scope.",
|
|
2034
|
+
"",
|
|
2035
|
+
"OPTIONS",
|
|
2036
|
+
"",
|
|
2037
|
+
" -g, --global Use global scope (default: false)",
|
|
2038
|
+
" --all Remove every skill in scope (mutually exclusive with SKILL)",
|
|
2039
|
+
" --dry-run Print plan without deleting",
|
|
2040
|
+
" -y, --yes Skip confirmation prompt (non-TTY only for --all)",
|
|
2041
|
+
" --force-lock Also remove entry from skills-lock.json (default: lock preserved)",
|
|
2042
|
+
" --lock-only Remove only the lock entry; keep on-disk directories",
|
|
2043
|
+
"",
|
|
2044
|
+
"EXAMPLES",
|
|
2045
|
+
"",
|
|
2046
|
+
" skillio rm brainstorming",
|
|
2047
|
+
" skillio rm brainstorming writing-plans --yes",
|
|
2048
|
+
" skillio rm --all --dry-run",
|
|
2049
|
+
" skillio rm --force-lock obsolete-skill",
|
|
2050
|
+
" skillio rm --lock-only stale-entry"
|
|
2051
|
+
];
|
|
2052
|
+
console.log(lines.join(`
|
|
2053
|
+
`));
|
|
2054
|
+
}
|
|
1769
2055
|
function firstPositional(argv) {
|
|
1770
2056
|
for (let i = 2;i < argv.length; i++) {
|
|
1771
2057
|
const tok = argv[i];
|
|
@@ -1811,7 +2097,7 @@ var main = defineCommand({
|
|
|
1811
2097
|
return;
|
|
1812
2098
|
const interactive = process.stdout.isTTY && process.stdin.isTTY;
|
|
1813
2099
|
if (interactive) {
|
|
1814
|
-
const { runPicker } = await import("./shared/chunk-
|
|
2100
|
+
const { runPicker } = await import("./shared/chunk-ajnqh9j9.js");
|
|
1815
2101
|
const status = await runPicker({
|
|
1816
2102
|
global: args.global ?? false
|
|
1817
2103
|
});
|
|
@@ -1833,7 +2119,8 @@ var main = defineCommand({
|
|
|
1833
2119
|
cst: costCommand,
|
|
1834
2120
|
usage: usageCommand,
|
|
1835
2121
|
us: usageCommand,
|
|
1836
|
-
usg: usageCommand
|
|
2122
|
+
usg: usageCommand,
|
|
2123
|
+
completion: completionCommand
|
|
1837
2124
|
}
|
|
1838
2125
|
});
|
|
1839
2126
|
(async () => {
|
|
@@ -1841,6 +2128,10 @@ var main = defineCommand({
|
|
|
1841
2128
|
printRootHelp();
|
|
1842
2129
|
return;
|
|
1843
2130
|
}
|
|
2131
|
+
if (isRemoveHelp(process.argv)) {
|
|
2132
|
+
printRemoveHelp();
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
1844
2135
|
if (isRootVersion(process.argv)) {
|
|
1845
2136
|
console.log(version);
|
|
1846
2137
|
return;
|