@simon_he/pi 0.2.9 → 0.2.11
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/README.md +70 -4
- package/dist/index.cjs +899 -149
- package/dist/index.mjs +901 -152
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -39,19 +39,21 @@ picocolors = __toESM(picocolors);
|
|
|
39
39
|
let node_readline = require("node:readline");
|
|
40
40
|
node_readline = __toESM(node_readline);
|
|
41
41
|
let node_console = require("node:console");
|
|
42
|
-
let
|
|
43
|
-
|
|
42
|
+
let node_fs_promises = require("node:fs/promises");
|
|
43
|
+
node_fs_promises = __toESM(node_fs_promises);
|
|
44
44
|
let node_os = require("node:os");
|
|
45
45
|
node_os = __toESM(node_os);
|
|
46
|
+
let node_fs = require("node:fs");
|
|
47
|
+
node_fs = __toESM(node_fs);
|
|
46
48
|
let node_module = require("node:module");
|
|
47
49
|
let node_url = require("node:url");
|
|
48
50
|
|
|
49
51
|
//#region package.json
|
|
50
|
-
var version = "0.2.
|
|
52
|
+
var version = "0.2.11";
|
|
51
53
|
|
|
52
54
|
//#endregion
|
|
53
55
|
//#region src/tty.ts
|
|
54
|
-
const isZh$
|
|
56
|
+
const isZh$7 = node_process.default.env.PI_Lang === "zh";
|
|
55
57
|
function isInteractive() {
|
|
56
58
|
return Boolean(node_process.default.stdin.isTTY && node_process.default.stdout.isTTY);
|
|
57
59
|
}
|
|
@@ -233,7 +235,7 @@ async function runSelect(options, config) {
|
|
|
233
235
|
if (anchor) {
|
|
234
236
|
const prompt = "> ";
|
|
235
237
|
const header = `? ${config.placeholder}`;
|
|
236
|
-
const hintLine = `${config.mode === "multiple" ? isZh$
|
|
238
|
+
const hintLine = `${config.mode === "multiple" ? isZh$7 ? "↑/↓ 选择,空格标记,Tab 补全,/ 搜索,回车确认,Esc 取消" : "Use ↑/↓ to move, Space to toggle, Tab to complete, / to search, Enter to confirm, Esc to cancel" : isZh$7 ? "↑/↓ 选择,Tab 补全,/ 搜索,回车确认,Esc 取消" : "Use ↑/↓ to move, Tab to complete, / to search, Enter to confirm, Esc to cancel"} (1/${options.length})`;
|
|
237
239
|
const headerRows = rowCount(header, columns);
|
|
238
240
|
const inputRows = rowCount(`${prompt}`, columns);
|
|
239
241
|
const hintRows = rowCount(hintLine, columns);
|
|
@@ -271,10 +273,10 @@ async function runSelect(options, config) {
|
|
|
271
273
|
const hintLine = (() => {
|
|
272
274
|
const position = ` (${Math.min(cursor + 1, filtered.length)}/${filtered.length})`;
|
|
273
275
|
if (config.mode === "multiple") {
|
|
274
|
-
if (isZh$
|
|
276
|
+
if (isZh$7) return picocolors.default.dim("↑/↓ 选择,") + picocolors.default.bold(picocolors.default.cyan("空格")) + picocolors.default.dim(" 标记,Tab 补全,/ 搜索,回车确认,Esc 取消") + picocolors.default.dim(position);
|
|
275
277
|
return picocolors.default.dim("Use ↑/↓ to move, ") + picocolors.default.bold(picocolors.default.cyan("Space")) + picocolors.default.dim(" to toggle, Tab to complete, / to search, Enter to confirm, Esc to cancel") + picocolors.default.dim(position);
|
|
276
278
|
}
|
|
277
|
-
const hint = isZh$
|
|
279
|
+
const hint = isZh$7 ? "↑/↓ 选择,Tab 补全,/ 搜索,回车确认,Esc 取消" : "Use ↑/↓ to move, Tab to complete, / to search, Enter to confirm, Esc to cancel";
|
|
278
280
|
return picocolors.default.dim(`${hint}${position}`);
|
|
279
281
|
})();
|
|
280
282
|
const headerRows = rowCount(header, columns);
|
|
@@ -288,7 +290,7 @@ async function runSelect(options, config) {
|
|
|
288
290
|
const maxVisibleRaw = needsScroll ? Math.max(minVisibleTarget, optionAreaRows - ellipsisReserve) : filtered.length;
|
|
289
291
|
const maxVisible = Math.max(1, Math.min(maxVisibleRaw, optionAreaRows, filtered.length));
|
|
290
292
|
const lines = [header, inputLine];
|
|
291
|
-
if (filtered.length === 0) lines.push(picocolors.default.dim(isZh$
|
|
293
|
+
if (filtered.length === 0) lines.push(picocolors.default.dim(isZh$7 ? "没有匹配项" : "No matches"));
|
|
292
294
|
else {
|
|
293
295
|
const window = getVisibleWindow(filtered.length, cursor, maxVisible);
|
|
294
296
|
const visible = filtered.slice(window.start, window.end);
|
|
@@ -489,11 +491,11 @@ function renderBox(lines, options = {}) {
|
|
|
489
491
|
|
|
490
492
|
//#endregion
|
|
491
493
|
//#region src/help.ts
|
|
492
|
-
const isZh$
|
|
494
|
+
const isZh$6 = node_process.default.env.PI_Lang === "zh";
|
|
493
495
|
async function help(argv) {
|
|
494
496
|
const arg = argv[0];
|
|
495
497
|
if (arg === "-v" || arg === "--version") {
|
|
496
|
-
const message = isZh$
|
|
498
|
+
const message = isZh$6 ? [
|
|
497
499
|
`pi 版本: ${version}`,
|
|
498
500
|
"请为我的努力点一个行 🌟",
|
|
499
501
|
"谢谢 🤟"
|
|
@@ -515,6 +517,13 @@ async function help(argv) {
|
|
|
515
517
|
console.log(renderBox([
|
|
516
518
|
"PI Commands:",
|
|
517
519
|
"~ pi: install package",
|
|
520
|
+
"~ pi --choose-tool: choose package manager for this workspace",
|
|
521
|
+
"~ pi --choose-tool bun: choose the tool directly",
|
|
522
|
+
"~ pi --forget-tool: clear saved package manager choice",
|
|
523
|
+
"~ pi --show-tool: show current workspace package manager",
|
|
524
|
+
"~ pi --show-tool --json: show current tool as JSON",
|
|
525
|
+
"~ pi --list-tools: list detected package-manager candidates",
|
|
526
|
+
"~ pi --list-tools --json: list candidates as JSON",
|
|
518
527
|
"~ pix: npx package",
|
|
519
528
|
"~ pui: uninstall package",
|
|
520
529
|
"~ prun: run package script",
|
|
@@ -524,10 +533,24 @@ async function help(argv) {
|
|
|
524
533
|
"~ pa: agent alias",
|
|
525
534
|
"~ pu: package upgrade",
|
|
526
535
|
"~ pci: package clean install",
|
|
527
|
-
"~
|
|
536
|
+
"~ pci --choose-tool: re-pick tool before clean install",
|
|
537
|
+
"~ pci --choose-tool bun: choose the tool directly",
|
|
538
|
+
"~ pci --forget-tool: clear saved tool before clean install",
|
|
539
|
+
"~ pci --show-tool: show current tool before clean install",
|
|
540
|
+
"~ pci --show-tool --json: show current tool as JSON",
|
|
541
|
+
"~ pci --list-tools: list detected candidates",
|
|
542
|
+
"~ pci --list-tools --json: list candidates as JSON",
|
|
543
|
+
"~ pil: package latest install",
|
|
544
|
+
"~ pil --choose-tool: re-pick tool before latest install",
|
|
545
|
+
"~ pil --choose-tool bun: choose the tool directly",
|
|
546
|
+
"~ pil --forget-tool: clear saved tool before latest install",
|
|
547
|
+
"~ pil --show-tool: show current tool before latest install",
|
|
548
|
+
"~ pil --show-tool --json: show current tool as JSON",
|
|
549
|
+
"~ pil --list-tools: list detected candidates",
|
|
550
|
+
"~ pil --list-tools --json: list candidates as JSON"
|
|
528
551
|
], {
|
|
529
552
|
align: "left",
|
|
530
|
-
width:
|
|
553
|
+
width: 76,
|
|
531
554
|
marginX: 2,
|
|
532
555
|
marginY: 1,
|
|
533
556
|
paddingX: 1,
|
|
@@ -557,9 +580,27 @@ async function detectNode() {
|
|
|
557
580
|
|
|
558
581
|
//#endregion
|
|
559
582
|
//#region src/pkgManager.ts
|
|
583
|
+
const resolvedToolCache = /* @__PURE__ */ new Map();
|
|
584
|
+
const toolIndicatorMap = {
|
|
585
|
+
pnpm: ["pnpm-workspace.yaml", "pnpm-lock.yaml"],
|
|
586
|
+
yarn: ["yarn.lock", ".yarnrc.yml"],
|
|
587
|
+
bun: ["bun.lock", "bun.lockb"],
|
|
588
|
+
npm: ["package-lock.json", "npm-shrinkwrap.json"]
|
|
589
|
+
};
|
|
590
|
+
const isZh$5 = node_process.default.env.PI_Lang === "zh";
|
|
591
|
+
const supportedPkgTools$1 = Object.keys(toolIndicatorMap);
|
|
592
|
+
function isEnabled(value) {
|
|
593
|
+
if (!value) return false;
|
|
594
|
+
const normalized = value.toLowerCase();
|
|
595
|
+
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
596
|
+
}
|
|
560
597
|
function normalizeDir$1(dir) {
|
|
561
598
|
return node_path.default.resolve(dir);
|
|
562
599
|
}
|
|
600
|
+
function isSameOrInsideDir(base, target) {
|
|
601
|
+
const relative = node_path.default.relative(base, target);
|
|
602
|
+
return relative === "" || !relative.startsWith("..") && !node_path.default.isAbsolute(relative);
|
|
603
|
+
}
|
|
563
604
|
function findUpSync$1(startDir, predicate) {
|
|
564
605
|
let current = normalizeDir$1(startDir);
|
|
565
606
|
while (true) {
|
|
@@ -569,24 +610,332 @@ function findUpSync$1(startDir, predicate) {
|
|
|
569
610
|
current = parent;
|
|
570
611
|
}
|
|
571
612
|
}
|
|
572
|
-
function
|
|
573
|
-
|
|
574
|
-
if (
|
|
575
|
-
|
|
576
|
-
return null;
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
613
|
+
function findToolCandidate(cwd, tool) {
|
|
614
|
+
const indicators = toolIndicatorMap[tool];
|
|
615
|
+
if (!indicators?.length) return null;
|
|
616
|
+
const root = findUpSync$1(cwd, (dir) => indicators.some((indicator) => (0, lazy_js_utils.isFile)(node_path.default.join(dir, indicator))));
|
|
617
|
+
if (!root) return null;
|
|
618
|
+
const foundIndicators = indicators.filter((indicator) => (0, lazy_js_utils.isFile)(node_path.default.join(root, indicator)));
|
|
619
|
+
return {
|
|
620
|
+
tool,
|
|
621
|
+
root,
|
|
622
|
+
indicators: foundIndicators.length ? foundIndicators : indicators.slice(0, 1)
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function getToolCandidates(cwd) {
|
|
626
|
+
return Object.keys(toolIndicatorMap).map((tool) => findToolCandidate(cwd, tool)).filter(Boolean);
|
|
627
|
+
}
|
|
628
|
+
function getPreferenceWorkspaceKey(cwd, candidates) {
|
|
629
|
+
const roots = [...new Set(candidates.map((candidate) => normalizeDir$1(candidate.root)))];
|
|
630
|
+
if (roots.length === 1) return roots[0];
|
|
631
|
+
return normalizeDir$1(cwd);
|
|
632
|
+
}
|
|
633
|
+
function findStoredWorkspaceKey(cwd, preferences) {
|
|
634
|
+
return Object.keys(preferences.workspaces).filter((workspaceKey) => isSameOrInsideDir(workspaceKey, cwd)).sort((a, b) => b.length - a.length)[0] || null;
|
|
635
|
+
}
|
|
636
|
+
function resolveWorkspaceKey(cwd, candidates, preferences) {
|
|
637
|
+
if (candidates.length > 0) return getPreferenceWorkspaceKey(cwd, candidates);
|
|
638
|
+
return findStoredWorkspaceKey(cwd, preferences) || normalizeDir$1(cwd);
|
|
639
|
+
}
|
|
640
|
+
function getConfigHome() {
|
|
641
|
+
const home = node_process.default.env.HOME || node_os.default.homedir();
|
|
642
|
+
if (node_process.default.platform === "win32") return node_process.default.env.APPDATA || node_path.default.join(home, "AppData", "Roaming");
|
|
643
|
+
return node_process.default.env.XDG_CONFIG_HOME || node_path.default.join(home, ".config");
|
|
644
|
+
}
|
|
645
|
+
function getWorkspaceToolPreferencePath() {
|
|
646
|
+
return node_path.default.join(getConfigHome(), "pi", "workspace-tools.json");
|
|
647
|
+
}
|
|
648
|
+
async function readWorkspaceToolPreferences() {
|
|
649
|
+
const configPath = getWorkspaceToolPreferencePath();
|
|
650
|
+
try {
|
|
651
|
+
const raw = await node_fs_promises.default.readFile(configPath, "utf8");
|
|
652
|
+
const parsed = JSON.parse(raw);
|
|
653
|
+
return {
|
|
654
|
+
version: 1,
|
|
655
|
+
workspaces: parsed.workspaces && typeof parsed.workspaces === "object" ? parsed.workspaces : {}
|
|
656
|
+
};
|
|
657
|
+
} catch {
|
|
658
|
+
return {
|
|
659
|
+
version: 1,
|
|
660
|
+
workspaces: {}
|
|
661
|
+
};
|
|
583
662
|
}
|
|
584
|
-
|
|
663
|
+
}
|
|
664
|
+
async function writeWorkspaceToolPreference(workspaceKey, tool) {
|
|
665
|
+
const configPath = getWorkspaceToolPreferencePath();
|
|
666
|
+
const data = await readWorkspaceToolPreferences();
|
|
667
|
+
data.workspaces[workspaceKey] = tool;
|
|
668
|
+
await node_fs_promises.default.mkdir(node_path.default.dirname(configPath), { recursive: true });
|
|
669
|
+
await node_fs_promises.default.writeFile(configPath, JSON.stringify(data, null, 2), "utf8");
|
|
670
|
+
resolvedToolCache.clear();
|
|
671
|
+
}
|
|
672
|
+
async function deleteWorkspaceToolPreference(workspaceKey) {
|
|
673
|
+
const configPath = getWorkspaceToolPreferencePath();
|
|
674
|
+
const data = await readWorkspaceToolPreferences();
|
|
675
|
+
if (!(workspaceKey in data.workspaces)) return;
|
|
676
|
+
delete data.workspaces[workspaceKey];
|
|
677
|
+
await node_fs_promises.default.mkdir(node_path.default.dirname(configPath), { recursive: true });
|
|
678
|
+
await node_fs_promises.default.writeFile(configPath, JSON.stringify(data, null, 2), "utf8");
|
|
679
|
+
resolvedToolCache.clear();
|
|
680
|
+
}
|
|
681
|
+
async function forgetPkgToolPreference() {
|
|
682
|
+
const workspaceKey = findStoredWorkspaceKey(normalizeDir$1(node_process.default.cwd()), await readWorkspaceToolPreferences());
|
|
683
|
+
if (!workspaceKey) return false;
|
|
684
|
+
await deleteWorkspaceToolPreference(workspaceKey);
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
function getSupportedPkgToolNames() {
|
|
688
|
+
return supportedPkgTools$1.slice();
|
|
689
|
+
}
|
|
690
|
+
function getPreferredToolFromEnv(candidates) {
|
|
691
|
+
const preferred = node_process.default.env.PI_DEFAULT;
|
|
692
|
+
if (!preferred) return null;
|
|
693
|
+
return candidates.some((candidate) => candidate.tool === preferred) ? preferred : null;
|
|
694
|
+
}
|
|
695
|
+
function getExplicitPreferredTool(value) {
|
|
696
|
+
if (!value) return null;
|
|
697
|
+
return supportedPkgTools$1.includes(value) ? value : null;
|
|
698
|
+
}
|
|
699
|
+
function validateExplicitPreferredTool(preferredTool, candidates) {
|
|
700
|
+
if (candidates.length === 0) return true;
|
|
701
|
+
return candidates.some((candidate) => candidate.tool === preferredTool);
|
|
702
|
+
}
|
|
703
|
+
function logInvalidPreferredTool(preferredTool, candidates) {
|
|
704
|
+
const names = candidates.map((candidate) => candidate.tool).join(", ");
|
|
705
|
+
console.log(picocolors.default.red(isZh$5 ? `当前 workspace 可选的包管理器是: ${names},不能直接指定 ${preferredTool}。` : `This workspace supports: ${names}. ${preferredTool} cannot be selected directly here.`));
|
|
706
|
+
}
|
|
707
|
+
function getDetectedToolFallback(detected, candidates) {
|
|
708
|
+
if (candidates.some((candidate) => candidate.tool === detected)) return detected;
|
|
709
|
+
return candidates[0]?.tool || detected;
|
|
710
|
+
}
|
|
711
|
+
function formatCandidateLabel(candidate, cwd) {
|
|
712
|
+
const indicators = candidate.indicators.join(", ");
|
|
713
|
+
const relativeRoot = node_path.default.relative(cwd, candidate.root) || ".";
|
|
714
|
+
if (relativeRoot === ".") return `${candidate.tool}: ${indicators}`;
|
|
715
|
+
return `${candidate.tool}: ${indicators} (${relativeRoot})`;
|
|
716
|
+
}
|
|
717
|
+
function toCandidateInfo(candidates) {
|
|
718
|
+
return candidates.map((candidate) => ({
|
|
719
|
+
tool: candidate.tool,
|
|
720
|
+
indicators: candidate.indicators,
|
|
721
|
+
root: candidate.root
|
|
722
|
+
}));
|
|
723
|
+
}
|
|
724
|
+
async function selectToolCandidate(candidates, cwd) {
|
|
725
|
+
if (!isInteractive()) return { status: "unavailable" };
|
|
726
|
+
const options = candidates.map((candidate) => formatCandidateLabel(candidate, cwd));
|
|
727
|
+
const labelToTool = new Map(candidates.map((candidate) => [formatCandidateLabel(candidate, cwd), candidate.tool]));
|
|
728
|
+
const choice = await ttySelect(options, isZh$5 ? "🤔检测到多个包管理环境,请选择当前 workspace 使用的安装方式" : "Multiple package managers were detected, choose one for this workspace.");
|
|
729
|
+
if (!choice) return { status: "cancelled" };
|
|
730
|
+
const tool = labelToTool.get(choice);
|
|
731
|
+
if (!tool) return { status: "cancelled" };
|
|
585
732
|
return {
|
|
733
|
+
status: "selected",
|
|
734
|
+
tool
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
function logAmbiguousToolFallback(candidates, tool) {
|
|
738
|
+
const names = candidates.map((candidate) => candidate.tool).join(", ");
|
|
739
|
+
console.log(picocolors.default.yellow(isZh$5 ? `检测到多个包管理环境(${names}),当前不是交互式终端,临时使用 ${tool}。可在交互式终端运行一次 pi 以保存当前 workspace 的选择。` : `Detected multiple package managers (${names}). Using ${tool} for now because no interactive TTY is available. Run pi once in an interactive shell to save this workspace preference.`));
|
|
740
|
+
}
|
|
741
|
+
function getSourceLabel(source) {
|
|
742
|
+
switch (source) {
|
|
743
|
+
case "saved-preference": return isZh$5 ? "已保存的 workspace 选择" : "saved workspace choice";
|
|
744
|
+
case "fresh-selection": return isZh$5 ? "本次重新选择并保存" : "picked now and saved";
|
|
745
|
+
case "single-candidate": return isZh$5 ? "当前只检测到一种包管理器标记" : "single detected package-manager indicator";
|
|
746
|
+
case "env-default": return isZh$5 ? "PI_DEFAULT 兜底" : "PI_DEFAULT fallback";
|
|
747
|
+
case "detected-tool": return isZh$5 ? "环境自动检测结果" : "environment auto-detection";
|
|
748
|
+
case "non-interactive-fallback": return isZh$5 ? "非交互终端下的临时兜底" : "non-interactive fallback";
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
function logWorkspaceToolSelected(tool, forceChoose) {
|
|
752
|
+
console.log(picocolors.default.green(forceChoose ? isZh$5 ? `当前 workspace 已切换为使用 ${tool},并保存了这个选择。` : `This workspace now uses ${tool}, and the choice has been saved.` : isZh$5 ? `已为当前 workspace 记住 ${tool} 作为包管理器。` : `Saved ${tool} as the package manager for this workspace.`));
|
|
753
|
+
}
|
|
754
|
+
function logWorkspaceToolResolved(tool) {
|
|
755
|
+
console.log(picocolors.default.green(isZh$5 ? `当前 workspace 使用 ${tool} 作为包管理器。` : `This workspace uses ${tool} as the package manager.`));
|
|
756
|
+
}
|
|
757
|
+
function logStaleWorkspaceToolRemoved(tool) {
|
|
758
|
+
console.log(picocolors.default.yellow(isZh$5 ? `检测到之前保存的 ${tool} 已不再适用于当前 workspace,已自动清除旧记录。` : `The saved ${tool} choice no longer matches this workspace and was removed automatically.`));
|
|
759
|
+
}
|
|
760
|
+
async function preparePkgToolContext(forgetPreference = false) {
|
|
761
|
+
const cwd = normalizeDir$1(node_process.default.cwd());
|
|
762
|
+
const originalDetected = await (0, lazy_js_utils_node.getPkgTool)() || "npm";
|
|
763
|
+
const candidates = getToolCandidates(cwd);
|
|
764
|
+
const preferences = await readWorkspaceToolPreferences();
|
|
765
|
+
const workspaceKey = resolveWorkspaceKey(cwd, candidates, preferences);
|
|
766
|
+
let detected = originalDetected;
|
|
767
|
+
if (forgetPreference) await deleteWorkspaceToolPreference(workspaceKey);
|
|
768
|
+
if (forgetPreference) delete preferences.workspaces[workspaceKey];
|
|
769
|
+
let rememberedTool = preferences.workspaces[workspaceKey];
|
|
770
|
+
if (rememberedTool && !candidates.some((candidate) => candidate.tool === rememberedTool)) {
|
|
771
|
+
await deleteWorkspaceToolPreference(workspaceKey);
|
|
772
|
+
delete preferences.workspaces[workspaceKey];
|
|
773
|
+
logStaleWorkspaceToolRemoved(rememberedTool);
|
|
774
|
+
rememberedTool = void 0;
|
|
775
|
+
}
|
|
776
|
+
if (detected === "npm" && candidates.length === 1) detected = candidates[0].tool;
|
|
777
|
+
return {
|
|
778
|
+
detected,
|
|
779
|
+
candidates,
|
|
780
|
+
rememberedTool
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
async function getPkgToolStatus() {
|
|
784
|
+
const { detected, candidates, rememberedTool } = await preparePkgToolContext();
|
|
785
|
+
const candidateInfo = toCandidateInfo(candidates);
|
|
786
|
+
if (rememberedTool) return {
|
|
787
|
+
status: "resolved",
|
|
788
|
+
detected,
|
|
789
|
+
tool: rememberedTool,
|
|
790
|
+
source: "saved-preference",
|
|
791
|
+
candidates: candidateInfo
|
|
792
|
+
};
|
|
793
|
+
if (candidates.length <= 1) {
|
|
794
|
+
const fallback = node_process.default.env.PI_DEFAULT;
|
|
795
|
+
return {
|
|
796
|
+
status: "resolved",
|
|
797
|
+
detected,
|
|
798
|
+
tool: detected === "npm" && fallback ? fallback : detected,
|
|
799
|
+
source: detected === "npm" && fallback ? "env-default" : candidates.length === 1 ? "single-candidate" : "detected-tool",
|
|
800
|
+
candidates: candidateInfo
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
const envPreferredTool = getPreferredToolFromEnv(candidates);
|
|
804
|
+
if (envPreferredTool) return {
|
|
805
|
+
status: "resolved",
|
|
806
|
+
detected,
|
|
807
|
+
tool: envPreferredTool,
|
|
808
|
+
source: "env-default",
|
|
809
|
+
candidates: candidateInfo
|
|
810
|
+
};
|
|
811
|
+
if (!isInteractive()) return {
|
|
812
|
+
status: "resolved",
|
|
813
|
+
detected,
|
|
814
|
+
tool: getDetectedToolFallback(detected, candidates),
|
|
815
|
+
source: "non-interactive-fallback",
|
|
816
|
+
candidates: candidateInfo
|
|
817
|
+
};
|
|
818
|
+
return {
|
|
819
|
+
status: "needs-selection",
|
|
586
820
|
detected,
|
|
587
|
-
|
|
821
|
+
candidates: candidateInfo
|
|
588
822
|
};
|
|
589
823
|
}
|
|
824
|
+
function printPkgToolStatus(status, options = {}) {
|
|
825
|
+
if (options.json) {
|
|
826
|
+
console.log(JSON.stringify({
|
|
827
|
+
...status,
|
|
828
|
+
sourceLabel: status.status === "resolved" ? getSourceLabel(status.source) : void 0
|
|
829
|
+
}, null, 2));
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (status.status === "resolved") {
|
|
833
|
+
const candidateNames = status.candidates.map((candidate) => candidate.tool).join(", ");
|
|
834
|
+
console.log(picocolors.default.green(isZh$5 ? `当前 workspace 使用 ${status.tool} 作为包管理器。` : `This workspace uses ${status.tool} as the package manager.`));
|
|
835
|
+
console.log(picocolors.default.cyan(`${isZh$5 ? "来源" : "Source"}: ${getSourceLabel(status.source)}`));
|
|
836
|
+
if (candidateNames) console.log(picocolors.default.dim(`${isZh$5 ? "候选项" : "Candidates"}: ${candidateNames}`));
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const candidateNames = status.candidates.map((candidate) => candidate.tool).join(", ");
|
|
840
|
+
console.log(picocolors.default.yellow(isZh$5 ? "当前 workspace 还没有固定包管理器选择。" : "This workspace does not have a locked package-manager choice yet."));
|
|
841
|
+
console.log(picocolors.default.cyan(`${isZh$5 ? "原因" : "Reason"}: ${isZh$5 ? "检测到了多个包管理器标记,且当前没有保存的选择。" : "Multiple package-manager indicators were found and no saved choice exists yet."}`));
|
|
842
|
+
console.log(picocolors.default.dim(`${isZh$5 ? "候选项" : "Candidates"}: ${candidateNames}`));
|
|
843
|
+
console.log(picocolors.default.dim(isZh$5 ? "可执行 `pi --choose-tool` 来保存当前 workspace 的选择。" : "Run `pi --choose-tool` to save a choice for this workspace."));
|
|
844
|
+
}
|
|
845
|
+
function printPkgToolCandidates(status, options = {}) {
|
|
846
|
+
if (options.json) {
|
|
847
|
+
console.log(JSON.stringify({
|
|
848
|
+
...status,
|
|
849
|
+
sourceLabel: status.status === "resolved" ? getSourceLabel(status.source) : void 0
|
|
850
|
+
}, null, 2));
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (status.status === "resolved") {
|
|
854
|
+
console.log(picocolors.default.green(isZh$5 ? `当前 workspace 使用 ${status.tool} 作为包管理器。` : `This workspace uses ${status.tool} as the package manager.`));
|
|
855
|
+
console.log(picocolors.default.cyan(`${isZh$5 ? "来源" : "Source"}: ${getSourceLabel(status.source)}`));
|
|
856
|
+
} else console.log(picocolors.default.yellow(isZh$5 ? "当前 workspace 还没有固定包管理器选择。" : "This workspace does not have a locked package-manager choice yet."));
|
|
857
|
+
if (status.candidates.length === 0) {
|
|
858
|
+
console.log(picocolors.default.dim(isZh$5 ? "当前 workspace 没有检测到明确的 lockfile / workspace 候选。" : "No explicit lockfile or workspace candidates were detected in this workspace."));
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
console.log(picocolors.default.bold(isZh$5 ? "候选工具:" : "Candidate tools:"));
|
|
862
|
+
for (const candidate of status.candidates) {
|
|
863
|
+
const indicators = candidate.indicators.join(", ");
|
|
864
|
+
console.log(`- ${candidate.tool}`);
|
|
865
|
+
console.log(picocolors.default.dim(` ${isZh$5 ? "root" : "root"}: ${candidate.root}`));
|
|
866
|
+
console.log(picocolors.default.dim(` ${isZh$5 ? "indicators" : "indicators"}: ${indicators}`));
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
async function resolvePkgTool(options = {}) {
|
|
870
|
+
const cwd = normalizeDir$1(node_process.default.cwd());
|
|
871
|
+
const forceChoose = options.forceChoose || isEnabled(node_process.default.env.PI_FORCE_PICK_TOOL);
|
|
872
|
+
const forgetPreference = options.forgetPreference || isEnabled(node_process.default.env.PI_FORGET_PICK_TOOL);
|
|
873
|
+
const preferredTool = getExplicitPreferredTool(options.preferredTool || node_process.default.env.PI_PREFERRED_TOOL);
|
|
874
|
+
const shouldBypassCache = forceChoose || forgetPreference || Boolean(preferredTool);
|
|
875
|
+
const cached = resolvedToolCache.get(cwd);
|
|
876
|
+
if (!shouldBypassCache && cached) return cached;
|
|
877
|
+
const pending = (async () => {
|
|
878
|
+
const { detected, candidates, rememberedTool } = await preparePkgToolContext(forgetPreference);
|
|
879
|
+
if (preferredTool) {
|
|
880
|
+
if (!validateExplicitPreferredTool(preferredTool, candidates)) {
|
|
881
|
+
logInvalidPreferredTool(preferredTool, candidates);
|
|
882
|
+
node_process.default.exit(1);
|
|
883
|
+
}
|
|
884
|
+
await writeWorkspaceToolPreference(resolveWorkspaceKey(normalizeDir$1(node_process.default.cwd()), candidates, await readWorkspaceToolPreferences()), preferredTool);
|
|
885
|
+
logWorkspaceToolSelected(preferredTool, true);
|
|
886
|
+
return {
|
|
887
|
+
detected,
|
|
888
|
+
tool: preferredTool,
|
|
889
|
+
source: "fresh-selection"
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
if (!forceChoose && rememberedTool) return {
|
|
893
|
+
detected,
|
|
894
|
+
tool: rememberedTool,
|
|
895
|
+
source: "saved-preference"
|
|
896
|
+
};
|
|
897
|
+
if (candidates.length <= 1) {
|
|
898
|
+
const fallback = node_process.default.env.PI_DEFAULT;
|
|
899
|
+
const tool = detected === "npm" && fallback ? fallback : detected;
|
|
900
|
+
if (forceChoose) logWorkspaceToolResolved(tool);
|
|
901
|
+
return {
|
|
902
|
+
detected,
|
|
903
|
+
tool,
|
|
904
|
+
source: detected === "npm" && fallback ? "env-default" : candidates.length === 1 ? "single-candidate" : "detected-tool"
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
const envPreferredTool = getPreferredToolFromEnv(candidates);
|
|
908
|
+
if (!forceChoose && envPreferredTool) return {
|
|
909
|
+
detected,
|
|
910
|
+
tool: envPreferredTool,
|
|
911
|
+
source: "env-default"
|
|
912
|
+
};
|
|
913
|
+
const cwdForSelection = normalizeDir$1(node_process.default.cwd());
|
|
914
|
+
const selection = await selectToolCandidate(candidates, cwd);
|
|
915
|
+
if (selection.status === "selected") {
|
|
916
|
+
await writeWorkspaceToolPreference(resolveWorkspaceKey(cwdForSelection, candidates, await readWorkspaceToolPreferences()), selection.tool);
|
|
917
|
+
logWorkspaceToolSelected(selection.tool, forceChoose);
|
|
918
|
+
return {
|
|
919
|
+
detected,
|
|
920
|
+
tool: selection.tool,
|
|
921
|
+
source: "fresh-selection"
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
if (selection.status === "cancelled") {
|
|
925
|
+
console.log(picocolors.default.dim(isZh$5 ? "已取消" : "Cancelled"));
|
|
926
|
+
node_process.default.exit(0);
|
|
927
|
+
}
|
|
928
|
+
const tool = getDetectedToolFallback(detected, candidates);
|
|
929
|
+
logAmbiguousToolFallback(candidates, tool);
|
|
930
|
+
return {
|
|
931
|
+
detected,
|
|
932
|
+
tool,
|
|
933
|
+
source: "non-interactive-fallback"
|
|
934
|
+
};
|
|
935
|
+
})();
|
|
936
|
+
resolvedToolCache.set(cwd, pending);
|
|
937
|
+
return pending;
|
|
938
|
+
}
|
|
590
939
|
function getInstallCommand(tool, hasParams) {
|
|
591
940
|
const action = hasParams ? "add" : "install";
|
|
592
941
|
switch (tool) {
|
|
@@ -644,12 +993,7 @@ async function findUpAsync(startDir, predicate) {
|
|
|
644
993
|
async function getParams(params) {
|
|
645
994
|
const cwd = node_process.default.cwd();
|
|
646
995
|
try {
|
|
647
|
-
|
|
648
|
-
if (tool === "npm") {
|
|
649
|
-
if (findUpSync(cwd, (dir) => (0, lazy_js_utils.isFile)(node_path.default.join(dir, "pnpm-workspace.yaml")) || (0, lazy_js_utils.isFile)(node_path.default.join(dir, "pnpm-lock.yaml")))) tool = "pnpm";
|
|
650
|
-
else if (findUpSync(cwd, (dir) => (0, lazy_js_utils.isFile)(node_path.default.join(dir, "yarn.lock")) || (0, lazy_js_utils.isFile)(node_path.default.join(dir, ".yarnrc.yml")))) tool = "yarn";
|
|
651
|
-
else if (findUpSync(cwd, (dir) => (0, lazy_js_utils.isFile)(node_path.default.join(dir, "bun.lockb")))) tool = "bun";
|
|
652
|
-
}
|
|
996
|
+
const { tool } = await resolvePkgTool();
|
|
653
997
|
switch (tool) {
|
|
654
998
|
case "pnpm": {
|
|
655
999
|
const pnpmWorkspaceRoot = findUpSync(cwd, (dir) => (0, lazy_js_utils.isFile)(node_path.default.join(dir, "pnpm-workspace.yaml")));
|
|
@@ -886,9 +1230,9 @@ async function pi(params, pkg, executor = "pi") {
|
|
|
886
1230
|
];
|
|
887
1231
|
let loading_status;
|
|
888
1232
|
const { PI_DEFAULT, PI_MaxSockets: sockets } = node_process.default.env;
|
|
889
|
-
const {
|
|
1233
|
+
const { tool } = await resolvePkgTool();
|
|
890
1234
|
const maxSockets = sockets || 4;
|
|
891
|
-
if (
|
|
1235
|
+
if (tool === "npm" && !PI_DEFAULT) stdio = "inherit";
|
|
892
1236
|
else loading_status = await loading(text, isSilent);
|
|
893
1237
|
executor = getInstallCommand(tool, Boolean(params));
|
|
894
1238
|
const newParams = isLatest ? "" : await getParams(params);
|
|
@@ -956,16 +1300,419 @@ function getCcommand() {
|
|
|
956
1300
|
}
|
|
957
1301
|
|
|
958
1302
|
//#endregion
|
|
959
|
-
//#region src/
|
|
1303
|
+
//#region src/prun.ts
|
|
1304
|
+
async function prun(params) {
|
|
1305
|
+
ensurePrunAutoInit();
|
|
1306
|
+
const hadNoHistoryEnv = node_process.default.env.CCOMMAND_NO_HISTORY != null || node_process.default.env.NO_HISTORY != null;
|
|
1307
|
+
const initialNoHistory = node_process.default.env.CCOMMAND_NO_HISTORY ?? node_process.default.env.NO_HISTORY;
|
|
1308
|
+
const prevNoHistory = node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
1309
|
+
if (!(hadNoHistoryEnv && isNoHistory$1(initialNoHistory))) delete node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
1310
|
+
else node_process.default.env.CCOMMAND_NO_HISTORY = "1";
|
|
1311
|
+
const { ccommand } = getCcommand();
|
|
1312
|
+
try {
|
|
1313
|
+
await ccommand(params);
|
|
1314
|
+
} finally {
|
|
1315
|
+
if (prevNoHistory == null) delete node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
1316
|
+
else node_process.default.env.CCOMMAND_NO_HISTORY = prevNoHistory;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
const isZh$2 = node_process.default.env.PI_Lang === "zh";
|
|
1320
|
+
const safeShellValue = /^[\w./:@%+=,-]+$/;
|
|
960
1321
|
function isNoHistory$1(value) {
|
|
961
1322
|
if (!value) return false;
|
|
962
1323
|
const normalized = value.toLowerCase();
|
|
963
1324
|
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
964
1325
|
}
|
|
1326
|
+
function shellQuote(value) {
|
|
1327
|
+
if (value === "") return "''";
|
|
1328
|
+
if (safeShellValue.test(value)) return value;
|
|
1329
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
1330
|
+
}
|
|
1331
|
+
function powerShellQuote(value) {
|
|
1332
|
+
if (value === "") return "''";
|
|
1333
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
1334
|
+
}
|
|
1335
|
+
function splitCommand(value) {
|
|
1336
|
+
const parts = [];
|
|
1337
|
+
let current = "";
|
|
1338
|
+
let quote = null;
|
|
1339
|
+
let hasValue = false;
|
|
1340
|
+
const pushCurrent = () => {
|
|
1341
|
+
if (!hasValue) return;
|
|
1342
|
+
parts.push(current);
|
|
1343
|
+
current = "";
|
|
1344
|
+
hasValue = false;
|
|
1345
|
+
};
|
|
1346
|
+
for (let i = 0; i < value.length; i++) {
|
|
1347
|
+
const char = value[i];
|
|
1348
|
+
if (quote) {
|
|
1349
|
+
if (char === quote) {
|
|
1350
|
+
quote = null;
|
|
1351
|
+
hasValue = true;
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
if (quote === "\"" && char === "\\") {
|
|
1355
|
+
const next = value[i + 1];
|
|
1356
|
+
if (next) {
|
|
1357
|
+
current += next;
|
|
1358
|
+
hasValue = true;
|
|
1359
|
+
i++;
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
current += char;
|
|
1364
|
+
hasValue = true;
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
if (char === "\"" || char === "'") {
|
|
1368
|
+
quote = char;
|
|
1369
|
+
hasValue = true;
|
|
1370
|
+
continue;
|
|
1371
|
+
}
|
|
1372
|
+
if (/\s/.test(char)) {
|
|
1373
|
+
pushCurrent();
|
|
1374
|
+
while (i + 1 < value.length && /\s/.test(value[i + 1])) i++;
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
if (char === "\\") {
|
|
1378
|
+
const next = value[i + 1];
|
|
1379
|
+
if (next) {
|
|
1380
|
+
current += next;
|
|
1381
|
+
hasValue = true;
|
|
1382
|
+
i++;
|
|
1383
|
+
continue;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
current += char;
|
|
1387
|
+
hasValue = true;
|
|
1388
|
+
}
|
|
1389
|
+
pushCurrent();
|
|
1390
|
+
return parts;
|
|
1391
|
+
}
|
|
1392
|
+
function normalizeShellName(value) {
|
|
1393
|
+
const shell = (value || "").toLowerCase().replace(/\.exe$/, "");
|
|
1394
|
+
if (shell === "powershell") return "powershell";
|
|
1395
|
+
if (shell === "pwsh") return "pwsh";
|
|
1396
|
+
if (shell === "fish" || shell === "zsh" || shell === "bash") return shell;
|
|
1397
|
+
return shell;
|
|
1398
|
+
}
|
|
1399
|
+
function detectShell() {
|
|
1400
|
+
const envShell = normalizeShellName(node_path.default.basename(node_process.default.env.SHELL || ""));
|
|
1401
|
+
if (node_process.default.env.FISH_VERSION) return "fish";
|
|
1402
|
+
if (node_process.default.env.ZSH_VERSION) return "zsh";
|
|
1403
|
+
if (node_process.default.env.BASH_VERSION) return "bash";
|
|
1404
|
+
if (node_process.default.env.POWERSHELL_DISTRIBUTION_CHANNEL) return "pwsh";
|
|
1405
|
+
if (envShell) return envShell;
|
|
1406
|
+
if (node_process.default.platform === "win32") return "powershell";
|
|
1407
|
+
return "zsh";
|
|
1408
|
+
}
|
|
1409
|
+
function getPowerShellProfilePath(shell, home) {
|
|
1410
|
+
if (node_process.default.platform === "win32") {
|
|
1411
|
+
const documentsHome = node_process.default.env.USERPROFILE || home;
|
|
1412
|
+
const profileDir = shell === "pwsh" ? "PowerShell" : "WindowsPowerShell";
|
|
1413
|
+
return node_path.default.join(documentsHome, "Documents", profileDir, "Microsoft.PowerShell_profile.ps1");
|
|
1414
|
+
}
|
|
1415
|
+
const configHome = node_process.default.env.XDG_CONFIG_HOME || node_path.default.join(home, ".config");
|
|
1416
|
+
return node_path.default.join(configHome, "powershell", "Microsoft.PowerShell_profile.ps1");
|
|
1417
|
+
}
|
|
1418
|
+
function ensurePrunAutoInit() {
|
|
1419
|
+
if (!shouldAutoInit()) return;
|
|
1420
|
+
const shell = detectShell();
|
|
1421
|
+
const home = node_process.default.env.HOME || node_os.default.homedir();
|
|
1422
|
+
let rcFile = "";
|
|
1423
|
+
let initLine = "";
|
|
1424
|
+
if (shell === "zsh") {
|
|
1425
|
+
const zdotdir = node_process.default.env.ZDOTDIR || home;
|
|
1426
|
+
rcFile = node_path.default.join(zdotdir, ".zshrc");
|
|
1427
|
+
initLine = "eval \"$(prun --init zsh)\"";
|
|
1428
|
+
} else if (shell === "bash") {
|
|
1429
|
+
rcFile = node_path.default.join(home, ".bashrc");
|
|
1430
|
+
initLine = "eval \"$(prun --init bash)\"";
|
|
1431
|
+
} else if (shell === "fish") {
|
|
1432
|
+
const configHome = node_process.default.env.XDG_CONFIG_HOME || node_path.default.join(home, ".config");
|
|
1433
|
+
rcFile = node_path.default.join(configHome, "fish", "config.fish");
|
|
1434
|
+
initLine = "prun --init fish | source";
|
|
1435
|
+
} else if (shell === "powershell" || shell === "pwsh") {
|
|
1436
|
+
rcFile = getPowerShellProfilePath(shell, home);
|
|
1437
|
+
initLine = `prun --init ${shell} | Out-String | Invoke-Expression`;
|
|
1438
|
+
} else return;
|
|
1439
|
+
try {
|
|
1440
|
+
const dir = node_path.default.dirname(rcFile);
|
|
1441
|
+
if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
|
|
1442
|
+
const content = node_fs.default.existsSync(rcFile) ? node_fs.default.readFileSync(rcFile, "utf8") : "";
|
|
1443
|
+
if (!/prun\s+--init/.test(content)) {
|
|
1444
|
+
const prefix = content.length && !content.endsWith("\n") ? "\n" : "";
|
|
1445
|
+
node_fs.default.appendFileSync(rcFile, `${prefix}${initLine}\n`, "utf8");
|
|
1446
|
+
}
|
|
1447
|
+
} catch {}
|
|
1448
|
+
}
|
|
1449
|
+
function shouldAutoInit() {
|
|
1450
|
+
const auto = node_process.default.env.PI_AUTO_INIT || node_process.default.env.PRUN_AUTO_INIT;
|
|
1451
|
+
if (auto != null) return isNoHistory$1(auto);
|
|
1452
|
+
if (isNoHistory$1(node_process.default.env.PI_NO_AUTO_INIT || node_process.default.env.PRUN_NO_AUTO_INIT)) return false;
|
|
1453
|
+
if (node_process.default.env.CI) return false;
|
|
1454
|
+
if (!node_process.default.stdout.isTTY || !node_process.default.stdin.isTTY) return false;
|
|
1455
|
+
return true;
|
|
1456
|
+
}
|
|
1457
|
+
function printPrunInit(args = []) {
|
|
1458
|
+
const shellArg = normalizeShellName(args[0]);
|
|
1459
|
+
const binArg = args[1] || node_process.default.env.PRUN_BIN || "prun";
|
|
1460
|
+
const bin = shellQuote(binArg);
|
|
1461
|
+
const shell = shellArg || detectShell() || "zsh";
|
|
1462
|
+
const historyHintExpr = "${CCOMMAND_HISTORY_HINT:-${XDG_CACHE_HOME:-$HOME/.cache}/ccommand/last-history}";
|
|
1463
|
+
let script = "";
|
|
1464
|
+
if (shell === "zsh") script = [
|
|
1465
|
+
"prun() {",
|
|
1466
|
+
` local bin=${bin}`,
|
|
1467
|
+
" local -a cmd",
|
|
1468
|
+
" cmd=(${=bin})",
|
|
1469
|
+
" command \"${cmd[@]}\" \"$@\"",
|
|
1470
|
+
"}",
|
|
1471
|
+
"__prun_sync_history() {",
|
|
1472
|
+
" local history_disable=${CCOMMAND_NO_HISTORY:-${NO_HISTORY:-\"\"}}",
|
|
1473
|
+
" local history_disable_lower=${history_disable:l}",
|
|
1474
|
+
" if [[ $history_disable_lower == \"1\" || $history_disable_lower == \"true\" || $history_disable_lower == \"yes\" ]]; then",
|
|
1475
|
+
" return",
|
|
1476
|
+
" fi",
|
|
1477
|
+
` local history_hint=${historyHintExpr}`,
|
|
1478
|
+
" if [[ ! -f $history_hint ]]; then",
|
|
1479
|
+
" return",
|
|
1480
|
+
" fi",
|
|
1481
|
+
" local line",
|
|
1482
|
+
" line=$(<\"$history_hint\")",
|
|
1483
|
+
" local hint_ts=${line%%$'\\t'*}",
|
|
1484
|
+
" local hint_cmd=${line#*$'\\t'}",
|
|
1485
|
+
" if [[ -z $hint_ts || $hint_ts == $line ]]; then",
|
|
1486
|
+
" hint_cmd=$line",
|
|
1487
|
+
" hint_ts=\"\"",
|
|
1488
|
+
" fi",
|
|
1489
|
+
" if [[ -n $hint_ts && $hint_ts == ${__PRUN_HISTORY_HINT_TS:-\"\"} ]]; then",
|
|
1490
|
+
" return",
|
|
1491
|
+
" fi",
|
|
1492
|
+
" __PRUN_HISTORY_HINT_TS=$hint_ts",
|
|
1493
|
+
" fc -R",
|
|
1494
|
+
" if [[ $hint_cmd != pfind* && $hint_cmd != prun* ]]; then",
|
|
1495
|
+
" return",
|
|
1496
|
+
" fi",
|
|
1497
|
+
" local last_line",
|
|
1498
|
+
" last_line=$(fc -l -1 2>/dev/null)",
|
|
1499
|
+
" local last_cmd",
|
|
1500
|
+
" last_cmd=$(printf \"%s\" \"$last_line\" | sed -E \"s/^[[:space:]]*[0-9]+[[:space:]]*//\")",
|
|
1501
|
+
" if [[ $last_cmd == \"$hint_cmd\" ]]; then",
|
|
1502
|
+
" return",
|
|
1503
|
+
" fi",
|
|
1504
|
+
" if [[ $last_cmd == prun || $last_cmd == prun\\ * ]]; then",
|
|
1505
|
+
" local last_num",
|
|
1506
|
+
" last_num=$(printf \"%s\" \"$last_line\" | sed -E \"s/^[[:space:]]*([0-9]+).*/\\1/\")",
|
|
1507
|
+
" if [[ -n $last_num ]]; then",
|
|
1508
|
+
" history -d $last_num 2>/dev/null",
|
|
1509
|
+
" fi",
|
|
1510
|
+
" fi",
|
|
1511
|
+
" print -s -- \"$hint_cmd\"",
|
|
1512
|
+
"}",
|
|
1513
|
+
"",
|
|
1514
|
+
"if ! typeset -f __prun_precmd >/dev/null; then",
|
|
1515
|
+
" __prun_precmd() { __prun_sync_history }",
|
|
1516
|
+
" autoload -Uz add-zsh-hook",
|
|
1517
|
+
" add-zsh-hook precmd __prun_precmd",
|
|
1518
|
+
"fi"
|
|
1519
|
+
].join("\n");
|
|
1520
|
+
else if (shell === "bash") script = [
|
|
1521
|
+
"prun() {",
|
|
1522
|
+
` local bin=${bin}`,
|
|
1523
|
+
" local -a cmd",
|
|
1524
|
+
" read -r -a cmd <<< \"$bin\"",
|
|
1525
|
+
" command \"${cmd[@]}\" \"$@\"",
|
|
1526
|
+
"}",
|
|
1527
|
+
"__prun_sync_history() {",
|
|
1528
|
+
" local history_disable=${CCOMMAND_NO_HISTORY:-${NO_HISTORY:-\"\"}}",
|
|
1529
|
+
" local history_disable_lower",
|
|
1530
|
+
" history_disable_lower=$(printf '%s' \"$history_disable\" | tr '[:upper:]' '[:lower:]')",
|
|
1531
|
+
" if [[ $history_disable_lower == \"1\" || $history_disable_lower == \"true\" || $history_disable_lower == \"yes\" ]]; then",
|
|
1532
|
+
" return",
|
|
1533
|
+
" fi",
|
|
1534
|
+
` local history_hint=${historyHintExpr}`,
|
|
1535
|
+
" if [[ ! -f $history_hint ]]; then",
|
|
1536
|
+
" return",
|
|
1537
|
+
" fi",
|
|
1538
|
+
" local line",
|
|
1539
|
+
" line=$(<\"$history_hint\")",
|
|
1540
|
+
" local hint_ts=\"${line%%$'\\t'*}\"",
|
|
1541
|
+
" local hint_cmd=\"${line#*$'\\t'}\"",
|
|
1542
|
+
" if [[ -z $hint_ts || $hint_ts == \"$line\" ]]; then",
|
|
1543
|
+
" hint_cmd=\"$line\"",
|
|
1544
|
+
" hint_ts=\"\"",
|
|
1545
|
+
" fi",
|
|
1546
|
+
" if [[ -n $hint_ts && $hint_ts == \"${__PRUN_HISTORY_HINT_TS:-}\" ]]; then",
|
|
1547
|
+
" return",
|
|
1548
|
+
" fi",
|
|
1549
|
+
" __PRUN_HISTORY_HINT_TS=$hint_ts",
|
|
1550
|
+
" if [[ $hint_cmd != pfind* && $hint_cmd != prun* ]]; then",
|
|
1551
|
+
" return",
|
|
1552
|
+
" fi",
|
|
1553
|
+
" history -n",
|
|
1554
|
+
" local last_line",
|
|
1555
|
+
" last_line=$(history 1)",
|
|
1556
|
+
" local last_cmd",
|
|
1557
|
+
" last_cmd=$(printf \"%s\" \"$last_line\" | sed -E \"s/^[[:space:]]*[0-9]+[[:space:]]*//\")",
|
|
1558
|
+
" if [[ $last_cmd == \"$hint_cmd\" ]]; then",
|
|
1559
|
+
" return",
|
|
1560
|
+
" fi",
|
|
1561
|
+
" if [[ $last_cmd == prun || $last_cmd == prun\\ * ]]; then",
|
|
1562
|
+
" local last_num",
|
|
1563
|
+
" last_num=$(printf \"%s\" \"$last_line\" | sed -E \"s/^[[:space:]]*([0-9]+).*/\\1/\")",
|
|
1564
|
+
" if [[ -n $last_num ]]; then",
|
|
1565
|
+
" history -d \"$last_num\" 2>/dev/null",
|
|
1566
|
+
" fi",
|
|
1567
|
+
" fi",
|
|
1568
|
+
" history -s -- \"$hint_cmd\"",
|
|
1569
|
+
"}",
|
|
1570
|
+
"",
|
|
1571
|
+
"if [[ -z \"${__PRUN_PROMPT_INSTALLED:-}\" ]]; then",
|
|
1572
|
+
" __PRUN_PROMPT_INSTALLED=1",
|
|
1573
|
+
" if [[ -n \"${PROMPT_COMMAND:-}\" ]]; then",
|
|
1574
|
+
" PROMPT_COMMAND=\"__prun_sync_history;${PROMPT_COMMAND}\"",
|
|
1575
|
+
" else",
|
|
1576
|
+
" PROMPT_COMMAND=\"__prun_sync_history\"",
|
|
1577
|
+
" fi",
|
|
1578
|
+
"fi"
|
|
1579
|
+
].join("\n");
|
|
1580
|
+
else if (shell === "fish") script = [
|
|
1581
|
+
"function prun",
|
|
1582
|
+
` set -l bin ${bin}`,
|
|
1583
|
+
" set -l cmd (string split -- \" \" $bin)",
|
|
1584
|
+
" command $cmd $argv",
|
|
1585
|
+
" set -l history_disable $CCOMMAND_NO_HISTORY",
|
|
1586
|
+
" if test -z \"$history_disable\"",
|
|
1587
|
+
" set history_disable $NO_HISTORY",
|
|
1588
|
+
" end",
|
|
1589
|
+
" set history_disable (string lower -- (string trim -- \"$history_disable\"))",
|
|
1590
|
+
" if test \"$history_disable\" != \"1\" -a \"$history_disable\" != \"true\" -a \"$history_disable\" != \"yes\"",
|
|
1591
|
+
" history --merge",
|
|
1592
|
+
" set -l history_hint $CCOMMAND_HISTORY_HINT",
|
|
1593
|
+
" if test -z \"$history_hint\"",
|
|
1594
|
+
" set -l cache_home $XDG_CACHE_HOME",
|
|
1595
|
+
" if test -z \"$cache_home\"",
|
|
1596
|
+
" set cache_home \"$HOME/.cache\"",
|
|
1597
|
+
" end",
|
|
1598
|
+
" set history_hint \"$cache_home/ccommand/last-history\"",
|
|
1599
|
+
" end",
|
|
1600
|
+
" if test -f \"$history_hint\"",
|
|
1601
|
+
" set -l last_cmd (string trim -- (cat \"$history_hint\"))",
|
|
1602
|
+
" set -l last_cmd (string replace -r \"^[0-9]+\\t\" \"\" -- \"$last_cmd\")",
|
|
1603
|
+
" if string match -q \"pfind*\" -- \"$last_cmd\"; or string match -q \"prun*\" -- \"$last_cmd\"",
|
|
1604
|
+
" set -l last_hist (history --max=1)",
|
|
1605
|
+
" if test \"$last_hist\" != \"$last_cmd\"",
|
|
1606
|
+
" history add -- \"$last_cmd\"",
|
|
1607
|
+
" end",
|
|
1608
|
+
" end",
|
|
1609
|
+
" end",
|
|
1610
|
+
" end",
|
|
1611
|
+
"end"
|
|
1612
|
+
].join("\n");
|
|
1613
|
+
else if (shell === "powershell" || shell === "pwsh") script = [
|
|
1614
|
+
`$script:__prun_bin = @(${splitCommand(binArg).map(powerShellQuote).join(", ") || powerShellQuote("prun")})`,
|
|
1615
|
+
"",
|
|
1616
|
+
"function global:prun {",
|
|
1617
|
+
" param([Parameter(ValueFromRemainingArguments = $true)] [string[]] $CliArgs)",
|
|
1618
|
+
" $command = $script:__prun_bin[0]",
|
|
1619
|
+
" if ($command -ieq \"prun\") {",
|
|
1620
|
+
" $resolved = Get-Command -Name $command -CommandType Application,ExternalScript -ErrorAction SilentlyContinue | Select-Object -First 1",
|
|
1621
|
+
" if ($null -ne $resolved) {",
|
|
1622
|
+
" if ($resolved.Path) { $command = $resolved.Path }",
|
|
1623
|
+
" elseif ($resolved.Definition) { $command = $resolved.Definition }",
|
|
1624
|
+
" elseif ($resolved.Source) { $command = $resolved.Source }",
|
|
1625
|
+
" }",
|
|
1626
|
+
" }",
|
|
1627
|
+
" $extra = @()",
|
|
1628
|
+
" if ($script:__prun_bin.Count -gt 1) {",
|
|
1629
|
+
" $extra = $script:__prun_bin[1..($script:__prun_bin.Count - 1)]",
|
|
1630
|
+
" }",
|
|
1631
|
+
" & $command @extra @CliArgs",
|
|
1632
|
+
"}",
|
|
1633
|
+
"",
|
|
1634
|
+
"function global:__prun_sync_history {",
|
|
1635
|
+
" $historyDisable = $env:CCOMMAND_NO_HISTORY",
|
|
1636
|
+
" if ([string]::IsNullOrWhiteSpace($historyDisable)) {",
|
|
1637
|
+
" $historyDisable = $env:NO_HISTORY",
|
|
1638
|
+
" }",
|
|
1639
|
+
" $historyDisable = \"$historyDisable\".Trim().ToLowerInvariant()",
|
|
1640
|
+
" if ($historyDisable -eq \"1\" -or $historyDisable -eq \"true\" -or $historyDisable -eq \"yes\") {",
|
|
1641
|
+
" return",
|
|
1642
|
+
" }",
|
|
1643
|
+
" $historyHint = $env:CCOMMAND_HISTORY_HINT",
|
|
1644
|
+
" if ([string]::IsNullOrWhiteSpace($historyHint)) {",
|
|
1645
|
+
" $cacheHome = $env:XDG_CACHE_HOME",
|
|
1646
|
+
" if ([string]::IsNullOrWhiteSpace($cacheHome)) {",
|
|
1647
|
+
" $cacheHome = Join-Path $HOME \".cache\"",
|
|
1648
|
+
" }",
|
|
1649
|
+
" $historyHint = Join-Path (Join-Path $cacheHome \"ccommand\") \"last-history\"",
|
|
1650
|
+
" }",
|
|
1651
|
+
" if (-not (Test-Path -LiteralPath $historyHint)) {",
|
|
1652
|
+
" return",
|
|
1653
|
+
" }",
|
|
1654
|
+
" $line = (Get-Content -LiteralPath $historyHint -Raw -ErrorAction SilentlyContinue)",
|
|
1655
|
+
" if ([string]::IsNullOrWhiteSpace($line)) {",
|
|
1656
|
+
" return",
|
|
1657
|
+
" }",
|
|
1658
|
+
" $line = $line.Trim()",
|
|
1659
|
+
" $hintTs = \"\"",
|
|
1660
|
+
" $hintCmd = $line",
|
|
1661
|
+
" $parts = $line -split \"`t\", 2",
|
|
1662
|
+
" if ($parts.Count -eq 2 -and $parts[0] -match \"^\\d+$\") {",
|
|
1663
|
+
" $hintTs = $parts[0]",
|
|
1664
|
+
" $hintCmd = $parts[1]",
|
|
1665
|
+
" }",
|
|
1666
|
+
" if (-not $hintCmd.StartsWith(\"prun\") -and -not $hintCmd.StartsWith(\"pfind\")) {",
|
|
1667
|
+
" return",
|
|
1668
|
+
" }",
|
|
1669
|
+
" if ($hintTs -and $script:__PRUN_HISTORY_HINT_TS -eq $hintTs) {",
|
|
1670
|
+
" return",
|
|
1671
|
+
" }",
|
|
1672
|
+
" $script:__PRUN_HISTORY_HINT_TS = $hintTs",
|
|
1673
|
+
" $psReadLineType = \"Microsoft.PowerShell.PSConsoleReadLine\" -as [type]",
|
|
1674
|
+
" if ($null -eq $psReadLineType) {",
|
|
1675
|
+
" return",
|
|
1676
|
+
" }",
|
|
1677
|
+
" $psReadLineType::AddToHistory($hintCmd)",
|
|
1678
|
+
"}",
|
|
1679
|
+
"",
|
|
1680
|
+
"if (-not $script:__PRUN_PROMPT_INSTALLED) {",
|
|
1681
|
+
" $script:__PRUN_PROMPT_INSTALLED = $true",
|
|
1682
|
+
" if (-not $script:__prun_original_prompt) {",
|
|
1683
|
+
" if (Test-Path Function:\\prompt) {",
|
|
1684
|
+
" $script:__prun_original_prompt = $function:prompt",
|
|
1685
|
+
" }",
|
|
1686
|
+
" }",
|
|
1687
|
+
" function global:prompt {",
|
|
1688
|
+
" __prun_sync_history",
|
|
1689
|
+
" if ($script:__prun_original_prompt) {",
|
|
1690
|
+
" & $script:__prun_original_prompt",
|
|
1691
|
+
" return",
|
|
1692
|
+
" }",
|
|
1693
|
+
" \"PS $($executionContext.SessionState.Path.CurrentLocation)> \"",
|
|
1694
|
+
" }",
|
|
1695
|
+
"}"
|
|
1696
|
+
].join("\n");
|
|
1697
|
+
else {
|
|
1698
|
+
console.log(picocolors.default.red(isZh$2 ? `不支持的 shell: ${shell}` : `Unsupported shell: ${shell}`));
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
console.log(script);
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
//#endregion
|
|
1705
|
+
//#region src/pfind.ts
|
|
1706
|
+
function isNoHistory(value) {
|
|
1707
|
+
if (!value) return false;
|
|
1708
|
+
const normalized = value.toLowerCase();
|
|
1709
|
+
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
1710
|
+
}
|
|
965
1711
|
async function pfind(params) {
|
|
1712
|
+
ensurePrunAutoInit();
|
|
966
1713
|
const hadNoHistoryEnv = node_process.default.env.CCOMMAND_NO_HISTORY != null || node_process.default.env.NO_HISTORY != null;
|
|
967
1714
|
const initialNoHistory = node_process.default.env.CCOMMAND_NO_HISTORY ?? node_process.default.env.NO_HISTORY;
|
|
968
|
-
const shouldWriteHistory = !(hadNoHistoryEnv && isNoHistory
|
|
1715
|
+
const shouldWriteHistory = !(hadNoHistoryEnv && isNoHistory(initialNoHistory));
|
|
969
1716
|
const prevNoHistory = node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
970
1717
|
if (shouldWriteHistory) delete node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
971
1718
|
else node_process.default.env.CCOMMAND_NO_HISTORY = "1";
|
|
@@ -1087,117 +1834,6 @@ async function pix(params) {
|
|
|
1087
1834
|
}
|
|
1088
1835
|
}
|
|
1089
1836
|
|
|
1090
|
-
//#endregion
|
|
1091
|
-
//#region src/prun.ts
|
|
1092
|
-
async function prun(params) {
|
|
1093
|
-
ensurePrunAutoInit();
|
|
1094
|
-
const hadNoHistoryEnv = node_process.default.env.CCOMMAND_NO_HISTORY != null || node_process.default.env.NO_HISTORY != null;
|
|
1095
|
-
const initialNoHistory = node_process.default.env.CCOMMAND_NO_HISTORY ?? node_process.default.env.NO_HISTORY;
|
|
1096
|
-
const prevNoHistory = node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
1097
|
-
if (!(hadNoHistoryEnv && isNoHistory(initialNoHistory))) delete node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
1098
|
-
else node_process.default.env.CCOMMAND_NO_HISTORY = "1";
|
|
1099
|
-
const { ccommand } = getCcommand();
|
|
1100
|
-
try {
|
|
1101
|
-
await ccommand(params);
|
|
1102
|
-
} finally {
|
|
1103
|
-
if (prevNoHistory == null) delete node_process.default.env.CCOMMAND_NO_HISTORY;
|
|
1104
|
-
else node_process.default.env.CCOMMAND_NO_HISTORY = prevNoHistory;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
const isZh$2 = node_process.default.env.PI_Lang === "zh";
|
|
1108
|
-
const safeShellValue = /^[\w./:@%+=,-]+$/;
|
|
1109
|
-
function isNoHistory(value) {
|
|
1110
|
-
if (!value) return false;
|
|
1111
|
-
const normalized = value.toLowerCase();
|
|
1112
|
-
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
1113
|
-
}
|
|
1114
|
-
function shellQuote(value) {
|
|
1115
|
-
if (value === "") return "''";
|
|
1116
|
-
if (safeShellValue.test(value)) return value;
|
|
1117
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
1118
|
-
}
|
|
1119
|
-
function detectShell() {
|
|
1120
|
-
const envShell = node_process.default.env.SHELL || "";
|
|
1121
|
-
if (node_process.default.env.FISH_VERSION) return "fish";
|
|
1122
|
-
if (node_process.default.env.ZSH_VERSION) return "zsh";
|
|
1123
|
-
if (node_process.default.env.BASH_VERSION) return "bash";
|
|
1124
|
-
return envShell.split("/").pop() || "zsh";
|
|
1125
|
-
}
|
|
1126
|
-
function ensurePrunAutoInit() {
|
|
1127
|
-
if (!shouldAutoInit()) return;
|
|
1128
|
-
const shell = detectShell();
|
|
1129
|
-
const home = node_process.default.env.HOME || node_os.default.homedir();
|
|
1130
|
-
let rcFile = "";
|
|
1131
|
-
let initLine = "";
|
|
1132
|
-
if (shell === "zsh") {
|
|
1133
|
-
const zdotdir = node_process.default.env.ZDOTDIR || home;
|
|
1134
|
-
rcFile = node_path.default.join(zdotdir, ".zshrc");
|
|
1135
|
-
initLine = "eval \"$(prun --init zsh)\"";
|
|
1136
|
-
} else if (shell === "bash") {
|
|
1137
|
-
rcFile = node_path.default.join(home, ".bashrc");
|
|
1138
|
-
initLine = "eval \"$(prun --init bash)\"";
|
|
1139
|
-
} else if (shell === "fish") {
|
|
1140
|
-
const configHome = node_process.default.env.XDG_CONFIG_HOME || node_path.default.join(home, ".config");
|
|
1141
|
-
rcFile = node_path.default.join(configHome, "fish", "config.fish");
|
|
1142
|
-
initLine = "prun --init fish | source";
|
|
1143
|
-
} else return;
|
|
1144
|
-
try {
|
|
1145
|
-
const dir = node_path.default.dirname(rcFile);
|
|
1146
|
-
if (!node_fs.default.existsSync(dir)) node_fs.default.mkdirSync(dir, { recursive: true });
|
|
1147
|
-
const content = node_fs.default.existsSync(rcFile) ? node_fs.default.readFileSync(rcFile, "utf8") : "";
|
|
1148
|
-
if (!/prun\s+--init/.test(content)) {
|
|
1149
|
-
const prefix = content.length && !content.endsWith("\n") ? "\n" : "";
|
|
1150
|
-
node_fs.default.appendFileSync(rcFile, `${prefix}${initLine}\n`, "utf8");
|
|
1151
|
-
}
|
|
1152
|
-
} catch {}
|
|
1153
|
-
}
|
|
1154
|
-
function shouldAutoInit() {
|
|
1155
|
-
const auto = node_process.default.env.PI_AUTO_INIT || node_process.default.env.PRUN_AUTO_INIT;
|
|
1156
|
-
if (auto != null) return isNoHistory(auto);
|
|
1157
|
-
if (isNoHistory(node_process.default.env.PI_NO_AUTO_INIT || node_process.default.env.PRUN_NO_AUTO_INIT)) return false;
|
|
1158
|
-
if (node_process.default.env.CI) return false;
|
|
1159
|
-
if (!node_process.default.stdout.isTTY || !node_process.default.stdin.isTTY) return false;
|
|
1160
|
-
return true;
|
|
1161
|
-
}
|
|
1162
|
-
function printPrunInit(args = []) {
|
|
1163
|
-
const shellArg = args[0];
|
|
1164
|
-
const binArg = args[1];
|
|
1165
|
-
const bin = shellQuote(binArg || node_process.default.env.PRUN_BIN || "prun");
|
|
1166
|
-
const shell = shellArg || detectShell() || "zsh";
|
|
1167
|
-
let script = "";
|
|
1168
|
-
if (shell === "zsh") script = [
|
|
1169
|
-
"prun() {",
|
|
1170
|
-
` local bin=${bin}`,
|
|
1171
|
-
" local -a cmd",
|
|
1172
|
-
" cmd=(${=bin})",
|
|
1173
|
-
" command \"${cmd[@]}\" \"$@\"",
|
|
1174
|
-
" fc -R",
|
|
1175
|
-
"}"
|
|
1176
|
-
].join("\n");
|
|
1177
|
-
else if (shell === "bash") script = [
|
|
1178
|
-
"prun() {",
|
|
1179
|
-
` local bin=${bin}`,
|
|
1180
|
-
" local -a cmd",
|
|
1181
|
-
" read -r -a cmd <<< \"$bin\"",
|
|
1182
|
-
" command \"${cmd[@]}\" \"$@\"",
|
|
1183
|
-
" history -n",
|
|
1184
|
-
"}"
|
|
1185
|
-
].join("\n");
|
|
1186
|
-
else if (shell === "fish") script = [
|
|
1187
|
-
"function prun",
|
|
1188
|
-
` set -l bin ${bin}`,
|
|
1189
|
-
" set -l cmd (string split -- \" \" $bin)",
|
|
1190
|
-
" command $cmd $argv",
|
|
1191
|
-
" history --merge",
|
|
1192
|
-
"end"
|
|
1193
|
-
].join("\n");
|
|
1194
|
-
else {
|
|
1195
|
-
console.log(picocolors.default.red(isZh$2 ? `不支持的 shell: ${shell}` : `Unsupported shell: ${shell}`));
|
|
1196
|
-
return;
|
|
1197
|
-
}
|
|
1198
|
-
console.log(script);
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
1837
|
//#endregion
|
|
1202
1838
|
//#region src/pu.ts
|
|
1203
1839
|
function pu() {
|
|
@@ -1268,6 +1904,72 @@ const runMap = {
|
|
|
1268
1904
|
"pio.mjs": pio
|
|
1269
1905
|
};
|
|
1270
1906
|
const isZh = node_process.default.env.PI_Lang === "zh";
|
|
1907
|
+
const pkgToolFlagCommands = new Set([
|
|
1908
|
+
"pi",
|
|
1909
|
+
"pi.mjs",
|
|
1910
|
+
"pil",
|
|
1911
|
+
"pil.mjs",
|
|
1912
|
+
"pci",
|
|
1913
|
+
"pci.mjs"
|
|
1914
|
+
]);
|
|
1915
|
+
const supportedPkgTools = new Set(getSupportedPkgToolNames());
|
|
1916
|
+
function parsePkgToolFlags(argv) {
|
|
1917
|
+
const hasInspectFlag = argv.includes("--show-tool") || argv.includes("--list-tools");
|
|
1918
|
+
let chooseTool = false;
|
|
1919
|
+
let forgetTool = false;
|
|
1920
|
+
let listTools = false;
|
|
1921
|
+
let showTool = false;
|
|
1922
|
+
let showToolJson = false;
|
|
1923
|
+
let preferredTool = "";
|
|
1924
|
+
let invalidPreferredTool = "";
|
|
1925
|
+
const normalizedArgv = [];
|
|
1926
|
+
for (let i = 0; i < argv.length; i++) {
|
|
1927
|
+
const arg = argv[i];
|
|
1928
|
+
if (arg === "--forget-tool") {
|
|
1929
|
+
forgetTool = true;
|
|
1930
|
+
continue;
|
|
1931
|
+
}
|
|
1932
|
+
if (arg === "--show-tool") {
|
|
1933
|
+
showTool = true;
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1936
|
+
if (arg === "--list-tools") {
|
|
1937
|
+
listTools = true;
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
if (arg === "--json" && hasInspectFlag) {
|
|
1941
|
+
showToolJson = true;
|
|
1942
|
+
continue;
|
|
1943
|
+
}
|
|
1944
|
+
if (arg === "--choose-tool") {
|
|
1945
|
+
chooseTool = true;
|
|
1946
|
+
const next = argv[i + 1];
|
|
1947
|
+
if (next && supportedPkgTools.has(next)) {
|
|
1948
|
+
preferredTool = next;
|
|
1949
|
+
i++;
|
|
1950
|
+
}
|
|
1951
|
+
continue;
|
|
1952
|
+
}
|
|
1953
|
+
if (arg.startsWith("--choose-tool=")) {
|
|
1954
|
+
chooseTool = true;
|
|
1955
|
+
const value = arg.slice(14);
|
|
1956
|
+
if (supportedPkgTools.has(value)) preferredTool = value;
|
|
1957
|
+
else invalidPreferredTool = value;
|
|
1958
|
+
continue;
|
|
1959
|
+
}
|
|
1960
|
+
normalizedArgv.push(arg);
|
|
1961
|
+
}
|
|
1962
|
+
return {
|
|
1963
|
+
chooseTool,
|
|
1964
|
+
forgetTool,
|
|
1965
|
+
invalidPreferredTool,
|
|
1966
|
+
listTools,
|
|
1967
|
+
normalizedArgv,
|
|
1968
|
+
preferredTool,
|
|
1969
|
+
showTool,
|
|
1970
|
+
showToolJson
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1271
1973
|
async function setup() {
|
|
1272
1974
|
const cmd = node_process.default.argv[1];
|
|
1273
1975
|
let exec = "";
|
|
@@ -1284,8 +1986,56 @@ async function setup() {
|
|
|
1284
1986
|
printPrunInit(argv.slice(1));
|
|
1285
1987
|
return;
|
|
1286
1988
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1989
|
+
const supportsPkgToolFlags = pkgToolFlagCommands.has(exec);
|
|
1990
|
+
const { chooseTool, forgetTool, invalidPreferredTool, listTools, normalizedArgv, preferredTool, showTool, showToolJson } = supportsPkgToolFlags ? parsePkgToolFlags(argv) : {
|
|
1991
|
+
chooseTool: false,
|
|
1992
|
+
forgetTool: false,
|
|
1993
|
+
invalidPreferredTool: "",
|
|
1994
|
+
listTools: false,
|
|
1995
|
+
normalizedArgv: argv,
|
|
1996
|
+
preferredTool: "",
|
|
1997
|
+
showTool: false,
|
|
1998
|
+
showToolJson: false
|
|
1999
|
+
};
|
|
2000
|
+
if (invalidPreferredTool) {
|
|
2001
|
+
console.log(picocolors.default.red(isZh ? `不支持直接指定 ${invalidPreferredTool},可选值为: ${getSupportedPkgToolNames().join(", ")}` : `Unsupported tool "${invalidPreferredTool}". Valid values: ${getSupportedPkgToolNames().join(", ")}`));
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
if (chooseTool) node_process.default.env.PI_FORCE_PICK_TOOL = "1";
|
|
2005
|
+
else delete node_process.default.env.PI_FORCE_PICK_TOOL;
|
|
2006
|
+
if (forgetTool) node_process.default.env.PI_FORGET_PICK_TOOL = "1";
|
|
2007
|
+
else delete node_process.default.env.PI_FORGET_PICK_TOOL;
|
|
2008
|
+
if (preferredTool) node_process.default.env.PI_PREFERRED_TOOL = preferredTool;
|
|
2009
|
+
else delete node_process.default.env.PI_PREFERRED_TOOL;
|
|
2010
|
+
let params = (0, lazy_js_utils.spaceFormat)(normalizedArgv.join(" ")).trim();
|
|
2011
|
+
const hasPackage = await (0, lazy_js_utils_node.hasPkg)(rootPath);
|
|
2012
|
+
if (supportsPkgToolFlags && (chooseTool || forgetTool || showTool || listTools)) {
|
|
2013
|
+
if (!hasPackage) {
|
|
2014
|
+
console.log(picocolors.default.yellow(isZh ? "当前命令仅在 Node 项目的包管理场景下可用。" : "This option is only available for package-manager selection in Node projects."));
|
|
2015
|
+
return;
|
|
2016
|
+
}
|
|
2017
|
+
if (showTool || listTools) {
|
|
2018
|
+
if (forgetTool && !chooseTool) {
|
|
2019
|
+
const removed = await forgetPkgToolPreference();
|
|
2020
|
+
console.log(removed ? picocolors.default.green(isZh ? "已清除当前 workspace 保存的包管理器选择。" : "Cleared the saved package-manager choice for this workspace.") : picocolors.default.yellow(isZh ? "当前 workspace 没有保存的包管理器选择。" : "No saved package-manager choice was found for this workspace."));
|
|
2021
|
+
}
|
|
2022
|
+
if (chooseTool) await resolvePkgTool();
|
|
2023
|
+
const status = await getPkgToolStatus();
|
|
2024
|
+
if (listTools) printPkgToolCandidates(status, { json: showToolJson });
|
|
2025
|
+
else printPkgToolStatus(status, { json: showToolJson });
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
if (normalizedArgv.length === 0) {
|
|
2029
|
+
if (forgetTool && !chooseTool) {
|
|
2030
|
+
const removed = await forgetPkgToolPreference();
|
|
2031
|
+
console.log(removed ? picocolors.default.green(isZh ? "已清除当前 workspace 保存的包管理器选择。" : "Cleared the saved package-manager choice for this workspace.") : picocolors.default.yellow(isZh ? "当前 workspace 没有保存的包管理器选择。" : "No saved package-manager choice was found for this workspace."));
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
await resolvePkgTool();
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
if (!hasPackage) {
|
|
1289
2039
|
if (await (0, lazy_js_utils_node.isGo)(rootPath)) {
|
|
1290
2040
|
if (exec === "pi") {
|
|
1291
2041
|
const loading_status = await loading(`${isZh ? "正在为您安装" : "Installing"} ${params} ...\n`);
|
|
@@ -1337,7 +2087,7 @@ async function setup() {
|
|
|
1337
2087
|
else console.log(picocolors.default.yellow(isZh ? "命令不存在, 请执行 pi -h 查看帮助" : "The command does not exist, please execute pi -h to view the help"));
|
|
1338
2088
|
return;
|
|
1339
2089
|
}
|
|
1340
|
-
const pkg =
|
|
2090
|
+
const pkg = normalizedArgv.filter((v) => !v.startsWith("-")).join(" ");
|
|
1341
2091
|
await handler(params, pkg);
|
|
1342
2092
|
}
|
|
1343
2093
|
if (!node_process.default.env.PI_TEST) setup().catch((error) => {
|