skild 0.4.1 → 0.4.3
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/dist/index.js +287 -47
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -128,16 +128,6 @@ async function promptPassword(question) {
|
|
|
128
128
|
stdin.on("keypress", onKeypress);
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
-
async function promptConfirm(question, options = {}) {
|
|
132
|
-
const defaultValue = options.defaultValue ?? false;
|
|
133
|
-
const suffix = defaultValue ? " (Y/n)" : " (y/N)";
|
|
134
|
-
const answer = await promptLine(`${question}${suffix}`);
|
|
135
|
-
const v = answer.trim().toLowerCase();
|
|
136
|
-
if (!v) return defaultValue;
|
|
137
|
-
if (v === "y" || v === "yes") return true;
|
|
138
|
-
if (v === "n" || v === "no") return false;
|
|
139
|
-
return defaultValue;
|
|
140
|
-
}
|
|
141
131
|
|
|
142
132
|
// src/commands/install-discovery.ts
|
|
143
133
|
import fs from "fs";
|
|
@@ -233,10 +223,6 @@ function printJson(value) {
|
|
|
233
223
|
process.stdout.write(`${JSON.stringify(value, null, 2)}
|
|
234
224
|
`);
|
|
235
225
|
}
|
|
236
|
-
function previewDiscovered(found, limit = 12) {
|
|
237
|
-
const preview = found.slice(0, limit).map((s) => ` - ${s.relPath}`).join("\n");
|
|
238
|
-
return `${preview}${found.length > limit ? "\n ..." : ""}`;
|
|
239
|
-
}
|
|
240
226
|
function asDiscoveredSkills(discovered, toSuggestedSource, toMaterializedDir) {
|
|
241
227
|
return discovered.map((d) => ({
|
|
242
228
|
relPath: d.relPath,
|
|
@@ -244,24 +230,258 @@ function asDiscoveredSkills(discovered, toSuggestedSource, toMaterializedDir) {
|
|
|
244
230
|
materializedDir: toMaterializedDir ? toMaterializedDir(d) : void 0
|
|
245
231
|
}));
|
|
246
232
|
}
|
|
233
|
+
function buildSkillTree(found) {
|
|
234
|
+
const root = { id: "", name: ".", children: [], leafIndices: [] };
|
|
235
|
+
const byId = /* @__PURE__ */ new Map([["", root]]);
|
|
236
|
+
for (let i = 0; i < found.length; i += 1) {
|
|
237
|
+
const relPath = found[i].relPath;
|
|
238
|
+
const parts = relPath === "." ? ["."] : relPath.split("/").filter(Boolean);
|
|
239
|
+
let currentId = "";
|
|
240
|
+
let current = root;
|
|
241
|
+
current.leafIndices.push(i);
|
|
242
|
+
for (const part of parts) {
|
|
243
|
+
const nextId = currentId ? `${currentId}/${part}` : part;
|
|
244
|
+
let node = byId.get(nextId);
|
|
245
|
+
if (!node) {
|
|
246
|
+
node = { id: nextId, name: part, children: [], leafIndices: [] };
|
|
247
|
+
byId.set(nextId, node);
|
|
248
|
+
current.children.push(node);
|
|
249
|
+
}
|
|
250
|
+
node.leafIndices.push(i);
|
|
251
|
+
current = node;
|
|
252
|
+
currentId = nextId;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return root;
|
|
256
|
+
}
|
|
257
|
+
function getNodeState(node, selected) {
|
|
258
|
+
const total = node.leafIndices.length;
|
|
259
|
+
if (total === 0) return "none";
|
|
260
|
+
let selectedCount = 0;
|
|
261
|
+
for (const idx of node.leafIndices) {
|
|
262
|
+
if (selected.has(idx)) selectedCount += 1;
|
|
263
|
+
}
|
|
264
|
+
if (selectedCount === 0) return "none";
|
|
265
|
+
if (selectedCount === total) return "all";
|
|
266
|
+
return "partial";
|
|
267
|
+
}
|
|
268
|
+
function renderSkillTree(root, selected) {
|
|
269
|
+
const items = [];
|
|
270
|
+
const stack = [];
|
|
271
|
+
for (let i = root.children.length - 1; i >= 0; i -= 1) {
|
|
272
|
+
stack.push({ node: root.children[i], depth: 0 });
|
|
273
|
+
}
|
|
274
|
+
while (stack.length) {
|
|
275
|
+
const current = stack.pop();
|
|
276
|
+
items.push(current);
|
|
277
|
+
const children = current.node.children;
|
|
278
|
+
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
279
|
+
stack.push({ node: children[i], depth: current.depth + 1 });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return items;
|
|
283
|
+
}
|
|
284
|
+
function parseSelectionInput(input, maxIndex) {
|
|
285
|
+
const trimmed = input.trim().toLowerCase();
|
|
286
|
+
if (!trimmed) return { command: "done" };
|
|
287
|
+
if (["q", "quit", "exit", "cancel"].includes(trimmed)) return { command: "cancel" };
|
|
288
|
+
if (["a", "all"].includes(trimmed)) return { command: "all" };
|
|
289
|
+
if (["n", "none"].includes(trimmed)) return { command: "none" };
|
|
290
|
+
if (["i", "invert"].includes(trimmed)) return { command: "invert" };
|
|
291
|
+
const tokens = trimmed.split(/[,\s]+/).filter(Boolean);
|
|
292
|
+
const indices = [];
|
|
293
|
+
for (const token of tokens) {
|
|
294
|
+
if (/^\d+$/.test(token)) {
|
|
295
|
+
const value = Number(token);
|
|
296
|
+
if (value < 1 || value > maxIndex) return null;
|
|
297
|
+
indices.push(value);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (/^\d+-\d+$/.test(token)) {
|
|
301
|
+
const [startRaw, endRaw] = token.split("-");
|
|
302
|
+
const start = Number(startRaw);
|
|
303
|
+
const end = Number(endRaw);
|
|
304
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 1 || end < 1 || start > maxIndex || end > maxIndex) {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
const from = Math.min(start, end);
|
|
308
|
+
const to = Math.max(start, end);
|
|
309
|
+
for (let i = from; i <= to; i += 1) indices.push(i);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
return { indices };
|
|
315
|
+
}
|
|
316
|
+
async function promptSkillSelection(found, options) {
|
|
317
|
+
const root = buildSkillTree(found);
|
|
318
|
+
const selected = /* @__PURE__ */ new Set();
|
|
319
|
+
if (options.defaultAll) {
|
|
320
|
+
for (let i = 0; i < found.length; i += 1) selected.add(i);
|
|
321
|
+
}
|
|
322
|
+
while (true) {
|
|
323
|
+
console.log(chalk2.cyan("\nSelect skills to install"));
|
|
324
|
+
console.log(chalk2.dim("Toggle by number. Commands: a=all, n=none, i=invert, enter=continue, q=cancel."));
|
|
325
|
+
const display = renderSkillTree(root, selected);
|
|
326
|
+
for (let i = 0; i < display.length; i += 1) {
|
|
327
|
+
const item = display[i];
|
|
328
|
+
const state = getNodeState(item.node, selected);
|
|
329
|
+
const box = state === "all" ? "[x]" : state === "partial" ? "[-]" : "[ ]";
|
|
330
|
+
const indent = " ".repeat(item.depth);
|
|
331
|
+
const idx = String(i + 1).padStart(2, " ");
|
|
332
|
+
console.log(`${idx} ${box} ${indent}${item.node.name}`);
|
|
333
|
+
}
|
|
334
|
+
const answer = await promptLine("Selection");
|
|
335
|
+
const parsed = parseSelectionInput(answer, display.length);
|
|
336
|
+
if (!parsed) {
|
|
337
|
+
console.log(chalk2.yellow('Invalid selection. Use numbers like "1,3-5" or a/n/i.'));
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (parsed.command === "done") break;
|
|
341
|
+
if (parsed.command === "cancel") return null;
|
|
342
|
+
if (parsed.command === "all") {
|
|
343
|
+
selected.clear();
|
|
344
|
+
for (let i = 0; i < found.length; i += 1) selected.add(i);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (parsed.command === "none") {
|
|
348
|
+
selected.clear();
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (parsed.command === "invert") {
|
|
352
|
+
const next = /* @__PURE__ */ new Set();
|
|
353
|
+
for (let i = 0; i < found.length; i += 1) {
|
|
354
|
+
if (!selected.has(i)) next.add(i);
|
|
355
|
+
}
|
|
356
|
+
selected.clear();
|
|
357
|
+
for (const idx of next) selected.add(idx);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (parsed.indices) {
|
|
361
|
+
for (const index of parsed.indices) {
|
|
362
|
+
const item = display[index - 1];
|
|
363
|
+
if (!item) continue;
|
|
364
|
+
const state = getNodeState(item.node, selected);
|
|
365
|
+
if (state === "all") {
|
|
366
|
+
for (const leaf of item.node.leafIndices) selected.delete(leaf);
|
|
367
|
+
} else {
|
|
368
|
+
for (const leaf of item.node.leafIndices) selected.add(leaf);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (selected.size === 0) return null;
|
|
374
|
+
const selectedFound = [];
|
|
375
|
+
for (let i = 0; i < found.length; i += 1) {
|
|
376
|
+
if (selected.has(i)) selectedFound.push(found[i]);
|
|
377
|
+
}
|
|
378
|
+
return selectedFound;
|
|
379
|
+
}
|
|
380
|
+
async function promptPlatformSelection(defaultAll) {
|
|
381
|
+
const selected = /* @__PURE__ */ new Set();
|
|
382
|
+
if (defaultAll) {
|
|
383
|
+
for (let i = 0; i < PLATFORMS.length; i += 1) selected.add(i);
|
|
384
|
+
}
|
|
385
|
+
while (true) {
|
|
386
|
+
console.log(chalk2.cyan("\nSelect platforms to install to"));
|
|
387
|
+
console.log(chalk2.dim("Toggle by number. Commands: a=all, n=none, i=invert, enter=continue, q=cancel."));
|
|
388
|
+
for (let i = 0; i < PLATFORMS.length; i += 1) {
|
|
389
|
+
const label = PLATFORMS[i];
|
|
390
|
+
const box = selected.has(i) ? "[x]" : "[ ]";
|
|
391
|
+
const idx = String(i + 1).padStart(2, " ");
|
|
392
|
+
console.log(`${idx} ${box} ${label}`);
|
|
393
|
+
}
|
|
394
|
+
const answer = await promptLine("Selection");
|
|
395
|
+
const parsed = parseSelectionInput(answer, PLATFORMS.length);
|
|
396
|
+
if (!parsed) {
|
|
397
|
+
console.log(chalk2.yellow('Invalid selection. Use numbers like "1,3-5" or a/n/i.'));
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (parsed.command === "done") break;
|
|
401
|
+
if (parsed.command === "cancel") return null;
|
|
402
|
+
if (parsed.command === "all") {
|
|
403
|
+
selected.clear();
|
|
404
|
+
for (let i = 0; i < PLATFORMS.length; i += 1) selected.add(i);
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
if (parsed.command === "none") {
|
|
408
|
+
selected.clear();
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
if (parsed.command === "invert") {
|
|
412
|
+
const next = /* @__PURE__ */ new Set();
|
|
413
|
+
for (let i = 0; i < PLATFORMS.length; i += 1) {
|
|
414
|
+
if (!selected.has(i)) next.add(i);
|
|
415
|
+
}
|
|
416
|
+
selected.clear();
|
|
417
|
+
for (const idx of next) selected.add(idx);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (parsed.indices) {
|
|
421
|
+
for (const index of parsed.indices) {
|
|
422
|
+
const idx = index - 1;
|
|
423
|
+
if (idx < 0 || idx >= PLATFORMS.length) continue;
|
|
424
|
+
if (selected.has(idx)) selected.delete(idx);
|
|
425
|
+
else selected.add(idx);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (selected.size === 0) return null;
|
|
430
|
+
const chosen = [];
|
|
431
|
+
for (let i = 0; i < PLATFORMS.length; i += 1) {
|
|
432
|
+
if (selected.has(i)) chosen.push(PLATFORMS[i]);
|
|
433
|
+
}
|
|
434
|
+
return chosen;
|
|
435
|
+
}
|
|
436
|
+
function printSelectedSkills(found) {
|
|
437
|
+
const names = found.map((skill) => skill.relPath);
|
|
438
|
+
if (names.length === 0) return;
|
|
439
|
+
const preview = names.slice(0, 20).map((name) => ` - ${name}`).join("\n");
|
|
440
|
+
console.log(chalk2.dim(`
|
|
441
|
+
Selected skills (${names.length}):`));
|
|
442
|
+
console.log(preview);
|
|
443
|
+
if (names.length > 20) {
|
|
444
|
+
console.log(chalk2.dim(` ... and ${names.length - 20} more`));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
247
447
|
async function install(source, options = {}) {
|
|
248
448
|
const scope = options.local ? "project" : "global";
|
|
249
449
|
const auth = loadRegistryAuth();
|
|
250
450
|
const registryUrlForDeps = options.registry || auth?.registryUrl;
|
|
251
|
-
const all = Boolean(options.all);
|
|
252
451
|
const jsonOnly = Boolean(options.json);
|
|
253
452
|
const recursive = Boolean(options.recursive);
|
|
254
453
|
const yes = Boolean(options.yes);
|
|
255
454
|
const maxDepth = parsePositiveInt(options.depth, 6);
|
|
256
455
|
const maxSkills = parsePositiveInt(options.maxSkills, 200);
|
|
257
|
-
const
|
|
258
|
-
|
|
456
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !jsonOnly;
|
|
457
|
+
const requestedAll = Boolean(options.all);
|
|
458
|
+
const requestedTarget = options.target;
|
|
459
|
+
if (requestedAll && options.target) {
|
|
259
460
|
const message = "Invalid options: use either --all or --target, not both.";
|
|
260
461
|
if (jsonOnly) printJson({ ok: false, error: message });
|
|
261
462
|
else console.error(chalk2.red(message));
|
|
262
463
|
process.exitCode = 1;
|
|
263
464
|
return;
|
|
264
465
|
}
|
|
466
|
+
let targets = [];
|
|
467
|
+
if (requestedAll) {
|
|
468
|
+
targets = [...PLATFORMS];
|
|
469
|
+
} else if (requestedTarget) {
|
|
470
|
+
targets = [requestedTarget];
|
|
471
|
+
} else if (yes) {
|
|
472
|
+
targets = [...PLATFORMS];
|
|
473
|
+
} else if (interactive) {
|
|
474
|
+
const selectedTargets = await promptPlatformSelection(true);
|
|
475
|
+
if (!selectedTargets) {
|
|
476
|
+
console.error(chalk2.red("No platforms selected."));
|
|
477
|
+
process.exitCode = 1;
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
targets = selectedTargets;
|
|
481
|
+
} else {
|
|
482
|
+
targets = ["claude"];
|
|
483
|
+
}
|
|
484
|
+
const allPlatformsSelected = targets.length === PLATFORMS.length;
|
|
265
485
|
let resolvedSource = source.trim();
|
|
266
486
|
try {
|
|
267
487
|
if (looksLikeAlias(resolvedSource)) {
|
|
@@ -277,12 +497,10 @@ async function install(source, options = {}) {
|
|
|
277
497
|
process.exitCode = 1;
|
|
278
498
|
return;
|
|
279
499
|
}
|
|
280
|
-
const targets = all ? [...PLATFORMS] : [platform];
|
|
281
500
|
const results = [];
|
|
282
501
|
const errors = [];
|
|
283
502
|
let effectiveRecursive = recursive;
|
|
284
503
|
let recursiveSkillCount = null;
|
|
285
|
-
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !jsonOnly;
|
|
286
504
|
async function installOne(inputSource, materializedDir) {
|
|
287
505
|
for (const targetPlatform of targets) {
|
|
288
506
|
try {
|
|
@@ -301,14 +519,14 @@ async function install(source, options = {}) {
|
|
|
301
519
|
}
|
|
302
520
|
}
|
|
303
521
|
}
|
|
304
|
-
async function
|
|
305
|
-
if (found.length === 0) return
|
|
522
|
+
async function resolveDiscoveredSelection(found, spinner) {
|
|
523
|
+
if (found.length === 0) return null;
|
|
306
524
|
if (found.length > maxSkills) {
|
|
307
525
|
const message = `Found more than ${maxSkills} skills. Increase --max-skills to proceed.`;
|
|
308
526
|
if (jsonOnly) printJson({ ok: false, error: "TOO_MANY_SKILLS", message, source, resolvedSource, maxSkills });
|
|
309
527
|
else console.error(chalk2.red(message));
|
|
310
528
|
process.exitCode = 1;
|
|
311
|
-
return
|
|
529
|
+
return null;
|
|
312
530
|
}
|
|
313
531
|
if (!effectiveRecursive) {
|
|
314
532
|
if (jsonOnly) {
|
|
@@ -322,29 +540,39 @@ async function install(source, options = {}) {
|
|
|
322
540
|
found: foundOutput
|
|
323
541
|
});
|
|
324
542
|
process.exitCode = 1;
|
|
325
|
-
return
|
|
543
|
+
return null;
|
|
326
544
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
` : `No SKILL.md found at root. Found ${found.length} skills
|
|
330
|
-
${previewDiscovered(found)}
|
|
545
|
+
if (spinner) spinner.stop();
|
|
546
|
+
const headline = found.length === 1 ? `No SKILL.md found at root. Found 1 skill.
|
|
547
|
+
` : `No SKILL.md found at root. Found ${found.length} skills.
|
|
331
548
|
`;
|
|
332
549
|
console.log(chalk2.yellow(headline));
|
|
333
|
-
|
|
334
|
-
const confirm = yes || interactive && await promptConfirm(question, { defaultValue: found.length === 1 });
|
|
335
|
-
if (!confirm) {
|
|
550
|
+
if (!interactive && !yes) {
|
|
336
551
|
console.log(chalk2.dim(`Tip: rerun with ${chalk2.cyan("skild install <source> --recursive")} to install all.`));
|
|
337
552
|
process.exitCode = 1;
|
|
338
|
-
return
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
if (!yes) {
|
|
556
|
+
const selected = await promptSkillSelection(found, { defaultAll: true });
|
|
557
|
+
if (!selected) {
|
|
558
|
+
console.log(chalk2.red("No skills selected."));
|
|
559
|
+
process.exitCode = 1;
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
printSelectedSkills(selected);
|
|
563
|
+
effectiveRecursive = true;
|
|
564
|
+
if (spinner) spinner.start();
|
|
565
|
+
recursiveSkillCount = selected.length;
|
|
566
|
+
return selected;
|
|
339
567
|
}
|
|
340
568
|
effectiveRecursive = true;
|
|
341
569
|
}
|
|
342
570
|
recursiveSkillCount = found.length;
|
|
343
|
-
return
|
|
571
|
+
return found;
|
|
344
572
|
}
|
|
345
573
|
try {
|
|
346
574
|
const spinner = jsonOnly ? null : createSpinner(
|
|
347
|
-
|
|
575
|
+
allPlatformsSelected ? `Installing ${chalk2.cyan(source)} to ${chalk2.dim("all platforms")} (${scope})...` : targets.length > 1 ? `Installing ${chalk2.cyan(source)} to ${chalk2.dim(`${targets.length} platforms`)} (${scope})...` : `Installing ${chalk2.cyan(source)} to ${chalk2.dim(targets[0])} (${scope})...`
|
|
348
576
|
);
|
|
349
577
|
let cleanupMaterialized = null;
|
|
350
578
|
let materializedRoot = null;
|
|
@@ -365,16 +593,17 @@ ${previewDiscovered(found)}
|
|
|
365
593
|
if (jsonOnly) {
|
|
366
594
|
printJson({ ok: false, error: "SKILL_MD_NOT_FOUND", message, source, resolvedSource });
|
|
367
595
|
} else {
|
|
596
|
+
if (spinner) spinner.stop();
|
|
368
597
|
console.error(chalk2.red(message));
|
|
369
598
|
}
|
|
370
599
|
process.exitCode = 1;
|
|
371
600
|
return;
|
|
372
601
|
}
|
|
373
602
|
const found = asDiscoveredSkills(discovered, (d) => path2.join(maybeLocalRoot, d.relPath));
|
|
374
|
-
const
|
|
375
|
-
if (
|
|
376
|
-
if (spinner) spinner.text = `Installing ${chalk2.cyan(source)} \u2014 discovered ${
|
|
377
|
-
for (const skill of
|
|
603
|
+
const selected = await resolveDiscoveredSelection(found, spinner);
|
|
604
|
+
if (!selected) return;
|
|
605
|
+
if (spinner) spinner.text = `Installing ${chalk2.cyan(source)} \u2014 discovered ${selected.length} skills...`;
|
|
606
|
+
for (const skill of selected) {
|
|
378
607
|
if (spinner) spinner.text = `Installing ${chalk2.cyan(skill.relPath)} (${scope})...`;
|
|
379
608
|
await installOne(skill.suggestedSource, skill.materializedDir);
|
|
380
609
|
}
|
|
@@ -393,6 +622,7 @@ ${previewDiscovered(found)}
|
|
|
393
622
|
if (jsonOnly) {
|
|
394
623
|
printJson({ ok: false, error: "SKILL_MD_NOT_FOUND", message, source, resolvedSource });
|
|
395
624
|
} else {
|
|
625
|
+
if (spinner) spinner.stop();
|
|
396
626
|
console.error(chalk2.red(message));
|
|
397
627
|
}
|
|
398
628
|
process.exitCode = 1;
|
|
@@ -403,10 +633,10 @@ ${previewDiscovered(found)}
|
|
|
403
633
|
(d) => deriveChildSource(resolvedSource, d.relPath),
|
|
404
634
|
(d) => d.absDir
|
|
405
635
|
);
|
|
406
|
-
const
|
|
407
|
-
if (
|
|
408
|
-
if (spinner) spinner.text = `Installing ${chalk2.cyan(source)} \u2014 discovered ${
|
|
409
|
-
for (const skill of
|
|
636
|
+
const selected = await resolveDiscoveredSelection(found, spinner);
|
|
637
|
+
if (!selected) return;
|
|
638
|
+
if (spinner) spinner.text = `Installing ${chalk2.cyan(source)} \u2014 discovered ${selected.length} skills...`;
|
|
639
|
+
for (const skill of selected) {
|
|
410
640
|
if (spinner) spinner.text = `Installing ${chalk2.cyan(skill.relPath)} (${scope})...`;
|
|
411
641
|
await installOne(skill.suggestedSource, skill.materializedDir);
|
|
412
642
|
}
|
|
@@ -417,11 +647,21 @@ ${previewDiscovered(found)}
|
|
|
417
647
|
if (cleanupMaterialized) cleanupMaterialized();
|
|
418
648
|
}
|
|
419
649
|
if (jsonOnly) {
|
|
420
|
-
if (!
|
|
650
|
+
if (!effectiveRecursive && targets.length === 1) {
|
|
421
651
|
if (errors.length) printJson({ ok: false, error: errors[0]?.error || "Install failed." });
|
|
422
652
|
else printJson(results[0] ?? null);
|
|
423
653
|
} else {
|
|
424
|
-
printJson({
|
|
654
|
+
printJson({
|
|
655
|
+
ok: errors.length === 0,
|
|
656
|
+
source,
|
|
657
|
+
resolvedSource,
|
|
658
|
+
scope,
|
|
659
|
+
recursive: effectiveRecursive,
|
|
660
|
+
all: allPlatformsSelected,
|
|
661
|
+
recursiveSkillCount,
|
|
662
|
+
results,
|
|
663
|
+
errors
|
|
664
|
+
});
|
|
425
665
|
}
|
|
426
666
|
process.exitCode = errors.length ? 1 : 0;
|
|
427
667
|
return;
|
|
@@ -429,7 +669,7 @@ ${previewDiscovered(found)}
|
|
|
429
669
|
if (errors.length === 0) {
|
|
430
670
|
const displayName = results[0]?.canonicalName || results[0]?.name || source;
|
|
431
671
|
spinner.succeed(
|
|
432
|
-
effectiveRecursive ? `Installed ${chalk2.green(String(recursiveSkillCount ?? results.length))}${chalk2.dim(" skills")} to ${chalk2.dim(`${targets.length} platforms`)}` :
|
|
672
|
+
effectiveRecursive ? `Installed ${chalk2.green(String(recursiveSkillCount ?? results.length))}${chalk2.dim(" skills")} to ${chalk2.dim(`${targets.length} platforms`)}` : targets.length > 1 ? `Installed ${chalk2.green(displayName)} to ${chalk2.dim(`${results.length} platforms`)}` : `Installed ${chalk2.green(displayName)} to ${chalk2.dim(results[0]?.installDir || "")}`
|
|
433
673
|
);
|
|
434
674
|
} else {
|
|
435
675
|
const attempted = results.length + errors.length;
|
|
@@ -437,9 +677,9 @@ ${previewDiscovered(found)}
|
|
|
437
677
|
effectiveRecursive ? `Install had failures (${errors.length}/${attempted} installs failed)` : `Failed to install ${chalk2.red(source)} to ${errors.length}/${targets.length} platforms`
|
|
438
678
|
);
|
|
439
679
|
process.exitCode = 1;
|
|
440
|
-
if (!
|
|
680
|
+
if (!effectiveRecursive && targets.length === 1 && errors[0]) console.error(chalk2.red(errors[0].error));
|
|
441
681
|
}
|
|
442
|
-
if (!effectiveRecursive &&
|
|
682
|
+
if (!effectiveRecursive && targets.length === 1 && results[0]) {
|
|
443
683
|
const record = results[0];
|
|
444
684
|
if (record.hasSkillMd) logger.installDetail("SKILL.md found \u2713");
|
|
445
685
|
else logger.installDetail("Warning: No SKILL.md found", true);
|
|
@@ -448,7 +688,7 @@ ${previewDiscovered(found)}
|
|
|
448
688
|
} else if (record.skill?.validation?.ok) {
|
|
449
689
|
logger.installDetail(`Validation: ${chalk2.green("ok")}`);
|
|
450
690
|
}
|
|
451
|
-
} else if (effectiveRecursive ||
|
|
691
|
+
} else if (effectiveRecursive || targets.length > 1) {
|
|
452
692
|
for (const r of results.slice(0, 60)) {
|
|
453
693
|
const displayName = r.canonicalName || r.name;
|
|
454
694
|
const suffix = r.hasSkillMd ? chalk2.green("\u2713") : chalk2.yellow("\u26A0");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skild",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "The npm for Agent Skills — Discover, install, manage, and publish AI Agent Skills with ease.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"commander": "^12.1.0",
|
|
38
38
|
"ora": "^8.0.1",
|
|
39
39
|
"tar": "^7.4.3",
|
|
40
|
-
"@skild/core": "^0.4.
|
|
40
|
+
"@skild/core": "^0.4.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^20.10.0",
|