@vectros-ai/cli 0.25.0 → 0.26.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/AUTHORING.md CHANGED
@@ -8,7 +8,7 @@ ready-to-use data model + a narrow `ssk_*` scoped key — no root key, no manual
8
8
  admin steps. `vectros blueprint apply <file> --tenant test|live` applies the same
9
9
  blueprint WITHOUT minting a key, for re-applying a change from CI.
10
10
 
11
- This guide is the authoring loop. Everything here except `bootstrap` and `blueprint apply` is
11
+ This guide is the authoring loop. Everything here except `blueprint-test`, `bootstrap` and `blueprint apply` is
12
12
  **creds-free and offline** — you can iterate on a blueprint with no account.
13
13
 
14
14
  > The examples use the bare `vectros` binary — install it once with
@@ -22,7 +22,7 @@ vectros blueprint init my-thing # 1. scaffold a starter
22
22
  # …edit ./my-thing.blueprint.yaml…
23
23
  vectros blueprint validate ./my-thing.blueprint.yaml # 2. structural + scope-gate + lint (offline)
24
24
  vectros blueprint plan ./my-thing.blueprint.yaml # 3. preview what it provisions (offline)
25
- vectros blueprint-test ./my-thing.blueprint.yaml --env staging # 4. prove it live (creds; auto-teardown)
25
+ vectros blueprint-test ./my-thing.blueprint.yaml --tenant test # 4. prove it live (creds; auto-teardown)
26
26
  vectros bootstrap --blueprint ./my-thing.blueprint.yaml # 5. apply for real + mint a key (needs a bridge token)
27
27
  vectros blueprint apply ./my-thing.blueprint.yaml --tenant test # 5'. apply for real, no key (CI: add --yes --confirm-existing-principal)
28
28
  ```
@@ -50,7 +50,7 @@ A name must be 2–50 chars: a lowercase letter, then lowercase letters / digits
50
50
  `validate` runs three layers and exits non-zero on any failure:
51
51
 
52
52
  1. **Structural** — the file parses against the blueprint schema (readable
53
- `path: message` errors, e.g. `schemas[0].fields[1]: Required`).
53
+ `path: message` errors, e.g. `schemas[0].fields[1].fieldType: Required`).
54
54
  2. **Scope + capability gates** — the requested `allowedActions` are data-plane
55
55
  only. This is the trust boundary: `keys`/`users`/`admin`/`app-contexts`/
56
56
  `namespaces` and the `*` wildcard are **hard-rejected, no override**.
@@ -97,12 +97,14 @@ A name must be 2–50 chars: a lowercase letter, then lowercase letters / digits
97
97
 
98
98
  ```
99
99
  Plan for blueprint 'my-thing' (v1.0.0) → context 'mcp':
100
- + schema 'thing' (1 field, HYBRID) lookup: [title]
101
- + context 'mcp' (MCP — my-thing)
100
+ ...
102
101
  + principal 'my-thing-sp' (SERVICE)
102
+ + context 'mcp' (MCP — my-thing)
103
+ + schema 'thing' (1 field, HYBRID) lookup: [title]
103
104
  + profile scopes [records:r, records:c, records:u, search:r, schemas:r] (data-plane ✓)
104
105
  + key my-thing-<machine> (mint 1 scoped ssk_*)
105
- + seed 1 record(s)
106
+ + seed 1 record
107
+ 6 step(s). This is a preview — nothing was minted.
106
108
  ```
107
109
 
108
110
  **A blueprint whose `accessProfile` composes roles (`roleIds:`) previews every
@@ -111,9 +113,10 @@ sharing an action set can still carry different `dataScope`:
111
113
 
112
114
  ```
113
115
  Plan for blueprint 'my-thing' (v1.0.0) → context 'mcp':
114
- + schema 'thing' (1 field, HYBRID) lookup: [title]
115
- + context 'mcp' (MCP — my-thing)
116
+ ...
116
117
  + principal 'my-thing-sp' (SERVICE)
118
+ + context 'mcp' (MCP — my-thing)
119
+ + schema 'thing' (1 field, HYBRID) lookup: [title]
117
120
  + role 'case-handler' (1 clause, actions [records:cru])
118
121
  clause 1: actions [records:cru], dataScope: scope:org=[${{ self.scope.org }}]
119
122
  + role 'hr-admin' (1 clause, actions [records:r])
@@ -121,7 +124,8 @@ sharing an action set can still carry different `dataScope`:
121
124
  assumable: scope:org=[org_engineering, org_sales]
122
125
  + profile via role(s) [case-handler, hr-admin] (composed — each role's own clauses, concatenated in order)
123
126
  + key my-thing-<machine> (mint 1 scoped ssk_*)
124
- + seed 1 record(s)
127
+ + seed 1 record
128
+ 8 step(s). This is a preview — nothing was minted.
125
129
  ```
126
130
 
127
131
  A role's `assumable` line only appears when the blueprint's top-level
@@ -164,13 +168,13 @@ everything it created:
164
168
 
165
169
  ```
166
170
  vectros login # sign in once (or pass --token)
167
- vectros blueprint-test ./my-thing.blueprint.yaml --env staging
171
+ vectros blueprint-test ./my-thing.blueprint.yaml --tenant test
168
172
  vectros blueprint-test task-management --keep # leave the graph in place to inspect it
169
173
  ```
170
174
 
171
175
  Teardown is the default and runs even if an assertion fails. It is **created-only** — a pre-apply
172
176
  snapshot means it never deletes a schema or AccessProfile that already existed, so it's safe to point at
173
- a shared staging tenant. (It does **not** delete the app-context: that's idempotent and reused.) Exit
177
+ a tenant other people use. (It does **not** delete the app-context: that's idempotent and reused.) Exit
174
178
  `0` = applied + every assertion passed; `1` = an assertion failed or apply errored; `2` = no credential,
175
179
  or the blueprint asked for control-plane scope (the same gate `validate` enforces). Run this before you
176
180
  ship a blueprint — it catches an unusable or mis-scoped credential that the offline checks can't.
@@ -367,6 +371,16 @@ identities:
367
371
  YAML or JSON are both accepted (chosen by extension). The bundled library is
368
372
  authored in TypeScript; YAML is the authoring affordance for your own.
369
373
 
374
+ ### Inputs — values you supply when you install
375
+
376
+ A blueprint can declare a top-level `inputs:` block (each input has a `type` of `string`, `number` or `boolean`, and may
377
+ have `required`, `default` and `description`) and use the values in any string with `${{ inputs.<name> }}`. The built-ins
378
+ `${{ vectros.context }}` and `${{ vectros.suffix }}` are the blueprint's literal `contextId` and a short stable token derived
379
+ from it. Supply values to `validate`, `plan` and `apply` with `--set name=value` (repeatable) or `--values <file>` (a YAML or
380
+ JSON map); `--set` wins over `--values`, which wins over the declared `default`. An unknown input, a missing value with no
381
+ default, or a value of the wrong type stops the command before any request is sent. Write `$${{` for a literal `${{`. The
382
+ `@vectros-ai/blueprints` README describes the block in full.
383
+
370
384
  ### Choosing lookup indexes — a permanent decision
371
385
 
372
386
  `lookupFields` are how you reach records *directly* — by exact value, by an
@@ -424,7 +438,6 @@ each tell you "records with this status" or "records with this area", but never
424
438
 
425
439
  ```yaml
426
440
  lookupFields:
427
- - externalId
428
441
  - { fieldNames: [status, area], sortBy: createdAt, allowOverflow: true }
429
442
  ```
430
443
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,46 @@
3
3
  All notable changes to `@vectros-ai/cli` are documented here.
4
4
  This project adheres to [Semantic Versioning](https://semver.org).
5
5
 
6
+ ## 0.26.0 — 2026-10-25
7
+
8
+ ### Added
9
+
10
+ - **`vectros whoami --tenant test|live`** shows the session for that tenant (default `live`). The output gains a `tenant type`
11
+ line and `--json` gains `tenantType`. The test tenant shows your own user id there, which needs platform 0.47.0 or later and
12
+ shows `—` on an earlier platform. Any other value stops with a usage error (exit 2).
13
+ - **`vectros access list --principal` prints a note on standard error naming the context it searched.** The command searches
14
+ the `default` context, and depending on the caller the platform may not look beyond it, so an empty result means none in
15
+ `default`; the note gives the `vectros access get --principal … --context <c>` command to check another. Standard output
16
+ and `--json` are unchanged. A `2>&1 | jq` pipeline fails on the note; redirect standard error instead.
17
+
18
+ ### Fixed
19
+
20
+ - **A blueprint file whose trigger `dataScope` uses `${{ input.userId }}` or `${{ input.scope.<namespace> }}` loads in
21
+ `validate`, `plan`, `apply` and `bootstrap`.** The platform resolves these placeholders against the record that fires the
22
+ trigger.
23
+
24
+ ### Changed
25
+
26
+ - **`vectros --version` reports SDK 0.48.0.**
27
+ - **`vectros blueprint apply` stops with the platform's message when another request changes the same item at the same
28
+ moment.** When apply updates a schema, role or trigger rule, the platform answers `409` (`VERSION_CONFLICT`) instead of
29
+ overwriting the other change. Run apply again once the other change has finished.
30
+ - **`vectros provider-config create` and `update` stop with the platform's `503` when it cannot store the provider key.**
31
+ Nothing is saved; run the command again shortly.
32
+ - **The bundled `@vectros-ai/blueprints` is 0.20.3, and the package description covers the whole command set.**
33
+ - **The comments in the shipped code describe the code as it is today.** Behaviour is unchanged, except for the text of the
34
+ error for a missing Cognito client id.
35
+
36
+ ### Documentation
37
+
38
+ - **The README documents `vectros login`, `logout`, `whoami` and `switch`, and `vectros keyring prune --dry-run`.**
39
+ - **The README says `vectros blueprint-test` exits `1` for a blueprint that cannot be read, and that
40
+ `vectros provider-config create` and `update` stop with the platform's `503` when it cannot store the provider key.**
41
+ - **The authoring guide describes the `inputs:` block of a blueprint: its types, `required` and `default`, `--set` and
42
+ `--values`, and the `vectros.context` and `vectros.suffix` built-ins.**
43
+ - **The authoring guide shows an abbreviated `plan` output, with the steps in the order they run and the closing step count, and
44
+ uses `--tenant test` for `blueprint-test`.**
45
+
6
46
  ## 0.25.0 — 2026-10-12
7
47
 
8
48
  ### Breaking changes
package/README.md CHANGED
@@ -5,6 +5,8 @@
5
5
 
6
6
  The Vectros provisioning CLI — the `vectros` binary:
7
7
 
8
+ - **`vectros login`** / **`logout`** / **`whoami`** — sign in through your browser (`--no-browser` prints the URL instead, for headless machines), clear the stored session, and show the signed-in session for a tenant (`--tenant test|live`, default `live`; `--json`).
9
+ - **`vectros switch <alias>`** — shortcut for `keyring use`.
8
10
  - **`vectros bootstrap`** — provision a least-privilege MCP credential (+ optional blueprint).
9
11
  - **`vectros blueprint`** — author + inspect blueprints (`init` / `validate` / `plan` / `list`, creds-free), and
10
12
  **`apply`** one into a tenant without minting a key (for CI).
@@ -210,8 +212,8 @@ vectros blueprint-test ./my-thing.blueprint.yaml --tenant test
210
212
  vectros blueprint-test task-management --keep
211
213
  ```
212
214
 
213
- Exit `0` = applied and every assertion passed; `1` = an assertion failed or apply
214
- errored; `2` = no credential, or the scope gate or the capability gate refused the blueprint.
215
+ Exit `0` = applied and every assertion passed; `1` = an assertion failed, apply
216
+ errored, or the blueprint could not be read; `2` = no credential, or the scope gate or the capability gate refused the blueprint.
215
217
  The app-context is intentionally **not** deleted (it's idempotent and reused).
216
218
 
217
219
  ## `vectros context` — app contexts
@@ -317,7 +319,7 @@ config up itself is refused by the platform with a `400` for anything but `--bil
317
319
  `byo-model-inference:customer-key` waiver type, and a plain `https://` endpoint on port 443 (no credentials,
318
320
  query or fragment). On `update`, only a **change** to one of those is refused; a value the config already
319
321
  holds is accepted. Changing an endpoint's host needs the key again (`--api-key-secret-file`). The key must
320
- be printable ASCII, at most 4096 characters. A tenant holds at most 25 provider configs.
322
+ be printable ASCII, at most 4096 characters. A tenant holds at most 25 provider configs. If the platform cannot store the key it answers `503`, nothing is saved, and the command stops with that message; run it again shortly.
321
323
 
322
324
  The CLI does not sign the risk waiver: an account owner signs it in the developer portal, under **Model
323
325
  Providers**, for each environment (live or test). A config is usable only while that waiver is in force for
@@ -541,12 +543,24 @@ vectros access grant --principal me --context my-app --role editor
541
543
  vectros access grant --principal usr_<id> --context my-app --actions records:r,search:r \
542
544
  --scope org:<orgId>
543
545
  vectros access list --context my-app # who's in this context
544
- vectros access list --principal me # which contexts I'm bound to
546
+ vectros access list --principal me # which contexts I'm bound to (see the note below)
545
547
  vectros access get --principal me --context my-app
546
548
  vectros access explain --principal me --context my-app
547
549
  vectros access revoke --principal usr_<id> --context my-app
548
550
  ```
549
551
 
552
+ `access list --principal` searches one context, `default`, because the command's token is pinned to it:
553
+ depending on the caller the platform may not look beyond that context, so a grant you hold in another
554
+ context can be missing from the list, and an empty list means no grant in `default`, not no grants
555
+ anywhere. The command says so on standard error, so `--json` output on standard output stays a bare array,
556
+ and it drops the line when a row from another context shows the lookup did span contexts. To see a grant
557
+ in a specific context, run `vectros access get --principal me --context <context-id>` (add `--tenant test`
558
+ for the test tenant), or `vectros access list --context <context-id>` for everyone in it.
559
+
560
+ The line is also written with `--json`, and there is no switch to turn it off. A script that merges standard
561
+ error into standard output (`2>&1`) will see one extra line and a `2>&1 | jq` pipeline will fail on it;
562
+ redirect standard error (`2>/dev/null`) to drop it.
563
+
550
564
  `--principal` accepts `usr_<userId>`, `key_<keyId>`, or the alias `me` (your
551
565
  own signed-in user, resolved from your login) — every `access` subcommand
552
566
  shares this grammar. In the **test tenant** your principal has a different id from your live user, so `me` resolves it per tenant: add `--tenant test` and it still works, e.g. `vectros access grant --principal me --context <context-id> --role <role> --tenant test`. This needs platform 0.47.0 or later; on an earlier platform the command typically stops and points you to `vectros identity list-all --tenant test` (an owner login), which shows the id to pass as `--principal usr_<id>`.
@@ -612,7 +626,7 @@ is optional and stripped if present) — narrower than `access`'s grammar: there
612
626
  is no `me` alias on any `key` subcommand, and a key never authenticates as a
613
627
  `key_*` principal. Look your own id up first with `vectros identity list
614
628
  --type user` (or `vectros whoami`; both show your live tenant, and for the test tenant
615
- use `vectros identity list-all --tenant test`), or grant/issue via `vectros join`, which
629
+ use `vectros whoami --tenant test` or `vectros identity list-all --tenant test`), or grant/issue via `vectros join`, which
616
630
  does resolve `--as me`.
617
631
 
618
632
  A minted secret has exactly two destinations, and the flags for choosing one
@@ -630,7 +644,7 @@ are shared by `issue` and `rotate`:
630
644
  | `issue` | `--principal <p>`, `--context <c>` (required); `--name <n>` (default `default`), `--label <l>`, `--tenant test\|live`, destination flags above | Idempotent on `(tenant, context, principal, name)` — re-issuing an existing tuple returns the key **without** the secret (never re-disclosed); the CLI detects that and points you at `rotate`. |
631
645
  | `list` | `--principal <p>`, `--context <c>`, `--tenant test\|live` **or** `--all-contexts` (owner-only; spans both tenants, not combinable with `--tenant`) | **The default lists only ONE context's keys** (the token's context — `default`, or `--context`), not your whole account — easy to miss since the active-key limit is tenant-wide across all contexts. `--all-contexts` is the true account-wide view. |
632
646
  | `get <keyId>` | `--context <c>`, `--tenant test\|live` | `--context` pins the verb token to the key's context — omit it for a key bound to a non-default context (e.g. one `bootstrap` minted) and the lookup 404s. |
633
- | `revoke <keyId>` | `--context <c>`, `--tenant test\|live` | Soft-delete; ~5 minutes to take effect (authorizer cache). Same `--context` pinning caveat as `get`. |
647
+ | `revoke <keyId>` | `--context <c>`, `--tenant test\|live` | Soft-delete; it takes about 5 minutes to take effect. Same `--context` pinning caveat as `get`. |
634
648
  | `rotate` | `--principal <p>`, `--context <c>` (required); `--name <n>`, `--force-new`, `--tenant test\|live`, destination flags above | Revokes the matching active key (by the exact `(context, principal, name)` tuple), then mints a fresh one — there is no dedicated rotate endpoint. **Default-name guard:** if no key is currently active under `--name` (default `default`) but the principal/context has *other* active keys, `rotate` refuses rather than silently minting an unrelated second key — pass the right `--name` or `--force-new` to proceed anyway. |
635
649
 
636
650
  `issue`/`rotate` have no `--json` (use `--format json` instead); `list`/`get`
@@ -652,6 +666,7 @@ vectros keyring show # the active entry's fields + its key
652
666
  vectros keyring show --format raw # JUST the secret, for scripts (see below)
653
667
  vectros keyring doctor # is the keyring healthy? which keys are live?
654
668
  vectros keyring prune # drop entries whose stored secret is gone
669
+ vectros keyring prune --dry-run # report what would be removed, remove nothing
655
670
  vectros keyring remove <alias> # drop one entry + its secret
656
671
  ```
657
672