Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/completion-install-tips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"clerk": patch
---

Fix shell completion install tips so they work on fresh systems. The `clerk doctor` zsh remedy now leads with `eval "$(clerk completion zsh)"` and points to `clerk completion --help` for the file-based install method, and the fish remedy prefixes `mkdir -p ~/.config/fish/completions` before writing. The zsh completion script's install banner now tells users to `mkdir -p ~/.zfunc` before writing the completion file.
1 change: 1 addition & 0 deletions packages/cli-core/src/cli-program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ Tutorial — enable completions for your shell:
# Then add to ~/.zshrc: fpath=(~/.zfunc $fpath); autoload -Uz compinit && compinit

Fish:
$ mkdir -p ~/.config/fish/completions
$ clerk completion fish > ~/.config/fish/completions/clerk.fish # Auto-discovered

PowerShell:
Expand Down
1 change: 1 addition & 0 deletions packages/cli-core/src/commands/completion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ clerk completion zsh > ~/.zfunc/_clerk

```sh
# Fish auto-discovers completion files — just save it
mkdir -p ~/.config/fish/completions
clerk completion fish > ~/.config/fish/completions/clerk.fish
```

Expand Down
20 changes: 20 additions & 0 deletions packages/cli-core/src/commands/completion/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,30 @@ describe("shell script generators", () => {
expect(generateZsh(BINARY)).toContain("_describe");
});

test("zsh banner instructs users to mkdir ~/.zfunc before writing", () => {
const script = generateZsh(BINARY);
const mkdirIdx = script.indexOf("mkdir -p ~/.zfunc");
const writeIdx = script.indexOf(`${BINARY} completion zsh > ~/.zfunc/_${BINARY}`);
expect(mkdirIdx).toBeGreaterThan(-1);
expect(writeIdx).toBeGreaterThan(-1);
expect(mkdirIdx).toBeLessThan(writeIdx);
});

test("fish uses complete command", () => {
expect(generateFish(BINARY)).toContain(`complete -c ${BINARY}`);
});

test("fish banner instructs users to mkdir ~/.config/fish/completions before writing", () => {
const script = generateFish(BINARY);
const mkdirIdx = script.indexOf("mkdir -p ~/.config/fish/completions");
const writeIdx = script.indexOf(
`${BINARY} completion fish > ~/.config/fish/completions/${BINARY}.fish`,
);
expect(mkdirIdx).toBeGreaterThan(-1);
expect(writeIdx).toBeGreaterThan(-1);
expect(mkdirIdx).toBeLessThan(writeIdx);
});

test("powershell uses Register-ArgumentCompleter", () => {
expect(generatePowershell(BINARY)).toContain("Register-ArgumentCompleter");
});
Expand Down
1 change: 1 addition & 0 deletions packages/cli-core/src/commands/completion/shells/fish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
export function generate(binaryName: string): string {
return `# Fish completion for ${binaryName}
# Save to:
# mkdir -p ~/.config/fish/completions
# ${binaryName} completion fish > ~/.config/fish/completions/${binaryName}.fish

function __${binaryName}_complete
Expand Down
1 change: 1 addition & 0 deletions packages/cli-core/src/commands/completion/shells/zsh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function generate(binaryName: string): string {
# Add to ~/.zshrc:
# eval "$(${binaryName} completion zsh)"
# Or save to a file in your $fpath:
# mkdir -p ~/.zfunc
# ${binaryName} completion zsh > ~/.zfunc/_${binaryName}
# # Then ensure ~/.zshrc contains:
# # fpath=(~/.zfunc $fpath)
Expand Down
5 changes: 3 additions & 2 deletions packages/cli-core/src/commands/doctor/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ const SHELL_COMPLETION: Record<
> = {
fish: {
isInstalled: (home) => Bun.file(join(home, ".config/fish/completions/clerk.fish")).exists(),
remedy: "Run `clerk completion fish > ~/.config/fish/completions/clerk.fish`",
remedy:
"Run `mkdir -p ~/.config/fish/completions && clerk completion fish > ~/.config/fish/completions/clerk.fish`",
},
bash: {
isInstalled: (home) =>
Expand All @@ -381,7 +382,7 @@ const SHELL_COMPLETION: Record<
(await fileContains([join(home, ".zshrc")], "clerk completion")) ||
(await Bun.file(join(home, ".zfunc/_clerk")).exists()),
remedy:
Comment thread
rafa-thayto marked this conversation as resolved.
'Add `eval "$(clerk completion zsh)"` to your ~/.zshrc, or run `clerk completion zsh > ~/.zfunc/_clerk`',
'Add `eval "$(clerk completion zsh)"` to your ~/.zshrc (run `clerk completion --help` for other install methods)',
},
};

Expand Down
17 changes: 17 additions & 0 deletions packages/cli-core/src/commands/doctor/doctor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,4 +667,21 @@ describe("checkShellCompletion", () => {
fix: false,
});
});

test("zsh remedy leads with the eval form (safe on fresh systems)", async () => {
process.env.SHELL = "/bin/zsh";
process.env.HOME = tempDir;
const result = await checkShellCompletion();
expect(result.remedy).toContain('eval "$(clerk completion zsh)"');
// The raw fpath one-liner was unsafe — it fails when ~/.zfunc doesn't exist
// and silently no-ops without fpath/compinit setup in ~/.zshrc.
expect(result.remedy).not.toMatch(/clerk completion zsh > ~\/\.zfunc\/_clerk/);
});

test("fish remedy creates the completions directory before writing", async () => {
process.env.SHELL = "/usr/bin/fish";
process.env.HOME = tempDir;
const result = await checkShellCompletion();
expect(result.remedy).toContain("mkdir -p ~/.config/fish/completions");
});
});
Loading