@warmhub/cli 0.133.0 → 0.135.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.
Files changed (2) hide show
  1. package/dist/wh.js +430 -239
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -18010,6 +18010,154 @@ var DEFAULT_MAX_OPS_PER_STREAM = 1e6;
18010
18010
  var DEFAULT_STREAM_APPEND_CHUNK_SIZE = 1000;
18011
18011
  var MAX_STREAM_APPEND_OPERATION_COUNT = 1e4;
18012
18012
  var MAX_STREAMING_SUBMISSION_LINE_BYTES = 1024 * 1024;
18013
+ // ../../packages/rules/src/crockford-base32.ts
18014
+ var ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
18015
+ var DECODE_TABLE = new Uint8Array(256).fill(255);
18016
+ for (let i = 0;i < ALPHABET.length; i++) {
18017
+ const ch = ALPHABET.charCodeAt(i);
18018
+ DECODE_TABLE[ch] = i;
18019
+ if (ch >= 65)
18020
+ DECODE_TABLE[ch + 32] = i;
18021
+ }
18022
+ function encodeBytes(data) {
18023
+ const bitLen = data.length * 8;
18024
+ const charCount = Math.ceil(bitLen / 5);
18025
+ let out = "";
18026
+ for (let i = 0;i < charCount; i++) {
18027
+ const bitPos = i * 5;
18028
+ const byteIdx = bitPos >> 3;
18029
+ const bitOff = bitPos & 7;
18030
+ const b1 = data[byteIdx] ?? 0;
18031
+ let val;
18032
+ if (bitOff <= 3) {
18033
+ val = b1 >> 3 - bitOff & 31;
18034
+ } else {
18035
+ const b2 = data[byteIdx + 1] ?? 0;
18036
+ val = (b1 << bitOff - 3 | b2 >> 11 - bitOff) & 31;
18037
+ }
18038
+ out += ALPHABET[val];
18039
+ }
18040
+ return out;
18041
+ }
18042
+ function decodeBytes(encoded) {
18043
+ const byteLen = Math.floor(encoded.length * 5 / 8);
18044
+ const bytes = new Uint8Array(byteLen);
18045
+ let bitBuf = 0;
18046
+ let bitsInBuf = 0;
18047
+ let bytePos = 0;
18048
+ for (let i = 0;i < encoded.length; i++) {
18049
+ const ch = encoded.charCodeAt(i);
18050
+ const val = DECODE_TABLE[ch];
18051
+ if (val === undefined || val === 255)
18052
+ return null;
18053
+ bitBuf = bitBuf << 5 | val;
18054
+ bitsInBuf += 5;
18055
+ if (bitsInBuf >= 8) {
18056
+ bitsInBuf -= 8;
18057
+ if (bytePos < byteLen) {
18058
+ bytes[bytePos++] = bitBuf >> bitsInBuf & 255;
18059
+ }
18060
+ }
18061
+ }
18062
+ return bytes;
18063
+ }
18064
+
18065
+ // ../../packages/rules/src/durable-id.ts
18066
+ var THING_SCHEME = 1;
18067
+ var REPO_SCHEME = 2;
18068
+ var UUID_BYTES = 16;
18069
+ var CRC_BYTES = 4;
18070
+ function encodedLengthFor(payloadLen) {
18071
+ return Math.ceil((1 + payloadLen + CRC_BYTES) * 8 / 5);
18072
+ }
18073
+ var CRC32C_TABLE = (() => {
18074
+ const POLY = 2197175160;
18075
+ const table = new Uint32Array(256);
18076
+ for (let i = 0;i < 256; i++) {
18077
+ let crc = i;
18078
+ for (let j = 0;j < 8; j++) {
18079
+ crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
18080
+ }
18081
+ table[i] = crc >>> 0;
18082
+ }
18083
+ return table;
18084
+ })();
18085
+ function crc32c(data) {
18086
+ let crc = 4294967295;
18087
+ for (const byte of data) {
18088
+ crc = (crc >>> 8 ^ (CRC32C_TABLE[(crc ^ byte) & 255] ?? 0)) >>> 0;
18089
+ }
18090
+ return (crc ^ 4294967295) >>> 0;
18091
+ }
18092
+ function bytesToUuid(bytes, offset = 0) {
18093
+ const hex = Array.from(bytes.slice(offset, offset + 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
18094
+ return [
18095
+ hex.slice(0, 8),
18096
+ hex.slice(8, 12),
18097
+ hex.slice(12, 16),
18098
+ hex.slice(16, 20),
18099
+ hex.slice(20, 32)
18100
+ ].join("-");
18101
+ }
18102
+ function unpackToken(scheme, token, payloadLen) {
18103
+ const stripped = token.startsWith("wh:") ? token.slice(3) : token;
18104
+ if (stripped.length !== encodedLengthFor(payloadLen))
18105
+ return null;
18106
+ const raw = decodeBytes(stripped);
18107
+ if (!raw || raw.length !== 1 + payloadLen + CRC_BYTES)
18108
+ return null;
18109
+ if (raw[0] !== scheme)
18110
+ return null;
18111
+ const crcOffset = 1 + payloadLen;
18112
+ const storedCrc = (raw[crcOffset] ?? 0) << 24 | (raw[crcOffset + 1] ?? 0) << 16 | (raw[crcOffset + 2] ?? 0) << 8 | (raw[crcOffset + 3] ?? 0);
18113
+ const computedCrc = crc32c(raw.slice(0, crcOffset));
18114
+ if (storedCrc >>> 0 !== computedCrc >>> 0)
18115
+ return null;
18116
+ if (encodeBytes(raw) !== stripped.toUpperCase())
18117
+ return null;
18118
+ return raw.slice(1, 1 + payloadLen);
18119
+ }
18120
+ function decodeDurableId(token) {
18121
+ const payload = unpackToken(THING_SCHEME, token, UUID_BYTES * 2);
18122
+ if (!payload)
18123
+ return null;
18124
+ return {
18125
+ repoId: bytesToUuid(payload, 0),
18126
+ thingId: bytesToUuid(payload, UUID_BYTES)
18127
+ };
18128
+ }
18129
+ var VERSION_SELECTOR_RE = /^(?:v0*[1-9]\d*|[Hh][Ee][Aa][Dd]|[Aa][Ll][Ll])$/;
18130
+ function parseDurableReferenceToken(raw) {
18131
+ const at = raw.lastIndexOf("@");
18132
+ const selector = at >= 0 && VERSION_SELECTOR_RE.test(raw.slice(at + 1)) ? raw.slice(at + 1) : null;
18133
+ const core = selector === null ? raw : raw.slice(0, at);
18134
+ if (decodeDurableId(core) === null)
18135
+ return null;
18136
+ const stripped = core.startsWith("wh:") ? core.slice(3) : core;
18137
+ return { durableId: stripped.toUpperCase(), selector };
18138
+ }
18139
+ function decodeRepoDurableId(token) {
18140
+ const payload = unpackToken(REPO_SCHEME, token, UUID_BYTES);
18141
+ if (!payload)
18142
+ return null;
18143
+ return { repoId: bytesToUuid(payload, 0) };
18144
+ }
18145
+
18146
+ // ../../packages/rules/src/wref.ts
18147
+ function splitLocalPath(value) {
18148
+ const slashIndex = value.indexOf("/");
18149
+ if (slashIndex <= 0 || slashIndex === value.length - 1) {
18150
+ return null;
18151
+ }
18152
+ return {
18153
+ shapeName: value.slice(0, slashIndex),
18154
+ bareName: value.slice(slashIndex + 1)
18155
+ };
18156
+ }
18157
+ function withVersion(wref, version) {
18158
+ return `${wref}@v${version}`;
18159
+ }
18160
+
18013
18161
  // ../../packages/rules/src/commit-types.ts
18014
18162
  var COMMIT_OPERATIONS = [
18015
18163
  "add",
@@ -18032,11 +18180,9 @@ var READ_KIND_FILTERS = [
18032
18180
  LEGACY_COLLECTION_READ_KIND,
18033
18181
  LEGACY_ASSERTION_READ_KIND
18034
18182
  ];
18035
- function splitLocalPath(name) {
18036
- const idx = name.indexOf("/");
18037
- if (idx === -1)
18038
- return null;
18039
- return { shapePrefix: name.slice(0, idx), bareName: name.slice(idx + 1) };
18183
+ function splitLocalPath2(name) {
18184
+ const local = splitLocalPath(name);
18185
+ return local ? { shapePrefix: local.shapeName, bareName: local.bareName } : null;
18040
18186
  }
18041
18187
  function inferOperationKind(op) {
18042
18188
  if (op.kind === "shape" || op.kind === "thing" || op.kind === "assertion" || op.kind === "collection") {
@@ -25802,6 +25948,8 @@ function validateManifestSemantics(manifest) {
25802
25948
  }
25803
25949
  return findings;
25804
25950
  }
25951
+ // ../../packages/rules/src/edge-authz.ts
25952
+ var MAX_ALLOWED_SHAPES_PER_LIST = 64;
25805
25953
  // ../../packages/rules/src/external-contract.ts
25806
25954
  var FORBIDDEN_EXTERNAL_FIELDS = new Set([
25807
25955
  "_id",
@@ -26118,6 +26266,16 @@ function illegalOpSequences(operations, errors, checkAddAdd, options) {
26118
26266
  }
26119
26267
  }
26120
26268
 
26269
+ // ../../packages/rules/src/reserved-roots.ts
26270
+ var RESERVED_THING_ROOT = "hub";
26271
+ var RESERVED_THING_ROOT_PREFIX = `${RESERVED_THING_ROOT}/`;
26272
+ function isReservedThingRoot(name) {
26273
+ return name === RESERVED_THING_ROOT || name.startsWith(RESERVED_THING_ROOT_PREFIX);
26274
+ }
26275
+ function reservedThingRootMessage(name) {
26276
+ return `Name "${name}" is under the reserved root "${RESERVED_THING_ROOT_PREFIX}"; only Shapes live there, as ${RESERVED_THING_ROOT_PREFIX}shapes/<Name>`;
26277
+ }
26278
+
26121
26279
  // ../../packages/rules/src/preflight-operation.ts
26122
26280
  var collectionTypes = ["arc", "bond", "set", "list", "pair"];
26123
26281
  var canonicalCollectionTypes = ["arc", "bond", "pair", "set", "list"];
@@ -26133,6 +26291,7 @@ function parseCollectionOp(value) {
26133
26291
  function preflightOpDiagnostics(op, operationIndex) {
26134
26292
  const errors = [];
26135
26293
  errors.push(...builtinShapeGuard(op, operationIndex));
26294
+ errors.push(...reservedRootGuard(op, operationIndex));
26136
26295
  errors.push(...contentNameGuard(op, operationIndex));
26137
26296
  errors.push(...plusSignGuard(op, operationIndex));
26138
26297
  errors.push(...validateCollectionAbouts(op, operationIndex));
@@ -26142,7 +26301,7 @@ function preflightOpDiagnostics(op, operationIndex) {
26142
26301
  function builtinShapeGuard(op, operationIndex) {
26143
26302
  const errors = [];
26144
26303
  const name = op.name;
26145
- const isShapeRename = op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name));
26304
+ const isShapeRename = op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath2(op.name));
26146
26305
  const reservedSourcePassThrough = isShapeRename && name !== undefined && isRenameableSquattedShape(name) && op.newName !== undefined && !isReservedCollectionShape(op.newName) && !isBuiltinShape(op.newName);
26147
26306
  if (name && isRetiredCollectionShape(name) && !reservedSourcePassThrough) {
26148
26307
  errors.push({
@@ -26151,7 +26310,7 @@ function builtinShapeGuard(op, operationIndex) {
26151
26310
  message: `Shape "${name}" is a retired collection shape and cannot be written manually`
26152
26311
  });
26153
26312
  }
26154
- if (op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name)) && op.newName && isRetiredCollectionShape(op.newName)) {
26313
+ if (op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath2(op.name)) && op.newName && isRetiredCollectionShape(op.newName)) {
26155
26314
  errors.push({
26156
26315
  code: "RESERVED_NAME",
26157
26316
  operationIndex,
@@ -26169,7 +26328,7 @@ function builtinShapeGuard(op, operationIndex) {
26169
26328
  }
26170
26329
  }
26171
26330
  if (name && op.operation !== "retract") {
26172
- const local = splitLocalPath(name);
26331
+ const local = splitLocalPath2(name);
26173
26332
  if (local && isRetiredCollectionShape(local.shapePrefix)) {
26174
26333
  errors.push({
26175
26334
  code: "VALIDATION_ERROR",
@@ -26187,10 +26346,33 @@ function builtinShapeGuard(op, operationIndex) {
26187
26346
  }
26188
26347
  return errors;
26189
26348
  }
26349
+ function reservedRootRefusal(name, operationIndex) {
26350
+ return {
26351
+ code: "RESERVED_NAME",
26352
+ operationIndex,
26353
+ message: reservedThingRootMessage(name)
26354
+ };
26355
+ }
26356
+ function reservedRootGuard(op, operationIndex) {
26357
+ if (op.kind === "shape")
26358
+ return [];
26359
+ if (op.operation === "add" && op.name) {
26360
+ const stored = op.kind === "collection" ? op.name : splitLocalPath2(op.name)?.bareName;
26361
+ if (stored !== undefined && isReservedThingRoot(stored)) {
26362
+ return [reservedRootRefusal(stored, operationIndex)];
26363
+ }
26364
+ return [];
26365
+ }
26366
+ const isShapeRename = op.name !== undefined && splitLocalPath2(op.name) === null;
26367
+ if (op.operation === "rename" && !isShapeRename && op.newName !== undefined && isReservedThingRoot(op.newName)) {
26368
+ return [reservedRootRefusal(op.newName, operationIndex)];
26369
+ }
26370
+ return [];
26371
+ }
26190
26372
  function contentNameGuard(op, operationIndex) {
26191
26373
  if (op.kind !== "thing" || !op.name)
26192
26374
  return [];
26193
- const local = splitLocalPath(op.name);
26375
+ const local = splitLocalPath2(op.name);
26194
26376
  if (!local || !isContentShape(local.shapePrefix))
26195
26377
  return [];
26196
26378
  const bareName = local.bareName;
@@ -26236,7 +26418,7 @@ function plusSignGuard(op, operationIndex) {
26236
26418
  }
26237
26419
  if (op.kind === "collection")
26238
26420
  return errors;
26239
- const local = splitLocalPath(name);
26421
+ const local = splitLocalPath2(name);
26240
26422
  if (local && isReservedCollectionShape(local.shapePrefix))
26241
26423
  return errors;
26242
26424
  errors.push({
@@ -43505,139 +43687,6 @@ function commitValidateRequestBodyBytes(input) {
43505
43687
  return new TextEncoder().encode(encodeCommitValidateRequestBody(input)).byteLength;
43506
43688
  }
43507
43689
 
43508
- // ../../packages/rules/src/crockford-base32.ts
43509
- var ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
43510
- var DECODE_TABLE = new Uint8Array(256).fill(255);
43511
- for (let i = 0;i < ALPHABET.length; i++) {
43512
- const ch = ALPHABET.charCodeAt(i);
43513
- DECODE_TABLE[ch] = i;
43514
- if (ch >= 65)
43515
- DECODE_TABLE[ch + 32] = i;
43516
- }
43517
- function encodeBytes(data) {
43518
- const bitLen = data.length * 8;
43519
- const charCount = Math.ceil(bitLen / 5);
43520
- let out = "";
43521
- for (let i = 0;i < charCount; i++) {
43522
- const bitPos = i * 5;
43523
- const byteIdx = bitPos >> 3;
43524
- const bitOff = bitPos & 7;
43525
- const b1 = data[byteIdx] ?? 0;
43526
- let val;
43527
- if (bitOff <= 3) {
43528
- val = b1 >> 3 - bitOff & 31;
43529
- } else {
43530
- const b2 = data[byteIdx + 1] ?? 0;
43531
- val = (b1 << bitOff - 3 | b2 >> 11 - bitOff) & 31;
43532
- }
43533
- out += ALPHABET[val];
43534
- }
43535
- return out;
43536
- }
43537
- function decodeBytes(encoded) {
43538
- const byteLen = Math.floor(encoded.length * 5 / 8);
43539
- const bytes = new Uint8Array(byteLen);
43540
- let bitBuf = 0;
43541
- let bitsInBuf = 0;
43542
- let bytePos = 0;
43543
- for (let i = 0;i < encoded.length; i++) {
43544
- const ch = encoded.charCodeAt(i);
43545
- const val = DECODE_TABLE[ch];
43546
- if (val === undefined || val === 255)
43547
- return null;
43548
- bitBuf = bitBuf << 5 | val;
43549
- bitsInBuf += 5;
43550
- if (bitsInBuf >= 8) {
43551
- bitsInBuf -= 8;
43552
- if (bytePos < byteLen) {
43553
- bytes[bytePos++] = bitBuf >> bitsInBuf & 255;
43554
- }
43555
- }
43556
- }
43557
- return bytes;
43558
- }
43559
-
43560
- // ../../packages/rules/src/durable-id.ts
43561
- var THING_SCHEME = 1;
43562
- var REPO_SCHEME = 2;
43563
- var UUID_BYTES = 16;
43564
- var CRC_BYTES = 4;
43565
- function encodedLengthFor(payloadLen) {
43566
- return Math.ceil((1 + payloadLen + CRC_BYTES) * 8 / 5);
43567
- }
43568
- var CRC32C_TABLE = (() => {
43569
- const POLY = 2197175160;
43570
- const table = new Uint32Array(256);
43571
- for (let i = 0;i < 256; i++) {
43572
- let crc = i;
43573
- for (let j = 0;j < 8; j++) {
43574
- crc = crc & 1 ? crc >>> 1 ^ POLY : crc >>> 1;
43575
- }
43576
- table[i] = crc >>> 0;
43577
- }
43578
- return table;
43579
- })();
43580
- function crc32c(data) {
43581
- let crc = 4294967295;
43582
- for (const byte of data) {
43583
- crc = (crc >>> 8 ^ (CRC32C_TABLE[(crc ^ byte) & 255] ?? 0)) >>> 0;
43584
- }
43585
- return (crc ^ 4294967295) >>> 0;
43586
- }
43587
- function bytesToUuid(bytes, offset = 0) {
43588
- const hex3 = Array.from(bytes.slice(offset, offset + 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
43589
- return [
43590
- hex3.slice(0, 8),
43591
- hex3.slice(8, 12),
43592
- hex3.slice(12, 16),
43593
- hex3.slice(16, 20),
43594
- hex3.slice(20, 32)
43595
- ].join("-");
43596
- }
43597
- function unpackToken(scheme, token, payloadLen) {
43598
- const stripped = token.startsWith("wh:") ? token.slice(3) : token;
43599
- if (stripped.length !== encodedLengthFor(payloadLen))
43600
- return null;
43601
- const raw = decodeBytes(stripped);
43602
- if (!raw || raw.length !== 1 + payloadLen + CRC_BYTES)
43603
- return null;
43604
- if (raw[0] !== scheme)
43605
- return null;
43606
- const crcOffset = 1 + payloadLen;
43607
- const storedCrc = (raw[crcOffset] ?? 0) << 24 | (raw[crcOffset + 1] ?? 0) << 16 | (raw[crcOffset + 2] ?? 0) << 8 | (raw[crcOffset + 3] ?? 0);
43608
- const computedCrc = crc32c(raw.slice(0, crcOffset));
43609
- if (storedCrc >>> 0 !== computedCrc >>> 0)
43610
- return null;
43611
- if (encodeBytes(raw) !== stripped.toUpperCase())
43612
- return null;
43613
- return raw.slice(1, 1 + payloadLen);
43614
- }
43615
- function decodeDurableId(token) {
43616
- const payload = unpackToken(THING_SCHEME, token, UUID_BYTES * 2);
43617
- if (!payload)
43618
- return null;
43619
- return {
43620
- repoId: bytesToUuid(payload, 0),
43621
- thingId: bytesToUuid(payload, UUID_BYTES)
43622
- };
43623
- }
43624
- var VERSION_SELECTOR_RE = /^(?:v0*[1-9]\d*|[Hh][Ee][Aa][Dd]|[Aa][Ll][Ll])$/;
43625
- function parseDurableReferenceToken(raw) {
43626
- const at = raw.lastIndexOf("@");
43627
- const selector = at >= 0 && VERSION_SELECTOR_RE.test(raw.slice(at + 1)) ? raw.slice(at + 1) : null;
43628
- const core2 = selector === null ? raw : raw.slice(0, at);
43629
- if (decodeDurableId(core2) === null)
43630
- return null;
43631
- const stripped = core2.startsWith("wh:") ? core2.slice(3) : core2;
43632
- return { durableId: stripped.toUpperCase(), selector };
43633
- }
43634
- function decodeRepoDurableId(token) {
43635
- const payload = unpackToken(REPO_SCHEME, token, UUID_BYTES);
43636
- if (!payload)
43637
- return null;
43638
- return { repoId: bytesToUuid(payload, 0) };
43639
- }
43640
-
43641
43690
  // ../../packages/rules/src/json-string-walk.ts
43642
43691
  function walkJsonStringLeaves(value, spec) {
43643
43692
  const { childContext, onStringValue, onObjectKey } = spec;
@@ -45429,7 +45478,7 @@ function createStreamingSubmissionHandle(input, deps) {
45429
45478
  // ../../packages/sdk-ts/package.json
45430
45479
  var package_default = {
45431
45480
  name: "@warmhub/sdk-ts",
45432
- version: "0.131.0",
45481
+ version: "0.133.0",
45433
45482
  private: false,
45434
45483
  type: "module",
45435
45484
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -49791,10 +49840,10 @@ class WorkOsAuthError extends Error {
49791
49840
  this.status = status;
49792
49841
  }
49793
49842
  }
49794
- async function refreshAccessToken(tokens, signal) {
49843
+ async function refreshAccessToken(tokens, signal, options = {}) {
49795
49844
  const log = getLog();
49796
49845
  const { clientId } = tokens;
49797
- const workosUrl = "https://api.workos.com";
49846
+ const workosUrl = (options.workosUrl ?? "https://api.workos.com").replace(/\/$/, "");
49798
49847
  const path = "/user_management/authenticate";
49799
49848
  const requestId = `${process.pid}-${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
49800
49849
  log.debug("http.request", {
@@ -49804,7 +49853,8 @@ async function refreshAccessToken(tokens, signal) {
49804
49853
  request_id: requestId
49805
49854
  });
49806
49855
  const startedAt = Date.now();
49807
- const requestSignal = signal ?? AbortSignal.timeout(WORKOS_REFRESH_TIMEOUT_MS);
49856
+ const timeoutSignal = AbortSignal.timeout(options.requestTimeoutMs ?? WORKOS_REFRESH_TIMEOUT_MS);
49857
+ const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
49808
49858
  let res;
49809
49859
  try {
49810
49860
  res = await fetch(`${workosUrl}${path}`, {
@@ -50379,6 +50429,9 @@ function corruptedAuthError(path, cause) {
50379
50429
  }
50380
50430
 
50381
50431
  // ../../packages/warmhub-cli/src/auth.ts
50432
+ var AUTH_REFRESH_BUDGET_MS = 30000;
50433
+ var AUTH_REFRESH_RETRY_DELAY_MS = 1000;
50434
+ var TRANSIENT_REFRESH_COOLDOWN_MS = 5000;
50382
50435
  function isAuthLockError(error51, authPath) {
50383
50436
  return error51 instanceof Error && error51.code === "ELOCKED" && (error51.file === undefined || error51.file === authPath);
50384
50437
  }
@@ -50400,6 +50453,17 @@ function delay2(ms, signal) {
50400
50453
  signal?.addEventListener("abort", onAbort, { once: true });
50401
50454
  });
50402
50455
  }
50456
+ function refreshCooldownActive(failedAt) {
50457
+ if (!failedAt)
50458
+ return false;
50459
+ const ageMs = Date.now() - new Date(failedAt).getTime();
50460
+ return ageMs >= 0 && ageMs < TRANSIENT_REFRESH_COOLDOWN_MS;
50461
+ }
50462
+ function withoutRefreshFailure(profile) {
50463
+ const next = { ...profile };
50464
+ delete next.transientRefreshFailedAt;
50465
+ return next;
50466
+ }
50403
50467
  function getTokenInfo(profile) {
50404
50468
  const envToken = process.env.WH_TOKEN;
50405
50469
  if (envToken) {
@@ -50428,7 +50492,7 @@ function getTokenInfo(profile) {
50428
50492
  canRefresh: source === "device" && !!tokens.refreshToken
50429
50493
  };
50430
50494
  }
50431
- async function getValidToken(profile, signal) {
50495
+ async function getValidToken(profile, signal, options = {}) {
50432
50496
  const log = getLog();
50433
50497
  const envToken = process.env.WH_TOKEN;
50434
50498
  if (envToken) {
@@ -50460,7 +50524,10 @@ async function getValidToken(profile, signal) {
50460
50524
  const classification = err.error === "invalid_grant" ? "invalid_grant" : "terminal";
50461
50525
  const staleProf = getProfile(profileName, authPath);
50462
50526
  if (staleProf) {
50463
- saveProfileWhileLocked(profileName, { ...staleProf, tokens: { ...staleProf.tokens, refreshToken: "" } }, authPath);
50527
+ saveProfileWhileLocked(profileName, withoutRefreshFailure({
50528
+ ...staleProf,
50529
+ tokens: { ...staleProf.tokens, refreshToken: "" }
50530
+ }), authPath);
50464
50531
  log.error("auth.refresh_token.wiped", {
50465
50532
  profile: profileName,
50466
50533
  reason: classification
@@ -50472,6 +50539,16 @@ async function getValidToken(profile, signal) {
50472
50539
  }
50473
50540
  throw new CliError(5 /* Auth */, "AUTH", `Session could not be refreshed (${err.error}).${err.errorDescription ? ` ${err.errorDescription}` : ""}`, err, `Run ${loginCmd} to re-authenticate.`);
50474
50541
  };
50542
+ const transientRefreshError = (cause) => new CliError(5 /* Auth */, "AUTH", "Token refresh failed (transient).", cause, `Check network connectivity, or run ${loginCmd} to re-authenticate.`);
50543
+ const markTransientRefreshFailure = () => {
50544
+ const failedProf = getProfile(profileName, authPath);
50545
+ if (!failedProf)
50546
+ return;
50547
+ saveProfileWhileLocked(profileName, {
50548
+ ...failedProf,
50549
+ transientRefreshFailedAt: new Date().toISOString()
50550
+ }, authPath);
50551
+ };
50475
50552
  try {
50476
50553
  return await withAuthLock(authPath, async () => {
50477
50554
  const lockedProf = getProfile(profileName, authPath);
@@ -50486,14 +50563,20 @@ async function getValidToken(profile, signal) {
50486
50563
  if (!lockedTokens.refreshToken) {
50487
50564
  throw new CliError(5 /* Auth */, "AUTH", "Session expired.", undefined, `Run ${loginCmd} to re-authenticate.`);
50488
50565
  }
50566
+ if (refreshCooldownActive(lockedProf.transientRefreshFailedAt)) {
50567
+ log.info("auth.refresh.cooldown", { profile: profileName });
50568
+ throw transientRefreshError();
50569
+ }
50570
+ const budgetSignal = AbortSignal.timeout(options.refreshBudgetMs ?? AUTH_REFRESH_BUDGET_MS);
50571
+ const refreshSignal = signal ? AbortSignal.any([signal, budgetSignal]) : budgetSignal;
50489
50572
  const refreshStarted = Date.now();
50490
50573
  log.info("auth.refresh.start", {
50491
50574
  profile: profileName,
50492
50575
  client_id: lockedTokens.clientId
50493
50576
  });
50494
50577
  try {
50495
- const refreshed = await refreshAccessToken(lockedTokens, signal);
50496
- saveProfileWhileLocked(profileName, { ...lockedProf, tokens: refreshed }, authPath);
50578
+ const refreshed = await refreshAccessToken(lockedTokens, refreshSignal);
50579
+ saveProfileWhileLocked(profileName, withoutRefreshFailure({ ...lockedProf, tokens: refreshed }), authPath);
50497
50580
  log.info("auth.refresh.ok", {
50498
50581
  profile: profileName,
50499
50582
  duration_ms: Date.now() - refreshStarted,
@@ -50521,15 +50604,25 @@ async function getValidToken(profile, signal) {
50521
50604
  duration_ms: Date.now() - refreshStarted,
50522
50605
  error_name: err instanceof Error ? err.name : "Unknown"
50523
50606
  });
50524
- await delay2(1000, signal);
50607
+ try {
50608
+ await delay2(options.retryDelayMs ?? AUTH_REFRESH_RETRY_DELAY_MS, refreshSignal);
50609
+ } catch (delayErr) {
50610
+ if (signal?.aborted)
50611
+ throw delayErr;
50612
+ markTransientRefreshFailure();
50613
+ throw transientRefreshError(delayErr);
50614
+ }
50525
50615
  log.info("auth.refresh.retry", { profile: profileName, attempt: 2 });
50526
50616
  let retryStarted = Date.now();
50527
50617
  try {
50528
50618
  const retryProf = getProfile(profileName, authPath);
50529
50619
  const retryTokens = retryProf?.tokens ?? lockedTokens;
50530
50620
  retryStarted = Date.now();
50531
- const refreshed = await refreshAccessToken(retryTokens, signal);
50532
- saveProfileWhileLocked(profileName, { ...retryProf ?? lockedProf, tokens: refreshed }, authPath);
50621
+ const refreshed = await refreshAccessToken(retryTokens, refreshSignal);
50622
+ saveProfileWhileLocked(profileName, withoutRefreshFailure({
50623
+ ...retryProf ?? lockedProf,
50624
+ tokens: refreshed
50625
+ }), authPath);
50533
50626
  log.info("auth.refresh.ok", {
50534
50627
  profile: profileName,
50535
50628
  duration_ms: Date.now() - retryStarted,
@@ -50554,7 +50647,8 @@ async function getValidToken(profile, signal) {
50554
50647
  failTerminalRefresh(retryErr);
50555
50648
  }
50556
50649
  log.info("auth.refresh.failed", fields);
50557
- throw new CliError(5 /* Auth */, "AUTH", "Token refresh failed (transient).", retryErr, `Check network connectivity, or run ${loginCmd} to re-authenticate.`);
50650
+ markTransientRefreshFailure();
50651
+ throw transientRefreshError(retryErr);
50558
50652
  }
50559
50653
  }
50560
50654
  });
@@ -50873,7 +50967,7 @@ function shouldGuardDomain(domainPath, canonicalVerb, args) {
50873
50967
  }
50874
50968
  async function probeCapabilities(ctx) {
50875
50969
  try {
50876
- return await ctx.client.diagnostics.capabilities();
50970
+ return await (ctx.compatibilityClient ?? ctx.client).diagnostics.capabilities();
50877
50971
  } catch {
50878
50972
  return;
50879
50973
  }
@@ -50887,7 +50981,7 @@ async function checkCompatibility(ctx, domainPath, canonicalVerb, args) {
50887
50981
  }
50888
50982
  let capabilities;
50889
50983
  try {
50890
- const diagnostics = ctx.client.diagnostics;
50984
+ const diagnostics = (ctx.compatibilityClient ?? ctx.client).diagnostics;
50891
50985
  if (typeof diagnostics.assertCompatible === "function") {
50892
50986
  await diagnostics.assertCompatible();
50893
50987
  if (clientFlags.length > 0)
@@ -50896,6 +50990,8 @@ async function checkCompatibility(ctx, domainPath, canonicalVerb, args) {
50896
50990
  capabilities = await diagnostics.capabilities();
50897
50991
  }
50898
50992
  } catch (err) {
50993
+ if (err instanceof CliError && err.kind === "AUTH")
50994
+ throw err;
50899
50995
  const message = err instanceof Error ? err.message : String(err);
50900
50996
  if (message.includes("Could not find") || message.includes("NOT_FOUND") || message.includes("is not a function")) {
50901
50997
  ctx.err("Backend does not support capabilities check (upgrade backend)");
@@ -52245,7 +52341,7 @@ function pinnedWref(c, wref, version2) {
52245
52341
  return `${c.cyan}${escapeTerminalTextForDisplay(wref)}${c.reset}`;
52246
52342
  }
52247
52343
  const base = wref.replace(/@v\d+$/, "");
52248
- return `${c.cyan}${escapeTerminalTextForDisplay(base)}@v${version2}${c.reset}`;
52344
+ return `${c.cyan}${withVersion(escapeTerminalTextForDisplay(base), version2)}${c.reset}`;
52249
52345
  }
52250
52346
  function kindLabel(c, kind) {
52251
52347
  return `${c.dim}${kind}${c.reset}`;
@@ -52256,16 +52352,21 @@ function asCollectionSummaries(value) {
52256
52352
  const entries = value.filter((entry) => typeof entry === "object" && entry !== null && typeof entry.shape === "string");
52257
52353
  return entries.length > 0 ? entries : undefined;
52258
52354
  }
52259
- function bareShapeName(token) {
52355
+ function bareShapeName2(token) {
52260
52356
  const withoutVersion = token.split("@", 1)[0] ?? "";
52261
52357
  return withoutVersion.slice(withoutVersion.lastIndexOf("/") + 1);
52262
52358
  }
52263
- function effectiveKind(kind, shapeName, collections) {
52359
+ function effectiveKind(kind, collections) {
52264
52360
  if (kind !== "thing" && kind)
52265
52361
  return kind;
52266
52362
  const summaryShape = collections?.[0]?.shape;
52267
52363
  if (summaryShape)
52268
- return bareShapeName(summaryShape).toLowerCase();
52364
+ return bareShapeName2(summaryShape).toLowerCase();
52365
+ return kind;
52366
+ }
52367
+ function kindWithoutCertificate(kind, shapeName) {
52368
+ if (kind !== "thing" && kind)
52369
+ return kind;
52269
52370
  if (shapeName && isBuiltinCollectionShape(shapeName)) {
52270
52371
  return shapeName.toLowerCase();
52271
52372
  }
@@ -53177,9 +53278,6 @@ var handleCreate2 = async (ctx, { flags, args }) => {
53177
53278
  };
53178
53279
 
53179
53280
  // ../../packages/warmhub-cli/src/domains/thing/render.ts
53180
- function singularShapeName(result) {
53181
- return result.shapeName ?? result.shape;
53182
- }
53183
53281
  function renderHead(out, c, chars, result, org, repo, shape, kind) {
53184
53282
  const items = result.items ?? [];
53185
53283
  const decorations = getResponseDecorations(result);
@@ -53191,8 +53289,7 @@ function renderHead(out, c, chars, result, org, repo, shape, kind) {
53191
53289
  out(`${c.dim}${chars.hLine.repeat(60)}${c.reset}`);
53192
53290
  for (const item of items) {
53193
53291
  const wref = pinnedWref(c, item.wref ?? item.name ?? "(unknown)", item.version);
53194
- const shapeName = item.shapeName;
53195
- const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", shapeName, asCollectionSummaries(item.collections)));
53292
+ const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", asCollectionSummaries(item.collections)));
53196
53293
  const retractedTag = item.active === false ? ` ${c.red}[RETRACTED]${c.reset}` : "";
53197
53294
  out(` ${wref} ${kl}${retractedTag}`);
53198
53295
  if (item.declaredShapes?.length) {
@@ -53220,8 +53317,7 @@ function renderHead(out, c, chars, result, org, repo, shape, kind) {
53220
53317
  function renderThing(out, c, result) {
53221
53318
  const decorations = getResponseDecorations(result);
53222
53319
  const wref = result.wref ?? result.name ?? "(unknown)";
53223
- const shapeName = singularShapeName(result);
53224
- const displayKind = effectiveKind(result.kind ?? "thing", shapeName, result.collections);
53320
+ const displayKind = effectiveKind(result.kind ?? "thing", result.collections);
53225
53321
  const retractedTag = result.active === false ? ` ${c.red}[RETRACTED]${c.reset}` : "";
53226
53322
  out(`${pinnedWref(c, wref, result.version)} ${kindLabel(c, displayKind)}${retractedTag}`);
53227
53323
  out(` ${c.dim}wref:${c.reset} ${escapeTerminalTextForDisplay(wref)}`);
@@ -53301,8 +53397,7 @@ function renderGraphValue(out, c, value, indent, decorations) {
53301
53397
  }
53302
53398
  function renderGraphNode(out, c, result, indent = "", decorations) {
53303
53399
  const wref = result.wref ?? result.name ?? "(unknown)";
53304
- const shapeName = singularShapeName(result);
53305
- const displayKind = effectiveKind(result.kind ?? "thing", shapeName, result.collections);
53400
+ const displayKind = effectiveKind(result.kind ?? "thing", result.collections);
53306
53401
  out(`${indent}${pinnedWref(c, wref, result.version)} ${kindLabel(c, displayKind)}`);
53307
53402
  if (result.about) {
53308
53403
  out(`${indent} ${c.dim}about:${c.reset}`);
@@ -53342,7 +53437,9 @@ function renderHistory(out, c, result) {
53342
53437
  const decorations = getResponseDecorations(result);
53343
53438
  if (result.thing && typeof result.thing === "object") {
53344
53439
  const wref = result.thing.wref ?? result.thing.name ?? "(unknown)";
53345
- out(`${c.bold}History: ${pinnedWref(c, wref)}${c.reset} ${kindLabel(c, effectiveKind(result.thing.kind ?? "thing", result.thing.shapeName))}`);
53440
+ const newest = (result.versions ?? []).reduce((best, v) => !best || v.version > best.version ? v : best, undefined);
53441
+ const kind = effectiveKind(result.thing.kind ?? "thing", asCollectionSummaries(newest?.collections));
53442
+ out(`${c.bold}History: ${pinnedWref(c, wref)}${c.reset} ${kindLabel(c, kind)}`);
53346
53443
  }
53347
53444
  const firstMeta = result.versions?.[0]?.metadata;
53348
53445
  if (firstMeta?.durableId) {
@@ -53393,7 +53490,7 @@ function renderRefs(out, c, result, wref, direction) {
53393
53490
  out(`${c.dim}${"─".repeat(60)}${c.reset}`);
53394
53491
  for (const item of items) {
53395
53492
  const refWref = refDisplay(c, item.wref, decorations, item.version);
53396
- const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", item.shapeName));
53493
+ const kl = kindLabel(c, kindWithoutCertificate(item.kind ?? "thing", item.shapeName));
53397
53494
  const field = `${c.dim}via ${c.reset}${escapeTerminalTextForDisplay(item.fieldPath ?? "(unknown)")}`;
53398
53495
  const binding = item.binding ? ` ${c.dim}${item.binding}${c.reset}` : "";
53399
53496
  out(` ${refWref} ${kl} ${field}${binding}`);
@@ -53405,7 +53502,7 @@ function* walkBatchResult(wrefs, result, flagsVersion) {
53405
53502
  let missIdx = 0;
53406
53503
  for (const requested of wrefs) {
53407
53504
  const nextMiss = result.missing[missIdx];
53408
- const qualified = flagsVersion !== undefined && !/@v\d+$/.test(requested) ? `${requested}@v${flagsVersion}` : requested;
53505
+ const qualified = flagsVersion !== undefined && !/@v\d+$/.test(requested) ? withVersion(requested, flagsVersion) : requested;
53409
53506
  if (nextMiss !== undefined && (nextMiss === requested || nextMiss === qualified)) {
53410
53507
  yield { kind: "miss", requested, missWref: nextMiss };
53411
53508
  missIdx++;
@@ -53432,9 +53529,9 @@ function renderBatchView(out, c, result, wrefs, flagsVersion) {
53432
53529
  const requestedBase = requested.replace(/@.+$/, "");
53433
53530
  const fallback = item.wref ?? `${item.shapeName ?? "?"}/${item.name ?? "(unknown)"}`;
53434
53531
  const base = requestedBase.length > 0 ? requestedBase : fallback.replace(/@v\d+$/, "");
53435
- const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", item.shapeName, asCollectionSummaries(item.collections)));
53532
+ const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", asCollectionSummaries(item.collections)));
53436
53533
  const retractedTag = item.active === false ? ` ${c.red}[RETRACTED]${c.reset}` : "";
53437
- const display = labeledRef(c, `${base}@v${item.version}`, fallback) ?? `${escapeTerminalTextForDisplay(base)}@v${item.version}`;
53534
+ const display = labeledRef(c, withVersion(base, item.version), fallback) ?? withVersion(escapeTerminalTextForDisplay(base), item.version);
53438
53535
  out(` ${display} ${kl}${retractedTag}`);
53439
53536
  }
53440
53537
  if (result.missing.length > 0) {
@@ -54183,8 +54280,7 @@ function renderQueryResults(out, c, result) {
54183
54280
  }
54184
54281
  for (const item of items) {
54185
54282
  const wref = pinnedWref(c, item.wref ?? item.name ?? "(unknown)", item.version);
54186
- const shapeName = item.shapeName;
54187
- const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", shapeName, asCollectionSummaries(item.collections)));
54283
+ const kl = kindLabel(c, effectiveKind(item.kind ?? "thing", asCollectionSummaries(item.collections)));
54188
54284
  const retractedTag = item.active === false ? ` ${c.red}[RETRACTED]${c.reset}` : "";
54189
54285
  out(` ${wref} ${kl}${retractedTag}`);
54190
54286
  if (item.declaredShapes?.length) {
@@ -55552,7 +55648,143 @@ Run \`wh auth login --profile ${explicitProfile}\` to create it.`);
55552
55648
  clientFlags,
55553
55649
  decorateResponses: decorate
55554
55650
  });
55555
- return { config: config2, profile: effectiveProfile, client, clientFlags, decorate };
55651
+ const compatibilityClient = args.client ?? createUnauthenticatedClient(config2, {
55652
+ functionLogs: args.functionLogs,
55653
+ signal: args.signal,
55654
+ clientFlags,
55655
+ decorateResponses: decorate
55656
+ });
55657
+ return {
55658
+ config: config2,
55659
+ profile: effectiveProfile,
55660
+ client,
55661
+ compatibilityClient,
55662
+ clientFlags,
55663
+ decorate
55664
+ };
55665
+ }
55666
+
55667
+ // ../../packages/warmhub-cli/src/scope-parse.ts
55668
+ var ENTRY_KEYS = new Set([
55669
+ "resource",
55670
+ "permissions",
55671
+ "allowedMatches",
55672
+ "allowedShapes"
55673
+ ]);
55674
+ var SHAPE_LIST_KEYS = ["shapes", "shapesAll", "shapesNot"];
55675
+ var SHAPE_CLAUSE_KEYS = new Set([...SHAPE_LIST_KEYS, "shapeless"]);
55676
+ function shapeClauseExample(allowResource) {
55677
+ const resource = allowResource ? '"resource":"myorg/myrepo",' : "";
55678
+ return `[{${resource}"permissions":["repo:read"],"allowedMatches":["**"],"allowedShapes":{"shapes":["Player"],"shapesNot":["Secret"]}}]`;
55679
+ }
55680
+ function parseScopeEntriesJson(json2, opts) {
55681
+ const { flagLabel, allowResource } = opts;
55682
+ let parsed;
55683
+ try {
55684
+ parsed = JSON.parse(json2);
55685
+ } catch {
55686
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} must be valid JSON`);
55687
+ }
55688
+ if (!Array.isArray(parsed) || parsed.length === 0) {
55689
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} must be a non-empty JSON array`);
55690
+ }
55691
+ return parsed.map((entry, i) => {
55692
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
55693
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: must be an object`);
55694
+ }
55695
+ const obj = entry;
55696
+ const unknownKey = Object.keys(obj).find((key) => !ENTRY_KEYS.has(key));
55697
+ if (unknownKey !== undefined) {
55698
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: unknown key "${unknownKey}"`, undefined, `Entry keys are resource, permissions, allowedMatches, allowedShapes. Example: ${flagLabel} '${shapeClauseExample(allowResource)}'`);
55699
+ }
55700
+ if (!Array.isArray(obj.permissions) || obj.permissions.length === 0 || obj.permissions.some((p) => typeof p !== "string" || p.trim().length === 0)) {
55701
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "permissions" must be a non-empty array of non-empty strings`);
55702
+ }
55703
+ if (obj.resource !== undefined) {
55704
+ if (!allowResource) {
55705
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "resource" is not supported (resource is set automatically)`);
55706
+ }
55707
+ if (typeof obj.resource !== "string") {
55708
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "resource" must be a string`);
55709
+ }
55710
+ }
55711
+ if (obj.allowedMatches !== undefined) {
55712
+ if (!Array.isArray(obj.allowedMatches) || obj.allowedMatches.some((m) => typeof m !== "string" || m.trim().length === 0)) {
55713
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "allowedMatches" must be an array of non-empty strings`);
55714
+ }
55715
+ }
55716
+ const allowedShapes = obj.allowedShapes === undefined ? undefined : parseAllowedShapes(obj.allowedShapes, flagLabel, i + 1, allowResource);
55717
+ if (allowResource && (obj.allowedMatches !== undefined || allowedShapes !== undefined) && (typeof obj.resource !== "string" || !obj.resource.includes("/"))) {
55718
+ const fields = [
55719
+ obj.allowedMatches !== undefined && '"allowedMatches"',
55720
+ allowedShapes !== undefined && '"allowedShapes"'
55721
+ ].filter(Boolean).join(" and ");
55722
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: ${fields} would restrict nothing on ${typeof obj.resource === "string" ? `the org entry "${obj.resource}"` : "an entry without a resource"}; name and Shape restrictions apply only to a repository entry`, undefined, `Name the repository. Example: ${flagLabel} '${shapeClauseExample(allowResource)}'`);
55723
+ }
55724
+ const result = {
55725
+ permissions: obj.permissions.map((p) => p.trim())
55726
+ };
55727
+ if (obj.resource !== undefined)
55728
+ result.resource = obj.resource;
55729
+ if (obj.allowedMatches !== undefined)
55730
+ result.allowedMatches = obj.allowedMatches.map((m) => m.trim());
55731
+ if (allowedShapes !== undefined)
55732
+ result.allowedShapes = allowedShapes;
55733
+ return result;
55734
+ });
55735
+ }
55736
+ function parseAllowedShapes(value, flagLabel, entry, allowResource) {
55737
+ const refuse = (message) => {
55738
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${entry}: "allowedShapes" ${message}`, undefined, `Keys are shapes, shapesAll, shapesNot (1-${MAX_ALLOWED_SHAPES_PER_LIST} Shape names each) and shapeless (boolean). Example: ${flagLabel} '${shapeClauseExample(allowResource)}'`);
55739
+ };
55740
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
55741
+ refuse("must be an object");
55742
+ }
55743
+ const obj = value;
55744
+ const unknownKey = Object.keys(obj).find((key) => !SHAPE_CLAUSE_KEYS.has(key));
55745
+ if (unknownKey !== undefined)
55746
+ refuse(`has unknown key "${unknownKey}"`);
55747
+ const clause = {};
55748
+ for (const key of SHAPE_LIST_KEYS) {
55749
+ const list = obj[key];
55750
+ if (list === undefined)
55751
+ continue;
55752
+ if (!Array.isArray(list) || list.length === 0 || list.some((n) => typeof n !== "string" || n.trim().length === 0)) {
55753
+ refuse(`"${key}" must be a non-empty array of non-empty Shape names`);
55754
+ }
55755
+ const names = list;
55756
+ if (names.length > MAX_ALLOWED_SHAPES_PER_LIST) {
55757
+ refuse(`"${key}" names ${names.length} Shapes; the limit is ${MAX_ALLOWED_SHAPES_PER_LIST}`);
55758
+ }
55759
+ clause[key] = names.map((n) => n.trim());
55760
+ }
55761
+ if (obj.shapeless !== undefined) {
55762
+ if (typeof obj.shapeless !== "boolean")
55763
+ refuse('"shapeless" must be a boolean');
55764
+ clause.shapeless = obj.shapeless;
55765
+ }
55766
+ return clause;
55767
+ }
55768
+ function formatAllowedShapes(allowedShapes) {
55769
+ if (allowedShapes === undefined)
55770
+ return "";
55771
+ const parts = [];
55772
+ for (const key of SHAPE_LIST_KEYS) {
55773
+ const list = allowedShapes[key];
55774
+ if (list !== undefined) {
55775
+ parts.push(`${key}: ${list.length > 0 ? list.join(", ") : "[none]"}`);
55776
+ }
55777
+ }
55778
+ if (allowedShapes.shapeless !== undefined)
55779
+ parts.push(allowedShapes.shapeless ? "shapeless" : "no shapeless");
55780
+ return parts.map((part) => ` ${part}`).join("");
55781
+ }
55782
+ function formatAllowedMatches(allowedMatches) {
55783
+ if (allowedMatches === undefined)
55784
+ return "";
55785
+ if (allowedMatches.length === 0)
55786
+ return " match: [deny-all]";
55787
+ return ` match: ${allowedMatches.join(", ")}`;
55556
55788
  }
55557
55789
 
55558
55790
  // ../../packages/warmhub-cli/src/domains/auth-shared.ts
@@ -61723,10 +61955,11 @@ async function collectChecks(ctx) {
61723
61955
  if (whoami.scopes && whoami.scopes.length > 0) {
61724
61956
  const scopeParts = whoami.scopes.map((s) => {
61725
61957
  const perms = s.permissions.join(", ");
61958
+ const shapes = formatAllowedShapes(s.allowedShapes);
61726
61959
  if (s.redactedResource) {
61727
- return `${perms} on redacted/inaccessible repo`;
61960
+ return `${perms} on redacted/inaccessible repo${shapes}`;
61728
61961
  }
61729
- return s.resource ? `${perms} on ${s.resource}` : perms;
61962
+ return `${s.resource ? `${perms} on ${s.resource}` : perms}${shapes}`;
61730
61963
  });
61731
61964
  detailLines.push(`Scopes: ${scopeParts.join(", ")}`);
61732
61965
  }
@@ -67179,57 +67412,6 @@ var SUB_DOMAIN = defineDomain({
67179
67412
  }
67180
67413
  }
67181
67414
  });
67182
- // ../../packages/warmhub-cli/src/scope-parse.ts
67183
- function parseScopeEntriesJson(json2, opts) {
67184
- const { flagLabel, allowResource } = opts;
67185
- let parsed;
67186
- try {
67187
- parsed = JSON.parse(json2);
67188
- } catch {
67189
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} must be valid JSON`);
67190
- }
67191
- if (!Array.isArray(parsed) || parsed.length === 0) {
67192
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} must be a non-empty JSON array`);
67193
- }
67194
- return parsed.map((entry, i) => {
67195
- if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
67196
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: must be an object`);
67197
- }
67198
- const obj = entry;
67199
- if (!Array.isArray(obj.permissions) || obj.permissions.length === 0 || obj.permissions.some((p) => typeof p !== "string" || p.trim().length === 0)) {
67200
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "permissions" must be a non-empty array of non-empty strings`);
67201
- }
67202
- if (obj.resource !== undefined) {
67203
- if (!allowResource) {
67204
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "resource" is not supported (resource is set automatically)`);
67205
- }
67206
- if (typeof obj.resource !== "string") {
67207
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "resource" must be a string`);
67208
- }
67209
- }
67210
- if (obj.allowedMatches !== undefined) {
67211
- if (!Array.isArray(obj.allowedMatches) || obj.allowedMatches.some((m) => typeof m !== "string" || m.trim().length === 0)) {
67212
- throw new CliError(2 /* UserInput */, "USER_INPUT", `${flagLabel} entry ${i + 1}: "allowedMatches" must be an array of non-empty strings`);
67213
- }
67214
- }
67215
- const result = {
67216
- permissions: obj.permissions.map((p) => p.trim())
67217
- };
67218
- if (obj.resource !== undefined)
67219
- result.resource = obj.resource;
67220
- if (obj.allowedMatches !== undefined)
67221
- result.allowedMatches = obj.allowedMatches.map((m) => m.trim());
67222
- return result;
67223
- });
67224
- }
67225
- function formatAllowedMatches(allowedMatches) {
67226
- if (allowedMatches === undefined)
67227
- return "";
67228
- if (allowedMatches.length === 0)
67229
- return " match: [deny-all]";
67230
- return ` match: ${allowedMatches.join(", ")}`;
67231
- }
67232
-
67233
67415
  // ../../packages/warmhub-cli/src/domains/token.ts
67234
67416
  var DURATION_MULTIPLIERS = {
67235
67417
  h: 3600000,
@@ -67262,7 +67444,7 @@ var createFlags10 = {
67262
67444
  multiple: true
67263
67445
  }),
67264
67446
  "scopes-json": flag.string({
67265
- description: "Structured scope entries as JSON array (advanced; use for allowedMatches or repeated resource entries; mutually exclusive with --scope)"
67447
+ description: "Structured scope entries as JSON array (advanced; use for allowedMatches, allowedShapes, or repeated resource entries; mutually exclusive with --scope)"
67266
67448
  }),
67267
67449
  description: flag.string({ short: "d", description: "Token description" }),
67268
67450
  expires: flag.string({
@@ -67307,10 +67489,10 @@ function formatScopes(scopes) {
67307
67489
  return "full access";
67308
67490
  return scopes.map((e) => {
67309
67491
  if (e.redactedResource) {
67310
- return `redacted/inaccessible repo=${e.permissions.join(",")}${formatAllowedMatches(e.allowedMatches)}`;
67492
+ return `redacted/inaccessible repo=${e.permissions.join(",")}${formatAllowedMatches(e.allowedMatches)}${formatAllowedShapes(e.allowedShapes)}`;
67311
67493
  }
67312
67494
  const base = e.resource ? `${e.resource}=${e.permissions.join(",")}` : e.permissions.join(",");
67313
- return `${base}${formatAllowedMatches(e.allowedMatches)}`;
67495
+ return `${base}${formatAllowedMatches(e.allowedMatches)}${formatAllowedShapes(e.allowedShapes)}`;
67314
67496
  }).join(" ");
67315
67497
  }
67316
67498
  var handleCreate9 = async (ctx, { flags }) => {
@@ -68177,7 +68359,7 @@ var handleEvaluate = async (ctx, { args, flags }) => {
68177
68359
  nextCursor: result.nextCursor ?? null,
68178
68360
  decorations: getResponseDecorations(result)
68179
68361
  }, () => {
68180
- const selected = `${result.view.wref}@v${result.view.version}`;
68362
+ const selected = withVersion(result.view.wref, result.view.version);
68181
68363
  ctx.out(`${ctx.colors.bold}View ${escapeTerminalTextForDisplay(selected)}${ctx.colors.reset}`);
68182
68364
  renderQueryResults(ctx.out, ctx.colors, result);
68183
68365
  });
@@ -69712,9 +69894,17 @@ async function runPreparedCli(rawArgv, prepared, opts) {
69712
69894
  requestedMode: requestedFunctionLogs
69713
69895
  });
69714
69896
  const localOnlyCommand = isLocalOnlyInvocation(invocation);
69715
- const { config: config2, client, profile, clientFlags, decorate } = localOnlyCommand ? {
69897
+ const {
69898
+ config: config2,
69899
+ client,
69900
+ compatibilityClient,
69901
+ profile,
69902
+ clientFlags,
69903
+ decorate
69904
+ } = localOnlyCommand ? {
69716
69905
  config: loadConfig(),
69717
69906
  client: createLocalOnlyClient(),
69907
+ compatibilityClient: undefined,
69718
69908
  profile: "default",
69719
69909
  clientFlags: [],
69720
69910
  decorate: true
@@ -69735,6 +69925,7 @@ async function runPreparedCli(rawArgv, prepared, opts) {
69735
69925
  const signal = abortController.signal;
69736
69926
  const commandContext = {
69737
69927
  client,
69928
+ compatibilityClient,
69738
69929
  config: config2,
69739
69930
  invocation,
69740
69931
  profile,
@@ -69861,7 +70052,7 @@ function resolveLogLevel(flagLevel, env) {
69861
70052
  // package.json
69862
70053
  var package_default3 = {
69863
70054
  name: "@warmhub/cli",
69864
- version: "0.133.0",
70055
+ version: "0.135.0",
69865
70056
  private: false,
69866
70057
  type: "module",
69867
70058
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -70486,5 +70677,5 @@ process.exitCode = interceptedExitCode === undefined ? await runPreparedCli(laun
70486
70677
  version: package_default3.version
70487
70678
  }) : interceptedExitCode;
70488
70679
 
70489
- //# debugId=AF530C2A20E5B7C564756E2164756E21
70490
- //# warmhub-cli-build-info {"cliVersion":"0.133.0","sdkVersion":"0.131.0"}
70680
+ //# debugId=BE49CDDCED2454CC64756E2164756E21
70681
+ //# warmhub-cli-build-info {"cliVersion":"0.135.0","sdkVersion":"0.133.0"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.133.0",
3
+ "version": "0.135.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",