@ichintansoni/skills-master 0.2.4 → 0.3.1
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 +3 -1
- package/dist/bin.js +54 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ npx @ichintansoni/skills-master doctor # same detection,
|
|
|
23
23
|
|
|
24
24
|
`status` and `doctor` share their drift detection but answer different questions. `status` is an inventory — it lists every installed skill with its version, targets, and whether the output has been edited or deleted, works entirely offline, and always exits 0, so it is safe to pipe (`status --json`, `status --problems`, `status <name>…`). `doctor` is the gate: same findings, but it exits non-zero, which is what you want in CI.
|
|
25
25
|
|
|
26
|
+
Both answer "is what I installed intact?" — neither answers "is what I installed **current?**", because both compare emitted files against the lockfile and never the lockfile against the source. An install pinned to a release from six months ago is perfectly healthy by that measure. `update --check` is the second gate: it resolves the content, reports which skills are behind, and exits non-zero. It catches the case a version comparison misses — a skill edited upstream *without* a version bump, which is what resource-file and description changes usually are.
|
|
27
|
+
|
|
26
28
|
`add` writes, per detected tool:
|
|
27
29
|
|
|
28
30
|
| Tool | Output |
|
|
@@ -59,7 +61,7 @@ Run `skills-master <command> --help` for the full flag list on any of these.
|
|
|
59
61
|
|---|---|
|
|
60
62
|
| `init` | Detect which tools the project uses and write `skills-master.json`. `--target` · `--commit` · `--ref` · `--force` |
|
|
61
63
|
| `add <names…>` | Install skills by name, category, or class |
|
|
62
|
-
| `update [names…]` | Re-install skills whose **content** changed upstream. Only touches targets a skill is already installed to |
|
|
64
|
+
| `update [names…]` | Re-install skills whose **content** changed upstream. Only touches targets a skill is already installed to. `--check` reports what is behind and exits non-zero |
|
|
63
65
|
| `sync [names…]` | Re-emit to match the **current config** — new targets, moved `paths`, deleted files. `--overwrite` · `--prune` · `--dry-run` |
|
|
64
66
|
| `remove <names…>` | Remove installed skills. `--target` removes from one tool only |
|
|
65
67
|
| `status [names…]` | Inventory: versions, targets, and local-edit state. Offline, always exits 0. `--problems` · `--json` |
|
package/dist/bin.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
|
|
6
6
|
// package.json
|
|
7
|
-
var version = "0.
|
|
7
|
+
var version = "0.3.1";
|
|
8
8
|
|
|
9
9
|
// src/schema/projectConfig.ts
|
|
10
10
|
import { z } from "zod";
|
|
@@ -1216,6 +1216,52 @@ async function updateCommand(opts) {
|
|
|
1216
1216
|
const content = await resolveContent({ content: opts.content, ref, cwd: opts.cwd });
|
|
1217
1217
|
const paths = resolvePaths(cfg);
|
|
1218
1218
|
const prefix = opts.dryRun ? "[dry-run] " : "";
|
|
1219
|
+
if (opts.check) {
|
|
1220
|
+
const behind = [];
|
|
1221
|
+
for (const name of names.sort()) {
|
|
1222
|
+
const locked = lock.skills[name];
|
|
1223
|
+
if (!locked) {
|
|
1224
|
+
log.warn(`"${name}" is not installed.`);
|
|
1225
|
+
skipped.push(name);
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
let skill;
|
|
1229
|
+
try {
|
|
1230
|
+
skill = content.loadSkill(name);
|
|
1231
|
+
} catch (err) {
|
|
1232
|
+
if (err instanceof SkillNotFoundError) {
|
|
1233
|
+
log.warn(`"${name}" no longer exists in the content library.`);
|
|
1234
|
+
} else {
|
|
1235
|
+
log.error(
|
|
1236
|
+
`Failed to load "${name}": ${err instanceof Error ? err.message : String(err)}`
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
skipped.push(name);
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
const available = skill.frontmatter["x-skills-master"].version;
|
|
1243
|
+
const sourceChanged = locked.sourceHash !== sourceHashOf(skill);
|
|
1244
|
+
const refChanged = lock.contentRef !== ref;
|
|
1245
|
+
if (!sourceChanged && !refChanged) {
|
|
1246
|
+
upToDate.push(name);
|
|
1247
|
+
continue;
|
|
1248
|
+
}
|
|
1249
|
+
const reason = !sourceChanged ? "ref" : available !== locked.version ? "version" : "content";
|
|
1250
|
+
behind.push({ name, installed: locked.version, available, reason });
|
|
1251
|
+
}
|
|
1252
|
+
for (const b of behind) {
|
|
1253
|
+
const detail = b.reason === "version" ? `${b.installed} \u2192 ${b.available}` : b.reason === "content" ? `${b.installed} (content changed without a version bump)` : `${b.installed} (content ref moved to ${ref})`;
|
|
1254
|
+
log.info(`\u2191 ${b.name.padEnd(32)} ${detail}`);
|
|
1255
|
+
}
|
|
1256
|
+
if (behind.length === 0) {
|
|
1257
|
+
log.success(`All ${upToDate.length} installed skill(s) are current.`);
|
|
1258
|
+
} else {
|
|
1259
|
+
log.warn(
|
|
1260
|
+
`${behind.length} of ${behind.length + upToDate.length} installed skill(s) are behind \u2014 run \`update\`.`
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
return { updated, upToDate, skipped, behind };
|
|
1264
|
+
}
|
|
1219
1265
|
for (const name of names.sort()) {
|
|
1220
1266
|
const locked = lock.skills[name];
|
|
1221
1267
|
if (!locked) {
|
|
@@ -2297,17 +2343,19 @@ program.command("add <names...>").description("Install skills (by name, category
|
|
|
2297
2343
|
})
|
|
2298
2344
|
)
|
|
2299
2345
|
);
|
|
2300
|
-
program.command("update [names...]").description("Re-install skills whose content changed").option("--dry-run", "preview without writing").option("--overwrite", "force re-install, replacing local edits").option("--content <dir>", "local skills directory").option("--ref <ref>", "content git ref (tag/branch/sha)").action(
|
|
2301
|
-
(names, opts) => run(
|
|
2302
|
-
|
|
2346
|
+
program.command("update [names...]").description("Re-install skills whose content changed").option("--check", "report which installed skills are behind; exit 1 if any are").option("--dry-run", "preview without writing").option("--overwrite", "force re-install, replacing local edits").option("--content <dir>", "local skills directory").option("--ref <ref>", "content git ref (tag/branch/sha)").action(
|
|
2347
|
+
(names, opts) => run(async () => {
|
|
2348
|
+
const res = await updateCommand({
|
|
2303
2349
|
cwd: process.cwd(),
|
|
2304
2350
|
names,
|
|
2351
|
+
check: opts.check,
|
|
2305
2352
|
dryRun: opts.dryRun,
|
|
2306
2353
|
overwrite: opts.overwrite,
|
|
2307
2354
|
content: opts.content,
|
|
2308
2355
|
ref: opts.ref
|
|
2309
|
-
})
|
|
2310
|
-
|
|
2356
|
+
});
|
|
2357
|
+
return opts.check ? (res.behind?.length ?? 0) === 0 : void 0;
|
|
2358
|
+
}, true)
|
|
2311
2359
|
);
|
|
2312
2360
|
program.command("remove <names...>").description("Remove installed skills").option("--target <list>", "comma list or 'all'").option("--dry-run", "preview without writing").action(
|
|
2313
2361
|
(names, opts) => run(
|
package/package.json
CHANGED