@simon_he/pi 0.2.2 → 0.2.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/dist/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
- //#region rolldown:runtime
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -35,6 +36,8 @@ let lazy_js_utils = require("lazy-js-utils");
35
36
  let lazy_js_utils_node = require("lazy-js-utils/node");
36
37
  let picocolors = require("picocolors");
37
38
  picocolors = __toESM(picocolors);
39
+ let node_readline = require("node:readline");
40
+ node_readline = __toESM(node_readline);
38
41
  let node_console = require("node:console");
39
42
  let node_fs = require("node:fs");
40
43
  node_fs = __toESM(node_fs);
@@ -44,96 +47,410 @@ let node_module = require("node:module");
44
47
  let node_url = require("node:url");
45
48
 
46
49
  //#region package.json
47
- var version = "0.2.2";
50
+ var version = "0.2.4";
48
51
 
49
52
  //#endregion
50
- //#region src/installDeps.ts
51
- const isZh$7 = node_process.default.env.PI_Lang === "zh";
52
- const gumDocUrl = "https://github.com/charmbracelet/gum";
53
- const niDocUrl = "https://github.com/antfu/ni";
54
- async function installDeps(options = {}) {
55
- const { gum = true, ni = true, strict = true } = options;
56
- const platform = node_process.default.platform;
57
- if (gum && !await (0, lazy_js_utils_node.isInstallPkg)("gum")) if (platform === "darwin") {
58
- console.log(picocolors.default.cyan(isZh$7 ? "正在为您安装必要的依赖gum..." : "Installing gum..."));
59
- const { status } = await (0, lazy_js_utils_node.jsShell)("brew install gum", [
60
- "inherit",
61
- "pipe",
62
- "inherit"
63
- ]);
64
- if (status === 0) console.log(picocolors.default.cyan(isZh$7 ? "gum 安装成功!" : "gum installed successfully!"));
65
- else {
66
- console.log(picocolors.default.red(isZh$7 ? `gum 安装失败,请尝试从官网解决安装问题! ${gumDocUrl}` : `gum installation failed, please try manual install: ${gumDocUrl}`));
67
- if (strict) node_process.default.exit(1);
53
+ //#region src/tty.ts
54
+ const isZh$6 = node_process.default.env.PI_Lang === "zh";
55
+ function isInteractive() {
56
+ return Boolean(node_process.default.stdin.isTTY && node_process.default.stdout.isTTY);
57
+ }
58
+ function stripAnsi$1(input) {
59
+ let output = "";
60
+ for (let i = 0; i < input.length; i++) {
61
+ const ch = input[i];
62
+ if (ch === "\x1B" && input[i + 1] === "[") {
63
+ let j = i + 2;
64
+ while (j < input.length && /[0-9;]/.test(input[j])) j++;
65
+ if (input[j] === "m") {
66
+ i = j;
67
+ continue;
68
+ }
68
69
  }
69
- } else console.log(picocolors.default.yellow(isZh$7 ? `未检测到 gum,请根据系统手动安装: ${gumDocUrl}` : `gum not found, please install it manually: ${gumDocUrl}`));
70
- if (ni && !await (0, lazy_js_utils_node.isInstallPkg)("ni")) {
71
- console.log(picocolors.default.cyan(isZh$7 ? "正在为您安装必要的依赖ni..." : "Installing ni..."));
72
- const { status } = await (0, lazy_js_utils_node.jsShell)("npm i -g @antfu/ni", [
73
- "inherit",
74
- "pipe",
75
- "inherit"
76
- ]);
77
- if (status === 0) console.log(picocolors.default.cyan(isZh$7 ? "ni 安装成功!" : "ni installed successfully!"));
70
+ output += ch;
71
+ }
72
+ return output;
73
+ }
74
+ function charWidth(ch) {
75
+ return (ch.codePointAt(0) ?? 0) >= 4352 ? 2 : 1;
76
+ }
77
+ function stringWidth(input) {
78
+ const clean = stripAnsi$1(input);
79
+ let width = 0;
80
+ for (const ch of clean) width += charWidth(ch);
81
+ return width;
82
+ }
83
+ function rowCount(input, columns) {
84
+ const width = stringWidth(input);
85
+ return Math.max(1, Math.ceil(width / columns));
86
+ }
87
+ function fuzzyScore(option, query) {
88
+ const optionLower = option.toLowerCase();
89
+ const queryLower = query.toLowerCase();
90
+ let score = 0;
91
+ let lastIndex = -1;
92
+ for (const ch of queryLower) {
93
+ const idx = optionLower.indexOf(ch, lastIndex + 1);
94
+ if (idx === -1) return null;
95
+ score += idx === lastIndex + 1 ? 5 : 1;
96
+ score -= idx;
97
+ lastIndex = idx;
98
+ }
99
+ return score;
100
+ }
101
+ function getMatchIndices(option, query) {
102
+ if (!query) return [];
103
+ const optionLower = option.toLowerCase();
104
+ const queryLower = query.toLowerCase();
105
+ const indices = [];
106
+ let lastIndex = -1;
107
+ for (const ch of queryLower) {
108
+ const idx = optionLower.indexOf(ch, lastIndex + 1);
109
+ if (idx === -1) return [];
110
+ indices.push(idx);
111
+ lastIndex = idx;
112
+ }
113
+ return indices;
114
+ }
115
+ function highlightMatch(option, query, active) {
116
+ if (!query) return active ? picocolors.default.cyan(option) : option;
117
+ const matchSet = new Set(getMatchIndices(option, query));
118
+ let output = "";
119
+ for (let i = 0; i < option.length; i++) {
120
+ const ch = option[i];
121
+ if (matchSet.has(i)) output += picocolors.default.bold(picocolors.default.yellow(ch));
122
+ else output += active ? picocolors.default.cyan(ch) : ch;
123
+ }
124
+ return output;
125
+ }
126
+ function filterOptions(options, query) {
127
+ if (!query) return options;
128
+ const ranked = options.map((option, index) => {
129
+ const score = fuzzyScore(option, query);
130
+ return score === null ? null : {
131
+ option,
132
+ score,
133
+ index
134
+ };
135
+ }).filter(Boolean);
136
+ ranked.sort((a, b) => {
137
+ if (b.score !== a.score) return b.score - a.score;
138
+ return a.index - b.index;
139
+ });
140
+ return ranked.map((item) => item.option);
141
+ }
142
+ function getVisibleWindow(total, cursor, limit) {
143
+ if (total <= limit) return {
144
+ start: 0,
145
+ end: total
146
+ };
147
+ let start = cursor - Math.floor(limit / 2);
148
+ let end = start + limit;
149
+ if (start < 0) {
150
+ start = 0;
151
+ end = limit;
152
+ }
153
+ if (end > total) {
154
+ end = total;
155
+ start = Math.max(0, end - limit);
156
+ }
157
+ return {
158
+ start,
159
+ end
160
+ };
161
+ }
162
+ async function runSelect(options, config) {
163
+ if (!isInteractive()) return null;
164
+ if (options.length === 0) return null;
165
+ const stdin = node_process.default.stdin;
166
+ const stdout = node_process.default.stdout;
167
+ node_readline.default.emitKeypressEvents(stdin, { escapeCodeTimeout: 50 });
168
+ if (stdin.isTTY) stdin.setRawMode(true);
169
+ let query = "";
170
+ let inputCursor = 0;
171
+ let filtered = options;
172
+ let cursor = 0;
173
+ const selected = /* @__PURE__ */ new Set();
174
+ let searchMode = false;
175
+ let anchorSet = false;
176
+ let columns = stdout.columns || 80;
177
+ let rows = stdout.rows || 24;
178
+ let maxVisible = Math.max(5, rows - 4);
179
+ const updateDimensions = () => {
180
+ columns = stdout.columns || 80;
181
+ rows = stdout.rows || 24;
182
+ maxVisible = Math.max(5, rows - 4);
183
+ };
184
+ const updateFiltered = () => {
185
+ filtered = filterOptions(options, query);
186
+ if (filtered.length === 0) cursor = 0;
187
+ else if (cursor >= filtered.length) cursor = filtered.length - 1;
188
+ };
189
+ const render = () => {
190
+ updateFiltered();
191
+ if (query.length > 0) searchMode = true;
192
+ const prompt = searchMode ? "/ " : "> ";
193
+ const header = `? ${config.placeholder}`;
194
+ const inputLine = `${prompt}${query}`;
195
+ const hint = config.mode === "multiple" ? isZh$6 ? "↑/↓ 选择,空格标记,Tab 补全,/ 搜索,回车确认,Esc 取消" : "Use ↑/↓ to move, Space to toggle, Tab to complete, / to search, Enter to confirm, Esc to cancel" : isZh$6 ? "↑/↓ 选择,Tab 补全,/ 搜索,回车确认,Esc 取消" : "Use ↑/↓ to move, Tab to complete, / to search, Enter to confirm, Esc to cancel";
196
+ const lines = [header, inputLine];
197
+ if (filtered.length === 0) lines.push(picocolors.default.dim(isZh$6 ? "没有匹配项" : "No matches"));
78
198
  else {
79
- console.log(picocolors.default.red(isZh$7 ? `ni 安装失败,请尝试从官网解决安装问题! ${niDocUrl}` : `ni installation failed, please try manual install: ${niDocUrl}`));
80
- if (strict) node_process.default.exit(1);
199
+ const window = getVisibleWindow(filtered.length, cursor, maxVisible);
200
+ const visible = filtered.slice(window.start, window.end);
201
+ if (window.start > 0) lines.push(picocolors.default.dim("…"));
202
+ visible.forEach((option, index) => {
203
+ const active = window.start + index === cursor;
204
+ const picked = selected.has(option);
205
+ const prefix = config.mode === "multiple" ? picked ? "[x] " : "[ ] " : "";
206
+ const indicator = active ? ">" : " ";
207
+ const renderedOption = highlightMatch(option, query, active);
208
+ const renderedPrefix = active ? picocolors.default.cyan(prefix) : prefix;
209
+ const content = `${active ? picocolors.default.cyan(indicator) : indicator} ${renderedPrefix}${renderedOption}`;
210
+ lines.push(content);
211
+ });
212
+ if (window.end < filtered.length) lines.push(picocolors.default.dim("…"));
81
213
  }
82
- }
214
+ lines.push(picocolors.default.dim(`${hint} (${Math.min(cursor + 1, filtered.length)}/${filtered.length})`));
215
+ if (!anchorSet) {
216
+ node_readline.default.cursorTo(stdout, 0);
217
+ stdout.write("\x1B[s");
218
+ anchorSet = true;
219
+ } else {
220
+ stdout.write("\x1B[u");
221
+ node_readline.default.cursorTo(stdout, 0);
222
+ node_readline.default.clearScreenDown(stdout);
223
+ }
224
+ stdout.write(lines.join("\n"));
225
+ const headerRows = rowCount(header, columns);
226
+ const inputRowOffset = Math.floor((prompt.length + inputCursor) / columns);
227
+ const inputCol = (prompt.length + inputCursor) % columns;
228
+ const targetRowOffset = headerRows + inputRowOffset;
229
+ stdout.write("\x1B[u");
230
+ node_readline.default.moveCursor(stdout, 0, targetRowOffset);
231
+ node_readline.default.cursorTo(stdout, inputCol);
232
+ };
233
+ return new Promise((resolve) => {
234
+ let onKeypress;
235
+ let onResize;
236
+ const done = (value) => {
237
+ if (stdin.isTTY) stdin.setRawMode(false);
238
+ stdin.off("keypress", onKeypress);
239
+ node_process.default.off("SIGWINCH", onResize);
240
+ stdout.write("\x1B[?25h");
241
+ if (anchorSet) {
242
+ stdout.write("\x1B[u");
243
+ node_readline.default.cursorTo(stdout, 0);
244
+ node_readline.default.clearScreenDown(stdout);
245
+ anchorSet = false;
246
+ }
247
+ stdout.write("\n");
248
+ resolve(value);
249
+ };
250
+ const confirmSelection = () => {
251
+ if (filtered.length === 0) return done(null);
252
+ if (config.mode === "multiple") {
253
+ const picked = options.filter((option) => selected.has(option));
254
+ if (picked.length > 0) return done(picked);
255
+ return done([filtered[cursor]]);
256
+ }
257
+ return done(filtered[cursor]);
258
+ };
259
+ const cancelSelection = () => done(null);
260
+ onKeypress = (input, key) => {
261
+ if (key?.ctrl && key.name === "c") return cancelSelection();
262
+ if (key?.name === "escape") {
263
+ if (query.length > 0) {
264
+ query = "";
265
+ inputCursor = 0;
266
+ return render();
267
+ }
268
+ return cancelSelection();
269
+ }
270
+ if (key?.name === "return") return confirmSelection();
271
+ if (key?.name === "up") {
272
+ if (filtered.length > 0) cursor = (cursor - 1 + filtered.length) % filtered.length;
273
+ return render();
274
+ }
275
+ if (key?.name === "down") {
276
+ if (filtered.length > 0) cursor = (cursor + 1) % filtered.length;
277
+ return render();
278
+ }
279
+ if (config.mode === "multiple" && key?.name === "space") {
280
+ const option = filtered[cursor];
281
+ if (option) if (selected.has(option)) selected.delete(option);
282
+ else selected.add(option);
283
+ return render();
284
+ }
285
+ if (key?.name === "tab") {
286
+ if (filtered.length > 0) {
287
+ query = filtered[cursor] || filtered[0];
288
+ inputCursor = query.length;
289
+ searchMode = true;
290
+ return render();
291
+ }
292
+ return;
293
+ }
294
+ if (input === "/" && !key?.ctrl && !key?.meta) {
295
+ if (!searchMode) {
296
+ searchMode = true;
297
+ query = "";
298
+ inputCursor = 0;
299
+ return render();
300
+ }
301
+ if (searchMode && query.length === 0) {
302
+ searchMode = false;
303
+ return render();
304
+ }
305
+ }
306
+ if (key?.name === "left") {
307
+ if (inputCursor > 0) inputCursor -= 1;
308
+ return render();
309
+ }
310
+ if (key?.name === "right") {
311
+ if (inputCursor < query.length) inputCursor += 1;
312
+ return render();
313
+ }
314
+ if (key?.name === "home" || key?.ctrl && key?.name === "a") {
315
+ inputCursor = 0;
316
+ return render();
317
+ }
318
+ if (key?.name === "end" || key?.ctrl && key?.name === "e") {
319
+ inputCursor = query.length;
320
+ return render();
321
+ }
322
+ if (key?.name === "backspace") {
323
+ if (query) {
324
+ query = query.slice(0, Math.max(0, inputCursor - 1)) + query.slice(inputCursor);
325
+ inputCursor = Math.max(0, inputCursor - 1);
326
+ return render();
327
+ }
328
+ return;
329
+ }
330
+ if (key?.name === "delete") {
331
+ if (query && inputCursor < query.length) {
332
+ query = query.slice(0, inputCursor) + query.slice(inputCursor + 1);
333
+ return render();
334
+ }
335
+ return;
336
+ }
337
+ if (key?.ctrl && key?.name === "u") {
338
+ query = "";
339
+ inputCursor = 0;
340
+ return render();
341
+ }
342
+ if (input && !key?.ctrl && !key?.meta && input.length === 1) {
343
+ if (config.mode !== "multiple" || input !== " ") {
344
+ query = query.slice(0, inputCursor) + input + query.slice(inputCursor);
345
+ inputCursor += input.length;
346
+ searchMode = true;
347
+ }
348
+ return render();
349
+ }
350
+ };
351
+ onResize = () => {
352
+ updateDimensions();
353
+ if (anchorSet) {
354
+ stdout.write("\x1B[u");
355
+ node_readline.default.cursorTo(stdout, 0);
356
+ stdout.write("\x1B[s");
357
+ }
358
+ render();
359
+ };
360
+ node_process.default.on("SIGWINCH", onResize);
361
+ stdin.on("keypress", onKeypress);
362
+ render();
363
+ });
83
364
  }
84
-
85
- //#endregion
86
- //#region src/help.ts
87
- const isZh$6 = node_process.default.env.PI_Lang === "zh";
88
- async function ensureGum() {
89
- if (await (0, lazy_js_utils_node.isInstallPkg)("gum")) return true;
90
- await installDeps({
91
- gum: true,
92
- ni: false,
93
- strict: false
365
+ async function ttySelect(options, placeholder) {
366
+ const result = await runSelect(options, {
367
+ placeholder,
368
+ mode: "single"
94
369
  });
95
- return await (0, lazy_js_utils_node.isInstallPkg)("gum");
370
+ return typeof result === "string" ? result : null;
96
371
  }
97
- function printPlainVersion() {
98
- console.log(isZh$6 ? `pi 版本: ${version}` : `pi version: ${version}`);
99
- console.log(isZh$6 ? "请为我的努力点一个行 🌟" : "Please give me a 🌟 for my efforts");
100
- console.log(isZh$6 ? "谢谢 🤟" : "Thank you 🤟");
372
+ async function ttyMultiSelect(options, placeholder) {
373
+ const result = await runSelect(options, {
374
+ placeholder,
375
+ mode: "multiple"
376
+ });
377
+ return Array.isArray(result) ? result : null;
101
378
  }
102
- function printPlainHelp() {
103
- console.log([
104
- "PI Commands:",
105
- "~ pi: install package",
106
- "~ pix: npx package",
107
- "~ pui: uninstall package",
108
- "~ prun: run package script",
109
- "~ pinit: package init",
110
- "~ pbuild: go build | cargo build",
111
- "~ pfind: find monorepo of yarn or pnpm",
112
- "~ pa: agent alias",
113
- "~ pu: package upgrade",
114
- "~ pci: package clean install",
115
- "~ pil: package latest install"
116
- ].join("\n"));
379
+ function renderBox(lines, options = {}) {
380
+ const width = options.width ?? Math.max(...lines.map((line) => line.length), 0);
381
+ const paddingX = options.paddingX ?? 2;
382
+ const paddingY = options.paddingY ?? 1;
383
+ const marginX = options.marginX ?? 0;
384
+ const marginY = options.marginY ?? 0;
385
+ const align = options.align ?? "left";
386
+ const innerWidth = width + paddingX * 2;
387
+ const margin = " ".repeat(marginX);
388
+ const top = `${margin}+${"-".repeat(innerWidth)}+`;
389
+ const bottom = top;
390
+ const emptyLine = `${margin}|${" ".repeat(innerWidth)}|`;
391
+ const alignedLines = lines.map((line) => {
392
+ const space = Math.max(0, width - line.length);
393
+ const leftPad = align === "center" ? Math.floor(space / 2) : 0;
394
+ const rightPad = space - leftPad;
395
+ return `${margin}|${" ".repeat(paddingX + leftPad)}${line}${" ".repeat(paddingX + rightPad)}|`;
396
+ });
397
+ const output = [];
398
+ for (let i = 0; i < marginY; i++) output.push("");
399
+ output.push(top);
400
+ for (let i = 0; i < paddingY; i++) output.push(emptyLine);
401
+ output.push(...alignedLines);
402
+ for (let i = 0; i < paddingY; i++) output.push(emptyLine);
403
+ output.push(bottom);
404
+ for (let i = 0; i < marginY; i++) output.push("");
405
+ return output.join("\n");
117
406
  }
407
+
408
+ //#endregion
409
+ //#region src/help.ts
410
+ const isZh$5 = node_process.default.env.PI_Lang === "zh";
118
411
  async function help(argv) {
119
412
  const arg = argv[0];
120
413
  if (arg === "-v" || arg === "--version") {
121
- if (await ensureGum()) await (0, lazy_js_utils_node.jsShell)(isZh$6 ? `gum style \
122
- --foreground 212 --border-foreground 212 --border double \
123
- --align center --width 50 --margin "1 2" --padding "2 4" \
124
- "pi 版本: ${version}" "请为我的努力点一个行 🌟" "谢谢 🤟"` : `gum style \
125
- --foreground 212 --border-foreground 212 --border double \
126
- --align center --width 50 --margin "1 2" --padding "2 4" \
127
- "pi version: ${version}" "Please give me a 🌟 for my efforts" "Thank you 🤟"`, "inherit");
128
- else printPlainVersion();
414
+ const message = isZh$5 ? [
415
+ `pi 版本: ${version}`,
416
+ "请为我的努力点一个行 🌟",
417
+ "谢谢 🤟"
418
+ ] : [
419
+ `pi version: ${version}`,
420
+ "Please give me a 🌟 for my efforts",
421
+ "Thank you 🤟"
422
+ ];
423
+ console.log(renderBox(message, {
424
+ align: "center",
425
+ width: 50,
426
+ marginX: 2,
427
+ marginY: 1,
428
+ paddingX: 4,
429
+ paddingY: 2
430
+ }));
129
431
  node_process.default.exit(0);
130
432
  } else if (arg === "-h" || arg === "--help") {
131
- if (await ensureGum()) await (0, lazy_js_utils_node.jsShell)(`gum style \
132
- --foreground 212 --border-foreground 212 --border double \
133
- --align left --width 50 --margin "1 2" --padding "1 1" \
134
- "PI Commands:" "~ pi: install package" "~ pix: npx package" "~ pui: uninstall package" "~ prun: run package script" "~ pinit: package init" "~ pbuild: go build | cargo build" "~ pfind: find monorepo of yarn or pnpm" "~ pa: agent alias" "~ pu: package upgrade" "~ pci: package clean install" "~ pil: package latest install"
135
- `, "inherit");
136
- else printPlainHelp();
433
+ console.log(renderBox([
434
+ "PI Commands:",
435
+ "~ pi: install package",
436
+ "~ pix: npx package",
437
+ "~ pui: uninstall package",
438
+ "~ prun: run package script",
439
+ "~ pinit: package init",
440
+ "~ pbuild: go build | cargo build",
441
+ "~ pfind: find monorepo of yarn or pnpm",
442
+ "~ pa: agent alias",
443
+ "~ pu: package upgrade",
444
+ "~ pci: package clean install",
445
+ "~ pil: package latest install"
446
+ ], {
447
+ align: "left",
448
+ width: 50,
449
+ marginX: 2,
450
+ marginY: 1,
451
+ paddingX: 1,
452
+ paddingY: 1
453
+ }));
137
454
  node_process.default.exit(0);
138
455
  }
139
456
  }
@@ -146,46 +463,43 @@ function pa() {
146
463
 
147
464
  //#endregion
148
465
  //#region src/detectNode.ts
149
- const isZh$5 = node_process.default.env.PI_Lang === "zh";
150
466
  async function detectNode() {
151
- let pkg;
152
467
  try {
153
- pkg = await (0, lazy_js_utils_node.getPkg)();
468
+ await (0, lazy_js_utils_node.getPkg)();
154
469
  } catch {
155
470
  const cwd = node_process.default.cwd();
156
471
  console.log(picocolors.default.red(`当前目录: ${cwd} 没有package.json文件`));
157
472
  node_process.default.exit(1);
158
473
  }
159
- if (pkg.engines?.node) {
160
- const semver = await import("semver");
161
- const satisfies = semver.satisfies || semver.default?.satisfies;
162
- if (!satisfies) return;
163
- if (!satisfies(node_process.default.version, pkg.engines.node)) {
164
- const hasGum = await (0, lazy_js_utils_node.isInstallPkg)("gum");
165
- const hasFnm = await (0, lazy_js_utils_node.isInstallPkg)("fnm");
166
- if (!hasGum || !hasFnm) {
167
- const missing = [!hasGum ? "gum" : "", !hasFnm ? "fnm" : ""].filter(Boolean).join(", ");
168
- console.log(picocolors.default.yellow(isZh$5 ? `当前 node 版本不满足 ${pkg.engines.node},未检测到 ${missing},请手动切换版本。` : `Current Node version does not satisfy ${pkg.engines.node}. Missing ${missing}. Please switch manually.`));
169
- return;
170
- }
171
- const { result, status } = await (0, lazy_js_utils_node.jsShell)(`echo "yes\nno" | gum filter --placeholder=" 当前node版本不满足 ${pkg.engines.node},是否切换node版本"`, [
172
- "inherit",
173
- "pipe",
174
- "inherit"
175
- ]);
176
- if (status === 0 && result === "yes") await (0, lazy_js_utils_node.jsShell)(`
177
- current=$(echo $(fnm current))
178
- registery=$(echo "$(fnm ls)" | sed 's/system//g' | sed 's/default//g' | sed 's/\* //g' | sed "s/$current/\* $current/g" | gum filter --placeholder=" 请选择一个node版本")
179
- registery=$(echo $\{registery// /} | sed 's/\*//g')
180
- if [ $registery ]; then
181
- fnm use $\{registery% -*}
182
- fi
183
- `, [
184
- "inherit",
185
- "pipe",
186
- "inherit"
187
- ]);
188
- }
474
+ }
475
+
476
+ //#endregion
477
+ //#region src/pkgManager.ts
478
+ async function resolvePkgTool() {
479
+ const detected = await (0, lazy_js_utils_node.getPkgTool)() || "npm";
480
+ const fallback = node_process.default.env.PI_DEFAULT;
481
+ return {
482
+ detected,
483
+ tool: detected === "npm" && fallback ? fallback : detected
484
+ };
485
+ }
486
+ function getInstallCommand(tool, hasParams) {
487
+ const action = hasParams ? "add" : "install";
488
+ switch (tool) {
489
+ case "pnpm": return `pnpm ${action}`;
490
+ case "yarn": return `yarn ${action}`;
491
+ case "bun": return `bun ${action}`;
492
+ case "npm": return "npm install";
493
+ default: return `${tool} ${action}`;
494
+ }
495
+ }
496
+ function getRemoveCommand(tool) {
497
+ switch (tool) {
498
+ case "pnpm": return "pnpm remove";
499
+ case "yarn": return "yarn remove";
500
+ case "bun": return "bun remove";
501
+ case "npm": return "npm uninstall";
502
+ default: return `${tool} remove`;
189
503
  }
190
504
  }
191
505
 
@@ -400,7 +714,7 @@ async function pushHistory(command) {
400
714
  //#endregion
401
715
  //#region src/pi.ts
402
716
  const isZh$3 = node_process.default.env.PI_Lang === "zh";
403
- async function pi(params, pkg, executor = "ni") {
717
+ async function pi(params, pkg, executor = "pi") {
404
718
  await detectNode();
405
719
  const text = pkg ? `Installing ${params} ...` : "Updating dependency ...";
406
720
  const isLatest = executor === "pil";
@@ -417,22 +731,13 @@ async function pi(params, pkg, executor = "ni") {
417
731
  ];
418
732
  let loading_status;
419
733
  const { PI_DEFAULT, PI_MaxSockets: sockets } = node_process.default.env;
420
- const pkgTool = await (0, lazy_js_utils_node.getPkgTool)();
734
+ const { detected, tool } = await resolvePkgTool();
421
735
  const maxSockets = sockets || 4;
422
- const install = !params ? "install" : "add";
423
- if (pkgTool === "npm") if (PI_DEFAULT) {
424
- executor = `${PI_DEFAULT} ${install}`;
425
- loading_status = await loading(text, isSilent);
426
- } else {
427
- stdio = "inherit";
428
- executor = "ni";
429
- }
430
- else {
431
- executor = `${pkgTool} ${install}`;
432
- loading_status = await loading(text, isSilent);
433
- }
736
+ if (detected === "npm" && !PI_DEFAULT) stdio = "inherit";
737
+ else loading_status = await loading(text, isSilent);
738
+ executor = getInstallCommand(tool, Boolean(params));
434
739
  const newParams = isLatest ? "" : await getParams(params);
435
- const runSockets = executor.split(" ")[0] === "npm" ? ` --max-sockets=${maxSockets}` : "";
740
+ const runSockets = tool === "npm" ? ` --max-sockets=${maxSockets}` : "";
436
741
  const latestParams = Array.isArray(params) ? params : params ? [params] : [];
437
742
  const cmdList = isLatest ? latestParams.map((p) => `${executor} ${p}`) : [`${executor}${newParams ? ` ${newParams}` : runSockets}`];
438
743
  const runCmd = isLatest ? cmdList.join(" & ") : cmdList[0];
@@ -524,20 +829,16 @@ async function pil(params) {
524
829
  const isZh = node_process.default.env.PI_Lang === "zh";
525
830
  const { dependencies = {}, devDependencies = {} } = await (0, lazy_js_utils_node.getPkg)();
526
831
  if (!params) {
527
- if (!await (0, lazy_js_utils_node.isInstallPkg)("gum")) {
528
- console.log(picocolors.default.yellow(isZh ? "未检测到 gum,请先安装 gum 后再选择依赖。" : "gum not found. Please install gum before selecting dependencies."));
832
+ if (!isInteractive()) {
833
+ console.log(picocolors.default.yellow(isZh ? "当前不是交互式终端,请直接传入要升级的依赖。" : "No interactive TTY detected, please pass the dependency names directly."));
529
834
  node_process.default.exit(1);
530
835
  }
531
- const { result: choose, status } = await (0, lazy_js_utils_node.jsShell)(`echo ${[...Object.keys(dependencies).map((key) => `${key}: ${dependencies[key].replace(/([><~])/g, "\\$1")}`), ...Object.keys(devDependencies).map((key) => `${key}: ${devDependencies[key].replace(/([><~])/g, "\\$1")}`)].join(",")} | sed "s/,/\\n/g" | gum filter --no-limit --placeholder=" 🤔${node_process.default.env.PI_Lang === "zh" ? "请选择一个需要获取最新版本的依赖" : "Please select a dependency that needs to obtain the latest version."}"`, { stdio: [
532
- "inherit",
533
- "pipe",
534
- "inherit"
535
- ] });
536
- if (status === 130) {
836
+ const choose = await ttyMultiSelect([...Object.keys(dependencies).map((key) => `${key}: ${dependencies[key]}`), ...Object.keys(devDependencies).map((key) => `${key}: ${devDependencies[key]}`)], ` 🤔${node_process.default.env.PI_Lang === "zh" ? "请选择一个需要获取最新版本的依赖" : "Please select a dependency that needs to obtain the latest version."}`);
837
+ if (!choose || choose.length === 0) {
537
838
  console.log(picocolors.default.dim("已取消"));
538
839
  node_process.default.exit(0);
539
- } else if (status !== 0) throw new Error(choose);
540
- params = choose.trim().split("\n").map((i) => {
840
+ }
841
+ params = choose.map((i) => {
541
842
  const name = i.split(": ")[0];
542
843
  if (name in devDependencies) return `${name}@latest -D`;
543
844
  return `${name}@latest -S`;
@@ -606,11 +907,14 @@ async function pinit() {
606
907
 
607
908
  //#endregion
608
909
  //#region src/pio.ts
609
- async function pio(params, pkg, executor = "ni") {
910
+ async function pio(params, pkg) {
610
911
  const successMsg = pkg ? `Installed ${pkg} successfully! 😊` : "Updated dependency successfully! 😊";
611
912
  const failMsg = pkg ? `Failed to install ${pkg} 😭` : "Failed to update dependency! 😭";
913
+ const offline = "--prefer-offline";
914
+ const newParams = await getParams(params);
915
+ const { tool } = await resolvePkgTool();
612
916
  const { status, result } = await (0, lazy_js_utils_node.useNodeWorker)({
613
- params: `${executor} ${await getParams(params)} --prefer-offline`,
917
+ params: `${getInstallCommand(tool, Boolean(params))}${newParams ? ` ${newParams}` : ""} ${offline}`.trim(),
614
918
  stdio: "inherit"
615
919
  });
616
920
  const loading_status = await loading("");
@@ -888,15 +1192,16 @@ async function pui(params, pkg) {
888
1192
  const text = `${isZh$1 ? "正在为您卸载" : "Uninstalling"} ${pkg} ...`;
889
1193
  if (!params) {
890
1194
  const { dependencies = {}, devDependencies = {} } = await (0, lazy_js_utils_node.getPkg)();
891
- const { result: choose, status } = await (0, lazy_js_utils_node.jsShell)(`echo ${[...Object.keys(dependencies).map((key) => `${key}: ${dependencies[key]}`), ...Object.keys(devDependencies).map((key) => `${key}: ${devDependencies[key]}`)].join(",")} | sed "s/,/\\n/g" | gum filter --placeholder=" 🤔${node_process.default.env.PI_Lang === "zh" ? "请选择一个需要删除依赖" : "Please select a dependency to get the latest version."}"`, [
892
- "inherit",
893
- "pipe",
894
- "inherit"
895
- ]);
896
- if (status === 130) {
1195
+ const deps = [...Object.keys(dependencies).map((key) => `${key}: ${dependencies[key]}`), ...Object.keys(devDependencies).map((key) => `${key}: ${devDependencies[key]}`)];
1196
+ if (!isInteractive()) {
1197
+ console.log(picocolors.default.yellow(isZh$1 ? "当前不是交互式终端,请直接传入要卸载的依赖。" : "No interactive TTY detected, please pass the dependency name directly."));
1198
+ node_process.default.exit(1);
1199
+ }
1200
+ const choose = await ttySelect(deps, ` 🤔${node_process.default.env.PI_Lang === "zh" ? "请选择一个需要删除依赖" : "Please select a dependency to uninstall."}`);
1201
+ if (!choose) {
897
1202
  console.log(picocolors.default.dim("已取消"));
898
1203
  node_process.default.exit(0);
899
- } else if (status !== 0) throw new Error(choose);
1204
+ }
900
1205
  pkg = params = choose.split(": ")[0];
901
1206
  }
902
1207
  const start = Date.now();
@@ -907,7 +1212,8 @@ async function pui(params, pkg) {
907
1212
  node_process.default.exit(1);
908
1213
  }
909
1214
  const loading_status = await loading(text);
910
- const { status, result } = await (0, lazy_js_utils_node.useNodeWorker)(`nun ${params}`);
1215
+ const { tool } = await resolvePkgTool();
1216
+ const { status, result } = await (0, lazy_js_utils_node.useNodeWorker)(`${getRemoveCommand(tool)} ${params}`);
911
1217
  const costTime = (Date.now() - start) / 1e3;
912
1218
  successMsg += picocolors.default.blue(` ---- ⏰:${costTime}s`);
913
1219
  if (status === 0) loading_status.succeed(picocolors.default.green(successMsg));
@@ -1013,7 +1319,6 @@ async function setup() {
1013
1319
  return;
1014
1320
  }
1015
1321
  const pkg = argv.filter((v) => !v.startsWith("-")).join(" ");
1016
- await installDeps();
1017
1322
  await handler(params, pkg);
1018
1323
  }
1019
1324
  if (!node_process.default.env.PI_TEST) setup().catch((error) => {