fix(tmux,run,hooks): the four pre-existing bugs the #37 evaluation found

- tmux targets are exact (`=name`, `=name:` for panes/options): a bare
  `-t agenthub-lane-1` resolves by prefix to agenthub-lane-12 once lane 1
  is gone, so killing a finished lane could kill another.
- getRun/killRun refuse ids that are not `agenthub-lane-<n>`, so
  DELETE /api/run/main can no longer kill a user's own tmux session.
- router/apply reports restart_required only for a running pane; getRun
  returns a `gone` handle, so it was always true.
- needs_action is cleared only by the session that raised it (new nullable
  lanes.needs_action_session); a second session in the same cwd used to
  clear it on its second hook.
This commit is contained in:
2026-09-23 13:13:16 +07:00
parent 04b6b98d97
commit 99a2a8277c
18 changed files with 134 additions and 33 deletions
+2
View File
@@ -2072,6 +2072,8 @@ GET /api/run/:id Run handle (returns live run state)
DELETE /api/run/:id Kill (SIGTERM → SIGKILL after 5 s)
```
`:id` must be a lane pane name, `agenthub-lane-<n>`; anything else answers 404 without reaching tmux, so these two routes can never touch a tmux session the dashboard did not start.
**`GET /api/run/binary`:** Probes for the binary (`claude` or `codex`). Optional query parameter `?tool=codex` probes for Codex; omitted or `?tool=claude` probes for Claude. Returns `{ found: bool, path: string | null }`.
**`POST /api/run` (start/attach):** Requires `laneId` (the lane this run belongs to). Creates or attaches an existing tmux session named `agenthub-lane-<id>` in the lane's working directory. If that session already exists and its pane is idling at a shell prompt, the appropriate command line (including `--resume` and any initial prompt) is typed into that pane instead of being dropped; if the pane is running a program, the request adopts the session unchanged. Optionally accepts `initialPrompt` to immediately type/send into the session (if empty or omitted, the session is created/attached with no initial input). Returns `{ id, laneId, status, cwd, model, permissionMode, effort, resumeSessionId, sessionId, startedAt, promptPreview }` where `id` is the tmux session name. The dashboard self-heals a lane's `run_id`/`status` on every read if the tmux session has been killed externally.