package tui import ( "fmt" "strings" ) // command is one thing the prompt box accepts with a leading slash: either a // control the TUI answers itself, or a skill the agent is asked to invoke. type command struct { name string // without the slash args string // what may follow the name; "" when it takes none desc string tag string // "personal" or "project" for a skill; "" for a built-in } // builtins are the commands submit answers without going near the model. The // order is the order the menu offers them in — most reached-for first, not // alphabetical, because the first row is the one a person lands on. // // This list is also what /help prints and what the completion menu offers, so // none of the three can drift away from the others. var builtins = []command{ {name: "help", desc: "the commands and the keys"}, {name: "skills", desc: "the instruction sets found at startup"}, {name: "model", args: "id", desc: "switch model — lists what the endpoint serves"}, {name: "effort", args: "level", desc: "how hard the model thinks — opens a slider"}, {name: "settings", desc: "change the saved defaults, a row at a time"}, {name: "setup", desc: "the full-screen wizard for the saved defaults"}, {name: "worktree", args: "name|task|resume", desc: "branch off into a worktree — resume opens one that exists"}, {name: "compact", desc: "fold the conversation into a summary now"}, {name: "clear", desc: "empty the transcript"}, {name: "resume", args: "id", desc: "switch to a session saved in this directory — opens a chooser"}, {name: "new", desc: "open a fresh session in another tab — ctrl+t does the same"}, {name: "close", desc: "close the tab on screen — alt+w does the same"}, {name: "image", args: "path", desc: "attach a picture — bare, it takes the clipboard's"}, {name: "mouse", desc: "hand the mouse back to the terminal, or take it again"}, {name: "allowed", desc: "what is permanently allowed this session"}, {name: "exit", desc: "leave Codey"}, } // commands is the catalogue: the built-ins, then every discovered skill. func (m *model) commands() []command { out := make([]command, 0, len(builtins)+len(m.opts.Skills)) out = append(out, builtins...) for _, s := range m.opts.Skills { desc := s.Description if desc == "" { desc = "a skill with no description" } out = append(out, command{name: s.Name, args: "arguments", desc: desc, tag: s.Source}) } return out } // matchCommands narrows the catalogue to what has been typed after the slash. // A name that starts with it comes before one that merely contains it, so // "/sk" offers /skills before a skill called "ask-the-docs". func matchCommands(all []command, typed string) []command { if typed == "" { return append([]command(nil), all...) } var prefix, contains []command for _, c := range all { switch { case strings.HasPrefix(c.name, typed): prefix = append(prefix, c) case strings.Contains(c.name, typed): contains = append(contains, c) } } return append(prefix, contains...) } // helpText is built from the catalogue rather than written out beside it. func (m *model) helpText() string { var b strings.Builder b.WriteString("commands:") for _, c := range builtins { name := "/" + c.name if c.args != "" { name += " <" + c.args + ">" } fmt.Fprintf(&b, "\n %-21s %s", name, c.desc) } if n := len(m.opts.Skills); n > 0 { fmt.Fprintf(&b, "\n %-21s %s", "/", plural(n, "discovered skill")+" — /skills lists them") } b.WriteString("\nmouse: wheel scrolls · drag selects and copies on release" + "\n double-click a word · triple-click a line · shift+click extends" + "\n click a menu row, a model, the slider or an approval to choose it" + "\n click the prompt to type while the agents sidebar is open" + "\n /mouse hands the mouse back to the terminal for its own selection" + "\nimages: ctrl+v pastes the clipboard's picture in as [image 1], and so does" + "\n dropping a file on the window — the marker is where the picture" + "\n goes in the message, and deleting it takes the paste back" + "\n a path left in the prompt becomes the picture when you send" + "\n /image is the way that works on any terminal" + "\nkeys: enter send · ctrl+j newline · shift+tab cycle approval mode" + "\n ctrl+t a new session in a tab · alt+1…9 go to one · alt+w close one" + "\n ctrl+pgup/pgdn walk the tabs — each is its own agent and history" + "\n ctrl+b the agents sidebar — ↑↓ move · enter read one · p pause · k kill" + "\n ! runs a shell command · $ runs python — both on an empty prompt" + "\n what they print goes to the agent too, so you can then say \"fix that\"" + "\n / opens the command menu · ↑↓ move · tab or enter complete · esc dismiss" + "\n ctrl+r toggle full tool output · pgup/pgdn scroll" + "\n esc or ctrl+c interrupt a turn · ctrl+c again to exit") return b.String() }