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.
- package/package.json +1 -1
- package/src/lib/prompt.js +72 -24
package/package.json
CHANGED
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
|
-
*
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
}
|