client-exec CLI

This commit is contained in:
Ian Gulliver
2026-10-21 10:48:59 -07:00
parent 48a05d92de
commit fab6ce5831
16 changed files with 760 additions and 364 deletions
+52 -6
View File
@@ -1266,8 +1266,8 @@ paths:
get:
operationId: getTailnet
description: >
The state of byre's own tailnet node. It is the only request byre answers on its loopback address, where it
needs no identity, so the app on the same Mac can sign the node in before it is reachable on the tailnet.
The state of byre's own tailnet node. byre answers it on its loopback address, where it needs no identity, so
the app on the same Mac can sign the node in before it is reachable on the tailnet.
responses:
"200":
description: The node's state.
@@ -1275,6 +1275,29 @@ paths:
application/json:
schema: { $ref: "#/components/schemas/Tailnet" }
/api/clients/exec:
post:
operationId: execClient
description: >
Runs a command on a client Mac as client_bash does, for `byre client-exec`. It needs the loopback token as a
bearer token, which byre puts in BYRE_TOKEN for everything it runs.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/ClientExec" }
responses:
"200":
description: The command ran; exit_code is -1 when its timeout killed it.
content:
application/json:
schema: { $ref: "#/components/schemas/ClientExecResult" }
"503":
description: No such client is connected, or it didn't acknowledge the request within 2 seconds, or it disconnected before replying.
content:
application/json:
schema: { $ref: "#/components/schemas/Error" }
/api/admin/usage-commands:
get:
operationId: getUsageCommands
@@ -2210,9 +2233,9 @@ components:
description: Work a task agent, or a merge, asks a connected Mac to do, sent over /api/clients/connect.
properties:
id: { type: string }
op: { type: string, enum: [bash, upload, download, read_file, write_file, hands, sign] }
command: { type: string, description: "bash: run with zsh as a login shell in the home directory, in its own process group." }
timeout_ms: { type: integer, description: "bash, sign: kill the process group after this long." }
op: { type: string, enum: [bash, exec, upload, download, read_file, write_file, hands, sign] }
command: { type: string, description: "bash, exec: run with zsh as a login shell in the home directory, in its own process group." }
timeout_ms: { type: integer, description: "bash, exec, sign: kill the process group after this long." }
ident: { type: string, description: "sign: the committer, as \"Name <email>\", to sign as when the Mac's git config has no user.signingkey." }
transfer: { type: string, description: "upload: the transfer id to get from /api/clients/transfers/{transferId}. download: the transfer id to put the archive to." }
dest: { type: string, description: "upload: where the archive's one entry ends up, absolute or starting with ~/; whatever is there is replaced." }
@@ -2227,17 +2250,40 @@ components:
ClientReply:
type: object
required: [id]
description: >
The app sends one reply with accepted set as soon as it receives a request, so byre knows within a moment that
the Mac is listening, then one final reply without it.
properties:
id: { type: string, description: The request's id. }
accepted: { type: boolean, description: "Set only on the first reply, which says the app received the request and started on it." }
error: { type: string, description: Set when the request couldn't be carried out. }
exit_code: { type: integer, description: "bash, sign: the exit status, -1 when it was killed by its timeout." }
exit_code: { type: integer, description: "bash, exec, sign: the exit status, -1 when it was killed by its timeout." }
output: { type: string, description: "bash: stdout and stderr together, at most their last 64 KiB. sign: the signing program's stderr, where it writes its GnuPG status lines, and the login shell's output." }
stdout: { type: string, format: byte, description: "exec: everything the command wrote to stdout." }
stderr: { type: string, format: byte, description: "exec: everything the command wrote to stderr." }
data: { type: string, format: byte, description: "read_file: the file's contents. sign: the detached signature." }
result:
type: object
additionalProperties: true
description: "hands: the tool's MCP CallToolResult."
ClientExec:
type: object
required: [command, timeout_ms]
properties:
client: { type: string, description: "The client's name or id; absent for the most recently active one." }
command: { type: string, description: Run with zsh as a login shell in the home directory, in its own process group. }
timeout_ms: { type: integer, description: Kill the process group after this long. }
ClientExecResult:
type: object
required: [client, exit_code, stdout, stderr]
properties:
client: { type: string, description: The id of the client that ran it. }
exit_code: { type: integer }
stdout: { type: string, format: byte }
stderr: { type: string, format: byte }
TurnRef:
type: object
required: [session_id, task_id, vendor]