···11+# nlcmd
22+33+Type natural language in your terminal, press Ctrl+G, get a shell command.
44+55+## Install
66+77+```bash
88+bun install
99+```
1010+1111+## Setup
1212+1313+Add to your `~/.zshrc`:
1414+1515+```zsh
1616+source /path/to/widget.zsh
1717+export ANTHROPIC_API_KEY="sk-..."
1818+```
1919+2020+## Usage
2121+2222+1. Type a natural language description of what you want to do
2323+2. Press `Ctrl+G`
2424+3. Watch the command stream in
2525+4. Press Enter to execute (or edit first)
2626+2727+## Examples
2828+2929+```
3030+find all pdf files in downloads ⟶ find ~/Downloads -name "*.pdf"
3131+list git branches by date ⟶ git branch --sort=-committerdate
3232+disk usage top 10 folders ⟶ du -h --max-depth=1 | sort -hr | head -10
3333+```
3434+3535+## How it works
3636+3737+- `cli.ts` - Bun script using Vercel AI SDK + Claude Haiku 4.5
3838+- `widget.zsh` - ZSH widget with streaming output via FIFO + animated spinner
+8-1
cli.ts
···22import { streamText } from "ai";
3344const anthropic = createAnthropic({
55- baseURL: "http://localhost:4001/v1",
55+ ...(process.env.ANTHROPIC_BASE_URL && { baseURL: process.env.ANTHROPIC_BASE_URL }),
66});
7788const input = await Bun.stdin.text();
···1111 model: anthropic("claude-haiku-4-5-20251001"),
1212 system: "Convert to shell command. Output ONLY the raw command. No markdown, no code fences, no explanation.",
1313 prompt: input.trim(),
1414+ onError({ error }: { error: any }) {
1515+ const msg = error.statusCode === 401 ? "Invalid API key"
1616+ : error.message?.includes("API key") ? "Missing API key"
1717+ : error.message || "Unknown error";
1818+ console.log(`# Error: ${msg}`);
1919+ process.exit(1);
2020+ },
1421});
15221623for await (const chunk of textStream) {