




















@@ -25,10 +25,17 @@
25252626import os from "node:os";
2727import path from "node:path";
28+import { pathToFileURL } from "node:url";
2829import { confirm, isCancel } from "@clack/prompts";
2930import { stylePromptMessage } from "../packages/terminal-core/src/prompt-style.js";
3031import { theme } from "../packages/terminal-core/src/theme.js";
31-import { installCompletion } from "../src/cli/completion-cli.js";
32+import {
33+COMPLETION_SHELLS,
34+installCompletion,
35+isCompletionShell,
36+resolveCompletionProfilePath,
37+type CompletionShell,
38+} from "../src/cli/completion-runtime.js";
3239import {
3340checkShellCompletionStatus,
3441ensureCompletionCacheExists,
@@ -40,6 +47,7 @@ interface Options {
4047checkOnly: boolean;
4148force: boolean;
4249help: boolean;
50+shell?: CompletionShell;
4351}
44524553function parseArgs(args: string[]): Options {
@@ -49,19 +57,38 @@ function parseArgs(args: string[]): Options {
4957help: false,
5058};
515952-for (const arg of args) {
60+for (let index = 0; index < args.length; index += 1) {
61+const arg = args[index];
5362if (arg === "--check-only") {
5463options.checkOnly = true;
5564} else if (arg === "--force") {
5665options.force = true;
5766} else if (arg === "--help" || arg === "-h") {
5867options.help = true;
68+} else if (arg === "--shell") {
69+const value = args[index + 1];
70+options.shell = parseShellOptionValue(value);
71+index += 1;
72+} else if (arg.startsWith("--shell=")) {
73+options.shell = parseShellOptionValue(arg.slice("--shell=".length));
74+} else {
75+throw new Error(`Unknown argument: ${arg}`);
5976}
6077}
61786279return options;
6380}
648182+function parseShellOptionValue(value: string | undefined): CompletionShell {
83+if (!value || value.startsWith("-")) {
84+throw new Error("--shell requires a value");
85+}
86+if (!isCompletionShell(value)) {
87+throw new Error(`--shell must be one of: ${COMPLETION_SHELLS.join(", ")}`);
88+}
89+return value;
90+}
91+6592function printHelp(): void {
6693console.log(`
6794${theme.heading("Shell Completion Test Script")}
@@ -75,6 +102,7 @@ ${theme.heading("Usage (run from repo root):")}
75102 bun scripts/test-shell-completion.ts [options]
7610377104${theme.heading("Options:")}
105+ --shell <shell> Override shell detection (zsh, bash, fish, powershell)
78106 --check-only Only check status, don't prompt to install
79107 --force Skip the "already installed" check and prompt anyway
80108 --help, -h Show this help message
@@ -87,37 +115,11 @@ ${theme.heading("Behavior:")}
87115${theme.heading("Examples:")}
88116 node --import tsx scripts/test-shell-completion.ts
89117 node --import tsx scripts/test-shell-completion.ts --check-only
118+ node --import tsx scripts/test-shell-completion.ts --shell bash
90119 node --import tsx scripts/test-shell-completion.ts --force
91120`);
92121}
9312294-function getShellProfilePath(shell: string): string {
95-const home = process.env.HOME || os.homedir();
96-97-switch (shell) {
98-case "zsh":
99-return path.join(home, ".zshrc");
100-case "bash":
101-return process.platform === "darwin"
102- ? path.join(home, ".bash_profile")
103- : path.join(home, ".bashrc");
104-case "fish":
105-return path.join(home, ".config", "fish", "config.fish");
106-case "powershell":
107-if (process.platform === "win32") {
108-return path.join(
109-process.env.USERPROFILE || home,
110-"Documents",
111-"PowerShell",
112-"Microsoft.PowerShell_profile.ps1",
113-);
114-}
115-return path.join(home, ".config", "powershell", "Microsoft.PowerShell_profile.ps1");
116-default:
117-return path.join(home, ".zshrc");
118-}
119-}
120-121123async function main() {
122124const args = process.argv.slice(2);
123125const options = parseArgs(args);
@@ -131,11 +133,12 @@ async function main() {
131133console.log("");
132134133135// Get completion status using the same function used by doctor/update/onboard
134-const status = await checkShellCompletionStatus(CLI_NAME);
136+const status = await checkShellCompletionStatus(CLI_NAME, { shell: options.shell });
137+const shellSource = options.shell ? "(from --shell)" : "(detected from $SHELL)";
135138136-console.log(` Shell: ${theme.accent(status.shell)} ${theme.muted("(detected from $SHELL)")}`);
139+console.log(` Shell: ${theme.accent(status.shell)} ${theme.muted(shellSource)}`);
137140console.log(` Platform: ${theme.muted(process.platform)} ${theme.muted(`(${os.release()})`)}`);
138-console.log(` Profile: ${theme.muted(getShellProfilePath(status.shell))}`);
141+console.log(` Profile: ${theme.muted(resolveCompletionProfilePath(status.shell))}`);
139142console.log(` Cache path: ${theme.muted(status.cachePath)}`);
140143console.log("");
141144console.log(
@@ -155,7 +158,7 @@ async function main() {
155158// Profile uses slow dynamic pattern - upgrade to cached version
156159if (status.usesSlowPattern) {
157160console.log(theme.warn("Profile uses slow dynamic completion. Upgrading to cached version..."));
158-const cacheGenerated = await ensureCompletionCacheExists(CLI_NAME);
161+const cacheGenerated = await ensureCompletionCacheExists(CLI_NAME, { shell: status.shell });
159162if (cacheGenerated) {
160163await installCompletion(status.shell, false, CLI_NAME);
161164console.log(theme.success("Upgraded to cached completion."));
@@ -168,7 +171,7 @@ async function main() {
168171// Profile has completion but no cache - auto-fix
169172if (status.profileInstalled && !status.cacheExists) {
170173console.log(theme.warn("Profile has completion but cache is missing. Regenerating..."));
171-const cacheGenerated = await ensureCompletionCacheExists(CLI_NAME);
174+const cacheGenerated = await ensureCompletionCacheExists(CLI_NAME, { shell: status.shell });
172175if (cacheGenerated) {
173176console.log(theme.success("Cache regenerated successfully."));
174177} else {
@@ -205,7 +208,7 @@ async function main() {
205208// Generate cache first (required for fast shell startup)
206209if (!status.cacheExists) {
207210console.log(theme.muted("Generating completion cache..."));
208-const cacheGenerated = await ensureCompletionCacheExists(CLI_NAME);
211+const cacheGenerated = await ensureCompletionCacheExists(CLI_NAME, { shell: status.shell });
209212if (!cacheGenerated) {
210213console.log(theme.error("Failed to generate completion cache."));
211214return;
@@ -217,7 +220,14 @@ async function main() {
217220await installCompletion(status.shell, false, CLI_NAME);
218221}
219222220-main().catch((err: unknown) => {
221-console.error(theme.error(`Error: ${String(err)}`));
222-process.exit(1);
223-});
223+export const testing = {
224+ parseArgs,
225+};
226+227+if (import.meta.url === pathToFileURL(path.resolve(process.argv[1] ?? "")).href) {
228+main().catch((err: unknown) => {
229+const message = err instanceof Error ? err.message : String(err);
230+console.error(theme.error(`Error: ${message}`));
231+process.exit(1);
232+});
233+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。