@vigilbase/cli 0.2.1 → 0.2.3

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/CLOUDFLARE.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `vigilbase cf` and `vigilbase cloudflare` use the authenticated Vigilbase One API. Run `vigilbase login` first (signing in isn't supported on Windows yet). Your organization, permissions, customer links, and allowed zones determine access. The CLI never requires a Cloudflare API key.
4
4
 
5
- `cf checkup` runs on One's servers. `cloudflare-checkup` (also `local cloudflare-checkup`) runs on your machine with Cloudflare's own `cf` CLI and needs no Vigilbase login: one command, `npx @vigilbase/cli cloudflare-checkup`, verifies your work email with a code, installs cf if needed, signs in read-only, collects and uploads after you confirm. It works while vigilbase.com has local checkups switched on; otherwise it says so before asking for your email and points you to the checkup in your browser at https://vigilbase.com/tools/cloudflare-checkup (see [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/LOCAL.md)).
5
+ `cf checkup` runs on One's servers. `cloudflare-checkup` (also `local cloudflare-checkup`) runs on your machine with Cloudflare's own `cf` CLI and needs no Vigilbase login: one command, `npx @vigilbase/cli cloudflare-checkup`, verifies your work email with a code, installs cf if needed, signs in read-only, collects and uploads after you confirm. It works while vigilbase.com has local checkups switched on; otherwise it says so before asking for your email and points you to the checkup in your browser at https://vigilbase.com/tools/cloudflare-checkup (see [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/LOCAL.md)).
6
6
 
7
7
  Customer provider access requires an `active` or `trialing` Cloudflare service
8
8
  entitlement for the selected account. Historical/inactive rows and legacy account
@@ -22,13 +22,13 @@ vigilbase cf zones
22
22
  vigilbase cf workspace --json
23
23
  ```
24
24
 
25
- `--customer-id` explicitly selects a customer; it never grants access to that customer. Customer users can usually omit it when their organization identifies the customer. Internal users should select it for customer-specific operations. Analytics always requires it. Live zone detail requires it; zone detail without it uses the stored workspace inventory.
25
+ `--customer-id` explicitly selects a customer; it never grants access to that customer. Customer users can usually omit it when their organization identifies the customer. Internal users should select it for customer-specific operations: One answers accounts, workspace and checkup reads without it with HTTP 400. Analytics, DNS, WAF and speed settings always require it, for every user: One refuses these reads without it, so the CLI stops before sending them. Live zone detail requires it; zone detail without it uses the stored workspace inventory. When One answers 400 to accounts, workspace or checkup reads because the customer is missing, the CLI adds the hint `Vigilbase staff: add --customer-id <uuid>.`
26
26
 
27
27
  An account or zone positional ID can instead be supplied using `--account-id` or `--zone-id` for commands that take that kind of ID. Supplying both requires identical values. Account-resource commands reject `--zone-id`; DNS, WAF, and speed-settings reject `--account-id` because those APIs scope by zone. `--days` is accepted only for analytics.
28
28
 
29
29
  ## Command grammar
30
30
 
31
- In this table, `C` means `[--customer-id <uuid>]`, `A` means `[--account-id <hex-id>]`, and `Z` means `[--zone-id <hex-id>]`. Every command also accepts the common options above.
31
+ In this table, `C` means `[--customer-id <uuid>]`, `C!` means a required `--customer-id <uuid>`, `A` means `[--account-id <hex-id>]`, and `Z` means `[--zone-id <hex-id>]`. Every command also accepts the common options above.
32
32
 
33
33
  | Command | Selection | Result |
34
34
  | --- | --- | --- |
@@ -38,9 +38,9 @@ In this table, `C` means `[--customer-id <uuid>]`, `A` means `[--account-id <hex
38
38
  | `cf accounts` | C A | Accessible account inventory including customer and service IDs |
39
39
  | `cf account <account-id>` | C | One stored account summary |
40
40
  | `cf workspace [section]` | C A Z | Workspace bootstrap or section data |
41
- | `cf dns <zone-id>` | C | DNS record IDs, types, names, contents, TTL and proxy state |
42
- | `cf waf <zone-id>` | C | Rules, expressions, analytics availability and suggestions |
43
- | `cf speed-settings <zone-id>` | C | Current performance settings; internal access required |
41
+ | `cf dns <zone-id>` | C! | DNS record IDs, types, names, contents, TTL and proxy state |
42
+ | `cf waf <zone-id>` | C! | Rules, expressions, analytics availability and suggestions |
43
+ | `cf speed-settings <zone-id>` | C! | Current performance settings; internal access required |
44
44
  | `cf audit-logs <account-id>` | C | Most recent provider audit events, up to 100 |
45
45
  | `cf zero-trust <account-id>` | C | Users, Access applications, tunnels and authentication analytics |
46
46
  | `cf developer-platform <account-id>` | C | Workers, Workers analytics and Pages projects |
@@ -64,8 +64,8 @@ Replace example IDs with IDs from your account inventory:
64
64
  ```bash
65
65
  vigilbase cf account bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
66
66
  vigilbase cf zone aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --customer-id cb156546-b6ba-42a9-bdd0-4a09cb156546
67
- vigilbase cf dns aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --json
68
- vigilbase cf waf aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
67
+ vigilbase cf dns aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --customer-id cb156546-b6ba-42a9-bdd0-4a09cb156546 --json
68
+ vigilbase cf waf aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --customer-id cb156546-b6ba-42a9-bdd0-4a09cb156546
69
69
  vigilbase cf zero-trust bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb --json
70
70
  vigilbase cf developer-platform bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
71
71
  vigilbase cf magic-transit bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
package/COMMANDS.md CHANGED
@@ -2,18 +2,19 @@
2
2
 
3
3
  The CLI uses public scanner APIs on `vigilbase.com` and authenticated APIs on
4
4
  `one.vigilbase.com`. Use `vigilbase <command> --help` or
5
- `vigilbase help <command>` for built-in help. Examples below omit `--json`,
6
- which every command supports.
5
+ `vigilbase help <command>` for built-in help, and `vigilbase help <tool>` (for
6
+ example `vigilbase help website-security`) for how to run a tool. Examples
7
+ below omit `--json`, which every command supports.
7
8
 
8
9
  ## References
9
10
 
10
11
  | Area | Complete command and API reference |
11
12
  | --- | --- |
12
- | Cloudflare | [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/CLOUDFLARE.md) |
13
- | Security | [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/SECURITY.md) |
14
- | Customers, organizations, monitoring, support | [ONE.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/ONE.md) |
15
- | Local Cloudflare Checkup (cf on your machine) | [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/LOCAL.md) |
16
- | Sign-in, credentials, configuration, troubleshooting | [README.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/README.md) |
13
+ | Cloudflare | [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/CLOUDFLARE.md) |
14
+ | Security | [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/SECURITY.md) |
15
+ | Customers, organizations, monitoring, support | [ONE.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/ONE.md) |
16
+ | Local Cloudflare Checkup (cf on your machine) | [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/LOCAL.md) |
17
+ | Sign-in, credentials, configuration, troubleshooting | [README.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/README.md) |
17
18
 
18
19
  The references list the supported operations, filters, response and pagination
19
20
  behaviour, API endpoints and access requirements of the CLI.
@@ -36,8 +37,13 @@ fragments. One requires HTTPS, except HTTP for loopback development.
36
37
  `--customer-id` is a command-specific One customer UUID; it does not change the
37
38
  session's permissions. API reads may still return 403 when the signed-in role
38
39
  lacks access. Unknown flags, flags a command doesn't take (including scope
39
- flags) and extra arguments fail before any API request. `--style` applies only
40
- to `badge`.
40
+ flags), missing arguments and extra arguments fail before any API request. A
41
+ missing argument is named with the command's usage, for example
42
+ `Missing <url>. Usage: vigilbase headers <url>` or
43
+ `Missing <customer-id>. Usage: vigilbase customers summary <customer-id>`.
44
+ `cf dns`, `cf waf` and `cf speed-settings` require `--customer-id` before
45
+ they send a request, because One refuses these reads without it. `--style`
46
+ applies only to `badge`.
41
47
 
42
48
  ## Authentication
43
49
 
@@ -52,7 +58,7 @@ issuer's `/.well-known/openid-configuration` (for production,
52
58
  | `login --token <bearer>` | Older input, discouraged because arguments can appear in process lists and history. `VIGILBASE_ONE_TOKEN` also works; neither combines with `--token-stdin` | Same as `--token-stdin` |
53
59
  | `whoami` | Shows the saved session; signed out is a successful answer. Notes a CLI 0.2.0 `credentials.json` that is being ignored | Identity: discovery and userinfo (a refresh first if due). Legacy: One `GET /api/auth/get-session` |
54
60
  | `logout` | Revokes every saved Identity sign-in, signs a legacy session out, then deletes the credential files. A sign-in Identity has already ended counts as revoked; any other failed Identity revocation keeps every file | Identity: discovery, then `POST /api/auth/oauth2/revoke` per saved sign-in. Legacy: One `POST /api/auth/sign-out` (best effort) |
55
- | `doctor` | Checks the public API, your session and your saved sign-in independently; exits 1 if any check fails | `GET {base-url}/api/agent/tools`. Signed out or legacy: One `GET /api/auth/get-session`. Identity: `GET {issuer}/.well-known/openid-configuration`, then the userinfo endpoint it names (One is not contacted); a refresh at the token endpoint first if the access token expires within 60 seconds |
61
+ | `doctor` | Checks the public API, your session and your saved sign-in independently; exits 1 if any check fails | `GET {base-url}/api/v1/agent/tools`. Signed out or legacy: One `GET /api/auth/get-session`. Identity: `GET {issuer}/.well-known/openid-configuration`, then the userinfo endpoint it names (One is not contacted); a refresh at the token endpoint first if the access token expires within 60 seconds |
56
62
 
57
63
  Credentials are saved atomically with owner-only permissions in
58
64
  `identity-credentials.json` (Identity) or `credentials.json` (legacy One
@@ -70,12 +76,28 @@ checked: One's `get-session`, the discovered userinfo endpoint, or the
70
76
  issuer's discovery URL when discovery itself failed. `checks.signIn` has no
71
77
  `url`.
72
78
 
79
+ `whoami` JSON has `authenticated`, `oneBaseUrl`, `user`, `issuer`,
80
+ `clientId`, `resource`, `organizationId`, `expiresAt`, `scope`, `obtainedAt`,
81
+ `authRequiredTools` and `legacyIdentityFileIgnored`. `expiresAt` and `scope`
82
+ are those of the access token in use, after any refresh `whoami` just made.
83
+ `obtainedAt` is when you signed in; a refresh doesn't change it. Signed out,
84
+ `expiresAt`, `scope` and `obtainedAt` are `null`.
85
+
86
+ `authRequiredTools` means something different per command. The names stay as
87
+ they are so scripts keep working:
88
+
89
+ | Command | `authRequiredTools` in JSON |
90
+ | --- | --- |
91
+ | `list`, `doctor` | Every tool that needs a One sign-in, whether you are signed in or not. In `list`, `oneExecutableTools` is what you can run through One now |
92
+ | `whoami` | The tools your sign-in unlocks: the same tools when signed in, `[]` when signed out |
93
+ | `login` | Every tool that needs a One sign-in; all of them are unlocked once login succeeds |
94
+
73
95
  ## Public scanners and authenticated scans
74
96
 
75
97
  | Command | Options | API |
76
98
  | --- | --- | --- |
77
- | `list` (alias `tools`) | Lists the public catalog and the One-only scanners | GET `/api/agent/tools` |
78
- | `run <tool> <target>` | `--via public\|one`; `--public` forces the public API | POST `/api/agent/tools/<tool>/execute` (anonymous) or One POST `/api/tools/<tool>/execute` |
99
+ | `list` (alias `tools`) | Lists the public catalog and the One-only scanners | GET `/api/v1/agent/tools` |
100
+ | `run <tool> <target>` | `--via public\|one`; `--public` forces the public API | POST `/api/v1/agent/tools/<tool>/execute` (anonymous) or One POST `/api/tools/<tool>/execute` |
79
101
  | `headers <url>` | Shortcut for `run security-headers`; same routing options | Same as `run` |
80
102
  | `email <domain>` | Shortcut for `run email-security`; same routing options | Same as `run` |
81
103
  | `describe <tool>` | `--no-skill` skips fetching skill Markdown | Catalog plus the tool's published skill URL |
@@ -83,10 +105,16 @@ issuer's discovery URL when discovery itself failed. `checks.signIn` has no
83
105
  | `badge <domain>` | `--style default\|compact\|mini` | None; builds the public badge URL locally |
84
106
 
85
107
  Public tools: `security-headers`, `email-security`. One-only tools:
86
- `website-security`, `react2shell`, `fortibleed-check`. Public scans use the
108
+ `website-security`, `react2shell`, `fortibleed-check`. Tools aren't commands of
109
+ their own: run them with `run <tool> <target>` (`vigilbase help <tool>` prints
110
+ that usage offline). Public scans use the
87
111
  public API unless you add `--via one`; being signed in doesn't change that.
88
112
  `--public` and `--via one` cannot be combined.
89
113
 
114
+ Public paths are relative to `--base-url`. CLI 0.2.1 and earlier call the
115
+ unversioned `/api/agent/tools` instead, which vigilbase.com plans to retire on
116
+ 1 September 2027.
117
+
90
118
  The public route is anonymous and never reads your saved sign-in, the
91
119
  credentials lock or Identity, so sign-in problems cannot make it fail. Runs
92
120
  that go through One (`--via one` and the One-only tools) need a sign-in.
@@ -113,7 +141,19 @@ credentials file is there.
113
141
  When a public scan fails and vigilbase.com explains why with a known error
114
142
  code, the CLI prints `Error: <message> (<code>)` (JSON: `error`, `code`,
115
143
  `status`), with the message cleaned to one line of at most 300 characters.
116
- Otherwise it prints `Request failed (HTTP <status>).`
144
+ Otherwise it prints a message of its own, never the server's text.
145
+
146
+ When a scan run through Vigilbase One fails (One answers 422), the CLI prints
147
+ `Error: The scan couldn't be completed. Try again later.` and exits 1. JSON
148
+ has `success: false`, that `error`, `status: 422` and the `toolRunId` One
149
+ recorded, for `vigilbase runs get <toolRunId>`.
150
+
151
+ When the scanner ran but couldn't assess the target, for example because the
152
+ site answered with a bot verification challenge or an error page, the CLI
153
+ prints `✗ <tool> · <target> · n/a` and the scanner's reason on the next line,
154
+ cleaned to one line of at most 300 characters, and exits 1. JSON has
155
+ `success: false`, that reason as `error`, `grade: null`, the scanner's
156
+ `result`, `status: 422`, `code: "scan_unassessed"` and the `toolRunId`.
117
157
 
118
158
  ## Account and billing
119
159
 
@@ -130,6 +170,8 @@ Otherwise it prints `Request failed (HTTP <status>).`
130
170
  | `billing` | `summary`, `show`, `status` | GET `/api/account/billing` |
131
171
  | `billing portal` | `open`; `--no-open` prints the portal URL without opening a browser | POST `/api/billing/portal` |
132
172
 
173
+ Invitations need a One browser session: Identity's management API doesn't accept CLI sign-ins, so `account invites` and `account invites create` answer 403 (`browser_session_required`): the CLI prints `You don't have access to this.` and points you to https://one.vigilbase.com.
174
+
133
175
  Creating an invitation sends it; `billing portal` starts a Stripe portal
134
176
  session. Both are explicit actions. Billing data comes from One's Stripe
135
177
  integration; the CLI does not store invoices or payment information.
@@ -196,10 +238,30 @@ the uploaded data and the error codes.
196
238
 
197
239
  Exit codes: **0** success, **1** validation, API, network or sign-in failure,
198
240
  **2** HTTP 429 rate limiting. A completed scan whose result is unsuccessful
199
- also exits 1. A signed-out `whoami` is not a failure, and a healthy `doctor`
241
+ also exits 1. So does a scan the scanner could not grade (result `status`
242
+ `"error"`, no grade): it prints `✗ <tool> · <target> · n/a` and the scanner's
243
+ message, cleaned to one line of at most 300 characters, and JSON has
244
+ `success: false` with that message as `error`. A signed-out `whoami` is not a
245
+ failure, and a healthy `doctor`
200
246
  does not need a sign-in. API error JSON keeps the status, code and retry delay
201
247
  when available.
202
248
 
249
+ Vigilbase One's error messages are never shown, because they can describe
250
+ One's configuration. The CLI prints its own message for the status instead:
251
+ ``Authentication required. Run `vigilbase login`.`` (401),
252
+ `You don't have access to this.` (403), `Rate limit exceeded.` (429) and
253
+ `Request failed (HTTP <status>).` otherwise. When it recognises the failure
254
+ from the route, the status and One's error code, it adds a hint of its own
255
+ (`Hint: …` in text, `hint` in JSON):
256
+
257
+ | One answers | Hint |
258
+ | --- | --- |
259
+ | 400 without `--customer-id` to `support tickets`, or to a `cf` command that reads the Cloudflare workspace or checkups (`cf accounts`, `cf account`, `cf workspace`, `cf zones` with filters, `cf checkup`, `cf checkup start`) | `Vigilbase staff: add --customer-id <uuid>.` |
260
+ | 403 to `security settings …` or `security notifications preferences` with `--customer-id` | `Personal settings belong to each user, so View-as (--customer-id) cannot read them.` |
261
+
262
+ A security command that needs a customer (`FLAREHAWK_VIEW_AS_REQUIRED`) says
263
+ `Select a customer with --customer-id <customer UUID> for security commands.`
264
+
203
265
  Security and customer operations keep JSON response envelopes and pagination
204
266
  fields. Cloudflare inventory commands may apply the account or zone filter you
205
267
  asked for locally as well as sending it to One; zone detail returns the
package/LOCAL.md CHANGED
@@ -15,7 +15,7 @@ before it asks for your email; when local mode is off it stops with
15
15
  your browser at <https://vigilbase.com/tools/cloudflare-checkup>.
16
16
 
17
17
  `vigilbase cf checkup` runs on Vigilbase One's servers with stored credentials
18
- (see [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/CLOUDFLARE.md));
18
+ (see [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/CLOUDFLARE.md));
19
19
  `vigilbase cloudflare-checkup` runs on your machine and needs no Vigilbase
20
20
  login.
21
21
 
@@ -31,7 +31,10 @@ npx @vigilbase/cli cloudflare-checkup
31
31
  If it answers `Unknown command "cloudflare-checkup"`, an older global install
32
32
  of the CLI (0.1.x) is running instead: `npx` prefers an installed global
33
33
  `@vigilbase/cli`. Run `npx @vigilbase/cli@latest cloudflare-checkup` once, or
34
- update the global install with `npm install -g @vigilbase/cli@latest`.
34
+ update the global install with `npm install -g @vigilbase/cli@latest`. With
35
+ Yarn 4.15+ or pnpm 11+, `yarn dlx` and `pnpm dlx` run an older release for a
36
+ day after each release; use `npx` (see
37
+ [Troubleshooting](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/README.md#troubleshooting)).
35
38
 
36
39
  The command does everything, in this order, and stops at the first problem
37
40
  before any slower step:
@@ -674,7 +677,7 @@ are never echoed.
674
677
  | `ACCOUNT_TOO_LARGE` | Over 100 zones: run the checkup in your browser instead, https://vigilbase.com/tools/cloudflare-checkup. |
675
678
  | `ACCOUNT_MISMATCH` | The checkup is bound to another account; run the same command again without `--account-id`. |
676
679
  | `OUTPUT_EXISTS` | Choose another `--out`, or pass `--overwrite`. |
677
- | `SNAPSHOT_INVALID` / `SNAPSHOT_SECRET_LIKE_VALUE` | Run the same command again (remove the credential-like text from the rule or name first). |
680
+ | `SNAPSHOT_INVALID` / `SNAPSHOT_SECRET_LIKE_VALUE` | Run the same command again (remove the credential-like text from the rule or name first). When `inspect` or `submit` finds no file at the path, check the path, or collect one with `npx @vigilbase/cli cloudflare-checkup collect --out <file>`. |
678
681
  | `SNAPSHOT_TOO_LARGE` | Run the checkup in your browser instead, https://vigilbase.com/tools/cloudflare-checkup. |
679
682
  | `SNAPSHOT_STALE` | Snapshots are accepted for 24 hours; run the same command again. |
680
683
  | `EMAIL_INVALID` | Use your work email (personal and disposable addresses are refused), then run the same command again. |
package/ONE.md CHANGED
@@ -12,6 +12,7 @@ vigilbase monitoring status CUSTOMER_UUID --light
12
12
  vigilbase monitoring history CUSTOMER_UUID --range 7d --region ams
13
13
  vigilbase orgs members
14
14
  vigilbase support tickets --all --limit 100
15
+ vigilbase support tickets --customer-id CUSTOMER_UUID
15
16
  ```
16
17
 
17
18
  Replace uppercase placeholders with IDs from the corresponding list. Customer, report, Vigil investigation, and monitoring target IDs must be UUIDs. Organization IDs may contain letters, digits, underscores, and hyphens (maximum 256 characters).
@@ -87,11 +88,11 @@ A successful health response may describe an unconfigured backend or unknown pro
87
88
  ## Support
88
89
 
89
90
  ```sh
90
- vigilbase support tickets [--all] [--limit 1..100] [--json]
91
+ vigilbase support tickets [--all] [--limit 1..100] [--customer-id <uuid>] [--json]
91
92
  ```
92
93
 
93
- `vigilbase support` also defaults to `tickets`. Maps to GET `/api/support/tickets?includeAll=true&limit=N`; omitted flags omit their query parameters. Requires `support:access`. The API identifies the current organization and its Pylon account. Open tickets are returned by default; `--all` includes closed tickets. Limit defaults to 50. An unlinked account returns an empty list with the API's explanation. `hasMore` is preserved, but this API exposes no cursor pagination. The API may rate-limit requests or return 503 when Pylon is unavailable.
94
+ `vigilbase support` also defaults to `tickets`. Maps to GET `/api/support/tickets?includeAll=true&limit=N&customerId=UUID`; omitted flags omit their query parameters. Requires `support:access`. Without `--customer-id`, the API uses the current organization's customer and its Pylon account. Vigilbase staff must choose the customer with `--customer-id <uuid>` (a UUID from `vigilbase customers list`); One checks your access to it. Without it, One answers HTTP 400 and the CLI prints `Request failed (HTTP 400).` with the hint `Vigilbase staff: add --customer-id <uuid>.` Open tickets are returned by default; `--all` includes closed tickets. Limit defaults to 50. An account with no customer or no Pylon link returns an empty list with the API's explanation. `hasMore` is preserved, but this API exposes no cursor pagination. The API may rate-limit requests or return 503 when Pylon is unavailable.
94
95
 
95
96
  ## Related commands and validation
96
97
 
97
- See [README.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/README.md) for sign-in and configuration, [COMMANDS.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/COMMANDS.md) for account, billing, public scanners, run history and Watchdog, [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/CLOUDFLARE.md) for `cf`/`cloudflare`, and [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/SECURITY.md) for security commands. The read operations above do not replace the existing explicitly confirmed write commands.
98
+ See [README.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/README.md) for sign-in and configuration, [COMMANDS.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/COMMANDS.md) for account, billing, public scanners, run history and Watchdog, [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/CLOUDFLARE.md) for `cf`/`cloudflare`, and [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/SECURITY.md) for security commands. The read operations above do not replace the existing explicitly confirmed write commands.
package/README.md CHANGED
@@ -28,14 +28,14 @@ supported on Windows yet; public tools and `cloudflare-checkup` still work there
28
28
 
29
29
  | Reference | Covers |
30
30
  | --- | --- |
31
- | [COMMANDS.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/COMMANDS.md) | Core commands, aliases, global options, API mapping, sign-in, output |
32
- | [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/CLOUDFLARE.md) | Accounts, zones, DNS, WAF, analytics, Zero Trust, Workers/Pages, audit, checkups |
33
- | [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/SECURITY.md) | Incidents, logs, intelligence, analytics, assets, connections, policies, notifications, reports |
34
- | [ONE.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/ONE.md) | Customer records, billing, reports, investigations, organizations, monitoring, support |
35
- | [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/LOCAL.md) | `cloudflare-checkup`: verifies your work email, collects your Cloudflare configuration on your machine with Cloudflare's `cf` and uploads it after you confirm |
31
+ | [COMMANDS.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/COMMANDS.md) | Core commands, aliases, global options, API mapping, sign-in, output |
32
+ | [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/CLOUDFLARE.md) | Accounts, zones, DNS, WAF, analytics, Zero Trust, Workers/Pages, audit, checkups |
33
+ | [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/SECURITY.md) | Incidents, logs, intelligence, analytics, assets, connections, policies, notifications, reports |
34
+ | [ONE.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/ONE.md) | Customer records, billing, reports, investigations, organizations, monitoring, support |
35
+ | [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/LOCAL.md) | `cloudflare-checkup`: verifies your work email, collects your Cloudflare configuration on your machine with Cloudflare's `cf` and uploads it after you confirm |
36
36
 
37
37
  These files ship with the package. Built-in help: `vigilbase <command> --help`
38
- or `vigilbase help <command>`.
38
+ or `vigilbase help <command>`; `vigilbase help <tool>` shows how to run a tool.
39
39
 
40
40
  ## Examples
41
41
 
@@ -70,8 +70,8 @@ Cloudflare IDs come from the inventory you can access:
70
70
  ```bash
71
71
  vigilbase cf accounts
72
72
  vigilbase cf zones
73
- vigilbase cf dns <zone-id>
74
- vigilbase cf waf <zone-id> --json
73
+ vigilbase cf dns <zone-id> --customer-id <customer-uuid>
74
+ vigilbase cf waf <zone-id> --customer-id <customer-uuid> --json
75
75
  vigilbase cf zero-trust <account-id>
76
76
  vigilbase cf developer-platform <account-id>
77
77
  vigilbase cf analytics --customer-id <customer-uuid> --zone-id <zone-id> --days 7
@@ -94,8 +94,9 @@ vigilbase security audit --limit 50
94
94
  ```
95
95
 
96
96
  Customer users inherit their organization's scope. Internal operators add
97
- `--customer-id <customer-uuid>` for security views; Cloudflare analytics needs
98
- it too. Other customer-specific commands take the customer UUID as an argument.
97
+ `--customer-id <customer-uuid>` for security views and support tickets.
98
+ Everyone adds it to `cf analytics`, `cf dns`, `cf waf` and `cf speed-settings`.
99
+ Other customer-specific commands take the customer UUID as an argument.
99
100
  Flags select records; One still decides whether your session can see them.
100
101
 
101
102
  After reviewing an incident, you can update its status explicitly:
@@ -142,7 +143,7 @@ read-only Cloudflare API token instead. When you are done:
142
143
  npx @vigilbase/cli cloudflare-checkup logout # removes the read-only cf login and the cf it installed
143
144
  ```
144
145
 
145
- See [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.1/files/LOCAL.md) for
146
+ See [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.3/files/LOCAL.md) for
146
147
  every step, what is uploaded and the error codes.
147
148
 
148
149
  ## Public tools and sign-in
@@ -190,8 +191,12 @@ fails and vigilbase.com explains why, the CLI shows that reason:
190
191
  `Error: <message> (<code>)` in text, and `error` plus `code` in JSON. The
191
192
  reason is shown only when vigilbase.com sends it as a known error code, and it
192
193
  is cleaned to one line of at most 300 characters. Anything else, and every
193
- Vigilbase One error, prints only `Request failed (HTTP <status>).` without the
194
- server's text. Hints (`Hint: …`, `hint` in JSON) are always written by the CLI.
194
+ Vigilbase One error, prints a message the CLI wrote (for example
195
+ `You don't have access to this.` or `Request failed (HTTP <status>).`), never
196
+ the server's text. The exception is a One scan the scanner couldn't assess
197
+ (for example a bot verification challenge): the CLI prints the scanner's
198
+ reason, cleaned the same way. Hints (`Hint: …`, `hint` in JSON) are always written by the
199
+ CLI; COMMANDS.md lists the One errors that get one.
195
200
 
196
201
  Commands use named One APIs and One's own authorization. They never take
197
202
  Cloudflare or other provider secrets, delegated identity claims or an arbitrary
@@ -246,14 +251,14 @@ that passes the [directory checks](#directory-checks) but can't be parsed.
246
251
  ### Using CLI 0.1.x or 0.2.0 too
247
252
 
248
253
  - CLI 0.2.0 kept its Identity sign-in in `credentials.json`, which CLI 0.1.x
249
- cannot read. The first 0.2.1 command that reads your sign-in moves it to
250
- `identity-credentials.json` (under the lock), unless that file already
251
- exists. From then on `credentials.json` is either absent or a legacy session
252
- that 0.1.x can use.
254
+ cannot read. The first command of 0.2.1 or later that reads your sign-in
255
+ moves it to `identity-credentials.json` (under the lock), unless that file
256
+ already exists. From then on `credentials.json` is either absent or a legacy
257
+ session that 0.1.x can use.
253
258
  - If 0.2.0 later saves a new `credentials.json` while
254
- `identity-credentials.json` exists, 0.2.1 ignores it. `whoami` notes it
255
- (`legacyIdentityFileIgnored` in JSON), and `vigilbase logout` revokes and
256
- removes it.
259
+ `identity-credentials.json` exists, 0.2.1 and later ignore it. `whoami`
260
+ notes it (`legacyIdentityFileIgnored` in JSON), and `vigilbase logout`
261
+ revokes and removes it.
257
262
  - An Identity login leaves a legacy `credentials.json` alone. A token login or
258
263
  a legacy device login first revokes and removes any Identity sign-in, so the
259
264
  new session is the one in use; if that revocation fails, login stops and
@@ -390,7 +395,7 @@ to 8 MiB; timeouts cover reading the body.
390
395
  **Check connectivity.** `vigilbase doctor` (add `--json` for details) runs
391
396
  three checks on their own and exits 1 if any fails:
392
397
 
393
- - `publicApi`: `GET https://vigilbase.com/api/agent/tools`.
398
+ - `publicApi`: `GET https://vigilbase.com/api/v1/agent/tools`.
394
399
  - `one`: your session. Signed out or with a legacy session,
395
400
  `GET https://one.vigilbase.com/api/auth/get-session`; a signed-out answer
396
401
  counts as reachable. With an Identity sign-in, the issuer's
@@ -409,6 +414,14 @@ takes priority over a bare `npx @vigilbase/cli`. Update it with
409
414
  `npx @vigilbase/cli@latest cloudflare-checkup`. `vigilbase --version` shows
410
415
  which version answers.
411
416
 
417
+ **`yarn dlx` or `pnpm dlx` runs an older version.** Yarn 4.15 and later and
418
+ pnpm 11 and later skip releases published in the last 24 hours by default
419
+ (Yarn's `npmMinimalAgeGate`, pnpm's `minimumReleaseAge`). For a day after a
420
+ release, `yarn dlx @vigilbase/cli` and `pnpm dlx @vigilbase/cli` run an
421
+ older release, and Yarn refuses the new version by number
422
+ (`All versions satisfying "…" are quarantined`). Use `npx @vigilbase/cli`, or
423
+ wait a day.
424
+
412
425
  **`Device sign-in isn't available at <origin> right now.`** Login got a 404
413
426
  from that origin. If you set `--one-url` or `--auth-url`, check it; otherwise
414
427
  try again later or email help@vigilbase.com. Public tools work without signing
package/SECURITY.md CHANGED
@@ -40,7 +40,7 @@ Logs require `--start` and `--end` together as ISO timestamps with an explicit t
40
40
  | `assets datasets <asset>` | None | `/fabric/assets/<asset>/datasets` |
41
41
  | `assets graph <asset>` | `--dataset`, `--hours`, `--min-weight`, `--limit` | `/fabric/assets/<asset>/graph` |
42
42
  | `fabric default-asset` | None | `/fabric/default-asset` |
43
- | `detections` | `--asset-id` | `/detections?asset_id=…` when scoped |
43
+ | `detections --asset-id <asset>` | None | `/detections?asset_id=<asset>` |
44
44
  | `providers` | None | `/providers?connectable=false` |
45
45
  | `connections [list]` | None | `/connections` |
46
46
  | `connections show <connection>` | None | `/connections/<connection>` |
@@ -49,6 +49,8 @@ Logs require `--start` and `--end` together as ISO timestamps with an explicit t
49
49
  | `connections logpush-status <connection> <job>` | None | `/connections/<connection>/logpush-jobs/<job>/status` |
50
50
  | `connections worker-stats <connection> <job>` | None | `/connections/<connection>/worker-routes/<job>/stats` |
51
51
 
52
+ Detections are configured per asset, and the API has no list for the whole tenant, so `--asset-id` is required; without it the CLI stops before any request. Take asset IDs from `security assets`.
53
+
52
54
  Graph `--hours` maps to `window_hours`; `--min-weight` maps to `min_weight`. Incident graphs use the incident window and reject `--hours`. IP lists retain enforcement verification and synchronization status. Connection health includes stored state, provider status, receipt health, and available warnings. Credential-bearing HEC profile retrieval is outside this command set.
53
55
 
54
56
  ## Analytics and Cloudflare security
@@ -97,7 +99,7 @@ Provider events map `--provider` to `provider_id`, `--dataset` to `dataset_id`,
97
99
  | `settings broadcast-emails` | None | `/settings/broadcast-emails` |
98
100
  | `settings applications` | None | `/integrations/grants` |
99
101
 
100
- Intel lookup input is trimmed and limited to 512 characters; the server validates the indicator and applies lookup quota. Personal settings show existing preferences and authorized application grants. They do not change preferences or revoke grants. Reports are fetched on demand; this CLI does not persist report or billing records.
102
+ Intel lookup input is trimmed and limited to 512 characters; the server validates the indicator and applies lookup quota. Personal settings show existing preferences and authorized application grants. They do not change preferences or revoke grants. Personal settings and `notifications preferences` belong to each user: with `--customer-id` (View-as), a refusal prints `You don't have access to this.` with the hint `Personal settings belong to each user, so View-as (--customer-id) cannot read them.` Reports are fetched on demand; this CLI does not persist report or billing records.
101
103
 
102
104
  ## Limits and pagination
103
105
 
@@ -14,10 +14,13 @@ export declare class DeviceAuthError extends Error {
14
14
  readonly code?: string;
15
15
  readonly status: number;
16
16
  readonly body: unknown;
17
+ /** The message is the CLI's own text, never the server's (see VigilbaseApiError). */
18
+ readonly isCliAuthored: boolean;
17
19
  constructor(message: string, options: {
18
20
  status: number;
19
21
  code?: string;
20
22
  body?: unknown;
23
+ isCliAuthored?: boolean;
21
24
  });
22
25
  }
23
26
  export declare function requestDeviceCode(config: CliConfig, options?: {
@@ -8,12 +8,15 @@ export class DeviceAuthError extends Error {
8
8
  code;
9
9
  status;
10
10
  body;
11
+ /** The message is the CLI's own text, never the server's (see VigilbaseApiError). */
12
+ isCliAuthored;
11
13
  constructor(message, options) {
12
14
  super(message);
13
15
  this.name = 'DeviceAuthError';
14
16
  this.status = options.status;
15
17
  this.code = options.code;
16
18
  this.body = options.body;
19
+ this.isCliAuthored = options.isCliAuthored ?? false;
17
20
  }
18
21
  }
19
22
  function authBase(config) {
@@ -139,7 +142,7 @@ export async function pollDeviceToken(config, deviceCode) {
139
142
  },
140
143
  };
141
144
  }
142
- throw new DeviceAuthError(`Device token request failed (HTTP ${status})`, { status, code, body: errorBody });
145
+ throw new DeviceAuthError(`Device token request failed (HTTP ${status})`, { status, code, body: errorBody, isCliAuthored: true });
143
146
  }
144
147
  export async function sleep(ms, signal) {
145
148
  await new Promise((resolve, reject) => {
@@ -198,14 +201,19 @@ export async function waitForDeviceAuthorization(config, device, options) {
198
201
  consecutiveTransient += 1;
199
202
  lastTransientStatus = result.httpStatus;
200
203
  if (consecutiveTransient >= maxTransient) {
204
+ // After an HTTP error the description is the server's, so only a network failure's
205
+ // own (CLI-authored) description joins the message.
206
+ const detail = (!lastTransientStatus && result.error.error_description) ||
207
+ 'Retry `vigilbase login` once One is healthy.';
201
208
  throw new DeviceAuthError(`Lost contact with device authorization on ${config.oneBaseUrl} while waiting for approval` +
202
209
  (lastTransientStatus
203
210
  ? ` (HTTP ${lastTransientStatus})`
204
211
  : '') +
205
- `. ${result.error.error_description ?? 'Retry `vigilbase login` once One is healthy.'}`, {
212
+ `. ${detail}`, {
206
213
  status: lastTransientStatus,
207
214
  code: 'unreachable',
208
215
  body: result.error,
216
+ isCliAuthored: true,
209
217
  });
210
218
  }
211
219
  break;
@@ -214,9 +222,10 @@ export async function waitForDeviceAuthorization(config, device, options) {
214
222
  status: 403,
215
223
  code: 'access_denied',
216
224
  body: result.error,
225
+ isCliAuthored: true,
217
226
  });
218
227
  case 'expired':
219
- throw new DeviceAuthError('The device code expired. Run `vigilbase login` again.', { status: 400, code: 'expired_token', body: result.error });
228
+ throw new DeviceAuthError('The device code expired. Run `vigilbase login` again.', { status: 400, code: 'expired_token', body: result.error, isCliAuthored: true });
220
229
  default: {
221
230
  const _exhaustive = result;
222
231
  throw new DeviceAuthError(`Unexpected poll result: ${JSON.stringify(_exhaustive)}`, {
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { VigilbaseApiError, VigilbaseClient } from './lib/client.js';
4
4
  import { createConfig, createLocalCommandConfig } from './lib/config.js';
5
5
  import { renderBanner, shouldShowBanner } from './lib/banner.js';
6
6
  import { createWriter, formatError } from './lib/format.js';
7
- import { HELP_TAGLINE, HELP_TEXT, helpForCommand } from './lib/help.js';
7
+ import { HELP_TAGLINE, HELP_TEXT, HELP_USAGE, helpForCommand, isCatalogTool } from './lib/help.js';
8
8
  import { wasRendered } from './lib/tui.js';
9
9
  import { getCommandHandler } from './commands/index.js';
10
10
  import { LocalCheckupError } from './local/cloudflare-checkup/errors.js';
@@ -183,7 +183,7 @@ export async function runCli(options = {}) {
183
183
  if (parsed.values.isVersion && parsed.positionals.length)
184
184
  throw new Error('Usage: vigilbase --version');
185
185
  if (parsed.positionals[0] === 'help' && parsed.positionals.length > 2)
186
- throw new Error('Usage: vigilbase help [command]');
186
+ throw new Error(HELP_USAGE);
187
187
  }
188
188
  if (parsed.values.isVersion) {
189
189
  if (mode === 'json') {
@@ -243,7 +243,10 @@ export async function runCli(options = {}) {
243
243
  const publicClient = new VigilbaseClient(config);
244
244
  const handler = getCommandHandler(command);
245
245
  if (!handler) {
246
- throw new Error(`Unknown command "${command}". Run \`vigilbase help\` for usage.`);
246
+ // Tools are not commands of their own (no aliases): point to how they run.
247
+ throw new Error(isCatalogTool(command)
248
+ ? `Unknown command "${command}". Run the tool with \`vigilbase run ${command} <target>\`.`
249
+ : `Unknown command "${command}". Run \`vigilbase help\` for usage.`);
247
250
  }
248
251
  return await handler({
249
252
  command,
@@ -18,7 +18,7 @@ export const handleAccount = async (ctx) => {
18
18
  else if (action === 'create' || action === 'add') {
19
19
  if (ctx.values.email !== undefined && ctx.rest[2] !== undefined)
20
20
  throw new Error('Specify the invite email either positionally or with --email, not both.');
21
- validateArguments(ctx, ctx.values.email === undefined ? 3 : 2, ['email', 'role', 'isConfirm']);
21
+ validateArguments(ctx, ctx.values.email === undefined ? 3 : 2, ['email', 'role', 'isConfirm'], 'vigilbase account invites create <email> --confirm');
22
22
  invitation = invitationSchema.parse({ email: ctx.values.email ?? ctx.rest[2], role: ctx.values.role });
23
23
  if (!ctx.values.isConfirm)
24
24
  throw new Error('Sending an organization invitation requires --confirm.');
@@ -218,7 +218,6 @@ export const handleWhoami = async (ctx) => {
218
218
  if (ctx.rest.length)
219
219
  throw new Error('Usage: vigilbase whoami');
220
220
  assertCommandFlags(ctx, []);
221
- const credentials = await readCredentials(ctx.config);
222
221
  const legacyIdentityFileIgnored = await hasIgnoredIdentityCredentials(ctx.config);
223
222
  const accessToken = await getOneAccessToken(ctx.config);
224
223
  let liveUser = null;
@@ -242,6 +241,8 @@ export const handleWhoami = async (ctx) => {
242
241
  }
243
242
  }
244
243
  const signedIn = Boolean(liveUser);
244
+ // Read after the token and session calls: either may have refreshed the sign-in, which saves a new expiry and scope.
245
+ const credentials = await readCredentials(ctx.config);
245
246
  const payload = {
246
247
  authenticated: signedIn,
247
248
  oneBaseUrl: ctx.config.oneBaseUrl,
@@ -1,3 +1,3 @@
1
1
  import { type CommandHandler } from './helpers.js';
2
- export declare const CLOUDFLARE_HELP = "Usage: vigilbase cf <command> [options]\nAlias: vigilbase cloudflare\n\nInventory and workspace:\n zones List zones (default); --customer-id, --account-id, --zone-id\n zone <zone-id> Zone detail; --customer-id selects live details, optional --account-id\n accounts List accessible accounts; --customer-id, --account-id\n account <account-id> Stored account detail; --customer-id\n workspace [section] Workspace bootstrap or section; --customer-id, --account-id, --zone-id\n Sections: overview, reports, zones, rule-analyzer, accounts, checkups, settings\n\nZone reads (optional --customer-id; IDs can use --zone-id):\n dns <zone-id> DNS records, TTL and proxy state\n waf <zone-id> WAF rules, expressions, analytics and suggestions\n speed-settings <zone-id> Performance settings (internal users only)\n\nAccount reads (optional --customer-id; IDs can use --account-id):\n audit-logs <account-id> Latest provider audit events (up to 100; service-read permission)\n zero-trust <account-id> Users, Access applications, tunnels and authentication analytics\n developer-platform <account-id>\n Workers, Workers analytics and Pages\n magic-transit <account-id> Prefixes, routes and traffic analytics\n Zero Trust, Developer Platform and Magic Transit require deployment-read permission.\n\nAnalytics and checkups:\n analytics --customer-id <uuid> [--account-id <id> | --zone-id <id>] [--days 1..30]\n Default 7 days; live zone analytics uses the most recent 23 hours.\n checkup [status] Latest completed checkup; --customer-id, --account-id\n checkup start Start and persist a scan; --customer-id, --account-id\n checkup progress <run-uuid> Read saved progress once\n checkup result <run-uuid> Read the stored Cloudflare checkup result\n checkups aliases checkup; list/show alias status; run aliases start.\n\nCommon options: --json, --one-url <origin>, --timeout <milliseconds>, --help\nCustomer IDs are UUIDs; account and zone IDs are 32 hexadecimal characters.\nOne login, tenant bindings and permissions apply to every command.\nCheckup start creates a scan run. These commands do not edit provider configuration.\nSee CLOUDFLARE.md for full grammar, API mapping, data limits and examples.";
2
+ export declare const CLOUDFLARE_HELP = "Usage: vigilbase cf <command> [options]\nAlias: vigilbase cloudflare\n\nInventory and workspace:\n zones List zones (default); --customer-id, --account-id, --zone-id\n zone <zone-id> Zone detail; --customer-id selects live details, optional --account-id\n accounts List accessible accounts; --customer-id, --account-id\n account <account-id> Stored account detail; --customer-id\n workspace [section] Workspace bootstrap or section; --customer-id, --account-id, --zone-id\n Sections: overview, reports, zones, rule-analyzer, accounts, checkups, settings\n\nZone reads (--customer-id <uuid> required; IDs can use --zone-id):\n dns <zone-id> DNS records, TTL and proxy state\n waf <zone-id> WAF rules, expressions, analytics and suggestions\n speed-settings <zone-id> Performance settings (internal users only)\n\nAccount reads (optional --customer-id; IDs can use --account-id):\n audit-logs <account-id> Latest provider audit events (up to 100; service-read permission)\n zero-trust <account-id> Users, Access applications, tunnels and authentication analytics\n developer-platform <account-id>\n Workers, Workers analytics and Pages\n magic-transit <account-id> Prefixes, routes and traffic analytics\n Zero Trust, Developer Platform and Magic Transit require deployment-read permission.\n\nAnalytics and checkups:\n analytics --customer-id <uuid> [--account-id <id> | --zone-id <id>] [--days 1..30]\n Default 7 days; live zone analytics uses the most recent 23 hours.\n checkup [status] Latest completed checkup; --customer-id, --account-id\n checkup start Start and persist a scan; --customer-id, --account-id\n checkup progress <run-uuid> Read saved progress once\n checkup result <run-uuid> Read the stored Cloudflare checkup result\n checkups aliases checkup; list/show alias status; run aliases start.\n\nCommon options: --json, --one-url <origin>, --timeout <milliseconds>, --help\nCustomer IDs are UUIDs; account and zone IDs are 32 hexadecimal characters.\nOne login, tenant bindings and permissions apply to every command.\nCheckup start creates a scan run. These commands do not edit provider configuration.\nSee CLOUDFLARE.md for full grammar, API mapping, data limits and examples.";
3
3
  export declare const handleCloudflare: CommandHandler;
@@ -14,7 +14,7 @@ Inventory and workspace:
14
14
  workspace [section] Workspace bootstrap or section; --customer-id, --account-id, --zone-id
15
15
  Sections: overview, reports, zones, rule-analyzer, accounts, checkups, settings
16
16
 
17
- Zone reads (optional --customer-id; IDs can use --zone-id):
17
+ Zone reads (--customer-id <uuid> required; IDs can use --zone-id):
18
18
  dns <zone-id> DNS records, TTL and proxy state
19
19
  waf <zone-id> WAF rules, expressions, analytics and suggestions
20
20
  speed-settings <zone-id> Performance settings (internal users only)
@@ -111,7 +111,7 @@ export const handleCloudflare = async (ctx) => {
111
111
  throw new Error('The positional account ID and --account-id must match.');
112
112
  accountId = args[0] ?? scope.accountId;
113
113
  if (!accountId)
114
- throw new Error(`Usage: vigilbase cf ${subcommand} <account-id> [--customer-id …] [--json]`);
114
+ throw new Error(`Missing <account-id>. Usage: vigilbase cf ${subcommand} <account-id> [--customer-id <uuid>] [--json]`);
115
115
  validate(cloudflareScopeSchema, { accountId });
116
116
  }
117
117
  else if (['dns', 'waf', 'zone', 'speed-settings'].includes(subcommand)) {
@@ -121,9 +121,12 @@ export const handleCloudflare = async (ctx) => {
121
121
  zoneId = args[0] ?? scope.zoneId;
122
122
  // Preserve the historical `cf zone` alias for the zone inventory.
123
123
  if (subcommand !== 'zone' && !zoneId)
124
- throw new Error(`Usage: vigilbase cf ${subcommand} <zone-id> [--customer-id …] [--json]`);
124
+ throw new Error(`Missing <zone-id>. Usage: vigilbase cf ${subcommand} <zone-id> --customer-id <uuid> [--json]`);
125
125
  if (zoneId)
126
126
  validate(cloudflareScopeSchema, { zoneId });
127
+ // One answers 400 to every caller that leaves the customer out of a zone read.
128
+ if (subcommand !== 'zone' && !scope.customerId)
129
+ throw new Error(`cf ${subcommand} requires --customer-id <uuid>. Find it with \`vigilbase cf accounts --json\`.`);
127
130
  }
128
131
  else if (!['workspace', 'checkup', 'checkups'].includes(subcommand)) {
129
132
  noExtraArgs(0);
@@ -144,6 +147,8 @@ export const handleCloudflare = async (ctx) => {
144
147
  if (subcommand === 'checkup' || subcommand === 'checkups') {
145
148
  if (['progress', 'result'].includes(action)) {
146
149
  noExtraArgs(2, checkupUsage);
150
+ if (args[1] === undefined)
151
+ throw new Error(`Missing <run-uuid>. Usage: vigilbase cf checkup ${action} <run-uuid> [--json]`);
147
152
  runId = validate(z.string().uuid('A checkup run UUID is required.'), args[1]);
148
153
  if (scope.customerId || scope.accountId)
149
154
  throw new Error(`cf checkup ${action} is scoped by run ID and does not accept --customer-id or --account-id.`);
@@ -1,6 +1,12 @@
1
1
  import { z } from 'zod';
2
2
  import { type CommandContext } from './helpers.js';
3
- export declare function validateArguments(ctx: CommandContext, count: number, flags?: readonly string[]): void;
3
+ /**
4
+ * Exactly `count` positional arguments. When some are missing, they are named from the trailing `<placeholders>`
5
+ * of `usage` (for example `vigilbase run <tool> <target>`), so `usage` lists only positional placeholders.
6
+ */
7
+ export declare function validateArguments(ctx: CommandContext, count: number, flags?: readonly string[], usage?: string): void;
8
+ /** "Missing <target>. Usage: vigilbase headers <url>", or a pointer to --help without a usage. */
9
+ export declare function missingArguments(command: string, missingCount: number, usage?: string): string;
4
10
  export declare function limitValue(raw: string | undefined, fallback: number, max: number): number;
5
11
  export declare const invitationSchema: z.ZodObject<{
6
12
  email: z.ZodString;