@vectros-ai/cli 0.6.8 → 0.7.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/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
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.7.0 — 2026-07-08
7
+
8
+ ### Added
9
+
10
+ - **`--tenant test|live` on `context create`, `context list`, and `context get`** —
11
+ pick the tenant a context is created in / read from (default `live`), mirroring the
12
+ flag `context destroy` and `blueprint-test` already carried. Previously these verbs
13
+ always targeted the live tenant, so a context on the test tenant could neither be
14
+ created, read, nor listed from the CLI.
15
+ - **`vectros context destroy <contextId>`** — permanently destroy an app context and
16
+ everything in it (records, documents, folders, schemas, roles, access profiles; the
17
+ context's scoped keys are revoked up front). The teardown is irreversible and runs
18
+ asynchronously on the server (the context reports `purging` until the drain
19
+ completes). Two safety rails: interactively you must re-type the context id to
20
+ confirm; `--force` skips the prompt and is required when stdin is not a terminal.
21
+ `--tenant test|live` picks the tenant the context lives in (default `live`).
22
+ Authenticates as the account owner — no root API key required.
23
+
6
24
  ## 0.6.8 — 2026-07-05
7
25
 
8
26
  ### Changed
package/dist/cli.js CHANGED
@@ -13446,6 +13446,7 @@ async function runRoleDelete(opts, deps = {}) {
13446
13446
  }
13447
13447
 
13448
13448
  // src/commands/context.ts
13449
+ var readline2 = __toESM(require("readline/promises"));
13449
13450
  function renderContext(c) {
13450
13451
  return formatKeyValues([
13451
13452
  ["context", c.contextId],
@@ -13507,6 +13508,80 @@ async function runContextList(opts, deps = {}) {
13507
13508
  }
13508
13509
  });
13509
13510
  }
13511
+ async function runContextDestroy(opts, deps = {}) {
13512
+ const { contextId } = opts;
13513
+ if (!opts.force) {
13514
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
13515
+ if (!isTty) {
13516
+ process.stderr.write(
13517
+ ` \u2716 context destroy is irreversible and needs an interactive confirmation.
13518
+ Re-run with --force to destroy '${contextId}' without a prompt.
13519
+ `
13520
+ );
13521
+ return 2;
13522
+ }
13523
+ const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
13524
+ const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
13525
+ return { prompt: (q) => rl.question(q), close: () => rl.close() };
13526
+ })();
13527
+ try {
13528
+ process.stdout.write(
13529
+ `
13530
+ \u26A0 Destroying app context '${contextId}' permanently erases it AND all of its
13531
+ records, documents, folders, schemas, roles, and access profiles, and revokes
13532
+ its scoped keys. This cannot be undone.
13533
+
13534
+ `
13535
+ );
13536
+ const typed = await promptCtx.prompt(` Type the context id ('${contextId}') to confirm: `);
13537
+ if (typed.trim() !== contextId) {
13538
+ process.stderr.write(` \u2716 Confirmation did not match \u2014 nothing destroyed.
13539
+ `);
13540
+ return 1;
13541
+ }
13542
+ } finally {
13543
+ promptCtx.close();
13544
+ }
13545
+ }
13546
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
13547
+ const fetchImpl = deps.fetchImpl ?? fetch;
13548
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/app-contexts/${encodeURIComponent(contextId)}?tenant=${encodeURIComponent(auth.tenant)}&confirm=${encodeURIComponent(contextId)}`;
13549
+ try {
13550
+ const res = await fetchImpl(url, {
13551
+ method: "DELETE",
13552
+ headers: { Authorization: `Bearer ${auth.cognitoToken}` }
13553
+ });
13554
+ if (!res.ok) {
13555
+ const body = await res.text().catch(() => "");
13556
+ let message = body;
13557
+ try {
13558
+ const parsed = JSON.parse(body);
13559
+ if (parsed.message) message = parsed.message;
13560
+ } catch {
13561
+ }
13562
+ process.stderr.write(` \u2716 context destroy failed: HTTP ${res.status}${message ? ` \u2014 ${message}` : ""}
13563
+ `);
13564
+ return 1;
13565
+ }
13566
+ if (opts.json) {
13567
+ process.stdout.write(`${formatJson({ contextId, status: "purging" })}
13568
+ `);
13569
+ return 0;
13570
+ }
13571
+ process.stdout.write(
13572
+ `
13573
+ \u2714 teardown of '${contextId}' started \u2014 the context and its contents are being
13574
+ deleted asynchronously (it reports status 'purging' until the drain completes)
13575
+ `
13576
+ );
13577
+ return 0;
13578
+ } catch (err) {
13579
+ process.stderr.write(` \u2716 context destroy failed: ${formatError(err)}
13580
+ `);
13581
+ return 1;
13582
+ }
13583
+ });
13584
+ }
13510
13585
  async function runContextGet(opts, deps = {}) {
13511
13586
  return withAuth({ ...opts, context: opts.contextId }, deps, async (auth) => {
13512
13587
  const client = auth.client;
@@ -14091,7 +14166,7 @@ async function runBlueprintTest(fileOrName, opts, deps = {}) {
14091
14166
 
14092
14167
  // src/build-info.ts
14093
14168
  var BUILD_INFO = {
14094
- cli: true ? "0.6.8" : "dev",
14169
+ cli: true ? "0.7.0" : "dev",
14095
14170
  sdk: true ? "0.33.0" : "dev",
14096
14171
  blueprints: true ? "0.6.5" : "dev"
14097
14172
  };
@@ -14167,18 +14242,75 @@ function buildProgram(deps = {}) {
14167
14242
  }
14168
14243
  function registerContextCommands(program, deps) {
14169
14244
  const context = program.command("context").description("Manage app contexts (the namespace all data lives in).");
14170
- const create = context.command("create").description("Create (idempotent) an app context.").argument("<contextId>", "context id (3-31 chars; lowercase letter + lowercase/digit/dash)").option("--name <name>", "human-readable name");
14171
- addCommonAuthOptions(create).action(async (contextId, flags) => {
14172
- process.exit(await runContextCreate({ ...toCommonOptions(flags), contextId, name: flags.name }, deps));
14173
- });
14174
- const list = context.command("list").description("List the tenant\u2019s app contexts.");
14245
+ const create = context.command("create").description("Create (idempotent) an app context.").argument("<contextId>", "context id (3-31 chars; lowercase letter + lowercase/digit/dash)").option("--name <name>", "human-readable name").option("--tenant <tenant>", "tenant to create the context in: 'test' or 'live' (default live)");
14246
+ addCommonAuthOptions(create).action(
14247
+ async (contextId, flags) => {
14248
+ if (flags.tenant !== void 0 && flags.tenant !== "test" && flags.tenant !== "live") {
14249
+ process.stderr.write(` \u2716 --tenant must be 'test' or 'live' (got '${flags.tenant}')
14250
+ `);
14251
+ process.exit(2);
14252
+ }
14253
+ process.exit(
14254
+ await runContextCreate(
14255
+ {
14256
+ ...toCommonOptions(flags),
14257
+ contextId,
14258
+ name: flags.name,
14259
+ tenant: flags.tenant
14260
+ },
14261
+ deps
14262
+ )
14263
+ );
14264
+ }
14265
+ );
14266
+ const list = context.command("list").description("List the tenant\u2019s app contexts.").option("--tenant <tenant>", "tenant to list: 'test' or 'live' (default live)");
14175
14267
  addCommonAuthOptions(list).action(async (flags) => {
14176
- process.exit(await runContextList(toCommonOptions(flags), deps));
14268
+ if (flags.tenant !== void 0 && flags.tenant !== "test" && flags.tenant !== "live") {
14269
+ process.stderr.write(` \u2716 --tenant must be 'test' or 'live' (got '${flags.tenant}')
14270
+ `);
14271
+ process.exit(2);
14272
+ }
14273
+ process.exit(
14274
+ await runContextList({ ...toCommonOptions(flags), tenant: flags.tenant }, deps)
14275
+ );
14177
14276
  });
14178
- const get = context.command("get").description("Show one app context.").argument("<contextId>");
14277
+ const get = context.command("get").description("Show one app context.").argument("<contextId>").option("--tenant <tenant>", "tenant the context lives in: 'test' or 'live' (default live)");
14179
14278
  addCommonAuthOptions(get).action(async (contextId, flags) => {
14180
- process.exit(await runContextGet({ ...toCommonOptions(flags), contextId }, deps));
14279
+ if (flags.tenant !== void 0 && flags.tenant !== "test" && flags.tenant !== "live") {
14280
+ process.stderr.write(` \u2716 --tenant must be 'test' or 'live' (got '${flags.tenant}')
14281
+ `);
14282
+ process.exit(2);
14283
+ }
14284
+ process.exit(
14285
+ await runContextGet(
14286
+ { ...toCommonOptions(flags), contextId, tenant: flags.tenant },
14287
+ deps
14288
+ )
14289
+ );
14181
14290
  });
14291
+ const destroy = context.command("destroy").description(
14292
+ "Permanently destroy an app context and ALL of its data (irreversible; asks for confirmation)."
14293
+ ).argument("<contextId>", "the app context to destroy").option("--force", "skip the interactive confirmation (required when stdin is not a TTY)").option("--tenant <tenant>", "tenant the context lives in: 'test' or 'live' (default live)");
14294
+ addCommonAuthOptions(destroy).action(
14295
+ async (contextId, flags) => {
14296
+ if (flags.tenant !== void 0 && flags.tenant !== "test" && flags.tenant !== "live") {
14297
+ process.stderr.write(` \u2716 --tenant must be 'test' or 'live' (got '${flags.tenant}')
14298
+ `);
14299
+ process.exit(2);
14300
+ }
14301
+ process.exit(
14302
+ await runContextDestroy(
14303
+ {
14304
+ ...toCommonOptions(flags),
14305
+ contextId,
14306
+ force: Boolean(flags.force),
14307
+ tenant: flags.tenant
14308
+ },
14309
+ deps
14310
+ )
14311
+ );
14312
+ }
14313
+ );
14182
14314
  }
14183
14315
  function registerRoleCommands(program, deps) {
14184
14316
  const role = program.command("role").description("Manage context-scoped roles (reusable scope rules; bind via `access grant --role`).");