VAPP-23: Run one-shot commands on a device from the detail page #28

Merged
David merged 2 commits from feat/run-device-command-vapp-23 into main 2026-06-07 20:10:37 +02:00
Owner

VAPP-23: Run one-shot commands on a device from the detail page

Adds a "Run command" action to the device detail page so an operator can dispatch a one-shot shell command to an online device without opening the interactive Terminal.

What changed

  • New server fn run_device_command(device_id, command) in src/server_fns/mod.rs. It sends the control channel's runcommands shell action (type 0, runAsUser 0) and resolves the routing ack (for: "runcommands"), mapping not-connected / not-authorized / no-nodes / no-db to inline errors. Mirrors the existing power_action / wake_device shape.
  • "Run command" button in the device header actions row, rendered only for online devices (same gating as the Terminal tab). Offline devices do not offer it.
  • A RunCommand modal reusing the page's existing modal / busy-guard / inline-error infrastructure (shared with Rename / Move / Delete): a command textarea, a busy-state Run button, a monospace result pane, and inline errors. Help text states the command runs as the agent's user and points to the Terminal tab for interactive work.

Verified protocol behavior (per the issue's "verify before wiring" directive)

Checked against the vervain-server and vervain-agent sources:

  • vervain-server run_commands (crates/meshcentral-web/src/user_session.rs): the shell path routes {action:"runcommands", type, cmds, runAsUser, userid, username} to the agent and answers the control channel with an ack only ({action:"ack", for:"runcommands", result}), result one of ok / not-connected / not-authorized / no-nodes / no-db.
  • vervain-agent (crates/vervain-agent/src/dispatch.rs): does not handle the shell runcommands action and emits no reply frame for it. Only the interactive msg/console relay (used by the Terminal tab) streams output back, and that path runs a curated built-in command set rather than an arbitrary shell.

Conclusion: the shell runcommands path is dispatch-only end-to-end. No stdout/stderr returns over the control channel, so per the issue the UI reports dispatch success/failure only and the dialog says so explicitly, pointing the operator at the Terminal tab for output.

Acceptance criteria

  • Online device detail shows a Run command action; offline devices do not offer it
  • Submitting a command dispatches it to the agent and shows the result (explicit dispatched confirmation, since the protocol returns no output)
  • Failures (offline mid-flight, missing rights, server error) render inline without hanging the dialog
  • just check passes

🤖 Generated with Claude Code

## VAPP-23: Run one-shot commands on a device from the detail page Adds a "Run command" action to the device detail page so an operator can dispatch a one-shot shell command to an online device without opening the interactive Terminal. ### What changed - New server fn `run_device_command(device_id, command)` in `src/server_fns/mod.rs`. It sends the control channel's `runcommands` shell action (`type` 0, `runAsUser` 0) and resolves the routing ack (`for: "runcommands"`), mapping `not-connected` / `not-authorized` / `no-nodes` / `no-db` to inline errors. Mirrors the existing `power_action` / `wake_device` shape. - "Run command" button in the device header actions row, rendered only for online devices (same gating as the Terminal tab). Offline devices do not offer it. - A `RunCommand` modal reusing the page's existing modal / busy-guard / inline-error infrastructure (shared with Rename / Move / Delete): a command textarea, a busy-state Run button, a monospace result pane, and inline errors. Help text states the command runs as the agent's user and points to the Terminal tab for interactive work. ### Verified protocol behavior (per the issue's "verify before wiring" directive) Checked against the vervain-server and vervain-agent sources: - vervain-server `run_commands` (`crates/meshcentral-web/src/user_session.rs`): the shell path routes `{action:"runcommands", type, cmds, runAsUser, userid, username}` to the agent and answers the control channel with an ack only (`{action:"ack", for:"runcommands", result}`), result one of `ok` / `not-connected` / `not-authorized` / `no-nodes` / `no-db`. - vervain-agent (`crates/vervain-agent/src/dispatch.rs`): does not handle the shell `runcommands` action and emits no reply frame for it. Only the interactive `msg`/`console` relay (used by the Terminal tab) streams output back, and that path runs a curated built-in command set rather than an arbitrary shell. Conclusion: the shell `runcommands` path is **dispatch-only end-to-end**. No stdout/stderr returns over the control channel, so per the issue the UI reports dispatch success/failure only and the dialog says so explicitly, pointing the operator at the Terminal tab for output. ### Acceptance criteria - [x] Online device detail shows a Run command action; offline devices do not offer it - [x] Submitting a command dispatches it to the agent and shows the result (explicit dispatched confirmation, since the protocol returns no output) - [x] Failures (offline mid-flight, missing rights, server error) render inline without hanging the dialog - [x] `just check` passes 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(devices): run one-shot commands from the detail page
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 58s
2f1693f0be
Add a "Run command" action to the device detail header (online devices only, same gating as the Terminal tab) that opens a modal with a command textarea, a busy-guarded Run button, and a result pane. The dialog reuses the existing modal/busy/inline-error infrastructure shared by Rename/Move/Delete.

New server fn `run_device_command(device_id, command)` dispatches over the control channel's `runcommands` shell path (type 0, runs as the agent's user) and resolves the routing ack, mapping not-connected / not-authorized / no-nodes / no-db results to inline errors so a failure never hangs the dialog.

Verified end-to-end behavior against the vervain-server (`run_commands`) and vervain-agent sources: the shell `runcommands` path is dispatch-only. The server ack confirms the command reached the agent, but no stdout/stderr returns over the control channel (the agent has no shell-`runcommands` reply frame; only the interactive `msg`/`console` relay behind the Terminal tab streams output back). The dialog therefore confirms dispatch and points operators at the Terminal tab for output.

#VAPP-23
Merge remote-tracking branch 'origin/main' into feat/run-device-command-vapp-23
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 1m45s
Create release / Create release from merged PR (pull_request) Has been skipped
4803b0f2c1
# Conflicts:
#	src/components/pages/device_detail.rs
David merged commit ecf8027511 into main 2026-06-07 20:10:37 +02:00
David deleted branch feat/run-device-command-vapp-23 2026-06-07 20:10:37 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-apps!28
No description provided.