control board: reply from the board through agent-send.sh (#1505)
Piece 2 of the MVP (#1503). A one-line reply box and Send in the detail of rows with a live registration; POST /api/reply runs tools/tmux/agent-send.sh -s <session> -S <host>:control-board [-L <socket>] -m <text> once for one seat and returns the exit code, stdout and stderr. The page shows delivered or failed with the tool's stderr; other rows say "reply needs a registered seat". No send-keys, queue, retries, history or broadcast; packages/seat and agent-send.sh untouched. Every message ends with a fixed trailer telling the seat to answer in its own session (Jason's refinement after the first Gate C exchange; the board has no pane). Board suite 98/98. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
@@ -407,3 +407,67 @@ of `gpt-5.6-*` and `glm-5.3`). Board suite 91/91. Jason's board on 7331
|
||||
needs a restart to pick this up. Sonnet review found the model hover title
|
||||
escaped an already escaped string (double encoding for names with `&` or
|
||||
`<`); fixed before commit, then APPROVED on that basis.
|
||||
|
||||
**2026-09-12 — Piece 2: reply-from-board (#1505).** Built to the brief
|
||||
above. `POST /api/reply {agent, text}` rescans, finds the row, and runs
|
||||
`tools/tmux/agent-send.sh -s <session> -S <host>:control-board -m <text>`,
|
||||
plus `-L <socket>` when the registration names one, with
|
||||
`MOSAIC_TMUX_SOCKET` stripped from the tool's environment so the
|
||||
registration is the only source of the socket. The answer carries
|
||||
`delivered`, the exit code, stdout and stderr; a non-zero exit is
|
||||
reported as is. Refusals before the tool runs: bad or empty or long text
|
||||
400, unknown row 404, no registration or stale registration or no tmux
|
||||
session 409, tool not startable 500. The page puts a one-line box and
|
||||
Send in the detail of rows whose registration is live and has a tmux
|
||||
session; other rows say "reply needs a registered seat". The receipt
|
||||
reads `delivered <time> to tmux <session>` or `failed (exit N): <stderr>`;
|
||||
drafts and receipts survive the periodic refresh and the caret is given
|
||||
back to the box; a delivered reply clears the box and rescans at once.
|
||||
Not built, per the brief: raw send-keys, queue, retries, history,
|
||||
broadcast, more than one seat per request; no change to `packages/seat`,
|
||||
the registration record or `agent-send.sh`.
|
||||
|
||||
Live check on a scratch server (port 7332) with a scratch tmux session
|
||||
`cb-reply-test` running `cat` and a temp data root: `agent-send.sh`
|
||||
accepted `dragon-lin:control-board` as sender, the text arrived in the
|
||||
pane as `[dragon-lin:control-board -> dragon-lin:cb-reply-test] ...`, and
|
||||
the page showed `delivered`. Killing the session also killed the
|
||||
registered pid, so the row went stale and the box gave way to "reply
|
||||
needs a registered seat", as intended. With a live pid pointed at a
|
||||
missing session the receipt read `failed (exit 1): ERROR: invalid
|
||||
resolved pane identity` and the draft stayed in the box. Tests: a fake
|
||||
`agent-send.sh` on the server's configured path captures argv and the
|
||||
environment; cases for `-s`/`-S`/`-m` without `-L`, with `-L`, exit 4 with
|
||||
stderr, each refusal with the tool never called, a missing tool, and
|
||||
static checks on the page (box only when `alive !== false` and a tmux
|
||||
session, JSON POST, escaped receipts). Board suite 98/98 (was 91). Gate C
|
||||
is Jason's to run against a real waiting seat; his board on 7331 needs a
|
||||
restart first.
|
||||
|
||||
Sonnet review of the piece: one finding, the route comment at the top of
|
||||
`serve.mjs` had the `/api/reply` line spliced into the middle of the
|
||||
`/api/seen` description, so it read as if a reply rescanned and returned
|
||||
the index; the comment was split back into two entries before commit.
|
||||
Noted but not changed: the body limit is bytes and the text limit is
|
||||
characters, so a non-ASCII text near 2000 characters is refused as an
|
||||
oversized body rather than as long text; and a row open in both "Waiting
|
||||
on you" and its project group has two forms with the same id, so the
|
||||
refocus after a refresh may land on the other copy.
|
||||
|
||||
**2026-09-12 — Gate C, first exchange, and the trailer.** Jason answered
|
||||
darkwing from his restarted board with "pizza?". The delivery worked
|
||||
(`[dragon-lin:control-board -> dragon-lin:darkwing] pizza?` in darkwing's
|
||||
session log) and the row showed the answer as its last message within one
|
||||
scan, so the return path exists: the board reads the transcript. What
|
||||
failed was the seat's side: the communications skill told the seat a reply
|
||||
only exists once `agent-send.sh` runs, the seat aimed at `-s
|
||||
control-board`, and the tool refused because `control-board` is not a
|
||||
tmux session ("invalid resolved pane identity"). That refusal is correct;
|
||||
the board is not made a pane. Fix in the board, relayed as Jason's ruling
|
||||
by the professor session: every message the board sends ends with a fixed
|
||||
line, `(control-board: answer in your own session as usual; the board
|
||||
reads your transcript. Do not agent-send to control-board.)`, exported as
|
||||
`REPLY_TRAILER`; `-S` stays `<host>:control-board` so the preamble stays
|
||||
honest about the origin. The fake agent-send test now checks the message
|
||||
text ends with the trailer; the receipt is unchanged. Committed with the
|
||||
piece.
|
||||
|
||||
Reference in New Issue
Block a user