chore: snapshot working tree - pty_exited notifications + in-flight inference WIP
feat(booterm): structured pty_exited WS notifications. Plan-validated, impl-validated, code-reviewed green (contracts build clean, contracts test 29/29, booterm + web typecheck clean). wip: in-progress inference/provider refactor (agents.ts, provider.ts, new llama-providers.ts, removed llama-args-validator), plus arena, dispatcher, compaction, schema changes. openspec: pty-exit-notifications complete; x-agent-flags planned (not yet implemented).
This commit is contained in:
53
openspec/changes/boocontrol-ssh-verbmode/proposal.md
Normal file
53
openspec/changes/boocontrol-ssh-verbmode/proposal.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# BooControl SSH editor verb-mode + model pull — proposal
|
||||
|
||||
**Status:** READY. Extends BooControl P9.1 (the SSH config editor) so it works
|
||||
against a forced-command-locked SSH key and can pull HuggingFace models into a
|
||||
host's models directory.
|
||||
|
||||
## Why
|
||||
|
||||
P9.1 shipped the SSH config editor sending raw shell commands (`cat`, `cp`,
|
||||
`cat >`, the restart command) over SSH. To restrict the BooControl key to a
|
||||
single drive/folder, the operator has deployed an `authorized_keys`
|
||||
**forced command** on the GPU hosts that binds the key to a wrapper script
|
||||
(`apps/control/remote/boocontrol-edit.{ps1,sh}`). A forced command ignores the
|
||||
client's command string and only honors fixed **verbs** (`read` / `backup` /
|
||||
`write` / `restart` / `pull <repo>`). So the editor's raw-shell commands are now
|
||||
rejected by those hosts, and there is no way to drive the wrapper's `pull` verb.
|
||||
|
||||
This change teaches the editor to speak verbs (per host) and adds a model-pull
|
||||
capability, closing the loop so a locked-down key is fully usable from the
|
||||
cockpit.
|
||||
|
||||
## What changes
|
||||
|
||||
1. **Per-host SSH mode.** `control_hosts.ssh_mode` (`shell` | `wrapper`, default
|
||||
`shell` for backward compatibility). `shell` keeps today's raw-command
|
||||
behavior for hosts without a wrapper; `wrapper` sends verbs.
|
||||
2. **Verb-mode remote ops.** `ssh-config.ts` gains a `RemoteOps` seam with two
|
||||
implementations (`shellOps`, `wrapperOps`). `applyRemoteConfig` and the
|
||||
read/diff paths route through it. The pipeline (validate -> read -> diff ->
|
||||
backup -> write -> restart -> health-wait) is unchanged; only the wire
|
||||
commands differ.
|
||||
3. **Model pull.** `POST /api/hosts/:id/pull {repo}` runs a non-blocking job that
|
||||
invokes the host's `pull <repo>` verb, streaming progress over the existing
|
||||
`control_job` frame (jobType `action`, `detail.kind = "pull"`). The repo id is
|
||||
validated server-side (`^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$`) as defense in depth
|
||||
on top of the wrapper's own check.
|
||||
4. **UI.** The Host config editor gains an SSH-mode selector and a "Pull model"
|
||||
field that posts a repo id and shows job progress.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Changing the wrapper scripts (already in `apps/control/remote/`).
|
||||
- A new `control_job` jobType (reuse `action` to avoid a contracts change).
|
||||
- Progress percentage parsing from `huggingface-cli` output (stream raw lines).
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| Refactor breaks existing P9.1 shell-mode tests | `shellOps` emits the identical `cat`/`cp`/`cat >`/restart command strings; existing assertions hold. `mode` defaults to `shell`. |
|
||||
| Repo id injection via the pull verb | server-side regex validation + the wrapper's own regex; repo passed as a single token. |
|
||||
| Long pull blocks the HTTP request | non-blocking job (fire-and-forget like bench/eval), progress over `control_job`. |
|
||||
| Operator points a `wrapper`-mode host at a box without the wrapper | verbs fail loudly (the forced command / shell returns "denied"/127); reported per step, no silent fallback. |
|
||||
Reference in New Issue
Block a user