@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.js CHANGED
@@ -518,7 +518,7 @@ var require_graceful_fs = __commonJS({
518
518
  function patch(fs5) {
519
519
  polyfills(fs5);
520
520
  fs5.gracefulify = patch;
521
- fs5.createReadStream = createReadStream2;
521
+ fs5.createReadStream = createReadStream3;
522
522
  fs5.createWriteStream = createWriteStream;
523
523
  var fs$readFile = fs5.readFile;
524
524
  fs5.readFile = readFile4;
@@ -728,7 +728,7 @@ var require_graceful_fs = __commonJS({
728
728
  }
729
729
  });
730
730
  }
731
- function createReadStream2(path4, options) {
731
+ function createReadStream3(path4, options) {
732
732
  return new fs5.ReadStream(path4, options);
733
733
  }
734
734
  function createWriteStream(path4, options) {
@@ -1614,7 +1614,7 @@ var require_proper_lockfile = __commonJS({
1614
1614
  // src/cli-bootstrap.ts
1615
1615
  var readline2 = __toESM(require("readline/promises"));
1616
1616
 
1617
- // ../../node_modules/@vectros-ai/sdk/dist/index.mjs
1617
+ // node_modules/@vectros-ai/sdk/dist/index.mjs
1618
1618
  var __defProp2 = Object.defineProperty;
1619
1619
  var __export = (target, all) => {
1620
1620
  for (var name in all)
@@ -1634,6 +1634,7 @@ __export(api_exports, {
1634
1634
  ContentTooLargeError: () => ContentTooLargeError,
1635
1635
  DocumentContextEvent: () => DocumentContextEvent,
1636
1636
  DocumentLookupRequest: () => DocumentLookupRequest,
1637
+ DocumentPatchRequest: () => DocumentPatchRequest,
1637
1638
  DocumentRequest: () => DocumentRequest,
1638
1639
  DocumentResponse: () => DocumentResponse,
1639
1640
  DoneEvent: () => DoneEvent,
@@ -1977,6 +1978,13 @@ var DocumentLookupRequest;
1977
1978
  Desc: "desc"
1978
1979
  };
1979
1980
  })(DocumentLookupRequest || (DocumentLookupRequest = {}));
1981
+ var DocumentPatchRequest;
1982
+ ((DocumentPatchRequest2) => {
1983
+ DocumentPatchRequest2.Status = {
1984
+ Active: "ACTIVE",
1985
+ Archived: "ARCHIVED"
1986
+ };
1987
+ })(DocumentPatchRequest || (DocumentPatchRequest = {}));
1980
1988
  var FileUploadRequest;
1981
1989
  ((FileUploadRequest2) => {
1982
1990
  FileUploadRequest2.IndexMode = {
@@ -1989,6 +1997,7 @@ var FileUploadRequest;
1989
1997
  var documents_exports = {};
1990
1998
  __export(documents_exports, {
1991
1999
  DocumentLookupRequest: () => DocumentLookupRequest,
2000
+ DocumentPatchRequest: () => DocumentPatchRequest,
1992
2001
  FileUploadRequest: () => FileUploadRequest,
1993
2002
  LookupDocumentsRequestOrder: () => LookupDocumentsRequestOrder
1994
2003
  });
@@ -4653,6 +4662,7 @@ var AuthClient = class {
4653
4662
  * @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
4654
4663
  *
4655
4664
  * @throws {@link Vectros.BadRequestError}
4665
+ * @throws {@link Vectros.PaymentRequiredError}
4656
4666
  * @throws {@link Vectros.ForbiddenError}
4657
4667
  * @throws {@link Vectros.TooManyRequestsError}
4658
4668
  *
@@ -4702,6 +4712,8 @@ var AuthClient = class {
4702
4712
  switch (_response.error.statusCode) {
4703
4713
  case 400:
4704
4714
  throw new BadRequestError(_response.error.body, _response.rawResponse);
4715
+ case 402:
4716
+ throw new PaymentRequiredError(_response.error.body, _response.rawResponse);
4705
4717
  case 403:
4706
4718
  throw new ForbiddenError(_response.error.body, _response.rawResponse);
4707
4719
  case 429:
@@ -6547,7 +6559,7 @@ var ComplianceClient = class {
6547
6559
  this._options = normalizeClientOptionsWithAuth(options);
6548
6560
  }
6549
6561
  /**
6550
- * 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.
6562
+ * 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.
6551
6563
  *
6552
6564
  * @param {Vectros.ErasureRequest} request
6553
6565
  * @param {ComplianceClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6610,7 +6622,7 @@ var ComplianceClient = class {
6610
6622
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v1/erasure-requests");
6611
6623
  }
6612
6624
  /**
6613
- * 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.
6625
+ * 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.
6614
6626
  *
6615
6627
  * @param {Vectros.GetErasureRequestRequest} request
6616
6628
  * @param {ComplianceClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6853,7 +6865,7 @@ var DocumentsClient = class {
6853
6865
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents");
6854
6866
  }
6855
6867
  /**
6856
- * 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.
6868
+ * 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.
6857
6869
  *
6858
6870
  * @param {Vectros.IngestDocumentRequest} request
6859
6871
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6873,10 +6885,11 @@ var DocumentsClient = class {
6873
6885
  return HttpResponsePromise.fromPromise(this.__ingestDocument(request, requestOptions));
6874
6886
  }
6875
6887
  async __ingestDocument(request, requestOptions) {
6876
- const { upsert, allowClear, body: _body } = request;
6888
+ const { upsert, allowClear, confirmUntyped, body: _body } = request;
6877
6889
  const _queryParams = {
6878
6890
  upsert,
6879
- allowClear
6891
+ allowClear,
6892
+ confirmUntyped
6880
6893
  };
6881
6894
  const _authRequest = await this._options.authProvider.getAuthRequest();
6882
6895
  const _headers = mergeHeaders(
@@ -7111,7 +7124,7 @@ var DocumentsClient = class {
7111
7124
  /**
7112
7125
  * 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.
7113
7126
  *
7114
- * @param {Vectros.PatchDocumentRequest} request
7127
+ * @param {Vectros.DocumentPatchRequest} request
7115
7128
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
7116
7129
  *
7117
7130
  * @throws {@link Vectros.BadRequestError}
@@ -7122,17 +7135,14 @@ var DocumentsClient = class {
7122
7135
  *
7123
7136
  * @example
7124
7137
  * await client.documents.patchDocument({
7125
- * id: "id",
7126
- * body: {
7127
- * title: "Patient Intake Form \u2014 Jane Doe"
7128
- * }
7138
+ * id: "id"
7129
7139
  * })
7130
7140
  */
7131
7141
  patchDocument(request, requestOptions) {
7132
7142
  return HttpResponsePromise.fromPromise(this.__patchDocument(request, requestOptions));
7133
7143
  }
7134
7144
  async __patchDocument(request, requestOptions) {
7135
- const { id, body: _body } = request;
7145
+ const { id, ..._body } = request;
7136
7146
  const _authRequest = await this._options.authProvider.getAuthRequest();
7137
7147
  const _headers = mergeHeaders(
7138
7148
  _authRequest.headers,
@@ -7504,7 +7514,7 @@ var DocumentsClient = class {
7504
7514
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/versions");
7505
7515
  }
7506
7516
  /**
7507
- * 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.
7517
+ * 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.
7508
7518
  *
7509
7519
  * @param {Vectros.FileUploadRequest} request
7510
7520
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -7523,9 +7533,10 @@ var DocumentsClient = class {
7523
7533
  return HttpResponsePromise.fromPromise(this.__uploadDocument(request, requestOptions));
7524
7534
  }
7525
7535
  async __uploadDocument(request, requestOptions) {
7526
- const { upsert, ..._body } = request;
7536
+ const { upsert, confirmUntyped, ..._body } = request;
7527
7537
  const _queryParams = {
7528
- upsert
7538
+ upsert,
7539
+ confirmUntyped
7529
7540
  };
7530
7541
  const _authRequest = await this._options.authProvider.getAuthRequest();
7531
7542
  const _headers = mergeHeaders(
@@ -12541,7 +12552,11 @@ var BlueprintIssuerSchema = import_zod.z.object({
12541
12552
  * actually scoped. An unverified domain fails the apply with the platform's `400`.
12542
12553
  *
12543
12554
  * Omit to register a domain-less issuer. Omitting it on a re-apply leaves an existing scope
12544
- * unchanged; removing a scope is `vectros issuers update --clear-restricted-to-domain`.
12555
+ * unchanged. On platform 0.45.0 and later a scope is removed only from a registration that
12556
+ * already holds the unrestricted `(issuer, audience)` pair, which one created with a domain
12557
+ * normally does not (`vectros issuers update --clear-restricted-to-domain` is refused for it):
12558
+ * replace it with a new issuer declared without `restrictedToDomain` and verify that, under a
12559
+ * different app context if the old issuer has served users.
12545
12560
  */
12546
12561
  restrictedToDomain: import_zod.z.string().regex(RESTRICTED_DOMAIN_RE, {
12547
12562
  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"
@@ -15655,7 +15670,7 @@ async function devRouteError(res, action) {
15655
15670
  }
15656
15671
  function formatCliError(err, opts) {
15657
15672
  const info = extractServerError(err);
15658
- const actionable = renderActionableError(info);
15673
+ const actionable = renderActionableError(info, opts.notFoundHint);
15659
15674
  const block = actionable ?? ` \u2716 ${opts.action}: ${info.message}
15660
15675
  `;
15661
15676
  const debug = opts.debug ?? Boolean(process.env.VECTROS_MCP_DEBUG);
@@ -15669,7 +15684,7 @@ function formatCliError(err, opts) {
15669
15684
  }
15670
15685
  return block;
15671
15686
  }
15672
- function renderActionableError(info) {
15687
+ function renderActionableError(info, notFoundHint) {
15673
15688
  const msg = info.message;
15674
15689
  switch (info.errorCode) {
15675
15690
  case "SESSION_REFRESH_REQUIRED":
@@ -15707,7 +15722,7 @@ function renderActionableError(info) {
15707
15722
  }
15708
15723
  if (info.statusCode === 404) {
15709
15724
  return ` \u2716 ${msg}
15710
- Check the id \u2014 'vectros context list' enumerates the contexts you can reach.
15725
+ Check the id \u2014 ${notFoundHint ?? "'vectros context list' enumerates the contexts you can reach."}
15711
15726
  `;
15712
15727
  }
15713
15728
  if (/migration-locked|cannot be (changed|modified)|immutable/i.test(msg) && /schema|field|lookup|type/i.test(msg)) {
@@ -19265,8 +19280,8 @@ async function withIndexLock(dir, fn, timings = LOCK_OPTS) {
19265
19280
  // sections are ~1ms, so in practice the holder is gone before the first tick
19266
19281
  // and nothing is ever detected. (The probe that observed the no-op ran at
19267
19282
  // stale:2000 with the section artificially held open — a configuration we do
19268
- // not ship. A measurement in a config you don't ship is not evidence:
19269
- // CONVENTIONS 78, whose first worked example is this very comment.) The
19283
+ // not ship, and a measurement taken in a configuration you don't ship is not
19284
+ // evidence about the configuration you do.) The
19270
19285
  // honest shape: our release runs unconditionally, and after a stale-break
19271
19286
  // collision it CAN remove a successor's fresh lock — one more route to two
19272
19287
  // writers at once, on top of the rmdir race below. The backstop for both is
@@ -24308,12 +24323,12 @@ function parseRestrictedToDomain(raw) {
24308
24323
  const domain = raw.trim();
24309
24324
  if (domain.length === 0) {
24310
24325
  throw new Error(
24311
- "--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."
24326
+ "--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)."
24312
24327
  );
24313
24328
  }
24314
24329
  if (!isRestrictedToDomainName(domain.toLowerCase())) {
24315
24330
  throw new Error(
24316
- `--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.`
24331
+ `--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).`
24317
24332
  );
24318
24333
  }
24319
24334
  return domain;
@@ -24766,6 +24781,541 @@ ${renderIssuer(issuer)}
24766
24781
  });
24767
24782
  }
24768
24783
 
24784
+ // src/commands/provider-config.ts
24785
+ var import_node_fs5 = require("fs");
24786
+ var readline6 = __toESM(require("readline/promises"));
24787
+ var PROVIDER_TYPES = ["ANTHROPIC_NATIVE", "OPENAI_COMPATIBLE"];
24788
+ var BILLING_MODES = ["PLATFORM_BILLED", "CUSTOMER_DIRECT"];
24789
+ var STATUSES = ["ACTIVE", "DISABLED"];
24790
+ var MAX_SECRET_BYTES = 8 * 1024;
24791
+ async function readBoundedSecret(stream) {
24792
+ try {
24793
+ return await readAllFrom(stream, MAX_SECRET_BYTES);
24794
+ } catch (err) {
24795
+ if (err instanceof TokenTooLargeError) {
24796
+ throw new Error(
24797
+ `the input is larger than ${MAX_SECRET_BYTES / 1024} KB, which no API key is; nothing was read further and nothing was sent.`
24798
+ );
24799
+ }
24800
+ throw err;
24801
+ }
24802
+ }
24803
+ function fileFailureReason2(err) {
24804
+ switch (err?.code) {
24805
+ case "ENOENT":
24806
+ return "no such file.";
24807
+ case "EISDIR":
24808
+ return "that is a directory.";
24809
+ case "EACCES":
24810
+ case "EPERM":
24811
+ return "permission denied.";
24812
+ default:
24813
+ return "it could not be read.";
24814
+ }
24815
+ }
24816
+ async function resolveApiKeySecret(fileFlag, deps, mode) {
24817
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
24818
+ const readStdin = deps.readStdin ?? (() => readBoundedSecret(process.stdin));
24819
+ const readTextFile = deps.readTextFile ?? ((path4) => readBoundedSecret((0, import_node_fs5.createReadStream)(path4)));
24820
+ let raw;
24821
+ if (fileFlag !== void 0 && fileFlag !== "-") {
24822
+ if (looksLikeCredential(fileFlag)) {
24823
+ throw new Error(
24824
+ "--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 -."
24825
+ );
24826
+ }
24827
+ try {
24828
+ raw = await readTextFile(fileFlag);
24829
+ } catch (err) {
24830
+ const name = safeBaseName(fileFlag);
24831
+ throw new Error(
24832
+ `could not read the file given to --api-key-secret-file${name ? ` (${name})` : ""}: ${fileFailureReason2(err)}`
24833
+ );
24834
+ }
24835
+ } else if (fileFlag === "-") {
24836
+ if (isTty) {
24837
+ throw new Error(
24838
+ "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>."
24839
+ );
24840
+ }
24841
+ raw = await readStdin();
24842
+ } else if (mode === "required" && !isTty) {
24843
+ process.stderr.write(" \u2026 no --api-key-secret-file given: reading the secret from stdin.\n");
24844
+ raw = await readStdin();
24845
+ } else if (mode === "required") {
24846
+ throw new Error(
24847
+ "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)."
24848
+ );
24849
+ } else {
24850
+ return void 0;
24851
+ }
24852
+ const secret = raw.trim();
24853
+ if (secret.length === 0) throw new Error("the secret is empty.");
24854
+ return secret;
24855
+ }
24856
+ function renderProviderConfig(c) {
24857
+ return formatKeyValues([
24858
+ ["id", c.id],
24859
+ ["tenantId", c.tenantId],
24860
+ ["alias", c.alias],
24861
+ ["providerType", c.providerType],
24862
+ ["endpoint", c.endpoint],
24863
+ ["declaredProcessingRegion", c.declaredProcessingRegion],
24864
+ ["defaultProviderModelId", c.defaultProviderModelId],
24865
+ ["waiverType", c.waiverType],
24866
+ ["billingMode", c.billingMode],
24867
+ ["platformTokenFactor", c.platformTokenFactor],
24868
+ ["platformOutputWeight", c.platformOutputWeight],
24869
+ ["status", c.status],
24870
+ ["createdAt", c.createdAt]
24871
+ ]);
24872
+ }
24873
+ function invalidEnum(flag, value, allowed) {
24874
+ return `${flag} must be one of ${allowed.join(", ")} (got '${value}').`;
24875
+ }
24876
+ var NOT_FOUND_HINT = "'vectros provider-config list --tenant <test|live>' enumerates configs in a tenant.";
24877
+ async function runProviderConfigCreate(opts, deps = {}) {
24878
+ if (!PROVIDER_TYPES.includes(opts.providerType)) {
24879
+ process.stderr.write(` \u2716 ${invalidEnum("--provider-type", opts.providerType, PROVIDER_TYPES)}
24880
+ `);
24881
+ return 2;
24882
+ }
24883
+ if (!BILLING_MODES.includes(opts.billingMode)) {
24884
+ process.stderr.write(` \u2716 ${invalidEnum("--billing-mode", opts.billingMode, BILLING_MODES)}
24885
+ `);
24886
+ return 2;
24887
+ }
24888
+ if (opts.status !== void 0 && !STATUSES.includes(opts.status)) {
24889
+ process.stderr.write(` \u2716 ${invalidEnum("--status", opts.status, STATUSES)}
24890
+ `);
24891
+ return 2;
24892
+ }
24893
+ if (opts.billingMode === "PLATFORM_BILLED") {
24894
+ if (opts.platformTokenFactor === void 0 || opts.platformOutputWeight === void 0) {
24895
+ process.stderr.write(
24896
+ " \u2716 --platform-token-factor and --platform-output-weight are required when --billing-mode PLATFORM_BILLED.\n"
24897
+ );
24898
+ return 2;
24899
+ }
24900
+ } else if (opts.platformTokenFactor !== void 0 || opts.platformOutputWeight !== void 0) {
24901
+ process.stderr.write(
24902
+ " \u2716 --platform-token-factor/--platform-output-weight only apply with --billing-mode PLATFORM_BILLED.\n"
24903
+ );
24904
+ return 2;
24905
+ }
24906
+ let apiKeySecret;
24907
+ try {
24908
+ apiKeySecret = await resolveApiKeySecret(opts.apiKeySecretFile, deps, "required");
24909
+ } catch (err) {
24910
+ process.stderr.write(` \u2716 ${formatError(err)}
24911
+ `);
24912
+ return 2;
24913
+ }
24914
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
24915
+ const fetchImpl = deps.fetchImpl ?? fetch;
24916
+ try {
24917
+ const tenantId = requireTenantId(auth);
24918
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs`, {
24919
+ method: "POST",
24920
+ headers: { Authorization: `Bearer ${auth.cognitoToken}`, "Content-Type": "application/json" },
24921
+ body: JSON.stringify({
24922
+ tenantId,
24923
+ alias: opts.alias,
24924
+ providerType: opts.providerType,
24925
+ endpoint: opts.endpoint,
24926
+ declaredProcessingRegion: opts.declaredProcessingRegion,
24927
+ defaultProviderModelId: opts.defaultProviderModelId,
24928
+ apiKeySecret,
24929
+ waiverType: opts.waiverType,
24930
+ billingMode: opts.billingMode,
24931
+ platformTokenFactor: opts.platformTokenFactor,
24932
+ platformOutputWeight: opts.platformOutputWeight,
24933
+ status: opts.status
24934
+ })
24935
+ });
24936
+ if (!res.ok) throw await devRouteError(res, "provider-config create");
24937
+ const config = await res.json();
24938
+ if (opts.json) {
24939
+ process.stdout.write(`${formatJson(config)}
24940
+ `);
24941
+ return 0;
24942
+ }
24943
+ process.stdout.write(`
24944
+ \u2714 provider config '${opts.alias}' created
24945
+ ${renderProviderConfig(config)}
24946
+ `);
24947
+ return 0;
24948
+ } catch (err) {
24949
+ process.stderr.write(formatCliError(err, { action: "provider-config create failed" }));
24950
+ return 1;
24951
+ }
24952
+ });
24953
+ }
24954
+ async function runProviderConfigList(opts, deps = {}) {
24955
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
24956
+ const fetchImpl = deps.fetchImpl ?? fetch;
24957
+ try {
24958
+ const tenantId = requireTenantId(auth);
24959
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs?tenantId=${encodeURIComponent(tenantId)}`;
24960
+ const res = await fetchImpl(url, { method: "GET", headers: { Authorization: `Bearer ${auth.cognitoToken}` } });
24961
+ if (!res.ok) throw await devRouteError(res, "provider-config list");
24962
+ const rows = await res.json();
24963
+ if (opts.json) {
24964
+ process.stdout.write(`${formatJson(rows)}
24965
+ `);
24966
+ return 0;
24967
+ }
24968
+ process.stdout.write(
24969
+ "\n" + formatTable(rows, [
24970
+ { header: "id", get: (c) => c.id },
24971
+ { header: "alias", get: (c) => c.alias },
24972
+ { header: "provider type", get: (c) => c.providerType },
24973
+ { header: "billing mode", get: (c) => c.billingMode },
24974
+ { header: "status", get: (c) => c.status }
24975
+ ]) + "\n"
24976
+ );
24977
+ return 0;
24978
+ } catch (err) {
24979
+ process.stderr.write(formatCliError(err, { action: "provider-config list failed" }));
24980
+ return 1;
24981
+ }
24982
+ });
24983
+ }
24984
+ async function runProviderConfigGet(opts, deps = {}) {
24985
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
24986
+ const fetchImpl = deps.fetchImpl ?? fetch;
24987
+ try {
24988
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs/${encodeURIComponent(opts.id)}`;
24989
+ const res = await fetchImpl(url, { method: "GET", headers: { Authorization: `Bearer ${auth.cognitoToken}` } });
24990
+ if (!res.ok) throw await devRouteError(res, "provider-config get");
24991
+ const config = await res.json();
24992
+ if (opts.json) {
24993
+ process.stdout.write(`${formatJson(config)}
24994
+ `);
24995
+ return 0;
24996
+ }
24997
+ process.stdout.write(`
24998
+ ${renderProviderConfig(config)}
24999
+ `);
25000
+ return 0;
25001
+ } catch (err) {
25002
+ process.stderr.write(formatCliError(err, { action: "provider-config get failed", notFoundHint: NOT_FOUND_HINT }));
25003
+ return 1;
25004
+ }
25005
+ });
25006
+ }
25007
+ async function runProviderConfigUpdate(opts, deps = {}) {
25008
+ if (opts.providerType !== void 0 && !PROVIDER_TYPES.includes(opts.providerType)) {
25009
+ process.stderr.write(` \u2716 ${invalidEnum("--provider-type", opts.providerType, PROVIDER_TYPES)}
25010
+ `);
25011
+ return 2;
25012
+ }
25013
+ if (opts.billingMode !== void 0 && !BILLING_MODES.includes(opts.billingMode)) {
25014
+ process.stderr.write(` \u2716 ${invalidEnum("--billing-mode", opts.billingMode, BILLING_MODES)}
25015
+ `);
25016
+ return 2;
25017
+ }
25018
+ if (opts.status !== void 0 && !STATUSES.includes(opts.status)) {
25019
+ process.stderr.write(` \u2716 ${invalidEnum("--status", opts.status, STATUSES)}
25020
+ `);
25021
+ return 2;
25022
+ }
25023
+ let apiKeySecret;
25024
+ try {
25025
+ apiKeySecret = await resolveApiKeySecret(opts.apiKeySecretFile, deps, "optional");
25026
+ } catch (err) {
25027
+ process.stderr.write(` \u2716 ${formatError(err)}
25028
+ `);
25029
+ return 2;
25030
+ }
25031
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25032
+ const fetchImpl = deps.fetchImpl ?? fetch;
25033
+ try {
25034
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs/${encodeURIComponent(opts.id)}`;
25035
+ const res = await fetchImpl(url, {
25036
+ method: "PUT",
25037
+ headers: { Authorization: `Bearer ${auth.cognitoToken}`, "Content-Type": "application/json" },
25038
+ body: JSON.stringify({
25039
+ alias: opts.alias,
25040
+ providerType: opts.providerType,
25041
+ endpoint: opts.endpoint,
25042
+ declaredProcessingRegion: opts.declaredProcessingRegion,
25043
+ defaultProviderModelId: opts.defaultProviderModelId,
25044
+ apiKeySecret,
25045
+ waiverType: opts.waiverType,
25046
+ billingMode: opts.billingMode,
25047
+ platformTokenFactor: opts.platformTokenFactor,
25048
+ platformOutputWeight: opts.platformOutputWeight,
25049
+ status: opts.status
25050
+ })
25051
+ });
25052
+ if (!res.ok) throw await devRouteError(res, "provider-config update");
25053
+ const config = await res.json();
25054
+ if (opts.json) {
25055
+ process.stdout.write(`${formatJson(config)}
25056
+ `);
25057
+ return 0;
25058
+ }
25059
+ process.stdout.write(`
25060
+ \u2714 provider config '${opts.id}' updated
25061
+ ${renderProviderConfig(config)}
25062
+ `);
25063
+ return 0;
25064
+ } catch (err) {
25065
+ process.stderr.write(formatCliError(err, { action: "provider-config update failed", notFoundHint: NOT_FOUND_HINT }));
25066
+ return 1;
25067
+ }
25068
+ });
25069
+ }
25070
+ async function runProviderConfigDelete(opts, deps = {}) {
25071
+ const { id } = opts;
25072
+ if (!opts.force) {
25073
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
25074
+ if (!isTty) {
25075
+ process.stderr.write(
25076
+ ` \u2716 provider-config delete needs an interactive confirmation.
25077
+ Re-run with --force to delete '${id}' without a prompt.
25078
+ `
25079
+ );
25080
+ return 2;
25081
+ }
25082
+ const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
25083
+ const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
25084
+ return { prompt: (q) => rl.question(q), close: () => rl.close() };
25085
+ })();
25086
+ try {
25087
+ process.stdout.write(
25088
+ `
25089
+ \u26A0 Deleting provider config '${id}' removes it permanently. Any inference call that resolves
25090
+ a provider by this config's alias starts failing immediately. To disable it instead (reversible),
25091
+ run \`vectros provider-config update ${id} --status DISABLED\`.
25092
+
25093
+ `
25094
+ );
25095
+ const typed = await promptCtx.prompt(` Type the config id ('${id}') to confirm: `);
25096
+ if (typed.trim() !== id) {
25097
+ process.stderr.write(` \u2716 Confirmation did not match \u2014 nothing deleted.
25098
+ `);
25099
+ return 1;
25100
+ }
25101
+ } finally {
25102
+ promptCtx.close();
25103
+ }
25104
+ }
25105
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25106
+ const fetchImpl = deps.fetchImpl ?? fetch;
25107
+ try {
25108
+ const url = `${auth.baseUrl.replace(/\/$/, "")}/developer/provider-configs/${encodeURIComponent(id)}`;
25109
+ const res = await fetchImpl(url, { method: "DELETE", headers: { Authorization: `Bearer ${auth.cognitoToken}` } });
25110
+ if (!res.ok) throw await devRouteError(res, "provider-config delete");
25111
+ if (opts.json) {
25112
+ process.stdout.write(`${formatJson({ id, deleted: true })}
25113
+ `);
25114
+ return 0;
25115
+ }
25116
+ process.stdout.write(`
25117
+ \u2714 provider config '${id}' deleted
25118
+ `);
25119
+ return 0;
25120
+ } catch (err) {
25121
+ process.stderr.write(formatCliError(err, { action: "provider-config delete failed", notFoundHint: NOT_FOUND_HINT }));
25122
+ return 1;
25123
+ }
25124
+ });
25125
+ }
25126
+
25127
+ // src/commands/domains.ts
25128
+ var readline7 = __toESM(require("readline/promises"));
25129
+ function renderDomainVerifyResult(d) {
25130
+ return formatKeyValues([
25131
+ ["id", d.id],
25132
+ ["domain", d.domain],
25133
+ ["status", d.status]
25134
+ ]);
25135
+ }
25136
+ var NOT_FOUND_HINT2 = "'vectros domains list' enumerates your registered domains.";
25137
+ async function runDomainsRegister(opts, deps = {}) {
25138
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25139
+ const fetchImpl = deps.fetchImpl ?? fetch;
25140
+ try {
25141
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/domains`, {
25142
+ method: "POST",
25143
+ headers: { Authorization: `Bearer ${auth.cognitoToken}`, "Content-Type": "application/json" },
25144
+ body: JSON.stringify({ domain: opts.domain })
25145
+ });
25146
+ if (res.status === 409) {
25147
+ const raw = await res.text().catch(() => "");
25148
+ let message = "Domain already registered";
25149
+ let existingId;
25150
+ let existingStatus;
25151
+ try {
25152
+ const parsed = JSON.parse(raw);
25153
+ if (typeof parsed.message === "string" && parsed.message.trim()) message = parsed.message.trim();
25154
+ if (typeof parsed.id === "string") existingId = parsed.id;
25155
+ if (typeof parsed.status === "string") existingStatus = parsed.status;
25156
+ } catch {
25157
+ }
25158
+ if (opts.json) {
25159
+ process.stdout.write(`${formatJson({ message, id: existingId, status: existingStatus })}
25160
+ `);
25161
+ return 1;
25162
+ }
25163
+ process.stderr.write(
25164
+ ` \u2716 ${message}${existingId ? ` (id: ${existingId}${existingStatus ? `, status: ${existingStatus}` : ""})` : ""}
25165
+ ` + (existingStatus === "PENDING" && existingId ? ` Still pending verification. Run: vectros domains verify ${existingId}
25166
+ ` : " Run `vectros domains list` to find it.\n")
25167
+ );
25168
+ return 1;
25169
+ }
25170
+ if (!res.ok) throw await devRouteError(res, "domains register");
25171
+ const result = await res.json();
25172
+ if (opts.json) {
25173
+ process.stdout.write(`${formatJson(result)}
25174
+ `);
25175
+ return 0;
25176
+ }
25177
+ process.stdout.write(
25178
+ `
25179
+ \u2714 domain '${result.domain ?? opts.domain}' registered (id: ${result.id ?? "?"}, status: ${result.status ?? "PENDING"})
25180
+
25181
+ ${result.instructions ?? `Add a DNS TXT record: _vectros-verify.${result.domain ?? opts.domain} \u2192 "${result.verificationToken ?? ""}"`}
25182
+
25183
+ Once the record is published, run:
25184
+ vectros domains verify ${result.id ?? "<id>"}
25185
+ `
25186
+ );
25187
+ return 0;
25188
+ } catch (err) {
25189
+ process.stderr.write(formatCliError(err, { action: "domains register failed" }));
25190
+ return 1;
25191
+ }
25192
+ });
25193
+ }
25194
+ async function runDomainsList(opts, deps = {}) {
25195
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25196
+ const fetchImpl = deps.fetchImpl ?? fetch;
25197
+ try {
25198
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/domains`, {
25199
+ method: "GET",
25200
+ headers: { Authorization: `Bearer ${auth.cognitoToken}` }
25201
+ });
25202
+ if (!res.ok) throw await devRouteError(res, "domains list");
25203
+ const rows = await res.json();
25204
+ if (opts.json) {
25205
+ process.stdout.write(`${formatJson(rows)}
25206
+ `);
25207
+ return 0;
25208
+ }
25209
+ process.stdout.write(
25210
+ "\n" + formatTable(rows, [
25211
+ { header: "id", get: (d) => d.id },
25212
+ { header: "domain", get: (d) => d.domain },
25213
+ { header: "status", get: (d) => d.status },
25214
+ { header: "verified at", get: (d) => d.verifiedAt }
25215
+ ]) + "\n"
25216
+ );
25217
+ return 0;
25218
+ } catch (err) {
25219
+ process.stderr.write(formatCliError(err, { action: "domains list failed" }));
25220
+ return 1;
25221
+ }
25222
+ });
25223
+ }
25224
+ async function runDomainsDelete(opts, deps = {}) {
25225
+ const { id } = opts;
25226
+ if (!opts.force) {
25227
+ const isTty = deps.isTty ?? Boolean(process.stdin.isTTY);
25228
+ if (!isTty) {
25229
+ process.stderr.write(
25230
+ ` \u2716 domains delete needs an interactive confirmation.
25231
+ Re-run with --force to delete '${id}' without a prompt.
25232
+ `
25233
+ );
25234
+ return 2;
25235
+ }
25236
+ const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
25237
+ const rl = readline7.createInterface({ input: process.stdin, output: process.stdout });
25238
+ return { prompt: (q) => rl.question(q), close: () => rl.close() };
25239
+ })();
25240
+ try {
25241
+ process.stdout.write(
25242
+ `
25243
+ \u26A0 Deleting domain '${id}' removes its proof-of-control record. The platform refuses this while
25244
+ any active webhook still references it \u2014 disable or delete those first if this fails.
25245
+
25246
+ `
25247
+ );
25248
+ const typed = await promptCtx.prompt(` Type the domain id ('${id}') to confirm: `);
25249
+ if (typed.trim() !== id) {
25250
+ process.stderr.write(` \u2716 Confirmation did not match \u2014 nothing deleted.
25251
+ `);
25252
+ return 1;
25253
+ }
25254
+ } finally {
25255
+ promptCtx.close();
25256
+ }
25257
+ }
25258
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25259
+ const fetchImpl = deps.fetchImpl ?? fetch;
25260
+ try {
25261
+ const res = await fetchImpl(`${auth.baseUrl.replace(/\/$/, "")}/developer/domains/${encodeURIComponent(id)}`, {
25262
+ method: "DELETE",
25263
+ headers: { Authorization: `Bearer ${auth.cognitoToken}` }
25264
+ });
25265
+ if (!res.ok) throw await devRouteError(res, "domains delete");
25266
+ if (opts.json) {
25267
+ process.stdout.write(`${formatJson({ id, deleted: true })}
25268
+ `);
25269
+ return 0;
25270
+ }
25271
+ process.stdout.write(`
25272
+ \u2714 domain '${id}' deleted
25273
+ `);
25274
+ return 0;
25275
+ } catch (err) {
25276
+ process.stderr.write(formatCliError(err, { action: "domains delete failed", notFoundHint: NOT_FOUND_HINT2 }));
25277
+ return 1;
25278
+ }
25279
+ });
25280
+ }
25281
+ async function runDomainsVerify(opts, deps = {}) {
25282
+ return withAuth({ ...opts, provisioning: true }, deps, async (auth) => {
25283
+ const fetchImpl = deps.fetchImpl ?? fetch;
25284
+ try {
25285
+ const res = await fetchImpl(
25286
+ `${auth.baseUrl.replace(/\/$/, "")}/developer/domains/${encodeURIComponent(opts.id)}/verify`,
25287
+ { method: "POST", headers: { Authorization: `Bearer ${auth.cognitoToken}` } }
25288
+ );
25289
+ if (!res.ok) throw await devRouteError(res, "domains verify");
25290
+ const result = await res.json();
25291
+ const verified = result.verified === true && result.status === "VERIFIED";
25292
+ if (opts.json) {
25293
+ process.stdout.write(`${formatJson(result)}
25294
+ `);
25295
+ return verified ? 0 : 1;
25296
+ }
25297
+ if (!verified) {
25298
+ process.stderr.write(
25299
+ ` \u2716 domain '${result.domain ?? opts.id}' is not verified (status: ${result.status ?? "(none)"}).
25300
+ Check the DNS TXT record is published, allow time for it to propagate, then re-run this command.
25301
+ `
25302
+ );
25303
+ return 1;
25304
+ }
25305
+ process.stdout.write(
25306
+ `
25307
+ \u2714 domain '${result.domain ?? opts.id}' verified.
25308
+ ${renderDomainVerifyResult(result)}
25309
+ `
25310
+ );
25311
+ return 0;
25312
+ } catch (err) {
25313
+ process.stderr.write(formatCliError(err, { action: "domains verify failed", notFoundHint: NOT_FOUND_HINT2 }));
25314
+ return 1;
25315
+ }
25316
+ });
25317
+ }
25318
+
24769
25319
  // src/commands/namespace.ts
24770
25320
  function renderNamespace(n) {
24771
25321
  return formatKeyValues([
@@ -24870,7 +25420,7 @@ ${renderNamespace(ns)}
24870
25420
 
24871
25421
  // src/commands/scripts.ts
24872
25422
  var import_promises4 = require("fs/promises");
24873
- var readline6 = __toESM(require("readline/promises"));
25423
+ var readline8 = __toESM(require("readline/promises"));
24874
25424
  var SOURCE_MAX_BYTES = 3e5;
24875
25425
  var INPUT_CONTRACT_MAX_BYTES = 5e4;
24876
25426
  var utf8Bytes2 = (s) => new TextEncoder().encode(s).length;
@@ -25089,7 +25639,7 @@ async function runScriptsDelete(opts, deps = {}) {
25089
25639
  return 2;
25090
25640
  }
25091
25641
  const promptCtx = deps.createPrompt ? deps.createPrompt() : (() => {
25092
- const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
25642
+ const rl = readline8.createInterface({ input: process.stdin, output: process.stdout });
25093
25643
  return { prompt: (q) => rl.question(q), close: () => rl.close() };
25094
25644
  })();
25095
25645
  try {
@@ -26248,9 +26798,9 @@ function emitJoined(opts) {
26248
26798
 
26249
26799
  // src/build-info.ts
26250
26800
  var BUILD_INFO = {
26251
- cli: true ? "0.23.0" : "dev",
26252
- sdk: true ? "0.45.0" : "dev",
26253
- blueprints: true ? "0.20.0" : "dev"
26801
+ cli: true ? "0.24.0" : "dev",
26802
+ sdk: true ? "0.46.0" : "dev",
26803
+ blueprints: true ? "0.20.1" : "dev"
26254
26804
  };
26255
26805
  function formatBuildInfo() {
26256
26806
  return `vectros ${BUILD_INFO.cli} (sdk ${BUILD_INFO.sdk}, blueprints ${BUILD_INFO.blueprints})`;
@@ -26287,6 +26837,18 @@ function parseTenantFlag(raw) {
26287
26837
  }
26288
26838
  return raw;
26289
26839
  }
26840
+ var NUMBER_FLAG_INVALID = /* @__PURE__ */ Symbol("parseOptionalNumberFlag:invalid");
26841
+ function parseOptionalNumberFlag(flag, raw) {
26842
+ if (raw === void 0) return void 0;
26843
+ const n = Number(raw);
26844
+ if (!Number.isFinite(n)) {
26845
+ process.stderr.write(` \u2716 ${flag} must be a number (got '${raw}')
26846
+ `);
26847
+ process.exitCode = 2;
26848
+ return NUMBER_FLAG_INVALID;
26849
+ }
26850
+ return n;
26851
+ }
26290
26852
  function toCommonOptions(flags) {
26291
26853
  return {
26292
26854
  env: flags.env,
@@ -26335,6 +26897,8 @@ function buildProgram(deps = {}) {
26335
26897
  registerRoleCommands(program, deps);
26336
26898
  registerContextCommands(program, deps);
26337
26899
  registerIssuersCommands(program, deps);
26900
+ registerProviderConfigCommands(program, deps);
26901
+ registerDomainsCommands(program, deps);
26338
26902
  registerNamespaceCommands(program, deps);
26339
26903
  registerScriptsCommands(program, deps);
26340
26904
  registerAssumeCommand(program, deps);
@@ -26545,7 +27109,10 @@ function registerIssuersCommands(program, deps) {
26545
27109
  ).option("--clear-captured-claims", "capture nothing beyond the email claim (sends an empty list; XOR --captured-claim)").option(
26546
27110
  "--restricted-to-domain <domain>",
26547
27111
  "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"
26548
- ).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)");
27112
+ ).option(
27113
+ "--clear-restricted-to-domain",
27114
+ "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"
27115
+ ).option("--tenant <tenant>", "tenant the context lives in: 'test' or 'live' (default live)");
26549
27116
  addCommonAuthOptions(update).action(
26550
27117
  async (issuerId, flags) => {
26551
27118
  const tenant = parseTenantFlag(flags.tenant);
@@ -26606,6 +27173,101 @@ function registerIssuersCommands(program, deps) {
26606
27173
  }
26607
27174
  );
26608
27175
  }
27176
+ function registerProviderConfigCommands(program, deps) {
27177
+ const providerConfig = program.command("provider-config").description("Manage BYOM (bring-your-own-model) tenant-level provider configs.");
27178
+ 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)");
27179
+ addCommonAuthOptions(create).action(
27180
+ async (flags) => {
27181
+ const tenant = parseTenantFlag(flags.tenant);
27182
+ if (tenant === TENANT_FLAG_INVALID) return;
27183
+ const platformTokenFactor = parseOptionalNumberFlag("--platform-token-factor", flags.platformTokenFactor);
27184
+ if (platformTokenFactor === NUMBER_FLAG_INVALID) return;
27185
+ const platformOutputWeight = parseOptionalNumberFlag("--platform-output-weight", flags.platformOutputWeight);
27186
+ if (platformOutputWeight === NUMBER_FLAG_INVALID) return;
27187
+ process.exitCode = await runProviderConfigCreate(
27188
+ {
27189
+ ...toCommonOptions(flags),
27190
+ alias: flags.alias,
27191
+ providerType: flags.providerType,
27192
+ endpoint: flags.endpoint,
27193
+ declaredProcessingRegion: flags.declaredProcessingRegion,
27194
+ defaultProviderModelId: flags.defaultProviderModelId,
27195
+ apiKeySecretFile: flags.apiKeySecretFile,
27196
+ waiverType: flags.waiverType,
27197
+ billingMode: flags.billingMode,
27198
+ platformTokenFactor,
27199
+ platformOutputWeight,
27200
+ status: flags.status,
27201
+ tenant
27202
+ },
27203
+ deps
27204
+ );
27205
+ }
27206
+ );
27207
+ const list = providerConfig.command("list").description("List provider configs in one tenant.").option("--tenant <tenant>", "tenant to read: 'test' or 'live' (default live)");
27208
+ addCommonAuthOptions(list).action(async (flags) => {
27209
+ const tenant = parseTenantFlag(flags.tenant);
27210
+ if (tenant === TENANT_FLAG_INVALID) return;
27211
+ process.exitCode = await runProviderConfigList({ ...toCommonOptions(flags), tenant }, deps);
27212
+ });
27213
+ const get = providerConfig.command("get").description("Show one provider config's metadata (no secret \u2014 the platform never returns it).").argument("<id>");
27214
+ addCommonAuthOptions(get).action(async (id, flags) => {
27215
+ process.exitCode = await runProviderConfigGet({ ...toCommonOptions(flags), id }, deps);
27216
+ });
27217
+ 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");
27218
+ addCommonAuthOptions(update).action(
27219
+ async (id, flags) => {
27220
+ const platformTokenFactor = parseOptionalNumberFlag("--platform-token-factor", flags.platformTokenFactor);
27221
+ if (platformTokenFactor === NUMBER_FLAG_INVALID) return;
27222
+ const platformOutputWeight = parseOptionalNumberFlag("--platform-output-weight", flags.platformOutputWeight);
27223
+ if (platformOutputWeight === NUMBER_FLAG_INVALID) return;
27224
+ process.exitCode = await runProviderConfigUpdate(
27225
+ {
27226
+ ...toCommonOptions(flags),
27227
+ id,
27228
+ alias: flags.alias,
27229
+ providerType: flags.providerType,
27230
+ endpoint: flags.endpoint,
27231
+ declaredProcessingRegion: flags.declaredProcessingRegion,
27232
+ defaultProviderModelId: flags.defaultProviderModelId,
27233
+ apiKeySecretFile: flags.apiKeySecretFile,
27234
+ waiverType: flags.waiverType,
27235
+ billingMode: flags.billingMode,
27236
+ platformTokenFactor,
27237
+ platformOutputWeight,
27238
+ status: flags.status
27239
+ },
27240
+ deps
27241
+ );
27242
+ }
27243
+ );
27244
+ 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)");
27245
+ addCommonAuthOptions(del).action(async (id, flags) => {
27246
+ process.exitCode = await runProviderConfigDelete(
27247
+ { ...toCommonOptions(flags), id, force: Boolean(flags.force) },
27248
+ deps
27249
+ );
27250
+ });
27251
+ }
27252
+ function registerDomainsCommands(program, deps) {
27253
+ const domains = program.command("domains").description("Manage account-level domain ownership verification (DNS TXT proof-of-control).");
27254
+ 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)");
27255
+ addCommonAuthOptions(register).action(async (flags) => {
27256
+ process.exitCode = await runDomainsRegister({ ...toCommonOptions(flags), domain: flags.domain }, deps);
27257
+ });
27258
+ const list = domains.command("list").description("List domains registered for this account (both tenants share this list).");
27259
+ addCommonAuthOptions(list).action(async (flags) => {
27260
+ process.exitCode = await runDomainsList(toCommonOptions(flags), deps);
27261
+ });
27262
+ 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)");
27263
+ addCommonAuthOptions(del).action(async (id, flags) => {
27264
+ process.exitCode = await runDomainsDelete({ ...toCommonOptions(flags), id, force: Boolean(flags.force) }, deps);
27265
+ });
27266
+ const verify = domains.command("verify").description("Perform one DNS TXT lookup and report VERIFIED/FAILED \u2014 always re-runnable, never polls.").argument("<id>");
27267
+ addCommonAuthOptions(verify).action(async (id, flags) => {
27268
+ process.exitCode = await runDomainsVerify({ ...toCommonOptions(flags), id }, deps);
27269
+ });
27270
+ }
26609
27271
  function registerNamespaceCommands(program, deps) {
26610
27272
  const namespace = program.command("namespace").description("Manage scope-namespace registrations (whether scope:<namespace> values resolve to identity entities).");
26611
27273
  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");