skild 0.10.13 → 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 +63 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -387,6 +387,24 @@ function truncateVisible(value, maxLen) {
387
387
  }
388
388
  return result;
389
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
+ }
390
408
  function formatTreeNode(node, selection, isCursor, options = {}) {
391
409
  const { state, selectedCount } = selection;
392
410
  const totalCount = node.leafIndices.length;
@@ -399,16 +417,33 @@ function formatTreeNode(node, selection, isCursor, options = {}) {
399
417
  if (totalCount > 1) {
400
418
  count = chalk2.dim(` (${selectedCount}/${totalCount})`);
401
419
  }
402
- const suffix = options.suffix || "";
403
- const hint = isCursor && totalCount > 0 ? chalk2.dim(" (Space to toggle)") : "";
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) : "";
404
424
  const prefix = `${cursorMark}${indent}${checkbox} `;
405
- const suffixWidth = stringWidth(suffix) + stringWidth(hint);
406
425
  const maxWidth = options.maxWidth;
407
426
  if (maxWidth) {
408
- const baseWidth = stringWidth(prefix) + stringWidth(count) + suffixWidth;
409
- const availableForName = Math.max(4, maxWidth - baseWidth);
410
- if (stringWidth(baseName) > availableForName) {
411
- 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);
412
447
  name = isCursor ? chalk2.cyan.underline(truncated) : truncated;
413
448
  }
414
449
  }
@@ -425,11 +460,20 @@ function getSkillDescriptionSuffix(skills, node, isCursor) {
425
460
  if (!skill?.description) return "";
426
461
  const description = truncateDescription(skill.description, 72);
427
462
  if (!description) return "";
428
- return chalk2.dim(` - ${description}`);
463
+ return ` - ${description}`;
429
464
  }
430
465
  function getPlatformDisplay(platform) {
431
466
  return PLATFORM_DISPLAY[platform] || platform;
432
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
+ }
433
477
  async function promptSkillsInteractive(skills, options = {}) {
434
478
  if (skills.length === 0) return null;
435
479
  const targetPlatforms = options.targetPlatforms || [];
@@ -446,25 +490,23 @@ async function promptSkillsInteractive(skills, options = {}) {
446
490
  subtitle: "\u2191\u2193 navigate \u2022 Space toggle \u2022 Enter confirm",
447
491
  buildTree: buildSkillTree,
448
492
  formatNode: (node, selection, isCursor, maxWidth) => {
449
- let installedSuffix = "";
493
+ let installedSuffixText = "";
450
494
  if (node.isLeaf && node.leafIndices.length === 1) {
451
495
  const skill = skills[node.leafIndices[0]];
452
496
  if (skill?.installedPlatforms?.length) {
453
497
  if (skill.installedPlatforms.length === targetPlatforms.length && targetPlatforms.length > 0) {
454
- installedSuffix = chalk2.dim(" [installed]");
498
+ installedSuffixText = " [installed]";
455
499
  } else if (skill.installedPlatforms.length > 0) {
456
- installedSuffix = chalk2.dim(` [installed on ${skill.installedPlatforms.length}]`);
500
+ installedSuffixText = ` [installed on ${skill.installedPlatforms.length}]`;
457
501
  }
458
502
  }
459
503
  }
460
504
  const descriptionSuffix = getSkillDescriptionSuffix(skills, node, isCursor);
461
505
  const formatted = formatTreeNode(node, selection, isCursor, {
462
- suffix: `${installedSuffix}${descriptionSuffix}`,
506
+ suffixText: `${installedSuffixText}${descriptionSuffix}`,
507
+ hintText: buildSpaceHint(node, selection),
463
508
  maxWidth
464
509
  });
465
- if (isCursor && installedSuffix && selection.state !== "all") {
466
- return formatted.replace("\u2190 Space to select", "\u2190 Space to reinstall");
467
- }
468
510
  return formatted;
469
511
  },
470
512
  defaultAll: false,
@@ -487,15 +529,15 @@ async function promptSyncTargetsInteractive(choices) {
487
529
  formatNode: (node, selection, isCursor, maxWidth) => {
488
530
  if (!node.isLeaf && node.depth === 2) {
489
531
  const display = getPlatformDisplay(node.name);
490
- return formatTreeNode({ ...node, name: display }, selection, isCursor, { maxWidth });
532
+ return formatTreeNode({ ...node, name: display }, selection, isCursor, { hintText: buildSpaceHint(node, selection), maxWidth });
491
533
  }
492
534
  if (node.isLeaf && node.leafIndices.length === 1) {
493
535
  const choice = choices[node.leafIndices[0]];
494
536
  const platformLabel = getPlatformDisplay(choice.sourcePlatform);
495
- const suffix = chalk2.dim(` [from ${platformLabel} \xB7 ${choice.sourceTypeLabel}]`);
496
- 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 });
497
539
  }
498
- return formatTreeNode(node, selection, isCursor, { maxWidth });
540
+ return formatTreeNode(node, selection, isCursor, { hintText: buildSpaceHint(node, selection), maxWidth });
499
541
  },
500
542
  defaultAll: true
501
543
  });
@@ -514,7 +556,7 @@ async function promptSkillsTreeInteractive(skills, tree, options = {}) {
514
556
  buildTree: () => buildTreeFromSkillNodes(tree, skills.length),
515
557
  formatNode: (node, selection, isCursor, maxWidth) => {
516
558
  const descriptionSuffix = getSkillDescriptionSuffix(skills, node, isCursor);
517
- return formatTreeNode(node, selection, isCursor, { suffix: descriptionSuffix, maxWidth });
559
+ return formatTreeNode(node, selection, isCursor, { suffixText: descriptionSuffix, hintText: buildSpaceHint(node, selection), maxWidth });
518
560
  },
519
561
  defaultAll: options.defaultAll !== false
520
562
  });
@@ -536,7 +578,7 @@ async function promptPlatformsInteractive(options = {}) {
536
578
  formatNode: (node, selection, isCursor, maxWidth) => {
537
579
  const displayName = node.name === "All Platforms" ? node.name : PLATFORM_DISPLAY[node.name] || node.name;
538
580
  const modifiedNode = { ...node, name: displayName };
539
- return formatTreeNode(modifiedNode, selection, isCursor, { maxWidth });
581
+ return formatTreeNode(modifiedNode, selection, isCursor, { hintText: buildSpaceHint(node, selection), maxWidth });
540
582
  },
541
583
  defaultAll: options.defaultAll !== false
542
584
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.10.13",
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",