@arkveil/cli 1.0.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/README.md +426 -0
- package/bin/cli.js +3 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +14323 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# arkveil-cli
|
|
2
|
+
|
|
3
|
+
A command-line interface for the **Arkveil Kernel API** — navigation
|
|
4
|
+
trees, actions, targets, policies, tags, access tests, attribute schemas, and
|
|
5
|
+
ABAC (attribute-based access control) operations.
|
|
6
|
+
|
|
7
|
+
The CLI is generated against the API's OpenAPI 3.1 specification, so its request
|
|
8
|
+
and response types are fully derived from the spec.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of contents
|
|
13
|
+
|
|
14
|
+
- [Install](#install)
|
|
15
|
+
- [Quick start](#quick-start)
|
|
16
|
+
- [Authentication](#authentication)
|
|
17
|
+
- [Global flags](#global-flags)
|
|
18
|
+
- [Configuration & environment](#configuration--environment)
|
|
19
|
+
- [Exit codes](#exit-codes)
|
|
20
|
+
- [Commands](#commands)
|
|
21
|
+
- [JSON output & scripting](#json-output--scripting)
|
|
22
|
+
- [Development](#development)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
Requires **Node.js ≥ 20**.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# from a published package
|
|
32
|
+
npm install -g arkveil-cli
|
|
33
|
+
|
|
34
|
+
# or run without installing
|
|
35
|
+
npx arkveil-cli --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
From source:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pnpm install
|
|
42
|
+
pnpm build
|
|
43
|
+
node bin/cli.js --help
|
|
44
|
+
# or link it onto your PATH:
|
|
45
|
+
npm link
|
|
46
|
+
arkveil --help
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# 1. Point at your API (default is https://api.arkveil.com)
|
|
55
|
+
export ARKVEIL_BASE_URL="https://kernel.example.com"
|
|
56
|
+
|
|
57
|
+
# 2. Authenticate (opens your browser to approve)
|
|
58
|
+
arkveil auth login
|
|
59
|
+
|
|
60
|
+
# 3. Confirm who you are
|
|
61
|
+
arkveil auth whoami
|
|
62
|
+
|
|
63
|
+
# 4. Use it
|
|
64
|
+
arkveil health
|
|
65
|
+
arkveil trees forest
|
|
66
|
+
arkveil tags list
|
|
67
|
+
arkveil eval explain -a orders:read --user '{"role":"admin"}' --context '{}'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Authentication
|
|
73
|
+
|
|
74
|
+
The CLI authenticates with the **OAuth 2.0 Device Authorization Grant**
|
|
75
|
+
(RFC 8628), as implemented by the backend's **better-auth Device Authorization**
|
|
76
|
+
plugin.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
arkveil auth login # request a device code, open the browser, poll for the token
|
|
80
|
+
arkveil auth login --no-browser # print the URL/code instead of opening a browser
|
|
81
|
+
arkveil auth logout # remove stored credentials
|
|
82
|
+
arkveil auth whoami # show current auth state (verifies the token by default)
|
|
83
|
+
arkveil auth whoami --no-verify # skip the verification API call
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`login` requests a device code, shows you a verification URL and short user code,
|
|
87
|
+
opens your browser, and then polls until you approve — handling
|
|
88
|
+
`authorization_pending`, `slow_down`, `expired_token`, and `access_denied`.
|
|
89
|
+
|
|
90
|
+
The resulting token is sent as `Authorization: Bearer <token>` on every request.
|
|
91
|
+
|
|
92
|
+
### Credential storage
|
|
93
|
+
|
|
94
|
+
Tokens are stored in the **OS keychain** when [`keytar`](https://www.npmjs.com/package/keytar)
|
|
95
|
+
is available; otherwise they fall back to `~/.config/arkveil/credentials.json`,
|
|
96
|
+
written with `0600` permissions. `arkveil auth whoami` reports which storage
|
|
97
|
+
backend is in use. Use `arkveil logout` to clear both.
|
|
98
|
+
|
|
99
|
+
You can bypass stored credentials entirely with an explicit token:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
arkveil --api-key "$TOKEN" tags list
|
|
103
|
+
# or
|
|
104
|
+
ARKVEIL_TOKEN="$TOKEN" arkveil tags list
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> **Note on the spec.** The bundled OpenAPI document defines no security scheme or
|
|
108
|
+
> device-flow endpoints. The device-flow endpoints are therefore derived from
|
|
109
|
+
> configuration and default to better-auth conventions
|
|
110
|
+
> (`<auth-base-url>/device/code` and `/device/token`, where `auth-base-url`
|
|
111
|
+
> defaults to `<base-url>/api/auth`). Override them via the environment if your
|
|
112
|
+
> deployment differs (see below). The API also exposes a **Workspace API Keys**
|
|
113
|
+
> resource (`arkveil keys …`) that you can use to mint long-lived keys to pass via
|
|
114
|
+
> `--api-key`.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Global flags
|
|
119
|
+
|
|
120
|
+
These apply to **every** command:
|
|
121
|
+
|
|
122
|
+
| Flag | Description |
|
|
123
|
+
| -------------------- | ------------------------------------------------------------------------- |
|
|
124
|
+
| `--json` | Emit machine-readable JSON to stdout; disables spinners and color. |
|
|
125
|
+
| `-q, --quiet` | Suppress non-essential status messages. |
|
|
126
|
+
| `-v, --verbose` | Print transport diagnostics (method, URL, request id, retries) to stderr. |
|
|
127
|
+
| `--no-color` | Disable ANSI color. |
|
|
128
|
+
| `--base-url <url>` | Override the API base URL. |
|
|
129
|
+
| `--api-key <token>` | Bearer token to use, overriding stored credentials. |
|
|
130
|
+
| `--config-dir <dir>` | Directory for config and credentials. |
|
|
131
|
+
| `--timeout <ms>` | Per-request timeout in milliseconds. |
|
|
132
|
+
| `-V, --version` | Print the CLI version. |
|
|
133
|
+
| `-h, --help` | Show help (available on every command and subcommand). |
|
|
134
|
+
|
|
135
|
+
Color and spinners are also disabled automatically when stdout is **not a TTY**
|
|
136
|
+
(e.g. piped) or when `NO_COLOR` is set.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Configuration & environment
|
|
141
|
+
|
|
142
|
+
Configuration is resolved with the precedence: **CLI flags > environment
|
|
143
|
+
variables > config file > built-in defaults**.
|
|
144
|
+
|
|
145
|
+
### Config file
|
|
146
|
+
|
|
147
|
+
`~/.config/arkveil/config.json` (or `$XDG_CONFIG_HOME/arkveil/config.json`, or a
|
|
148
|
+
`--config-dir`). Validated at runtime; unknown keys are rejected.
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"baseUrl": "https://kernel.example.com",
|
|
153
|
+
"authBaseUrl": "https://auth.example.com/api/auth",
|
|
154
|
+
"clientId": "arkveil-cli",
|
|
155
|
+
"deviceCodePath": "/device/code",
|
|
156
|
+
"deviceTokenPath": "/device/token",
|
|
157
|
+
"timeoutMs": 30000,
|
|
158
|
+
"retries": 2
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Environment variables
|
|
163
|
+
|
|
164
|
+
| Variable | Purpose | Default |
|
|
165
|
+
| ----------------------- | ------------------------------------------- | ------------------------- |
|
|
166
|
+
| `ARKVEIL_BASE_URL` | API base URL | `https://api.arkveil.com` |
|
|
167
|
+
| `ARKVEIL_AUTH_BASE_URL` | better-auth mount point | `<base-url>/api/auth` |
|
|
168
|
+
| `ARKVEIL_CLIENT_ID` | Device-flow client id | `arkveil-cli` |
|
|
169
|
+
| `ARKVEIL_SCOPE` | Optional OAuth scope | _(unset)_ |
|
|
170
|
+
| `ARKVEIL_TOKEN` | Bearer token (overrides stored credentials) | _(unset)_ |
|
|
171
|
+
| `ARKVEIL_TIMEOUT` | Request timeout (ms) | `30000` |
|
|
172
|
+
| `ARKVEIL_RETRIES` | Retry attempts for idempotent requests | `2` |
|
|
173
|
+
| `ARKVEIL_CONFIG_DIR` | Config/credentials directory | `~/.config/arkveil` |
|
|
174
|
+
| `NO_COLOR` | Disable color when set | _(unset)_ |
|
|
175
|
+
|
|
176
|
+
### Networking behavior
|
|
177
|
+
|
|
178
|
+
- **Timeouts**: every request is bounded by `--timeout` (default 30s).
|
|
179
|
+
- **Retries**: idempotent requests (`GET`/`PUT`/`DELETE`) are retried with
|
|
180
|
+
exponential backoff on `429`/`502`/`503`/`504` and network errors, honoring
|
|
181
|
+
`Retry-After`. `POST`/`PATCH` are never retried.
|
|
182
|
+
- **Request IDs**: every request carries an `x-request-id` header, shown under
|
|
183
|
+
`--verbose`.
|
|
184
|
+
- **Pagination**: the API returns full collections (no pagination parameters), so
|
|
185
|
+
list commands return complete results.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Exit codes
|
|
190
|
+
|
|
191
|
+
| Code | Meaning |
|
|
192
|
+
| ----- | ------------------------------------ |
|
|
193
|
+
| `0` | Success |
|
|
194
|
+
| `1` | Generic / unexpected error |
|
|
195
|
+
| `2` | Usage error (bad flags or arguments) |
|
|
196
|
+
| `3` | Authentication required or rejected |
|
|
197
|
+
| `4` | Resource not found (404) |
|
|
198
|
+
| `5` | Network failure or timeout |
|
|
199
|
+
| `6` | API returned an error response |
|
|
200
|
+
| `7` | Invalid local configuration |
|
|
201
|
+
| `130` | Cancelled at an interactive prompt |
|
|
202
|
+
|
|
203
|
+
Errors are printed as a one-line message plus an actionable hint — never a raw
|
|
204
|
+
stack trace. Re-run with `--verbose` for the underlying cause.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Commands
|
|
209
|
+
|
|
210
|
+
Run `arkveil <group> --help` or `arkveil <group> <command> --help` for full,
|
|
211
|
+
auto-generated usage with examples.
|
|
212
|
+
|
|
213
|
+
### `auth` — authentication
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
arkveil auth login [--no-browser]
|
|
217
|
+
arkveil auth logout
|
|
218
|
+
arkveil auth whoami [--no-verify]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### `health` — connectivity check
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
arkveil health
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### `keys` — workspace API keys
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
arkveil keys list
|
|
231
|
+
arkveil keys create # secret is shown once
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `tags`
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
arkveil tags list
|
|
238
|
+
arkveil tags get <id>
|
|
239
|
+
arkveil tags create --slug pii --color '#e11' [--tooltip <t>] [--description <d>]
|
|
240
|
+
arkveil tags update <id> --color '#f00' [--tooltip <t>] [--description <d>]
|
|
241
|
+
arkveil tags delete <id> [--yes]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### `trees` — navigation trees (read-only)
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
arkveil trees forest
|
|
248
|
+
arkveil trees tests
|
|
249
|
+
arkveil trees data-policies
|
|
250
|
+
arkveil trees actions
|
|
251
|
+
arkveil trees action-policies
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### `folders`
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
arkveil folders create --parent <id> --title <t> [--description <d>]
|
|
258
|
+
arkveil folders update <folderId> --title <t> [--description <d>]
|
|
259
|
+
arkveil folders delete <folderId> [--yes]
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `actions`
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
arkveil actions create --parent <id> --service <svc> --name <n> --title <t> \
|
|
266
|
+
[--tag <slug> ...] [--description <d>] [--request-schema <json|@file|->]
|
|
267
|
+
arkveil actions update <actionNodeId> --title <t> [--tag <slug> ...] \
|
|
268
|
+
[--description <d>] [--request-schema <json|@file|->]
|
|
269
|
+
arkveil actions delete <actionNodeId> [--yes]
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### `targets`
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
arkveil targets create --parent <id> --type ACTION|DATA --mode INDIVIDUAL|CUSTOM|ALL \
|
|
276
|
+
--title <t> [--action-code <code>] [--dataset-id <id>] [--condition <dsl>] \
|
|
277
|
+
[--request-schema <json|@file|->]
|
|
278
|
+
arkveil targets update <targetNodeId> --title <t> [--condition <dsl>] [--request-schema <...>]
|
|
279
|
+
arkveil targets delete <targetNodeId> [--yes]
|
|
280
|
+
arkveil targets suggest --condition '<dsl>' # suggest a request schema from a condition
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### `policies` (attached to a target)
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
arkveil policies create <targetNodeId> --type PERMISSION|READ|WRITE|INVARIANT|PROJECTION \
|
|
287
|
+
--status ENABLED|DISABLED|DRAFT|DELETED --title <t> \
|
|
288
|
+
[--condition <dsl>] [--filter <dsl>] [--projection <json|@file|->]
|
|
289
|
+
arkveil policies update <targetNodeId> <policyId> --status <s> --title <t> [...]
|
|
290
|
+
arkveil policies delete <targetNodeId> <policyId> [--yes]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `tests` — access tests
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
arkveil tests create --parent <id> --name <n> --status DRAFT \
|
|
297
|
+
--selector-type ACTION_SET|FORMULA|ALL_ACTIONS --expected-access GRANTED|DENIED \
|
|
298
|
+
[--action-code <code> ...] [--formula <dsl>] \
|
|
299
|
+
[--user '<json>'] [--context '<json>'] [--tag <slug> ...] \
|
|
300
|
+
[--must-be-granted-by <policyId> ...]
|
|
301
|
+
arkveil tests update <testNodeId> --name <n> --status <s> --selector-type <t> --expected-access <a> [...]
|
|
302
|
+
arkveil tests set-status <testNodeId> --status ENABLED
|
|
303
|
+
arkveil tests delete <testNodeId> [--yes]
|
|
304
|
+
arkveil tests run <testId>
|
|
305
|
+
arkveil tests run-all
|
|
306
|
+
arkveil tests history [testId] # per-test runs, or aggregate when no id given
|
|
307
|
+
arkveil tests run-info <runId> # a single run with per-action results
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### `settings` — user settings
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
arkveil settings get
|
|
314
|
+
arkveil settings set [--theme LIGHT|DARK|SYSTEM] [--ui-mode SIMPLE|STRUCTURED]
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### `schemas` — attribute JSON schemas
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
arkveil schemas get <user|context|action>
|
|
321
|
+
arkveil schemas set <user|context|action> --data @schema.json
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### `formula` — formula DSL
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
arkveil formula parse --context ACTION_PERMISSION --dsl 'user.role == "admin"'
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### `eval` — explain access decisions
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
arkveil eval explain -a orders:read --user '{"role":"admin"}' --context '{}' [--request '<json>']
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### `abac` — ABAC SDK operations
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
arkveil abac check --code orders:read --user '<json>' --context '<json>' [--request '<json>']
|
|
340
|
+
arkveil abac read --dataset-id <id> --user '<json>' --context '<json>' [--alias t]
|
|
341
|
+
arkveil abac write --dataset-id <id> --user '<json>' --context '<json>' [--id <rowId> ...]
|
|
342
|
+
arkveil abac action-data <service> <name>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### `admin` — workspace administration
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
arkveil admin seed-demo # idempotent; preserves existing entities
|
|
349
|
+
arkveil admin reset-demo [--yes] # DESTRUCTIVE: wipes all authz data, then reseeds
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### JSON payloads (`--data`, `--request-schema`, `--projection`, …)
|
|
353
|
+
|
|
354
|
+
Flags that accept JSON take one of three forms:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
--data '{"a":1}' # inline JSON
|
|
358
|
+
--data @payload.json # read from a file
|
|
359
|
+
--data - # read from stdin
|
|
360
|
+
echo '{"a":1}' | arkveil schemas set user --data -
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## JSON output & scripting
|
|
366
|
+
|
|
367
|
+
Add `--json` to any command to emit the raw API payload (or a small status object
|
|
368
|
+
for actions like `delete`/`login`) as JSON on stdout. In JSON mode, spinners and
|
|
369
|
+
color are disabled and status text is suppressed, so stdout is always valid JSON:
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
arkveil tags list --json | jq '.[].slug'
|
|
373
|
+
arkveil eval explain -a orders:read --user '{"role":"admin"}' --context '{}' --json | jq .granted
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Errors in `--json` mode are emitted to **stderr** as a JSON object
|
|
377
|
+
(`{"error":{"message":…,"hint":…,"exitCode":…}}`) while the process exit code
|
|
378
|
+
still reflects the failure category (see [Exit codes](#exit-codes)).
|
|
379
|
+
|
|
380
|
+
Destructive commands (`delete`, `admin reset-demo`) prompt for confirmation when
|
|
381
|
+
interactive and **refuse** to run non-interactively unless `--yes` is passed — so
|
|
382
|
+
piped/CI usage never hangs.
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Development
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
pnpm install
|
|
390
|
+
pnpm gen:api # regenerate the typed client from .docs/api.yaml
|
|
391
|
+
pnpm dev -- --help
|
|
392
|
+
pnpm typecheck # tsc --noEmit
|
|
393
|
+
pnpm lint # eslint
|
|
394
|
+
pnpm test # vitest (network is mocked; no live calls)
|
|
395
|
+
pnpm build # tsup -> dist/ (publishable ESM + d.ts)
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Project layout
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
bin/cli.js # shebang wrapper -> dist/index.js
|
|
402
|
+
src/index.ts # entry: program wiring + global error handler
|
|
403
|
+
src/commands/<resource>/<action> # one file per command
|
|
404
|
+
src/lib/
|
|
405
|
+
api-client.ts # typed openapi-fetch client + unwrap()
|
|
406
|
+
generated/schema.d.ts # openapi-typescript output (do not edit)
|
|
407
|
+
config.ts # config precedence + validation
|
|
408
|
+
context.ts # per-invocation context (config + output + client)
|
|
409
|
+
auth.ts # device flow + credential store
|
|
410
|
+
http.ts # timeout, retry/backoff, request ids
|
|
411
|
+
output.ts # JSON/human renderers, color/spinner gating
|
|
412
|
+
errors.ts # typed errors + exit codes
|
|
413
|
+
input.ts # JSON payload parsing (--data/@file/-)
|
|
414
|
+
types.ts # friendly aliases for generated schema types
|
|
415
|
+
tests/ # vitest: config, output, api-client, http, auth
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Publishing
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
pnpm version <patch|minor|major>
|
|
422
|
+
pnpm publish # runs prepublishOnly: typecheck + test + build
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The package ships only `dist/`, `bin/`, and `README.md` (see `package.json`
|
|
426
|
+
`files`), with `bin.arkveil` pointing at `bin/cli.js`.
|
package/bin/cli.js
ADDED