agentskillsdk 0.1.4 → 0.1.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentskillsdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Install agent skills from agentskills.dk",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,7 +38,7 @@ export async function addCommand(skillName, options) {
38
38
  (options.skill ? ` (skill: ${chalk.bold(options.skill)})` : ''));
39
39
  } else {
40
40
  installName = skillName;
41
- const spinner = ora({ text: `Looking up ${chalk.bold(skillName)}...`, indent: 2 }).start();
41
+ const spinner = ora({ text: `Looking up ${chalk.bold(skillName)}...`, indent: 4 }).start();
42
42
  try {
43
43
  skill = await fetchSkill(skillName);
44
44
  } catch (err) {
@@ -85,14 +85,14 @@ export async function addCommand(skillName, options) {
85
85
  scope = 'project';
86
86
  } else {
87
87
  scope = await selectPrompt('Install scope:', [
88
- { label: 'Project', hint: '(.claude/skills/ in current directory)', value: 'project' },
89
- { label: 'Global', hint: '(~/.claude/skills/ for all projects)', value: 'global' },
88
+ { label: 'Project', hint: '(local .claude/skills/)', value: 'project' },
89
+ { label: 'Global', hint: '(~/.claude/skills/)', value: 'global' },
90
90
  ]);
91
91
  }
92
92
 
93
93
  // --- download ---
94
94
  const destDir = agent.path(installName, { cwd, scope });
95
- const spinner = ora({ text: 'Downloading skill files...', indent: 2 }).start();
95
+ const spinner = ora({ text: 'Downloading skill files...', indent: 4 }).start();
96
96
  try {
97
97
  await downloadSkill(skill, destDir);
98
98
  } catch (err) {
package/src/lib/prompt.js CHANGED
@@ -1,5 +1,12 @@
1
1
  import chalk from 'chalk';
2
2
 
3
+ // --- strip ANSI for width calculation ---
4
+
5
+ const ANSI_RE = /\x1b\[[0-9;]*m/g;
6
+ function stripAnsi(str) {
7
+ return str.replace(ANSI_RE, '');
8
+ }
9
+
3
10
  /**
4
11
  * Interactive select prompt with arrow-key navigation.
5
12
  * Up/Down to move, Enter to confirm.
@@ -13,57 +20,70 @@ export function selectPrompt(question, choices, { defaultIndex = 0 } = {}) {
13
20
  return new Promise((resolve) => {
14
21
  let selected = defaultIndex;
15
22
  const { stdin, stdout } = process;
23
+ const cols = stdout.columns || 80;
24
+
25
+ /** Count how many physical terminal lines a string occupies. */
26
+ function physicalLines(str) {
27
+ const w = stripAnsi(str).length;
28
+ return Math.max(1, Math.ceil(w / cols));
29
+ }
30
+
31
+ /** Total physical lines used by the rendered choices. */
32
+ function totalPhysicalLines(lines) {
33
+ return lines.reduce((sum, l) => sum + physicalLines(l), 0);
34
+ }
16
35
 
17
36
  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) => {
37
+ return choices.map((c, i) => {
21
38
  const marker = i === selected ? chalk.cyan('\u276f') : ' ';
22
39
  const label = i === selected ? chalk.cyan(c.label) : c.label;
23
40
  const hint = c.hint ? chalk.dim(` ${c.hint}`) : '';
24
- return ` ${marker} ${label}${hint}`;
41
+ return ` ${marker} ${label}${hint}`;
25
42
  });
26
- return lines.join('\n');
27
43
  }
28
44
 
29
- // Print question
30
- stdout.write(`\n ${question}\n\n`);
45
+ // Hide cursor
46
+ stdout.write('\x1b[?25l');
47
+
48
+ // Print question (4-space indent)
49
+ stdout.write(`\n ${question}\n\n`);
31
50
 
32
51
  // Initial render
33
- stdout.write(render());
52
+ let prevLines = render();
53
+ stdout.write(prevLines.join('\n'));
34
54
 
35
55
  // Enter raw mode for keypress detection
36
56
  const wasRaw = stdin.isRaw;
37
57
  stdin.setRawMode(true);
38
58
  stdin.resume();
39
59
 
60
+ function cleanup() {
61
+ stdin.setRawMode(wasRaw ?? false);
62
+ stdin.removeListener('data', onData);
63
+ stdin.pause();
64
+ // Restore cursor visibility
65
+ stdout.write('\x1b[?25h');
66
+ }
67
+
40
68
  function onData(buf) {
41
69
  const key = buf.toString();
42
70
 
43
71
  // Ctrl+C
44
72
  if (key === '\x03') {
45
- stdin.setRawMode(wasRaw ?? false);
46
- stdin.removeListener('data', onData);
47
- stdin.pause();
73
+ cleanup();
48
74
  stdout.write('\n');
49
75
  process.exit(0);
50
76
  }
51
77
 
52
78
  // Enter
53
79
  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
80
+ // Move up by physical lines to clear previous render
81
+ const upCount = totalPhysicalLines(prevLines);
82
+ stdout.write(`\x1b[${upCount}A`);
59
83
  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');
84
+ const final = ` ${chalk.cyan('\u276f')} ${chalk.cyan(choices[selected].label)}`;
66
85
  stdout.write(final + '\n');
86
+ cleanup();
67
87
  resolve(choices[selected].value);
68
88
  return;
69
89
  }
@@ -79,10 +99,12 @@ export function selectPrompt(question, choices, { defaultIndex = 0 } = {}) {
79
99
  return; // ignore other keys
80
100
  }
81
101
 
82
- // Redraw: move cursor up N lines, clear, rewrite
83
- stdout.write(`\x1b[${choices.length}A`);
102
+ // Redraw: move cursor up by physical lines, clear, rewrite
103
+ const upCount = totalPhysicalLines(prevLines);
104
+ stdout.write(`\x1b[${upCount}A`);
84
105
  stdout.write('\x1b[J');
85
- stdout.write(render());
106
+ prevLines = render();
107
+ stdout.write(prevLines.join('\n'));
86
108
  }
87
109
 
88
110
  stdin.on('data', onData);
package/src/lib/ui.js CHANGED
@@ -20,12 +20,12 @@ export function box(lines, { borderColor, padding = 2 } = {}) {
20
20
 
21
21
  const colorize = borderColor ? chalk[borderColor].bind(chalk) : (s) => s;
22
22
 
23
- const top = colorize(` \u250c${'─'.repeat(inner)}\u2510`);
24
- const bottom = colorize(` \u2514${'─'.repeat(inner)}\u2518`);
23
+ const top = colorize(` \u250c${'─'.repeat(inner)}\u2510`);
24
+ const bottom = colorize(` \u2514${'─'.repeat(inner)}\u2518`);
25
25
  const rowLines = lines.map(l => {
26
26
  const visible = stripAnsi(l).length;
27
27
  const rightPad = ' '.repeat(maxWidth - visible);
28
- return ` ${colorize('\u2502')}${pad}${l}${rightPad}${pad}${colorize('\u2502')}`;
28
+ return ` ${colorize('\u2502')}${pad}${l}${rightPad}${pad}${colorize('\u2502')}`;
29
29
  });
30
30
 
31
31
  return [top, ...rowLines, bottom].join('\n');
@@ -72,9 +72,9 @@ export function printCompletionSummary({ skillName, scope, installPath, agentNam
72
72
  // --- step / error output ---
73
73
 
74
74
  export function step(text) {
75
- console.log(chalk.green(' \u2713') + ` ${text}`);
75
+ console.log(chalk.green(' \u2713') + ` ${text}`);
76
76
  }
77
77
 
78
78
  export function error(text) {
79
- console.error(chalk.red(` ${text}`));
79
+ console.error(chalk.red(` ${text}`));
80
80
  }