Show HN: Magic-cli – A copilot for your command line
github.com
github.com
It should be unsage execution but with an easy undo like git or zfs.
$ man mr
MR(1)
NAME
mr, relink - restore directory entries
$ mr -fr / # restore a filesystem root after deleting it (recursively, forced restore)Edit: lies!
import timetravel from timetravel import Delorean
d = Delorean(color="SILVER")
if d.power_gw >= 1.21:
d.flux_compensator.charge()
print("Great Scott!")Spinning up a VM for testing is another Very Good Practice.
It should be non recoverable. Everybody need to learn their lesson right.
ps. they had backups
The worst situation I've been in was running the classic 'rm -rf' from the root filesystem, several decades ago.
I was running a bootable distro, had mounted all filesystems but the one I was actually attempting to reformat and repurpose read-only, and the upshot was that I enjoyed the experience of seeing just what a system which has shell internals (not sure it was even full bash) and little else functions like. (I found that "echo *" is a good poor-man's 'ls'.) Then, having removed the filesystem I'd intended to remove in the first place (and a few more ... memory-only ... filesystems), I rebooted and continued.
What saved me was safeing all parts of the system save that which I was specifically acting on. Where I've had to perform similarly destructive commands elsewhere and since, I've made a habit of doing similarly, ensuring I'd had backups where necessary, triple-checking that what I wanted to annihilate was in fact what I was going to annihilate.
Among those practices:
I'll often move files or directories to a specific "DELETE_ME" directory, which 1) gives a few non-destructive checkpoints to destructive actions, 2) takes no system time or space (file / directory moves on the same filesystem don't involve copying or writing data other than the filesystem metadata), then review and finally delete those files.
I'll set all filesystems other than those I'm specifically performing surgery on to "read-only". This suffices for almost any file-oriented actions, though of course not filesystem or partition operations. ('dd' is the exception to file-oriented commands, though you'd have to be writing to a partition to cause problems.)
Rather than using dynamically-generated file lists (e.g., using shell globs, 'find | xargs', $(shell expansions), or similar techniques, I'll generate a one-off shell script to perform complex operations. This makes explicit all expansions and permits reviewing of operations before committing them.
I'll often log complex output so that I can review the operation and see if it ran as intended.
These have avoided numerous unpleasant surprises.
How do I "undo", say, `rm ./temp/*.txt`
/s but I sincerely hope it isn’t necessary
Besides I need .sh scripts not just cli completion.
But this reminds me of warp. Gonna have to give it a spin in the morning.
Magic-cli also seems to be using same workflow as github copilot, so I'm not rushing to use it.
On occasions when I do know what I don't know, and want to specifically opt in, this looks perfect.
[0]: https://codeium.com/blog/termium-codeium-in-terminal-launch
https://github.com/pmarreck/dotfiles/blob/master/bin/functio...
[ -v EDIT ] && unset EDIT && edit_function "${FUNCNAME[0]}" "$BASH_SOURCE" && return
Very cool script overall, thanks for sharing needs() {
[ -v EDIT ] && unset EDIT && edit_function "${FUNCNAME[0]}" "$BASH_SOURCE" && return;
local bin="$1";
shift;
command -v "$bin" > /dev/null 2>&1 || {
printf "%s is required but it's not installed or in PATH; %s\n" "$bin" "$*" 1>&2;
return 1
}
}
contains() {
[ -v EDIT ] && unset EDIT && edit_function "${FUNCNAME[0]}" "$BASH_SOURCE" && return;
local word;
for word in $1;
do
if [[ "$word" == "$2" ]]; then
return 0;
fi;
done;
return 1
}
edit_function() {
[ -v EDIT ] && unset EDIT && edit_function "${FUNCNAME[0]}" "$BASH_SOURCE" && return;
needs rg "please install ripgrep!";
local function_name="$1";
local function_name="${function_name//\?/\\?}";
local file="$2";
local fl=$(rg -n -e "${function_name} *\(\) *\{" -e "function +${function_name}(?: *\(\))? *\{" "$file" | tail -n1 | cut -d: -f1);
$EDITOR "$file":$fl
}
edit() {
[ -v EDIT ] && unset EDIT && edit_function "${FUNCNAME[0]}" "$BASH_SOURCE" && return;
if contains "$(functions)" $1; then
EDIT=1 $1;
else
$EDITOR "$@";
fi
}
Once you have those set in your environment, and EDITOR points to whatever editor you prefer, you can simply add the following line to the top of any bash function you define and make it editable-in-place basically: [ -v EDIT ] && unset EDIT && edit_function "${FUNCNAME[0]}" "$BASH_SOURCE" && return;
I use the [ -v variablename ] pattern to detect whether it's set or not so that things like EDIT=1 and EDIT=true will work the same way, but I've also seen ((EDIT)) used, which for values of 1 gives a return code of 0 (making that expression true) otherwise returns a fail, but that only works if you use 1 or 0 to designate "true" and "false" for switches... and it's of course confusing that you need to reverse those in Bash logic which works off return codes and not actual valuesI guess I'm not very familiar with Rust but it just seems like a lot for what it does.
If so.. that's kinda sketchy from a security perspective. Especially because the flag you've shown is very unwieldy.
But -L is very useful, so being able to prevent downgrades has useful functionality to help restrict it.
Was there any particular motive for building your own over using something that's been around a bit longer like aichat?
An CLI assistant that responds by generating and auto-executing a Python script. https://github.com/AbanteAI/rawdog
In short, besides the obvious AI stuff, which works well:
- You can edit the command line as though it's in a GUI program (including with mouse, etc) instead of it being inside the terminal where you need to use different keybindings and no mouse.
- When in a shell, instead of your window being one long stream of text, each command and each output is a discrete area, so it's easier to, say, select the whole output of a command.
Edit: link to feature: https://docs.warp.dev/features/blocks
This is one of the things I most _dislike_ about it. Don't incentivize hording those useful tools in yet-another-silo, get them out into a shared code package!
I think the integration is important though; I’ve vented plenty of steam at co-workers who don’t look at the COMMANDS.md / README.md / etc in a repo. It being auto imported into their terminal program (with search, autosuggestion, and adjacent documentation) seems a pretty killer offering for teams.
I'm often pretty torn on recommendations like this - to use another tool to account for coworkers unwillingness to use (or, learn to use) the existing/underlying one. It reminds me of a time that I saw someone singing the praises of a GUI for Git because it allowed them to do things you couldn't do from the CLI "like adding only parts of a file" - to which someone replied simply "`git add -p`".
From an outcome-focused perspective, I suppose any introduced tool or process which "gets the job done better" is desirable, if it comes at zero cost. To me, the "lock-in" that everyone _has_ to use Warp in order to benefit from this shared knowledge is a non-zero cost, and requiring software engineers to know how to push code to a Git repo is not an unreasonable expectation. But if everyone's _already_ enthusiastic to use Warp for other reasons, I suppose my objection is moot.
> (with search, autosuggestion, and adjacent documentation)
adjacent documentation feels like a straw-man - man pages or `my-tool --help` exist for standard scripts! Ditto for search - if GitHub's search lets you down, then `grep searchterm /path/to/my/scripts/directory` still works. Autosuggestion is fair, though - although I do know that it's possible to have tool-specific auto-completes (e.g. https://kubernetes.io/docs/reference/kubectl/generated/kubec...), I'll bet Warp makes it easier than a standard shell does.
We know how much damage a cli can do, they often don't have the protections in place most other systems. I mean if I copy files with AWS s3 there is zero confirmation that I am not overriding files.
Personally I feel like if you really want to use an LLM to generate your commands, the extra step of copying it from a website is probably a good one. At least you will be forced to actually look at it instead of just assume it is right and hit enter.
The example given in the document is a simple one, but with more complex CLI calls I would be scared to use this for anything but the simplest of things.
That is ignoring the questionable decision to possibly send very sensitive information to ChatGPT to generate these commands.
How is this different than looking up a random webpage with the same information?
This:
curl google.com/?search=remove+directory+linux&feeling_lucky=1 | html_strip | head -n 1 | bash
Is pretty dangerous, all things being equal, much more dangerous than copying and pasting and of course everything is more dangerous if you avoid engaging your brain entirely.
suggest.mode: The mode to use for suggesting commands. Supported values: "clipboard" (copying command to clipboard), "unsafe-execution" (executing in the current shell session) (default: "unsafe-execution")
So default mode seems to be shoot first, ask questions later.It's very composable and I can do incremental work with it.
Or for extra points ^[v which will serve as a handier escape, as well.
The AGI version is "command line" also enabling the agents to communicate, modify, make each other.