skild 0.10.12 → 0.10.14

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.
Files changed (2) hide show
  1. package/dist/index.js +67 -24
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -313,10 +313,11 @@ async function interactiveTreeSelect(items, options) {
313
313
  }
314
314
  function toggleNode(node) {
315
315
  const { state } = getNodeSelection(node, selected);
316
- if (state === "all") {
317
- for (const idx of node.leafIndices) selected.delete(idx);
318
- } else {
316
+ const shouldSelectAll = state !== "all";
317
+ if (shouldSelectAll) {
319
318
  for (const idx of node.leafIndices) selected.add(idx);
319
+ } else {
320
+ for (const idx of node.leafIndices) selected.delete(idx);
320
321
  }
321
322
  }
322
323
  function toggleAll() {
@@ -386,6 +387,24 @@ function truncateVisible(value, maxLen) {
386
387
  }
387
388
  return result;
388
389
  }
390
+ function truncateMiddleVisible(value, maxLen) {
391
+ if (stringWidth(value) <= maxLen) return value;
392
+ if (maxLen <= 1) return "\u2026";
393
+ const leftMax = Math.max(1, Math.floor((maxLen - 1) / 2));
394
+ const rightMax = Math.max(1, maxLen - 1 - leftMax);
395
+ const left = truncateVisible(value, leftMax).replace(/…$/, "");
396
+ let width = 0;
397
+ let right = "";
398
+ for (let i = value.length - 1; i >= 0; i--) {
399
+ const ch = value[i];
400
+ const w = stringWidth(ch);
401
+ if (width + w > rightMax) break;
402
+ width += w;
403
+ right = ch + right;
404
+ }
405
+ if (!right) right = value[value.length - 1] || "";
406
+ return `${left}\u2026${right}`;
407
+ }
389
408
  function formatTreeNode(node, selection, isCursor, options = {}) {
390
409
  const { state, selectedCount } = selection;
391
410
  const totalCount = node.leafIndices.length;
@@ -398,16 +417,33 @@ function formatTreeNode(node, selection, isCursor, options = {}) {
398
417
  if (totalCount > 1) {
399
418
  count = chalk2.dim(` (${selectedCount}/${totalCount})`);
400
419
  }
401
- const suffix = options.suffix || "";
402
- const hint = "";
420
+ let rawSuffix = options.suffixText || "";
421
+ let rawHint = isCursor ? options.hintText || "" : "";
422
+ let hint = rawHint ? chalk2.dim(rawHint) : "";
423
+ let suffix = rawSuffix ? chalk2.dim(rawSuffix) : "";
403
424
  const prefix = `${cursorMark}${indent}${checkbox} `;
404
- const suffixWidth = stringWidth(suffix) + stringWidth(hint);
405
425
  const maxWidth = options.maxWidth;
406
426
  if (maxWidth) {
407
- const baseWidth = stringWidth(prefix) + stringWidth(count) + suffixWidth;
408
- const availableForName = Math.max(4, maxWidth - baseWidth);
409
- if (stringWidth(baseName) > availableForName) {
410
- const truncated = truncateVisible(baseName, availableForName);
427
+ const fixedWidth = stringWidth(prefix) + stringWidth(count);
428
+ const fits = (n, s, h) => {
429
+ const nStyled = isCursor ? chalk2.cyan.underline(n) : n;
430
+ const sStyled = s ? chalk2.dim(s) : "";
431
+ const hStyled = h ? chalk2.dim(h) : "";
432
+ return stringWidth(`${prefix}${nStyled}${count}${sStyled}${hStyled}`) <= maxWidth;
433
+ };
434
+ if (rawSuffix && !fits(baseName, rawSuffix, rawHint)) {
435
+ const available = Math.max(1, maxWidth - fixedWidth - stringWidth(baseName) - stringWidth(rawHint));
436
+ rawSuffix = truncateVisible(rawSuffix, available);
437
+ suffix = chalk2.dim(rawSuffix);
438
+ }
439
+ if (rawHint && !fits(baseName, rawSuffix, rawHint)) {
440
+ const available = Math.max(1, maxWidth - fixedWidth - stringWidth(baseName) - stringWidth(rawSuffix));
441
+ rawHint = truncateVisible(rawHint, available);
442
+ hint = chalk2.dim(rawHint);
443
+ }
444
+ if (!fits(baseName, rawSuffix, rawHint)) {
445
+ const available = Math.max(1, maxWidth - fixedWidth - stringWidth(rawSuffix) - stringWidth(rawHint));
446
+ const truncated = truncateMiddleVisible(baseName, available);
411
447
  name = isCursor ? chalk2.cyan.underline(truncated) : truncated;
412
448
  }
413
449
  }
@@ -424,11 +460,20 @@ function getSkillDescriptionSuffix(skills, node, isCursor) {
424
460
  if (!skill?.description) return "";
425
461
  const description = truncateDescription(skill.description, 72);
426
462
  if (!description) return "";
427
- return chalk2.dim(` - ${description}`);
463
+ return ` - ${description}`;
428
464
  }
429
465
  function getPlatformDisplay(platform) {
430
466
  return PLATFORM_DISPLAY[platform] || platform;
431
467
  }
468
+ function buildSpaceHint(node, selection) {
469
+ const totalCount = node.leafIndices.length;
470
+ if (totalCount <= 0) return "";
471
+ const isLeaf = Boolean(node.isLeaf && node.leafIndices.length === 1);
472
+ if (selection.state === "all") {
473
+ return isLeaf ? " (Space: unselect)" : " (Space: unselect all)";
474
+ }
475
+ return isLeaf ? " (Space: select)" : " (Space: select all)";
476
+ }
432
477
  async function promptSkillsInteractive(skills, options = {}) {
433
478
  if (skills.length === 0) return null;
434
479
  const targetPlatforms = options.targetPlatforms || [];
@@ -445,25 +490,23 @@ async function promptSkillsInteractive(skills, options = {}) {
445
490
  subtitle: "\u2191\u2193 navigate \u2022 Space toggle \u2022 Enter confirm",
446
491
  buildTree: buildSkillTree,
447
492
  formatNode: (node, selection, isCursor, maxWidth) => {
448
- let installedSuffix = "";
493
+ let installedSuffixText = "";
449
494
  if (node.isLeaf && node.leafIndices.length === 1) {
450
495
  const skill = skills[node.leafIndices[0]];
451
496
  if (skill?.installedPlatforms?.length) {
452
497
  if (skill.installedPlatforms.length === targetPlatforms.length && targetPlatforms.length > 0) {
453
- installedSuffix = chalk2.dim(" [installed]");
498
+ installedSuffixText = " [installed]";
454
499
  } else if (skill.installedPlatforms.length > 0) {
455
- installedSuffix = chalk2.dim(` [installed on ${skill.installedPlatforms.length}]`);
500
+ installedSuffixText = ` [installed on ${skill.installedPlatforms.length}]`;
456
501
  }
457
502
  }
458
503
  }
459
504
  const descriptionSuffix = getSkillDescriptionSuffix(skills, node, isCursor);
460
505
  const formatted = formatTreeNode(node, selection, isCursor, {
461
- suffix: `${installedSuffix}${descriptionSuffix}`,
506
+ suffixText: `${installedSuffixText}${descriptionSuffix}`,
507
+ hintText: buildSpaceHint(node, selection),
462
508
  maxWidth
463
509
  });
464
- if (isCursor && installedSuffix && selection.state !== "all") {
465
- return formatted.replace("\u2190 Space to select", "\u2190 Space to reinstall");
466
- }
467
510
  return formatted;
468
511
  },
469
512
  defaultAll: false,
@@ -486,15 +529,15 @@ async function promptSyncTargetsInteractive(choices) {
486
529
  formatNode: (node, selection, isCursor, maxWidth) => {
487
530
  if (!node.isLeaf && node.depth === 2) {
488
531
  const display = getPlatformDisplay(node.name);
489
- return formatTreeNode({ ...node, name: display }, selection, isCursor, { maxWidth });
532
+ return formatTreeNode({ ...node, name: display }, selection, isCursor, { hintText: buildSpaceHint(node, selection), maxWidth });
490
533
  }
491
534
  if (node.isLeaf && node.leafIndices.length === 1) {
492
535
  const choice = choices[node.leafIndices[0]];
493
536
  const platformLabel = getPlatformDisplay(choice.sourcePlatform);
494
- const suffix = chalk2.dim(` [from ${platformLabel} \xB7 ${choice.sourceTypeLabel}]`);
495
- return formatTreeNode(node, selection, isCursor, { suffix, maxWidth });
537
+ const suffixText = ` [from ${platformLabel} \xB7 ${choice.sourceTypeLabel}]`;
538
+ return formatTreeNode(node, selection, isCursor, { suffixText, hintText: buildSpaceHint(node, selection), maxWidth });
496
539
  }
497
- return formatTreeNode(node, selection, isCursor, { maxWidth });
540
+ return formatTreeNode(node, selection, isCursor, { hintText: buildSpaceHint(node, selection), maxWidth });
498
541
  },
499
542
  defaultAll: true
500
543
  });
@@ -513,7 +556,7 @@ async function promptSkillsTreeInteractive(skills, tree, options = {}) {
513
556
  buildTree: () => buildTreeFromSkillNodes(tree, skills.length),
514
557
  formatNode: (node, selection, isCursor, maxWidth) => {
515
558
  const descriptionSuffix = getSkillDescriptionSuffix(skills, node, isCursor);
516
- return formatTreeNode(node, selection, isCursor, { suffix: descriptionSuffix, maxWidth });
559
+ return formatTreeNode(node, selection, isCursor, { suffixText: descriptionSuffix, hintText: buildSpaceHint(node, selection), maxWidth });
517
560
  },
518
561
  defaultAll: options.defaultAll !== false
519
562
  });
@@ -535,7 +578,7 @@ async function promptPlatformsInteractive(options = {}) {
535
578
  formatNode: (node, selection, isCursor, maxWidth) => {
536
579
  const displayName = node.name === "All Platforms" ? node.name : PLATFORM_DISPLAY[node.name] || node.name;
537
580
  const modifiedNode = { ...node, name: displayName };
538
- return formatTreeNode(modifiedNode, selection, isCursor, { maxWidth });
581
+ return formatTreeNode(modifiedNode, selection, isCursor, { hintText: buildSpaceHint(node, selection), maxWidth });
539
582
  },
540
583
  defaultAll: options.defaultAll !== false
541
584
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.10.12",
3
+ "version": "0.10.14",
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",