@vectros-ai/cli 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/cli.js +200 -67
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +200 -67
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -481,10 +481,18 @@ var DocumentRequest;
|
|
|
481
481
|
Text: "TEXT",
|
|
482
482
|
None: "NONE"
|
|
483
483
|
};
|
|
484
|
+
DocumentRequest2.Status = {
|
|
485
|
+
Active: "ACTIVE",
|
|
486
|
+
Archived: "ARCHIVED"
|
|
487
|
+
};
|
|
484
488
|
})(DocumentRequest || (DocumentRequest = {}));
|
|
485
489
|
var DocumentResponse;
|
|
486
490
|
((DocumentResponse2) => {
|
|
487
491
|
DocumentResponse2.Status = {
|
|
492
|
+
Active: "ACTIVE",
|
|
493
|
+
Archived: "ARCHIVED"
|
|
494
|
+
};
|
|
495
|
+
DocumentResponse2.IndexStatus = {
|
|
488
496
|
PendingUpload: "PENDING_UPLOAD",
|
|
489
497
|
Uploaded: "UPLOADED",
|
|
490
498
|
Extracting: "EXTRACTING",
|
|
@@ -5255,7 +5263,7 @@ var DocumentsClient = class {
|
|
|
5255
5263
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/documents/{id}/versions");
|
|
5256
5264
|
}
|
|
5257
5265
|
/**
|
|
5258
|
-
* 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 to the SAME existing document/object (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
|
|
5266
|
+
* 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 to the SAME existing document/object (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).
|
|
5259
5267
|
*
|
|
5260
5268
|
* @param {Vectros.FileUploadRequest} request
|
|
5261
5269
|
* @param {DocumentsClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -9648,9 +9656,22 @@ var codingAgentMemory = {
|
|
|
9648
9656
|
]
|
|
9649
9657
|
};
|
|
9650
9658
|
var coding_agent_memory_default = codingAgentMemory;
|
|
9659
|
+
var DATA_PLANE_ACTIONS = [
|
|
9660
|
+
"records:r",
|
|
9661
|
+
"records:c",
|
|
9662
|
+
"records:u",
|
|
9663
|
+
"search:r",
|
|
9664
|
+
"schemas:r",
|
|
9665
|
+
"inference:r",
|
|
9666
|
+
"documents:r",
|
|
9667
|
+
"documents:c",
|
|
9668
|
+
"folders:r",
|
|
9669
|
+
"folders:c"
|
|
9670
|
+
];
|
|
9671
|
+
var EDITOR_ACTIONS = [...DATA_PLANE_ACTIONS, "records:d", "documents:d", "folders:d"];
|
|
9651
9672
|
var agenticSdlc = {
|
|
9652
9673
|
name: "agentic-sdlc",
|
|
9653
|
-
version: "1.
|
|
9674
|
+
version: "1.2.0",
|
|
9654
9675
|
description: "A whole-SDLC system of record for an AI development team \u2014 decisions, designs, references, runbooks, post-mortems (as documents) plus controls, conventions, gotchas, and a glossary (as records), cross-linked and recalled by meaning.",
|
|
9655
9676
|
contextId: "agentic-sdlc",
|
|
9656
9677
|
contextName: "Agentic SDLC Knowledge Base",
|
|
@@ -10085,6 +10106,19 @@ var agenticSdlc = {
|
|
|
10085
10106
|
fieldType: "date",
|
|
10086
10107
|
description: "ISO-8601 last-reviewed date. Range-queryable.",
|
|
10087
10108
|
renderHints: { label: "Reviewed on", widget: "date", order: 12 }
|
|
10109
|
+
},
|
|
10110
|
+
{
|
|
10111
|
+
// Provenance for sync: the source file this record was distilled from. A
|
|
10112
|
+
// record can't carry an in-file marker the way a document can (many records
|
|
10113
|
+
// come from one file), so it names its source instead — a change to that file
|
|
10114
|
+
// finds (equality lookup) and re-extracts exactly its records. Equality, not
|
|
10115
|
+
// range: file-level is the sync unit (re-extraction reprocesses the whole file),
|
|
10116
|
+
// and the schema keeps its single range lookup for the date row.
|
|
10117
|
+
fieldId: "sourceRef",
|
|
10118
|
+
fieldType: "string",
|
|
10119
|
+
filterable: true,
|
|
10120
|
+
description: "The source file (repo path) this record was extracted from \u2014 its provenance; a change to that file re-extracts its records. The specific section is encoded in the record externalId.",
|
|
10121
|
+
renderHints: { label: "Source ref", widget: "text", order: 13 }
|
|
10088
10122
|
}
|
|
10089
10123
|
],
|
|
10090
10124
|
lookupFields: [
|
|
@@ -10094,7 +10128,8 @@ var agenticSdlc = {
|
|
|
10094
10128
|
"area",
|
|
10095
10129
|
"verifiedBy",
|
|
10096
10130
|
"relatedDecision",
|
|
10097
|
-
{ fieldName: "reviewedOn", rangeEnabled: true }
|
|
10131
|
+
{ fieldName: "reviewedOn", rangeEnabled: true },
|
|
10132
|
+
"sourceRef"
|
|
10098
10133
|
]
|
|
10099
10134
|
},
|
|
10100
10135
|
{
|
|
@@ -10171,9 +10206,23 @@ var agenticSdlc = {
|
|
|
10171
10206
|
fieldType: "date",
|
|
10172
10207
|
description: "ISO-8601 \u2014 when last revised. Range-queryable.",
|
|
10173
10208
|
renderHints: { label: "Updated on", widget: "date", order: 9 }
|
|
10209
|
+
},
|
|
10210
|
+
{
|
|
10211
|
+
// Provenance for sync — see the note on `control.sourceRef`.
|
|
10212
|
+
fieldId: "sourceRef",
|
|
10213
|
+
fieldType: "string",
|
|
10214
|
+
filterable: true,
|
|
10215
|
+
description: "The source file (repo path) this record was extracted from \u2014 its provenance; a change to that file re-extracts its records. The specific section is encoded in the record externalId.",
|
|
10216
|
+
renderHints: { label: "Source ref", widget: "text", order: 10 }
|
|
10174
10217
|
}
|
|
10175
10218
|
],
|
|
10176
|
-
lookupFields: [
|
|
10219
|
+
lookupFields: [
|
|
10220
|
+
"area",
|
|
10221
|
+
"status",
|
|
10222
|
+
"establishedBy",
|
|
10223
|
+
{ fieldName: "updatedOn", rangeEnabled: true },
|
|
10224
|
+
"sourceRef"
|
|
10225
|
+
]
|
|
10177
10226
|
},
|
|
10178
10227
|
{
|
|
10179
10228
|
// A GOTCHA / sharp edge: a symptom, its cause, and the fix. A tight typed
|
|
@@ -10227,9 +10276,22 @@ var agenticSdlc = {
|
|
|
10227
10276
|
fieldType: "date",
|
|
10228
10277
|
description: "ISO-8601 \u2014 when first hit. Range-queryable.",
|
|
10229
10278
|
renderHints: { label: "Discovered on", widget: "date", order: 7 }
|
|
10279
|
+
},
|
|
10280
|
+
{
|
|
10281
|
+
// Provenance for sync — see the note on `control.sourceRef`.
|
|
10282
|
+
fieldId: "sourceRef",
|
|
10283
|
+
fieldType: "string",
|
|
10284
|
+
filterable: true,
|
|
10285
|
+
description: "The source file (repo path) this record was extracted from \u2014 its provenance; a change to that file re-extracts its records. The specific section is encoded in the record externalId.",
|
|
10286
|
+
renderHints: { label: "Source ref", widget: "text", order: 8 }
|
|
10230
10287
|
}
|
|
10231
10288
|
],
|
|
10232
|
-
lookupFields: [
|
|
10289
|
+
lookupFields: [
|
|
10290
|
+
"area",
|
|
10291
|
+
"status",
|
|
10292
|
+
{ fieldName: "discoveredOn", rangeEnabled: true },
|
|
10293
|
+
"sourceRef"
|
|
10294
|
+
]
|
|
10233
10295
|
},
|
|
10234
10296
|
{
|
|
10235
10297
|
// A glossary TERM — a definition keyed by the term itself. Structure-dominant:
|
|
@@ -10289,6 +10351,14 @@ var agenticSdlc = {
|
|
|
10289
10351
|
fieldType: "date",
|
|
10290
10352
|
description: "ISO-8601 \u2014 when last revised. Range-queryable.",
|
|
10291
10353
|
renderHints: { label: "Updated on", widget: "date", order: 7 }
|
|
10354
|
+
},
|
|
10355
|
+
{
|
|
10356
|
+
// Provenance for sync — see the note on `control.sourceRef`.
|
|
10357
|
+
fieldId: "sourceRef",
|
|
10358
|
+
fieldType: "string",
|
|
10359
|
+
filterable: true,
|
|
10360
|
+
description: "The source file (repo path) this record was extracted from \u2014 its provenance; a change to that file re-extracts its records. The specific section is encoded in the record externalId.",
|
|
10361
|
+
renderHints: { label: "Source ref", widget: "text", order: 8 }
|
|
10292
10362
|
}
|
|
10293
10363
|
],
|
|
10294
10364
|
// `term` is a UNIQUE equality lookup — exact "define X" + a one-per-term
|
|
@@ -10297,27 +10367,32 @@ var agenticSdlc = {
|
|
|
10297
10367
|
{ fieldName: "term", unique: true },
|
|
10298
10368
|
"area",
|
|
10299
10369
|
"relatedDecision",
|
|
10300
|
-
{ fieldName: "updatedOn", rangeEnabled: true }
|
|
10370
|
+
{ fieldName: "updatedOn", rangeEnabled: true },
|
|
10371
|
+
"sourceRef"
|
|
10301
10372
|
]
|
|
10302
10373
|
}
|
|
10303
10374
|
],
|
|
10304
|
-
// Least-privilege, data-plane only.
|
|
10305
|
-
//
|
|
10306
|
-
//
|
|
10307
|
-
// via a status flip, so the trail of how the team's thinking evolved stays intact.
|
|
10375
|
+
// Least-privilege, data-plane only. The scope of the `ssk_*` key the bootstrap
|
|
10376
|
+
// mints for THIS blueprint's service principal (the MCP/API runtime). See
|
|
10377
|
+
// DATA_PLANE_ACTIONS above for the action set + rationale.
|
|
10308
10378
|
accessProfile: {
|
|
10309
|
-
allowedActions:
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10379
|
+
allowedActions: DATA_PLANE_ACTIONS
|
|
10380
|
+
},
|
|
10381
|
+
// A reusable `editor` role for the HUMAN owner — DISTINCT from `accessProfile`
|
|
10382
|
+
// (which scopes only the service-principal key). `bootstrap` provisions this
|
|
10383
|
+
// role in the context but binds it to no one; the owner joins themselves so the
|
|
10384
|
+
// data-plane app (app.vectros.ai) shows their KB — its switcher lists only
|
|
10385
|
+
// contexts the signed-in user holds an active access profile in, and bootstrap
|
|
10386
|
+
// grants the human none by default. Bind it after bootstrap with:
|
|
10387
|
+
// vectros access grant --principal usr_<your-user-id> --context agentic-sdlc --role editor
|
|
10388
|
+
// (or the admin app's Access > Contexts > agentic-sdlc > Profiles > Create).
|
|
10389
|
+
// The editor gets the full data plane so a human curator can browse, write/correct,
|
|
10390
|
+
// AND hard-delete the KB (EDITOR_ACTIONS = the service key's set + delete). The
|
|
10391
|
+
// service key deliberately lacks delete and archives instead; the trusted human
|
|
10392
|
+
// owner may permanently remove genuine strays. Still no control-plane action, so
|
|
10393
|
+
// the scope gate accepts it as a data-plane-only role.
|
|
10394
|
+
roles: {
|
|
10395
|
+
editor: [{ allowedActions: EDITOR_ACTIONS }]
|
|
10321
10396
|
},
|
|
10322
10397
|
servicePrincipal: {
|
|
10323
10398
|
externalId: "agentic-sdlc",
|
|
@@ -12602,12 +12677,63 @@ function splitCsv(csv) {
|
|
|
12602
12677
|
return csv.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
12603
12678
|
}
|
|
12604
12679
|
|
|
12680
|
+
// src/paginate.ts
|
|
12681
|
+
var PAGE_LIMIT = 100;
|
|
12682
|
+
async function drainPages(fetch2) {
|
|
12683
|
+
const out = [];
|
|
12684
|
+
let startFrom;
|
|
12685
|
+
for (; ; ) {
|
|
12686
|
+
const page = await fetch2(startFrom);
|
|
12687
|
+
if (page.data) out.push(...page.data);
|
|
12688
|
+
const next = page.nextCursor;
|
|
12689
|
+
if (!next) break;
|
|
12690
|
+
startFrom = next;
|
|
12691
|
+
}
|
|
12692
|
+
return out;
|
|
12693
|
+
}
|
|
12694
|
+
|
|
12695
|
+
// src/self-principal.ts
|
|
12696
|
+
var PRINCIPAL_PREFIX_USER = "usr_";
|
|
12697
|
+
function emailFromJwt(token) {
|
|
12698
|
+
const parts = token.split(".");
|
|
12699
|
+
if (parts.length < 2) return void 0;
|
|
12700
|
+
try {
|
|
12701
|
+
const payload = Buffer.from(parts[1], "base64url").toString("utf8");
|
|
12702
|
+
const claims = JSON.parse(payload);
|
|
12703
|
+
return typeof claims.email === "string" && claims.email.trim() ? claims.email.trim() : void 0;
|
|
12704
|
+
} catch {
|
|
12705
|
+
return void 0;
|
|
12706
|
+
}
|
|
12707
|
+
}
|
|
12708
|
+
async function resolveSelfPrincipal(client, cognitoToken) {
|
|
12709
|
+
const email = emailFromJwt(cognitoToken);
|
|
12710
|
+
if (!email) return null;
|
|
12711
|
+
const target = email.toLowerCase();
|
|
12712
|
+
const users = await drainPages(
|
|
12713
|
+
(startFrom) => client.identity.listUsers(
|
|
12714
|
+
startFrom === void 0 ? { limit: PAGE_LIMIT } : { startFrom, limit: PAGE_LIMIT }
|
|
12715
|
+
)
|
|
12716
|
+
);
|
|
12717
|
+
const match = users.find(
|
|
12718
|
+
(u) => u.id && typeof u.email === "string" && u.email.toLowerCase() === target
|
|
12719
|
+
);
|
|
12720
|
+
if (!match?.id) return null;
|
|
12721
|
+
return { principalId: `${PRINCIPAL_PREFIX_USER}${match.id}`, userId: match.id, email };
|
|
12722
|
+
}
|
|
12723
|
+
|
|
12605
12724
|
// src/commands/whoami.ts
|
|
12606
12725
|
async function runWhoami(options, deps = {}) {
|
|
12607
12726
|
return withAuth(options, deps, async (auth) => {
|
|
12608
12727
|
const { identity, baseUrl } = auth;
|
|
12728
|
+
let self2 = null;
|
|
12729
|
+
try {
|
|
12730
|
+
self2 = await resolveSelfPrincipal(auth.client, auth.cognitoToken);
|
|
12731
|
+
} catch {
|
|
12732
|
+
self2 = null;
|
|
12733
|
+
}
|
|
12609
12734
|
if (options.json) {
|
|
12610
|
-
|
|
12735
|
+
const out = self2 ? { ...identity, userId: self2.userId, userPrincipalId: self2.principalId } : identity;
|
|
12736
|
+
process.stdout.write(`${formatJson(out)}
|
|
12611
12737
|
`);
|
|
12612
12738
|
return 0;
|
|
12613
12739
|
}
|
|
@@ -12619,6 +12745,7 @@ async function runWhoami(options, deps = {}) {
|
|
|
12619
12745
|
["principal", identity.principalType],
|
|
12620
12746
|
["principal id", identity.principalKeyId],
|
|
12621
12747
|
["label", identity.principalLabel],
|
|
12748
|
+
["your user id", self2?.principalId],
|
|
12622
12749
|
["allowed actions", identity.allowedActions?.length ? identity.allowedActions.join(", ") : void 0],
|
|
12623
12750
|
["token expires", expiry],
|
|
12624
12751
|
["api", baseUrl]
|
|
@@ -12628,21 +12755,6 @@ async function runWhoami(options, deps = {}) {
|
|
|
12628
12755
|
});
|
|
12629
12756
|
}
|
|
12630
12757
|
|
|
12631
|
-
// src/paginate.ts
|
|
12632
|
-
var PAGE_LIMIT = 100;
|
|
12633
|
-
async function drainPages(fetch2) {
|
|
12634
|
-
const out = [];
|
|
12635
|
-
let startFrom;
|
|
12636
|
-
for (; ; ) {
|
|
12637
|
-
const page = await fetch2(startFrom);
|
|
12638
|
-
if (page.data) out.push(...page.data);
|
|
12639
|
-
const next = page.nextCursor;
|
|
12640
|
-
if (!next) break;
|
|
12641
|
-
startFrom = next;
|
|
12642
|
-
}
|
|
12643
|
-
return out;
|
|
12644
|
-
}
|
|
12645
|
-
|
|
12646
12758
|
// src/commands/key.ts
|
|
12647
12759
|
var DEFAULT_KEY_NAME = "default";
|
|
12648
12760
|
function emitMintedKey(key, format) {
|
|
@@ -13032,6 +13144,17 @@ function assertPrincipalShape(principal) {
|
|
|
13032
13144
|
throw new Error(`--principal must be 'usr_<userId>' or 'key_<keyId>' (got '${principal}').`);
|
|
13033
13145
|
}
|
|
13034
13146
|
}
|
|
13147
|
+
var SELF_PRINCIPAL_ALIAS = "me";
|
|
13148
|
+
async function resolvePrincipalArg(raw, auth) {
|
|
13149
|
+
if (raw !== SELF_PRINCIPAL_ALIAS) return raw;
|
|
13150
|
+
const self2 = await resolveSelfPrincipal(auth.client, auth.cognitoToken);
|
|
13151
|
+
if (!self2) {
|
|
13152
|
+
throw new Error(
|
|
13153
|
+
"Could not resolve your own user id from your login. Pass --principal usr_<id> explicitly (find the id with `vectros identity list --type user`)."
|
|
13154
|
+
);
|
|
13155
|
+
}
|
|
13156
|
+
return self2.principalId;
|
|
13157
|
+
}
|
|
13035
13158
|
function renderProfile(p) {
|
|
13036
13159
|
return formatKeyValues([
|
|
13037
13160
|
["context", p.contextId],
|
|
@@ -13048,21 +13171,24 @@ async function runAccessGrant(opts, deps = {}) {
|
|
|
13048
13171
|
process.stderr.write(" \u2716 Provide exactly one of --role <roleId> or --actions <csv>.\n");
|
|
13049
13172
|
return 2;
|
|
13050
13173
|
}
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13174
|
+
if (opts.principal !== SELF_PRINCIPAL_ALIAS) {
|
|
13175
|
+
try {
|
|
13176
|
+
assertPrincipalShape(opts.principal);
|
|
13177
|
+
} catch (err) {
|
|
13178
|
+
process.stderr.write(` \u2716 ${formatError(err)}
|
|
13055
13179
|
`);
|
|
13056
|
-
|
|
13180
|
+
return 2;
|
|
13181
|
+
}
|
|
13057
13182
|
}
|
|
13058
13183
|
return withAuth(opts, deps, async (auth) => {
|
|
13059
13184
|
const client = auth.client;
|
|
13060
13185
|
try {
|
|
13186
|
+
const principal = await resolvePrincipalArg(opts.principal, auth);
|
|
13061
13187
|
const scopes = hasActions ? [{ allowed_actions: splitCsv(opts.actions) }] : void 0;
|
|
13062
13188
|
const profile = await client.auth.createAccessProfile({
|
|
13063
13189
|
contextId: opts.context,
|
|
13064
13190
|
body: {
|
|
13065
|
-
principalId:
|
|
13191
|
+
principalId: principal,
|
|
13066
13192
|
roleId: opts.role,
|
|
13067
13193
|
scopes
|
|
13068
13194
|
}
|
|
@@ -13074,7 +13200,7 @@ async function runAccessGrant(opts, deps = {}) {
|
|
|
13074
13200
|
}
|
|
13075
13201
|
process.stdout.write(
|
|
13076
13202
|
`
|
|
13077
|
-
\u2714 Granted ${
|
|
13203
|
+
\u2714 Granted ${principal} in '${opts.context}'` + (hasRole ? ` via role '${opts.role}'` : ` with ${splitCsv(opts.actions).length} action(s)`) + `
|
|
13078
13204
|
${renderProfile(profile)}
|
|
13079
13205
|
`
|
|
13080
13206
|
);
|
|
@@ -13087,18 +13213,21 @@ ${renderProfile(profile)}
|
|
|
13087
13213
|
});
|
|
13088
13214
|
}
|
|
13089
13215
|
async function runAccessRevoke(opts, deps = {}) {
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13216
|
+
if (opts.principal !== SELF_PRINCIPAL_ALIAS) {
|
|
13217
|
+
try {
|
|
13218
|
+
assertPrincipalShape(opts.principal);
|
|
13219
|
+
} catch (err) {
|
|
13220
|
+
process.stderr.write(` \u2716 ${formatError(err)}
|
|
13094
13221
|
`);
|
|
13095
|
-
|
|
13222
|
+
return 2;
|
|
13223
|
+
}
|
|
13096
13224
|
}
|
|
13097
13225
|
return withAuth(opts, deps, async (auth) => {
|
|
13098
13226
|
const client = auth.client;
|
|
13099
13227
|
try {
|
|
13100
|
-
|
|
13101
|
-
|
|
13228
|
+
const principal = await resolvePrincipalArg(opts.principal, auth);
|
|
13229
|
+
await client.auth.deleteAccessProfile({ contextId: opts.context, principalId: principal });
|
|
13230
|
+
process.stdout.write(` \u2714 Revoked ${principal} from '${opts.context}'
|
|
13102
13231
|
`);
|
|
13103
13232
|
return 0;
|
|
13104
13233
|
} catch (err) {
|
|
@@ -13113,7 +13242,7 @@ async function runAccessList(opts, deps = {}) {
|
|
|
13113
13242
|
process.stderr.write(" \u2716 Provide exactly one of --context <c> or --principal <p>.\n");
|
|
13114
13243
|
return 2;
|
|
13115
13244
|
}
|
|
13116
|
-
if (opts.principal) {
|
|
13245
|
+
if (opts.principal && opts.principal !== SELF_PRINCIPAL_ALIAS) {
|
|
13117
13246
|
try {
|
|
13118
13247
|
assertPrincipalShape(opts.principal);
|
|
13119
13248
|
} catch (err) {
|
|
@@ -13125,10 +13254,11 @@ async function runAccessList(opts, deps = {}) {
|
|
|
13125
13254
|
return withAuth(opts, deps, async (auth) => {
|
|
13126
13255
|
const client = auth.client;
|
|
13127
13256
|
try {
|
|
13257
|
+
const principal = opts.principal ? await resolvePrincipalArg(opts.principal, auth) : void 0;
|
|
13128
13258
|
const rows = opts.context ? await drainPages(
|
|
13129
13259
|
(startFrom) => client.auth.listAccessProfiles({ contextId: opts.context, startFrom, limit: PAGE_LIMIT })
|
|
13130
13260
|
) : await drainPages(
|
|
13131
|
-
(startFrom) => client.auth.listProfilesForPrincipal({ principalId:
|
|
13261
|
+
(startFrom) => client.auth.listProfilesForPrincipal({ principalId: principal, startFrom, limit: PAGE_LIMIT })
|
|
13132
13262
|
);
|
|
13133
13263
|
if (opts.json) {
|
|
13134
13264
|
process.stdout.write(`${formatJson(rows)}
|
|
@@ -13152,17 +13282,20 @@ async function runAccessList(opts, deps = {}) {
|
|
|
13152
13282
|
});
|
|
13153
13283
|
}
|
|
13154
13284
|
async function runAccessGet(opts, deps = {}) {
|
|
13155
|
-
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13285
|
+
if (opts.principal !== SELF_PRINCIPAL_ALIAS) {
|
|
13286
|
+
try {
|
|
13287
|
+
assertPrincipalShape(opts.principal);
|
|
13288
|
+
} catch (err) {
|
|
13289
|
+
process.stderr.write(` \u2716 ${formatError(err)}
|
|
13159
13290
|
`);
|
|
13160
|
-
|
|
13291
|
+
return 2;
|
|
13292
|
+
}
|
|
13161
13293
|
}
|
|
13162
13294
|
return withAuth(opts, deps, async (auth) => {
|
|
13163
13295
|
const client = auth.client;
|
|
13164
13296
|
try {
|
|
13165
|
-
const
|
|
13297
|
+
const principal = await resolvePrincipalArg(opts.principal, auth);
|
|
13298
|
+
const p = await client.auth.getAccessProfile({ contextId: opts.context, principalId: principal });
|
|
13166
13299
|
if (opts.json) {
|
|
13167
13300
|
process.stdout.write(`${formatJson(p)}
|
|
13168
13301
|
`);
|
|
@@ -13938,9 +14071,9 @@ async function runBlueprintTest(fileOrName, opts, deps = {}) {
|
|
|
13938
14071
|
|
|
13939
14072
|
// src/build-info.ts
|
|
13940
14073
|
var BUILD_INFO = {
|
|
13941
|
-
cli: true ? "0.6.
|
|
13942
|
-
sdk: true ? "0.
|
|
13943
|
-
blueprints: true ? "0.6.
|
|
14074
|
+
cli: true ? "0.6.6" : "dev",
|
|
14075
|
+
sdk: true ? "0.32.0" : "dev",
|
|
14076
|
+
blueprints: true ? "0.6.4" : "dev"
|
|
13944
14077
|
};
|
|
13945
14078
|
function formatBuildInfo() {
|
|
13946
14079
|
return `vectros ${BUILD_INFO.cli} (sdk ${BUILD_INFO.sdk}, blueprints ${BUILD_INFO.blueprints})`;
|
|
@@ -14059,7 +14192,7 @@ function registerRoleCommands(program, deps) {
|
|
|
14059
14192
|
}
|
|
14060
14193
|
function registerAccessCommands(program, deps) {
|
|
14061
14194
|
const access2 = program.command("access").description("Manage access bindings: principal \u2194 context \u2194 role/scopes.");
|
|
14062
|
-
const grant = access2.command("grant").description("Bind a principal to a context via a role or inline actions.").requiredOption("--principal <p>", "principal: 'usr_<userId>'
|
|
14195
|
+
const grant = access2.command("grant").description("Bind a principal to a context via a role or inline actions.").requiredOption("--principal <p>", "principal: 'usr_<userId>', 'key_<keyId>', or 'me' (your own user)").requiredOption("--context <c>", "app context").option("--role <roleId>", "reference a Role (XOR --actions)").option("--actions <csv>", "inline single-clause actions, comma-separated (XOR --role)");
|
|
14063
14196
|
addCommonAuthOptions(grant).action(
|
|
14064
14197
|
async (flags) => {
|
|
14065
14198
|
process.exit(
|
|
@@ -14073,15 +14206,15 @@ function registerAccessCommands(program, deps) {
|
|
|
14073
14206
|
);
|
|
14074
14207
|
}
|
|
14075
14208
|
);
|
|
14076
|
-
const revoke = access2.command("revoke").description("Remove a principal\u2019s binding in a context.").requiredOption("--principal <p>", "principal: 'usr_<userId>'
|
|
14209
|
+
const revoke = access2.command("revoke").description("Remove a principal\u2019s binding in a context.").requiredOption("--principal <p>", "principal: 'usr_<userId>', 'key_<keyId>', or 'me' (your own user)").requiredOption("--context <c>", "app context");
|
|
14077
14210
|
addAuthOptions(revoke).action(async (flags) => {
|
|
14078
14211
|
process.exit(await runAccessRevoke({ ...toCommonOptions(flags), principal: flags.principal, context: flags.context }, deps));
|
|
14079
14212
|
});
|
|
14080
|
-
const list = access2.command("list").description("List a context\u2019s members (--context) or a principal\u2019s contexts (--principal).").option("--context <c>", "list members of this context").option("--principal <p>", "list contexts this principal is bound to");
|
|
14213
|
+
const list = access2.command("list").description("List a context\u2019s members (--context) or a principal\u2019s contexts (--principal).").option("--context <c>", "list members of this context").option("--principal <p>", "list contexts this principal is bound to ('me' = your own user)");
|
|
14081
14214
|
addCommonAuthOptions(list).action(async (flags) => {
|
|
14082
14215
|
process.exit(await runAccessList({ ...toCommonOptions(flags), context: flags.context, principal: flags.principal }, deps));
|
|
14083
14216
|
});
|
|
14084
|
-
const get = access2.command("get").description("Show one principal\u2019s binding in a context.").requiredOption("--principal <p>", "principal: 'usr_<userId>'
|
|
14217
|
+
const get = access2.command("get").description("Show one principal\u2019s binding in a context.").requiredOption("--principal <p>", "principal: 'usr_<userId>', 'key_<keyId>', or 'me' (your own user)").requiredOption("--context <c>", "app context");
|
|
14085
14218
|
addCommonAuthOptions(get).action(async (flags) => {
|
|
14086
14219
|
process.exit(await runAccessGet({ ...toCommonOptions(flags), principal: flags.principal, context: flags.context }, deps));
|
|
14087
14220
|
});
|