Skip to content

Instantly share code, notes, and snippets.

@bendytree
Created October 23, 2025 17:54
Show Gist options
  • Select an option

  • Save bendytree/ca27db29e8ccd5560533928cb018caa8 to your computer and use it in GitHub Desktop.

Select an option

Save bendytree/ca27db29e8ccd5560533928cb018caa8 to your computer and use it in GitHub Desktop.
isuckatbash: Use GPT to generate or fix zsh commands from your prompt
# -----------------------------------------------------------------------------
# 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
@bendytree
Copy link
Author

CleanShot 2025-10-23 at 13 21 29

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment