cli: rewrite help text for AI-driven discovery
Frontier models tend to discover a CLI by running --help, scanning the Long description, and inferring the dominant workflow from the examples. Today's banger help reads like a man page index — every verb has a one-line Short and nothing else. This rewrites the groups (banger, vm, vm workspace, image, kernel, system, ssh-config) so each landing page answers "what is this for, what's the 80% command, what comes next" in three to ten lines, with runnable examples. Also disambiguates the near-twin lifecycle commands so a model reading the subcommand index can tell stop/kill/delete apart at a glance: start Start a stopped VM stop Stop a running VM gracefully restart Stop then start a VM kill Force-kill a VM (use when 'vm stop' hangs) delete Stop a VM and remove its disks (irreversible) vm create / vm ssh / vm logs / vm show pick up Long descriptions and examples for the same reason. No behaviour changes; help text only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
41ced66a54
commit
35bfac3f13
6 changed files with 251 additions and 30 deletions
|
|
@ -25,18 +25,43 @@ import (
|
|||
func (d *deps) newVMCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "vm",
|
||||
Short: "Manage virtual machines",
|
||||
RunE: helpNoArgs,
|
||||
Short: "Manage Firecracker microVM sandboxes",
|
||||
Long: strings.TrimSpace(`
|
||||
Lifecycle commands for banger's microVMs.
|
||||
|
||||
For most cases you want 'banger vm run' — it creates, starts,
|
||||
provisions ssh, and drops you into the guest in one command. Use
|
||||
'vm create' / 'vm start' / 'vm ssh' separately when you want a
|
||||
longer-lived VM you'll come back to.
|
||||
|
||||
Quick reference:
|
||||
banger vm run ephemeral sandbox; --rm to delete on exit
|
||||
banger vm run ./repo -- make test ship a repo, run a command, exit
|
||||
banger vm create --name dev persistent VM; pair with 'vm ssh'
|
||||
banger vm ssh <name> open a shell in a running VM
|
||||
banger vm stop <name> | vm restart graceful lifecycle
|
||||
banger vm kill <name> force-kill if stop hangs
|
||||
banger vm delete <name> stop + remove disks
|
||||
banger ps / banger vm list running / all VMs (use --all)
|
||||
banger vm logs <name> guest console + daemon log
|
||||
banger vm workspace prepare/export ship a repo in, pull diffs back
|
||||
`),
|
||||
Example: strings.TrimSpace(`
|
||||
banger vm run -- uname -a
|
||||
banger vm run ./project -- npm test
|
||||
banger vm create --name agent && banger vm ssh agent
|
||||
`),
|
||||
RunE: helpNoArgs,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
d.newVMCreateCommand(),
|
||||
d.newVMRunCommand(),
|
||||
d.newVMListCommand(),
|
||||
d.newVMShowCommand(),
|
||||
d.newVMActionCommand("start", "Start a VM", "vm.start"),
|
||||
d.newVMActionCommand("stop", "Stop a VM", "vm.stop"),
|
||||
d.newVMActionCommand("start", "Start a stopped VM", "vm.start"),
|
||||
d.newVMActionCommand("stop", "Stop a running VM gracefully", "vm.stop"),
|
||||
d.newVMKillCommand(),
|
||||
d.newVMActionCommand("restart", "Restart a VM", "vm.restart"),
|
||||
d.newVMActionCommand("restart", "Stop then start a VM", "vm.restart"),
|
||||
d.newVMDeleteCommand(),
|
||||
d.newVMPruneCommand(),
|
||||
d.newVMSetCommand(),
|
||||
|
|
@ -169,8 +194,16 @@ Three modes:
|
|||
func (d *deps) newVMKillCommand() *cobra.Command {
|
||||
var signal string
|
||||
cmd := &cobra.Command{
|
||||
Use: "kill <id-or-name>...",
|
||||
Short: "Send a signal to a VM process",
|
||||
Use: "kill <id-or-name>...",
|
||||
Short: "Force-kill a VM (use when 'vm stop' hangs)",
|
||||
Long: strings.TrimSpace(`
|
||||
Send a signal directly to the firecracker process. Default is
|
||||
SIGTERM; pass --signal SIGKILL when the VM is stuck and a graceful
|
||||
'vm stop' has already failed.
|
||||
|
||||
This skips the normal stop sequence (no flush, no clean shutdown).
|
||||
Prefer 'banger vm stop' for routine teardown.
|
||||
`),
|
||||
Args: minArgsUsage(1, "usage: banger vm kill [--signal SIGTERM|SIGKILL|...] <id-or-name>..."),
|
||||
ValidArgsFunction: d.completeVMNames,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -320,8 +353,21 @@ func (d *deps) newVMCreateCommand() *cobra.Command {
|
|||
)
|
||||
cmd := &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a VM",
|
||||
Args: noArgsUsage("usage: banger vm create"),
|
||||
Short: "Create a VM (without entering it)",
|
||||
Long: strings.TrimSpace(`
|
||||
Create a microVM in the 'running' state and return its summary.
|
||||
Unlike 'banger vm run', this does NOT open an ssh session — pair it
|
||||
with 'banger vm ssh <name>' when you want to attach.
|
||||
|
||||
Use 'vm create' for a longer-lived VM you'll come back to. Use
|
||||
'vm run' for one-shot sandboxes (especially with --rm).
|
||||
`),
|
||||
Example: strings.TrimSpace(`
|
||||
banger vm create --name agent
|
||||
banger vm create --name big --vcpu 8 --memory 16384
|
||||
banger vm create --no-start --name spare # provision but leave stopped
|
||||
`),
|
||||
Args: noArgsUsage("usage: banger vm create"),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
params, err := vmCreateParamsFromFlags(cmd, name, imageName, vcpu, memory, systemOverlaySize, workDiskSize, natEnabled, noStart)
|
||||
if err != nil {
|
||||
|
|
@ -427,8 +473,15 @@ func selectVMListVMs(vms []model.VMRecord, showAll, latest bool) []model.VMRecor
|
|||
|
||||
func (d *deps) newVMShowCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "show <id-or-name>",
|
||||
Short: "Show VM details",
|
||||
Use: "show <id-or-name>",
|
||||
Short: "Print full VM record as JSON",
|
||||
Long: strings.TrimSpace(`
|
||||
Emit the complete VM record (spec, runtime state, image reference,
|
||||
created/updated timestamps) as a single JSON object. Suitable for
|
||||
piping into 'jq' or feeding into automation.
|
||||
|
||||
For human-readable summaries use 'banger ps' or 'banger vm stats'.
|
||||
`),
|
||||
Args: exactArgsUsage(1, "usage: banger vm show <id-or-name>"),
|
||||
ValidArgsFunction: d.completeVMNameOnlyAtPos0,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -477,9 +530,17 @@ func (d *deps) newVMActionCommand(use, short, method string, aliases ...string)
|
|||
|
||||
func (d *deps) newVMDeleteCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "delete <id-or-name>...",
|
||||
Aliases: []string{"rm"},
|
||||
Short: "Delete a VM",
|
||||
Use: "delete <id-or-name>...",
|
||||
Aliases: []string{"rm"},
|
||||
Short: "Stop a VM and remove its disks (irreversible)",
|
||||
Long: strings.TrimSpace(`
|
||||
Stop the VM if it's running, then remove its work disk, system
|
||||
overlay, snapshot, and metadata. Frees host disk space. The
|
||||
operation is irreversible — anything written inside the guest is
|
||||
lost.
|
||||
|
||||
Use 'banger vm prune' to bulk-delete every VM that isn't running.
|
||||
`),
|
||||
Args: minArgsUsage(1, "usage: banger vm delete <id-or-name>..."),
|
||||
ValidArgsFunction: d.completeVMNames,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -559,8 +620,22 @@ func (d *deps) newVMSetCommand() *cobra.Command {
|
|||
|
||||
func (d *deps) newVMSSHCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "ssh <id-or-name> [ssh args...]",
|
||||
Short: "SSH into a running VM",
|
||||
Use: "ssh <id-or-name> [ssh args...]",
|
||||
Short: "Open an interactive ssh session to a running VM",
|
||||
Long: strings.TrimSpace(`
|
||||
Connect to a running VM as root over the host bridge. Trailing
|
||||
arguments are passed through to the underlying 'ssh' command, so
|
||||
'-- -L 8080:localhost:8080' forwards a port and '-- echo hi' runs
|
||||
a single command and exits.
|
||||
|
||||
To run a one-shot command without holding a session, prefer
|
||||
'banger vm run --rm -- <command>' over 'vm ssh -- <command>'.
|
||||
`),
|
||||
Example: strings.TrimSpace(`
|
||||
banger vm ssh agent
|
||||
banger vm ssh agent -- uname -a
|
||||
banger vm ssh agent -- -L 8080:localhost:8080 -N
|
||||
`),
|
||||
Args: minArgsUsage(1, "usage: banger vm ssh <id-or-name> [ssh args...]"),
|
||||
ValidArgsFunction: d.completeVMNameOnlyAtPos0,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
@ -587,8 +662,29 @@ func (d *deps) newVMSSHCommand() *cobra.Command {
|
|||
func (d *deps) newVMWorkspaceCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "workspace",
|
||||
Short: "Manage repository workspaces inside a running VM",
|
||||
RunE: helpNoArgs,
|
||||
Short: "Ship a host repo into a guest, pull diffs back",
|
||||
Long: strings.TrimSpace(`
|
||||
Two-step pattern for round-tripping a working tree through a guest
|
||||
VM:
|
||||
|
||||
prepare Copy a local git repo into the guest at /root/repo
|
||||
(or any path you choose). Default ships tracked files
|
||||
only; pass --include-untracked to ship the rest.
|
||||
export Capture every change inside the guest workspace as a
|
||||
host-readable patch. Non-mutating: the guest's working
|
||||
tree is left untouched.
|
||||
|
||||
This is the supported flow for AI agents and CI runners that want
|
||||
to evaluate code changes inside a sandbox without touching the
|
||||
host checkout. 'banger vm run ./repo -- <cmd>' is shorthand for
|
||||
prepare + run + delete.
|
||||
`),
|
||||
Example: strings.TrimSpace(`
|
||||
banger vm workspace prepare agent ../repo
|
||||
banger vm ssh agent -- bash -lc 'cd /root/repo && make test'
|
||||
banger vm workspace export agent --base-commit <commit> > out.patch
|
||||
`),
|
||||
RunE: helpNoArgs,
|
||||
}
|
||||
cmd.AddCommand(
|
||||
d.newVMWorkspacePrepareCommand(),
|
||||
|
|
@ -723,8 +819,18 @@ func (d *deps) newVMWorkspaceExportCommand() *cobra.Command {
|
|||
func (d *deps) newVMLogsCommand() *cobra.Command {
|
||||
var follow bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "logs <id-or-name>",
|
||||
Short: "Show VM logs",
|
||||
Use: "logs <id-or-name>",
|
||||
Short: "Show guest console + per-VM daemon log",
|
||||
Long: strings.TrimSpace(`
|
||||
Print the firecracker console log (kernel + early init output) and
|
||||
the per-VM daemon log (lifecycle stages, errors). Pass -f to follow
|
||||
new lines as they arrive — useful while a VM is starting up or
|
||||
hanging on boot.
|
||||
`),
|
||||
Example: strings.TrimSpace(`
|
||||
banger vm logs agent
|
||||
banger vm logs agent -f
|
||||
`),
|
||||
Args: exactArgsUsage(1, "usage: banger vm logs [-f] <id-or-name>"),
|
||||
ValidArgsFunction: d.completeVMNameOnlyAtPos0,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue