skilllib 1.11.1 → 1.11.2
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
CHANGED
|
@@ -397,7 +397,7 @@ The repo commands (`status`, `add`, `remove`, `sync`, `outdated`, `update`, `lin
|
|
|
397
397
|
|
|
398
398
|
Flags: `--force` (overwrite local edits, backed up to `~/.skilllib/edit-backup`), `--allow-tracked` (link into git-tracked folders; skills git doesn't share are still left out), `--days N`, `--json`. For `tidy`: `--dry-run` (preview), `--allow-git` (also change committed files), `<name> --keep <folder>` (the copy that wins when copies differ).
|
|
399
399
|
|
|
400
|
-
A command exits 1 when it couldn't do all you asked: a skill skipped (not in the library, or local edits in the way), links git-tracked folders blocked, an unknown `tidy` name or `--keep` folder. What it did do is still done, and listed.
|
|
400
|
+
A command exits 1 when it couldn't do all you asked: a skill skipped (not in the library, or local edits in the way), links git-tracked folders blocked, an unknown `tidy` name or `--keep` folder. What it did do is still done, and listed. An unknown or misspelled flag is an error too, so a typo never runs silently. With `--json`, a failure prints `{"error": "…"}` on stdout as well as the message on stderr.
|
|
401
401
|
|
|
402
402
|
**`--json`** prints one line of JSON on stdout, for scripts and agents. Messages and warnings go to stderr. It works with `status`, `list`, `show`, `projects`, `outdated`, `usage`, `doctor`, `apply`, `add`, `remove`, `sync`, `update`, `import`, `global move` and `agent-skill`. The output is shaped to keep agents fast and cheap:
|
|
403
403
|
|
|
@@ -47,6 +47,7 @@ var jsonMode = false;
|
|
|
47
47
|
function setJsonMode(on) {
|
|
48
48
|
jsonMode = on;
|
|
49
49
|
}
|
|
50
|
+
var isJsonMode = () => jsonMode;
|
|
50
51
|
function json(output, data) {
|
|
51
52
|
process.stdout.write(JSON.stringify(data) + "\n");
|
|
52
53
|
}
|
|
@@ -219,7 +220,8 @@ function isSkillDir(dir) {
|
|
|
219
220
|
function listFiles(dir) {
|
|
220
221
|
return readdirSync(dir).filter((entry) => !IGNORED.has(entry)).flatMap((entry) => {
|
|
221
222
|
const full = join3(dir, entry);
|
|
222
|
-
|
|
223
|
+
const st = statSync(full, { throwIfNoEntry: false });
|
|
224
|
+
return !st ? [] : st.isDirectory() ? listFiles(full) : [full];
|
|
223
225
|
});
|
|
224
226
|
}
|
|
225
227
|
function treeHash(dir) {
|
|
@@ -232,8 +234,9 @@ function treeHash(dir) {
|
|
|
232
234
|
return hash.digest("hex").slice(0, 16);
|
|
233
235
|
}
|
|
234
236
|
function copySkill(from, to) {
|
|
237
|
+
const source = realpathSync2(from);
|
|
235
238
|
rmSync(to, { recursive: true, force: true });
|
|
236
|
-
cpSync(
|
|
239
|
+
cpSync(source, to, { recursive: true, dereference: true, filter: (src) => !IGNORED.has(basename(src)) && existsSync2(src) });
|
|
237
240
|
}
|
|
238
241
|
function skillDirsIn(dir) {
|
|
239
242
|
if (!existsSync2(dir)) return [];
|
|
@@ -461,7 +464,7 @@ function setKeepGlobal(names, keep) {
|
|
|
461
464
|
|
|
462
465
|
// src/library.ts
|
|
463
466
|
import { execFileSync } from "child_process";
|
|
464
|
-
import { existsSync as existsSync7, lstatSync as lstatSync2, mkdirSync as mkdirSync5, readdirSync as readdirSync4, readFileSync as readFileSync6, realpathSync as realpathSync4, renameSync, rmSync as rmSync2, symlinkSync, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
|
|
467
|
+
import { cpSync as cpSync2, existsSync as existsSync7, lstatSync as lstatSync2, mkdirSync as mkdirSync5, readdirSync as readdirSync4, readFileSync as readFileSync6, realpathSync as realpathSync4, renameSync, rmSync as rmSync2, symlinkSync, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
|
|
465
468
|
import { basename as basename3, dirname as dirname2, join as join8, relative as relative2, sep as sep3 } from "path";
|
|
466
469
|
|
|
467
470
|
// src/sources.ts
|
|
@@ -1032,25 +1035,28 @@ function removeSkill(root, name, { force = false } = {}) {
|
|
|
1032
1035
|
return { name, action: "removed", ...backedUp ? { backedUp } : {} };
|
|
1033
1036
|
}
|
|
1034
1037
|
function syncProject(root, { force = false } = {}) {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
});
|
|
1038
|
+
return Object.keys(readManifest(root).skills).flatMap((name) => syncSkill(root, name, { force }));
|
|
1039
|
+
}
|
|
1040
|
+
function syncSkill(root, name, { force = false } = {}) {
|
|
1041
|
+
const dep = readManifest(root).skills[name];
|
|
1042
|
+
if (!dep) return [];
|
|
1043
|
+
const local = treeHash(join8(root, dep.dir ?? PROJECT_SKILLS_DIR, name));
|
|
1044
|
+
const linksOk = (dep.links ?? []).every((d) => existsSync7(join8(root, d, name, "SKILL.md")));
|
|
1045
|
+
if (local === dep.hash && linksOk) return [];
|
|
1046
|
+
if (local !== null && local !== dep.hash && !force) return [{ name, action: "skipped", reason: "has local edits (use --force to reset them)" }];
|
|
1047
|
+
const change = addSkill(root, name, { force: true, version: pinnedVersion(name, dep) });
|
|
1048
|
+
if (change.action === "skipped") return [{ ...change, reason: `not in your library (${tildify(libraryDir())}); import it, or set SKILLLIB_HOME to the library that has it` }];
|
|
1049
|
+
return [{ ...change, action: local === null ? "installed" : change.action }];
|
|
1050
|
+
}
|
|
1051
|
+
function pinnedVersion(name, dep) {
|
|
1052
|
+
return versionForHash(name, dep.hash)?.version ?? (dep.version > 0 && getVersion(name, dep.version) ? dep.version : void 0);
|
|
1046
1053
|
}
|
|
1047
1054
|
function discardEdits(root, name) {
|
|
1048
1055
|
const dep = readManifest(root).skills[name];
|
|
1049
1056
|
if (!dep) return { name, action: "skipped", reason: "not managed by skilllib in this project" };
|
|
1050
1057
|
const dir = join8(root, dep.dir ?? PROJECT_SKILLS_DIR, name);
|
|
1051
|
-
const pinned = dep.version > 0 && getVersion(name, dep.version) ? dep.version : void 0;
|
|
1052
1058
|
if (existsSync7(dir) && !isLink(dir)) stash(dir, "edit-backup");
|
|
1053
|
-
return addSkill(root, name, { force: true, version:
|
|
1059
|
+
return addSkill(root, name, { force: true, version: pinnedVersion(name, dep) });
|
|
1054
1060
|
}
|
|
1055
1061
|
function updateProject(root, names, { force = false } = {}) {
|
|
1056
1062
|
const { skills } = readManifest(root);
|
|
@@ -1090,6 +1096,15 @@ function readBackupIndex(bucket) {
|
|
|
1090
1096
|
return {};
|
|
1091
1097
|
}
|
|
1092
1098
|
}
|
|
1099
|
+
function move(from, to) {
|
|
1100
|
+
try {
|
|
1101
|
+
renameSync(from, to);
|
|
1102
|
+
} catch (err) {
|
|
1103
|
+
if (err.code !== "EXDEV") throw err;
|
|
1104
|
+
cpSync2(from, to, { recursive: true, verbatimSymlinks: true });
|
|
1105
|
+
rmSync2(from, { recursive: true, force: true });
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1093
1108
|
function stash(dir, bucket) {
|
|
1094
1109
|
let at = Date.now();
|
|
1095
1110
|
const entryAt = (ms) => `${basename3(dir)}-${new Date(ms).toISOString().replace(/[:.]/g, "-")}`;
|
|
@@ -1097,7 +1112,7 @@ function stash(dir, bucket) {
|
|
|
1097
1112
|
const entry = entryAt(at);
|
|
1098
1113
|
const target = join8(skilllibHome(), bucket, entry);
|
|
1099
1114
|
mkdirSync5(join8(skilllibHome(), bucket), { recursive: true });
|
|
1100
|
-
|
|
1115
|
+
move(dir, target);
|
|
1101
1116
|
writeFileSync5(backupIndexFile(bucket), JSON.stringify({ ...readBackupIndex(bucket), [entry]: dir }, null, 2) + "\n");
|
|
1102
1117
|
return target;
|
|
1103
1118
|
}
|
|
@@ -1195,7 +1210,7 @@ function restoreBackup(backup) {
|
|
|
1195
1210
|
}
|
|
1196
1211
|
if (taken) return { ok: false, reason: `${backup.name} already exists there` };
|
|
1197
1212
|
mkdirSync5(join8(to, ".."), { recursive: true });
|
|
1198
|
-
|
|
1213
|
+
move(backup.path, to);
|
|
1199
1214
|
forgetLatest(backup.name);
|
|
1200
1215
|
return { ok: true, to };
|
|
1201
1216
|
}
|
|
@@ -1265,6 +1280,7 @@ function refreshAgentSkill() {
|
|
|
1265
1280
|
|
|
1266
1281
|
// src/commands.ts
|
|
1267
1282
|
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
1283
|
+
import { parseArgs as parseFlags } from "util";
|
|
1268
1284
|
import { basename as basename9, join as join14, resolve as resolve7, sep as sep5 } from "path";
|
|
1269
1285
|
|
|
1270
1286
|
// src/git.ts
|
|
@@ -2604,23 +2620,35 @@ function moveGlobalSkills(skills, roots, { group, allowTracked = false, label =
|
|
|
2604
2620
|
|
|
2605
2621
|
// src/commands.ts
|
|
2606
2622
|
var USAGE_DAYS = 30;
|
|
2623
|
+
var FLAGS = {
|
|
2624
|
+
force: { type: "boolean" },
|
|
2625
|
+
all: { type: "boolean" },
|
|
2626
|
+
global: { type: "boolean" },
|
|
2627
|
+
fix: { type: "boolean" },
|
|
2628
|
+
"allow-tracked": { type: "boolean" },
|
|
2629
|
+
json: { type: "boolean" },
|
|
2630
|
+
"dry-run": { type: "boolean" },
|
|
2631
|
+
"allow-git": { type: "boolean" },
|
|
2632
|
+
days: { type: "string" },
|
|
2633
|
+
keep: { type: "string" },
|
|
2634
|
+
to: { type: "string", multiple: true }
|
|
2635
|
+
};
|
|
2607
2636
|
function parseArgs(argv) {
|
|
2608
|
-
const
|
|
2609
|
-
const days =
|
|
2610
|
-
const keepIdx = argv.indexOf("--keep");
|
|
2637
|
+
const { values: v, positionals } = parseFlags({ args: argv, options: FLAGS, allowPositionals: true, strict: true });
|
|
2638
|
+
const days = Number(v.days ?? USAGE_DAYS);
|
|
2611
2639
|
return {
|
|
2612
|
-
positional:
|
|
2613
|
-
force:
|
|
2614
|
-
all:
|
|
2615
|
-
global:
|
|
2616
|
-
fix:
|
|
2617
|
-
allowTracked:
|
|
2618
|
-
json:
|
|
2640
|
+
positional: positionals,
|
|
2641
|
+
force: !!v.force,
|
|
2642
|
+
all: !!v.all,
|
|
2643
|
+
global: !!v.global,
|
|
2644
|
+
fix: !!v.fix,
|
|
2645
|
+
allowTracked: !!v["allow-tracked"],
|
|
2646
|
+
json: !!v.json,
|
|
2619
2647
|
days: Number.isFinite(days) && days > 0 ? days : USAGE_DAYS,
|
|
2620
|
-
dryRun:
|
|
2621
|
-
allowGit:
|
|
2622
|
-
...
|
|
2623
|
-
to:
|
|
2648
|
+
dryRun: !!v["dry-run"],
|
|
2649
|
+
allowGit: !!v["allow-git"],
|
|
2650
|
+
...v.keep ? { keep: v.keep } : {},
|
|
2651
|
+
to: (v.to ?? []).flatMap((t) => t.split(",").filter(Boolean))
|
|
2624
2652
|
};
|
|
2625
2653
|
}
|
|
2626
2654
|
function colorState(state) {
|
|
@@ -2844,8 +2872,7 @@ function projects(args) {
|
|
|
2844
2872
|
}
|
|
2845
2873
|
function add(args) {
|
|
2846
2874
|
if (args.positional.length === 0) {
|
|
2847
|
-
|
|
2848
|
-
process.exit(1);
|
|
2875
|
+
throw new Error("Usage: skilllib add <skill-name>... [--force]");
|
|
2849
2876
|
}
|
|
2850
2877
|
const root = requireProject();
|
|
2851
2878
|
if (args.allowTracked) allowTrackedLinks(root);
|
|
@@ -2854,13 +2881,13 @@ function add(args) {
|
|
|
2854
2881
|
}
|
|
2855
2882
|
function remove(args) {
|
|
2856
2883
|
if (args.positional.length === 0) {
|
|
2857
|
-
|
|
2858
|
-
process.exit(1);
|
|
2884
|
+
throw new Error("Usage: skilllib remove <skill-name>... [--force]");
|
|
2859
2885
|
}
|
|
2860
2886
|
const root = requireProject();
|
|
2861
2887
|
printChanges(root, args.positional.map((name) => removeSkill(root, name, { force: args.force })), args);
|
|
2862
2888
|
}
|
|
2863
2889
|
function sync(args) {
|
|
2890
|
+
if (args.positional.length) throw new Error(`sync takes no skill names: it installs exactly what skilllib.json pins. To add a skill: skilllib add ${args.positional.join(" ")}`);
|
|
2864
2891
|
const roots = args.all ? visibleProjects() : [requireProject()];
|
|
2865
2892
|
const results = roots.map((root) => {
|
|
2866
2893
|
if (args.allowTracked) allowTrackedLinks(root);
|
|
@@ -2913,20 +2940,21 @@ function outdated(args) {
|
|
|
2913
2940
|
function importSkills(args) {
|
|
2914
2941
|
const dirs = args.global ? machineSkills().filter((m) => m.movable && !m.broken).map((m) => m.path) : args.positional.map((p) => resolve7(p));
|
|
2915
2942
|
if (dirs.length === 0) {
|
|
2916
|
-
|
|
2917
|
-
process.exit(1);
|
|
2943
|
+
throw new Error("Usage: skilllib import <skill-dir>... [--force] | skilllib import --global");
|
|
2918
2944
|
}
|
|
2919
2945
|
const results = [];
|
|
2920
2946
|
for (const dir of dirs) {
|
|
2921
2947
|
if (!isSkillDir(dir)) {
|
|
2922
2948
|
warn(`${tildify(dir)}: no SKILL.md, skipping`);
|
|
2923
2949
|
results.push({ path: dir, status: "no SKILL.md" });
|
|
2950
|
+
process.exitCode = 1;
|
|
2924
2951
|
continue;
|
|
2925
2952
|
}
|
|
2926
2953
|
const { name, status: result } = importSkill(dir, { force: args.force });
|
|
2927
2954
|
results.push({ path: dir, name, status: result });
|
|
2928
2955
|
if (result === "exists") {
|
|
2929
2956
|
warn(`${name}: the library already has a different version (use --force to replace it)`);
|
|
2957
|
+
process.exitCode = 1;
|
|
2930
2958
|
continue;
|
|
2931
2959
|
}
|
|
2932
2960
|
success(`${name} ${dim(result === "unchanged" ? "already in library" : result === "added" ? "added to library" : "library updated")}`);
|
|
@@ -2990,12 +3018,11 @@ function folders(args) {
|
|
|
2990
3018
|
info(roots.length ? `Project folders:
|
|
2991
3019
|
${roots.map((r) => ` ${tildify(r)}`).join("\n")}` : "No project folders. Add one: skilllib folders add ~/Projects");
|
|
2992
3020
|
if (hidden.length) info(dim(`Hidden projects: ${hidden.map((h) => tildify(h)).join(", ")} (skilllib unhide <path>)`));
|
|
2993
|
-
if (failed) process.
|
|
3021
|
+
if (failed) process.exitCode = 1;
|
|
2994
3022
|
}
|
|
2995
3023
|
function unhide(args) {
|
|
2996
3024
|
if (args.positional.length === 0) {
|
|
2997
|
-
|
|
2998
|
-
process.exit(1);
|
|
3025
|
+
throw new Error("Usage: skilllib unhide <path>...");
|
|
2999
3026
|
}
|
|
3000
3027
|
let failed = false;
|
|
3001
3028
|
for (const p of args.positional) {
|
|
@@ -3007,18 +3034,16 @@ function unhide(args) {
|
|
|
3007
3034
|
failed = true;
|
|
3008
3035
|
}
|
|
3009
3036
|
}
|
|
3010
|
-
if (failed) process.
|
|
3037
|
+
if (failed) process.exitCode = 1;
|
|
3011
3038
|
}
|
|
3012
3039
|
function newSkill(args) {
|
|
3013
3040
|
const [name, ...rest] = args.positional;
|
|
3014
3041
|
if (!name) {
|
|
3015
|
-
|
|
3016
|
-
process.exit(1);
|
|
3042
|
+
throw new Error("Usage: skilllib new <name> [description]");
|
|
3017
3043
|
}
|
|
3018
3044
|
const r = createSkill(name, rest.join(" "));
|
|
3019
3045
|
if (!r.ok) {
|
|
3020
|
-
|
|
3021
|
-
process.exit(1);
|
|
3046
|
+
throw new Error(`Can't create ${name}: ${r.reason}`);
|
|
3022
3047
|
}
|
|
3023
3048
|
success(`Created ${tildify(join14(r.dir, "SKILL.md"))}`);
|
|
3024
3049
|
}
|
|
@@ -3033,8 +3058,7 @@ function restore(args) {
|
|
|
3033
3058
|
}
|
|
3034
3059
|
const backup = backups.find((b) => b.name === name);
|
|
3035
3060
|
if (!backup) {
|
|
3036
|
-
|
|
3037
|
-
process.exit(1);
|
|
3061
|
+
throw new Error(`No backup named ${name}`);
|
|
3038
3062
|
}
|
|
3039
3063
|
const r = backup.kind === "plugin" ? restorePlugin(backup) : restoreBackup(backup);
|
|
3040
3064
|
if (r.ok) success(`Restored ${name} to ${tildify(r.to)}`);
|
|
@@ -3160,8 +3184,7 @@ function show(args) {
|
|
|
3160
3184
|
const name = args.positional[0];
|
|
3161
3185
|
const dir = name ? join14(libraryDir(), name) : "";
|
|
3162
3186
|
if (!name || !isSkillDir(dir)) {
|
|
3163
|
-
|
|
3164
|
-
process.exit(1);
|
|
3187
|
+
throw new Error(name ? `${name} is not in the library` : "Usage: skilllib show <skill-name>");
|
|
3165
3188
|
}
|
|
3166
3189
|
const { description } = readSkillInfo(dir);
|
|
3167
3190
|
if (args.json) {
|
|
@@ -3187,8 +3210,7 @@ function harnessesCommand(args) {
|
|
|
3187
3210
|
if (args.positional.length) {
|
|
3188
3211
|
const unknown = args.positional.filter((p) => !ids.includes(p));
|
|
3189
3212
|
if (unknown.length) {
|
|
3190
|
-
|
|
3191
|
-
process.exit(1);
|
|
3213
|
+
throw new Error(`Unknown harness: ${unknown.join(", ")}. Choose from: ${ids.join(", ")}`);
|
|
3192
3214
|
}
|
|
3193
3215
|
setHarnesses(args.positional);
|
|
3194
3216
|
success(`Using ${args.positional.join(", ")}`);
|
|
@@ -3225,14 +3247,12 @@ function globalCommand(args) {
|
|
|
3225
3247
|
if (action === "keep" || action === "unkeep") {
|
|
3226
3248
|
const unknown = names.filter((n) => !yours.some((m) => m.name === n));
|
|
3227
3249
|
if (!names.length || unknown.length) {
|
|
3228
|
-
|
|
3229
|
-
process.exit(1);
|
|
3250
|
+
throw new Error(names.length ? `Not one of your global skills: ${unknown.join(", ")}` : `Usage: skilllib global ${action} <name>...`);
|
|
3230
3251
|
}
|
|
3231
3252
|
setKeepGlobal(names, action === "keep");
|
|
3232
3253
|
success(action === "keep" ? `Keeping ${names.join(", ")} global on purpose` : `${names.join(", ")} will show up in cleanup again`);
|
|
3233
3254
|
} else if (action) {
|
|
3234
|
-
|
|
3235
|
-
process.exit(1);
|
|
3255
|
+
throw new Error("Usage: skilllib global [keep|unkeep <name>...] | skilllib global move <name>... --to <repo>...");
|
|
3236
3256
|
}
|
|
3237
3257
|
const kept = keptGlobal();
|
|
3238
3258
|
if (!yours.length) return info("None of your skills load globally.");
|
|
@@ -3285,8 +3305,7 @@ function tidy(args) {
|
|
|
3285
3305
|
const names = args.positional;
|
|
3286
3306
|
const keepFor = (base) => args.keep ? Object.fromEntries(names.map((n) => [n, base ? resolve7(base, args.keep) : expandHome(args.keep)])) : {};
|
|
3287
3307
|
if (args.keep && !names.length) {
|
|
3288
|
-
|
|
3289
|
-
process.exit(1);
|
|
3308
|
+
throw new Error("Usage: skilllib tidy <name>... --keep <folder>");
|
|
3290
3309
|
}
|
|
3291
3310
|
const targets = args.global ? [null] : args.all ? visibleProjects() : [requireProject()];
|
|
3292
3311
|
const problems = [];
|
|
@@ -3306,8 +3325,7 @@ function tidy(args) {
|
|
|
3306
3325
|
}
|
|
3307
3326
|
}
|
|
3308
3327
|
if (problems.length) {
|
|
3309
|
-
|
|
3310
|
-
process.exit(1);
|
|
3328
|
+
throw new Error(problems.join("\n"));
|
|
3311
3329
|
}
|
|
3312
3330
|
const reports = targets.map(
|
|
3313
3331
|
(root) => root === null ? { label: "global folders", report: planGlobalTidy({ keep: keepFor(null) }) } : { label: basename9(root), report: planProjectTidy(root, { keep: keepFor(root) }) }
|
|
@@ -3347,8 +3365,7 @@ function agentSkill(args) {
|
|
|
3347
3365
|
if (action === "install") {
|
|
3348
3366
|
const r = installAgentSkill();
|
|
3349
3367
|
if (!r.ok) {
|
|
3350
|
-
|
|
3351
|
-
process.exit(1);
|
|
3368
|
+
throw new Error(`Can't install the skilllib skill: ${r.reason}`);
|
|
3352
3369
|
}
|
|
3353
3370
|
if (args.json) return json("agent-skill", { state: agentSkillState(), dirs: r.dirs });
|
|
3354
3371
|
success(`Installed in ${r.dirs.map((d) => tildify(d)).join(" and ")}`);
|
|
@@ -3380,6 +3397,8 @@ export {
|
|
|
3380
3397
|
projectHere,
|
|
3381
3398
|
readManifest,
|
|
3382
3399
|
setJsonMode,
|
|
3400
|
+
isJsonMode,
|
|
3401
|
+
json,
|
|
3383
3402
|
error,
|
|
3384
3403
|
tildify,
|
|
3385
3404
|
readConfig,
|
|
@@ -3406,7 +3425,7 @@ export {
|
|
|
3406
3425
|
relinkDependency,
|
|
3407
3426
|
addSkill,
|
|
3408
3427
|
removeSkill,
|
|
3409
|
-
|
|
3428
|
+
syncSkill,
|
|
3410
3429
|
updateProject,
|
|
3411
3430
|
importSkill,
|
|
3412
3431
|
removeUntracked,
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
globalCommand,
|
|
10
10
|
harnessesCommand,
|
|
11
11
|
importSkills,
|
|
12
|
+
isJsonMode,
|
|
13
|
+
json,
|
|
12
14
|
link,
|
|
13
15
|
list,
|
|
14
16
|
newSkill,
|
|
@@ -28,7 +30,7 @@ import {
|
|
|
28
30
|
unhide,
|
|
29
31
|
update,
|
|
30
32
|
usage
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-OFWHWIER.js";
|
|
32
34
|
|
|
33
35
|
// src/index.ts
|
|
34
36
|
import { readFileSync } from "fs";
|
|
@@ -91,15 +93,15 @@ function packageVersion() {
|
|
|
91
93
|
}
|
|
92
94
|
async function main() {
|
|
93
95
|
const [command, ...rest] = process.argv.slice(2);
|
|
96
|
+
setJsonMode(rest.includes("--json"));
|
|
94
97
|
const args = parseArgs(rest);
|
|
95
|
-
setJsonMode(args.json);
|
|
96
98
|
if (!["--version", "-v", "version", "help", "--help", "-h"].includes(command ?? "")) refreshAgentSkill();
|
|
97
99
|
switch (command) {
|
|
98
100
|
case void 0:
|
|
99
|
-
return process.stdin.isTTY && process.stdout.isTTY ? (await import("./tui-
|
|
101
|
+
return process.stdin.isTTY && process.stdout.isTTY ? (await import("./tui-NGTOOVAQ.js")).tui() : overview(args);
|
|
100
102
|
case "ui":
|
|
101
103
|
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("`skilllib ui` needs an interactive terminal. Agents and scripts: use `skilllib status --json`.");
|
|
102
|
-
return (await import("./tui-
|
|
104
|
+
return (await import("./tui-NGTOOVAQ.js")).tui();
|
|
103
105
|
case "status":
|
|
104
106
|
return status(args);
|
|
105
107
|
case "add":
|
|
@@ -108,7 +110,6 @@ async function main() {
|
|
|
108
110
|
case "rm":
|
|
109
111
|
return remove(args);
|
|
110
112
|
case "sync":
|
|
111
|
-
case "install":
|
|
112
113
|
return sync(args);
|
|
113
114
|
case "update":
|
|
114
115
|
case "upgrade":
|
|
@@ -165,6 +166,7 @@ async function main() {
|
|
|
165
166
|
console.log(HELP);
|
|
166
167
|
return;
|
|
167
168
|
default:
|
|
169
|
+
if (isJsonMode()) throw new Error(`Unknown command: ${command} (skilllib help lists them)`);
|
|
168
170
|
console.error(`Unknown command: ${command}
|
|
169
171
|
`);
|
|
170
172
|
console.log(HELP);
|
|
@@ -172,7 +174,9 @@ async function main() {
|
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
main().catch((err) => {
|
|
175
|
-
|
|
177
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
178
|
+
if (isJsonMode()) json("error", { error: message });
|
|
179
|
+
error(message);
|
|
176
180
|
if (process.env.DEBUG && err instanceof Error) console.error(err.stack);
|
|
177
181
|
process.exit(1);
|
|
178
182
|
});
|
package/dist/json.d.cts
CHANGED
|
@@ -178,6 +178,10 @@ type DoctorJson = {
|
|
|
178
178
|
message: string;
|
|
179
179
|
};
|
|
180
180
|
}[];
|
|
181
|
+
/** Any command with --json that fails: it exits 1, and this is the one line on stdout. */
|
|
182
|
+
type ErrorJson = {
|
|
183
|
+
error: string;
|
|
184
|
+
};
|
|
181
185
|
/** `skilllib apply <issue-id> [choice] --json` */
|
|
182
186
|
type ApplyJson = {
|
|
183
187
|
id: string;
|
|
@@ -219,4 +223,4 @@ type AgentSkillJson = {
|
|
|
219
223
|
removed?: string[];
|
|
220
224
|
};
|
|
221
225
|
|
|
222
|
-
export type { AgentSkillJson, AgentSkillState, AllChangesJson, ApplyJson, ChangeJson, ChangesJson, DoctorJson, GitState, GlobalMoveJson, HarnessId, ImportJson, ListJson, OutdatedJson, ProjectSource, ProjectsJson, ShowJson, SkillState, SourceKind, StatusGlobalGroup, StatusIssue, StatusJson, StatusSkillGroup, UsageJson };
|
|
226
|
+
export type { AgentSkillJson, AgentSkillState, AllChangesJson, ApplyJson, ChangeJson, ChangesJson, DoctorJson, ErrorJson, GitState, GlobalMoveJson, HarnessId, ImportJson, ListJson, OutdatedJson, ProjectSource, ProjectsJson, ShowJson, SkillState, SourceKind, StatusGlobalGroup, StatusIssue, StatusJson, StatusSkillGroup, UsageJson };
|
package/dist/json.d.ts
CHANGED
|
@@ -178,6 +178,10 @@ type DoctorJson = {
|
|
|
178
178
|
message: string;
|
|
179
179
|
};
|
|
180
180
|
}[];
|
|
181
|
+
/** Any command with --json that fails: it exits 1, and this is the one line on stdout. */
|
|
182
|
+
type ErrorJson = {
|
|
183
|
+
error: string;
|
|
184
|
+
};
|
|
181
185
|
/** `skilllib apply <issue-id> [choice] --json` */
|
|
182
186
|
type ApplyJson = {
|
|
183
187
|
id: string;
|
|
@@ -219,4 +223,4 @@ type AgentSkillJson = {
|
|
|
219
223
|
removed?: string[];
|
|
220
224
|
};
|
|
221
225
|
|
|
222
|
-
export type { AgentSkillJson, AgentSkillState, AllChangesJson, ApplyJson, ChangeJson, ChangesJson, DoctorJson, GitState, GlobalMoveJson, HarnessId, ImportJson, ListJson, OutdatedJson, ProjectSource, ProjectsJson, ShowJson, SkillState, SourceKind, StatusGlobalGroup, StatusIssue, StatusJson, StatusSkillGroup, UsageJson };
|
|
226
|
+
export type { AgentSkillJson, AgentSkillState, AllChangesJson, ApplyJson, ChangeJson, ChangesJson, DoctorJson, ErrorJson, GitState, GlobalMoveJson, HarnessId, ImportJson, ListJson, OutdatedJson, ProjectSource, ProjectsJson, ShowJson, SkillState, SourceKind, StatusGlobalGroup, StatusIssue, StatusJson, StatusSkillGroup, UsageJson };
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
setPluginOn,
|
|
64
64
|
skilllibHome,
|
|
65
65
|
skillsLoadedIn,
|
|
66
|
-
|
|
66
|
+
syncSkill,
|
|
67
67
|
tildify,
|
|
68
68
|
turnOffIn,
|
|
69
69
|
uninstallPlugin,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
versionHistory,
|
|
74
74
|
visibilityOf,
|
|
75
75
|
visibleProjects
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-OFWHWIER.js";
|
|
77
77
|
|
|
78
78
|
// src/tui/index.tsx
|
|
79
79
|
import { render } from "ink";
|
|
@@ -1671,7 +1671,7 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
1671
1671
|
pickRepos: (w, repos) => w.ops.moveGlobal(mine, repos, label)
|
|
1672
1672
|
}),
|
|
1673
1673
|
...mine.some((m) => !m.kept) ? [fixOption({ label: `Keep all ${mine.length} global on purpose`, preview: `skilllib stops warning about these ${n(mine.length)}.`, run: (w) => (mine.forEach((m) => w.ops.keepGlobal(m.name, true)), `${n(mine.length)} marked as global on purpose`) })] : [],
|
|
1674
|
-
fixOption({ label: `Delete all ${mine.length}`, preview: `Move these ${n(mine.length)} to Settings \u203A Backups.`, run: (w) => (mine.
|
|
1674
|
+
fixOption({ label: `Delete all ${mine.length}`, preview: `Move these ${n(mine.length)} to Settings \u203A Backups.`, run: (w) => joined(mine.map((m) => w.ops.deleteGlobal(m))) })
|
|
1675
1675
|
] : [],
|
|
1676
1676
|
...libs.length ? [
|
|
1677
1677
|
fixOption({
|
|
@@ -1683,7 +1683,7 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
1683
1683
|
})
|
|
1684
1684
|
] : [],
|
|
1685
1685
|
...libs.length ? [fixOption(deleteLibraryFix(world, libs.map((l) => l.name)))] : [],
|
|
1686
|
-
...locals.length ? [fixOption({ label: `Remove all ${locals.length} from this repo`, preview: `Remove these ${n(locals.length)} from ${open}; your library keeps the tracked ones.`, run: (w) => (locals.
|
|
1686
|
+
...locals.length ? [fixOption({ label: `Remove all ${locals.length} from this repo`, preview: `Remove these ${n(locals.length)} from ${open}; your library keeps the tracked ones.`, run: (w) => joined(locals.map((s) => w.ops.remove(open, s.name))) })] : [],
|
|
1687
1687
|
...[...new Set(machines.filter((m) => m.source === "plugin").map((m) => m.where))].map((id) => ({ label: `Open ${id.split("@")[0]} in Plugins`, action: () => openInPlugins(id) })),
|
|
1688
1688
|
{ label: "Review prompt", action: () => ui.copy(reviewPrompt(world, names, `Review these related skills (${label}).`), `a review prompt for ${label}`) }
|
|
1689
1689
|
];
|
|
@@ -2013,7 +2013,8 @@ function App({ initial, reload, loadUsage: loadUsage2 }) {
|
|
|
2013
2013
|
if (row.create && !/^[a-z0-9]/.test(m.query)) return setToast("Type the new skill's name first");
|
|
2014
2014
|
setModal(null);
|
|
2015
2015
|
if (!row.create) return apply(row.run);
|
|
2016
|
-
row.run(world);
|
|
2016
|
+
const created = row.run(world);
|
|
2017
|
+
if (isFailure(created)) return setToast(`\u2717 ${said2(created)}`);
|
|
2017
2018
|
return edit(world.ops.libraryFile(m.query), row.afterEdit);
|
|
2018
2019
|
}
|
|
2019
2020
|
if (isNameChar(input, key)) return setModal({ ...m, query: m.query + input.toLowerCase(), cursor: 0 });
|
|
@@ -2636,7 +2637,7 @@ function realOps(roots, backups) {
|
|
|
2636
2637
|
return orForce(removeSkill(rootOf(repo), name), repo, "Remove it anyway", () => removeSkill(rootOf(repo), name, { force: true }));
|
|
2637
2638
|
},
|
|
2638
2639
|
restore: (repo, name) => {
|
|
2639
|
-
const c =
|
|
2640
|
+
const [c] = syncSkill(rootOf(repo), name);
|
|
2640
2641
|
return c ? result(c, repo) : `${name} is already in place`;
|
|
2641
2642
|
},
|
|
2642
2643
|
update: (repo, name) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skilllib",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.2",
|
|
4
4
|
"description": "Manage your agent skills like dependencies. One library for all your skills; each repo gets only the ones it needs, and every agent can see them. Works with Claude Code, Cursor, Codex, Zed and Grok.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
package/skills/skilllib/SKILL.md
CHANGED
|
@@ -8,7 +8,7 @@ allowed-tools: Bash(skilllib:*)
|
|
|
8
8
|
|
|
9
9
|
The user manages agent skills with the `skilllib` CLI. Their **library** (`~/.skilllib/library`, "my skills", "the registry") holds versioned skills that load nowhere until added to a repo. A repo pins its skills in `skilllib.json`.
|
|
10
10
|
|
|
11
|
-
Always pass `--json` (one line of JSON on stdout; messages go to stderr). Never run bare `skilllib` or `skilllib ui`: that's an interactive app.
|
|
11
|
+
Always pass `--json` (one line of JSON on stdout; messages go to stderr). A failure exits 1 with `{"error": "..."}` as that line; `link`, `tidy` and `global keep` print messages only. Unknown flags are errors. Never run bare `skilllib` or `skilllib ui`: that's an interactive app.
|
|
12
12
|
|
|
13
13
|
## Reading
|
|
14
14
|
|
|
@@ -25,12 +25,12 @@ Also: `usage --json` (Claude Code usage only, so "unused" is a hint; each skill
|
|
|
25
25
|
|
|
26
26
|
## Changing (ask first unless the user asked for this exact change)
|
|
27
27
|
|
|
28
|
-
`add <name>...` · `remove <name>...` · `update [name...]` · `sync` (
|
|
28
|
+
`add <name>...` · `remove <name>...` · `update [name...]` · `sync` (installs what `skilllib.json` pins; takes no names). Pass several names in one call. Their result is `[{name, action, from, to, dirs, reason, blocked, uncommitted, backedUp}]`, which is the whole result: there's no need to check files afterwards. `import <dir>...` (into the library) prints `[{path, name, status}]` and exits 1 if a folder was skipped (`exists`, `no SKILL.md`). `doctor --fix` prints doctor's issues, each fix with `fixed: {ok, message}`.
|
|
29
29
|
|
|
30
30
|
- `skipped` + `reason`: nothing changed for that skill, and the command exits 1; tell the user. `--force` overwrites local edits (`backedUp` says where they went; `skilllib restore <name>` brings them back), but only use it with their OK.
|
|
31
31
|
- `blocked`: git tracks that folder. Re-run with `--allow-tracked` only with their OK.
|
|
32
32
|
- `uncommitted`: git tracks that folder but not the skill's real copy, so a link there would break for teammates; `--allow-tracked` doesn't change that. Once the copy is committed, `link --allow-tracked` adds it.
|
|
33
|
-
- Changes apply from the agent's next session. Remind the user to commit `skilllib.json` and `.
|
|
33
|
+
- Changes apply from the agent's next session. Remind the user to commit `skilllib.json` and the folders in `dirs`.
|
|
34
34
|
|
|
35
35
|
**Prefer per-repo skills to global ones.** A global skill loads in every repo, for every agent. When `usage --json` shows one used in only a few repos, propose moving it there:
|
|
36
36
|
|