voroa-cli 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +247 -2
- package/package.json +41 -4
- package/src/agent.js +95 -0
- package/src/api.js +552 -0
- package/src/commands/db.js +99 -0
- package/src/commands/deploy.js +130 -0
- package/src/commands/domains.js +122 -0
- package/src/commands/env.js +143 -0
- package/src/commands/lifecycle.js +40 -0
- package/src/commands/link.js +92 -0
- package/src/commands/login.js +104 -0
- package/src/commands/logs.js +304 -0
- package/src/commands/services.js +72 -0
- package/src/commands/ssh.js +46 -0
- package/src/commands/status.js +50 -0
- package/src/commands/tokens.js +81 -0
- package/src/commands/workspace.js +63 -0
- package/src/config.js +108 -0
- package/src/errors.js +53 -0
- package/src/flags.js +32 -0
- package/src/index.js +212 -0
- package/src/interactive.js +34 -0
- package/src/link.js +72 -0
- package/src/mcp/build.js +72 -0
- package/src/mcp/kernel/index.js +59 -0
- package/src/mcp/kernel/logger.js +28 -0
- package/src/mcp/lib/config.js +72 -0
- package/src/mcp/lib/credentials.js +51 -0
- package/src/mcp/lib/http.js +136 -0
- package/src/mcp/lib/response.js +14 -0
- package/src/mcp/lib/reversibility.js +33 -0
- package/src/mcp/reversibilityMap.json +77 -0
- package/src/mcp/tools/_action.js +49 -0
- package/src/mcp/tools/_ids.js +42 -0
- package/src/mcp/tools/_shape.js +318 -0
- package/src/mcp/tools/actions.js +94 -0
- package/src/mcp/tools/getBuildLog.js +39 -0
- package/src/mcp/tools/getDeployHistory.js +42 -0
- package/src/mcp/tools/getRuntimeLogs.js +44 -0
- package/src/mcp/tools/getServiceStatus.js +41 -0
- package/src/mcp/tools/getUsage.js +34 -0
- package/src/mcp/tools/listDatabases.js +25 -0
- package/src/mcp/tools/listDomains.js +33 -0
- package/src/mcp/tools/listServices.js +20 -0
- package/src/mcp/tools/propose.js +124 -0
- package/src/mcp/tools/reads.js +756 -0
- package/src/mcp/tools/writes.js +632 -0
- package/src/mcpTools.js +292 -0
- package/src/output.js +145 -0
- package/src/prompt.js +229 -0
- package/src/region.js +5 -0
- package/src/resolve.js +64 -0
- package/src/session.js +270 -0
- package/src/status.js +199 -0
- package/src/stepup.js +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Web Tech Digital Work
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,248 @@
|
|
|
1
|
-
#
|
|
1
|
+
# voroa-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!--
|
|
4
|
+
ZERO RUNTIME DEPENDENCIES - and that is a decision, not an oversight.
|
|
5
|
+
|
|
6
|
+
This package installs onto machines we do not control: a laptop, a CI image, a colleague's
|
|
7
|
+
Windows box. Two entries in the project's known-bugs log are exactly that failure mode:
|
|
8
|
+
|
|
9
|
+
bug #2 - `npm install` died building a native module (node-gyp / "could not find Visual
|
|
10
|
+
Studio") because the installed Node had no prebuilt binary for it.
|
|
11
|
+
bug #11 - the same package fell back to compiling from source inside a slim Docker image
|
|
12
|
+
that had no Python and no build tools, so the image would not build at all.
|
|
13
|
+
|
|
14
|
+
A CLI that cannot be installed is worse than a CLI that is missing a nicety. So: no native
|
|
15
|
+
modules, no node-gyp, no prebuild-install, and no transitive supply chain to audit. HTTP is
|
|
16
|
+
the built-in `fetch`, prompts are `node:readline`, tests are `node --test`. Node >=20 gives
|
|
17
|
+
us all three in the standard library.
|
|
18
|
+
|
|
19
|
+
If a future change wants a dependency, the bar is that question again: what happens on the
|
|
20
|
+
machine where it does not compile?
|
|
21
|
+
|
|
22
|
+
PUBLISHING: released through .github/workflows/publish-cli.yml (manual trigger, dry-run by default, npm
|
|
23
|
+
trusted publishing - no stored token). The docs pages `docs-site/content/cli.md` and `cli-reference.md`
|
|
24
|
+
flip from `status: coming-soon` only AFTER `npm view voroa-cli` resolves, never before (coming-soon
|
|
25
|
+
honesty: we do not describe something a reader cannot get).
|
|
26
|
+
-->
|
|
27
|
+
|
|
28
|
+
Deploy and inspect Voroa services from the terminal.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
Needs Node 20 or newer.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
npm install -g voroa-cli
|
|
36
|
+
voroa --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or without installing: `npx voroa-cli --help`.
|
|
40
|
+
|
|
41
|
+
## Sign in
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
voroa login # emails you a 6-digit code
|
|
45
|
+
voroa login --password # email + password instead
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The session token is written to `~/.voroa/config.json` with owner-only permissions (`0600`
|
|
49
|
+
on Linux and macOS; on Windows the file inherits your user profile's ACL, which the Node
|
|
50
|
+
runtime cannot narrow further). The token is never printed, never passed on a command line
|
|
51
|
+
and never included in an error message.
|
|
52
|
+
|
|
53
|
+
**A stored session is bound to the endpoint that issued it.** If you point the CLI somewhere
|
|
54
|
+
else with `--api-url` or `VOROA_API_URL`, the stored token is deliberately *not* sent there
|
|
55
|
+
and the command stops with a message naming the endpoint your session belongs to. That flag
|
|
56
|
+
is one word in a command you might paste from anywhere, and a live session token is not
|
|
57
|
+
something to hand to whatever host it names. To use a different endpoint, sign in to it
|
|
58
|
+
(`voroa login --api-url <url>`) or pass `VOROA_TOKEN` explicitly.
|
|
59
|
+
|
|
60
|
+
For CI, set `VOROA_TOKEN` instead of signing in — it is an explicit choice by whoever runs
|
|
61
|
+
the command, so it works against any endpoint. Use an **API token** created in the dashboard
|
|
62
|
+
(it starts with `voroa_cat_`): it is scoped, revocable, expires, and is pinned to one workspace,
|
|
63
|
+
so `--workspace` does not apply to it. A login session in a CI secret is a full-power login with
|
|
64
|
+
none of those limits. A token reaches only what its scopes allow; a command outside them fails
|
|
65
|
+
with "not available to an API token". Live build streaming is session-only, so
|
|
66
|
+
`deploy --wait` with a token polls instead. `VOROA_API_URL` overrides the API endpoint
|
|
67
|
+
(so does `--api-url`, which is mainly useful against a local backend).
|
|
68
|
+
|
|
69
|
+
Signing in as a different account clears the workspace you had selected, so a workspace id
|
|
70
|
+
from one account is never sent on another's behalf.
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
voroa services list the services in the active workspace
|
|
76
|
+
voroa status <service> one service's live state
|
|
77
|
+
voroa logs <service> tail the running container's output
|
|
78
|
+
voroa logs <service> --follow keep tailing
|
|
79
|
+
voroa logs <service> --build the latest build's log (add a deploy id for an older one)
|
|
80
|
+
voroa deploy <service> trigger a deploy
|
|
81
|
+
voroa deploy <service> --wait trigger a deploy and wait for the outcome
|
|
82
|
+
voroa deploy <service> --follow also stream the build log while it waits
|
|
83
|
+
voroa restart|stop|start <service> restart, stop or start the running service
|
|
84
|
+
voroa rollback <service> [--to <id>] serve the previous version, or a chosen deploy, again
|
|
85
|
+
voroa env list [service] variable names
|
|
86
|
+
voroa env set <KEY> [service] value from stdin or a hidden prompt; --overwrite to replace
|
|
87
|
+
voroa env unset <KEY> [service] remove a variable
|
|
88
|
+
voroa db list databases in the active workspace
|
|
89
|
+
voroa db connect <database> open psql as the postgres user (asks you to confirm it is you)
|
|
90
|
+
voroa tokens list API tokens
|
|
91
|
+
voroa tokens create --name <n> --scope <a,b> the value is shown once
|
|
92
|
+
voroa tokens revoke <id> stop a token working immediately
|
|
93
|
+
voroa domains list [service] custom domains and their state
|
|
94
|
+
voroa domains add <domain> add one and print the DNS record to create
|
|
95
|
+
voroa domains verify <domain> check it (exit 2 until live; --fix re-applies a stuck one)
|
|
96
|
+
voroa ssh [service] [--print] a shell in the running service (uses your account's SSH keys)
|
|
97
|
+
voroa link <service> bind this folder to a service
|
|
98
|
+
voroa unlink remove that binding
|
|
99
|
+
voroa open [service] [--print] the service's dashboard page
|
|
100
|
+
voroa workspace list your workspaces
|
|
101
|
+
voroa workspace set <id> choose the workspace later commands act on
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`<service>` is a service name or its id. Names are resolved only within the active
|
|
105
|
+
workspace; if two services share a name you will be asked for the id.
|
|
106
|
+
|
|
107
|
+
`voroa link` writes `.voroa.json` (a service id, its name and the workspace id - no secret, safe
|
|
108
|
+
to commit). In that folder and any subfolder, `<service>` becomes optional. The id is checked
|
|
109
|
+
against your workspace on every command, so a link copied from someone else's repository does
|
|
110
|
+
nothing. An explicit `--workspace` still wins over the one the link remembers.
|
|
111
|
+
|
|
112
|
+
## Interactive session
|
|
113
|
+
|
|
114
|
+
Run `voroa` with nothing after it and you get a session instead of a single command:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
$ voroa
|
|
118
|
+
|
|
119
|
+
| ^ voroa CLI 0.3.0
|
|
120
|
+
|
|
|
121
|
+
| Account you@example.com
|
|
122
|
+
| Services * 2 running o 1 idle x 0 failed
|
|
123
|
+
|
|
124
|
+
/help commands - Tab complete - Ctrl+C stop - /exit
|
|
125
|
+
|
|
126
|
+
voroa > services
|
|
127
|
+
voroa > logs web --follow
|
|
128
|
+
voroa > deploy web --wait
|
|
129
|
+
voroa > /exit
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Every command on this page works there, with or without the leading `/`. **Tab** completes a command
|
|
133
|
+
name, then a service name. **Up arrow** recalls earlier commands - only commands: what you type into a
|
|
134
|
+
password, code or value prompt is never kept. **Ctrl+C** stops a running log tail and returns to the
|
|
135
|
+
prompt; at an empty prompt, pressing it twice leaves, as does `/exit` or Ctrl+D. A command that fails
|
|
136
|
+
prints its message and the session carries on.
|
|
137
|
+
|
|
138
|
+
It is not a shell: quotes group words (`--command "node job.js"`), and nothing else on the line is
|
|
139
|
+
expanded or executed. In a pipe or in CI, `voroa` with no arguments prints the usage text exactly as
|
|
140
|
+
before; `voroa session` opens a session by name.
|
|
141
|
+
|
|
142
|
+
On a real terminal the header, the status marks (green running, grey idle, amber changing, red failed)
|
|
143
|
+
and the last line of a deploy are coloured. That is decoration on top of the words: set `NO_COLOR`, or
|
|
144
|
+
pipe the output anywhere, and you get the same text with no colour and no escape codes.
|
|
145
|
+
|
|
146
|
+
## For scripts and AI agents
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
voroa agent the rules, written for a model to read
|
|
150
|
+
voroa agent --json the same as data
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- `--json` on any command: the result is JSON on stdout, and a failure is one object on stderr,
|
|
154
|
+
`{"error": "...", "code": "NOT_FOUND"}`. The codes are a short fixed list - `voroa agent` prints them.
|
|
155
|
+
- `--no-input` or `VOROA_NO_INPUT=1`: a step that would ask a question (a sign-in code, a password)
|
|
156
|
+
fails at once with `NEEDS_HUMAN` instead of waiting for an answer nobody will type.
|
|
157
|
+
- `deploy --wait --json` prints one object when it ends, with `outcome` (`live`, `failed`,
|
|
158
|
+
`failed_to_start`, `timeout`, ...) and the same `exitCode` the process returns.
|
|
159
|
+
- `logs --json` prints `{"service", "lines"}`; with `--follow`, one `{"line"}` object per line.
|
|
160
|
+
- `status --all --json` gives every service with its `verdict` in one call.
|
|
161
|
+
- `voroa tools <word>` narrows the list (`voroa tools bucket`); each command is marked as changing
|
|
162
|
+
something or not.
|
|
163
|
+
- A flag a command does not have is refused (`BAD_INPUT`), never ignored.
|
|
164
|
+
- Authenticate an agent with `VOROA_TOKEN`, never with a sign-in.
|
|
165
|
+
|
|
166
|
+
## Everything else: `voroa tools`
|
|
167
|
+
|
|
168
|
+
The commands above are the everyday ones. Everything else the platform lets a token do is a command
|
|
169
|
+
too - projects and environments, scheduled tasks, database backups and users, storage buckets,
|
|
170
|
+
environment groups, previews, edge cache, maintenance mode, usage, invoices, support tickets:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
voroa tools the full list, one line each
|
|
174
|
+
voroa list-buckets run one
|
|
175
|
+
voroa create-scheduled-task --help what it takes
|
|
176
|
+
voroa create-scheduled-task web --name nightly --command "node job.js" --frequency daily
|
|
177
|
+
voroa get-database-metrics <database-id> --json
|
|
178
|
+
voroa tool restart web one whose short name an everyday command already uses
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
These are the same operations, with the same checks and the same output, that the Voroa connector
|
|
182
|
+
for AI clients offers - the CLI runs that tool set directly, so the two cannot drift apart.
|
|
183
|
+
|
|
184
|
+
- **Arguments** are flags named after the argument (`--service-id`, `--database-id`). Required ones
|
|
185
|
+
can also be given as bare words, in the order `--help` lists them. `--args '<json>'` or
|
|
186
|
+
`--args-file <path>` passes them all as one JSON object.
|
|
187
|
+
- **Keep secrets off the command line.** A flag's value lands in your shell history. When an argument
|
|
188
|
+
is a secret - a variable's value, a secret file's contents - put the arguments in a file, or pipe
|
|
189
|
+
them: `cat vars.json | voroa set-env-vars --args-file -`.
|
|
190
|
+
- **A service** can be given by name, and can be left out in a folder you have run `voroa link` in.
|
|
191
|
+
Databases, buckets and the rest are given by id - the matching `list-...` command prints it.
|
|
192
|
+
- **Output** is a table for a simple list and JSON otherwise. `--json` is always JSON.
|
|
193
|
+
- **They need an API token**, not just a sign-in. Either set `VOROA_TOKEN`, or create one and keep it
|
|
194
|
+
on this machine:
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
voroa tokens create --name cli --scope services:read,services:act,services:write,services:admin --save
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
With `--save` the value is stored in `~/.voroa/config.json` and never printed. A token expires
|
|
201
|
+
(90 days, or 30 when it carries `services:admin`); when it does, run the same command again.
|
|
202
|
+
- **Creating or deleting a resource is proposed, not done.** `voroa propose --action create_bucket
|
|
203
|
+
--args '{...}'` raises a request that a person approves in the dashboard. Nothing irreversible
|
|
204
|
+
happens from the terminal, and no command here can move money or read a secret's value.
|
|
205
|
+
|
|
206
|
+
## Environment variables
|
|
207
|
+
|
|
208
|
+
Values are write-only: they can be set or replaced, never shown or downloaded, so there is no
|
|
209
|
+
`env pull`. A value is never taken from the command line (it would land in shell history) - pipe
|
|
210
|
+
it in: `echo "$DATABASE_URL" | voroa env set DATABASE_URL`. Replacing an existing key needs
|
|
211
|
+
`--overwrite`, because the old value is gone for good. Setting or removing a variable redeploys.
|
|
212
|
+
|
|
213
|
+
## Confirming it is you
|
|
214
|
+
|
|
215
|
+
Revealing a database password and creating an API token need a fresh confirmation on top of
|
|
216
|
+
being signed in. The CLI asks only when Voroa asks for it: your authenticator code (or a recovery
|
|
217
|
+
code with `--recovery`) if two-step verification is on, otherwise your password or an emailed
|
|
218
|
+
code. A passkey cannot be used from a terminal. `voroa login` completes two-step sign-in the same
|
|
219
|
+
way. `db connect` hands the password to psql through its environment, never the command line, and
|
|
220
|
+
prints it only with `--show-url`.
|
|
221
|
+
|
|
222
|
+
## Exit codes
|
|
223
|
+
|
|
224
|
+
| Code | Meaning |
|
|
225
|
+
|---|---|
|
|
226
|
+
| 0 | The command succeeded. With `deploy --wait`, the service is live. |
|
|
227
|
+
| 1 | The command failed - including a deploy that failed or failed to start. |
|
|
228
|
+
| 2 | `deploy --wait` ran out of time while the deploy was still going. |
|
|
229
|
+
|
|
230
|
+
Code 2 is deliberately not 0. A timeout means we stopped watching, not that the deploy
|
|
231
|
+
worked.
|
|
232
|
+
|
|
233
|
+
## Global flags
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
--workspace <id> act on this workspace for this command only
|
|
237
|
+
--api-url <url> talk to a different Voroa API
|
|
238
|
+
--json machine-readable output (services, status, workspace list)
|
|
239
|
+
--lines <n> with logs: how many lines to fetch (default 100, maximum 1000)
|
|
240
|
+
--search <text> with logs: only lines containing the text, ignoring case (last 24 hours)
|
|
241
|
+
--timeout <min> with deploy --wait: how long to wait (default 10)
|
|
242
|
+
--help, --version
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`--lines` and `--timeout` take a number. A value that is not one is refused rather than
|
|
246
|
+
quietly replaced by the default — `--timeout abc` used to wait ten minutes without saying so.
|
|
247
|
+
`--lines` above the server's maximum of 1000 is clamped to it, because that ceiling is
|
|
248
|
+
published and clamping is what it means.
|
package/package.json
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voroa-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Voroa command line interface - deploy, inspect and manage your services, databases, cron jobs and storage from the terminal.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"private": false,
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/srtayde94/voroa.git",
|
|
11
|
+
"directory": "cli"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"voroa": "src/index.js"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "node --test",
|
|
25
|
+
"prepack": "node scripts/pack-mcp.mjs",
|
|
26
|
+
"postpack": "node scripts/pack-mcp.mjs --clean"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"voroa",
|
|
30
|
+
"cli",
|
|
31
|
+
"paas",
|
|
32
|
+
"deploy",
|
|
33
|
+
"logs"
|
|
34
|
+
],
|
|
35
|
+
"homepage": "https://getvoroa.com/docs/cli",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://getvoroa.com/docs/cli",
|
|
38
|
+
"email": "support@getvoroa.com"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/agent.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// `voroa agent` - how to drive this CLI, written for an AI agent to read.
|
|
2
|
+
//
|
|
3
|
+
// A customer's coding agent (Claude Code, Cursor, anything that can run a shell command) does not need
|
|
4
|
+
// a plugin to use Voroa: it needs to know five rules and where to look things up. This prints them.
|
|
5
|
+
// The exit codes and error codes are READ from the modules that own them, not retyped, so the guide
|
|
6
|
+
// cannot describe a contract the binary does not keep (test/agent.test.js).
|
|
7
|
+
import { ERROR_CODES } from './errors.js';
|
|
8
|
+
import { EXIT_OK, EXIT_FAILED, EXIT_TIMEOUT, VERDICT_MEANINGS } from './status.js';
|
|
9
|
+
import { out, json } from './output.js';
|
|
10
|
+
|
|
11
|
+
const EXIT_CODES = {
|
|
12
|
+
[EXIT_OK]: 'Succeeded. With deploy --wait: the service is live.',
|
|
13
|
+
[EXIT_FAILED]: 'Failed. The error says why.',
|
|
14
|
+
[EXIT_TIMEOUT]: 'Still going when the wait ended (deploy --wait), or not live yet (domains verify). Not a failure and not a success - check again.',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const RULES = [
|
|
18
|
+
'Authenticate with the VOROA_TOKEN environment variable: an API token that starts with voroa_cat_. A person creates it (dashboard: Settings -> API tokens, or `voroa tokens create`). You cannot sign in yourself - `voroa login` sends a code to a person\'s email.',
|
|
19
|
+
'Add --json to every command. The result is JSON on stdout. A failure is one JSON object on stderr: {"error": "...", "code": "..."}.',
|
|
20
|
+
'Set VOROA_NO_INPUT=1 (or pass --no-input). A step that needs a person then fails at once with code NEEDS_HUMAN instead of waiting for an answer that will not come.',
|
|
21
|
+
'Read the exit code, not the text. It says whether the COMMAND worked - not whether a service is healthy: `voroa status` exits 0 for a stopped service too. For health, read the "verdict" field (table below), never the raw "status" field.',
|
|
22
|
+
'Prefer the everyday commands (services, status, logs, deploy, restart, rollback, env, domains). The `voroa tools` commands cover everything else; a few overlap (services and list-services are the same list).',
|
|
23
|
+
'To stay read-only, run only commands that `voroa tools` marks "changes: no", plus services, status and logs.',
|
|
24
|
+
'A service is named by its name or its id. Every other resource (database, bucket, task) takes an id - get it from the matching list command.',
|
|
25
|
+
'Creating or deleting a resource is a PROPOSAL: `voroa propose` returns a request a person approves in the dashboard. Tell the person; do not retry, and do not look for another way.',
|
|
26
|
+
'Never put a secret value in a command line. Pipe it: `printf %s "$VALUE" | voroa env set KEY <service>`, or pass arguments with --args-file.',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const DISCOVER = [
|
|
30
|
+
['voroa tools <word> --json', 'platform commands matching a word (bucket, backup, task...), each with its argument schema and whether it changes anything'],
|
|
31
|
+
['voroa tools --json', 'all of them (large)'],
|
|
32
|
+
['voroa <tools-command> --help', 'one of those: what it does and what it takes'],
|
|
33
|
+
['voroa --help', 'the everyday commands and their flags'],
|
|
34
|
+
['voroa agent --json', 'this guide as data'],
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const EXAMPLES = [
|
|
38
|
+
['voroa services --json', 'the services (names, ids, repository, branch)'],
|
|
39
|
+
['voroa status --all --json', 'how every service is doing: its verdict'],
|
|
40
|
+
['voroa status <service> --json', 'one service in full'],
|
|
41
|
+
['voroa deploy <service> --wait --json', 'deploy and wait; exit 0 only when live'],
|
|
42
|
+
['voroa logs <service> --lines 100 --json', 'recent output'],
|
|
43
|
+
['voroa get-deploy-history <service> --json', 'what was deployed, and how it went'],
|
|
44
|
+
['voroa rollback <service> --json', 'serve the previous version again'],
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export function agentGuide(version) {
|
|
48
|
+
return {
|
|
49
|
+
cli: 'voroa',
|
|
50
|
+
version,
|
|
51
|
+
rules: RULES,
|
|
52
|
+
exitCodes: EXIT_CODES,
|
|
53
|
+
errorCodes: ERROR_CODES,
|
|
54
|
+
verdicts: VERDICT_MEANINGS,
|
|
55
|
+
discover: DISCOVER.map(([command, what]) => ({ command, what })),
|
|
56
|
+
examples: EXAMPLES.map(([command, what]) => ({ command, what })),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const table = (rows) => {
|
|
61
|
+
const width = Math.max(...rows.map(([a]) => String(a).length));
|
|
62
|
+
return rows.map(([a, b]) => ` ${String(a).padEnd(width)} ${b}`).join('\n');
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export function agent({ flags, version }) {
|
|
66
|
+
const guide = agentGuide(version);
|
|
67
|
+
if (flags.json) {
|
|
68
|
+
json(guide);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
out(
|
|
72
|
+
[
|
|
73
|
+
`Voroa CLI ${version} - guide for an AI agent`,
|
|
74
|
+
'',
|
|
75
|
+
'Rules',
|
|
76
|
+
...RULES.map((r, i) => ` ${i + 1}. ${r}`),
|
|
77
|
+
'',
|
|
78
|
+
'Exit codes',
|
|
79
|
+
table(Object.entries(EXIT_CODES)),
|
|
80
|
+
'',
|
|
81
|
+
'Error codes (the "code" field of a --json failure)',
|
|
82
|
+
table(Object.entries(ERROR_CODES)),
|
|
83
|
+
'',
|
|
84
|
+
'A service\'s "verdict"',
|
|
85
|
+
table(Object.entries(VERDICT_MEANINGS)),
|
|
86
|
+
'',
|
|
87
|
+
'Look things up',
|
|
88
|
+
table(DISCOVER),
|
|
89
|
+
'',
|
|
90
|
+
'Examples',
|
|
91
|
+
table(EXAMPLES),
|
|
92
|
+
].join('\n')
|
|
93
|
+
);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|