Show HN: Isuckatbash – convert plain wording to zsh commands inline

5 hours ago 1
# ----------------------------------------------------------------------------- # isuckatbash.zsh — press Esc-; to ask GPT for shell help # # Description: # Sends your current zsh command line (BUFFER) to OpenAI's API and replaces it # with a suggested command plus a short explanation. # # Usage: # 1. Add this snippet to ~/.zshrc # 2. Set your OpenAI key env OPENAI_API_KEY # 3. Type a goal or partial command, then press Esc-; (macos) # # Example: # $ list jpg files recurs ← then press [ESC]+[;] # thinking... # List all .jpg files recursively from current directory. # > find . -type f -iname '*.jpeg' # also matches .jpeg # > find . -type f \( -iname '*.jpg' -o -iname '*.jpeg' \) # both .jpg and .jpeg # $ find . -type f -iname "*.jpg" ← ready to edit or run # # ----------------------------------------------------------------------------- isuckatbash() { typeset -g _isuckatbash_next="${BUFFER}" print -sr -- "$BUFFER" zle send-break } zle -N isuckatbash bindkey '^[;' isuckatbash # esc-; autoload -Uz add-zle-hook-widget _isuckatbash_line_init() { if [[ -n $_isuckatbash_next ]]; then BUFFER="" CURSOR=${#BUFFER} USER_INPUT="${_isuckatbash_next}" node - <<'NODESCRIPT' console.log = ((_log) => (...args) => { _log('\x1b[36m', ...args, '\x1b[0m'); })(console.log); process.stdout.write('\x1b[2K\r'); // next line if (!process.env.USER_INPUT) { console.log('No user input found.'); process.exit(0); } const os = require('os'); const fs = require('fs'); const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 30000); (async () => { const sysExample = `{"command":"find . -iname '*foo*'","warning":"","details":"List files/dirs recursively.\n> find . -type f -iname '*foo*' # only files\n> find . -type d -iname '*foo*' # only dirs"}`; const sys1 = "Create a one-line zsh command to accomplish the goal stated below. " + "Return a JSON object like " + sysExample + ". " + `"command" is the one-line zsh command; "warning" is optional and will be shown in red - use it for deletes, etc (and suggest a dry run version if possible). "details" is a brief explanation plus related options (one per line) as needed.\n\nIf the user provided a command, then start details by confirming if's a valid command by saying "Perfect..." or invalid "Close...". Then explain what it does and give related options and provide the corrected command as the result.`; const sys2 = JSON.stringify({ shell: process.env.SHELL, os: process.platform, osRelease: os.release(), osArch: os.arch(), homeDir: os.homedir(), hostname: os.hostname(), pwd: process.cwd(), nodeVersion: process.version, }); try { process.stdout.write('\x1b[2mthinking...\x1b[0m\n'); const res = await fetch('https://api.openai.com/v1/chat/completions', { signal: controller.signal, method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}` }, body: JSON.stringify({ model: 'gpt-4.1', messages: [ { role: 'system', content: sys1 }, { role: 'system', content: 'Keep it simple if possible. For advanced commands, consider using node -e.\n\n' + sys2 }, { role: 'user', content: process.env.USER_INPUT } ] }), }); const j = await res.json(); const payload = JSON.parse(j?.choices?.[0]?.message?.content ?? ""); if (payload.details) console.log(String(payload.details + "\n").trim()); if (payload.warning) process.stdout.write('\x1b[31m'+payload.warning+'\x1b[0m\n'); if (payload.command) fs.writeFileSync('/tmp/_isuckatbash_cmd.txt', payload.command); } catch (e) { if (e.name === 'AbortError') { console.log("API request timed out."); } else { console.log(String(e?.message || e)); } } finally { clearTimeout(timeout); } })(); NODESCRIPT BUFFER="$(< /tmp/_isuckatbash_cmd.txt)" CURSOR=${#BUFFER} unset _isuckatbash_next zle reset-prompt zle -R fi } add-zle-hook-widget line-init _isuckatbash_line_init
Read Entire Article