@vectros-ai/cli 0.23.0 → 0.24.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/dist/cli.mjs CHANGED
@@ -523,7 +523,7 @@ var require_graceful_fs = __commonJS({
523
523
  function patch(fs5) {
524
524
  polyfills(fs5);
525
525
  fs5.gracefulify = patch;
526
- fs5.createReadStream = createReadStream2;
526
+ fs5.createReadStream = createReadStream3;
527
527
  fs5.createWriteStream = createWriteStream;
528
528
  var fs$readFile = fs5.readFile;
529
529
  fs5.readFile = readFile4;
@@ -733,7 +733,7 @@ var require_graceful_fs = __commonJS({
733
733
  }
734
734
  });
735
735
  }
736
- function createReadStream2(path4, options) {
736
+ function createReadStream3(path4, options) {
737
737
  return new fs5.ReadStream(path4, options);
738
738
  }
739
739
  function createWriteStream(path4, options) {
@@ -1619,7 +1619,7 @@ var require_proper_lockfile = __commonJS({
1619
1619
  // src/cli-bootstrap.ts
1620
1620
  import * as readline2 from "readline/promises";
1621
1621
 
1622
- // ../../node_modules/@vectros-ai/sdk/dist/index.mjs
1622
+ // node_modules/@vectros-ai/sdk/dist/index.mjs
1623
1623
  var __defProp2 = Object.defineProperty;
1624
1624
  var __export = (target, all) => {
1625
1625
  for (var name in all)
@@ -1639,6 +1639,7 @@ __export(api_exports, {
1639
1639
  ContentTooLargeError: () => ContentTooLargeError,
1640
1640
  DocumentContextEvent: () => DocumentContextEvent,
1641
1641
  DocumentLookupRequest: () => DocumentLookupRequest,
1642
+ DocumentPatchRequest: () => DocumentPatchRequest,
1642
1643
  DocumentRequest: () => DocumentRequest,
1643
1644
  DocumentResponse: () => DocumentResponse,
1644
1645
  DoneEvent: () => DoneEvent,
@@ -1982,6 +1983,13 @@ var DocumentLookupRequest;
1982
1983
  Desc: "desc"
1983
1984
  };
1984
1985
  })(DocumentLookupRequest || (DocumentLookupRequest = {}));
1986
+ var DocumentPatchRequest;
1987
+ ((DocumentPatchRequest2) => {
1988
+ DocumentPatchRequest2.Status = {
1989
+ Active: "ACTIVE",
1990
+ Archived: "ARCHIVED"
1991
+ };
1992
+ })(DocumentPatchRequest || (DocumentPatchRequest = {}));
1985
1993
  var FileUploadRequest;
1986
1994
  ((FileUploadRequest2) => {
1987
1995
  FileUploadRequest2.IndexMode = {
@@ -1994,6 +2002,7 @@ var FileUploadRequest;
1994
2002
  var documents_exports = {};
1995
2003
  __export(documents_exports, {
1996
2004
  DocumentLookupRequest: () => DocumentLookupRequest,
2005
+ DocumentPatchRequest: () => DocumentPatchRequest,
1997
2006
  FileUploadRequest: () => FileUploadRequest,
1998
2007
  LookupDocumentsRequestOrder: () => LookupDocumentsRequestOrder
1999
2008
  });
@@ -4658,6 +4667,7 @@ var AuthClient = class {
4658
4667
  * @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
4659
4668
  *
4660
4669
  * @throws {@link Vectros.BadRequestError}
4670
+ * @throws {@link Vectros.PaymentRequiredError}
4661
4671
  * @throws {@link Vectros.ForbiddenError}
4662
4672
  * @throws {@link Vectros.TooManyRequestsError}
4663
4673
  *
@@ -4707,6 +4717,8 @@ var AuthClient = class {
4707
4717
  switch (_response.error.statusCode) {
4708
4718
  case 400:
4709
4719
  throw new BadRequestError(_response.error.body, _response.rawResponse);
4720
+ case 402:
4721
+ throw new PaymentRequiredError(_response.error.body, _response.rawResponse);
4710
4722
  case 403:
4711
4723
  throw new ForbiddenError(_response.error.body, _response.rawResponse);
4712
4724
  case 429:
@@ -6552,7 +6564,7 @@ var ComplianceClient = class {
6552
6564
  this._options = normalizeClientOptionsWithAuth(options);
6553
6565
  }
6554
6566
  /**
6555
- * Submits a right-to-erasure request for a single end-subject (a user, or an identity entity in any namespace). Erasure removes exactly the data the subject solely owns across the declared contexts, plus the subject's identity and lookup rows. It never touches another account's data and never cascades into another subject's data. The request is asynchronous: it returns 202 with a `requestId`; poll `GET /v1/erasure-requests/{id}` until the job completes to obtain the completion certificate. Requires a root API key — a scoped credential is rejected with 403.
6567
+ * Submits a right-to-erasure request for a single end-subject (a user, or an identity entity in any namespace). Erasure removes exactly the data the subject solely owns across the declared contexts, plus its identity and lookup rows when all contexts are covered. It never touches another account's data and never cascades into another subject's data. The request is asynchronous: it returns 202 with a `requestId`; poll `GET /v1/erasure-requests/{id}` until the job completes to obtain the completion certificate. Requires a root API key — a scoped credential is rejected with 403.
6556
6568
  *
6557
6569
  * @param {Vectros.ErasureRequest} request
6558
6570
  * @param {ComplianceClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6615,7 +6627,7 @@ var ComplianceClient = class {
6615
6627
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/erasure-requests");
6616
6628
  }
6617
6629
  /**
6618
- * Polls an erasure request by id. While the job is still running this returns its status only; once it completes, the response also includes the verifiable completion certificate (which contexts were swept, per-context deletion counts, and reports of dangling references and shared rows that were left intact). Requires a root API key.
6630
+ * Polls an erasure request by id. While the job is still running this returns its status only; once it completes, the response also includes the verifiable completion certificate (which contexts were swept, per-context deletion counts, whether the identity was kept, and reports of dangling references and shared rows left intact). Requires a root API key.
6619
6631
  *
6620
6632
  * @param {Vectros.GetErasureRequestRequest} request
6621
6633
  * @param {ComplianceClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6858,7 +6870,7 @@ var DocumentsClient = class {
6858
6870
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents");
6859
6871
  }
6860
6872
  /**
6861
- * Creates a document from a raw text string and queues it for asynchronous indexing so it becomes searchable. Optionally supply an `externalId` to make the create idempotent — if a document with the same `externalId` already exists in your context, that existing document is returned unchanged instead of a duplicate being created. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing document was returned) tells the two apart. To overwrite an existing document's content instead of returning it unchanged, set `?upsert=true` (this also requires the `documents:u` scope). Requires the `documents:c` scope to create. Being returned the existing document on a collision is a read of that document's data and additionally requires the `documents:r` scope — a credential holding `documents:c` alone receives a `400` ("already exists") on collision instead of the document.
6873
+ * Creates a document from a raw text string and queues it for asynchronous indexing so it becomes searchable. Optionally supply an `externalId` to make the create idempotent — if a document with the same `externalId` already exists in your context, that existing document is returned unchanged instead of a duplicate being created. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing document was returned) tells the two apart. To overwrite an existing document's content instead of returning it unchanged, set `?upsert=true` (this also requires the `documents:u` scope). Requires the `documents:c` scope to create. Being returned the existing document on a collision is a read of that document's data and additionally requires the `documents:r` scope — a credential holding `documents:c` alone receives a `400` ("already exists") on collision instead of the document. Supplying `externalId` WITHOUT `schemaId` is refused (`400`) unless you also pass `confirmUntyped=true` — externalId uniqueness is scoped per schema, so omitting `schemaId` by mistake would otherwise silently create a separate untyped document instead of targeting the typed one you likely meant.
6862
6874
  *
6863
6875
  * @param {Vectros.IngestDocumentRequest} request
6864
6876
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6878,10 +6890,11 @@ var DocumentsClient = class {
6878
6890
  return HttpResponsePromise.fromPromise(this.__ingestDocument(request, requestOptions));
6879
6891
  }
6880
6892
  async __ingestDocument(request, requestOptions) {
6881
- const { upsert, allowClear, body: _body } = request;
6893
+ const { upsert, allowClear, confirmUntyped, body: _body } = request;
6882
6894
  const _queryParams = {
6883
6895
  upsert,
6884
- allowClear
6896
+ allowClear,
6897
+ confirmUntyped
6885
6898
  };
6886
6899
  const _authRequest = await this._options.authProvider.getAuthRequest();
6887
6900
  const _headers = mergeHeaders(
@@ -7116,7 +7129,7 @@ var DocumentsClient = class {
7116
7129
  /**
7117
7130
  * Partially updates a document using an RFC 7386 JSON Merge Patch. The `payload` object is deep-merged: keys you send overwrite existing values (recursing into nested objects), a key set to `null` is deleted, and keys you omit are preserved — unlike PUT, which replaces the whole payload. Top-level fields (`title`, `folderId`, `schemaId`, ownership) are set when present and left unchanged when omitted; sending a top-level field as `null` is rejected. Supplying `text` re-ingests the document body (same as PUT). `indexMode`, `externalId`, and `storeText` (text retention is fixed at ingest) are immutable and rejected if present. The merged result is validated against the bound schema. Pass `expectedVersion` for optimistic concurrency (409 on conflict). Requires the `documents:u` scope.
7118
7131
  *
7119
- * @param {Vectros.PatchDocumentRequest} request
7132
+ * @param {Vectros.DocumentPatchRequest} request
7120
7133
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
7121
7134
  *
7122
7135
  * @throws {@link Vectros.BadRequestError}
@@ -7127,17 +7140,14 @@ var DocumentsClient = class {
7127
7140
  *
7128
7141
  * @example
7129
7142
  * await client.documents.patchDocument({
7130
- * id: "id",
7131
- * body: {
7132
- * title: "Patient Intake Form \u2014 Jane Doe"
7133
- * }
7143
+ * id: "id"
7134
7144
  * })
7135
7145
  */
7136
7146
  patchDocument(request, requestOptions) {
7137
7147
  return HttpResponsePromise.fromPromise(this.__patchDocument(request, requestOptions));
7138
7148
  }
7139
7149
  async __patchDocument(request, requestOptions) {
7140
- const { id, body: _body } = request;
7150
+ const { id, ..._body } = request;
7141
7151
  const _authRequest = await this._options.authProvider.getAuthRequest();
7142
7152
  const _headers = mergeHeaders(
7143
7153
  _authRequest.headers,
@@ -7509,7 +7519,7 @@ var DocumentsClient = class {
7509
7519
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/versions");
7510
7520
  }
7511
7521
  /**
7512
- * Starts a file-based document by returning a short-lived presigned S3 PUT URL. Upload the file bytes directly to `uploadUrl`; the document is then automatically queued for text extraction and asynchronous indexing. Supplying an `externalId` makes this idempotent — re-initiating an upload with the same `externalId` re-issues a fresh presigned URL for the SAME existing document, targeting a newly-staged object rather than the document's current one — your PUT lands there first, and the document only adopts it once the upload is validated (so a re-upload inherently replaces the file body) rather than creating a duplicate. The response's `created` field (and the HTTP status — 201 when a new document was minted, 200 when an existing one was matched) tells the two apart. With `?upsert=true`, the submitted `payload`/`title` are also applied to the matched document (file-body divergence cannot be diffed at upload-init — the bytes have not arrived yet — so the re-upload itself replaces the body). Creating a NEW document requires the `documents:c` scope. Re-uploading over an EXISTING document overwrites (and re-indexes) its body, so it is an update: it requires the `documents:u` scope (as does `?upsert=true` for the metadata). **Your PUT to `uploadUrl` MUST include the header named in the response's `requiredHeaderName`, set to `requiredHeaderValue` exactly.** It is a signed part of the presigned request — the PUT never reaches this service either way, so neither failure uses this API's JSON error shape. Omitting it, or sending a different value, invalidates the request's signature and S3 rejects it with a 403 `SignatureDoesNotMatch`. Sending it correctly makes the URL single-use: `requiredHeaderName` is always `If-None-Match` and `requiredHeaderValue` is always `*` — a create, a recovery upload for a document whose earlier file is missing, and a re-upload ALL target a freshly-minted, never-written key, so the same S3 conditional-write precondition applies uniformly (S3's own documented conditional-write behavior): a replay after the object already exists (from your own completed PUT, or anyone else's) fails with `412 Precondition Failed`; a replay after the object was deleted and never re-created finds an absent key again and can succeed — single-use is a property of the object's existence, not a one-time token. **Either precondition can also fail with `409 Conflict` if your PUT genuinely races a concurrent delete on the same object.** Whichever of `412` or `409` you receive, the remedy is the same: call this endpoint again for a fresh URL rather than retrying the same PUT — a fresh call always targets a new key, so it is never subject to whatever raced the previous one.
7522
+ * Starts a file-based document by returning a short-lived presigned S3 PUT URL. Upload the file bytes directly to `uploadUrl`; the document is then automatically queued for text extraction and asynchronous indexing. Supplying an `externalId` makes this idempotent — re-initiating an upload with the same `externalId` re-issues a fresh presigned URL for the SAME existing document, targeting a newly-staged object rather than the document's current one — your PUT lands there first, and the document only adopts it once the upload is validated (so a re-upload inherently replaces the file body) rather than creating a duplicate. The response's `created` field (and the HTTP status — 201 when a new document was minted, 200 when an existing one was matched) tells the two apart. With `?upsert=true`, the submitted `payload`/`title` are also applied to the matched document (file-body divergence cannot be diffed at upload-init — the bytes have not arrived yet — so the re-upload itself replaces the body). Creating a NEW document requires the `documents:c` scope. Re-uploading over an EXISTING document overwrites (and re-indexes) its body, so it is an update: it requires the `documents:u` scope (as does `?upsert=true` for the metadata). **Your PUT to `uploadUrl` MUST include the header named in the response's `requiredHeaderName`, set to `requiredHeaderValue` exactly.** It is a signed part of the presigned request — the PUT never reaches this service either way, so neither failure uses this API's JSON error shape. Omitting it, or sending a different value, invalidates the request's signature and S3 rejects it with a 403 `SignatureDoesNotMatch`. Sending it correctly makes the URL single-use: `requiredHeaderName` is always `If-None-Match` and `requiredHeaderValue` is always `*` — a create, a recovery upload for a document whose earlier file is missing, and a re-upload ALL target a freshly-minted, never-written key, so the same S3 conditional-write precondition applies uniformly (S3's own documented conditional-write behavior): a replay after the object already exists (from your own completed PUT, or anyone else's) fails with `412 Precondition Failed`; a replay after the object was deleted and never re-created finds an absent key again and can succeed — single-use is a property of the object's existence, not a one-time token. **Either precondition can also fail with `409 Conflict` if your PUT genuinely races a concurrent delete on the same object.** Whichever of `412` or `409` you receive, the remedy is the same: call this endpoint again for a fresh URL rather than retrying the same PUT — a fresh call always targets a new key, so it is never subject to whatever raced the previous one. Supplying `externalId` WITHOUT `schemaId` is refused (`400`) unless you also pass `confirmUntyped=true` — externalId uniqueness is scoped per schema, so omitting `schemaId` by mistake would otherwise silently create a separate untyped document instead of targeting the typed one you likely meant.
7513
7523
  *
7514
7524
  * @param {Vectros.FileUploadRequest} request
7515
7525
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -7528,9 +7538,10 @@ var DocumentsClient = class {
7528
7538
  return HttpResponsePromise.fromPromise(this.__uploadDocument(request, requestOptions));
7529
7539
  }
7530
7540
  async __uploadDocument(request, requestOptions) {
7531
- const { upsert, ..._body } = request;
7541
+ const { upsert, confirmUntyped, ..._body } = request;
7532
7542
  const _queryParams = {
7533
- upsert
7543
+ upsert,
7544
+ confirmUntyped
7534
7545
  };
7535
7546
  const _authRequest = await this._options.authProvider.getAuthRequest();
7536
7547
  const _headers = mergeHeaders(
@@ -12546,7 +12557,11 @@ var BlueprintIssuerSchema = z.object({
12546
12557
  * actually scoped. An unverified domain fails the apply with the platform's `400`.
12547
12558
  *
12548
12559
  * Omit to register a domain-less issuer. Omitting it on a re-apply leaves an existing scope
12549
- * unchanged; removing a scope is `vectros issuers update --clear-restricted-to-domain`.
12560
+ * unchanged. On platform 0.45.0 and later a scope is removed only from a registration that
12561
+ * already holds the unrestricted `(issuer, audience)` pair, which one created with a domain
12562
+ * normally does not (`vectros issuers update --clear-restricted-to-domain` is refused for it):
12563
+ * replace it with a new issuer declared without `restrictedToDomain` and verify that, under a
12564
+ * different app context if the old issuer has served users.
12550
12565
  */
12551
12566
  restrictedToDomain: z.string().regex(RESTRICTED_DOMAIN_RE, {
12552
12567
  message: "restrictedToDomain must be a lowercase DNS name such as 'acme.com' \u2014 letters, digits and dashes in dot-separated labels, at least two labels, no scheme, path, port or uppercase; write an internationalized domain in its punycode (xn--\u2026) form"
@@ -15660,7 +15675,7 @@ async function devRouteError(res, action) {
15660
15675
  }
15661
15676
  function formatCliError(err, opts) {
15662
15677
  const info = extractServerError(err);
15663
- const actionable = renderActionableError(info);
15678
+ const actionable = renderActionableError(info, opts.notFoundHint);
15664
15679
  const block = actionable ?? ` \u2716 ${opts.action}: ${info.message}
15665
15680
  `;
15666
15681
  const debug = opts.debug ?? Boolean(process.env.VECTROS_MCP_DEBUG);
@@ -15674,7 +15689,7 @@ function formatCliError(err, opts) {
15674
15689
  }
15675
15690
  return block;
15676
15691
  }
15677
- function renderActionableError(info) {
15692
+ function renderActionableError(info, notFoundHint) {
15678
15693
  const msg = info.message;
15679
15694
  switch (info.errorCode) {
15680
15695
  case "SESSION_REFRESH_REQUIRED":
@@ -15712,7 +15727,7 @@ function renderActionableError(info) {
15712
15727
  }
15713
15728
  if (info.statusCode === 404) {
15714
15729
  return ` \u2716 ${msg}
15715
- Check the id \u2014 'vectros context list' enumerates the contexts you can reach.
15730
+ Check the id \u2014 ${notFoundHint ?? "'vectros context list' enumerates the contexts you can reach."}
15716
15731
  `;
15717
15732
  }
15718
15733
  if (/migration-locked|cannot be (changed|modified)|immutable/i.test(msg) && /schema|field|lookup|type/i.test(msg)) {
@@ -19270,8 +19285,8 @@ async function withIndexLock(dir, fn, timings = LOCK_OPTS) {
19270
19285
  // sections are ~1ms, so in practice the holder is gone before the first tick
19271
19286
  // and nothing is ever detected. (The probe that observed the no-op ran at
19272
19287
  // stale:2000 with the section artificially held open — a configuration we do
19273
- // not ship. A measurement in a config you don't ship is not evidence:
19274
- // CONVENTIONS 78, whose first worked example is this very comment.) The
19288
+ // not ship, and a measurement taken in a configuration you don't ship is not
19289
+ // evidence about the configuration you do.) The
19275
19290
  // honest shape: our release runs unconditionally, and after a stale-break
19276
19291
  // collision it CAN remove a successor's fresh lock — one more route to two
19277
19292
  // writers at once, on top of the rmdir race below. The backstop for both is
@@ -24313,12 +24328,12 @@ function parseRestrictedToDomain(raw) {
24313
24328
  const domain = raw.trim();
24314
24329
  if (domain.length === 0) {
24315
24330
  throw new Error(
24316
- "--restricted-to-domain must be a non-blank domain (e.g. 'acme.com'). To remove the scope from an existing issuer, use --clear-restricted-to-domain."
24331
+ "--restricted-to-domain must be a non-blank domain (e.g. 'acme.com'). To remove the scope from an existing issuer, use --clear-restricted-to-domain (the platform refuses that unless the registration already holds the unrestricted (issuer, audience) pair)."
24317
24332
  );
24318
24333
  }
24319
24334
  if (!isRestrictedToDomainName(domain.toLowerCase())) {
24320
24335
  throw new Error(
24321
- `--restricted-to-domain must be a DNS name such as 'acme.com' \u2014 letters, digits and dashes in dot-separated labels, at least two labels, no scheme, path or port (write an internationalized domain in its punycode xn-- form); got '${domain}'. To remove the scope from an existing issuer, use --clear-restricted-to-domain.`
24336
+ `--restricted-to-domain must be a DNS name such as 'acme.com' \u2014 letters, digits and dashes in dot-separated labels, at least two labels, no scheme, path or port (write an internationalized domain in its punycode xn-- form); got '${domain}'. To remove the scope from an existing issuer, use --clear-restricted-to-domain (the platform refuses that unless the registration already holds the unrestricted (issuer, audience) pair).`
24322
24337
  );
24323
24338
  }
24324
24339
  return domain;
@@ -24771,6 +24786,541 @@ ${renderIssuer(issuer)}
24771
24786
  });
24772
24787
  }
24773
24788
 
24789
+ // src/commands/provider-config.ts
24790
+ import { createReadStream as createReadStream2 } from "fs";
24791
+ import * as readline6 from "readline/promises";
24792
+ var PROVIDER_TYPES = ["ANTHROPIC_NATIVE", "OPENAI_COMPATIBLE"];
24793
+ var BILLING_MODES = ["PLATFORM_BILLED", "CUSTOMER_DIRECT"];
24794
+ var STATUSES = ["ACTIVE", "DISABLED"];
24795
+ var MAX_SECRET_BYTES = 8 * 1024;
24796
+ async function readBoundedSecret(stream) {
24797
+ try {
24798
+ return await readAllFrom(stream, MAX_SECRET_BYTES);
24799
+ } catch (err) {
24800
+ if (err instanceof TokenTooLargeError) {
24801
+ throw new Error(
24802
+ `the input is larger than ${MAX_SECRET_BYTES / 1024} KB, which no API key is; nothing was read further and nothing was sent.`
24803
+ );
24804
+ }
24805
+ throw err;
24806
+ }
24807
+ }
24808
+ function fileFailureReason2(err) {
24809
+ switch (err?.code) {
24810
+ case "ENOENT":
24811
+ return "no such file.";
24812
+ case "EISDIR":
24813
+ return "that is a directory.";
24814
+ case "EACCES":
24815
+ case "EPERM":
24816
+ return "permission denied.";
24817
+ default:
24818
+ return "it could not be read.";
24819
+ }
24820
+ }
24821
+ async function resolveApiKeySecret(fileFlag, deps, mode) {
24822
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
24823
+ const readStdin = deps.readStdin ?? (() => readBoundedSecret(process.stdin));
24824
+ const readTextFile = deps.readTextFile ?? ((path4) => readBoundedSecret(createReadStream2(path4)));
24825
+ let raw;
24826
+ if (fileFlag !== void 0 && fileFlag !== "-") {
24827
+ if (looksLikeCredential(fileFlag)) {
24828
+ throw new Error(
24829
+ "--api-key-secret-file takes the PATH of a file holding the secret, but the value given looks like a secret (or is too long to be a path). Save it to a file and pass that path (for a file in this directory, write ./name), or pipe it on stdin with --api-key-secret-file -."
24830
+ );
24831
+ }
24832
+ try {
24833
+ raw = await readTextFile(fileFlag);
24834
+ } catch (err) {
24835
+ const name = safeBaseName(fileFlag);
24836
+ throw new Error(
24837
+ `could not read the file given to --api-key-secret-file${name ? ` (${name})` : ""}: ${fileFailureReason2(err)}`
24838
+ );
24839
+ }
24840
+ } else if (fileFlag === "-") {
24841
+ if (isTty) {
24842
+ throw new Error(
24843
+ "stdin is a terminal, so --api-key-secret-file - would have you paste the secret where it is displayed. Pipe it instead (some-command | vectros provider-config \u2026), or save it to a file and pass --api-key-secret-file <path>."
24844
+ );
24845
+ }
24846
+ raw = await readStdin();
24847
+ } else if (mode === "required" && !isTty) {
24848
+ process.stderr.write(" \u2026 no --api-key-secret-file given: reading the secret from stdin.\n");
24849
+ raw = await readStdin();
24850
+ } else if (mode === "required") {
24851
+ throw new Error(
24852
+ "apiKeySecret is required. Save it to a file and pass --api-key-secret-file <path>, or pipe it on stdin (some-command | vectros provider-config create \u2026)."
24853
+ );
24854
+ } else {
24855
+ return void 0;
24856
+ }
24857
+ const secret = raw.trim();
24858
+ if (secret.length === 0) throw new Error("the secret is empty.");
24859
+ return secret;
24860
+ }
24861
+ function renderProviderConfig(c) {
24862
+ return formatKeyValues([
24863
+ ["id", c.id],
24864
+ ["tenantId", c.tenantId],
24865
+ ["alias", c.alias],
24866
+ ["providerType", c.providerType],
24867
+ ["endpoint", c.endpoint],
24868
+ ["declaredProcessingRegion", c.declaredProcessingRegion],
24869
+ ["defaultProviderModelId", c.defaultProviderModelId],
24870
+ ["waiverType", c.waiverType],
24871
+ ["billingMode", c.billingMode],
24872
+ ["platformTokenFactor", c.platformTokenFactor],
24873
+ ["platformOutputWeight", c.platformOutputWeight],
24874
+ ["status", c.status],
24875
+ ["createdAt", c.createdAt]
24876
+ ]);
24877
+ }
24878
+ function invalidEnum(flag, value, allowed) {
24879
+ return `${flag} must be one of ${allowed.join(", ")} (got '${value}').`;
24880
+ }
24881
+ var NOT_FOUND_HINT = "'vectros provider-config list --tenant <test|live>' enumerates configs in a tenant.";
24882
+ async function runProviderConfigCreate(opts, deps = {}) {
24883
+ if (!PROVIDER_TYPES.includes(opts.providerType)) {
24884
+ process.stderr.write(` \u2716 ${invalidEnum("--provider-type", opts.providerType, PROVIDER_TYPES)}
24885
+ `);
24886
+ return 2;
24887
+ }
24888
+ if (!BILLING_MODES.includes(opts.billingMode)) {
24889
+ process.stderr.write(` \u2716 ${invalidEnum("--billing-mode", opts.billingMode, BILLING_MODES)}
24890
+ `);
24891
+ return 2;
24892
+ }
24893
+ if (opts.status !== void 0 && !STATUSES.includes(opts.status)) {
24894
+ process.stderr.write(` \u2716 ${invalidEnum("--status", opts.status, STATUSES)}
24895
+ `);
24896
+ return 2;
24897
+ }
24898
+ if (opts.billingMode === "PLATFORM_BILLED") {
24899
+ if (opts.platformTokenFactor === void 0 || opts.platformOutputWeight === void 0) {
24900
+ process.stderr.write(
24901
+ " \u2716 --platform-token-factor and --platform-output-weight are required when --billing-mode PLATFORM_BILLED.\n"
24902
+ );
24903
+ return 2;
24904
+ }
24905
+ } else if (opts.platformTokenFactor !== void 0 || opts.platformOutputWeight !== void 0) {
24906
+ process.stderr.write(
24907
+ " \u2716 --platform-token-factor/--platform-output-weight only apply with --billing-mode PLATFORM_BILLED.\n"
24908
+ );
24909
+ return 2;
24910
+ }
24911
+ let apiKeySecret;
24912
+ try {
24913
+ apiKeySecret = await resolveApiKeySecret(opts.apiKeySecretFile, deps, "required");
24914
+ } catch (err) {
24915
+ process.stderr.write(` \u2716 ${formatError(err)}
24916
+ `);
24917
+ return 2;
24918
+ }
24919
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
24920
+ const fetchImpl = deps.fetchImpl ?? fetch;
24921
+ try {
24922
+ const tenantId = requireTenantId(auth);
24923
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs`, {
24924
+ method: "POST",
24925
+ headers: { Authorization: `Bearer ${auth.cognitoToken}`, "Content-Type": "application/json" },
24926
+ body: JSON.stringify({
24927
+ tenantId,
24928
+ alias: opts.alias,
24929
+ providerType: opts.providerType,
24930
+ endpoint: opts.endpoint,
24931
+ declaredProcessingRegion: opts.declaredProcessingRegion,
24932
+ defaultProviderModelId: opts.defaultProviderModelId,
24933
+ apiKeySecret,
24934
+ waiverType: opts.waiverType,
24935
+ billingMode: opts.billingMode,
24936
+ platformTokenFactor: opts.platformTokenFactor,
24937
+ platformOutputWeight: opts.platformOutputWeight,
24938
+ status: opts.status
24939
+ })
24940
+ });
24941
+ if (!res.ok) throw await devRouteError(res, "provider-config create");
24942
+ const config = await res.json();
24943
+ if (opts.json) {
24944
+ process.stdout.write(`${formatJson(config)}
24945
+ `);
24946
+ return 0;
24947
+ }
24948
+ process.stdout.write(`
24949
+ \u2714 provider config '${opts.alias}' created
24950
+ ${renderProviderConfig(config)}
24951
+ `);
24952
+ return 0;
24953
+ } catch (err) {
24954
+ process.stderr.write(formatCliError(err, { action: "provider-config create failed" }));
24955
+ return 1;
24956
+ }
24957
+ });
24958
+ }
24959
+ async function runProviderConfigList(opts, deps = {}) {
24960
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
24961
+ const fetchImpl = deps.fetchImpl ?? fetch;
24962
+ try {
24963
+ const tenantId = requireTenantId(auth);
24964
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs?tenantId=${encodeURIComponent(tenantId)}`;
24965
+ const res = await fetchImpl(url, { method: "GET", headers: { Authorization: `Bearer ${auth.cognitoToken}` } });
24966
+ if (!res.ok) throw await devRouteError(res, "provider-config list");
24967
+ const rows = await res.json();
24968
+ if (opts.json) {
24969
+ process.stdout.write(`${formatJson(rows)}
24970
+ `);
24971
+ return 0;
24972
+ }
24973
+ process.stdout.write(
24974
+ "\n" + formatTable(rows, [
24975
+ { header: "id", get: (c) => c.id },
24976
+ { header: "alias", get: (c) => c.alias },
24977
+ { header: "provider type", get: (c) => c.providerType },
24978
+ { header: "billing mode", get: (c) => c.billingMode },
24979
+ { header: "status", get: (c) => c.status }
24980
+ ]) + "\n"
24981
+ );
24982
+ return 0;
24983
+ } catch (err) {
24984
+ process.stderr.write(formatCliError(err, { action: "provider-config list failed" }));
24985
+ return 1;
24986
+ }
24987
+ });
24988
+ }
24989
+ async function runProviderConfigGet(opts, deps = {}) {
24990
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
24991
+ const fetchImpl = deps.fetchImpl ?? fetch;
24992
+ try {
24993
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs/${encodeURIComponent(opts.id)}`;
24994
+ const res = await fetchImpl(url, { method: "GET", headers: { Authorization: `Bearer ${auth.cognitoToken}` } });
24995
+ if (!res.ok) throw await devRouteError(res, "provider-config get");
24996
+ const config = await res.json();
24997
+ if (opts.json) {
24998
+ process.stdout.write(`${formatJson(config)}
24999
+ `);
25000
+ return 0;
25001
+ }
25002
+ process.stdout.write(`
25003
+ ${renderProviderConfig(config)}
25004
+ `);
25005
+ return 0;
25006
+ } catch (err) {
25007
+ process.stderr.write(formatCliError(err, { action: "provider-config get failed", notFoundHint: NOT_FOUND_HINT }));
25008
+ return 1;
25009
+ }
25010
+ });
25011
+ }
25012
+ async function runProviderConfigUpdate(opts, deps = {}) {
25013
+ if (opts.providerType !== void 0 && !PROVIDER_TYPES.includes(opts.providerType)) {
25014
+ process.stderr.write(` \u2716 ${invalidEnum("--provider-type", opts.providerType, PROVIDER_TYPES)}
25015
+ `);
25016
+ return 2;
25017
+ }
25018
+ if (opts.billingMode !== void 0 && !BILLING_MODES.includes(opts.billingMode)) {
25019
+ process.stderr.write(` \u2716 ${invalidEnum("--billing-mode", opts.billingMode, BILLING_MODES)}
25020
+ `);
25021
+ return 2;
25022
+ }
25023
+ if (opts.status !== void 0 && !STATUSES.includes(opts.status)) {
25024
+ process.stderr.write(` \u2716 ${invalidEnum("--status", opts.status, STATUSES)}
25025
+ `);
25026
+ return 2;
25027
+ }
25028
+ let apiKeySecret;
25029
+ try {
25030
+ apiKeySecret = await resolveApiKeySecret(opts.apiKeySecretFile, deps, "optional");
25031
+ } catch (err) {
25032
+ process.stderr.write(` \u2716 ${formatError(err)}
25033
+ `);
25034
+ return 2;
25035
+ }
25036
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25037
+ const fetchImpl = deps.fetchImpl ?? fetch;
25038
+ try {
25039
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs/${encodeURIComponent(opts.id)}`;
25040
+ const res = await fetchImpl(url, {
25041
+ method: "PUT",
25042
+ headers: { Authorization: `Bearer ${auth.cognitoToken}`, "Content-Type": "application/json" },
25043
+ body: JSON.stringify({
25044
+ alias: opts.alias,
25045
+ providerType: opts.providerType,
25046
+ endpoint: opts.endpoint,
25047
+ declaredProcessingRegion: opts.declaredProcessingRegion,
25048
+ defaultProviderModelId: opts.defaultProviderModelId,
25049
+ apiKeySecret,
25050
+ waiverType: opts.waiverType,
25051
+ billingMode: opts.billingMode,
25052
+ platformTokenFactor: opts.platformTokenFactor,
25053
+ platformOutputWeight: opts.platformOutputWeight,
25054
+ status: opts.status
25055
+ })
25056
+ });
25057
+ if (!res.ok) throw await devRouteError(res, "provider-config update");
25058
+ const config = await res.json();
25059
+ if (opts.json) {
25060
+ process.stdout.write(`${formatJson(config)}
25061
+ `);
25062
+ return 0;
25063
+ }
25064
+ process.stdout.write(`
25065
+ \u2714 provider config '${opts.id}' updated
25066
+ ${renderProviderConfig(config)}
25067
+ `);
25068
+ return 0;
25069
+ } catch (err) {
25070
+ process.stderr.write(formatCliError(err, { action: "provider-config update failed", notFoundHint: NOT_FOUND_HINT }));
25071
+ return 1;
25072
+ }
25073
+ });
25074
+ }
25075
+ async function runProviderConfigDelete(opts, deps = {}) {
25076
+ const { id } = opts;
25077
+ if (!opts.force) {
25078
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
25079
+ if (!isTty) {
25080
+ process.stderr.write(
25081
+ ` \u2716 provider-config delete needs an interactive confirmation.
25082
+ Re-run with --force to delete '${id}' without a prompt.
25083
+ `
25084
+ );
25085
+ return 2;
25086
+ }
25087
+ const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
25088
+ const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
25089
+ return { prompt: (q) => rl.question(q), close: () => rl.close() };
25090
+ })();
25091
+ try {
25092
+ process.stdout.write(
25093
+ `
25094
+ \u26A0 Deleting provider config '${id}' removes it permanently. Any inference call that resolves
25095
+ a provider by this config's alias starts failing immediately. To disable it instead (reversible),
25096
+ run \`vectros provider-config update ${id} --status DISABLED\`.
25097
+
25098
+ `
25099
+ );
25100
+ const typed = await promptCtx.prompt(` Type the config id ('${id}') to confirm: `);
25101
+ if (typed.trim() !== id) {
25102
+ process.stderr.write(` \u2716 Confirmation did not match \u2014 nothing deleted.
25103
+ `);
25104
+ return 1;
25105
+ }
25106
+ } finally {
25107
+ promptCtx.close();
25108
+ }
25109
+ }
25110
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25111
+ const fetchImpl = deps.fetchImpl ?? fetch;
25112
+ try {
25113
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs/${encodeURIComponent(id)}`;
25114
+ const res = await fetchImpl(url, { method: "DELETE", headers: { Authorization: `Bearer ${auth.cognitoToken}` } });
25115
+ if (!res.ok) throw await devRouteError(res, "provider-config delete");
25116
+ if (opts.json) {
25117
+ process.stdout.write(`${formatJson({ id, deleted: true })}
25118
+ `);
25119
+ return 0;
25120
+ }
25121
+ process.stdout.write(`
25122
+ \u2714 provider config '${id}' deleted
25123
+ `);
25124
+ return 0;
25125
+ } catch (err) {
25126
+ process.stderr.write(formatCliError(err, { action: "provider-config delete failed", notFoundHint: NOT_FOUND_HINT }));
25127
+ return 1;
25128
+ }
25129
+ });
25130
+ }
25131
+
25132
+ // src/commands/domains.ts
25133
+ import * as readline7 from "readline/promises";
25134
+ function renderDomainVerifyResult(d) {
25135
+ return formatKeyValues([
25136
+ ["id", d.id],
25137
+ ["domain", d.domain],
25138
+ ["status", d.status]
25139
+ ]);
25140
+ }
25141
+ var NOT_FOUND_HINT2 = "'vectros domains list' enumerates your registered domains.";
25142
+ async function runDomainsRegister(opts, deps = {}) {
25143
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25144
+ const fetchImpl = deps.fetchImpl ?? fetch;
25145
+ try {
25146
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/domains`, {
25147
+ method: "POST",
25148
+ headers: { Authorization: `Bearer ${auth.cognitoToken}`, "Content-Type": "application/json" },
25149
+ body: JSON.stringify({ domain: opts.domain })
25150
+ });
25151
+ if (res.status === 409) {
25152
+ const raw = await res.text().catch(() => "");
25153
+ let message = "Domain already registered";
25154
+ let existingId;
25155
+ let existingStatus;
25156
+ try {
25157
+ const parsed = JSON.parse(raw);
25158
+ if (typeof parsed.message === "string" && parsed.message.trim()) message = parsed.message.trim();
25159
+ if (typeof parsed.id === "string") existingId = parsed.id;
25160
+ if (typeof parsed.status === "string") existingStatus = parsed.status;
25161
+ } catch {
25162
+ }
25163
+ if (opts.json) {
25164
+ process.stdout.write(`${formatJson({ message, id: existingId, status: existingStatus })}
25165
+ `);
25166
+ return 1;
25167
+ }
25168
+ process.stderr.write(
25169
+ ` \u2716 ${message}${existingId ? ` (id: ${existingId}${existingStatus ? `, status: ${existingStatus}` : ""})` : ""}
25170
+ ` + (existingStatus === "PENDING" && existingId ? ` Still pending verification. Run: vectros domains verify ${existingId}
25171
+ ` : " Run `vectros domains list` to find it.\n")
25172
+ );
25173
+ return 1;
25174
+ }
25175
+ if (!res.ok) throw await devRouteError(res, "domains register");
25176
+ const result = await res.json();
25177
+ if (opts.json) {
25178
+ process.stdout.write(`${formatJson(result)}
25179
+ `);
25180
+ return 0;
25181
+ }
25182
+ process.stdout.write(
25183
+ `
25184
+ \u2714 domain '${result.domain ?? opts.domain}' registered (id: ${result.id ?? "?"}, status: ${result.status ?? "PENDING"})
25185
+
25186
+ ${result.instructions ?? `Add a DNS TXT record: _vectros-verify.${result.domain ?? opts.domain} \u2192 "${result.verificationToken ?? ""}"`}
25187
+
25188
+ Once the record is published, run:
25189
+ vectros domains verify ${result.id ?? "<id>"}
25190
+ `
25191
+ );
25192
+ return 0;
25193
+ } catch (err) {
25194
+ process.stderr.write(formatCliError(err, { action: "domains register failed" }));
25195
+ return 1;
25196
+ }
25197
+ });
25198
+ }
25199
+ async function runDomainsList(opts, deps = {}) {
25200
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25201
+ const fetchImpl = deps.fetchImpl ?? fetch;
25202
+ try {
25203
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/domains`, {
25204
+ method: "GET",
25205
+ headers: { Authorization: `Bearer ${auth.cognitoToken}` }
25206
+ });
25207
+ if (!res.ok) throw await devRouteError(res, "domains list");
25208
+ const rows = await res.json();
25209
+ if (opts.json) {
25210
+ process.stdout.write(`${formatJson(rows)}
25211
+ `);
25212
+ return 0;
25213
+ }
25214
+ process.stdout.write(
25215
+ "\n" + formatTable(rows, [
25216
+ { header: "id", get: (d) => d.id },
25217
+ { header: "domain", get: (d) => d.domain },
25218
+ { header: "status", get: (d) => d.status },
25219
+ { header: "verified at", get: (d) => d.verifiedAt }
25220
+ ]) + "\n"
25221
+ );
25222
+ return 0;
25223
+ } catch (err) {
25224
+ process.stderr.write(formatCliError(err, { action: "domains list failed" }));
25225
+ return 1;
25226
+ }
25227
+ });
25228
+ }
25229
+ async function runDomainsDelete(opts, deps = {}) {
25230
+ const { id } = opts;
25231
+ if (!opts.force) {
25232
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
25233
+ if (!isTty) {
25234
+ process.stderr.write(
25235
+ ` \u2716 domains delete needs an interactive confirmation.
25236
+ Re-run with --force to delete '${id}' without a prompt.
25237
+ `
25238
+ );
25239
+ return 2;
25240
+ }
25241
+ const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
25242
+ const rl = readline7.createInterface({ input: process.stdin, output: process.stdout });
25243
+ return { prompt: (q) => rl.question(q), close: () => rl.close() };
25244
+ })();
25245
+ try {
25246
+ process.stdout.write(
25247
+ `
25248
+ \u26A0 Deleting domain '${id}' removes its proof-of-control record. The platform refuses this while
25249
+ any active webhook still references it \u2014 disable or delete those first if this fails.
25250
+
25251
+ `
25252
+ );
25253
+ const typed = await promptCtx.prompt(` Type the domain id ('${id}') to confirm: `);
25254
+ if (typed.trim() !== id) {
25255
+ process.stderr.write(` \u2716 Confirmation did not match \u2014 nothing deleted.
25256
+ `);
25257
+ return 1;
25258
+ }
25259
+ } finally {
25260
+ promptCtx.close();
25261
+ }
25262
+ }
25263
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25264
+ const fetchImpl = deps.fetchImpl ?? fetch;
25265
+ try {
25266
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/domains/${encodeURIComponent(id)}`, {
25267
+ method: "DELETE",
25268
+ headers: { Authorization: `Bearer ${auth.cognitoToken}` }
25269
+ });
25270
+ if (!res.ok) throw await devRouteError(res, "domains delete");
25271
+ if (opts.json) {
25272
+ process.stdout.write(`${formatJson({ id, deleted: true })}
25273
+ `);
25274
+ return 0;
25275
+ }
25276
+ process.stdout.write(`
25277
+ \u2714 domain '${id}' deleted
25278
+ `);
25279
+ return 0;
25280
+ } catch (err) {
25281
+ process.stderr.write(formatCliError(err, { action: "domains delete failed", notFoundHint: NOT_FOUND_HINT2 }));
25282
+ return 1;
25283
+ }
25284
+ });
25285
+ }
25286
+ async function runDomainsVerify(opts, deps = {}) {
25287
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25288
+ const fetchImpl = deps.fetchImpl ?? fetch;
25289
+ try {
25290
+ const res = await fetchImpl(
25291
+ `${auth.baseUrl.replace(/\/$/, "")}/developer/domains/${encodeURIComponent(opts.id)}/verify`,
25292
+ { method: "POST", headers: { Authorization: `Bearer ${auth.cognitoToken}` } }
25293
+ );
25294
+ if (!res.ok) throw await devRouteError(res, "domains verify");
25295
+ const result = await res.json();
25296
+ const verified = result.verified === true && result.status === "VERIFIED";
25297
+ if (opts.json) {
25298
+ process.stdout.write(`${formatJson(result)}
25299
+ `);
25300
+ return verified ? 0 : 1;
25301
+ }
25302
+ if (!verified) {
25303
+ process.stderr.write(
25304
+ ` \u2716 domain '${result.domain ?? opts.id}' is not verified (status: ${result.status ?? "(none)"}).
25305
+ Check the DNS TXT record is published, allow time for it to propagate, then re-run this command.
25306
+ `
25307
+ );
25308
+ return 1;
25309
+ }
25310
+ process.stdout.write(
25311
+ `
25312
+ \u2714 domain '${result.domain ?? opts.id}' verified.
25313
+ ${renderDomainVerifyResult(result)}
25314
+ `
25315
+ );
25316
+ return 0;
25317
+ } catch (err) {
25318
+ process.stderr.write(formatCliError(err, { action: "domains verify failed", notFoundHint: NOT_FOUND_HINT2 }));
25319
+ return 1;
25320
+ }
25321
+ });
25322
+ }
25323
+
24774
25324
  // src/commands/namespace.ts
24775
25325
  function renderNamespace(n) {
24776
25326
  return formatKeyValues([
@@ -24875,7 +25425,7 @@ ${renderNamespace(ns)}
24875
25425
 
24876
25426
  // src/commands/scripts.ts
24877
25427
  import { readFile as readFile3 } from "fs/promises";
24878
- import * as readline6 from "readline/promises";
25428
+ import * as readline8 from "readline/promises";
24879
25429
  var SOURCE_MAX_BYTES = 3e5;
24880
25430
  var INPUT_CONTRACT_MAX_BYTES = 5e4;
24881
25431
  var utf8Bytes2 = (s) => new TextEncoder().encode(s).length;
@@ -25094,7 +25644,7 @@ async function runScriptsDelete(opts, deps = {}) {
25094
25644
  return 2;
25095
25645
  }
25096
25646
  const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
25097
- const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
25647
+ const rl = readline8.createInterface({ input: process.stdin, output: process.stdout });
25098
25648
  return { prompt: (q) => rl.question(q), close: () => rl.close() };
25099
25649
  })();
25100
25650
  try {
@@ -26253,9 +26803,9 @@ function emitJoined(opts) {
26253
26803
 
26254
26804
  // src/build-info.ts
26255
26805
  var BUILD_INFO = {
26256
- cli: true ? "0.23.0" : "dev",
26257
- sdk: true ? "0.45.0" : "dev",
26258
- blueprints: true ? "0.20.0" : "dev"
26806
+ cli: true ? "0.24.0" : "dev",
26807
+ sdk: true ? "0.46.0" : "dev",
26808
+ blueprints: true ? "0.20.1" : "dev"
26259
26809
  };
26260
26810
  function formatBuildInfo() {
26261
26811
  return `vectros ${BUILD_INFO.cli} (sdk ${BUILD_INFO.sdk}, blueprints ${BUILD_INFO.blueprints})`;
@@ -26292,6 +26842,18 @@ function parseTenantFlag(raw) {
26292
26842
  }
26293
26843
  return raw;
26294
26844
  }
26845
+ var NUMBER_FLAG_INVALID = /* @__PURE__ */ Symbol("parseOptionalNumberFlag:invalid");
26846
+ function parseOptionalNumberFlag(flag, raw) {
26847
+ if (raw === void 0) return void 0;
26848
+ const n = Number(raw);
26849
+ if (!Number.isFinite(n)) {
26850
+ process.stderr.write(` \u2716 ${flag} must be a number (got '${raw}')
26851
+ `);
26852
+ process.exitCode = 2;
26853
+ return NUMBER_FLAG_INVALID;
26854
+ }
26855
+ return n;
26856
+ }
26295
26857
  function toCommonOptions(flags) {
26296
26858
  return {
26297
26859
  env: flags.env,
@@ -26340,6 +26902,8 @@ function buildProgram(deps = {}) {
26340
26902
  registerRoleCommands(program, deps);
26341
26903
  registerContextCommands(program, deps);
26342
26904
  registerIssuersCommands(program, deps);
26905
+ registerProviderConfigCommands(program, deps);
26906
+ registerDomainsCommands(program, deps);
26343
26907
  registerNamespaceCommands(program, deps);
26344
26908
  registerScriptsCommands(program, deps);
26345
26909
  registerAssumeCommand(program, deps);
@@ -26550,7 +27114,10 @@ function registerIssuersCommands(program, deps) {
26550
27114
  ).option("--clear-captured-claims", "capture nothing beyond the email claim (sends an empty list; XOR --captured-claim)").option(
26551
27115
  "--restricted-to-domain <domain>",
26552
27116
  "scope the registration to a domain already verified for your account; a token with no matching 'hd' claim then stops matching \u2014 omit to leave unchanged. Refused on a registration that is pending verification: verify it first"
26553
- ).option("--clear-restricted-to-domain", "remove the domain scope (XOR --restricted-to-domain)").option("--tenant <tenant>", "tenant the context lives in: 'test' or 'live' (default live)");
27117
+ ).option(
27118
+ "--clear-restricted-to-domain",
27119
+ "remove the domain scope (XOR --restricted-to-domain). Refused unless the registration already holds the unrestricted (issuer, audience) pair, which one created scoped to a domain normally does not; see the README"
27120
+ ).option("--tenant <tenant>", "tenant the context lives in: 'test' or 'live' (default live)");
26554
27121
  addCommonAuthOptions(update).action(
26555
27122
  async (issuerId, flags) => {
26556
27123
  const tenant = parseTenantFlag(flags.tenant);
@@ -26611,6 +27178,101 @@ function registerIssuersCommands(program, deps) {
26611
27178
  }
26612
27179
  );
26613
27180
  }
27181
+ function registerProviderConfigCommands(program, deps) {
27182
+ const providerConfig = program.command("provider-config").description("Manage BYOM (bring-your-own-model) tenant-level provider configs.");
27183
+ const create = providerConfig.command("create").description("Create a new BYOM provider config (not idempotent \u2014 a repeat --alias 400s).").requiredOption("--alias <alias>", "operator-facing name used to select this config; unique per tenant").requiredOption("--provider-type <type>", "'ANTHROPIC_NATIVE' or 'OPENAI_COMPATIBLE'").option("--endpoint <url>", "required for OPENAI_COMPATIBLE (no default); an optional override for ANTHROPIC_NATIVE").option("--declared-processing-region <region>", "customer-asserted, free-text, Vectros-unverified transparency field").option("--default-provider-model-id <id>", "convenience default only \u2014 a per-request model id, when the caller supplies one, always takes precedence").requiredOption("--api-key-secret-file <path>", "path to a file holding the provider credential ('-' for stdin) \u2014 never pass the secret as a bare flag value").requiredOption("--waiver-type <type>", "the waiver code this config is entitled under (e.g. byo-model-inference:customer-key)").requiredOption("--billing-mode <mode>", "'PLATFORM_BILLED' or 'CUSTOMER_DIRECT'").option("--platform-token-factor <n>", "required when --billing-mode PLATFORM_BILLED; refused otherwise").option("--platform-output-weight <n>", "required when --billing-mode PLATFORM_BILLED; refused otherwise").option("--status <status>", "'ACTIVE' or 'DISABLED' (default ACTIVE) \u2014 ACTIVE requires the tenant already hold a granted waiver for --waiver-type").option("--tenant <tenant>", "tenant to create the config in: 'test' or 'live' (default live)");
27184
+ addCommonAuthOptions(create).action(
27185
+ async (flags) => {
27186
+ const tenant = parseTenantFlag(flags.tenant);
27187
+ if (tenant === TENANT_FLAG_INVALID) return;
27188
+ const platformTokenFactor = parseOptionalNumberFlag("--platform-token-factor", flags.platformTokenFactor);
27189
+ if (platformTokenFactor === NUMBER_FLAG_INVALID) return;
27190
+ const platformOutputWeight = parseOptionalNumberFlag("--platform-output-weight", flags.platformOutputWeight);
27191
+ if (platformOutputWeight === NUMBER_FLAG_INVALID) return;
27192
+ process.exitCode = await runProviderConfigCreate(
27193
+ {
27194
+ ...toCommonOptions(flags),
27195
+ alias: flags.alias,
27196
+ providerType: flags.providerType,
27197
+ endpoint: flags.endpoint,
27198
+ declaredProcessingRegion: flags.declaredProcessingRegion,
27199
+ defaultProviderModelId: flags.defaultProviderModelId,
27200
+ apiKeySecretFile: flags.apiKeySecretFile,
27201
+ waiverType: flags.waiverType,
27202
+ billingMode: flags.billingMode,
27203
+ platformTokenFactor,
27204
+ platformOutputWeight,
27205
+ status: flags.status,
27206
+ tenant
27207
+ },
27208
+ deps
27209
+ );
27210
+ }
27211
+ );
27212
+ const list = providerConfig.command("list").description("List provider configs in one tenant.").option("--tenant <tenant>", "tenant to read: 'test' or 'live' (default live)");
27213
+ addCommonAuthOptions(list).action(async (flags) => {
27214
+ const tenant = parseTenantFlag(flags.tenant);
27215
+ if (tenant === TENANT_FLAG_INVALID) return;
27216
+ process.exitCode = await runProviderConfigList({ ...toCommonOptions(flags), tenant }, deps);
27217
+ });
27218
+ const get = providerConfig.command("get").description("Show one provider config's metadata (no secret \u2014 the platform never returns it).").argument("<id>");
27219
+ addCommonAuthOptions(get).action(async (id, flags) => {
27220
+ process.exitCode = await runProviderConfigGet({ ...toCommonOptions(flags), id }, deps);
27221
+ });
27222
+ const update = providerConfig.command("update").description("Patch a provider config (partial update \u2014 an omitted field is left unchanged).").argument("<id>").option("--alias <alias>", "rename this config (still unique per tenant)").option("--provider-type <type>", "'ANTHROPIC_NATIVE' or 'OPENAI_COMPATIBLE'").option("--endpoint <url>", "update the provider endpoint").option("--declared-processing-region <region>", "update the transparency field").option("--default-provider-model-id <id>", "update the convenience default model id").option("--api-key-secret-file <path>", "rotate the provider credential from a file ('-' for stdin); omit to leave the stored secret unchanged").option("--waiver-type <type>", "update the waiver code this config is entitled under").option("--billing-mode <mode>", "'PLATFORM_BILLED' or 'CUSTOMER_DIRECT' \u2014 switching to CUSTOMER_DIRECT clears the platform pricing fields server-side").option("--platform-token-factor <n>", "update the platform pricing factor (PLATFORM_BILLED only)").option("--platform-output-weight <n>", "update the platform pricing weight (PLATFORM_BILLED only)").option("--status <status>", "'ACTIVE' or 'DISABLED' \u2014 activating requires a granted waiver for this config's waiverType");
27223
+ addCommonAuthOptions(update).action(
27224
+ async (id, flags) => {
27225
+ const platformTokenFactor = parseOptionalNumberFlag("--platform-token-factor", flags.platformTokenFactor);
27226
+ if (platformTokenFactor === NUMBER_FLAG_INVALID) return;
27227
+ const platformOutputWeight = parseOptionalNumberFlag("--platform-output-weight", flags.platformOutputWeight);
27228
+ if (platformOutputWeight === NUMBER_FLAG_INVALID) return;
27229
+ process.exitCode = await runProviderConfigUpdate(
27230
+ {
27231
+ ...toCommonOptions(flags),
27232
+ id,
27233
+ alias: flags.alias,
27234
+ providerType: flags.providerType,
27235
+ endpoint: flags.endpoint,
27236
+ declaredProcessingRegion: flags.declaredProcessingRegion,
27237
+ defaultProviderModelId: flags.defaultProviderModelId,
27238
+ apiKeySecretFile: flags.apiKeySecretFile,
27239
+ waiverType: flags.waiverType,
27240
+ billingMode: flags.billingMode,
27241
+ platformTokenFactor,
27242
+ platformOutputWeight,
27243
+ status: flags.status
27244
+ },
27245
+ deps
27246
+ );
27247
+ }
27248
+ );
27249
+ const del = providerConfig.command("delete").description("Delete a provider config.").argument("<id>").option("--force", "skip the interactive confirmation (required when stdin is not a TTY)");
27250
+ addCommonAuthOptions(del).action(async (id, flags) => {
27251
+ process.exitCode = await runProviderConfigDelete(
27252
+ { ...toCommonOptions(flags), id, force: Boolean(flags.force) },
27253
+ deps
27254
+ );
27255
+ });
27256
+ }
27257
+ function registerDomainsCommands(program, deps) {
27258
+ const domains = program.command("domains").description("Manage account-level domain ownership verification (DNS TXT proof-of-control).");
27259
+ const register = domains.command("register").description("Register a domain and start DNS TXT verification (not idempotent \u2014 a repeat --domain 409s).").requiredOption("--domain <domain>", "the domain to prove control of (e.g. example.com)");
27260
+ addCommonAuthOptions(register).action(async (flags) => {
27261
+ process.exitCode = await runDomainsRegister({ ...toCommonOptions(flags), domain: flags.domain }, deps);
27262
+ });
27263
+ const list = domains.command("list").description("List domains registered for this account (both tenants share this list).");
27264
+ addCommonAuthOptions(list).action(async (flags) => {
27265
+ process.exitCode = await runDomainsList(toCommonOptions(flags), deps);
27266
+ });
27267
+ const del = domains.command("delete").description("Deregister a domain (refused while any active webhook still references it).").argument("<id>").option("--force", "skip the interactive confirmation (required when stdin is not a TTY)");
27268
+ addCommonAuthOptions(del).action(async (id, flags) => {
27269
+ process.exitCode = await runDomainsDelete({ ...toCommonOptions(flags), id, force: Boolean(flags.force) }, deps);
27270
+ });
27271
+ const verify = domains.command("verify").description("Perform one DNS TXT lookup and report VERIFIED/FAILED \u2014 always re-runnable, never polls.").argument("<id>");
27272
+ addCommonAuthOptions(verify).action(async (id, flags) => {
27273
+ process.exitCode = await runDomainsVerify({ ...toCommonOptions(flags), id }, deps);
27274
+ });
27275
+ }
26614
27276
  function registerNamespaceCommands(program, deps) {
26615
27277
  const namespace = program.command("namespace").description("Manage scope-namespace registrations (whether scope:<namespace> values resolve to identity entities).");
26616
27278
  const register = namespace.command("register").description("Register a new scope namespace (NOT idempotent \u2014 a repeat name 400s).").argument("<name>", "namespace name: 2-32 chars, a lowercase letter first, then lowercase/digit/dash/underscore").requiredOption("--context <c>", "app context to own this registration").requiredOption("--specificity-rank <n>", "position in the account specificity order (integer 0-1000000, unique)").option("--entity-backed", "values must resolve to an identity entity (create via `identity create --type <name>`)").option("--default-schema-id <id>", "default record schema bound to entities in this namespace");