@vectros-ai/cli 0.10.0 → 0.12.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
@@ -1654,6 +1654,7 @@ __export(api_exports, {
1654
1654
  FileUploadRequest: () => FileUploadRequest,
1655
1655
  ForbiddenError: () => ForbiddenError,
1656
1656
  IdentityLookupRequest: () => IdentityLookupRequest,
1657
+ IndexFailure: () => IndexFailure,
1657
1658
  InternalServerError: () => InternalServerError,
1658
1659
  ListEntitiesRequestOrder: () => ListEntitiesRequestOrder,
1659
1660
  ListUsersRequestOrder: () => ListUsersRequestOrder,
@@ -2175,6 +2176,17 @@ var IdentityLookupRequest;
2175
2176
  Desc: "desc"
2176
2177
  };
2177
2178
  })(IdentityLookupRequest || (IdentityLookupRequest = {}));
2179
+ var IndexFailure;
2180
+ ((IndexFailure2) => {
2181
+ IndexFailure2.Code = {
2182
+ SourceUnavailable: "SOURCE_UNAVAILABLE",
2183
+ TextIndexFailed: "TEXT_INDEX_FAILED",
2184
+ EmbeddingFailed: "EMBEDDING_FAILED",
2185
+ IndexingFailed: "INDEXING_FAILED",
2186
+ VectorLimitExceeded: "VECTOR_LIMIT_EXCEEDED",
2187
+ Internal: "INTERNAL"
2188
+ };
2189
+ })(IndexFailure || (IndexFailure = {}));
2178
2190
  var ModelDataVersionResponse;
2179
2191
  ((ModelDataVersionResponse2) => {
2180
2192
  ModelDataVersionResponse2.ChangeType = {
@@ -5691,7 +5703,7 @@ var AuthClient = class {
5691
5703
  );
5692
5704
  }
5693
5705
  /**
5694
- * Creates a short-lived JWT bearer token restricted to specific actions and, optionally, to a particular user, organization, or client. Use this to hand a narrowly-scoped credential to a browser or downstream service so it never sees your root API key. Only callable with a root API key (`sk_*`).
5706
+ * Creates a short-lived JWT bearer token restricted to specific actions and, optionally, to a particular user or identity entity (in any namespace). Use this to hand a narrowly-scoped credential to a browser or downstream service so it never sees your root API key. Only callable with a root API key (`sk_*`).
5695
5707
  *
5696
5708
  * @param {Vectros.TokenRequest} request
5697
5709
  * @param {AuthClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -5908,7 +5920,7 @@ var ComplianceClient = class {
5908
5920
  this._options = normalizeClientOptionsWithAuth(options);
5909
5921
  }
5910
5922
  /**
5911
- * Submits a right-to-erasure request for a single end-subject (a user, client, or organization). 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.
5923
+ * 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.
5912
5924
  *
5913
5925
  * @param {Vectros.ErasureRequest} request
5914
5926
  * @param {ComplianceClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6217,7 +6229,7 @@ var DocumentsClient = class {
6217
6229
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents");
6218
6230
  }
6219
6231
  /**
6220
- * 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.
6232
+ * 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.
6221
6233
  *
6222
6234
  * @param {Vectros.IngestDocumentRequest} request
6223
6235
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -6543,25 +6555,29 @@ var DocumentsClient = class {
6543
6555
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "PATCH", "/v1/documents/{id}");
6544
6556
  }
6545
6557
  /**
6546
- * Finds documents of a given type by field value. Supported fields: `externalId` (the document's first-class external identifier — no schema declaration required) and any field declared as a lookup field on the bound schema. A lookup on a sensitive field is rejected here because the value would appear in the URL query string; use POST /v1/documents/lookup (the request-body variant) for a sensitive field instead. Results are paginated: set `limit` for the page size and feed the returned `nextCursor` back as `startFrom` to fetch the next page. The response is a `{data, nextCursor}` envelope. Requires the `documents:r` scope.
6558
+ * Finds documents of a given type by field value. Supported fields: `externalId` (the document's first-class external identifier — no schema declaration required) and any field declared as a lookup field on the bound schema. A lookup on a sensitive field is rejected here because the value would appear in the URL query string; use POST /v1/documents/lookup (the request-body variant) for a sensitive field instead. `type`'s schema resolves with basedOn-aware shadowing: your own `userId`- or `scope`-owned variant if you have one, otherwise the shared base — for a scoped credential the owner is always your own token identity; `userId`/`scope` here only apply as an explicit owner selector for a root API key. Results are paginated: set `limit` for the page size and feed the returned `nextCursor` back as `startFrom` to fetch the next page. The response is a `{data, nextCursor}` envelope. Requires the `documents:r` scope.
6547
6559
  *
6548
6560
  * @param {Vectros.LookupDocumentsRequest} request
6549
6561
  * @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
6550
6562
  *
6563
+ * @throws {@link Vectros.BadRequestError}
6564
+ *
6551
6565
  * @example
6552
6566
  * await client.documents.lookupDocuments({
6553
6567
  * type: "invoice",
6554
6568
  * field: "po_number",
6555
6569
  * value: "PO-1001",
6556
6570
  * prefix: "PO-2024",
6557
- * startFrom: "550e8400-e29b-41d4-a716-446655440000"
6571
+ * startFrom: "550e8400-e29b-41d4-a716-446655440000",
6572
+ * userId: "550e8400-e29b-41d4-a716-446655440000",
6573
+ * scope: "org:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
6558
6574
  * })
6559
6575
  */
6560
6576
  lookupDocuments(request, requestOptions) {
6561
6577
  return HttpResponsePromise.fromPromise(this.__lookupDocuments(request, requestOptions));
6562
6578
  }
6563
6579
  async __lookupDocuments(request, requestOptions) {
6564
- const { type: type_, field, value, from: from_, to, prefix, startFrom, limit, order } = request;
6580
+ const { type: type_, field, value, from: from_, to, prefix, startFrom, limit, order, userId, scope } = request;
6565
6581
  const _queryParams = {
6566
6582
  type: type_,
6567
6583
  field,
@@ -6571,7 +6587,9 @@ var DocumentsClient = class {
6571
6587
  prefix,
6572
6588
  startFrom,
6573
6589
  limit,
6574
- order: order != null ? order : void 0
6590
+ order: order != null ? order : void 0,
6591
+ userId,
6592
+ scope
6575
6593
  };
6576
6594
  const _authRequest = await this._options.authProvider.getAuthRequest();
6577
6595
  const _headers = mergeHeaders(
@@ -6597,11 +6615,16 @@ var DocumentsClient = class {
6597
6615
  return { data: _response.body, rawResponse: _response.rawResponse };
6598
6616
  }
6599
6617
  if (_response.error.reason === "status-code") {
6600
- throw new VectrosError({
6601
- statusCode: _response.error.statusCode,
6602
- body: _response.error.body,
6603
- rawResponse: _response.rawResponse
6604
- });
6618
+ switch (_response.error.statusCode) {
6619
+ case 400:
6620
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
6621
+ default:
6622
+ throw new VectrosError({
6623
+ statusCode: _response.error.statusCode,
6624
+ body: _response.error.body,
6625
+ rawResponse: _response.rawResponse
6626
+ });
6627
+ }
6605
6628
  }
6606
6629
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/lookup");
6607
6630
  }
@@ -6969,7 +6992,7 @@ var FoldersClient = class {
6969
6992
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/folders");
6970
6993
  }
6971
6994
  /**
6972
- * Creates a folder to organize your documents and records. If `parentFolderId` is omitted, the folder is created under your context's default root folder. Folder creation is idempotent by (slug + parent): if a folder with the same slug already exists under the same parent, that existing folder 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 folder was returned) tells the two apart. To overwrite an existing folder's mutable fields instead of returning it unchanged, set `?upsert=true` (this also requires the `folders:u` scope). Requires the `folders:c` scope.
6995
+ * Creates a folder to organize your documents and records. If `parentFolderId` is omitted, the folder is created under your context's default root folder. Folder creation is idempotent by (slug + parent): if a folder with the same slug already exists under the same parent, that existing folder 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 folder was returned) tells the two apart. To overwrite an existing folder's mutable fields instead of returning it unchanged, set `?upsert=true` (this also requires the `folders:u` scope). Requires the `folders:c` scope to create. Being returned the existing folder on a collision is a read of that folder's data and additionally requires the `folders:r` scope — a credential holding `folders:c` alone receives a `400` ("already exists") on collision instead of the folder.
6973
6996
  *
6974
6997
  * @param {Vectros.CreateFolderRequest} request
6975
6998
  * @param {FoldersClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -7427,7 +7450,7 @@ var IdentityClient = class {
7427
7450
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/entities/{namespace}");
7428
7451
  }
7429
7452
  /**
7430
- * Creates a new entity in the given namespace. This call is idempotent on `externalId` within the namespace: if an entity with the same `externalId` already exists, the existing record is returned instead of creating a duplicate (`created: false`, HTTP 200). To overwrite an existing entity's content instead of returning it unchanged, set `?upsert=true` (also requires the `entities:u:<namespace>` scope). The namespace must be entity-backed (`org`/`client`, or registered via `POST /v1/namespaces`). Requires the `entities:c:<namespace>` scope.
7453
+ * Creates a new entity in the given namespace. This call is idempotent on `externalId` within the namespace: if an entity with the same `externalId` already exists, the existing record is returned instead of creating a duplicate (`created: false`, HTTP 200). To overwrite an existing entity's content instead of returning it unchanged, set `?upsert=true` (also requires the `entities:u:<namespace>` scope). The namespace must be entity-backed (`org`/`client`, or registered via `POST /v1/namespaces`). Requires the `entities:c:<namespace>` scope to create. Being returned the existing entity on a collision is a read of that entity's data and additionally requires the `entities:r:<namespace>` scope — a credential holding `entities:c:<namespace>` alone receives a `400` ("already in use") on collision instead of the entity.
7431
7454
  *
7432
7455
  * @param {Vectros.CreateEntityRequest} request
7433
7456
  * @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -7871,7 +7894,7 @@ var IdentityClient = class {
7871
7894
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/namespaces/{namespace}");
7872
7895
  }
7873
7896
  /**
7874
- * Updates the mutable fields (`entityBacked`, `defaultSchemaId`) of a registered namespace. The namespace name itself is immutable. Requires a root API key. The reserved built-ins cannot be updated.
7897
+ * Updates the mutable fields (`entityBacked`, `defaultSchemaId`, `specificityRank`) of a registered namespace. The namespace name itself is immutable. Requires a root API key. The reserved built-ins cannot be updated.
7875
7898
  *
7876
7899
  * @param {Vectros.UpdateNamespaceRequest} request
7877
7900
  * @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -7884,7 +7907,8 @@ var IdentityClient = class {
7884
7907
  * await client.identity.updateNamespace({
7885
7908
  * namespace: "team",
7886
7909
  * body: {
7887
- * namespace: "team"
7910
+ * namespace: "team",
7911
+ * specificityRank: 1500
7888
7912
  * }
7889
7913
  * })
7890
7914
  */
@@ -8049,7 +8073,7 @@ var IdentityClient = class {
8049
8073
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/namespaces");
8050
8074
  }
8051
8075
  /**
8052
- * Registers a new scope namespace and declares whether its values resolve to identity entities (`entityBacked`). Requires a root API key. The reserved names `org` and `client` are built in and cannot be registered.
8076
+ * Registers a new scope namespace and declares whether its values resolve to identity entities (`entityBacked`). Also requires `specificityRank`, an explicit, account-unique position in the specificity order used to break recordType schema-resolution ties. Requires a root API key. The reserved names `org` and `client` are built in and cannot be registered.
8053
8077
  *
8054
8078
  * @param {Vectros.NamespaceRequest} request
8055
8079
  * @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -8060,7 +8084,8 @@ var IdentityClient = class {
8060
8084
  *
8061
8085
  * @example
8062
8086
  * await client.identity.registerNamespace({
8063
- * namespace: "team"
8087
+ * namespace: "team",
8088
+ * specificityRank: 1500
8064
8089
  * })
8065
8090
  */
8066
8091
  registerNamespace(request, requestOptions) {
@@ -8177,7 +8202,7 @@ var IdentityClient = class {
8177
8202
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/users");
8178
8203
  }
8179
8204
  /**
8180
- * Creates a user identity in your account. The operation is idempotent on `externalId`: if a user with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing user was returned) tells the two apart. To overwrite an existing user's mutable fields (email, status, payload, schema binding) instead of returning it unchanged, set `?upsert=true` (this also requires the `users:u` scope). Requires the `users:c` scope.
8205
+ * Creates a user identity in your account. The operation is idempotent on `externalId`: if a user with the same `externalId` already exists, the existing record is returned instead of creating a duplicate. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing user was returned) tells the two apart. To overwrite an existing user's mutable fields (email, status, payload, schema binding) instead of returning it unchanged, set `?upsert=true` (this also requires the `users:u` scope). Requires the `users:c` scope to create. Being returned the existing user on a collision is a read of that user's data and additionally requires the `users:r` scope — a credential holding `users:c` alone receives a `400` ("already exists") on collision instead of the user.
8181
8206
  *
8182
8207
  * @param {Vectros.CreateUserRequest} request
8183
8208
  * @param {IdentityClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -9048,7 +9073,7 @@ var RecordsClient = class {
9048
9073
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/records");
9049
9074
  }
9050
9075
  /**
9051
- * Creates a new record of a given type. The `payload` is validated against that type's schema before the record is stored. Identify the type by sending `typeName`, `schemaId`, or both (they must agree); if you send only `schemaId`, the type is taken from that schema. Optionally supply an `externalId` to make the create idempotent — if a record with the same `externalId` already exists in your context, that existing record 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 record was returned) tells the two apart. To overwrite an existing record's content instead of returning it unchanged, set `?upsert=true` (this also requires the `records:u:<type>` scope). Requires the `records:c:<type>` scope.
9076
+ * Creates a new record of a given type. The `payload` is validated against that type's schema before the record is stored. Identify the type by sending `typeName`, `schemaId`, or both (they must agree); if you send only `schemaId`, the type is taken from that schema. Optionally supply an `externalId` to make the create idempotent — if a record with the same `externalId` already exists in your context, that existing record 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 record was returned) tells the two apart. To overwrite an existing record's content instead of returning it unchanged, set `?upsert=true` (this also requires the `records:u:<type>` scope). Requires the `records:c:<type>` scope to create. Being returned the existing record on a collision is a read of that record's data and additionally requires the `records:r:<type>` scope — a credential holding `records:c:<type>` alone receives a `400` ("already exists") on collision instead of the record.
9052
9077
  *
9053
9078
  * @param {Vectros.CreateRecordRequest} request
9054
9079
  * @param {RecordsClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -9639,6 +9664,8 @@ var SchemasClient = class {
9639
9664
  * @param {Vectros.ListSchemasRequest} request
9640
9665
  * @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
9641
9666
  *
9667
+ * @throws {@link Vectros.BadRequestError}
9668
+ *
9642
9669
  * @example
9643
9670
  * await client.schemas.listSchemas({
9644
9671
  * userId: "550e8400-e29b-41d4-a716-446655440000",
@@ -9685,16 +9712,21 @@ var SchemasClient = class {
9685
9712
  return { data: _response.body, rawResponse: _response.rawResponse };
9686
9713
  }
9687
9714
  if (_response.error.reason === "status-code") {
9688
- throw new VectrosError({
9689
- statusCode: _response.error.statusCode,
9690
- body: _response.error.body,
9691
- rawResponse: _response.rawResponse
9692
- });
9715
+ switch (_response.error.statusCode) {
9716
+ case 400:
9717
+ throw new BadRequestError(_response.error.body, _response.rawResponse);
9718
+ default:
9719
+ throw new VectrosError({
9720
+ statusCode: _response.error.statusCode,
9721
+ body: _response.error.body,
9722
+ rawResponse: _response.rawResponse
9723
+ });
9724
+ }
9693
9725
  }
9694
9726
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/schemas");
9695
9727
  }
9696
9728
  /**
9697
- * Defines a new record type with optional field definitions, validation rules, and lookup indexes. Idempotent by `typeName` within the same ownership scope: re-creating an existing `typeName` returns the existing schema rather than failing. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing schema was returned) tells the two apart. To reconcile an existing schema to the submitted shape instead of returning it unchanged, set `?upsert=true` (this also requires the `schemas:w` scope; only legal schema changes are applied — migration-locked changes are rejected). Requires the `schemas:w` scope.
9729
+ * Defines a new record type with optional field definitions, validation rules, and lookup indexes. Idempotent by `typeName` within the same ownership scope: re-creating an existing `typeName` returns the existing schema rather than failing. The response's `created` field (and the HTTP status — 201 when created, 200 when an existing schema was returned) tells the two apart. To reconcile an existing schema to the submitted shape instead of returning it unchanged, set `?upsert=true` (this also requires the `schemas:u` scope; only legal schema changes are applied — migration-locked changes are rejected). Requires the `schemas:c` scope to create. Being returned the existing schema on a collision is a read of that schema's data and additionally requires the `schemas:r` scope — a credential holding `schemas:c` alone receives a `400` ("already in use") on collision instead of the schema.
9698
9730
  *
9699
9731
  * @param {Vectros.CreateSchemaRequest} request
9700
9732
  * @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -9838,7 +9870,7 @@ var SchemasClient = class {
9838
9870
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/schemas/{id}");
9839
9871
  }
9840
9872
  /**
9841
- * Updates a record schema. Fields you omit are preserved; `typeName` is immutable and cannot be changed. Collection fields (`fields`, `lookupFields`, `renderHints`, `capabilities`) are replaced in full when supplied. Requires the `schemas:w` scope.
9873
+ * Updates a record schema. Fields you omit are preserved; `typeName` is immutable and cannot be changed. Collection fields (`fields`, `lookupFields`, `renderHints`, `capabilities`) are replaced in full when supplied. Requires the `schemas:u` scope.
9842
9874
  *
9843
9875
  * @param {Vectros.UpdateSchemaRequest} request
9844
9876
  * @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -9907,7 +9939,7 @@ var SchemasClient = class {
9907
9939
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "PUT", "/v1/schemas/{id}");
9908
9940
  }
9909
9941
  /**
9910
- * Permanently deletes a record schema. The request is refused with 409 if records of this type still exist — delete those records first, since every record must reference a live schema. Requires the `schemas:w` scope.
9942
+ * Permanently deletes a record schema. The request is refused with 409 if records of this type still exist — delete those records first, since every record must reference a live schema. A lineage base (a schema other schemas declare `basedOn`) also cannot be deleted while any such variant still exists — delete the variant schema(s) first. Requires the `schemas:d` scope.
9911
9943
  *
9912
9944
  * @param {Vectros.DeleteSchemaRequest} request
9913
9945
  * @param {SchemasClient.RequestOptions} requestOptions - Request-specific configuration.
@@ -10304,7 +10336,14 @@ var BlueprintSchemaSchema = z.object({
10304
10336
  // With a scoped token these must be consistent with the profile's dataScope
10305
10337
  // (a cross-consistency lint is deferred to the lint slice).
10306
10338
  userId: z.string().min(1).optional(),
10307
- scopes: z.array(z.string().min(1)).max(2).optional()
10339
+ scopes: z.array(z.string().min(1)).max(2).optional(),
10340
+ // The id of an existing schema this one is a CUSTOMIZATION of, when a schema
10341
+ // named `typeName` already exists in this context — required in that case,
10342
+ // and must be omitted when this create is the first schema under that name
10343
+ // (it becomes that name's shared base). Must point directly at the base (one
10344
+ // hop); immutable once set. Mirrors the `basedOn` field on the platform's
10345
+ // schema-create request.
10346
+ basedOn: z.string().min(1).optional()
10308
10347
  }).strict();
10309
10348
  var BlueprintAccessProfileSchema = z.object({
10310
10349
  // Validated structurally here; the SCOPE GATE (in @vectros-ai/cli) is
@@ -12485,19 +12524,21 @@ function extractServerError(err) {
12485
12524
  const statusCode = typeof e.statusCode === "number" ? e.statusCode : void 0;
12486
12525
  let serverMessage;
12487
12526
  let requestId;
12527
+ let errorCode;
12488
12528
  if (e.body && typeof e.body === "object") {
12489
12529
  const b = e.body;
12490
12530
  if (typeof b.message === "string" && b.message.trim()) serverMessage = b.message.trim();
12491
12531
  if (typeof b.requestId === "string" && b.requestId.trim()) requestId = b.requestId.trim();
12532
+ if (typeof b.errorCode === "string" && b.errorCode.trim()) errorCode = b.errorCode.trim();
12492
12533
  } else if (typeof e.body === "string" && e.body.trim()) {
12493
12534
  serverMessage = e.body.trim();
12494
12535
  }
12495
- if (serverMessage) return { statusCode, message: serverMessage, requestId };
12536
+ if (serverMessage) return { statusCode, message: serverMessage, requestId, errorCode };
12496
12537
  const message = typeof e.message === "string" ? e.message : "";
12497
12538
  const isSdkEnvelope = /\nStatus code:/.test(message);
12498
- if (message && !isSdkEnvelope) return { statusCode, message, requestId };
12499
- if (statusCode) return { statusCode, message: `HTTP ${statusCode}`, requestId };
12500
- if (message) return { statusCode, message, requestId };
12539
+ if (message && !isSdkEnvelope) return { statusCode, message, requestId, errorCode };
12540
+ if (statusCode) return { statusCode, message: `HTTP ${statusCode}`, requestId, errorCode };
12541
+ if (message) return { statusCode, message, requestId, errorCode };
12501
12542
  }
12502
12543
  return { message: String(err) };
12503
12544
  }
@@ -12508,15 +12549,17 @@ async function devRouteError(res, action) {
12508
12549
  const raw = await res.text().catch(() => "");
12509
12550
  let message;
12510
12551
  let requestId;
12552
+ let errorCode;
12511
12553
  try {
12512
12554
  const parsed = JSON.parse(raw);
12513
12555
  if (typeof parsed.message === "string" && parsed.message.trim()) message = parsed.message.trim();
12514
12556
  if (typeof parsed.requestId === "string" && parsed.requestId.trim()) requestId = parsed.requestId.trim();
12557
+ if (typeof parsed.errorCode === "string" && parsed.errorCode.trim()) errorCode = parsed.errorCode.trim();
12515
12558
  } catch {
12516
12559
  }
12517
12560
  const err = new Error(`${action}: HTTP ${res.status}`);
12518
12561
  err.statusCode = res.status;
12519
- err.body = { message: message ?? `HTTP ${res.status}`, requestId };
12562
+ err.body = { message: message ?? `HTTP ${res.status}`, requestId, errorCode };
12520
12563
  return err;
12521
12564
  }
12522
12565
  function formatCliError(err, opts) {
@@ -12525,14 +12568,28 @@ function formatCliError(err, opts) {
12525
12568
  const block = actionable ?? ` \u2716 ${opts.action}: ${info.message}
12526
12569
  `;
12527
12570
  const debug = opts.debug ?? Boolean(process.env.VECTROS_MCP_DEBUG);
12528
- if (debug && info.requestId) {
12529
- return `${block} (requestId: ${info.requestId} \u2014 quote this to support)
12571
+ if (debug && (info.requestId || info.errorCode)) {
12572
+ const parts = [
12573
+ info.errorCode ? `errorCode: ${info.errorCode}` : null,
12574
+ info.requestId ? `requestId: ${info.requestId}` : null
12575
+ ].filter(Boolean);
12576
+ return `${block} (${parts.join(", ")} \u2014 quote this to support)
12530
12577
  `;
12531
12578
  }
12532
12579
  return block;
12533
12580
  }
12534
12581
  function renderActionableError(info) {
12535
12582
  const msg = info.message;
12583
+ switch (info.errorCode) {
12584
+ case "SESSION_REFRESH_REQUIRED":
12585
+ return ` \u2716 Your session has expired.
12586
+ Run 'vectros login' to re-authenticate, then retry.
12587
+ `;
12588
+ case "RATE_LIMITED":
12589
+ return ` \u2716 ${msg}
12590
+ You're being rate-limited \u2014 wait a moment and retry.
12591
+ `;
12592
+ }
12536
12593
  if (/scoped-key limit reached/i.test(msg)) {
12537
12594
  const plan = /plan '([^']+)'/i.exec(msg)?.[1];
12538
12595
  const count = /\((\d+) active keys\)/i.exec(msg)?.[1];
@@ -13081,8 +13138,13 @@ var KNOWN_CONTROL_PLANE_RESOURCES = [
13081
13138
  "users",
13082
13139
  "billing",
13083
13140
  "admin",
13084
- "clients",
13085
- "orgs"
13141
+ // Identity/compartment provisioning. The flat `orgs`/`clients` resources were
13142
+ // folded into the generic `entities` (per-namespace) + `namespaces` surfaces,
13143
+ // which is what the API now scopes on — so those are the current spellings a
13144
+ // pack could name. (Cosmetic: any non-data-plane resource hard-rejects whether
13145
+ // or not it is listed here; this list only sharpens the error message.)
13146
+ "entities",
13147
+ "namespaces"
13086
13148
  ];
13087
13149
  var VALID_OPS = /* @__PURE__ */ new Set(["c", "r", "u", "d"]);
13088
13150
  var DATA_PLANE_SET = new Set(DATA_PLANE_ALLOWLIST);
@@ -13439,7 +13501,8 @@ async function runLoader(client, input) {
13439
13501
  capabilities: toCapabilities(s.capabilities),
13440
13502
  active: s.active,
13441
13503
  userId: s.userId,
13442
- scopes: s.scopes
13504
+ scopes: s.scopes,
13505
+ basedOn: s.basedOn
13443
13506
  };
13444
13507
  const resp = await ctxClient.schemas.createSchema({ upsert: true, body: schemaBody });
13445
13508
  if (resp.id) schemaIds[s.typeName] = resp.id;
@@ -13529,6 +13592,21 @@ async function runLoader(client, input) {
13529
13592
  let seededCount = 0;
13530
13593
  const seededRecordIds = [];
13531
13594
  const seededDocumentIds = [];
13595
+ const seedIndexFailures = [];
13596
+ const noteIfIndexFailed = (created, rec, surface) => {
13597
+ if (created.indexStatus !== "FAILED") return;
13598
+ seedIndexFailures.push({
13599
+ externalId: rec.externalId,
13600
+ typeName: rec.typeName,
13601
+ surface,
13602
+ code: created.indexFailure?.code,
13603
+ message: created.indexFailure?.message
13604
+ });
13605
+ log.warn(
13606
+ { component: "loader", typeName: rec.typeName, externalId: rec.externalId, code: created.indexFailure?.code },
13607
+ "seed stored but failed to index"
13608
+ );
13609
+ };
13532
13610
  for (const rec of skipSeed ? [] : blueprint.seed ?? []) {
13533
13611
  const schemaId = schemaIds[rec.typeName];
13534
13612
  if (!schemaId) {
@@ -13549,6 +13627,7 @@ async function runLoader(client, input) {
13549
13627
  }
13550
13628
  });
13551
13629
  if (created.id) seededDocumentIds.push(created.id);
13630
+ noteIfIndexFailed(created, rec, "document");
13552
13631
  } else {
13553
13632
  const created = await ctxClient.records.createRecord({
13554
13633
  body: {
@@ -13560,6 +13639,7 @@ async function runLoader(client, input) {
13560
13639
  }
13561
13640
  });
13562
13641
  if (created.id) seededRecordIds.push(created.id);
13642
+ noteIfIndexFailed(created, rec, "record");
13563
13643
  }
13564
13644
  seededCount++;
13565
13645
  }
@@ -13578,7 +13658,8 @@ async function runLoader(client, input) {
13578
13658
  roleIds,
13579
13659
  seededCount,
13580
13660
  seededRecordIds,
13581
- seededDocumentIds
13661
+ seededDocumentIds,
13662
+ seedIndexFailures
13582
13663
  };
13583
13664
  }
13584
13665
  function buildPlan(blueprint, opts = {}) {
@@ -13833,6 +13914,17 @@ function seedSummaryLine(opts) {
13833
13914
  return opts.seededCount ? ` \u2714 Seeded ${opts.seededCount} record(s)
13834
13915
  ` : "";
13835
13916
  }
13917
+ function seedIndexWarningBlock(failures) {
13918
+ if (failures.length === 0) return "";
13919
+ const lines = failures.map((f) => {
13920
+ const reason = f.message ?? f.code ?? "indexing failed";
13921
+ return ` \u2022 ${f.typeName}/${f.externalId} (${f.surface}): ${reason}
13922
+ `;
13923
+ });
13924
+ return ` \u26A0 ${failures.length} seed(s) stored but not fully searchable:
13925
+ ` + lines.join("") + ` They're stored and retrievable by id, but won't appear in search until the issue above is resolved.
13926
+ `;
13927
+ }
13836
13928
  function reconcileTally(items, noun) {
13837
13929
  if (items.length === 0) return null;
13838
13930
  const created = items.filter((i) => i.action === "created").length;
@@ -14089,7 +14181,7 @@ ${renderPlan(blueprint, planSteps)}
14089
14181
  noSeed,
14090
14182
  declinedInteractively: seedDeclinedInteractively,
14091
14183
  seededCount: result.seededCount
14092
- })
14184
+ }) + seedIndexWarningBlock(result.seedIndexFailures)
14093
14185
  );
14094
14186
  const entry = buildVectrosServerEntry({ apiKey: result.rawKey, apiBaseUrl: baseUrl });
14095
14187
  const isCode = args.client === "code";
@@ -15370,6 +15462,25 @@ function canonicalDim(key) {
15370
15462
  if (key === "userId" || key === "partnerUserId") return "user";
15371
15463
  return key;
15372
15464
  }
15465
+ var FORBIDDEN_SCOPE_NAMESPACES = /* @__PURE__ */ new Set([
15466
+ "user",
15467
+ "record",
15468
+ "document",
15469
+ "entity",
15470
+ "self",
15471
+ "tenant",
15472
+ "context",
15473
+ "scope",
15474
+ "versions",
15475
+ "lookup"
15476
+ ]);
15477
+ var SCOPE_NAMESPACE_RE = /^[a-z][a-z0-9_-]{1,31}$/;
15478
+ function isRecognizedOwnershipKey(key) {
15479
+ if (key === "userId" || key === "partnerUserId") return true;
15480
+ if (!key.startsWith("scope:")) return false;
15481
+ const ns = key.slice("scope:".length);
15482
+ return !FORBIDDEN_SCOPE_NAMESPACES.has(ns) && SCOPE_NAMESPACE_RE.test(ns);
15483
+ }
15373
15484
  var SELF_TOKEN_RE2 = /^\$\{\{\s*self\.[a-zA-Z.]+\s*\}\}$/;
15374
15485
  function normalizeClauses(raw) {
15375
15486
  const out = [];
@@ -15379,15 +15490,18 @@ function normalizeClauses(raw) {
15379
15490
  const actions = obj.allowed_actions ?? obj.allowedActions ?? [];
15380
15491
  const ds = obj.data_scope ?? obj.dataScope ?? {};
15381
15492
  const dataScope = {};
15493
+ const unrecognizedDims = [];
15382
15494
  for (const [k, v] of Object.entries(ds)) {
15495
+ const dim = canonicalDim(k);
15383
15496
  const values = Array.isArray(v) ? v : [v];
15384
- dataScope[canonicalDim(k)] = values.map((val) => {
15497
+ dataScope[dim] = values.map((val) => {
15385
15498
  if (val === null) return null;
15386
15499
  const s = String(val);
15387
15500
  return SELF_TOKEN_RE2.test(s) ? SELF : s;
15388
15501
  });
15502
+ if (!isRecognizedOwnershipKey(k)) unrecognizedDims.push(k);
15389
15503
  }
15390
- out.push({ actions: Array.isArray(actions) ? actions.map(String) : [], dataScope });
15504
+ out.push({ actions: Array.isArray(actions) ? actions.map(String) : [], dataScope, unrecognizedDims });
15391
15505
  }
15392
15506
  return out;
15393
15507
  }
@@ -15398,6 +15512,7 @@ function buildArchetypes(clauses) {
15398
15512
  ];
15399
15513
  const scopeDims = /* @__PURE__ */ new Map();
15400
15514
  for (const c of clauses) {
15515
+ if (c.unrecognizedDims.length > 0) continue;
15401
15516
  for (const [dim, values] of Object.entries(c.dataScope)) {
15402
15517
  if (dim === "user") continue;
15403
15518
  const set = scopeDims.get(dim) ?? /* @__PURE__ */ new Set();
@@ -15421,6 +15536,7 @@ function buildArchetypes(clauses) {
15421
15536
  return rows;
15422
15537
  }
15423
15538
  function clauseMatches(clause, arch) {
15539
+ if (clause.unrecognizedDims.length > 0) return false;
15424
15540
  for (const [dim, allowed] of Object.entries(clause.dataScope)) {
15425
15541
  const recordValue = arch.owners[dim];
15426
15542
  const ok = allowed.some((a) => {
@@ -15486,7 +15602,14 @@ async function runAccessExplain(opts, deps = {}) {
15486
15602
  context: opts.context,
15487
15603
  via,
15488
15604
  identityOverrides: profile.identityOverrides,
15489
- clauses: clauses.map((c, i) => ({ n: i + 1, actions: c.actions, dataScope: renderDataScope(c.dataScope) })),
15605
+ clauses: clauses.map((c, i) => ({
15606
+ n: i + 1,
15607
+ actions: c.actions,
15608
+ dataScope: renderDataScope(c.dataScope),
15609
+ // Present only on a dead clause — an unrecognized dim the platform
15610
+ // denies (a retired key or a bad scope:<ns>); the matrix omits it.
15611
+ ...c.unrecognizedDims.length > 0 ? { grantsNothing: true, unrecognizedDims: c.unrecognizedDims } : {}
15612
+ })),
15490
15613
  matrix: rows,
15491
15614
  note: "Ownership dimensions only: per-type action qualifiers narrow further, and search/RAG visibility is bounded per row by the same clause's typed read grants. Client-side preview; the platform decides at request time."
15492
15615
  })}
@@ -15505,6 +15628,12 @@ async function runAccessExplain(opts, deps = {}) {
15505
15628
  clauses.forEach((c, i) => {
15506
15629
  process.stdout.write(` ${i + 1}. [${c.actions.join(", ")}] where ${renderDataScope(c.dataScope)}
15507
15630
  `);
15631
+ if (c.unrecognizedDims.length > 0) {
15632
+ process.stdout.write(
15633
+ ` \u2716 grants nothing \u2014 unrecognized dimension${c.unrecognizedDims.length > 1 ? "s" : ""}: ${c.unrecognizedDims.join(", ")} (the platform denies a clause keyed on any dim that is not userId or a valid scope:<namespace>)
15634
+ `
15635
+ );
15636
+ }
15508
15637
  });
15509
15638
  process.stdout.write(
15510
15639
  "\n" + formatTable(rows, [
@@ -18250,9 +18379,9 @@ function emitJoined(alias, context, principalId, role, keyId, reused) {
18250
18379
 
18251
18380
  // src/build-info.ts
18252
18381
  var BUILD_INFO = {
18253
- cli: true ? "0.10.0" : "dev",
18254
- sdk: true ? "0.35.0" : "dev",
18255
- blueprints: true ? "0.8.0" : "dev"
18382
+ cli: true ? "0.12.0" : "dev",
18383
+ sdk: true ? "0.37.0" : "dev",
18384
+ blueprints: true ? "0.9.0" : "dev"
18256
18385
  };
18257
18386
  function formatBuildInfo() {
18258
18387
  return `vectros ${BUILD_INFO.cli} (sdk ${BUILD_INFO.sdk}, blueprints ${BUILD_INFO.blueprints})`;