agentskillsdk 0.1.3 → 0.1.4

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/package.json +1 -1
  2. package/src/lib/prompt.js +72 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentskillsdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Install agent skills from agentskills.dk",
5
5
  "type": "module",
6
6
  "bin": {
package/src/lib/prompt.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import chalk from 'chalk';
2
- import { createInterface } from 'node:readline';
3
2
 
4
3
  /**
5
- * Enhanced select prompt with arrow indicator and hints.
4
+ * Interactive select prompt with arrow-key navigation.
5
+ * Up/Down to move, Enter to confirm.
6
6
  *
7
7
  * @param {string} question
8
8
  * @param {{ label: string, hint?: string, value: any }[]} choices
@@ -10,33 +10,81 @@ import { createInterface } from 'node:readline';
10
10
  * @returns {Promise<any>} selected value
11
11
  */
12
12
  export function selectPrompt(question, choices, { defaultIndex = 0 } = {}) {
13
- const rl = createInterface({ input: process.stdin, output: process.stdout });
14
-
15
- console.log(`\n ${question}\n`);
16
- choices.forEach((c, i) => {
17
- const marker = i === defaultIndex ? chalk.cyan('>') : ' ';
18
- const num = `${i + 1})`;
19
- const label = i === defaultIndex ? chalk.cyan(`${num} ${c.label}`) : `${num} ${c.label}`;
20
- const hint = c.hint ? chalk.dim(` ${c.hint}`) : '';
21
- console.log(` ${marker} ${label}${hint}`);
22
- });
13
+ return new Promise((resolve) => {
14
+ let selected = defaultIndex;
15
+ const { stdin, stdout } = process;
23
16
 
24
- const defaultDisplay = defaultIndex + 1;
17
+ function render() {
18
+ // Move cursor up to overwrite previous render (all choice lines + 1 blank line below question)
19
+ // On first render we just printed the question, so we only clear choice lines after that
20
+ const lines = choices.map((c, i) => {
21
+ const marker = i === selected ? chalk.cyan('\u276f') : ' ';
22
+ const label = i === selected ? chalk.cyan(c.label) : c.label;
23
+ const hint = c.hint ? chalk.dim(` ${c.hint}`) : '';
24
+ return ` ${marker} ${label}${hint}`;
25
+ });
26
+ return lines.join('\n');
27
+ }
25
28
 
26
- return new Promise((resolve) => {
27
- rl.question(`\n Choice ${chalk.dim(`[${defaultDisplay}]`)}: `, (answer) => {
28
- rl.close();
29
- const trimmed = answer.trim();
30
- if (trimmed === '') {
31
- resolve(choices[defaultIndex].value);
29
+ // Print question
30
+ stdout.write(`\n ${question}\n\n`);
31
+
32
+ // Initial render
33
+ stdout.write(render());
34
+
35
+ // Enter raw mode for keypress detection
36
+ const wasRaw = stdin.isRaw;
37
+ stdin.setRawMode(true);
38
+ stdin.resume();
39
+
40
+ function onData(buf) {
41
+ const key = buf.toString();
42
+
43
+ // Ctrl+C
44
+ if (key === '\x03') {
45
+ stdin.setRawMode(wasRaw ?? false);
46
+ stdin.removeListener('data', onData);
47
+ stdin.pause();
48
+ stdout.write('\n');
49
+ process.exit(0);
50
+ }
51
+
52
+ // Enter
53
+ if (key === '\r' || key === '\n') {
54
+ stdin.setRawMode(wasRaw ?? false);
55
+ stdin.removeListener('data', onData);
56
+ stdin.pause();
57
+ // Clear the choices and rewrite with final selection
58
+ stdout.write(`\x1b[${choices.length}A`); // move up
59
+ stdout.write('\x1b[J'); // clear to end
60
+ const final = choices.map((c, i) => {
61
+ if (i === selected) {
62
+ return ` ${chalk.cyan('\u276f')} ${chalk.cyan(c.label)}`;
63
+ }
64
+ return '';
65
+ }).filter(Boolean).join('\n');
66
+ stdout.write(final + '\n');
67
+ resolve(choices[selected].value);
32
68
  return;
33
69
  }
34
- const idx = parseInt(trimmed, 10) - 1;
35
- if (idx >= 0 && idx < choices.length) {
36
- resolve(choices[idx].value);
70
+
71
+ // Arrow keys come as escape sequences: \x1b[A (up), \x1b[B (down)
72
+ if (key === '\x1b[A' || key === '\x1b[D') {
73
+ // Up or Left
74
+ selected = (selected - 1 + choices.length) % choices.length;
75
+ } else if (key === '\x1b[B' || key === '\x1b[C') {
76
+ // Down or Right
77
+ selected = (selected + 1) % choices.length;
37
78
  } else {
38
- resolve(choices[defaultIndex].value);
79
+ return; // ignore other keys
39
80
  }
40
- });
81
+
82
+ // Redraw: move cursor up N lines, clear, rewrite
83
+ stdout.write(`\x1b[${choices.length}A`);
84
+ stdout.write('\x1b[J');
85
+ stdout.write(render());
86
+ }
87
+
88
+ stdin.on('data', onData);
41
89
  });
42
90
  }