skillio 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -20
- package/dist/cli.js +168 -51
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -9,29 +9,93 @@ Audit and manage AI agent skills for Claude Code and OpenAI Codex.
|
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
11
|
# one-off (no install needed)
|
|
12
|
-
npx skillio
|
|
13
|
-
pnpm dlx skillio
|
|
12
|
+
npx skillio --agent claude --period 7d
|
|
13
|
+
pnpm dlx skillio --agent codex --period 2w
|
|
14
14
|
|
|
15
|
-
# global install
|
|
16
|
-
npm install -g skillio
|
|
15
|
+
# global install — provides both `skillio` and `skl` commands in $PATH
|
|
16
|
+
npm install -g skillio # recommended
|
|
17
17
|
pnpm add -g skillio
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
### Local install (per-project)
|
|
21
|
+
|
|
22
|
+
If you'd rather pin `skillio` to a single project (e.g. for CI) instead of
|
|
23
|
+
installing globally:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm install -D skillio # adds to devDependencies
|
|
27
|
+
pnpm add -D skillio
|
|
28
|
+
yarn add -D skillio
|
|
29
|
+
bun add -d skillio
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then run via your package manager — both `skillio` and `skl` are exposed:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npx skillio # works from any subdir of the project
|
|
36
|
+
pnpm exec skl # short alias
|
|
37
|
+
yarn skl
|
|
38
|
+
bun x skillio
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
You can also wire it into `package.json` scripts:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"scripts": {
|
|
46
|
+
"audit:skills": "skl"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
…then `npm run audit:skills`.
|
|
52
|
+
|
|
53
|
+
## Updating
|
|
54
|
+
|
|
55
|
+
> Already have `skillio` installed? Get the latest version:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npm install -g skillio@latest # recommended
|
|
59
|
+
pnpm add -g skillio@latest
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If you're on `0.1.3` or older — please upgrade. Newer versions add per-repo
|
|
63
|
+
scoping, the `skl` short alias, and saner defaults (`skillio` with no flags now
|
|
64
|
+
audits both Claude Code and Codex over all time).
|
|
65
|
+
|
|
20
66
|
## Usage
|
|
21
67
|
|
|
22
68
|
```sh
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
69
|
+
# from any repo: scoped to that repo
|
|
70
|
+
skl # both agents, all-time, this repo only
|
|
71
|
+
skl -a claude --period 7d # claude only, last 7 days, this repo
|
|
72
|
+
|
|
73
|
+
# from $HOME (or anywhere with -g): global, all repos on this machine
|
|
74
|
+
cd ~ && skl # auto-global when cwd === $HOME
|
|
75
|
+
skl -g # force global from any repo
|
|
76
|
+
skl --global --period 1m # global, last 30 days
|
|
77
|
+
|
|
78
|
+
skillio … # same binary, longer alias
|
|
79
|
+
skillio -a claude-code codex # both agents (space-separated)
|
|
80
|
+
skillio -a claude -a codex # equivalent: repeated --agent flag
|
|
81
|
+
skillio list # list skills in local skills-lock.json
|
|
82
|
+
skillio list --global # list from ~/.agents/.skill-lock.json
|
|
83
|
+
skillio remove brainstorming # remove skill from lock
|
|
31
84
|
skillio remove brainstorming writing-plans # remove multiple skills
|
|
32
|
-
skillio remove --dry-run brainstorming
|
|
85
|
+
skillio remove --dry-run brainstorming # preview removal
|
|
33
86
|
```
|
|
34
87
|
|
|
88
|
+
### Scope (per-repo vs global)
|
|
89
|
+
|
|
90
|
+
`skillio` / `skl` automatically picks a scope based on your current directory:
|
|
91
|
+
|
|
92
|
+
| where you run it | scope |
|
|
93
|
+
|------------------|-------|
|
|
94
|
+
| inside a git repo | that repo only (data filtered to its path) |
|
|
95
|
+
| in `$HOME` exactly | global — all repos on this machine |
|
|
96
|
+
| anywhere with `-g` / `--global` | global override |
|
|
97
|
+
| with `--root <dir>` | that exact dir, treated as global |
|
|
98
|
+
|
|
35
99
|
## What it does
|
|
36
100
|
|
|
37
101
|
- **Audit skill usage** — parse agent session logs and count which skills were invoked, when, and how often
|
|
@@ -39,23 +103,25 @@ skillio remove --dry-run brainstorming # preview removal
|
|
|
39
103
|
|
|
40
104
|
## Options
|
|
41
105
|
|
|
42
|
-
### `skillio`
|
|
106
|
+
### `skillio` (audit)
|
|
43
107
|
|
|
44
|
-
Audits skill usage from agent session logs.
|
|
108
|
+
Audits skill usage from agent session logs. This is the default operation —
|
|
109
|
+
no subcommand keyword is needed.
|
|
45
110
|
|
|
46
111
|
```sh
|
|
47
112
|
skillio --agent claude --period 7d
|
|
48
|
-
skillio
|
|
113
|
+
skillio --agent codex --mode activations
|
|
49
114
|
```
|
|
50
115
|
|
|
51
116
|
| Flag | Default | Description |
|
|
52
117
|
|------|---------|-------------|
|
|
53
|
-
| `-a, --agent` |
|
|
54
|
-
| `-p, --period` | `
|
|
118
|
+
| `-a, --agent` | both | `claude-code`/`claude`, `codex` — pass both space-separated (`-a claude-code codex`) or repeat the flag (`-a claude -a codex`) |
|
|
119
|
+
| `-p, --period` | `all` | `7d`, `2w`, `1m`, `1y`, `all` |
|
|
55
120
|
| `--since` | — | `yyyy-mm-dd`, overrides `--period` |
|
|
56
|
-
| `--mode` | `attributed` | `attributed` \| `activations` \| `mentions` |
|
|
121
|
+
| `--mode` | `attributed` (claude) / `activations` (codex) | `attributed` \| `activations` \| `mentions` |
|
|
57
122
|
| `--format` | `text` | `text` \| `json` |
|
|
58
|
-
|
|
|
123
|
+
| `-g, --global` | `false` | Force global scope (ignore current directory) |
|
|
124
|
+
| `--root` | — | Override agent sessions directory; implies global |
|
|
59
125
|
| `--scan-all-files` | — | Ignore file mtime, read everything |
|
|
60
126
|
|
|
61
127
|
### Modes
|
package/dist/cli.js
CHANGED
|
@@ -545,6 +545,10 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
545
545
|
return [`--${long}`, `-${short}`];
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
+
// src/commands/audit.ts
|
|
549
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
550
|
+
import { join as join4 } from "node:path";
|
|
551
|
+
|
|
548
552
|
// src/readers/claude.ts
|
|
549
553
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
550
554
|
|
|
@@ -729,7 +733,64 @@ function readClaudeUsage(options) {
|
|
|
729
733
|
}
|
|
730
734
|
|
|
731
735
|
// src/readers/codex.ts
|
|
732
|
-
import { existsSync, readFileSync as readFileSync3 } from "node:fs";
|
|
736
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
737
|
+
|
|
738
|
+
// src/utils/scope.ts
|
|
739
|
+
import { existsSync } from "node:fs";
|
|
740
|
+
import { homedir as homedir2 } from "node:os";
|
|
741
|
+
import { dirname, join as join3 } from "node:path";
|
|
742
|
+
function detectScope(opts) {
|
|
743
|
+
const home = opts.home ?? homedir2();
|
|
744
|
+
if (opts.global || opts.rootOverride)
|
|
745
|
+
return { global: true };
|
|
746
|
+
if (norm(opts.cwd) === norm(home))
|
|
747
|
+
return { global: true };
|
|
748
|
+
return { global: false, projectRoot: findGitRoot(opts.cwd) ?? opts.cwd };
|
|
749
|
+
}
|
|
750
|
+
function isPathInProject(path, projectRoot) {
|
|
751
|
+
const p = norm(path);
|
|
752
|
+
const r = norm(projectRoot);
|
|
753
|
+
return p === r || p.startsWith(`${r}/`);
|
|
754
|
+
}
|
|
755
|
+
function encodeClaudeProjectDir(absPath) {
|
|
756
|
+
return absPath.replaceAll("/", "-");
|
|
757
|
+
}
|
|
758
|
+
function findGitRoot(start) {
|
|
759
|
+
let dir = start;
|
|
760
|
+
while (true) {
|
|
761
|
+
if (existsSync(join3(dir, ".git")))
|
|
762
|
+
return dir;
|
|
763
|
+
const parent = dirname(dir);
|
|
764
|
+
if (parent === dir)
|
|
765
|
+
return;
|
|
766
|
+
dir = parent;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
function norm(p) {
|
|
770
|
+
return p.toLowerCase().replace(/\/+$/, "");
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// src/readers/codex.ts
|
|
774
|
+
function readSessionCwd(file) {
|
|
775
|
+
let head;
|
|
776
|
+
try {
|
|
777
|
+
head = readFileSync3(file, "utf8");
|
|
778
|
+
} catch {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const lines = head.split(`
|
|
782
|
+
`, 30);
|
|
783
|
+
for (const line of lines) {
|
|
784
|
+
if (!line.trim())
|
|
785
|
+
continue;
|
|
786
|
+
try {
|
|
787
|
+
const e = JSON.parse(line);
|
|
788
|
+
if (e.type === "session_meta" && typeof e.payload?.cwd === "string")
|
|
789
|
+
return e.payload.cwd;
|
|
790
|
+
} catch {}
|
|
791
|
+
}
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
733
794
|
function readCodexUsage(options) {
|
|
734
795
|
return options.mode === "mentions" ? readCodexMentions(options) : readCodexActivations(options);
|
|
735
796
|
}
|
|
@@ -740,6 +801,11 @@ function readCodexActivations(options) {
|
|
|
740
801
|
let linesRead = 0;
|
|
741
802
|
const since = options.scanAllFiles ? undefined : options.since;
|
|
742
803
|
for (const file of findJsonlFiles(root, since)) {
|
|
804
|
+
if (options.projectRoot) {
|
|
805
|
+
const sessionCwd = readSessionCwd(file);
|
|
806
|
+
if (!sessionCwd || !isPathInProject(sessionCwd, options.projectRoot))
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
743
809
|
filesRead++;
|
|
744
810
|
for (const line of readFileSync3(file, "utf8").split(`
|
|
745
811
|
`)) {
|
|
@@ -765,7 +831,7 @@ function readCodexMentions(options) {
|
|
|
765
831
|
const historyPath = expandHome(options.history ?? "~/.codex/history.jsonl");
|
|
766
832
|
const counts = new Map;
|
|
767
833
|
let linesRead = 0;
|
|
768
|
-
if (!
|
|
834
|
+
if (!existsSync2(historyPath))
|
|
769
835
|
return { counts, filesRead: 0, linesRead: 0 };
|
|
770
836
|
for (const line of readFileSync3(historyPath, "utf8").split(`
|
|
771
837
|
`)) {
|
|
@@ -791,9 +857,11 @@ function readCodexMentions(options) {
|
|
|
791
857
|
var UNITS = { d: 1, w: 7, m: 30, y: 365 };
|
|
792
858
|
var MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
793
859
|
function parsePeriod(period) {
|
|
860
|
+
if (period === "all")
|
|
861
|
+
return Number.POSITIVE_INFINITY;
|
|
794
862
|
const match = period.match(/^(\d+)([dwmy])$/);
|
|
795
863
|
if (!match)
|
|
796
|
-
throw new Error(`Invalid period: "${period}". Use values like 7d, 2w, 1m, 1y.`);
|
|
864
|
+
throw new Error(`Invalid period: "${period}". Use values like 7d, 2w, 1m, 1y, all.`);
|
|
797
865
|
const unit = UNITS[match[2] ?? ""] ?? 1;
|
|
798
866
|
return Number(match[1]) * unit;
|
|
799
867
|
}
|
|
@@ -801,13 +869,13 @@ function parsePeriod(period) {
|
|
|
801
869
|
// src/commands/audit.ts
|
|
802
870
|
function parseAgents(agent) {
|
|
803
871
|
if (!agent)
|
|
804
|
-
|
|
805
|
-
const normalized = agent.split("
|
|
872
|
+
return ["claude-code", "codex"];
|
|
873
|
+
const normalized = agent.split("\x1F").map((a) => a.trim()).filter(Boolean).map((a) => {
|
|
806
874
|
if (a === "codex")
|
|
807
875
|
return "codex";
|
|
808
876
|
if (["claude", "claude-code", "claudecode"].includes(a))
|
|
809
877
|
return "claude-code";
|
|
810
|
-
throw new Error(`Unknown agent: "${a}". Use "claude-code" or "codex".`);
|
|
878
|
+
throw new Error(`Unknown agent: "${a}". Use "claude-code" or "codex" (space-separated for both: -a claude-code codex).`);
|
|
811
879
|
});
|
|
812
880
|
return [...new Set(normalized)];
|
|
813
881
|
}
|
|
@@ -816,21 +884,26 @@ function toRows(counts) {
|
|
|
816
884
|
}
|
|
817
885
|
async function runAudit(args) {
|
|
818
886
|
const agents = parseAgents(args.agent);
|
|
819
|
-
const
|
|
887
|
+
const allTime = !args.since && args.period === "all";
|
|
888
|
+
const since = args.since ? new Date(`${args.since}T00:00:00`) : args.period === "all" ? new Date(0) : new Date(Date.now() - parsePeriod(args.period) * 24 * 60 * 60 * 1000);
|
|
889
|
+
const scanAllFiles = allTime || args["scan-all-files"];
|
|
820
890
|
if (Number.isNaN(since.getTime())) {
|
|
821
891
|
console.error(`Invalid --since value: ${args.since}`);
|
|
822
892
|
process.exit(1);
|
|
823
893
|
}
|
|
894
|
+
const scope = detectScope({
|
|
895
|
+
global: args.global,
|
|
896
|
+
rootOverride: !!args.root,
|
|
897
|
+
cwd: process.cwd()
|
|
898
|
+
});
|
|
899
|
+
const claudeProjectsRoot = expandHome("~/.claude/projects");
|
|
900
|
+
const claudeRoot = args.root ?? (scope.projectRoot ? join4(claudeProjectsRoot, encodeClaudeProjectDir(scope.projectRoot)) : claudeProjectsRoot);
|
|
901
|
+
const claudeRootMissing = !args.root && !!scope.projectRoot && !existsSync3(claudeRoot);
|
|
824
902
|
const results = [];
|
|
825
903
|
for (const agent of agents) {
|
|
826
904
|
if (agent === "claude-code") {
|
|
827
905
|
const mode = args.mode ?? "attributed";
|
|
828
|
-
const result = readClaudeUsage({
|
|
829
|
-
since,
|
|
830
|
-
mode,
|
|
831
|
-
root: args.root,
|
|
832
|
-
scanAllFiles: args["scan-all-files"]
|
|
833
|
-
});
|
|
906
|
+
const result = claudeRootMissing ? { counts: new Map, filesRead: 0, linesRead: 0 } : readClaudeUsage({ since, mode, root: claudeRoot, scanAllFiles });
|
|
834
907
|
results.push({
|
|
835
908
|
agent,
|
|
836
909
|
mode,
|
|
@@ -843,7 +916,8 @@ async function runAudit(args) {
|
|
|
843
916
|
since,
|
|
844
917
|
mode,
|
|
845
918
|
root: args.root,
|
|
846
|
-
scanAllFiles
|
|
919
|
+
scanAllFiles,
|
|
920
|
+
projectRoot: scope.projectRoot
|
|
847
921
|
});
|
|
848
922
|
results.push({
|
|
849
923
|
agent,
|
|
@@ -863,9 +937,12 @@ async function runAudit(args) {
|
|
|
863
937
|
console.log(JSON.stringify(output.length === 1 ? output[0] : output, null, 2));
|
|
864
938
|
return;
|
|
865
939
|
}
|
|
940
|
+
const sinceLabel = allTime ? "all-time" : `since ${since.toISOString().slice(0, 10)}`;
|
|
941
|
+
const scopeLabel = scope.global ? "global" : scope.projectRoot ?? "global";
|
|
942
|
+
console.log(`Scope: ${scopeLabel}${scope.global ? "" : " (use -g for global)"}`);
|
|
866
943
|
for (const { agent, mode, rows, stats } of results) {
|
|
867
944
|
console.log(`
|
|
868
|
-
${agent} skill usage
|
|
945
|
+
${agent} skill usage ${sinceLabel} (${mode})`);
|
|
869
946
|
console.log(`Files read: ${stats.filesRead}; JSONL lines read: ${stats.linesRead}`);
|
|
870
947
|
if (rows.length === 0) {
|
|
871
948
|
console.log("No skills found.");
|
|
@@ -876,64 +953,63 @@ ${agent} skill usage since ${since.toISOString().slice(0, 10)} (${mode})`);
|
|
|
876
953
|
}
|
|
877
954
|
}
|
|
878
955
|
}
|
|
879
|
-
var
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
since: { type: "string", description: "yyyy-mm-dd, overrides --period" },
|
|
885
|
-
mode: { type: "string", description: "attributed | activations | mentions" },
|
|
886
|
-
format: { type: "string", default: "text", description: "text | json" },
|
|
887
|
-
root: { type: "string", description: "Override agent sessions directory" },
|
|
888
|
-
"scan-all-files": { type: "boolean", default: false, description: "Ignore file mtime" }
|
|
956
|
+
var auditArgs = {
|
|
957
|
+
agent: {
|
|
958
|
+
type: "string",
|
|
959
|
+
alias: "a",
|
|
960
|
+
description: "claude-code, codex (default: both; pass space-separated for both)"
|
|
889
961
|
},
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
962
|
+
period: { type: "string", alias: "p", default: "all", description: "7d, 2w, 1m, 1y, all" },
|
|
963
|
+
since: { type: "string", description: "yyyy-mm-dd, overrides --period" },
|
|
964
|
+
mode: { type: "string", description: "attributed | activations | mentions" },
|
|
965
|
+
format: { type: "string", default: "text", description: "text | json" },
|
|
966
|
+
root: { type: "string", description: "Override agent sessions directory; implies global" },
|
|
967
|
+
"scan-all-files": { type: "boolean", default: false, description: "Ignore file mtime" },
|
|
968
|
+
global: {
|
|
969
|
+
type: "boolean",
|
|
970
|
+
alias: "g",
|
|
971
|
+
default: false,
|
|
972
|
+
description: "Force global scope (ignore current directory)"
|
|
897
973
|
}
|
|
898
|
-
}
|
|
974
|
+
};
|
|
899
975
|
|
|
900
976
|
// src/lock/file.ts
|
|
901
977
|
import {
|
|
902
978
|
copyFileSync,
|
|
903
|
-
existsSync as
|
|
979
|
+
existsSync as existsSync4,
|
|
904
980
|
mkdirSync,
|
|
905
981
|
readFileSync as readFileSync4,
|
|
906
982
|
renameSync,
|
|
907
983
|
writeFileSync
|
|
908
984
|
} from "node:fs";
|
|
909
|
-
import { homedir as
|
|
910
|
-
import { basename, dirname, join as
|
|
985
|
+
import { homedir as homedir3 } from "node:os";
|
|
986
|
+
import { basename, dirname as dirname2, join as join5 } from "node:path";
|
|
911
987
|
function getLockPath(global) {
|
|
912
|
-
return global ?
|
|
988
|
+
return global ? join5(homedir3(), ".agents", ".skill-lock.json") : "skills-lock.json";
|
|
913
989
|
}
|
|
914
990
|
function readLock(path) {
|
|
915
|
-
if (!
|
|
991
|
+
if (!existsSync4(path))
|
|
916
992
|
return { skills: {} };
|
|
917
993
|
return JSON.parse(readFileSync4(path, "utf8"));
|
|
918
994
|
}
|
|
919
995
|
function writeLock(path, lock) {
|
|
920
|
-
mkdirSync(
|
|
921
|
-
const tmp =
|
|
996
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
997
|
+
const tmp = join5(dirname2(path), `.${Date.now()}.skill-lock.json`);
|
|
922
998
|
writeFileSync(tmp, `${JSON.stringify(lock, null, 2)}
|
|
923
999
|
`);
|
|
924
1000
|
renameSync(tmp, path);
|
|
925
1001
|
}
|
|
926
1002
|
function getBackupPath(path) {
|
|
927
|
-
return
|
|
1003
|
+
return join5(dirname2(path), ".tmp", `${basename(path)}.bak`);
|
|
928
1004
|
}
|
|
929
1005
|
function backupLock(path) {
|
|
930
1006
|
const backupPath = getBackupPath(path);
|
|
931
|
-
mkdirSync(
|
|
1007
|
+
mkdirSync(dirname2(backupPath), { recursive: true });
|
|
932
1008
|
copyFileSync(path, backupPath);
|
|
933
1009
|
return backupPath;
|
|
934
1010
|
}
|
|
935
1011
|
function removeSkillFromLock(path, skill, { skipBackup = false } = {}) {
|
|
936
|
-
if (!
|
|
1012
|
+
if (!existsSync4(path))
|
|
937
1013
|
return { removed: false };
|
|
938
1014
|
const lock = readLock(path);
|
|
939
1015
|
if (!Object.hasOwn(lock.skills, skill))
|
|
@@ -959,7 +1035,7 @@ var listCommand = defineCommand({
|
|
|
959
1035
|
});
|
|
960
1036
|
|
|
961
1037
|
// src/commands/remove.ts
|
|
962
|
-
import { existsSync as
|
|
1038
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
963
1039
|
var removeCommand = defineCommand({
|
|
964
1040
|
meta: { description: "Remove one or more skills from the lock file" },
|
|
965
1041
|
args: {
|
|
@@ -981,7 +1057,7 @@ var removeCommand = defineCommand({
|
|
|
981
1057
|
}
|
|
982
1058
|
return;
|
|
983
1059
|
}
|
|
984
|
-
const backupPath =
|
|
1060
|
+
const backupPath = existsSync5(path) ? backupLock(path) : undefined;
|
|
985
1061
|
for (const skill of skills) {
|
|
986
1062
|
const result = removeSkillFromLock(path, skill, { skipBackup: true });
|
|
987
1063
|
if (result.removed) {
|
|
@@ -999,20 +1075,61 @@ var removeCommand = defineCommand({
|
|
|
999
1075
|
|
|
1000
1076
|
// src/cli.ts
|
|
1001
1077
|
var { version } = createRequire(import.meta.url)("../package.json");
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
var firstArg = process.argv[2];
|
|
1005
|
-
if (firstArg === undefined || !SUBCOMMANDS.has(firstArg) && !HELP_FLAGS.has(firstArg)) {
|
|
1006
|
-
process.argv.splice(2, 0, "audit");
|
|
1078
|
+
if (process.argv[2] === "audit") {
|
|
1079
|
+
process.argv.splice(2, 1);
|
|
1007
1080
|
}
|
|
1081
|
+
function mergeAgentArgs(argv) {
|
|
1082
|
+
const out = [];
|
|
1083
|
+
const values = [];
|
|
1084
|
+
let slotIdx = -1;
|
|
1085
|
+
let i = 0;
|
|
1086
|
+
while (i < argv.length) {
|
|
1087
|
+
const tok = argv[i];
|
|
1088
|
+
if (tok === undefined) {
|
|
1089
|
+
i++;
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
if (tok === "-a" || tok === "--agent") {
|
|
1093
|
+
if (slotIdx === -1)
|
|
1094
|
+
slotIdx = out.length;
|
|
1095
|
+
let j = i + 1;
|
|
1096
|
+
while (j < argv.length) {
|
|
1097
|
+
const next = argv[j];
|
|
1098
|
+
if (next === undefined || next.startsWith("-"))
|
|
1099
|
+
break;
|
|
1100
|
+
values.push(next);
|
|
1101
|
+
j++;
|
|
1102
|
+
}
|
|
1103
|
+
i = j;
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
out.push(tok);
|
|
1107
|
+
i++;
|
|
1108
|
+
}
|
|
1109
|
+
if (values.length > 0 && slotIdx !== -1)
|
|
1110
|
+
out.splice(slotIdx, 0, "--agent", values.join("\x1F"));
|
|
1111
|
+
return out;
|
|
1112
|
+
}
|
|
1113
|
+
process.argv = mergeAgentArgs(process.argv);
|
|
1114
|
+
var SUBCOMMAND_NAMES = new Set(["list", "ls", "remove", "rm"]);
|
|
1008
1115
|
var main = defineCommand({
|
|
1009
1116
|
meta: {
|
|
1010
1117
|
name: "skillio",
|
|
1011
1118
|
version,
|
|
1012
1119
|
description: "Audit and manage AI agent skills"
|
|
1013
1120
|
},
|
|
1121
|
+
args: auditArgs,
|
|
1122
|
+
async run({ args }) {
|
|
1123
|
+
if (SUBCOMMAND_NAMES.has(process.argv[2] ?? ""))
|
|
1124
|
+
return;
|
|
1125
|
+
try {
|
|
1126
|
+
await runAudit(args);
|
|
1127
|
+
} catch (e) {
|
|
1128
|
+
console.error(e instanceof Error ? e.message : String(e));
|
|
1129
|
+
process.exit(1);
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1014
1132
|
subCommands: {
|
|
1015
|
-
audit: auditCommand,
|
|
1016
1133
|
list: listCommand,
|
|
1017
1134
|
ls: listCommand,
|
|
1018
1135
|
remove: removeCommand,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Audit and manage AI agent skills for Claude Code and Codex",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ihororlovskyi",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
],
|
|
24
24
|
"type": "module",
|
|
25
25
|
"bin": {
|
|
26
|
-
"skillio": "dist/cli.js"
|
|
26
|
+
"skillio": "dist/cli.js",
|
|
27
|
+
"skl": "dist/cli.js"
|
|
27
28
|
},
|
|
28
29
|
"exports": {
|
|
29
30
|
".": {
|