vskill 0.2.28 → 0.2.30

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.
@@ -2,31 +2,9 @@
2
2
  // vskill find -- search the verified-skill.com registry
3
3
  // ---------------------------------------------------------------------------
4
4
  import { searchSkills } from "../api/client.js";
5
- import { bold, green, yellow, dim, cyan, red, link, table } from "../utils/output.js";
6
- /**
7
- * Extract owner/repo from a URL and wrap it in a clickable OSC 8 hyperlink.
8
- * Falls back to author name if no URL is available.
9
- */
10
- function formatRepo(repoUrl, author) {
11
- if (!repoUrl)
12
- return author || "-";
13
- try {
14
- const ownerRepo = new URL(repoUrl).pathname
15
- .replace(/^\//, "")
16
- .replace(/\.git$/, "")
17
- .replace(/\/$/, "");
18
- return link(repoUrl, ownerRepo);
19
- }
20
- catch {
21
- return repoUrl;
22
- }
23
- }
5
+ import { bold, dim, cyan, red, link, formatInstalls } from "../utils/output.js";
24
6
  /**
25
7
  * Extract the base `owner/repo` slug from a repoUrl.
26
- * Handles URLs like:
27
- * https://github.com/owner/repo
28
- * https://github.com/owner/repo/tree/main/path
29
- * https://github.com/owner/repo.git
30
8
  */
31
9
  function extractBaseRepo(repoUrl) {
32
10
  if (!repoUrl)
@@ -35,49 +13,17 @@ function extractBaseRepo(repoUrl) {
35
13
  return match ? match[1] : null;
36
14
  }
37
15
  /**
38
- * Build a display row for a single skill result.
16
+ * Format as `owner/repo@skill-name`.
39
17
  */
40
- function buildRow(r) {
41
- let displayTier;
42
- let tierColor;
43
- let scoreCol;
44
- if (r.isBlocked) {
45
- displayTier = "BLOCKED";
46
- tierColor = red;
47
- const parts = [r.severity, r.threatType].filter(Boolean);
48
- scoreCol = parts.length > 0 ? parts.join(" | ") : "blocked";
49
- }
50
- else if (r.isTainted) {
51
- displayTier = "TAINTED";
52
- tierColor = red;
53
- scoreCol = String(r.score ?? "-");
54
- }
55
- else {
56
- displayTier = r.tier || "VERIFIED";
57
- tierColor =
58
- r.tier === "CERTIFIED"
59
- ? yellow
60
- : r.tier === "VERIFIED"
61
- ? green
62
- : dim;
63
- scoreCol = String(r.score ?? "-");
64
- }
65
- const repo = formatRepo(r.repoUrl, r.author);
66
- return [
67
- r.isBlocked ? red(bold(r.name)) : bold(r.name),
68
- repo,
69
- tierColor(displayTier),
70
- r.isBlocked ? red(scoreCol) : scoreCol,
71
- ];
18
+ function formatRepoSkill(repoUrl, skillName) {
19
+ const base = extractBaseRepo(repoUrl);
20
+ return base ? `${base}@${skillName}` : skillName;
72
21
  }
73
22
  /**
74
- * Indent every line of a block of text by a given prefix.
23
+ * Get the verified-skill.com URL for a skill.
75
24
  */
76
- function indent(text, prefix) {
77
- return text
78
- .split("\n")
79
- .map((line) => prefix + line)
80
- .join("\n");
25
+ function getSkillUrl(skillName) {
26
+ return `https://verified-skill.com/skills/${encodeURIComponent(skillName)}`;
81
27
  }
82
28
  export async function findCommand(query, opts) {
83
29
  console.log(dim(`Searching for "${query}"...\n`));
@@ -99,102 +45,87 @@ export async function findCommand(query, opts) {
99
45
  console.log(dim(`Try a broader search or visit ${cyan("https://verified-skill.com")}`));
100
46
  return;
101
47
  }
102
- // Sort: non-blocked by score descending, blocked at the end
48
+ // Sort: non-blocked by installs descending, score as tiebreaker, blocked at end
103
49
  results.sort((a, b) => {
104
50
  if (a.isBlocked && !b.isBlocked)
105
51
  return 1;
106
52
  if (!a.isBlocked && b.isBlocked)
107
53
  return -1;
54
+ const installDiff = (b.installs ?? 0) - (a.installs ?? 0);
55
+ if (installDiff !== 0)
56
+ return installDiff;
108
57
  return (b.score ?? 0) - (a.score ?? 0);
109
58
  });
110
- // JSON output mode — no table, no hints, flat array
59
+ // JSON output mode
111
60
  if (opts?.json) {
112
61
  console.log(JSON.stringify(results, null, 2));
113
62
  return;
114
63
  }
115
64
  const blockedCount = results.filter((r) => r.isBlocked).length;
116
- const headers = ["Name", "Repository", "Tier", "Score"];
117
- // ---------- Grouped TTY display -------------------------------------------
65
+ // ---------- TTY display: flat two-line entries ----------------------------
118
66
  if (process.stdout.isTTY) {
119
- // Group results by base repo
120
- const groupOrder = [];
121
- const groups = new Map();
122
67
  for (const r of results) {
123
- const base = extractBaseRepo(r.repoUrl) ?? "__ungrouped__";
124
- if (!groups.has(base)) {
125
- groups.set(base, []);
126
- groupOrder.push(base);
68
+ const label = formatRepoSkill(r.repoUrl, r.name);
69
+ const url = getSkillUrl(r.name);
70
+ if (r.isBlocked) {
71
+ const parts = [r.severity, r.threatType].filter(Boolean);
72
+ const threatInfo = parts.length > 0 ? parts.join(" | ") : "blocked";
73
+ console.log(`${red(bold(label))} ${red(threatInfo)}`);
127
74
  }
128
- groups.get(base).push(r);
129
- }
130
- // Separate marketplace groups (2+ skills) from singletons
131
- const marketplaceKeys = groupOrder.filter((k) => k !== "__ungrouped__" && groups.get(k).length >= 2);
132
- const singletonResults = [];
133
- for (const key of groupOrder) {
134
- const items = groups.get(key);
135
- if (key === "__ungrouped__" || items.length < 2) {
136
- singletonResults.push(...items);
75
+ else {
76
+ const installStr = `${formatInstalls(r.installs)} installs`;
77
+ console.log(`${bold(label)} ${dim(installStr)}`);
137
78
  }
138
- }
139
- const hasMarketplaceGroups = marketplaceKeys.length > 0;
140
- // Render marketplace groups
141
- for (const baseRepo of marketplaceKeys) {
142
- const items = groups.get(baseRepo);
143
- console.log(bold(`Plugin Marketplace: ${baseRepo} (${items.length} skills)`) +
144
- " " +
145
- dim(`Install: npx vskill install ${baseRepo}`));
146
- const rows = items.map((r) => buildRow(r));
147
- console.log(indent(table(headers, rows), " "));
79
+ console.log(dim(` \u2514 ${link(url, url)}`));
148
80
  console.log();
149
81
  }
150
- // Render singletons / ungrouped
151
- if (singletonResults.length > 0) {
152
- if (hasMarketplaceGroups) {
153
- console.log(bold("Other results"));
154
- }
155
- const rows = singletonResults.map((r) => buildRow(r));
156
- if (hasMarketplaceGroups) {
157
- console.log(indent(table(headers, rows), " "));
158
- }
159
- else {
160
- console.log(table(headers, rows));
161
- }
82
+ // Footer
83
+ if (hasMore) {
84
+ const currentLimit = opts?.limit ?? 15;
85
+ const suggestedLimit = Math.min(currentLimit * 2, 50);
86
+ console.log(dim(`Showing ${results.length} results. Use --limit ${suggestedLimit} for more.`));
87
+ }
88
+ else {
89
+ console.log(dim(`${results.length} result${results.length === 1 ? "" : "s"} found.`));
162
90
  }
163
- const countText = `${results.length} result${results.length === 1 ? "" : "s"} found`;
164
- console.log(dim(`\n${countText}${hasMore ? " (more available — browse at verified-skill.com)" : ""}`));
165
91
  if (blockedCount > 0) {
166
- console.log(red(`\n ${blockedCount} BLOCKED skill${blockedCount === 1 ? "" : "s"} known malicious, installation will be refused`));
92
+ console.log(red(`\n ${blockedCount} BLOCKED skill${blockedCount === 1 ? "" : "s"} \u2014 known malicious, installation will be refused`));
167
93
  }
168
- // Install hints — show copy-pasteable commands
169
- const hasInstallable = results.some((r) => !r.isBlocked);
170
- if (!opts?.noHint && hasInstallable) {
171
- if (hasMarketplaceGroups) {
172
- const firstMp = marketplaceKeys[0];
173
- console.log(dim(`\nInstall marketplace: `) + cyan(`npx vskill i ${firstMp}`));
174
- }
175
- else {
176
- const firstResult = results.find((r) => !r.isBlocked);
177
- const repo = firstResult ? extractBaseRepo(firstResult.repoUrl) : null;
94
+ // Install hint
95
+ if (!opts?.noHint) {
96
+ const firstInstallable = results.find((r) => !r.isBlocked);
97
+ if (firstInstallable) {
98
+ const repo = extractBaseRepo(firstInstallable.repoUrl);
178
99
  if (repo) {
179
- console.log(dim(`\nInstall: `) + cyan(`npx vskill i ${repo}`));
100
+ console.log(dim("\nInstall: ") + cyan(`npx vskill i ${repo}`));
180
101
  }
181
102
  }
182
103
  }
183
104
  return;
184
105
  }
185
- // ---------- Non-TTY (piped) display — flat table --------------------------
186
- const rows = results.map((r) => buildRow(r));
187
- console.log(table(headers, rows));
106
+ // ---------- Non-TTY (piped) — tab-separated flat lines --------------------
107
+ for (const r of results) {
108
+ const label = formatRepoSkill(r.repoUrl, r.name);
109
+ if (r.isBlocked) {
110
+ console.log(`${label}\tBLOCKED\t${r.threatType ?? ""}`);
111
+ }
112
+ else {
113
+ console.log(`${label}\t${r.installs}\t${r.tier}`);
114
+ }
115
+ }
188
116
  const pipeCountText = `${results.length} result${results.length === 1 ? "" : "s"} found`;
189
- console.log(dim(`\n${pipeCountText}${hasMore ? " (more available)" : ""}`));
117
+ console.log(`\n${pipeCountText}${hasMore ? " (more available)" : ""}`);
190
118
  if (blockedCount > 0) {
191
- console.log(red(`\n ${blockedCount} BLOCKED skill${blockedCount === 1 ? "" : "s"} known malicious, installation will be refused`));
119
+ console.log(`\n ${blockedCount} BLOCKED skill${blockedCount === 1 ? "" : "s"} \u2014 known malicious, installation will be refused`);
192
120
  }
193
- const hasInstallable = results.some((r) => !r.isBlocked);
194
- if (!opts?.noHint && hasInstallable) {
121
+ if (!opts?.noHint) {
195
122
  const firstInstallable = results.find((r) => !r.isBlocked);
196
- const firstName = firstInstallable?.name ?? "<name>";
197
- console.log(dim(`\nTo install: npx skills add ${firstName}`));
123
+ if (firstInstallable) {
124
+ const repo = extractBaseRepo(firstInstallable.repoUrl);
125
+ if (repo) {
126
+ console.log(`\nInstall: npx vskill i ${repo}`);
127
+ }
128
+ }
198
129
  }
199
130
  }
200
131
  //# sourceMappingURL=find.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"find.js","sourceRoot":"","sources":["../../src/commands/find.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../src/commands/find.ts"],"names":[],"mappings":"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"}
@@ -1,53 +1,105 @@
1
1
  // ---------------------------------------------------------------------------
2
- // Tests for find command (T-009)
2
+ // Tests for find command
3
3
  // ---------------------------------------------------------------------------
4
- import { describe, it, expect, vi, beforeEach } from "vitest";
4
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
5
5
  const mockSearchSkills = vi.hoisted(() => vi.fn());
6
6
  vi.mock("../api/client.js", () => ({
7
7
  searchSkills: mockSearchSkills,
8
8
  }));
9
- // Capture console.log output
10
9
  const logs = [];
11
- const originalLog = console.log;
10
+ let origIsTTY;
12
11
  import { findCommand } from "./find.js";
13
- describe("findCommand hints", () => {
12
+ describe("findCommand", () => {
14
13
  beforeEach(() => {
15
14
  logs.length = 0;
16
15
  vi.spyOn(console, "log").mockImplementation((...args) => {
17
16
  logs.push(args.map(String).join(" "));
18
17
  });
19
18
  vi.spyOn(console, "error").mockImplementation(() => { });
19
+ origIsTTY = process.stdout.isTTY;
20
20
  mockSearchSkills.mockResolvedValue({
21
21
  results: [
22
- { name: "test-skill", author: "test", repoUrl: "https://github.com/test/test-skill", tier: "VERIFIED", score: 90 },
22
+ { name: "test-skill", author: "test", repoUrl: "https://github.com/test/test-skill", tier: "VERIFIED", score: 90, installs: 1250 },
23
23
  ],
24
24
  hasMore: false,
25
25
  });
26
26
  });
27
- it("TC-030: non-TTY output includes hint line", async () => {
28
- // Simulate non-TTY
29
- const origIsTTY = process.stdout.isTTY;
27
+ afterEach(() => {
28
+ Object.defineProperty(process.stdout, "isTTY", { value: origIsTTY, configurable: true });
29
+ });
30
+ it("TC-030: non-TTY output includes tab-separated result", async () => {
30
31
  Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
31
32
  await findCommand("test", { json: false, noHint: false });
32
33
  const output = logs.join("\n");
33
- expect(output).toContain("To install: npx skills add");
34
- Object.defineProperty(process.stdout, "isTTY", { value: origIsTTY, configurable: true });
34
+ expect(output).toContain("test/test-skill@test-skill");
35
+ expect(output).toContain("1250");
35
36
  });
36
37
  it("TC-031: hint is suppressed with --json flag", async () => {
37
- const origIsTTY = process.stdout.isTTY;
38
38
  Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
39
39
  await findCommand("test", { json: true, noHint: false });
40
40
  const output = logs.join("\n");
41
- expect(output).not.toContain("To install: npx skills add");
42
- Object.defineProperty(process.stdout, "isTTY", { value: origIsTTY, configurable: true });
41
+ expect(output).not.toContain("Install:");
43
42
  });
44
43
  it("TC-032: hint is suppressed with --no-hint flag", async () => {
45
- const origIsTTY = process.stdout.isTTY;
46
44
  Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
47
45
  await findCommand("test", { json: false, noHint: true });
48
46
  const output = logs.join("\n");
49
- expect(output).not.toContain("To install: npx skills add");
50
- Object.defineProperty(process.stdout, "isTTY", { value: origIsTTY, configurable: true });
47
+ expect(output).not.toContain("Install:");
48
+ });
49
+ it("displays install counts in TTY mode", async () => {
50
+ Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
51
+ await findCommand("test");
52
+ const output = logs.join("\n");
53
+ expect(output).toContain("1.3K installs");
54
+ expect(output).toContain("test/test-skill@test-skill");
55
+ });
56
+ it("sorts results by installs descending", async () => {
57
+ Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
58
+ mockSearchSkills.mockResolvedValue({
59
+ results: [
60
+ { name: "low-installs", author: "a", repoUrl: "https://github.com/a/b", tier: "VERIFIED", score: 90, installs: 10 },
61
+ { name: "high-installs", author: "b", repoUrl: "https://github.com/b/c", tier: "VERIFIED", score: 50, installs: 5000 },
62
+ ],
63
+ hasMore: false,
64
+ });
65
+ await findCommand("test");
66
+ const output = logs.join("\n");
67
+ const highIdx = output.indexOf("high-installs");
68
+ const lowIdx = output.indexOf("low-installs");
69
+ expect(highIdx).toBeLessThan(lowIdx);
70
+ });
71
+ it("shows --limit hint when truncated", async () => {
72
+ Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
73
+ mockSearchSkills.mockResolvedValue({
74
+ results: [
75
+ { name: "skill-1", author: "a", repoUrl: "https://github.com/a/b", tier: "VERIFIED", score: 90, installs: 100 },
76
+ ],
77
+ hasMore: true,
78
+ });
79
+ await findCommand("test");
80
+ const output = logs.join("\n");
81
+ expect(output).toContain("Use --limit");
82
+ });
83
+ it("shows blocked skills with threat info", async () => {
84
+ Object.defineProperty(process.stdout, "isTTY", { value: true, configurable: true });
85
+ mockSearchSkills.mockResolvedValue({
86
+ results: [
87
+ { name: "bad-skill", author: "evil", repoUrl: "https://github.com/evil/bad", tier: "BLOCKED", score: 0, installs: 0, isBlocked: true, threatType: "credential-theft", severity: "critical" },
88
+ ],
89
+ hasMore: false,
90
+ });
91
+ await findCommand("test");
92
+ const output = logs.join("\n");
93
+ expect(output).toContain("credential-theft");
94
+ });
95
+ it("JSON output includes installs field", async () => {
96
+ Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
97
+ await findCommand("test", { json: true });
98
+ // Skip the "Searching..." line — JSON starts at the second log entry
99
+ const jsonLine = logs.find((l) => l.trimStart().startsWith("["));
100
+ expect(jsonLine).toBeDefined();
101
+ const parsed = JSON.parse(jsonLine);
102
+ expect(parsed[0].installs).toBe(1250);
51
103
  });
52
104
  });
53
105
  //# sourceMappingURL=find.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"find.test.js","sourceRoot":"","sources":["../../src/commands/find.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"find.test.js","sourceRoot":"","sources":["../../src/commands/find.test.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEzE,MAAM,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AAEnD,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,YAAY,EAAE,gBAAgB;CAC/B,CAAC,CAAC,CAAC;AAEJ,MAAM,IAAI,GAAa,EAAE,CAAC;AAC1B,IAAI,SAA8B,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAChB,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE;YACjE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxD,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACjC,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,oCAAoC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;aACnI;YACD,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;gBACnH,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;aACvH;YACD,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,wBAAwB,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE;aAChH;YACD,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,gBAAgB,CAAC,iBAAiB,CAAC;YACjC,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,6BAA6B,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,QAAQ,EAAE,UAAU,EAAE;aAC7L;YACD,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,WAAW,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,qEAAqE;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QACjE,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAS,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -70,7 +70,7 @@ program
70
70
  .command("find <query>")
71
71
  .alias("search")
72
72
  .description("Search the verified-skill.com registry")
73
- .option("--limit <n>", "Max results to return (default 50, max 50)", parseInt)
73
+ .option("--limit <n>", "Max results to return (default 15, max 50)", parseInt)
74
74
  .option("--json", "Output raw JSON")
75
75
  .action(async (query, opts) => {
76
76
  const { findCommand } = await import("./commands/find.js");
@@ -16,6 +16,12 @@ export declare function link(url: string, text: string): string;
16
16
  * Column widths are auto-calculated from the widest cell.
17
17
  */
18
18
  export declare function table(headers: string[], rows: string[][], gap?: number): string;
19
+ /**
20
+ * Format install count as human-readable string.
21
+ * 0 → "0", 999 → "999", 1000 → "1.0K", 1250 → "1.2K",
22
+ * 10000 → "10K", 999999 → "999K", 1000000 → "1.0M"
23
+ */
24
+ export declare function formatInstalls(n: number): string;
19
25
  export declare function spinner(message: string): {
20
26
  stop: (final?: string) => void;
21
27
  };
@@ -68,6 +68,23 @@ function padRight(str, width, gap) {
68
68
  const padding = Math.max(0, width - visible.length) + gap;
69
69
  return str + " ".repeat(padding);
70
70
  }
71
+ // ---- Formatting -----------------------------------------------------------
72
+ /**
73
+ * Format install count as human-readable string.
74
+ * 0 → "0", 999 → "999", 1000 → "1.0K", 1250 → "1.2K",
75
+ * 10000 → "10K", 999999 → "999K", 1000000 → "1.0M"
76
+ */
77
+ export function formatInstalls(n) {
78
+ if (n < 1_000)
79
+ return String(n);
80
+ if (n < 10_000)
81
+ return `${(n / 1_000).toFixed(1)}K`;
82
+ if (n < 1_000_000)
83
+ return `${Math.floor(n / 1_000)}K`;
84
+ if (n < 10_000_000)
85
+ return `${(n / 1_000_000).toFixed(1)}M`;
86
+ return `${Math.floor(n / 1_000_000)}M`;
87
+ }
71
88
  // ---- Spinner --------------------------------------------------------------
72
89
  export function spinner(message) {
73
90
  const frames = ["|", "/", "-", "\\"];
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,iEAAiE;AACjE,8EAA8E;AAE9E,MAAM,gBAAgB,GACpB,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG;IAC/B,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS;IAClC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC;AAE5D,SAAS,IAAI,CAAC,IAAY,EAAE,KAAa;IACvC,IAAI,CAAC,gBAAgB;QAAE,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC;IACrD,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,CAAC;AACpD,CAAC;AAED,8EAA8E;AAE9E,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAClD,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACnD,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACjD,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,GAAW,EAAE,IAAY;IAC5C,IAAI,CAAC,gBAAgB;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,WAAW,GAAG,OAAO,IAAI,cAAc,CAAC;AACjD,CAAC;AAED,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,OAAiB,EAAE,IAAgB,EAAE,GAAG,GAAG,CAAC;IAChE,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACnC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACzC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,SAAS;IACT,MAAM,UAAU,GAAG,OAAO;SACvB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC7C,IAAI,CAAC,EAAE,CAAC;SACR,OAAO,EAAE,CAAC;IACb,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7B,KAAK,CAAC,IAAI,CACR,GAAG,CACD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAC1D,CACF,CAAC;IAEF,YAAY;IACZ,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,GAAG;aACb,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;aACnD,IAAI,CAAC,EAAE,CAAC;aACR,OAAO,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,4CAA4C;IAC5C,OAAO,GAAG,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,KAAa,EAAE,GAAW;IACvD,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC;IAC1D,OAAO,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACnC,CAAC;AAED,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,IAAI,CAAC,GAAG,KAAK;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,MAAM;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,IAAI,CAAC,GAAG,SAAS;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;IACtD,IAAI,CAAC,GAAG,UAAU;QAAE,OAAO,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC5D,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC;AACzC,CAAC;AAED,8EAA8E;AAE9E,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,IAAI,CAAC,gBAAgB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,OAAO,CAAC,CAAC;QACxC,OAAO;YACL,IAAI,EAAE,CAAC,KAAc,EAAE,EAAE;gBACvB,IAAI,KAAK;oBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;YAChD,CAAC;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC,EAAE,CAAC;IACN,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,IAAI,EAAE,CAAC,KAAc,EAAE,EAAE;YACvB,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;YAC9D,IAAI,KAAK;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;QAChD,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { formatInstalls } from "./output.js";
3
+ describe("formatInstalls", () => {
4
+ it("returns raw number below 1000", () => {
5
+ expect(formatInstalls(0)).toBe("0");
6
+ expect(formatInstalls(999)).toBe("999");
7
+ });
8
+ it("formats thousands with one decimal", () => {
9
+ expect(formatInstalls(1000)).toBe("1.0K");
10
+ expect(formatInstalls(1250)).toBe("1.3K");
11
+ expect(formatInstalls(9999)).toBe("10.0K");
12
+ });
13
+ it("formats ten-thousands without decimal", () => {
14
+ expect(formatInstalls(10000)).toBe("10K");
15
+ expect(formatInstalls(999999)).toBe("999K");
16
+ });
17
+ it("formats millions", () => {
18
+ expect(formatInstalls(1000000)).toBe("1.0M");
19
+ expect(formatInstalls(10000000)).toBe("10M");
20
+ });
21
+ });
22
+ //# sourceMappingURL=output.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../src/utils/output.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -100,17 +100,49 @@ const KEY_SPACE = " ";
100
100
  const KEY_ENTER_CR = "\r";
101
101
  const KEY_ENTER_LF = "\n";
102
102
  const KEY_CTRL_C = "\x03";
103
+ /**
104
+ * Queue-based keypress reader that prevents race conditions.
105
+ * A persistent listener buffers incoming data, so no keystrokes
106
+ * are lost between reads (e.g. during render cycles).
107
+ */
108
+ const keyQueue = [];
109
+ const keyWaiters = [];
110
+ let keyListenerAttached = false;
111
+ function ensureKeyListener() {
112
+ if (keyListenerAttached)
113
+ return;
114
+ keyListenerAttached = true;
115
+ process.stdin.on("data", (data) => {
116
+ const key = data.toString();
117
+ const waiter = keyWaiters.shift();
118
+ if (waiter) {
119
+ waiter(key);
120
+ }
121
+ else {
122
+ keyQueue.push(key);
123
+ }
124
+ });
125
+ }
126
+ function detachKeyListener() {
127
+ if (!keyListenerAttached)
128
+ return;
129
+ process.stdin.removeAllListeners("data");
130
+ keyListenerAttached = false;
131
+ keyQueue.length = 0;
132
+ keyWaiters.length = 0;
133
+ }
103
134
  /**
104
135
  * Read a single keypress from stdin in raw mode.
105
136
  * Returns the raw key string (may be multi-byte for arrow keys).
106
137
  */
107
138
  function readKey() {
139
+ ensureKeyListener();
140
+ const buffered = keyQueue.shift();
141
+ if (buffered !== undefined) {
142
+ return Promise.resolve(buffered);
143
+ }
108
144
  return new Promise((resolve) => {
109
- function onData(data) {
110
- process.stdin.removeListener("data", onData);
111
- resolve(data.toString());
112
- }
113
- process.stdin.on("data", onData);
145
+ keyWaiters.push(resolve);
114
146
  });
115
147
  }
116
148
  // ---------------------------------------------------------------------------
@@ -229,6 +261,7 @@ function createInteractivePrompter() {
229
261
  }
230
262
  }
231
263
  finally {
264
+ detachKeyListener();
232
265
  process.stdin.setRawMode(false);
233
266
  process.stdin.pause();
234
267
  write(SHOW_CURSOR);
@@ -291,6 +324,7 @@ function createInteractivePrompter() {
291
324
  }
292
325
  }
293
326
  finally {
327
+ detachKeyListener();
294
328
  process.stdin.setRawMode(false);
295
329
  process.stdin.pause();
296
330
  write(SHOW_CURSOR);
@@ -325,6 +359,7 @@ function createInteractivePrompter() {
325
359
  }
326
360
  }
327
361
  finally {
362
+ detachKeyListener();
328
363
  process.stdin.setRawMode(false);
329
364
  process.stdin.pause();
330
365
  }