skild 0.10.6 → 0.10.8

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 +49 -116
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -86,31 +86,10 @@ var logger = {
86
86
  };
87
87
 
88
88
  // src/utils/interactive-select.ts
89
+ import { checkbox } from "@inquirer/prompts";
89
90
  import readline from "readline";
90
91
  import chalk2 from "chalk";
91
92
  import { PLATFORMS } from "@skild/core";
92
- function buildSkillTree(skills) {
93
- const allNode = createTreeNode("all", "All Skills", 1, false);
94
- for (let i = 0; i < skills.length; i++) {
95
- const relPath = skills[i].relPath;
96
- const parts = relPath === "." ? ["."] : relPath.split("/").filter(Boolean);
97
- allNode.leafIndices.push(i);
98
- let current = allNode;
99
- for (let d = 0; d < parts.length; d++) {
100
- const part = parts[d];
101
- const nodeId = parts.slice(0, d + 1).join("/");
102
- let child = current.children.find((c2) => c2.name === part);
103
- if (!child) {
104
- child = createTreeNode(nodeId, part, d + 2, d === parts.length - 1);
105
- current.children.push(child);
106
- }
107
- child.leafIndices.push(i);
108
- current = child;
109
- }
110
- }
111
- collapseIntermediateNodes(allNode);
112
- return wrapWithRoot(allNode);
113
- }
114
93
  function buildSyncTree(choices) {
115
94
  const root = createTreeNode("root", "All targets", 1, false);
116
95
  const platforms = /* @__PURE__ */ new Map();
@@ -144,56 +123,12 @@ function buildPlatformTree(items) {
144
123
  }
145
124
  return wrapWithRoot(allNode);
146
125
  }
147
- function buildTreeFromSkillNodes(nodes, totalSkills) {
148
- const allNode = createTreeNode("all", "All Skills", 1, false);
149
- const attach = (node, depth) => {
150
- const treeNode = createTreeNode(
151
- node.id,
152
- node.label,
153
- depth,
154
- Boolean(node.skillIndex != null && (!node.children || node.children.length === 0)),
155
- node.skillIndex != null ? [node.skillIndex] : []
156
- );
157
- if (node.children?.length) {
158
- for (const child of node.children) {
159
- const childNode = attach(child, depth + 1);
160
- treeNode.children.push(childNode);
161
- treeNode.leafIndices.push(...childNode.leafIndices);
162
- }
163
- }
164
- return treeNode;
165
- };
166
- for (const node of nodes) {
167
- const childNode = attach(node, 2);
168
- allNode.children.push(childNode);
169
- allNode.leafIndices.push(...childNode.leafIndices);
170
- }
171
- if (allNode.leafIndices.length === 0 && totalSkills > 0) {
172
- for (let i = 0; i < totalSkills; i++) allNode.leafIndices.push(i);
173
- }
174
- return wrapWithRoot(allNode);
175
- }
176
126
  function createTreeNode(id, name, depth, isLeaf, leafIndices = []) {
177
127
  return { id, name, depth, children: [], leafIndices, isLeaf };
178
128
  }
179
129
  function wrapWithRoot(allNode) {
180
130
  return { id: "", name: ".", depth: 0, children: [allNode], leafIndices: [...allNode.leafIndices], isLeaf: false };
181
131
  }
182
- function collapseIntermediateNodes(allNode) {
183
- while (allNode.children.length === 1 && !allNode.children[0].isLeaf && allNode.children[0].children.length > 0) {
184
- const singleChild = allNode.children[0];
185
- for (const grandchild of singleChild.children) {
186
- adjustDepth(grandchild, -1);
187
- }
188
- allNode.children = singleChild.children;
189
- }
190
- }
191
- function adjustDepth(node, delta) {
192
- node.depth += delta;
193
- for (const child of node.children) {
194
- adjustDepth(child, delta);
195
- }
196
- }
197
132
  function flattenTree(root) {
198
133
  const result = [];
199
134
  function walk(node) {
@@ -263,15 +198,19 @@ async function interactiveTreeSelect(items, options) {
263
198
  if (!stdin.isTTY || !stdout.isTTY) {
264
199
  return defaultAll ? Array.from(selected) : null;
265
200
  }
201
+ const useAltScreen = true;
266
202
  const wasRaw = Boolean(stdin.isRaw);
267
203
  stdin.setRawMode(true);
268
204
  stdin.resume();
269
205
  readline.emitKeypressEvents(stdin);
206
+ if (useAltScreen) {
207
+ stdout.write("\x1B[?1049h");
208
+ }
270
209
  const renderer = createRenderer(title, subtitle, flatNodes, selected, () => cursor, formatNode);
271
210
  writeToTerminal(stdout, renderer.renderContent());
272
211
  return new Promise((resolve) => {
273
212
  function cleanup(clear = false) {
274
- if (clear) {
213
+ if (clear && !useAltScreen) {
275
214
  const lineCount = renderer.getLineCount();
276
215
  stdout.write(`\x1B[${lineCount}A`);
277
216
  stdout.write("\x1B[0J");
@@ -280,6 +219,9 @@ async function interactiveTreeSelect(items, options) {
280
219
  stdin.pause();
281
220
  stdin.removeListener("keypress", onKeypress);
282
221
  stdout.write("\x1B[?25h");
222
+ if (useAltScreen) {
223
+ stdout.write("\x1B[?1049l");
224
+ }
283
225
  }
284
226
  function rerender() {
285
227
  clearAndRerender(stdout, renderer.getLineCount(), renderer.renderContent());
@@ -347,7 +289,7 @@ function formatTreeNode(node, selection, isCursor, options = {}) {
347
289
  const { state, selectedCount } = selection;
348
290
  const totalCount = node.leafIndices.length;
349
291
  const indent = " ".repeat(node.depth - 1);
350
- const checkbox = state === "all" ? chalk2.green("\u25CF") : state === "partial" ? chalk2.yellow("\u25D0") : chalk2.dim("\u25CB");
292
+ const checkbox2 = state === "all" ? chalk2.green("\u25CF") : state === "partial" ? chalk2.yellow("\u25D0") : chalk2.dim("\u25CB");
351
293
  const name = isCursor ? chalk2.cyan.underline(node.name) : node.name;
352
294
  const cursorMark = isCursor ? chalk2.cyan("\u203A ") : " ";
353
295
  let count = "";
@@ -359,21 +301,13 @@ function formatTreeNode(node, selection, isCursor, options = {}) {
359
301
  if (isCursor && totalCount > 0) {
360
302
  hint = state === "all" ? chalk2.dim(" \u2190 Space to deselect") : chalk2.dim(" \u2190 Space to select");
361
303
  }
362
- return `${cursorMark}${indent}${checkbox} ${name}${count}${suffix}${hint}`;
304
+ return `${cursorMark}${indent}${checkbox2} ${name}${count}${suffix}${hint}`;
363
305
  }
364
306
  function truncateDescription(value, maxLen) {
365
307
  const trimmed = value.trim();
366
308
  if (trimmed.length <= maxLen) return trimmed;
367
309
  return `${trimmed.slice(0, maxLen - 3).trimEnd()}...`;
368
310
  }
369
- function getSkillDescriptionSuffix(skills, node, isCursor) {
370
- if (!isCursor || !node.isLeaf || node.leafIndices.length !== 1) return "";
371
- const skill = skills[node.leafIndices[0]];
372
- if (!skill?.description) return "";
373
- const description = truncateDescription(skill.description, 72);
374
- if (!description) return "";
375
- return chalk2.dim(` - ${description}`);
376
- }
377
311
  function getPlatformDisplay(platform) {
378
312
  return PLATFORM_DISPLAY[platform] || platform;
379
313
  }
@@ -386,37 +320,27 @@ async function promptSkillsInteractive(skills, options = {}) {
386
320
  const skill = skills[i];
387
321
  const installedOnTargets = skill.installedPlatforms?.filter((p) => targetPlatforms.includes(p)) || [];
388
322
  const isFullyInstalled = hasInstalledCheck && installedOnTargets.length === targetPlatforms.length;
389
- if (options.defaultAll !== false && !isFullyInstalled) {
390
- defaultSelected.add(i);
391
- }
323
+ if (options.defaultAll !== false && !isFullyInstalled) defaultSelected.add(i);
392
324
  }
393
- const selectedIndices = await interactiveTreeSelect(skills, {
394
- title: "Select skills to install",
395
- subtitle: "\u2191\u2193 navigate \u2022 Space toggle \u2022 Enter confirm",
396
- buildTree: buildSkillTree,
397
- formatNode: (node, selection, isCursor) => {
398
- let installedSuffix = "";
399
- if (node.isLeaf && node.leafIndices.length === 1) {
400
- const skill = skills[node.leafIndices[0]];
401
- if (skill?.installedPlatforms?.length) {
402
- if (skill.installedPlatforms.length === targetPlatforms.length && targetPlatforms.length > 0) {
403
- installedSuffix = chalk2.dim(" [installed]");
404
- } else if (skill.installedPlatforms.length > 0) {
405
- installedSuffix = chalk2.dim(` [installed on ${skill.installedPlatforms.length}]`);
406
- }
407
- }
408
- }
409
- const descriptionSuffix = getSkillDescriptionSuffix(skills, node, isCursor);
410
- const formatted = formatTreeNode(node, selection, isCursor, { suffix: `${installedSuffix}${descriptionSuffix}` });
411
- if (isCursor && installedSuffix && selection.state !== "all") {
412
- return formatted.replace("\u2190 Space to select", "\u2190 Space to reinstall");
413
- }
414
- return formatted;
415
- },
416
- defaultAll: false,
417
- defaultSelected
325
+ const choices = skills.map((skill, i) => {
326
+ const base = skill.relPath === "." ? skill.suggestedSource : skill.relPath;
327
+ const desc = skill.description ? ` - ${truncateDescription(skill.description, 72)}` : "";
328
+ let installedSuffix = "";
329
+ if (skill.installedPlatforms?.length) {
330
+ installedSuffix = targetPlatforms.length > 0 && skill.installedPlatforms.length === targetPlatforms.length ? " [installed]" : ` [installed on ${skill.installedPlatforms.length}]`;
331
+ }
332
+ return {
333
+ name: `${base}${installedSuffix ? chalk2.dim(installedSuffix) : ""}${desc ? chalk2.dim(desc) : ""}`,
334
+ value: i,
335
+ checked: defaultSelected.has(i)
336
+ };
337
+ });
338
+ const selectedIndices = await checkbox({
339
+ message: "Select skills to install",
340
+ choices,
341
+ loop: false,
342
+ pageSize: Math.min(20, choices.length)
418
343
  });
419
- if (!selectedIndices) return null;
420
344
  const selectedSkills = selectedIndices.map((i) => skills[i]);
421
345
  const names = selectedSkills.map((s) => s.relPath === "." ? s.suggestedSource : s.relPath);
422
346
  console.log(chalk2.green(`
@@ -454,17 +378,26 @@ async function promptSyncTargetsInteractive(choices) {
454
378
  return selected;
455
379
  }
456
380
  async function promptSkillsTreeInteractive(skills, tree, options = {}) {
457
- const selectedIndices = await interactiveTreeSelect(skills, {
458
- title: "Select skills from markdown",
459
- subtitle: "\u2191\u2193 navigate \u2022 Space toggle \u2022 Enter confirm",
460
- buildTree: () => buildTreeFromSkillNodes(tree, skills.length),
461
- formatNode: (node, selection, isCursor) => {
462
- const descriptionSuffix = getSkillDescriptionSuffix(skills, node, isCursor);
463
- return formatTreeNode(node, selection, isCursor, { suffix: descriptionSuffix });
464
- },
465
- defaultAll: options.defaultAll !== false
381
+ if (skills.length === 0) return null;
382
+ const defaultSelected = /* @__PURE__ */ new Set();
383
+ if (options.defaultAll !== false) {
384
+ for (let i = 0; i < skills.length; i++) defaultSelected.add(i);
385
+ }
386
+ const choices = skills.map((skill, i) => {
387
+ const label = skill.displayName || skill.relPath || skill.suggestedSource;
388
+ const desc = skill.description ? ` - ${truncateDescription(skill.description, 72)}` : "";
389
+ return {
390
+ name: `${label}${desc ? chalk2.dim(desc) : ""}`,
391
+ value: i,
392
+ checked: defaultSelected.has(i)
393
+ };
394
+ });
395
+ const selectedIndices = await checkbox({
396
+ message: "Select skills",
397
+ choices,
398
+ loop: false,
399
+ pageSize: Math.min(20, choices.length)
466
400
  });
467
- if (!selectedIndices) return null;
468
401
  const selectedSkills = selectedIndices.map((i) => skills[i]);
469
402
  const names = selectedSkills.map((s) => s.displayName || s.relPath || s.suggestedSource);
470
403
  console.log(chalk2.green(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.10.6",
3
+ "version": "0.10.8",
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",