openvibers/openvibe.contracts Commits

Contracts 0.166.0: computer kinds (exec, fs, screen) with their answer in data, and bot.computer.control (#122)

OP OpenVibers committed 30 days ago · 541115455d · 52 files, +572 −86

Plan T14/T17, computer control (after Node#41, the Node's `computer` plugin).

- **`bot.command@1`**: new kinds `exec` (argv, cwd, timeout_s, stdin), `fs` (op list|stat|read|write|mkdir, path, offset, length, content_b64, mode) and `screen` (max_width), each with its value's shape. `exec` takes a program and its arguments, never a shell line.
- **`bot.command-result@1`** and the device `ack` of **`bot.device-message@1`** gain `data`: the machine's answer to a computer command. The device `command` frame's kind list adds button, point and the computer kinds.
- **`bot.computer.control`** (active, first-party, sensitive): an agent service uses a person's own machine through `POST /api/v1/robots/:id/commands`. It works only for the machine's owner, and only when the owner turned it on for their agent. The owner's control level on the machine decides what may happen. The `bot` manifest lists it.

Additive. 0.166.0, CHANGELOG, generated files.

Fixtures:
- valid: `exec`, `fs-read`, `screen`, and an ack with data (operator and device)
- invalid: `exec-shell-line`, `fs-bad-op`

The full suite passes (19,694 checks). `compat.js v0.165.0` finds no breaking change.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex dabe573c..724b2168 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,18 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
++## 0.166.0 — 2026-10-14
++
++- **Computer control (plan T14/T17, OpenVibe.Node's `computer` plugin, Node#41).** `bot.command@1` takes the kinds
++ `exec` (argv, cwd, timeout_s, stdin), `fs` (op list|stat|read|write|mkdir, path, offset, length, content_b64, mode) and
++ `screen` (max_width), each with its value's shape. `bot.command-result@1` and the device `ack` of
++ `bot.device-message@1` gain `data`: the machine's answer. The device `command` frame lists button, point and the
++ computer kinds.
++- **`bot.computer.control`** (active, first-party, sensitive): an agent service uses a person's own machine through
++ `POST /api/v1/robots/:id/commands`. It works only for the machine's owner, and only when the owner turned it on for
++ their agent. The owner's control level on the machine decides what may happen. The `bot` manifest lists it.
++- Additive. Fixtures: valid `exec`, `fs-read`, `screen` and an ack with data; invalid `exec-shell-line`, `fs-bad-op`.
++
## 0.165.0 — 2026-10-14
- **`watch.resource.control`** (active, first-party, sensitive): OpenVibe.Watch's control API (ADR-048, plan T13 step
ddiff --git a/contracts/bot/command-result.v1.json b/contracts/bot/command-result.v1.json
iindex 93b79953..665ead76 100644
---- a/contracts/bot/command-result.v1.json
++++ b/contracts/bot/command-result.v1.json
@@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/bot/command-result.v1.json",
"title": "BotCommandResult",
-- "description": "bot.command-result@1: the command_result frame OpenVibe.Bot answers a bot.command@1 with on the operator WebSocket (server/realtime.js). result: ack or nack (the device answered; reason is its fault code, latency_ms the round trip), refused (the gate refused it; code is Bot's refusal code such as bot.estop_latched, bot.cooldown or bot.device_offline, and reason says why), expired (no answer before the deadline) or pending (the same id is still in flight). cached is true when a repeated id is answered from the first result.",
++ "description": "bot.command-result@1: the command_result frame OpenVibe.Bot answers a bot.command@1 with on the operator WebSocket (server/realtime.js). result: ack or nack (the device answered; reason is its fault code, latency_ms the round trip), refused (the gate refused it; code is Bot's refusal code such as bot.estop_latched, bot.cooldown or bot.device_offline, and reason says why), expired (no answer before the deadline) or pending (the same id is still in flight). cached is true when a repeated id is answered from the first result. An ack of a computer command (exec, fs, screen) carries its answer in data.",
"type": "object",
"required": [
"v",
@@@ -58,6 +58,10 @@
},
"cached": {
"type": "boolean"
++ },
++ "data": {
++ "type": "object",
++ "description": "A computer command's answer as the machine gave it (exec: exit_code, stdout, stderr, truncated, timed_out, duration_ms; fs: entries, the stat, content_b64, written, created; screen: format, width, height, content_b64). Present only on an ack of exec, fs or screen."
}
}
}
ddiff --git a/contracts/bot/command.v1.json b/contracts/bot/command.v1.json
iindex 2b2189a1..137a9aed 100644
---- a/contracts/bot/command.v1.json
++++ b/contracts/bot/command.v1.json
@@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/bot/command.v1.json",
"title": "BotCommand",
-- "description": "bot.command@1: an operator's command frame on OpenVibe.Bot's operator WebSocket (wss://openvibe.bot/control, after join; server/realtime.js onOperatorCommand). id is the operator's idempotency key (at most 64 characters; Bot mints one when it is missing): a repeated id answers with the first result. Bot's gate stamps the robot, the operator and the role, builds the value from the robot profile's commands (clamped by the owner's limits) and sets the deadline; ms asks for a duration within max_command_ms. Answered by one command_result frame (bot.command-result@1). The kinds button (a profile button by name, with an optional state for a hold button) and point (a normalised x, y video click) were added in 0.109.0 (plan T15 R9).",
++ "description": "bot.command@1: an operator's command frame on OpenVibe.Bot's operator WebSocket (wss://openvibe.bot/control, after join; server/realtime.js onOperatorCommand). id is the operator's idempotency key (at most 64 characters; Bot mints one when it is missing): a repeated id answers with the first result. Bot's gate stamps the robot, the operator and the role, builds the value from the robot profile's commands (clamped by the owner's limits) and sets the deadline; ms asks for a duration within max_command_ms. Answered by one command_result frame (bot.command-result@1). The kinds button (a profile button by name, with an optional state for a hold button) and point (a normalised x, y video click) were added in 0.109.0 (plan T15 R9). The computer kinds (exec, fs, screen; OpenVibe.Node's computer plugin, Node docs/computer.md) are taken only for a person's own machine, from its owner or an agent the owner let use it (bot.computer.control); the machine's owner sets on the machine what they may do, and the answer comes back in bot.command-result@1's data.",
"type": "object",
"required": [
"type",
@@@ -38,7 +38,10 @@
"display",
"halt",
"button",
-- "point"
++ "point",
++ "exec",
++ "fs",
++ "screen"
]
},
"value": {
@@@ -128,6 +131,157 @@
}
}
}
++ },
++ {
++ "if": {
++ "properties": {
++ "kind": {
++ "const": "exec"
++ }
++ },
++ "required": [
++ "kind"
++ ]
++ },
++ "then": {
++ "required": [
++ "value"
++ ],
++ "properties": {
++ "value": {
++ "type": "object",
++ "required": [
++ "argv"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "argv": {
++ "type": "array",
++ "minItems": 1,
++ "maxItems": 64,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 4096
++ },
++ "description": "a program and its arguments, never a shell line"
++ },
++ "cwd": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 4096,
++ "description": "an absolute folder on the machine (default: its first allowed folder)"
++ },
++ "timeout_s": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 600,
++ "description": "capped by the owner's timeout_s on the machine"
++ },
++ "stdin": {
++ "type": "string",
++ "maxLength": 65536
++ }
++ }
++ }
++ }
++ }
++ },
++ {
++ "if": {
++ "properties": {
++ "kind": {
++ "const": "fs"
++ }
++ },
++ "required": [
++ "kind"
++ ]
++ },
++ "then": {
++ "required": [
++ "value"
++ ],
++ "properties": {
++ "value": {
++ "type": "object",
++ "required": [
++ "op",
++ "path"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "op": {
++ "enum": [
++ "list",
++ "stat",
++ "read",
++ "write",
++ "mkdir"
++ ]
++ },
++ "path": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 4096,
++ "description": "absolute, on the machine"
++ },
++ "offset": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "length": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 262144
++ },
++ "content_b64": {
++ "type": "string",
++ "maxLength": 349528,
++ "description": "write: at most 256 KB of content, base64"
++ },
++ "mode": {
++ "enum": [
++ "create",
++ "overwrite",
++ "append"
++ ],
++ "description": "write: create (default) never replaces a file"
++ }
++ }
++ }
++ }
++ }
++ },
++ {
++ "if": {
++ "properties": {
++ "kind": {
++ "const": "screen"
++ }
++ },
++ "required": [
++ "kind"
++ ]
++ },
++ "then": {
++ "required": [
++ "value"
++ ],
++ "properties": {
++ "value": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "max_width": {
++ "type": "integer",
++ "minimum": 320,
++ "maximum": 3840
++ }
++ }
++ }
++ }
++ }
}
]
}
ddiff --git a/contracts/bot/device-message.v1.json b/contracts/bot/device-message.v1.json
iindex 8956a9a7..b6952414 100644
---- a/contracts/bot/device-message.v1.json
++++ b/contracts/bot/device-message.v1.json
@@@ -166,7 +166,12 @@
"ptz",
"say",
"display",
-- "halt"
++ "halt",
++ "button",
++ "point",
++ "exec",
++ "fs",
++ "screen"
]
},
"value": {
@@@ -174,7 +179,7 @@
},
"deadline_ms": {
"type": "integer",
-- "description": "Absolute deadline, epoch milliseconds; the device stops the motion at it."
++ "description": "Absolute deadline, epoch milliseconds; the device stops the motion at it. For exec, fs and screen it is the reply window."
},
"operator": {
"type": "object",
@@@ -728,6 +733,10 @@
"latency_ms": {
"type": "integer",
"minimum": 0
++ },
++ "data": {
++ "type": "object",
++ "description": "OpenVibe.Node: a computer command's answer (exec, fs, screen), at most 512 KB of JSON."
}
}
},
ddiff --git a/fixtures/bot.command-result/valid/ack-with-data.json b/fixtures/bot.command-result/valid/ack-with-data.json
nnew file mode 100644
iindex 00000000..c18def0f
---- /dev/null
++++ b/fixtures/bot.command-result/valid/ack-with-data.json
@@@ -0,0 +1,18 @@
++{
++ "v": 1,
++ "seq": 14,
++ "ts": 1759600000120,
++ "type": "command_result",
++ "id": "op-30",
++ "result": "ack",
++ "reason": null,
++ "latency_ms": 118,
++ "data": {
++ "exit_code": 0,
++ "stdout": " M index.html\n",
++ "stderr": "",
++ "truncated": false,
++ "timed_out": false,
++ "duration_ms": 35
++ }
++}
ddiff --git a/fixtures/bot.command/invalid/exec-shell-line.json b/fixtures/bot.command/invalid/exec-shell-line.json
nnew file mode 100644
iindex 00000000..85f8b54a
---- /dev/null
++++ b/fixtures/bot.command/invalid/exec-shell-line.json
@@@ -0,0 +1,11 @@
++{
++ "v": 1,
++ "seq": 33,
++ "ts": 1759600000000,
++ "type": "command",
++ "id": "op-33",
++ "kind": "exec",
++ "value": {
++ "argv": "rm -rf /"
++ }
++}
ddiff --git a/fixtures/bot.command/invalid/fs-bad-op.json b/fixtures/bot.command/invalid/fs-bad-op.json
nnew file mode 100644
iindex 00000000..30c33210
---- /dev/null
++++ b/fixtures/bot.command/invalid/fs-bad-op.json
@@@ -0,0 +1,12 @@
++{
++ "v": 1,
++ "seq": 34,
++ "ts": 1759600000000,
++ "type": "command",
++ "id": "op-34",
++ "kind": "fs",
++ "value": {
++ "op": "delete",
++ "path": "/home/ada"
++ }
++}
ddiff --git a/fixtures/bot.command/valid/exec.json b/fixtures/bot.command/valid/exec.json
nnew file mode 100644
iindex 00000000..e6c81cd5
---- /dev/null
++++ b/fixtures/bot.command/valid/exec.json
@@@ -0,0 +1,14 @@
++{
++ "v": 1,
++ "seq": 30,
++ "ts": 1759600000000,
++ "type": "command",
++ "id": "op-30",
++ "kind": "exec",
++ "value": {
++ "argv": ["git", "status", "--short"],
++ "cwd": "/home/ada/projects/site",
++ "timeout_s": 20
++ },
++ "ms": 120000
++}
ddiff --git a/fixtures/bot.command/valid/fs-read.json b/fixtures/bot.command/valid/fs-read.json
nnew file mode 100644
iindex 00000000..cda21e67
---- /dev/null
++++ b/fixtures/bot.command/valid/fs-read.json
@@@ -0,0 +1,13 @@
++{
++ "v": 1,
++ "seq": 31,
++ "ts": 1759600000000,
++ "type": "command",
++ "id": "op-31",
++ "kind": "fs",
++ "value": {
++ "op": "read",
++ "path": "/home/ada/projects/site/README.md",
++ "length": 4096
++ }
++}
ddiff --git a/fixtures/bot.command/valid/screen.json b/fixtures/bot.command/valid/screen.json
nnew file mode 100644
iindex 00000000..0e56fe01
---- /dev/null
++++ b/fixtures/bot.command/valid/screen.json
@@@ -0,0 +1,11 @@
++{
++ "v": 1,
++ "seq": 32,
++ "ts": 1759600000000,
++ "type": "command",
++ "id": "op-32",
++ "kind": "screen",
++ "value": {
++ "max_width": 1280
++ }
++}
ddiff --git a/fixtures/bot.device-message/valid/ack-with-data.json b/fixtures/bot.device-message/valid/ack-with-data.json
nnew file mode 100644
iindex 00000000..3aa50ed4
---- /dev/null
++++ b/fixtures/bot.device-message/valid/ack-with-data.json
@@@ -0,0 +1,14 @@
++{
++ "v": 1,
++ "seq": 52,
++ "ts": 1759600000118,
++ "type": "ack",
++ "id": "cmd_01JA0000000000000000000030",
++ "latency_ms": 101,
++ "data": {
++ "path": "/home/ada/projects/site",
++ "entries": [{ "name": "index.html", "type": "file", "size": 812, "mtime": 1759599000 }],
++ "total": 1,
++ "truncated": false
++ }
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex beeba26a..8cf4c272 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -70427,7 +70427,12 @@
"ptz",
"say",
"display",
-- "halt"
++ "halt",
++ "button",
++ "point",
++ "exec",
++ "fs",
++ "screen"
]
},
"value": {
@@@ -70435,7 +70440,7 @@
},
"deadline_ms": {
"type": "integer",
-- "description": "Absolute deadline, epoch milliseconds; the device stops the motion at it."
++ "description": "Absolute deadline, epoch milliseconds; the device stops the motion at it. For exec, fs and screen it is the reply window."
},
"operator": {
"type": "object",
@@@ -70989,6 +70994,10 @@
"latency_ms": {
"type": "integer",
"minimum": 0
++ },
++ "data": {
++ "type": "object",
++ "description": "OpenVibe.Node: a computer command's answer (exec, fs, screen), at most 512 KB of JSON."
}
}
},
@@@ -71157,7 +71166,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/bot/command.v1.json",
"title": "BotCommand",
-- "description": "bot.command@1: an operator's command frame on OpenVibe.Bot's operator WebSocket (wss://openvibe.bot/control, after join; server/realtime.js onOperatorCommand). id is the operator's idempotency key (at most 64 characters; Bot mints one when it is missing): a repeated id answers with the first result. Bot's gate stamps the robot, the operator and the role, builds the value from the robot profile's commands (clamped by the owner's limits) and sets the deadline; ms asks for a duration within max_command_ms. Answered by one command_result frame (bot.command-result@1). The kinds button (a profile button by name, with an optional state for a hold button) and point (a normalised x, y video click) were added in 0.109.0 (plan T15 R9).",
++ "description": "bot.command@1: an operator's command frame on OpenVibe.Bot's operator WebSocket (wss://openvibe.bot/control, after join; server/realtime.js onOperatorCommand). id is the operator's idempotency key (at most 64 characters; Bot mints one when it is missing): a repeated id answers with the first result. Bot's gate stamps the robot, the operator and the role, builds the value from the robot profile's commands (clamped by the owner's limits) and sets the deadline; ms asks for a duration within max_command_ms. Answered by one command_result frame (bot.command-result@1). The kinds button (a profile button by name, with an optional state for a hold button) and point (a normalised x, y video click) were added in 0.109.0 (plan T15 R9). The computer kinds (exec, fs, screen; OpenVibe.Node's computer plugin, Node docs/computer.md) are taken only for a person's own machine, from its owner or an agent the owner let use it (bot.computer.control); the machine's owner sets on the machine what they may do, and the answer comes back in bot.command-result@1's data.",
"type": "object",
"required": [
"type",
@@@ -71193,7 +71202,10 @@
"display",
"halt",
"button",
-- "point"
++ "point",
++ "exec",
++ "fs",
++ "screen"
]
},
"value": {
@@@ -71283,6 +71295,157 @@
}
}
}
++ },
++ {
++ "if": {
++ "properties": {
++ "kind": {
++ "const": "exec"
++ }
++ },
++ "required": [
++ "kind"
++ ]
++ },
++ "then": {
++ "required": [
++ "value"
++ ],
++ "properties": {
++ "value": {
++ "type": "object",
++ "required": [
++ "argv"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "argv": {
++ "type": "array",
++ "minItems": 1,
++ "maxItems": 64,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 4096
++ },
++ "description": "a program and its arguments, never a shell line"
++ },
++ "cwd": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 4096,
++ "description": "an absolute folder on the machine (default: its first allowed folder)"
++ },
++ "timeout_s": {
++ "type": "integer",
++ "minimum": 1,
++ "maximum": 600,
++ "description": "capped by the owner's timeout_s on the machine"
++ },
++ "stdin": {
++ "type": "string",
++ "maxLength": 65536
++ }
++ }
++ }
++ }
++ }
++ },
++ {
++ "if": {
++ "properties": {
++ "kind": {
++ "const": "fs"
++ }
++ },
++ "required": [
++ "kind"
++ ]
++ },
++ "then": {
++ "required": [
++ "value"
++ ],
++ "properties": {
++ "value": {
++ "type": "object",
++ "required": [
++ "op",
++ "path"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "op": {
++ "enum": [
++ "list",
++ "stat",
++ "read",
++ "write",
++ "mkdir"
++ ]
++ },
++ "path": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 4096,
++ "description": "absolute, on the machine"
++ },
++ "offset": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "length": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 262144
++ },
++ "content_b64": {
++ "type": "string",
++ "maxLength": 349528,
++ "description": "write: at most 256 KB of content, base64"
++ },
++ "mode": {
++ "enum": [
++ "create",
++ "overwrite",
++ "append"
++ ],
++ "description": "write: create (default) never replaces a file"
++ }
++ }
++ }
++ }
++ }
++ },
++ {
++ "if": {
++ "properties": {
++ "kind": {
++ "const": "screen"
++ }
++ },
++ "required": [
++ "kind"
++ ]
++ },
++ "then": {
++ "required": [
++ "value"
++ ],
++ "properties": {
++ "value": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "max_width": {
++ "type": "integer",
++ "minimum": 320,
++ "maximum": 3840
++ }
++ }
++ }
++ }
++ }
}
]
}
@@@ -71295,7 +71458,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/bot/command-result.v1.json",
"title": "BotCommandResult",
-- "description": "bot.command-result@1: the command_result frame OpenVibe.Bot answers a bot.command@1 with on the operator WebSocket (server/realtime.js). result: ack or nack (the device answered; reason is its fault code, latency_ms the round trip), refused (the gate refused it; code is Bot's refusal code such as bot.estop_latched, bot.cooldown or bot.device_offline, and reason says why), expired (no answer before the deadline) or pending (the same id is still in flight). cached is true when a repeated id is answered from the first result.",
++ "description": "bot.command-result@1: the command_result frame OpenVibe.Bot answers a bot.command@1 with on the operator WebSocket (server/realtime.js). result: ack or nack (the device answered; reason is its fault code, latency_ms the round trip), refused (the gate refused it; code is Bot's refusal code such as bot.estop_latched, bot.cooldown or bot.device_offline, and reason says why), expired (no answer before the deadline) or pending (the same id is still in flight). cached is true when a repeated id is answered from the first result. An ack of a computer command (exec, fs, screen) carries its answer in data.",
"type": "object",
"required": [
"v",
@@@ -71351,6 +71514,10 @@
},
"cached": {
"type": "boolean"
++ },
++ "data": {
++ "type": "object",
++ "description": "A computer command's answer as the machine gave it (exec: exit_code, stdout, stderr, truncated, timed_out, duration_ms; fs: entries, the stat, content_b64, written, created; screen: format, width, height, content_b64). Present only on an ack of exec, fs or screen."
}
}
}
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex 6a20279b..9adb5f03 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex ddad8782..247d39c1 100644
---- a/generated/openapi/ai.json
++++ b/generated/openapi/ai.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.AI API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/billing.json b/generated/openapi/billing.json
iindex f6032691..d9eb0a67 100644
---- a/generated/openapi/billing.json
++++ b/generated/openapi/billing.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Billing API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex ff5e2b22..548effcc 100644
---- a/generated/openapi/blog.json
++++ b/generated/openapi/blog.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Blog API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex ab8438e2..73f701c3 100644
---- a/generated/openapi/bot.json
++++ b/generated/openapi/bot.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bot API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
@@@ -2911,6 +2911,10 @@
}
},
"x-openvibe-other-bindings": [
++ {
++ "capability": "bot.computer.control",
++ "binding": "POST /api/v1/robots/:id/commands with kind exec, fs or screen (bot.command@1, answered by bot.command-result@1 with data)"
++ },
{
"capability": "bot.robot.control",
"binding": "WS /control {type:\"command\"} (bot.command@1, answered by a command_result frame, bot.command-result@1)"
ddiff --git a/generated/openapi/chat.json b/generated/openapi/chat.json
iindex 55ab11d7..ae1f86b5 100644
---- a/generated/openapi/chat.json
++++ b/generated/openapi/chat.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Chat API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/codes.json b/generated/openapi/codes.json
iindex a261586f..c6c71148 100644
---- a/generated/openapi/codes.json
++++ b/generated/openapi/codes.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Codes API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/community.json b/generated/openapi/community.json
iindex 04c9ea55..5404e49e 100644
---- a/generated/openapi/community.json
++++ b/generated/openapi/community.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Community API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/coupons.json b/generated/openapi/coupons.json
iindex 4e9298b1..54f652a1 100644
---- a/generated/openapi/coupons.json
++++ b/generated/openapi/coupons.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Coupons API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/deals.json b/generated/openapi/deals.json
iindex 440b6c8b..5e548e4e 100644
---- a/generated/openapi/deals.json
++++ b/generated/openapi/deals.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Deals API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/events.json b/generated/openapi/events.json
iindex 173b1504..046623da 100644
---- a/generated/openapi/events.json
++++ b/generated/openapi/events.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Events API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex a8b68bdf..d4af93d9 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/games.json b/generated/openapi/games.json
iindex ea7a292f..ea6b58bf 100644
---- a/generated/openapi/games.json
++++ b/generated/openapi/games.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Games API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/host.json b/generated/openapi/host.json
iindex ac096ba6..34223f46 100644
---- a/generated/openapi/host.json
++++ b/generated/openapi/host.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Host API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/index.json b/generated/openapi/index.json
iindex d4f1dd62..122fa8a2 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -34,7 +34,7 @@
"name": "OpenVibe.Bot",
"origin": "https://openvibe.bot",
"operations": 20,
-- "capabilities": 5
++ "capabilities": 6
},
{
"service": "chat",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex 17e37d35..5dfcf6af 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/live.json b/generated/openapi/live.json
iindex 6b67e39b..d6c0360c 100644
---- a/generated/openapi/live.json
++++ b/generated/openapi/live.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Live API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media-hub.json b/generated/openapi/media-hub.json
iindex d600ab57..9b65543a 100644
---- a/generated/openapi/media-hub.json
++++ b/generated/openapi/media-hub.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.MediaHub API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media.json b/generated/openapi/media.json
iindex 817ecc56..a9e3acda 100644
---- a/generated/openapi/media.json
++++ b/generated/openapi/media.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Media API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 226b9147..64a3438f 100644
---- a/generated/openapi/network.json
++++ b/generated/openapi/network.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Network API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/news.json b/generated/openapi/news.json
iindex f3963d3a..de9a7219 100644
---- a/generated/openapi/news.json
++++ b/generated/openapi/news.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.News API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/openre.json b/generated/openapi/openre.json
iindex 4f034c7e..6303ec73 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRestream API",
-- "version": "0.165.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex 53d358dc..2c809876 100644
---- a/generated/openapi/reviews.json
++++ b/generated/openapi/reviews.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Reviews API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex 9aa7a4c6..c6f99c89 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/search.json b/generated/openapi/search.json
iindex 7af79edd..de82c6a1 100644
---- a/generated/openapi/search.json
++++ b/generated/openapi/search.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Search API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex 5dd188fb..6d828512 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/sources.json b/generated/openapi/sources.json
iindex d2135ff9..3d34e5a3 100644
---- a/generated/openapi/sources.json
++++ b/generated/openapi/sources.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Sources API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/space.json b/generated/openapi/space.json
iindex b0d99809..78b20443 100644
---- a/generated/openapi/space.json
++++ b/generated/openapi/space.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Space API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tips.json b/generated/openapi/tips.json
iindex 1ef0ab66..63ba28b9 100644
---- a/generated/openapi/tips.json
++++ b/generated/openapi/tips.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tips API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tools.json b/generated/openapi/tools.json
iindex 9d566ca2..d2af00eb 100644
---- a/generated/openapi/tools.json
++++ b/generated/openapi/tools.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tools API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/trade.json b/generated/openapi/trade.json
iindex 5e58d906..413ada86 100644
---- a/generated/openapi/trade.json
++++ b/generated/openapi/trade.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Trade API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vip.json b/generated/openapi/vip.json
iindex c96fb926..d99c3b06 100644
---- a/generated/openapi/vip.json
++++ b/generated/openapi/vip.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.VIP API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex beb05a3f..1487cbea 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/wiki.json b/generated/openapi/wiki.json
iindex cffceb60..7ec99d48 100644
---- a/generated/openapi/wiki.json
++++ b/generated/openapi/wiki.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Wiki API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/work.json b/generated/openapi/work.json
iindex d9a0c6eb..e6275713 100644
---- a/generated/openapi/work.json
++++ b/generated/openapi/work.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Work API",
-- "version": "0.165.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.165.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.166.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.166.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 65bcb173..4de9ee5e 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -176086,10 +176086,10 @@ export type BotDeviceMessage =
type: "command";
id: string;
ref?: string;
-- kind: "drive" | "actuator" | "ptz" | "say" | "display" | "halt";
++ kind: "drive" | "actuator" | "ptz" | "say" | "display" | "halt" | "button" | "point" | "exec" | "fs" | "screen";
value?: {};
/**
-- * Absolute deadline, epoch milliseconds; the device stops the motion at it.
++ * Absolute deadline, epoch milliseconds; the device stops the motion at it. For exec, fs and screen it is the reply window.
*/
deadline_ms?: number;
operator?: {
@@@ -176228,6 +176228,10 @@ export type BotDeviceMessage =
type: "ack";
id: string;
latency_ms?: number;
++ /**
++ * OpenVibe.Node: a computer command's answer (exec, fs, screen), at most 512 KB of JSON.
++ */
++ data?: {};
}
| {
v: 1;
@@@ -176268,7 +176272,7 @@ export type BotDeviceMessage =
/** [email protected] (owner: bot) */
/**
-- * bot.command@1: an operator's command frame on OpenVibe.Bot's operator WebSocket (wss://openvibe.bot/control, after join; server/realtime.js onOperatorCommand). id is the operator's idempotency key (at most 64 characters; Bot mints one when it is missing): a repeated id answers with the first result. Bot's gate stamps the robot, the operator and the role, builds the value from the robot profile's commands (clamped by the owner's limits) and sets the deadline; ms asks for a duration within max_command_ms. Answered by one command_result frame (bot.command-result@1). The kinds button (a profile button by name, with an optional state for a hold button) and point (a normalised x, y video click) were added in 0.109.0 (plan T15 R9).
++ * bot.command@1: an operator's command frame on OpenVibe.Bot's operator WebSocket (wss://openvibe.bot/control, after join; server/realtime.js onOperatorCommand). id is the operator's idempotency key (at most 64 characters; Bot mints one when it is missing): a repeated id answers with the first result. Bot's gate stamps the robot, the operator and the role, builds the value from the robot profile's commands (clamped by the owner's limits) and sets the deadline; ms asks for a duration within max_command_ms. Answered by one command_result frame (bot.command-result@1). The kinds button (a profile button by name, with an optional state for a hold button) and point (a normalised x, y video click) were added in 0.109.0 (plan T15 R9). The computer kinds (exec, fs, screen; OpenVibe.Node's computer plugin, Node docs/computer.md) are taken only for a person's own machine, from its owner or an agent the owner let use it (bot.computer.control); the machine's owner sets on the machine what they may do, and the answer comes back in bot.command-result@1's data.
*/
export type BotCommand = {
[k: string]: unknown | undefined;
@@@ -176278,14 +176282,14 @@ export type BotCommand = {
ts?: number;
type: "command";
id?: string;
-- kind: "drive" | "actuator" | "ptz" | "say" | "display" | "halt" | "button" | "point";
++ kind: "drive" | "actuator" | "ptz" | "say" | "display" | "halt" | "button" | "point" | "exec" | "fs" | "screen";
value?: {};
ms?: number;
};
/** [email protected] (owner: bot) */
/**
-- * bot.command-result@1: the command_result frame OpenVibe.Bot answers a bot.command@1 with on the operator WebSocket (server/realtime.js). result: ack or nack (the device answered; reason is its fault code, latency_ms the round trip), refused (the gate refused it; code is Bot's refusal code such as bot.estop_latched, bot.cooldown or bot.device_offline, and reason says why), expired (no answer before the deadline) or pending (the same id is still in flight). cached is true when a repeated id is answered from the first result.
++ * bot.command-result@1: the command_result frame OpenVibe.Bot answers a bot.command@1 with on the operator WebSocket (server/realtime.js). result: ack or nack (the device answered; reason is its fault code, latency_ms the round trip), refused (the gate refused it; code is Bot's refusal code such as bot.estop_latched, bot.cooldown or bot.device_offline, and reason says why), expired (no answer before the deadline) or pending (the same id is still in flight). cached is true when a repeated id is answered from the first result. An ack of a computer command (exec, fs, screen) carries its answer in data.
*/
export interface BotCommandResult {
v: 1;
@@@ -176298,6 +176302,10 @@ export interface BotCommandResult {
code?: string;
latency_ms?: number;
cached?: boolean;
++ /**
++ * A computer command's answer as the machine gave it (exec: exit_code, stdout, stderr, truncated, timed_out, duration_ms; fs: entries, the stat, content_b64, written, created; screen: format, width, height, content_b64). Present only on an ack of exec, fs or screen.
++ */
++ data?: {};
}
/** [email protected] (owner: bot) */
ddiff --git a/manifests/capabilities/bot.computer.control.json b/manifests/capabilities/bot.computer.control.json
nnew file mode 100644
iindex 00000000..9d5b3674
---- /dev/null
++++ b/manifests/capabilities/bot.computer.control.json
@@@ -0,0 +1,24 @@
++{
++ "id": "bot.computer.control",
++ "version": "1.0",
++ "owner": "bot",
++ "status": "active",
++ "visibility": "first-party",
++ "sensitive": true,
++ "description": "Use a person's own computer with a Network service token naming that person in X-OV-Subject: the computer kinds of bot.command@1 (exec, fs, screen) through POST /api/v1/robots/:id/commands, for a machine (openvibe.bot/machines) whose owner is that person and who turned on 'Let my agent use this computer'. Bot takes them from no one else (never an operator or a queue member), and the machine's owner sets on the machine itself what may happen (OpenVibe.Node's computer plugin: observe, ask, trusted or full; ask waits for the owner's approval there). The answer is bot.command-result@1's data; every command is audited, a refused one emits bot.command.refused.",
++ "permissions": [
++ "bot:computer:control"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "bot-control",
++ "events": [
++ "bot.command.refused"
++ ],
++ "implementedBy": [
++ "POST /api/v1/robots/:id/commands with kind exec, fs or screen (bot.command@1, answered by bot.command-result@1 with data)"
++ ],
++ "inputSchema": "bot.command@1",
++ "outputSchema": "bot.command-result@1"
++}
ddiff --git a/manifests/services/bot.json b/manifests/services/bot.json
iindex 7490db0f..3f5b22a2 100644
---- a/manifests/services/bot.json
++++ b/manifests/services/bot.json
@@@ -30,6 +30,7 @@
"bot.robot.read",
"bot.robot.manage",
"bot.robot.control",
++ "bot.computer.control",
"bot.device.connect",
"bot.job.dispatch",
"bot.resource.read"
ddiff --git a/package.json b/package.json
iindex da701da6..253f9afa 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.165.0",
++ "version": "0.166.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
ddiff --git a/test/bot-manifest.test.js b/test/bot-manifest.test.js
iindex 4cd3b463..d1cb8711 100644
---- a/test/bot-manifest.test.js
++++ b/test/bot-manifest.test.js
@@@ -7,7 +7,9 @@ const c = require('..');
// OpenVibe.Bot STATUS.json "capabilities" and "events" at origin/main (2026-10-04, with bot.job.dispatch, plan T14 step 6).
// bot.resource.read: the robots in OpenVibe.Services' resource index (planned 0.129.0, active 0.130.0; plan T13 step 8).
--const BOT_CAPABILITIES = ['bot.robot.read', 'bot.robot.manage', 'bot.robot.control', 'bot.device.connect', 'bot.job.dispatch', 'bot.resource.read'];
++// bot.computer.control: an owner's agent uses their own machine (0.166.0, plan T14/T17; Bot's STATUS.json lists it with
++// the computer kinds).
++const BOT_CAPABILITIES = ['bot.robot.read', 'bot.robot.manage', 'bot.robot.control', 'bot.computer.control', 'bot.device.connect', 'bot.job.dispatch', 'bot.resource.read'];
const BOT_EVENTS = ['bot.robot.online', 'bot.robot.offline', 'bot.estop.set', 'bot.estop.cleared', 'bot.command.refused'];
const bot = c.services.get('bot');
@@@ -18,4 +20,12 @@ for (const t of BOT_EVENTS) assert.ok(c.resolve(`${t}@1`), `${t} has a payload c
// The device and operator WebSocket frames are contracts too, and a command frame is refused for an unknown kind.
for (const id of ['bot.device-message@1', 'bot.command@1', 'bot.command-result@1', 'bot.robot-profile@1']) assert.ok(c.resolve(id), `${id} resolves`);
assert.ok(!c.validate('bot.command@1', { type: 'command', kind: 'fly' }).valid, 'an unknown command kind is refused');
++// The computer kinds: a program and its arguments, never a shell line; a file op from the list; the answer in data.
++const cmd = (kind, value) => ({ v: 1, seq: 1, ts: 1, type: 'command', id: 'op-1', kind, value });
++assert.ok(c.validate('bot.command@1', cmd('exec', { argv: ['ls', '-la'] })).valid, 'exec with argv');
++assert.ok(!c.validate('bot.command@1', cmd('exec', { argv: 'ls -la' })).valid, 'exec with a shell line is refused');
++assert.ok(!c.validate('bot.command@1', cmd('exec', {})).valid, 'exec needs argv');
++assert.ok(!c.validate('bot.command@1', cmd('fs', { op: 'delete', path: '/x' })).valid, 'fs has no delete');
++assert.ok(!c.validate('bot.command@1', cmd('screen', { max_width: 100 })).valid, 'a screen at least 320 wide');
++assert.ok(c.validate('bot.command-result@1', { v: 1, seq: 1, ts: 1, type: 'command_result', id: 'op-1', result: 'ack', data: { exit_code: 0 } }).valid, 'an ack with data');
console.log('bot manifest: all checks passed');