9p: reject unrecognized ctl commands

ctl now validates the first word of input against a closed set of
known commands. Unrecognized input returns an error instead of being
silently forwarded as a prompt to the agent.
This commit is contained in:
Levi Neely 2026-04-13 15:44:14 +02:00
parent fdcf048a70
commit b048aac109
2 changed files with 16 additions and 7 deletions

View File

@ -109,7 +109,7 @@ echo "rn my-name" > ~/mnt/ollie/s/<session-id>/ctl # rename session
echo "model qwen3:8b" > ~/mnt/ollie/s/<session-id>/ctl
```
`ctl` accepts `stop`, `kill`, `rn <name>`, or any command supported by the agent (the `/` prefix is added automatically).
`ctl` accepts only recognized commands: `stop`, `kill`, `rn <name>`, `compact`, `clear`, `backend`, `model`, `models`, `agents`, `agent`, `sessions`, `cwd`, `skills`, `tools`, `mcp`, `context`, `usage`, `history`, `irw`, `help`. The `/` prefix is added automatically. Unrecognized input is rejected with an error.
### Switch backend, model, or agent
@ -119,7 +119,7 @@ echo qwen3:8b > ~/mnt/ollie/s/<session-id>/model
echo myagent > ~/mnt/ollie/s/<session-id>/agent
```
Writes to `backend`, `model`, and `agent` are rejected with an error when the agent is not idle. Writes via `ctl` are asynchronous and cannot return errors; if the agent is running, the command is silently rejected. Check `state` to confirm the change took effect.
Writes to `backend`, `model`, and `agent` are rejected with an error when the agent is not idle. Writes to `ctl` return an error for unrecognized commands; recognized commands are dispatched asynchronously. Check `state` to confirm the change took effect.
### Kill a session

View File

@ -1039,19 +1039,28 @@ func (s *Server) handleWrite(path, input string) error {
return nil
case "ctl":
switch {
case input == "stop":
cmd := strings.Fields(input)
if len(cmd) == 0 {
return fmt.Errorf("empty ctl command")
}
switch cmd[0] {
case "stop":
sess.core.Interrupt(agent.ErrInterrupted)
case input == "kill":
case "kill":
s.killSession(sessID)
case strings.HasPrefix(input, "rn "):
case "rn":
if name := strings.TrimSpace(input[3:]); name != "" {
if err := s.renameSession(sessID, name); err != nil {
fmt.Fprintf(os.Stderr, "olliesrv: rename: %v\n", err)
}
}
default:
case "compact", "clear", "backend", "model", "models",
"agents", "agent", "sessions", "cwd", "skills",
"tools", "mcp", "context", "usage", "history",
"irw", "help":
sess.core.Submit(sess.ctx, "/"+input, publish)
default:
return fmt.Errorf("unknown ctl command: %s", cmd[0])
}
return nil