@warmhub/cli 0.88.0 → 0.90.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 (3) hide show
  1. package/README.md +4 -0
  2. package/dist/wh.js +1031 -489
  3. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -19389,6 +19389,19 @@ var ALL_BUILTIN_SHAPE_DEFS = {
19389
19389
  ...BUILTIN_VIEW_SHAPE_DEFS,
19390
19390
  ...BUILTIN_LICENSE_SHAPE_DEFS
19391
19391
  };
19392
+ // ../../packages/rules/src/client-flags.ts
19393
+ var CLIENT_FLAGS_HEADER = "X-WarmHub-Client-Flags";
19394
+ var CLIENT_FLAG_COMPATIBILITY_OVERRIDE = "compatibility-override";
19395
+ var KNOWN_CLIENT_FLAGS = new Set([
19396
+ CLIENT_FLAG_COMPATIBILITY_OVERRIDE
19397
+ ]);
19398
+ var CLIENT_FLAG_TOKEN_RE = /^[a-z0-9-]+$/;
19399
+ function isValidClientFlagToken(token) {
19400
+ return CLIENT_FLAG_TOKEN_RE.test(token);
19401
+ }
19402
+ function serializeClientFlags(flags) {
19403
+ return [...new Set(flags)].sort().join(",");
19404
+ }
19392
19405
  // ../../packages/rules/src/client-header.ts
19393
19406
  var CLIENT_HEADER = "X-WarmHub-Client";
19394
19407
  var WARMHUB_SDK_CLIENT_NAME = "@warmhub/sdk-ts";
@@ -19930,16 +19943,21 @@ function validateComponentManifestCliContract(manifest) {
19930
19943
  }
19931
19944
  return findings;
19932
19945
  }
19946
+ // ../../packages/rules/src/component-manifest-validate-types.ts
19947
+ function failureIfAny(errors, warnings) {
19948
+ const [first, ...rest] = errors;
19949
+ if (first === undefined)
19950
+ return;
19951
+ return { valid: false, errors: [first, ...rest], warnings };
19952
+ }
19953
+
19933
19954
  // ../../packages/rules/src/component-version.ts
19934
19955
  var SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
19935
- function isValidSemver(version) {
19936
- return SEMVER_RE.test(version);
19956
+ function parseSemver(version) {
19957
+ return SEMVER_RE.test(version) ? version : null;
19937
19958
  }
19938
- function parse(version) {
19959
+ function decompose(version) {
19939
19960
  const match = SEMVER_RE.exec(version);
19940
- if (!match) {
19941
- throw new Error(`Invalid semver: ${JSON.stringify(version)}`);
19942
- }
19943
19961
  return {
19944
19962
  major: Number(match[1]),
19945
19963
  minor: Number(match[2]),
@@ -19959,6 +19977,8 @@ function comparePrerelease(a, b) {
19959
19977
  for (let i = 0;i < len; i++) {
19960
19978
  const ai = a[i];
19961
19979
  const bi = b[i];
19980
+ if (ai === undefined || bi === undefined)
19981
+ break;
19962
19982
  if (ai === bi)
19963
19983
  continue;
19964
19984
  const aNum = NUMERIC_RE.test(ai);
@@ -19977,8 +19997,8 @@ function comparePrerelease(a, b) {
19977
19997
  return a.length < b.length ? -1 : 1;
19978
19998
  }
19979
19999
  function compareSemver(a, b) {
19980
- const pa = parse(a);
19981
- const pb = parse(b);
20000
+ const pa = decompose(a);
20001
+ const pb = decompose(b);
19982
20002
  if (pa.major !== pb.major)
19983
20003
  return pa.major < pb.major ? -1 : 1;
19984
20004
  if (pa.minor !== pb.minor)
@@ -19989,8 +20009,8 @@ function compareSemver(a, b) {
19989
20009
  }
19990
20010
 
19991
20011
  // ../../packages/rules/src/component-manifest-validate-json.ts
19992
- function fail(errors, warnings = []) {
19993
- return { valid: false, errors, warnings };
20012
+ function failWith(message) {
20013
+ return { valid: false, errors: [message], warnings: [] };
19994
20014
  }
19995
20015
  function isObject2(v) {
19996
20016
  return typeof v === "object" && v !== null && !Array.isArray(v);
@@ -20020,7 +20040,7 @@ function optionalStringArray(obj, field, path, errors) {
20020
20040
  }
20021
20041
  function validateComponentJson(data) {
20022
20042
  if (!isObject2(data)) {
20023
- return fail(["component.json must be a JSON object"]);
20043
+ return failWith("component.json must be a JSON object");
20024
20044
  }
20025
20045
  const errors = [];
20026
20046
  requireString(data, "id", "component", errors);
@@ -20029,11 +20049,8 @@ function validateComponentJson(data) {
20029
20049
  optionalString(data, "description", "component", errors);
20030
20050
  optionalString(data, "author", "component", errors);
20031
20051
  optionalStringArray(data, "tags", "component", errors);
20032
- if (errors.length > 0)
20033
- return fail(errors);
20034
- return {
20052
+ return failureIfAny(errors, []) ?? {
20035
20053
  valid: true,
20036
- errors: [],
20037
20054
  warnings: [],
20038
20055
  value: data
20039
20056
  };
@@ -20067,7 +20084,7 @@ function validateManifestComponent(data, errors) {
20067
20084
  requireString(data, "name", "manifest.component", errors);
20068
20085
  requireString(data, "version", "manifest.component", errors);
20069
20086
  if (typeof data.version === "string" && data.version.length > 0) {
20070
- if (!isValidSemver(data.version)) {
20087
+ if (parseSemver(data.version) === null) {
20071
20088
  errors.push(`manifest.component.version "${data.version}" is not valid semver (e.g. 1.2.3, 1.2.3-rc.1)`);
20072
20089
  }
20073
20090
  }
@@ -20260,7 +20277,7 @@ function validateTeardown(teardown, path, errors) {
20260
20277
  }
20261
20278
  function validateManifestJson(data) {
20262
20279
  if (!isObject2(data)) {
20263
- return fail(["manifest.json must be a JSON object"]);
20280
+ return failWith("manifest.json must be a JSON object");
20264
20281
  }
20265
20282
  const errors = [];
20266
20283
  const warnings = [];
@@ -20313,11 +20330,8 @@ function validateManifestJson(data) {
20313
20330
  if (data.cli !== undefined) {
20314
20331
  errors.push(...validateComponentManifestCliShape(data.cli).map((finding) => finding.message));
20315
20332
  }
20316
- if (errors.length > 0)
20317
- return { valid: false, errors, warnings };
20318
- return {
20333
+ return failureIfAny(errors, warnings) ?? {
20319
20334
  valid: true,
20320
- errors: [],
20321
20335
  warnings,
20322
20336
  value: data
20323
20337
  };
@@ -20538,17 +20552,27 @@ function joinFieldIdentityPath(...segments) {
20538
20552
  function joinFieldPathWithEscaper(escapeSegment, segments) {
20539
20553
  return segments.map((segment) => typeof segment === "number" ? `[${segment}]` : escapeSegment(segment)).join(".").replace(/\.\[/g, "[");
20540
20554
  }
20541
- // ../../packages/rules/src/tokens.ts
20542
- var COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE = "$N/#N commit-token syntax is no longer supported. Use explicit names and explicit wrefs. For assertions about newly created things, create the thing with a deterministic name and set about to that wref in the same commit.";
20543
- var ANY_TOKEN_RE = /[$#]\d+/;
20544
- function hasAnyTokens(s) {
20545
- return ANY_TOKEN_RE.test(s);
20555
+ // ../../packages/rules/src/org-qualified-ref.ts
20556
+ function splitOrgQualified(ref) {
20557
+ const parts = ref.split("/");
20558
+ if (parts.length !== 2)
20559
+ return null;
20560
+ const [first, second] = parts;
20561
+ if (!first || !second)
20562
+ return null;
20563
+ return [first, second];
20564
+ }
20565
+ function parseRepoSlug(ref) {
20566
+ const parts = splitOrgQualified(ref);
20567
+ return parts === null ? null : { org: parts[0], repo: parts[1] };
20568
+ }
20569
+ function parseComponentRef(ref) {
20570
+ const parts = splitOrgQualified(ref);
20571
+ return parts === null ? null : { org: parts[0], name: parts[1] };
20546
20572
  }
20547
-
20548
20573
  // ../../packages/rules/src/preflight-commit.ts
20549
20574
  function preflightCommitDiagnostics(operations, options) {
20550
20575
  const errors = [];
20551
- rejectCommitTokenSyntax(operations, errors, options);
20552
20576
  illegalOpSequences(operations, errors, options?.checkAddAdd ?? true, options);
20553
20577
  return errors;
20554
20578
  }
@@ -20558,33 +20582,6 @@ function sourceOperationIndex(filteredIndex, options) {
20558
20582
  function getOpName(op) {
20559
20583
  return op.name;
20560
20584
  }
20561
- function tokenStringFields(op) {
20562
- const fields = [getOpName(op), op.newName];
20563
- if (typeof op.about === "string") {
20564
- fields.push(op.about);
20565
- }
20566
- if (op.members) {
20567
- fields.push(...op.members);
20568
- }
20569
- return fields;
20570
- }
20571
- function rejectCommitTokenSyntax(operations, errors, options) {
20572
- for (let i = 0;i < operations.length; i++) {
20573
- const op = operations[i];
20574
- if (!op)
20575
- continue;
20576
- for (const field of tokenStringFields(op)) {
20577
- if (field && hasAnyTokens(field)) {
20578
- errors.push({
20579
- code: "COMMIT_TOKEN_SYNTAX_REMOVED",
20580
- operationIndex: sourceOperationIndex(i, options),
20581
- message: COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE
20582
- });
20583
- break;
20584
- }
20585
- }
20586
- }
20587
- }
20588
20585
  function illegalOpSequences(operations, errors, checkAddAdd, options) {
20589
20586
  const opHistory = new Map;
20590
20587
  for (let i = 0;i < operations.length; i++) {
@@ -20594,8 +20591,6 @@ function illegalOpSequences(operations, errors, checkAddAdd, options) {
20594
20591
  const name = getOpName(op);
20595
20592
  if (!name)
20596
20593
  continue;
20597
- if (hasAnyTokens(name))
20598
- continue;
20599
20594
  const kind = inferOperationKind({ ...op, name });
20600
20595
  const qualName = kind === "shape" ? `shape:${name}` : `thing:${name}`;
20601
20596
  const history = opHistory.get(qualName) ?? [];
@@ -20638,6 +20633,12 @@ var canonicalCollectionTypes = ["arc", "bond", "set", "list"];
20638
20633
  var collectionOps = ["add", "revise"];
20639
20634
  var COLLECTION_CREATE_REQUIRES_NAME_MESSAGE = "Collection create requires a name. Collections are ordinary named things (ADR 0004).";
20640
20635
  var COLLECTION_ABOUT_REMOVED_MESSAGE = 'about accepts a wref. Create the collection as its own named operation, then point the assertion at it. Prefer deterministic relationship names, for example: [{"operation":"add","kind":"collection","type":"arc","name":"a-to-b","members":["A","B"]},{"operation":"add","kind":"assertion","about":"Arc/a-to-b","name":"Assertion/example","data":{}}]. For CLI usage, use wh commit submit --file with the two operations.';
20636
+ function parseCollectionType(value) {
20637
+ return collectionTypes.find((candidate) => candidate === value) ?? null;
20638
+ }
20639
+ function parseCollectionOp(value) {
20640
+ return collectionOps.find((candidate) => candidate === value) ?? null;
20641
+ }
20641
20642
  function preflightOpDiagnostics(op, operationIndex) {
20642
20643
  const errors = [];
20643
20644
  errors.push(...builtinShapeGuard(op, operationIndex));
@@ -20770,7 +20771,7 @@ function validateCollectionOps(op, operationIndex) {
20770
20771
  const errors = [];
20771
20772
  if (op.kind !== "collection")
20772
20773
  return errors;
20773
- if (!collectionOps.includes(op.operation)) {
20774
+ if (parseCollectionOp(op.operation) === null) {
20774
20775
  return errors;
20775
20776
  }
20776
20777
  if (op.operation === "add" && !op.name) {
@@ -20780,7 +20781,8 @@ function validateCollectionOps(op, operationIndex) {
20780
20781
  message: COLLECTION_CREATE_REQUIRES_NAME_MESSAGE
20781
20782
  });
20782
20783
  }
20783
- if (!op.type || !collectionTypes.includes(op.type)) {
20784
+ const collectionType = parseCollectionType(op.type);
20785
+ if (collectionType === null) {
20784
20786
  errors.push({
20785
20787
  code: "VALIDATION_ERROR",
20786
20788
  operationIndex,
@@ -20804,8 +20806,8 @@ function validateCollectionOps(op, operationIndex) {
20804
20806
  }
20805
20807
  }
20806
20808
  }
20807
- if (op.type && op.members) {
20808
- const arityError = collectionArityError(op.type, op.members);
20809
+ if (collectionType !== null && op.members) {
20810
+ const arityError = collectionArityError(collectionType, op.members);
20809
20811
  if (arityError) {
20810
20812
  errors.push({
20811
20813
  code: "VALIDATION_ERROR",
@@ -20827,6 +20829,10 @@ function collectionArityError(tag, members) {
20827
20829
  case "set":
20828
20830
  case "list":
20829
20831
  return members.length < 1 ? `${tag === "set" ? "Set" : "List"} requires at least 1 member, got 0` : null;
20832
+ default: {
20833
+ const unhandled = tag;
20834
+ return unhandled;
20835
+ }
20830
20836
  }
20831
20837
  }
20832
20838
  // ../../packages/rules/src/preflight.ts
@@ -20896,7 +20902,7 @@ __export(exports_external, {
20896
20902
  pipe: () => pipe,
20897
20903
  partialRecord: () => partialRecord,
20898
20904
  parseAsync: () => parseAsync2,
20899
- parse: () => parse4,
20905
+ parse: () => parse3,
20900
20906
  overwrite: () => _overwrite,
20901
20907
  optional: () => optional,
20902
20908
  object: () => object,
@@ -21098,7 +21104,7 @@ __export(exports_core2, {
21098
21104
  process: () => process2,
21099
21105
  prettifyError: () => prettifyError,
21100
21106
  parseAsync: () => parseAsync,
21101
- parse: () => parse2,
21107
+ parse: () => parse,
21102
21108
  meta: () => meta,
21103
21109
  locales: () => exports_locales,
21104
21110
  isValidJWT: () => isValidJWT,
@@ -22282,7 +22288,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
22282
22288
  }
22283
22289
  return result.value;
22284
22290
  };
22285
- var parse2 = /* @__PURE__ */ _parse($ZodRealError);
22291
+ var parse = /* @__PURE__ */ _parse($ZodRealError);
22286
22292
  var _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
22287
22293
  const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
22288
22294
  let result = schema._zod.run({ value, issues: [] }, ctx);
@@ -25069,10 +25075,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
25069
25075
  throw new Error("implement() must be called with a function");
25070
25076
  }
25071
25077
  return function(...args) {
25072
- const parsedArgs = inst._def.input ? parse2(inst._def.input, args) : args;
25078
+ const parsedArgs = inst._def.input ? parse(inst._def.input, args) : args;
25073
25079
  const result = Reflect.apply(func, this, parsedArgs);
25074
25080
  if (inst._def.output) {
25075
- return parse2(inst._def.output, result);
25081
+ return parse(inst._def.output, result);
25076
25082
  }
25077
25083
  return result;
25078
25084
  };
@@ -33294,7 +33300,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, {
33294
33300
  });
33295
33301
 
33296
33302
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/parse.js
33297
- var parse4 = /* @__PURE__ */ _parse(ZodRealError);
33303
+ var parse3 = /* @__PURE__ */ _parse(ZodRealError);
33298
33304
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
33299
33305
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
33300
33306
  var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -33357,7 +33363,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
33357
33363
  inst.def = def;
33358
33364
  inst.type = def.type;
33359
33365
  Object.defineProperty(inst, "_def", { value: def });
33360
- inst.parse = (data, params) => parse4(inst, data, params, { callee: inst.parse });
33366
+ inst.parse = (data, params) => parse3(inst, data, params, { callee: inst.parse });
33361
33367
  inst.safeParse = (data, params) => safeParse2(inst, data, params);
33362
33368
  inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
33363
33369
  inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
@@ -35417,16 +35423,8 @@ var BASE_PRIMITIVE_TYPES = [
35417
35423
  ];
35418
35424
  var BASE_PRIMITIVE_TYPE_SET = new Set(BASE_PRIMITIVE_TYPES);
35419
35425
  var VALID_PRIMITIVE_TYPES = new Set([
35420
- "number",
35421
- "string",
35422
- "boolean",
35423
- "wref",
35424
- "array",
35425
- "number?",
35426
- "string?",
35427
- "boolean?",
35428
- "wref?",
35429
- "array?"
35426
+ ...BASE_PRIMITIVE_TYPES,
35427
+ ...BASE_PRIMITIVE_TYPES.map((type) => `${type}?`)
35430
35428
  ]);
35431
35429
  function isPlainObject2(value) {
35432
35430
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -42601,6 +42599,54 @@ var SYSTEM_INFRA_SHAPE_NAMES = new Set(SYSTEM_COMPONENTS.filter((entry) => entry
42601
42599
  function findSystemComponent(componentId) {
42602
42600
  return SYSTEM_COMPONENTS.find((entry) => entry.componentId === componentId);
42603
42601
  }
42602
+ // ../../packages/sdk-ts/src/grant-client.ts
42603
+ function createGrantClient(getTrpc, mapError) {
42604
+ return {
42605
+ create: async (orgName, repoName, input) => {
42606
+ try {
42607
+ return await getTrpc().grant.create.mutate({
42608
+ orgName,
42609
+ repoName,
42610
+ ...input
42611
+ });
42612
+ } catch (error51) {
42613
+ throw mapError(error51);
42614
+ }
42615
+ },
42616
+ get: async (orgName, repoName, grantId) => {
42617
+ try {
42618
+ return await getTrpc().grant.get.query({ orgName, repoName, grantId });
42619
+ } catch (error51) {
42620
+ throw mapError(error51);
42621
+ }
42622
+ },
42623
+ list: async (orgName, repoName, opts) => {
42624
+ try {
42625
+ return await getTrpc().grant.list.query({
42626
+ orgName,
42627
+ repoName,
42628
+ limit: opts?.limit,
42629
+ cursor: opts?.cursor
42630
+ });
42631
+ } catch (error51) {
42632
+ throw mapError(error51);
42633
+ }
42634
+ },
42635
+ revoke: async (orgName, repoName, grantId, opts) => {
42636
+ try {
42637
+ return await getTrpc().grant.revoke.mutate({
42638
+ orgName,
42639
+ repoName,
42640
+ grantId,
42641
+ reason: opts?.reason
42642
+ });
42643
+ } catch (error51) {
42644
+ throw mapError(error51);
42645
+ }
42646
+ }
42647
+ };
42648
+ }
42649
+
42604
42650
  // ../../packages/sdk-ts/src/repository-checkpoint-client.ts
42605
42651
  function normalizeRepositoryCheckpointStatus(status) {
42606
42652
  return {
@@ -42894,8 +42940,8 @@ function normalizeOptionalName(value) {
42894
42940
 
42895
42941
  // ../../packages/sdk-ts/src/operation-normalize.ts
42896
42942
  function toBackendStreamOperation(operation) {
42897
- if (operation.expectedVersion !== undefined && operation.operation !== "revise" && operation.operation !== "retract") {
42898
- throw new Error("expectedVersion is only valid on revise or retract operations — set an explicit operation discriminator");
42943
+ if (operation.expectedVersion !== undefined && operation.operation !== "revise" && operation.operation !== "retract" && operation.operation !== "reaffirm") {
42944
+ throw new Error("expectedVersion is only valid on revise, retract, or reaffirm operations — set an explicit operation discriminator");
42899
42945
  }
42900
42946
  if (operation.operation === "retract") {
42901
42947
  return {
@@ -42907,6 +42953,17 @@ function toBackendStreamOperation(operation) {
42907
42953
  ...operation.leaseId ? { leaseId: operation.leaseId } : {}
42908
42954
  };
42909
42955
  }
42956
+ if (operation.operation === "reaffirm") {
42957
+ return {
42958
+ operation: "reaffirm",
42959
+ name: operation.name,
42960
+ ...operation.expectedVersion !== undefined ? { expectedVersion: operation.expectedVersion } : {},
42961
+ ...operation.kind ? { kind: operation.kind } : {},
42962
+ ...operation.add ? { add: operation.add } : {},
42963
+ ...operation.remove ? { remove: operation.remove } : {},
42964
+ ...operation.leaseId ? { leaseId: operation.leaseId } : {}
42965
+ };
42966
+ }
42910
42967
  if (operation.operation === "rename") {
42911
42968
  return {
42912
42969
  operation: "rename",
@@ -42924,6 +42981,9 @@ function toBackendStreamOperation(operation) {
42924
42981
  if (Object.hasOwn(operation, "active")) {
42925
42982
  throw new Error(`${kind2} revise operation no longer supports 'active' — use retract('${name}') instead`);
42926
42983
  }
42984
+ if (kind2 !== "assertion" && operation.affirmedTargets !== undefined) {
42985
+ throw new Error(`${kind2} revise operation does not support 'affirmedTargets' — it applies only to assertions; set kind: 'assertion' explicitly`);
42986
+ }
42927
42987
  if (kind2 === "collection") {
42928
42988
  return normalizeBackendCollectionRevise(operation, "commit.apply");
42929
42989
  }
@@ -42936,6 +42996,7 @@ function toBackendStreamOperation(operation) {
42936
42996
  kind: "assertion",
42937
42997
  name,
42938
42998
  data: operation.data,
42999
+ ...operation.affirmedTargets ? { affirmedTargets: operation.affirmedTargets } : {},
42939
43000
  ...operation.expectedVersion !== undefined ? { expectedVersion: operation.expectedVersion } : {},
42940
43001
  ...operation.leaseId ? { leaseId: operation.leaseId } : {}
42941
43002
  };
@@ -42954,6 +43015,9 @@ function toBackendStreamOperation(operation) {
42954
43015
  if (kind !== "collection" && (("type" in operation) && operation.type !== undefined || ("members" in operation) && operation.members !== undefined)) {
42955
43016
  throw new Error(`add operation '${operation.name ?? ""}' has collection fields but resolved kind '${kind}' — collection adds require both 'type' and 'members', or set kind: 'collection'`);
42956
43017
  }
43018
+ if (kind !== "assertion" && operation.affirmedTargets !== undefined) {
43019
+ throw new Error(`${kind} add operation does not support 'affirmedTargets' — it applies only to assertions; set kind: 'assertion' explicitly`);
43020
+ }
42957
43021
  if (kind === "collection") {
42958
43022
  return normalizeBackendCollectionAdd({ ...operation, skipExisting }, "commit.apply");
42959
43023
  }
@@ -42976,6 +43040,7 @@ function toBackendStreamOperation(operation) {
42976
43040
  name: operation.name,
42977
43041
  about: operation.about,
42978
43042
  data: operation.data,
43043
+ ...operation.affirmedTargets ? { affirmedTargets: operation.affirmedTargets } : {},
42979
43044
  ...skipExisting === true ? { skipExisting } : {}
42980
43045
  };
42981
43046
  }
@@ -43360,11 +43425,12 @@ function aggregateSubmittedStreamResult(input) {
43360
43425
  operations: input.results.map((result) => ({
43361
43426
  ...result.opIndex !== undefined ? { opIndex: result.opIndex } : {},
43362
43427
  name: result.name ?? "",
43363
- operation: result.operation === "revise" || result.operation === "retract" || result.operation === "rename" || result.operation === "noop" ? result.operation : "add",
43428
+ operation: result.operation === "revise" || result.operation === "retract" || result.operation === "reaffirm" || result.operation === "rename" || result.operation === "noop" ? result.operation : "add",
43364
43429
  dataHash: result.dataHash ?? "",
43365
43430
  version: result.version ?? 0,
43366
43431
  status: streamAppendResultStatus(result),
43367
43432
  error: result.error,
43433
+ ...result.affirmations ? { affirmations: result.affirmations } : {},
43368
43434
  ...result.status === "failed" && result.opIndex !== undefined && input.operations[result.opIndex]?.name !== undefined ? { submittedName: input.operations[result.opIndex]?.name } : {},
43369
43435
  ...result.resolvedName !== undefined ? { resolvedName: result.resolvedName } : {},
43370
43436
  ...result.retryable !== undefined ? { retryable: result.retryable } : {},
@@ -43379,7 +43445,7 @@ function completedOperationsFrom(result) {
43379
43445
  // ../../packages/sdk-ts/package.json
43380
43446
  var package_default = {
43381
43447
  name: "@warmhub/sdk-ts",
43382
- version: "0.86.0",
43448
+ version: "0.88.0",
43383
43449
  private: false,
43384
43450
  type: "module",
43385
43451
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -43514,21 +43580,23 @@ function clientCompatibilityFailure(capabilities, identity2) {
43514
43580
  hint: "Upgrade the WarmHub backend before retrying this write."
43515
43581
  };
43516
43582
  }
43517
- const minimum = capabilities.minSupportedClients[identity2.name];
43518
- if (typeof minimum !== "string" || !isValidSemver(minimum)) {
43583
+ const advertised = capabilities.minSupportedClients[identity2.name];
43584
+ const minimum = typeof advertised === "string" ? parseSemver(advertised) : null;
43585
+ if (!minimum) {
43519
43586
  return {
43520
43587
  message: `The backend does not advertise a valid compatibility floor for ${identity2.name}.`,
43521
43588
  hint: "Upgrade the WarmHub backend or register this first-party client family before writing."
43522
43589
  };
43523
43590
  }
43524
43591
  if (!sdkVersionIsDevelopment(identity2.version)) {
43525
- if (!isValidSemver(identity2.version)) {
43592
+ const version2 = parseSemver(identity2.version);
43593
+ if (!version2) {
43526
43594
  return {
43527
43595
  message: `${identity2.name} reported malformed version "${identity2.version}".`,
43528
43596
  hint: "Use a released WarmHub client with a SemVer package version."
43529
43597
  };
43530
43598
  }
43531
- if (compareSemver(identity2.version, minimum) < 0) {
43599
+ if (compareSemver(version2, minimum) < 0) {
43532
43600
  return {
43533
43601
  message: `${identity2.name} ${identity2.version} is older than the backend's minimum supported version ${minimum}.`,
43534
43602
  hint: clientUpgradeHint(identity2.name)
@@ -43556,7 +43624,8 @@ var WARMHUB_CLIENT_OPTION_NAMES = [
43556
43624
  "accessToken",
43557
43625
  "auth",
43558
43626
  "functionLogs",
43559
- "client"
43627
+ "client",
43628
+ "clientFlags"
43560
43629
  ];
43561
43630
  var WARMHUB_CLIENT_OPTION_NAME_SET = new Set(WARMHUB_CLIENT_OPTION_NAMES);
43562
43631
  var ACCESS_TOKEN_OPTION_ALIASES = new Set(["token", "apiKey", "bearer"]);
@@ -43572,6 +43641,17 @@ function validateWarmHubClientOptions(options) {
43572
43641
  throw new TypeError(`Unknown WarmHubClient option "${key}"${hint}`);
43573
43642
  }
43574
43643
  }
43644
+ function normalizeClientFlags(flags) {
43645
+ if (!flags || flags.length === 0) {
43646
+ return [];
43647
+ }
43648
+ for (const token of flags) {
43649
+ if (!isValidClientFlagToken(token)) {
43650
+ throw new TypeError(`Invalid client flag "${token}": expected lowercase tokens matching [a-z0-9-]+.`);
43651
+ }
43652
+ }
43653
+ return [...new Set(flags)].sort();
43654
+ }
43575
43655
  var DEFAULT_API_URL = "https://api.warmhub.ai";
43576
43656
  var UNBATCHED_TRPC_PATHS = new Set([
43577
43657
  "repo.shapeInstanceCounts",
@@ -43891,9 +43971,11 @@ function connectionErrorMessage(url2) {
43891
43971
  function sdkVersionIsBelowMinimum(version2, minimum) {
43892
43972
  if (sdkVersionIsDevelopment(version2))
43893
43973
  return false;
43894
- if (!isValidSemver(version2) || !isValidSemver(minimum))
43974
+ const parsed = parseSemver(version2);
43975
+ const floor = parseSemver(minimum);
43976
+ if (!parsed || !floor)
43895
43977
  return false;
43896
- return compareSemver(version2, minimum) < 0;
43978
+ return compareSemver(parsed, floor) < 0;
43897
43979
  }
43898
43980
  function clientIncompatible(message, hint) {
43899
43981
  return new WarmHubError("CLIENT_INCOMPATIBLE", message, 412, hint);
@@ -43910,10 +43992,22 @@ class WarmHubClient {
43910
43992
  fetchImpl;
43911
43993
  accessToken;
43912
43994
  clientIdentity;
43995
+ clientFlags;
43913
43996
  functionLogMode;
43914
43997
  getToken;
43915
43998
  compatibilityCheck;
43999
+ overrideNoticePrinted = false;
44000
+ noteCompatibilityOverride() {
44001
+ if (this.overrideNoticePrinted)
44002
+ return;
44003
+ this.overrideNoticePrinted = true;
44004
+ console.error(`warmhub: compatibility checks overridden by client flag ${CLIENT_FLAG_COMPATIBILITY_OVERRIDE}; the server remains authoritative.`);
44005
+ }
43916
44006
  assertWriteCompatible() {
44007
+ if (this.clientFlags.includes(CLIENT_FLAG_COMPATIBILITY_OVERRIDE)) {
44008
+ this.noteCompatibilityOverride();
44009
+ return Promise.resolve();
44010
+ }
43917
44011
  if (sdkVersionIsDevelopment(this.clientIdentity.version) && isProductionApiUrl(this.apiUrl, DEFAULT_API_URL)) {
43918
44012
  return Promise.reject(clientIncompatible(`Development client ${this.clientIdentity.name}/${this.clientIdentity.version} cannot write to production.`, "Install a released WarmHub client artifact before writing to api.warmhub.ai."));
43919
44013
  }
@@ -45224,6 +45318,32 @@ class WarmHubClient {
45224
45318
  }
45225
45319
  }
45226
45320
  };
45321
+ view = {
45322
+ evaluate: async (orgName, repoName, wref, opts) => {
45323
+ try {
45324
+ return await this.trpc.view.evaluate.query({
45325
+ orgName,
45326
+ repoName,
45327
+ wref,
45328
+ limit: opts?.limit,
45329
+ cursor: opts?.cursor
45330
+ });
45331
+ } catch (error51) {
45332
+ throw toWarmHubError(error51);
45333
+ }
45334
+ },
45335
+ evaluateIter: (orgName, repoName, wref, opts) => {
45336
+ return paginate((cursor) => this.view.evaluate(orgName, repoName, wref, { ...opts, cursor }), (page) => page.items, opts?.cursor);
45337
+ },
45338
+ evaluateAll: async (orgName, repoName, wref, opts) => {
45339
+ const { max, ...pageOpts } = opts ?? {};
45340
+ return await collectPaginatedPages((cursor) => this.view.evaluate(orgName, repoName, wref, {
45341
+ ...pageOpts,
45342
+ cursor
45343
+ }), (page) => page.items, max, pageOpts.cursor);
45344
+ }
45345
+ };
45346
+ grant = createGrantClient(() => this.trpc, toWarmHubError);
45227
45347
  thing = {
45228
45348
  head: async (orgName, repoName, opts) => {
45229
45349
  try {
@@ -45471,6 +45591,7 @@ class WarmHubClient {
45471
45591
  repoName,
45472
45592
  shape: opts?.shape,
45473
45593
  about: opts?.about,
45594
+ affirmedAbout: opts?.affirmedAbout,
45474
45595
  kind: narrowKind(opts?.kind),
45475
45596
  match: opts?.match,
45476
45597
  includeRetracted: opts?.includeRetracted,
@@ -45803,6 +45924,7 @@ class WarmHubClient {
45803
45924
  name: options?.client?.name ?? WARMHUB_SDK_CLIENT_NAME,
45804
45925
  version: options?.client?.version ?? SDK_VERSION
45805
45926
  };
45927
+ this.clientFlags = normalizeClientFlags(options?.clientFlags);
45806
45928
  if (typeof this.accessToken === "function") {
45807
45929
  const provider = this.accessToken;
45808
45930
  this.getToken = async () => await provider();
@@ -45833,7 +45955,8 @@ class WarmHubClient {
45833
45955
  apiUrl: this.apiUrl,
45834
45956
  fetch: this.fetchImpl,
45835
45957
  accessToken,
45836
- client: this.clientIdentity
45958
+ client: this.clientIdentity,
45959
+ clientFlags: this.clientFlags
45837
45960
  });
45838
45961
  }
45839
45962
  actions = this.action;
@@ -45906,6 +46029,9 @@ class WarmHubClient {
45906
46029
  if (!headers.has(CLIENT_HEADER)) {
45907
46030
  headers.set(CLIENT_HEADER, formatClientHeader(this.clientIdentity.name, this.clientIdentity.version));
45908
46031
  }
46032
+ if (this.clientFlags.length > 0 && !headers.has(CLIENT_FLAGS_HEADER)) {
46033
+ headers.set(CLIENT_FLAGS_HEADER, serializeClientFlags(this.clientFlags));
46034
+ }
45909
46035
  }
45910
46036
  async fetchWithAuth(input, init) {
45911
46037
  const fetchImpl = this.fetchImpl ?? globalThis.fetch;
@@ -46173,7 +46299,9 @@ var CONFLICT_SHAPED_CODES = new Set([
46173
46299
  "REPO_PENDING_DELETE",
46174
46300
  "ALREADY_RETRACTED",
46175
46301
  "LEASE_UNAVAILABLE",
46176
- "INCREMENTAL_READ_UNAVAILABLE"
46302
+ "INCREMENTAL_READ_UNAVAILABLE",
46303
+ "VIEW_EVALUATION_UNAVAILABLE",
46304
+ "IDEMPOTENCY_CONFLICT"
46177
46305
  ]);
46178
46306
 
46179
46307
  // ../../packages/warmhub-cli/src/errors-types.ts
@@ -46652,11 +46780,13 @@ function cliErrorFromAllFailed(failures) {
46652
46780
  return bestErr;
46653
46781
  return new CliError(4 /* Backend */, "BACKEND", `All ${failures.length} operations failed`);
46654
46782
  }
46655
- function assertSingleOpSuccess(result) {
46783
+ function requireSingleOpSuccess(result) {
46656
46784
  const op = result.operations[0];
46657
- if (!op || !isFailedOpStatus(op.status))
46658
- return;
46659
- throw cliErrorFromOpFailure(op);
46785
+ if (!op)
46786
+ throw new Error("Commit returned no operation result");
46787
+ if (isFailedOpStatus(op.status))
46788
+ throw cliErrorFromOpFailure(op);
46789
+ return op;
46660
46790
  }
46661
46791
 
46662
46792
  // ../../packages/warmhub-cli/src/args.ts
@@ -48010,9 +48140,11 @@ async function modifyStore(mutator, path) {
48010
48140
  return result;
48011
48141
  });
48012
48142
  }
48013
- async function saveProfileLocked(name, profile, path) {
48143
+ async function saveProfileWithFlagsLocked(name, profile, flags, path) {
48014
48144
  await modifyStore((store) => {
48015
- setProfile(store, name, profile);
48145
+ const stored = hasProfile(store, name) ? store.profiles[name]?.flags : undefined;
48146
+ const resolved = flags ?? (Array.isArray(stored) ? stored : undefined);
48147
+ setProfile(store, name, resolved?.length ? { ...profile, flags: [...resolved] } : profile);
48016
48148
  }, path);
48017
48149
  }
48018
48150
  async function deleteProfileLocked(name, path) {
@@ -48392,7 +48524,8 @@ function createClient(config2, opts = {}) {
48392
48524
  },
48393
48525
  fetch: createBenchmarkAwareFetch(benchmarkId, opts.signal),
48394
48526
  functionLogs: opts.functionLogs,
48395
- client: cliClientIdentity()
48527
+ client: cliClientIdentity(),
48528
+ clientFlags: opts.clientFlags
48396
48529
  });
48397
48530
  }
48398
48531
  function createUnauthenticatedClient(config2, opts = {}) {
@@ -48401,7 +48534,8 @@ function createUnauthenticatedClient(config2, opts = {}) {
48401
48534
  apiUrl: config2.apiUrl,
48402
48535
  fetch: createBenchmarkAwareFetch(benchmarkId, opts.signal),
48403
48536
  functionLogs: opts.functionLogs,
48404
- client: cliClientIdentity()
48537
+ client: cliClientIdentity(),
48538
+ clientFlags: opts.clientFlags
48405
48539
  });
48406
48540
  }
48407
48541
  function wantsStructuredLiveOutput(format) {
@@ -48434,7 +48568,8 @@ async function runLive(opts) {
48434
48568
  auth,
48435
48569
  fetch: createBenchmarkAwareFetch(benchmarkId, controller.signal),
48436
48570
  functionLogs: opts.functionLogs,
48437
- client: cliClientIdentity()
48571
+ client: cliClientIdentity(),
48572
+ clientFlags: opts.clientFlags
48438
48573
  });
48439
48574
  if (opts.signal) {
48440
48575
  if (opts.signal.aborted)
@@ -48516,15 +48651,29 @@ function shouldGuardDomain(domainPath, canonicalVerb, args) {
48516
48651
  }
48517
48652
  return true;
48518
48653
  }
48654
+ async function probeCapabilities(ctx) {
48655
+ try {
48656
+ return await ctx.client.diagnostics.capabilities();
48657
+ } catch {
48658
+ return;
48659
+ }
48660
+ }
48519
48661
  async function checkCompatibility(ctx, domainPath, canonicalVerb, args) {
48520
48662
  if (!shouldGuardDomain(domainPath, canonicalVerb, args))
48521
48663
  return;
48664
+ const clientFlags = ctx.clientFlags ?? [];
48665
+ if (clientFlags.includes(CLIENT_FLAG_COMPATIBILITY_OVERRIDE)) {
48666
+ ctx.err(`compatibility checks overridden by client flag ${CLIENT_FLAG_COMPATIBILITY_OVERRIDE}`);
48667
+ }
48668
+ let capabilities;
48522
48669
  try {
48523
48670
  const diagnostics = ctx.client.diagnostics;
48524
48671
  if (typeof diagnostics.assertCompatible === "function") {
48525
48672
  await diagnostics.assertCompatible();
48673
+ if (clientFlags.length > 0)
48674
+ capabilities = await probeCapabilities(ctx);
48526
48675
  } else {
48527
- await diagnostics.capabilities();
48676
+ capabilities = await diagnostics.capabilities();
48528
48677
  }
48529
48678
  } catch (err) {
48530
48679
  const message = err instanceof Error ? err.message : String(err);
@@ -48533,6 +48682,17 @@ async function checkCompatibility(ctx, domainPath, canonicalVerb, args) {
48533
48682
  } else {
48534
48683
  ctx.err(`Could not verify compatibility: ${message}`);
48535
48684
  }
48685
+ if (clientFlags.length > 0)
48686
+ capabilities = await probeCapabilities(ctx);
48687
+ }
48688
+ if (clientFlags.length === 0 || !capabilities)
48689
+ return;
48690
+ const echoed = capabilities.honoredClientFlags;
48691
+ const honored = new Set(Array.isArray(echoed) ? echoed : []);
48692
+ for (const flagName of clientFlags) {
48693
+ if (honored.has(flagName))
48694
+ continue;
48695
+ ctx.err(`client flag "${flagName}" is not honored by this backend`);
48536
48696
  }
48537
48697
  }
48538
48698
 
@@ -48603,15 +48763,9 @@ function getRepoRef(ctx) {
48603
48763
  return r[r.length - 1];
48604
48764
  return;
48605
48765
  }
48606
- function splitRepoSlug(ref) {
48607
- const parts = ref.split("/");
48608
- if (parts.length !== 2 || !parts[0] || !parts[1])
48609
- return null;
48610
- return { org: parts[0], repo: parts[1] };
48611
- }
48612
48766
  function parseOrgRepo(ref, config2) {
48613
48767
  if (ref?.includes("/")) {
48614
- const parsed = splitRepoSlug(ref);
48768
+ const parsed = parseRepoSlug(ref);
48615
48769
  if (!parsed) {
48616
48770
  throw new CliError(3 /* Config */, "CONFIG", `Invalid repo format "${ref}". Expected "org/repo".`);
48617
48771
  }
@@ -48621,7 +48775,7 @@ function parseOrgRepo(ref, config2) {
48621
48775
  return { org: config2.defaultOrg, repo: ref };
48622
48776
  }
48623
48777
  if (config2.defaultRepo) {
48624
- const parsed = splitRepoSlug(config2.defaultRepo);
48778
+ const parsed = parseRepoSlug(config2.defaultRepo);
48625
48779
  if (!parsed) {
48626
48780
  throw new CliError(3 /* Config */, "CONFIG", `Invalid repo format "${config2.defaultRepo}". Expected "org/repo".`);
48627
48781
  }
@@ -49188,20 +49342,20 @@ function getCacheBaseDir() {
49188
49342
  return override;
49189
49343
  return join7(homedir3(), ".warmhub", "cache", "install-snapshots");
49190
49344
  }
49191
- function isValidSegment(segment) {
49192
- return segment.length > 0 && segment !== "." && segment !== ".." && /^[a-zA-Z0-9._-]+$/.test(segment);
49345
+ function isPathSafeSegment(segment) {
49346
+ return segment !== "." && segment !== ".." && /^[a-zA-Z0-9._-]+$/.test(segment);
49193
49347
  }
49194
- function parseRepoSlug(repoSlug) {
49195
- const segments = repoSlug.split("/");
49196
- if (segments.length !== 2)
49348
+ function parseSnapshotCacheSlug(repoSlug) {
49349
+ const parsed = parseRepoSlug(repoSlug);
49350
+ if (!parsed)
49197
49351
  return null;
49198
- const [org, repo] = segments;
49199
- if (!isValidSegment(org) || !isValidSegment(repo))
49352
+ const { org, repo } = parsed;
49353
+ if (!isPathSafeSegment(org) || !isPathSafeSegment(repo))
49200
49354
  return null;
49201
49355
  return { org, repo, fileName: `${org}--${repo}.json` };
49202
49356
  }
49203
49357
  function getInstallSnapshotCachePath(repoSlug) {
49204
- const parsed = parseRepoSlug(repoSlug);
49358
+ const parsed = parseSnapshotCacheSlug(repoSlug);
49205
49359
  if (!parsed)
49206
49360
  return null;
49207
49361
  return join7(getCacheBaseDir(), parsed.fileName);
@@ -49328,7 +49482,7 @@ async function loadOrPopulateInstallSnapshotCacheForComponent(repoSlug, client,
49328
49482
  if (cached2 && isCacheFresh(cached2, opts))
49329
49483
  return cached2;
49330
49484
  try {
49331
- const parsed = parseRepoSlug(repoSlug);
49485
+ const parsed = parseSnapshotCacheSlug(repoSlug);
49332
49486
  if (!parsed)
49333
49487
  return null;
49334
49488
  const activeItems = filterActiveItems(await fetchAllSummaries(client, parsed.org, parsed.repo));
@@ -49358,7 +49512,7 @@ async function ensureFreshInstallSnapshotCache(repoSlug, client, opts) {
49358
49512
  }
49359
49513
  }
49360
49514
  async function refreshInstallSnapshotCache(repoSlug, client, opts) {
49361
- const parsed = parseRepoSlug(repoSlug);
49515
+ const parsed = parseSnapshotCacheSlug(repoSlug);
49362
49516
  if (!parsed) {
49363
49517
  throw new Error(`Invalid repo slug for install snapshot cache: '${repoSlug}'`);
49364
49518
  }
@@ -49446,15 +49600,15 @@ function filterActiveItems(items) {
49446
49600
  return items.filter((i) => i.active && i.state !== "uninstalled" && i.state !== "paused" && i.state !== "error");
49447
49601
  }
49448
49602
  function extractRegisteredRef(ref) {
49449
- if (typeof ref !== "string" || ref.length === 0)
49603
+ if (typeof ref !== "string")
49450
49604
  return null;
49451
- const segments = ref.split("/");
49452
- if (segments.length !== 2)
49453
- return null;
49454
- const [org, name] = segments;
49455
- if (!org || !name)
49605
+ const parsed = parseComponentRef(ref);
49606
+ if (!parsed)
49456
49607
  return null;
49457
- return { ownerOrgName: org, registeredComponentName: name };
49608
+ return {
49609
+ ownerOrgName: parsed.org,
49610
+ registeredComponentName: parsed.name
49611
+ };
49458
49612
  }
49459
49613
 
49460
49614
  // ../../packages/warmhub-cli/src/domain-help.ts
@@ -49835,6 +49989,9 @@ function pinnedWref(c, wref, version2) {
49835
49989
  const base = wref.replace(/@v\d+$/, "");
49836
49990
  return `${c.cyan}${escapeTerminalTextForDisplay(base)}@v${version2}${c.reset}`;
49837
49991
  }
49992
+ function formatAffirmedWrefs(c, wrefs) {
49993
+ return wrefs.map((wref) => pinnedWref(c, wref)).join(`${c.dim},${c.reset} `);
49994
+ }
49838
49995
  function kindLabel(c, kind) {
49839
49996
  return `${c.dim}${kind}${c.reset}`;
49840
49997
  }
@@ -50047,7 +50204,7 @@ function parseAbout(raw) {
50047
50204
  return raw;
50048
50205
  }
50049
50206
  const tag = raw.slice(0, colonIdx).toLowerCase();
50050
- if (!COLLECTION_TAGS.includes(tag)) {
50207
+ if (!COLLECTION_TAGS.some((candidate) => candidate === tag)) {
50051
50208
  return raw;
50052
50209
  }
50053
50210
  throw new CliError(2 /* UserInput */, "USER_INPUT", COLLECTION_ABOUT_REMOVED_MESSAGE, undefined, "Use wh commit submit --file with a named collection add followed by an assertion add.");
@@ -50068,6 +50225,9 @@ function renderAbout(out, c, result) {
50068
50225
  const a = item;
50069
50226
  const wref = a.wref ?? a.name;
50070
50227
  out(` ${pinnedWref(c, wref, a.version)} ${kindLabel(c, a.kind ?? "assertion")}`);
50228
+ if (Array.isArray(a.affirmedWrefs) && a.affirmedWrefs.length > 0) {
50229
+ out(` ${c.dim}affirms:${c.reset} ${formatAffirmedWrefs(c, a.affirmedWrefs.map(String))}`);
50230
+ }
50071
50231
  if (a.data && typeof a.data === "object") {
50072
50232
  out(` ${c.dim}data:${c.reset}`);
50073
50233
  const lines = JSON.stringify(a.data, null, 2).split(`
@@ -50151,6 +50311,10 @@ var createFlags = {
50151
50311
  shape: flag.string({ description: "Shape for assertion (required)" }),
50152
50312
  data: flag.string({ description: "Data payload (JSON)" }),
50153
50313
  about: flag.string({ description: "Target wref" }),
50314
+ affirm: flag.string({
50315
+ multiple: true,
50316
+ description: "Pinned target version the claim is affirmed for (repeatable): Shape/name@vN"
50317
+ }),
50154
50318
  message: flag.string({ short: "m", description: "Commit message" }),
50155
50319
  committer: flag.string({
50156
50320
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -50158,6 +50322,27 @@ var createFlags = {
50158
50322
  };
50159
50323
  var reviseFlags = {
50160
50324
  data: flag.string({ description: "Data payload (JSON)" }),
50325
+ affirm: flag.string({
50326
+ multiple: true,
50327
+ description: "Complete affirmation set for the changed claim (repeatable); omitted clears it"
50328
+ }),
50329
+ message: flag.string({ short: "m", description: "Commit message" }),
50330
+ committer: flag.string({
50331
+ description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
50332
+ })
50333
+ };
50334
+ var reaffirmFlags = {
50335
+ add: flag.string({
50336
+ multiple: true,
50337
+ description: "Pinned target wref to affirm (repeatable): Shape/name@vN"
50338
+ }),
50339
+ remove: flag.string({
50340
+ multiple: true,
50341
+ description: "Pinned target wref to stop affirming (repeatable)"
50342
+ }),
50343
+ "expected-version": flag.number({
50344
+ description: "only reaffirm if the assertion is still at this version (optimistic concurrency)"
50345
+ }),
50161
50346
  message: flag.string({ short: "m", description: "Commit message" }),
50162
50347
  committer: flag.string({
50163
50348
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -50189,13 +50374,11 @@ var handleRevise = async (ctx, { flags, args }) => {
50189
50374
  operation: "revise",
50190
50375
  kind: "assertion",
50191
50376
  name,
50192
- data
50377
+ data,
50378
+ ...flags.affirm && flags.affirm.length > 0 ? { affirmedTargets: flags.affirm } : {}
50193
50379
  }
50194
50380
  ], { committer: flags.committer });
50195
- const result = commitResult.operations[0];
50196
- if (!result)
50197
- throw new Error("Commit returned no operation result");
50198
- assertSingleOpSuccess(commitResult);
50381
+ const result = requireSingleOpSuccess(commitResult);
50199
50382
  writeOutput(ctx, commitResult, () => renderSingleOpSuccess(ctx.out, c, ctx.chars, result, {
50200
50383
  marker: "~",
50201
50384
  color: c.yellow,
@@ -50220,14 +50403,51 @@ var handleRetract = async (ctx, { flags, args }) => {
50220
50403
  ], {
50221
50404
  committer: flags.committer
50222
50405
  });
50223
- const result = commitResult.operations[0];
50224
- if (!result)
50225
- throw new Error("Commit returned no operation result");
50226
- assertSingleOpSuccess(commitResult);
50406
+ const result = requireSingleOpSuccess(commitResult);
50227
50407
  writeOutput(ctx, commitResult, () => {
50228
- const op = result;
50229
50408
  renderCommitterEcho(ctx.out, ctx.colors, flags.committer);
50230
- ctx.out(`${ctx.colors.red}-${ctx.colors.reset} ${displayName(ctx.colors, op?.name ?? name)}`);
50409
+ ctx.out(`${ctx.colors.red}-${ctx.colors.reset} ${displayName(ctx.colors, result.name)}`);
50410
+ });
50411
+ };
50412
+ var handleReaffirm = async (ctx, { flags, args }) => {
50413
+ const name = args[0];
50414
+ const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", "wh assertion reaffirm Belief/cave-safe --add Location/cave@v3 --expected-version 2");
50415
+ if (!name) {
50416
+ usageError("Usage: wh assertion reaffirm <wref> [--add <wref@vN>]... [--remove <wref@vN>]... [--expected-version <n>]", "wh assertion reaffirm Belief/cave-safe --add Location/cave@v3");
50417
+ }
50418
+ const add = flags.add ?? [];
50419
+ const remove = flags.remove ?? [];
50420
+ if (add.length + remove.length === 0) {
50421
+ usageError("Reaffirm requires at least one --add or --remove target", "wh assertion reaffirm Belief/cave-safe --add Location/cave@v3 --expected-version 2");
50422
+ }
50423
+ const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
50424
+ const commitResult = await ctx.client.commit.apply(org, repo, flags.message ?? `reaffirm ${name}`, [
50425
+ {
50426
+ operation: "reaffirm",
50427
+ kind: "assertion",
50428
+ name,
50429
+ ...expectedVersion !== undefined ? { expectedVersion } : {},
50430
+ ...add.length > 0 ? { add } : {},
50431
+ ...remove.length > 0 ? { remove } : {}
50432
+ }
50433
+ ], { committer: flags.committer });
50434
+ const result = requireSingleOpSuccess(commitResult);
50435
+ writeOutput(ctx, commitResult, () => {
50436
+ const c = ctx.colors;
50437
+ renderSingleOpSuccess(ctx.out, c, ctx.chars, result, {
50438
+ marker: "±",
50439
+ color: c.cyan,
50440
+ committer: flags.committer
50441
+ });
50442
+ const delta = result.affirmations;
50443
+ if (delta) {
50444
+ for (const wref of delta.added)
50445
+ ctx.out(` ${c.green}+${c.reset} ${wref}`);
50446
+ for (const wref of delta.removed)
50447
+ ctx.out(` ${c.red}-${c.reset} ${wref}`);
50448
+ for (const wref of delta.ignored)
50449
+ ctx.out(` ${c.dim}= ${wref} (no change)${c.reset}`);
50450
+ }
50231
50451
  });
50232
50452
  };
50233
50453
  var handleCreate = async (ctx, { flags, args }) => {
@@ -50244,20 +50464,19 @@ var handleCreate = async (ctx, { flags, args }) => {
50244
50464
  }
50245
50465
  const about = parseAbout(aboutRaw);
50246
50466
  const localName = `${shape}/${name}`;
50467
+ const affirmedTargets = flags.affirm ?? [];
50247
50468
  const operations = [
50248
50469
  {
50249
50470
  operation: "add",
50250
50471
  kind: "assertion",
50251
50472
  name: localName,
50252
50473
  about,
50253
- data
50474
+ data,
50475
+ ...affirmedTargets.length > 0 ? { affirmedTargets } : {}
50254
50476
  }
50255
50477
  ];
50256
50478
  const commitResult = await ctx.client.commit.apply(org, repo, message ?? `assert ${shape}`, operations, { committer });
50257
- const result = commitResult.operations[0];
50258
- if (!result)
50259
- throw new Error("Commit returned no operation result");
50260
- assertSingleOpSuccess(commitResult);
50479
+ const result = requireSingleOpSuccess(commitResult);
50261
50480
  writeOutput(ctx, commitResult, () => renderSingleOpSuccess(ctx.out, c, ctx.chars, result, {
50262
50481
  marker: "+",
50263
50482
  color: c.green,
@@ -50420,6 +50639,7 @@ var handleAbout = async (ctx, { flags, args }) => {
50420
50639
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
50421
50640
  functionLogs: ctx.functionLogMode,
50422
50641
  profile: ctx.profile,
50642
+ clientFlags: ctx.clientFlags,
50423
50643
  signal: ctx.signal
50424
50644
  });
50425
50645
  return;
@@ -50566,10 +50786,7 @@ var handleCreate2 = async (ctx, { flags, args }) => {
50566
50786
  data
50567
50787
  }
50568
50788
  ], { committer });
50569
- const result = commitResult.operations[0];
50570
- if (!result)
50571
- throw new Error("Commit returned no operation result");
50572
- assertSingleOpSuccess(commitResult);
50789
+ const result = requireSingleOpSuccess(commitResult);
50573
50790
  writeOutput(ctx, commitResult, () => renderSingleOpSuccess(ctx.out, c, ctx.chars, result, {
50574
50791
  marker: "+",
50575
50792
  color: c.green,
@@ -50770,6 +50987,9 @@ function renderHead(out, c, chars, result, org, repo, shape, kind) {
50770
50987
  if (item.kind === "assertion" && item.aboutWref) {
50771
50988
  out(` ${c.dim}about:${c.reset} ${pinnedWref(c, item.aboutWref)}`);
50772
50989
  }
50990
+ if (item.affirmedWrefs?.length) {
50991
+ out(` ${c.dim}affirms:${c.reset} ${formatAffirmedWrefs(c, item.affirmedWrefs)}`);
50992
+ }
50773
50993
  const fields = shapeName && (item.kind === "thing" || item.kind === "collection") && item.data ? collectionFields(shapeName, item.data) : null;
50774
50994
  if (fields) {
50775
50995
  const allWrefs = fields.flatMap((f) => f.wrefs);
@@ -50802,6 +51022,9 @@ function renderThing(out, c, result) {
50802
51022
  if (aboutWref) {
50803
51023
  out(` ${c.dim}about:${c.reset} ${escapeTerminalTextForDisplay(String(aboutWref))}`);
50804
51024
  }
51025
+ if (result.affirmedWrefs?.length) {
51026
+ out(` ${c.dim}affirms:${c.reset} ${formatAffirmedWrefs(c, result.affirmedWrefs)}`);
51027
+ }
50805
51028
  const meta3 = result.metadata;
50806
51029
  if (meta3?.durableId || meta3?.createdOn || meta3?.revisedOn) {
50807
51030
  const now = Date.now();
@@ -50936,6 +51159,8 @@ function renderHistory(out, c, result) {
50936
51159
  } else if (ver.operation === "retract") {
50937
51160
  const reason = ver.retractReason ? ` ${c.dim}'${escapeTerminalTextForDisplay(ver.retractReason.length > 80 ? `${ver.retractReason.slice(0, 77)}...` : ver.retractReason)}'${c.reset}` : "";
50938
51161
  op = `${c.red}retract${c.reset}${reason}`;
51162
+ } else if (ver.operation === "reaffirm") {
51163
+ op = `${c.cyan}reaffirm${c.reset}`;
50939
51164
  } else {
50940
51165
  op = `${c.yellow}revise${c.reset}`;
50941
51166
  }
@@ -50946,6 +51171,10 @@ function renderHistory(out, c, result) {
50946
51171
  const createdOn = ver.metadata?.createdOn;
50947
51172
  const thingCreatedStr = createdOn ? ` ${c.dim}born:${formatTime(createdOn, now)}${c.reset}` : "";
50948
51173
  out(` ${wrefStr} ${op} ${c.dim}${time3}${c.reset}${by}${thingCreatedStr}`);
51174
+ const affirmed = ver.affirmedWrefs;
51175
+ if (Array.isArray(affirmed) && affirmed.length > 0) {
51176
+ out(` ${c.dim}affirms:${c.reset} ${formatAffirmedWrefs(c, affirmed.map(String))}`);
51177
+ }
50949
51178
  }
50950
51179
  }
50951
51180
  function renderRefs(out, c, result, wref, direction) {
@@ -51090,6 +51319,7 @@ var handleHistory = async (ctx, { flags, args }) => {
51090
51319
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
51091
51320
  functionLogs: ctx.functionLogMode,
51092
51321
  profile: ctx.profile,
51322
+ clientFlags: ctx.clientFlags,
51093
51323
  signal: ctx.signal
51094
51324
  });
51095
51325
  return;
@@ -51192,8 +51422,9 @@ var VALID_KINDS = [
51192
51422
  function validateKind(value, flagName = "--kind") {
51193
51423
  if (value === undefined)
51194
51424
  return;
51195
- if (VALID_KINDS.includes(value))
51196
- return value;
51425
+ const parsed = VALID_KINDS.find((candidate) => candidate === value);
51426
+ if (parsed)
51427
+ return parsed;
51197
51428
  const message = `Invalid ${flagName} "${value}". Supported kinds: ${VALID_KINDS.join(", ")}.`;
51198
51429
  const hint = /^[A-Z]/.test(value) ? `Did you mean --shape ${value} --kind assertion?` : `Example: ${flagName} assertion`;
51199
51430
  throw new CliError(2 /* UserInput */, "USER_INPUT", message, undefined, hint);
@@ -51396,6 +51627,7 @@ var handleHead = async (ctx, { flags, args }) => {
51396
51627
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
51397
51628
  functionLogs: ctx.functionLogMode,
51398
51629
  profile: ctx.profile,
51630
+ clientFlags: ctx.clientFlags,
51399
51631
  signal: ctx.signal
51400
51632
  });
51401
51633
  return;
@@ -51468,6 +51700,9 @@ var queryFlags = {
51468
51700
  shape: flag.string({ description: "Filter by shape" }),
51469
51701
  kind: flag.string({ description: "Filter by kind" }),
51470
51702
  about: flag.string({ description: "Filter by about wref" }),
51703
+ "affirmed-about": flag.string({
51704
+ description: "Only active assertions whose current version affirms exactly this pinned target version: Shape/name@vN"
51705
+ }),
51471
51706
  limit: flag.number({
51472
51707
  description: "Max results per page (default: 50, max: 500)"
51473
51708
  }),
@@ -51502,6 +51737,7 @@ var handleQuery = async (ctx, { flags }) => {
51502
51737
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
51503
51738
  const shape = flags.shape;
51504
51739
  const about = flags.about;
51740
+ const affirmedAbout = flags["affirmed-about"];
51505
51741
  const kind = validateKind(flags.kind);
51506
51742
  const limit = flags.limit;
51507
51743
  const cursor = flags.cursor;
@@ -51524,6 +51760,9 @@ var handleQuery = async (ctx, { flags }) => {
51524
51760
  if (ctx.liveMode && sinceRepoSeq !== undefined) {
51525
51761
  usageError("--since-repo-seq cannot be used with --live.", "wh thing query --since-repo-seq 42 --all --format json");
51526
51762
  }
51763
+ if (affirmedAbout && (match || count)) {
51764
+ usageError("--affirmed-about is PG-served per exact pinned version; it cannot be combined with --match or --count.", "wh thing query --affirmed-about Location/cave@v3");
51765
+ }
51527
51766
  if (count) {
51528
51767
  if (cursor || all || limit || ctx.liveMode || role) {
51529
51768
  usageError("Usage: wh thing query --count [--shape SHAPE] [--about WREF] [--kind KIND] [--match PATTERN] [--since-repo-seq N]", "wh thing query --kind assertion --about Player/alice --count --since-repo-seq 42");
@@ -51556,6 +51795,7 @@ var handleQuery = async (ctx, { flags }) => {
51556
51795
  const queryOpts = {
51557
51796
  shape,
51558
51797
  about,
51798
+ affirmedAbout,
51559
51799
  kind,
51560
51800
  match,
51561
51801
  includeRetracted,
@@ -51585,6 +51825,7 @@ var handleQuery = async (ctx, { flags }) => {
51585
51825
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
51586
51826
  functionLogs: ctx.functionLogMode,
51587
51827
  profile: ctx.profile,
51828
+ clientFlags: ctx.clientFlags,
51588
51829
  signal: ctx.signal
51589
51830
  });
51590
51831
  return;
@@ -51593,6 +51834,7 @@ var handleQuery = async (ctx, { flags }) => {
51593
51834
  const result = all ? await fetchAllQueryPages(ctx, org, repo, {
51594
51835
  shape,
51595
51836
  about,
51837
+ affirmedAbout,
51596
51838
  kind,
51597
51839
  match,
51598
51840
  includeRetracted,
@@ -51611,6 +51853,7 @@ var handleQuery = async (ctx, { flags }) => {
51611
51853
  } : undefined) : await ctx.client.thing.query(org, repo, {
51612
51854
  shape,
51613
51855
  about,
51856
+ affirmedAbout,
51614
51857
  kind,
51615
51858
  match,
51616
51859
  includeRetracted,
@@ -51642,6 +51885,7 @@ async function fetchAllQueryPages(ctx, org, repo, opts, onPage) {
51642
51885
  fetchPage: (cursor) => ctx.client.thing.query(org, repo, {
51643
51886
  shape: opts.shape,
51644
51887
  about: opts.about,
51888
+ affirmedAbout: opts.affirmedAbout,
51645
51889
  kind: opts.kind,
51646
51890
  match: opts.match,
51647
51891
  includeRetracted: opts.includeRetracted,
@@ -51868,14 +52112,10 @@ var handleThingRetract = async (ctx, { flags, args }) => {
51868
52112
  ...leaseId ? { leaseId } : {}
51869
52113
  }
51870
52114
  ], { committer });
51871
- const result = commitResult.operations[0];
51872
- if (!result)
51873
- throw new Error("Commit returned no operation result");
51874
- assertSingleOpSuccess(commitResult);
52115
+ const result = requireSingleOpSuccess(commitResult);
51875
52116
  writeOutput(ctx, commitResult, () => {
51876
- const op = result;
51877
52117
  renderCommitterEcho(ctx.out, c, committer);
51878
- ctx.out(`${c.red}-${c.reset} ${displayName(c, op?.name ?? name)}`);
52118
+ ctx.out(`${c.red}-${c.reset} ${displayName(c, result.name)}`);
51879
52119
  });
51880
52120
  };
51881
52121
 
@@ -51918,10 +52158,7 @@ var handleRevise2 = async (ctx, { flags, args }) => {
51918
52158
  ...leaseId ? { leaseId } : {}
51919
52159
  }
51920
52160
  ], { committer });
51921
- const result = commitResult.operations[0];
51922
- if (!result)
51923
- throw new Error("Commit returned no operation result");
51924
- assertSingleOpSuccess(commitResult);
52161
+ const result = requireSingleOpSuccess(commitResult);
51925
52162
  writeOutput(ctx, commitResult, () => renderSingleOpSuccess(ctx.out, c, ctx.chars, result, {
51926
52163
  marker: "~",
51927
52164
  color: c.yellow,
@@ -52292,6 +52529,7 @@ async function runSingleView(ctx, wref, flags) {
52292
52529
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
52293
52530
  functionLogs: ctx.functionLogMode,
52294
52531
  profile: ctx.profile,
52532
+ clientFlags: ctx.clientFlags,
52295
52533
  signal: ctx.signal
52296
52534
  });
52297
52535
  return;
@@ -52362,7 +52600,7 @@ var handleView = async (ctx, { flags, args, terminator }) => {
52362
52600
  }
52363
52601
  if (isBatch)
52364
52602
  return runBatchView(ctx, wrefs, flags);
52365
- const singleWref = wrefs[0];
52603
+ const [singleWref] = wrefs;
52366
52604
  return runSingleView(ctx, singleWref, flags);
52367
52605
  };
52368
52606
 
@@ -52576,6 +52814,7 @@ var handleView2 = async (ctx, { flags, args }) => {
52576
52814
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
52577
52815
  functionLogs: ctx.functionLogMode,
52578
52816
  profile: ctx.profile,
52817
+ clientFlags: ctx.clientFlags,
52579
52818
  signal: ctx.signal
52580
52819
  });
52581
52820
  return;
@@ -52632,6 +52871,7 @@ var handleHistory2 = async (ctx, { flags, args }) => {
52632
52871
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
52633
52872
  functionLogs: ctx.functionLogMode,
52634
52873
  profile: ctx.profile,
52874
+ clientFlags: ctx.clientFlags,
52635
52875
  signal: ctx.signal
52636
52876
  });
52637
52877
  return;
@@ -52756,6 +52996,7 @@ var handleList = async (ctx, { flags, args }) => {
52756
52996
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
52757
52997
  functionLogs: ctx.functionLogMode,
52758
52998
  profile: ctx.profile,
52999
+ clientFlags: ctx.clientFlags,
52759
53000
  signal: ctx.signal
52760
53001
  });
52761
53002
  return;
@@ -52799,6 +53040,7 @@ var handleList = async (ctx, { flags, args }) => {
52799
53040
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
52800
53041
  functionLogs: ctx.functionLogMode,
52801
53042
  profile: ctx.profile,
53043
+ clientFlags: ctx.clientFlags,
52802
53044
  signal: ctx.signal
52803
53045
  });
52804
53046
  return;
@@ -52884,6 +53126,17 @@ var ASSERTION_DOMAIN = defineDomain({
52884
53126
  ],
52885
53127
  handler: handleRevise
52886
53128
  },
53129
+ reaffirm: {
53130
+ prime: true,
53131
+ summary: "Edit which pinned target versions an assertion's claim is affirmed for (claim data unchanged)",
53132
+ args: "<wref>",
53133
+ flags: reaffirmFlags,
53134
+ examples: [
53135
+ "wh assertion reaffirm Belief/cave-safe --add Location/cave@v3",
53136
+ "wh assertion reaffirm Belief/cave-safe --add Location/cave@v4 --remove Location/cave@v1 --expected-version 3"
53137
+ ],
53138
+ handler: handleReaffirm
53139
+ },
52887
53140
  retract: {
52888
53141
  prime: true,
52889
53142
  summary: "Retract an assertion",
@@ -52903,8 +53156,99 @@ var ASSERTION_DOMAIN = defineDomain({
52903
53156
  }
52904
53157
  });
52905
53158
 
53159
+ // ../../packages/warmhub-cli/src/cli-context.ts
53160
+ function resolveClientFlags(profileFlags, env = process.env) {
53161
+ const candidates = [
53162
+ ...Array.isArray(profileFlags) ? profileFlags : [],
53163
+ ...(env.WH_CLIENT_FLAGS ?? "").split(",")
53164
+ ];
53165
+ const flags = new Set;
53166
+ const dropped = [];
53167
+ for (const raw of candidates) {
53168
+ const token = typeof raw === "string" ? raw.trim() : "";
53169
+ if (!token)
53170
+ continue;
53171
+ if (isValidClientFlagToken(token))
53172
+ flags.add(token);
53173
+ else
53174
+ dropped.push(token);
53175
+ }
53176
+ return { flags: [...flags].sort(), dropped };
53177
+ }
53178
+ function resolveCliContext(args) {
53179
+ const { invocation, format } = args;
53180
+ const config2 = args.config ?? loadConfig();
53181
+ const apiUrlFlag = invocation.flags["api-url"];
53182
+ const explicitApiUrl = typeof apiUrlFlag === "string" ? apiUrlFlag : undefined;
53183
+ const profileFlag = invocation.flags.profile;
53184
+ const apiUrl = explicitApiUrl ?? process.env.WARMHUB_API_URL ?? config2.apiUrl;
53185
+ config2.apiUrl = apiUrl;
53186
+ const explicitProfile = (typeof profileFlag === "string" ? profileFlag : undefined) ?? config2.profile;
53187
+ const effectiveProfile = explicitProfile ?? "default";
53188
+ const overridesBypassProfile = !explicitProfile && !!process.env.WH_TOKEN && (!!process.env.WARMHUB_API_URL || !!explicitApiUrl);
53189
+ let profileData = null;
53190
+ if (!overridesBypassProfile) {
53191
+ try {
53192
+ profileData = getProfile(effectiveProfile);
53193
+ } catch (err) {
53194
+ if (explicitProfile)
53195
+ throw err;
53196
+ const reason = err instanceof Error ? err.message : String(err);
53197
+ if (format === "json" || format === "jsonl") {
53198
+ process.stderr.write(`${JSON.stringify({
53199
+ level: "warning",
53200
+ kind: "auth-file-unreadable",
53201
+ message: `could not read auth.json: ${reason}`
53202
+ })}
53203
+ `);
53204
+ } else {
53205
+ process.stderr.write(`warning: could not read auth.json (${reason})
53206
+ `);
53207
+ }
53208
+ }
53209
+ }
53210
+ if (profileData) {
53211
+ if (profileData.apiUrl && !explicitApiUrl) {
53212
+ config2.apiUrl = profileData.apiUrl;
53213
+ }
53214
+ } else if (explicitProfile) {
53215
+ const isAuthLogin = invocation.kind === "static" && invocation.commandPath[0] === "auth" && invocation.commandPath[1] === "login";
53216
+ if (!isAuthLogin) {
53217
+ const available = listProfiles();
53218
+ const availableHint = available.length > 0 ? `Available profiles: ${available.join(", ")}.` : "No profiles found.";
53219
+ throw new CliError(5 /* Auth */, "AUTH", `Auth profile "${explicitProfile}" does not exist.`, undefined, `${availableHint}
53220
+ Run \`wh auth login --profile ${explicitProfile}\` to create it.`);
53221
+ }
53222
+ }
53223
+ const { flags: clientFlags, dropped: droppedFlags } = resolveClientFlags(profileData?.flags);
53224
+ for (const token of droppedFlags) {
53225
+ process.stderr.write(`warning: ignoring malformed client flag "${token}"
53226
+ `);
53227
+ }
53228
+ const client = args.client ?? createClient(config2, {
53229
+ functionLogs: args.functionLogs,
53230
+ profile: effectiveProfile,
53231
+ signal: args.signal,
53232
+ clientFlags
53233
+ });
53234
+ return { config: config2, profile: effectiveProfile, client, clientFlags };
53235
+ }
53236
+
52906
53237
  // ../../packages/warmhub-cli/src/domains/auth-shared.ts
52907
- async function loginWithToken(ctx, profile) {
53238
+ function clientForStoredFlags(ctx, profile) {
53239
+ const { flags } = resolveClientFlags(getProfile(profile)?.flags);
53240
+ const active = ctx.clientFlags ?? [];
53241
+ if (flags.length === active.length && flags.every((token, i) => token === active[i])) {
53242
+ return ctx.client;
53243
+ }
53244
+ return createClient(ctx.config, {
53245
+ functionLogs: ctx.functionLogMode,
53246
+ profile,
53247
+ signal: ctx.signal,
53248
+ clientFlags: flags
53249
+ });
53250
+ }
53251
+ async function loginWithToken(ctx, profile, explicitFlags) {
52908
53252
  const c = ctx.colors;
52909
53253
  if (process.stdin.isTTY) {
52910
53254
  throw new CliError(2 /* UserInput */, "USER_INPUT", "No token provided on stdin.", undefined, 'Pipe a JWT token via stdin: echo "$TOKEN" | wh auth login --with-token');
@@ -52932,7 +53276,7 @@ async function loginWithToken(ctx, profile) {
52932
53276
  if (Date.now() >= new Date(expiresAt).getTime() - EXPIRY_BUFFER_MS) {
52933
53277
  throw new CliError(5 /* Auth */, "AUTH", `Token is already expired (at ${new Date(expiresAt).toLocaleString()}).`, undefined, "Provide a valid, non-expired JWT.");
52934
53278
  }
52935
- await saveProfileLocked(profile, {
53279
+ await saveProfileWithFlagsLocked(profile, {
52936
53280
  tokens: {
52937
53281
  accessToken: jwt2,
52938
53282
  refreshToken: "",
@@ -52941,9 +53285,9 @@ async function loginWithToken(ctx, profile) {
52941
53285
  source: "token"
52942
53286
  },
52943
53287
  apiUrl: ctx.config.apiUrl
52944
- });
53288
+ }, explicitFlags);
52945
53289
  try {
52946
- await ctx.client.auth.sync();
53290
+ await clientForStoredFlags(ctx, profile).auth.sync();
52947
53291
  } catch (err) {
52948
53292
  ctx.err(`${c.yellow}Warning: could not sync user record: ${err instanceof Error ? err.message : String(err)}${c.reset}`);
52949
53293
  }
@@ -53030,7 +53374,7 @@ async function pollForDeviceToken(params) {
53030
53374
  poll().catch(reject);
53031
53375
  });
53032
53376
  }
53033
- function renderTokenInfo(ctx, info, profileName, apiUrl, identityWref) {
53377
+ function renderTokenInfo(ctx, info, profileName, apiUrl, identityWref, flags) {
53034
53378
  const c = ctx.colors;
53035
53379
  const prefix = profileName ? `${c.bold}${profileName}${c.reset}: ` : "";
53036
53380
  const sourceLabel = {
@@ -53065,6 +53409,9 @@ function renderTokenInfo(ctx, info, profileName, apiUrl, identityWref) {
53065
53409
  ctx.status(` ${c.dim}Identity:${c.reset} ${identityWref}`);
53066
53410
  }
53067
53411
  }
53412
+ if (flags?.length) {
53413
+ ctx.status(` ${c.dim}Client flags:${c.reset} ${flags.join(", ")}`);
53414
+ }
53068
53415
  }
53069
53416
  async function fetchIdentityWref(ctx) {
53070
53417
  if (process.env.WH_TOKEN)
@@ -53088,6 +53435,10 @@ function openBrowser(url2) {
53088
53435
  var loginFlags = {
53089
53436
  "with-token": flag.boolean({
53090
53437
  description: "Read a JWT token from stdin instead of using the browser flow"
53438
+ }),
53439
+ flag: flag.string({
53440
+ multiple: true,
53441
+ description: "Client flag to store on this profile. Repeatable. Validated " + "server-side; the backend honors only configured flags."
53091
53442
  })
53092
53443
  };
53093
53444
  function authStatusEntry(info, options) {
@@ -53098,6 +53449,7 @@ function authStatusEntry(info, options) {
53098
53449
  canRefresh: info.canRefresh,
53099
53450
  email: info.email ?? null,
53100
53451
  expiresAt: info.expiresAt ?? null,
53452
+ flags: options.flags ?? [],
53101
53453
  identityWref: options.identityWref ?? null,
53102
53454
  profile: options.profile ?? null,
53103
53455
  source: info.source
@@ -53110,10 +53462,23 @@ function authStatusOutput(activeProfile, entries) {
53110
53462
  entries
53111
53463
  };
53112
53464
  }
53465
+ var GENERIC_CLIENT_FLAG_HINT = "Use lowercase tokens matching [a-z0-9-]+, e.g. `wh auth login --flag <name>`.";
53466
+ function invalidClientFlagMessage(token) {
53467
+ const base = `Invalid client flag "${token}": expected lowercase tokens matching [a-z0-9-]+`;
53468
+ const normalized = token.trim().toLowerCase();
53469
+ return isValidClientFlagToken(normalized) ? `${base} (did you mean "${normalized}"?)` : `${base}.`;
53470
+ }
53113
53471
  var handleLogin = async (ctx, { flags }) => {
53114
53472
  const profile = flags.profile ?? ctx.config.profile ?? "default";
53473
+ const requestedFlags = (flags.flag ?? []).map((t) => t.trim());
53474
+ for (const token of requestedFlags) {
53475
+ if (!isValidClientFlagToken(token)) {
53476
+ throw new CliError(2 /* UserInput */, "USER_INPUT", invalidClientFlagMessage(token), undefined, GENERIC_CLIENT_FLAG_HINT);
53477
+ }
53478
+ }
53479
+ const explicitFlags = requestedFlags.length > 0 ? [...new Set(requestedFlags)].sort() : undefined;
53115
53480
  if (flags["with-token"]) {
53116
- return loginWithToken(ctx, profile);
53481
+ return loginWithToken(ctx, profile, explicitFlags);
53117
53482
  }
53118
53483
  const c = ctx.colors;
53119
53484
  let clientId;
@@ -53121,7 +53486,8 @@ var handleLogin = async (ctx, { flags }) => {
53121
53486
  clientId = await ctx.client.auth.getClientId();
53122
53487
  } catch {
53123
53488
  clientId = await createUnauthenticatedClient(ctx.config, {
53124
- functionLogs: ctx.functionLogMode
53489
+ functionLogs: ctx.functionLogMode,
53490
+ clientFlags: ctx.clientFlags
53125
53491
  }).auth.getClientId();
53126
53492
  }
53127
53493
  if (!clientId) {
@@ -53185,7 +53551,7 @@ var handleLogin = async (ctx, { flags }) => {
53185
53551
  } catch {
53186
53552
  expiresAt = new Date(Date.now() + 5 * 60 * 1000).toISOString();
53187
53553
  }
53188
- await saveProfileLocked(profile, {
53554
+ await saveProfileWithFlagsLocked(profile, {
53189
53555
  tokens: {
53190
53556
  accessToken: tokenResponse.access_token,
53191
53557
  refreshToken: tokenResponse.refresh_token,
@@ -53196,9 +53562,9 @@ var handleLogin = async (ctx, { flags }) => {
53196
53562
  source: "device"
53197
53563
  },
53198
53564
  apiUrl: ctx.config.apiUrl
53199
- });
53565
+ }, explicitFlags);
53200
53566
  try {
53201
- await ctx.client.auth.sync();
53567
+ await clientForStoredFlags(ctx, profile).auth.sync();
53202
53568
  } catch (err) {
53203
53569
  ctx.err(`${c.yellow}Warning: could not sync user record: ${err instanceof Error ? err.message : String(err)}${c.reset}`);
53204
53570
  }
@@ -53238,10 +53604,11 @@ var handleStatus = async (ctx, { flags }) => {
53238
53604
  const entry = authStatusEntry(info, {
53239
53605
  active: true,
53240
53606
  apiUrl: prof.apiUrl,
53607
+ flags: Array.isArray(prof.flags) ? prof.flags : [],
53241
53608
  identityWref,
53242
53609
  profile: selectedProfile
53243
53610
  });
53244
- writeOutput(ctx, authStatusOutput(selectedProfile, [entry]), () => renderTokenInfo(ctx, info, selectedProfile, prof.apiUrl, identityWref));
53611
+ writeOutput(ctx, authStatusOutput(selectedProfile, [entry]), () => renderTokenInfo(ctx, info, selectedProfile, prof.apiUrl, identityWref, entry.flags));
53245
53612
  return;
53246
53613
  }
53247
53614
  const envToken = process.env.WH_TOKEN;
@@ -53270,13 +53637,15 @@ var handleStatus = async (ctx, { flags }) => {
53270
53637
  canRefresh: source === "device" && !!tokens.refreshToken
53271
53638
  };
53272
53639
  const identityWref = !info.expired && name === activeProfile ? await fetchIdentityWref(ctx) : null;
53640
+ const profileFlags = Array.isArray(prof.flags) ? prof.flags : [];
53273
53641
  entries.push(authStatusEntry(info, {
53274
53642
  active: !envToken && name === activeProfile,
53275
53643
  apiUrl: prof.apiUrl,
53644
+ flags: profileFlags,
53276
53645
  identityWref,
53277
53646
  profile: name
53278
53647
  }));
53279
- prettyEntries.push(() => renderTokenInfo(ctx, info, name, prof.apiUrl, identityWref));
53648
+ prettyEntries.push(() => renderTokenInfo(ctx, info, name, prof.apiUrl, identityWref, profileFlags));
53280
53649
  }
53281
53650
  }
53282
53651
  writeOutput(ctx, authStatusOutput(envToken ? null : activeProfile, entries), () => {
@@ -53781,9 +54150,8 @@ function requireMembers(members, example) {
53781
54150
  }
53782
54151
  }
53783
54152
  function renderMutation(ctx, result) {
53784
- assertSingleOpSuccess(result);
53785
- const operation = result.operations[0];
53786
- if (!operation || !("version" in operation) || typeof operation.version !== "number") {
54153
+ const operation = requireSingleOpSuccess(result);
54154
+ if (!("version" in operation) || typeof operation.version !== "number") {
53787
54155
  throw new Error("Collection mutation returned no version-bearing operation");
53788
54156
  }
53789
54157
  const isNoop = operation.operation === "noop";
@@ -54023,10 +54391,11 @@ var collectionStatsFlags = {
54023
54391
  version: flag.number({ description: "Specific collection version number" })
54024
54392
  };
54025
54393
  function validateCollectionType(value) {
54026
- if (!value || !SUPPORTED_COLLECTION_TYPES.includes(value)) {
54394
+ const parsed = SUPPORTED_COLLECTION_TYPES.find((candidate) => candidate === value);
54395
+ if (!parsed) {
54027
54396
  usageError(`Usage: wh collection create --type ${CANONICAL_COLLECTION_TYPE_USAGE} --members <wref...>`, 'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"');
54028
54397
  }
54029
- return value;
54398
+ return parsed;
54030
54399
  }
54031
54400
  function validateDiffMode(value) {
54032
54401
  if (value === undefined)
@@ -54052,7 +54421,7 @@ function collectionQuerySourceFromFlags(flags) {
54052
54421
  function parseSourceRepoFlag(value) {
54053
54422
  if (!value)
54054
54423
  return;
54055
- const parsed = splitRepoSlug(value);
54424
+ const parsed = parseRepoSlug(value);
54056
54425
  if (!parsed) {
54057
54426
  usageError("--source-repo must be an org/repo slug", "wh collection create --type set --name wake-voters --source-repo data/nc-voters --shape Voter --where county=Wake");
54058
54427
  }
@@ -54089,7 +54458,7 @@ function isMissingCollectionMemberError(error51, type) {
54089
54458
  function collectionTypeFromWref2(wref) {
54090
54459
  const local = wref.replace(/^wh:[^/]+\/[^/]+\//, "").replace(/@(?:HEAD|ALL|v\d+)$/, "");
54091
54460
  const shape = local.split("/")[0]?.toLowerCase();
54092
- return SUPPORTED_COLLECTION_TYPES.includes(shape) ? shape : undefined;
54461
+ return SUPPORTED_COLLECTION_TYPES.find((candidate) => candidate === shape);
54093
54462
  }
54094
54463
  function parseCollectionReadRepo(ctx, wrefs) {
54095
54464
  const allDurable = wrefs.length > 0 && wrefs.every(looksLikeDurableId);
@@ -54501,7 +54870,7 @@ function renderPrettyReceipt(ctx, receipt, committer) {
54501
54870
  const record2 = operation;
54502
54871
  const operationKind = String(record2.operation ?? "operation");
54503
54872
  const failed = isFailedOpStatus(record2.status);
54504
- const marker = failed ? "!" : operationKind === "add" ? "+" : operationKind === "revise" ? "~" : "-";
54873
+ const marker = failed ? "!" : operationKind === "add" ? "+" : operationKind === "revise" ? "~" : operationKind === "reaffirm" ? "±" : "-";
54505
54874
  const error51 = typeof record2.error === "object" && record2.error !== null ? record2.error : undefined;
54506
54875
  const errorSummary = failed ? ` ${error51?.message ?? error51?.code ?? "failed"}` : "";
54507
54876
  ctx.out(` ${marker} ${displayName(c, String(record2.name ?? record2.resolvedName ?? "(unnamed)"))}${errorSummary}`);
@@ -54603,6 +54972,10 @@ var createFlags3 = {
54603
54972
  description: "Target shape or shaped thing for assertions. Repeatable; one per --add, or a single value broadcast to all.",
54604
54973
  multiple: true
54605
54974
  }),
54975
+ affirm: flag.string({
54976
+ description: "Pinned target version the assertion claim is affirmed for (repeatable): Shape/name@vN. Requires a single assertion --add or --revise.",
54977
+ multiple: true
54978
+ }),
54606
54979
  reason: flag.string({
54607
54980
  description: "Reason for retraction. Repeatable; one per --retract, or a single value broadcast to all.",
54608
54981
  multiple: true
@@ -54685,6 +55058,7 @@ function assertNoNulBytes(data, locator) {
54685
55058
 
54686
55059
  // ../../packages/warmhub-cli/src/domains/commit-submit-template.ts
54687
55060
  import { writeFile } from "node:fs/promises";
55061
+ var WRITE_TEMPLATE_KINDS = ["thing", "assertion"];
54688
55062
  function zeroValueForField(fieldSpec) {
54689
55063
  if (Array.isArray(fieldSpec))
54690
55064
  return [];
@@ -54773,20 +55147,21 @@ var handleTemplate = async (ctx, { flags, args }) => {
54773
55147
  if (operationType !== "add" && operationType !== "revise" && operationType !== "retract") {
54774
55148
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --operation "${operationType}". Must be "add", "revise", or "retract".`);
54775
55149
  }
54776
- const validKinds = operationType === "retract" ? COMMIT_OPERATION_KINDS : ["thing", "assertion"];
54777
- if (!validKinds.includes(flags.kind ?? "thing")) {
55150
+ const requestedKind = flags.kind ?? "thing";
55151
+ const validKinds = operationType === "retract" ? COMMIT_OPERATION_KINDS : WRITE_TEMPLATE_KINDS;
55152
+ const templateKind = validKinds.find((candidate) => candidate === requestedKind);
55153
+ if (templateKind === undefined) {
54778
55154
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind "${flags.kind}". Must be one of: ${validKinds.join(", ")}.`);
54779
55155
  }
54780
55156
  const count = Math.max(1, flags.count ?? 1);
54781
55157
  const operations = [];
54782
55158
  for (const shapeName of shapeNames) {
54783
55159
  if (operationType === "retract") {
54784
- const kind2 = flags.kind ?? "thing";
54785
55160
  for (let i = 0;i < count; i++) {
54786
55161
  operations.push({
54787
55162
  operation: "retract",
54788
- kind: kind2,
54789
- name: kind2 === "shape" ? shapeName : `${shapeName}/FILL_IN`
55163
+ kind: templateKind,
55164
+ name: templateKind === "shape" ? shapeName : `${shapeName}/FILL_IN`
54790
55165
  });
54791
55166
  }
54792
55167
  continue;
@@ -54795,25 +55170,27 @@ var handleTemplate = async (ctx, { flags, args }) => {
54795
55170
  const shapeVersion = shape.version;
54796
55171
  const shapeData = shapeVersion?.data;
54797
55172
  const fields = shapeData?.fields ?? {};
54798
- const kind = flags.kind ?? "thing";
54799
55173
  let aboutPlaceholder;
54800
- if (kind === "assertion") {
55174
+ if (templateKind === "assertion") {
54801
55175
  aboutPlaceholder = flags.about ? parseCollectionAboutFlag(flags.about) : "Shape/FILL_IN";
54802
55176
  }
54803
55177
  const data = buildTemplateData(fields);
54804
55178
  const nameSuffix = count > 1 ? (i) => `my-${shapeName.toLowerCase()}-${i + 1}` : () => `my-${shapeName.toLowerCase()}`;
55179
+ const affirmedTargetsPlaceholder = templateKind === "assertion" ? { affirmedTargets: [] } : {};
54805
55180
  for (let i = 0;i < count; i++) {
54806
55181
  const op = operationType === "add" ? {
54807
55182
  operation: "add",
54808
- kind,
55183
+ kind: templateKind,
54809
55184
  name: `${shapeName}/${nameSuffix(i)}`,
54810
55185
  ...aboutPlaceholder ? { about: aboutPlaceholder } : {},
54811
- data
55186
+ data,
55187
+ ...affirmedTargetsPlaceholder
54812
55188
  } : {
54813
55189
  operation: "revise",
54814
- kind,
55190
+ kind: templateKind,
54815
55191
  name: `${shapeName}/FILL_IN`,
54816
- data
55192
+ data,
55193
+ ...affirmedTargetsPlaceholder
54817
55194
  };
54818
55195
  operations.push(op);
54819
55196
  }
@@ -54838,7 +55215,7 @@ var handleTemplate = async (ctx, { flags, args }) => {
54838
55215
  // ../../packages/warmhub-cli/src/domains/commit-submit-ops.ts
54839
55216
  var SHORT_FORM_MAX_ADDS = 20;
54840
55217
  function buildAddOperations(input) {
54841
- const { addNames, dataJsons, shapes, abouts, kinds } = input;
55218
+ const { addNames, dataJsons, shapes, abouts, affirms, kinds } = input;
54842
55219
  if (addNames.length > SHORT_FORM_MAX_ADDS) {
54843
55220
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Short-form --add is capped at ${SHORT_FORM_MAX_ADDS} operations per write (got ${addNames.length}).`, undefined, "Use --file <path.json> or --ops '<json>' for bulk writes.");
54844
55221
  }
@@ -54856,6 +55233,9 @@ function buildAddOperations(input) {
54856
55233
  assertCardinality("--shape", shapes, { allowBroadcast: true });
54857
55234
  assertCardinality("--about", abouts, { allowBroadcast: true });
54858
55235
  assertCardinality("--kind", kinds, { allowBroadcast: true });
55236
+ if (affirms.length > 0 && addNames.length !== 1) {
55237
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `--affirm requires exactly one --add (got ${addNames.length}); the repeated values form that assertion's affirmation set.`, undefined, 'Use --file <path.json> with per-op "affirmedTargets" for multi-add writes.');
55238
+ }
54859
55239
  const pick2 = (values, i, { allowBroadcast }) => {
54860
55240
  if (values.length === 0)
54861
55241
  return;
@@ -54876,7 +55256,17 @@ function buildAddOperations(input) {
54876
55256
  }
54877
55257
  const localName = shape ? `${shape}/${addName}` : addName;
54878
55258
  const kind = kindFlag ?? (about ? "assertion" : "thing");
54879
- return { operation: "add", kind, name: localName, data, about };
55259
+ if (affirms.length > 0 && kind !== "assertion") {
55260
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `--affirm applies only to assertion adds, but --add "${addName}" resolved kind '${kind}'.`, undefined, `wh commit submit --add ${addName} --about Target/FILL_IN --data '{...}' --affirm Target/FILL_IN@v1`);
55261
+ }
55262
+ return {
55263
+ operation: "add",
55264
+ kind,
55265
+ name: localName,
55266
+ data,
55267
+ about,
55268
+ ...affirms.length > 0 ? { affirmedTargets: affirms } : {}
55269
+ };
54880
55270
  });
54881
55271
  }
54882
55272
  function buildRetractOperations(input) {
@@ -54931,6 +55321,8 @@ function synthesizeCommitMessage(operations) {
54931
55321
  if (operations.length > 1)
54932
55322
  return `batch: ${operations.length} operations`;
54933
55323
  const op = operations[0];
55324
+ if (!op)
55325
+ return;
54934
55326
  const name = op.name ?? "";
54935
55327
  if (op.operation === "revise") {
54936
55328
  return name ? `revise ${name}` : "revise";
@@ -54940,6 +55332,9 @@ function synthesizeCommitMessage(operations) {
54940
55332
  return `retract shape ${name}`;
54941
55333
  return name ? `retract ${name}` : "retract";
54942
55334
  }
55335
+ if (op.operation === "reaffirm") {
55336
+ return name ? `reaffirm ${name}` : "reaffirm";
55337
+ }
54943
55338
  const add = op;
54944
55339
  if (add.kind === "collection") {
54945
55340
  const type = add.type ?? "collection";
@@ -54963,8 +55358,8 @@ var ALLOWED_FLAGS = {
54963
55358
  "--stream": new Set,
54964
55359
  "--ops": new Set,
54965
55360
  "--file": new Set,
54966
- "--add": new Set(["data", "shape", "about", "kind"]),
54967
- "--revise": new Set(["data", "kind"]),
55361
+ "--add": new Set(["data", "shape", "about", "affirm", "kind"]),
55362
+ "--revise": new Set(["data", "affirm", "kind"]),
54968
55363
  "--retract": new Set(["reason", "kind"]),
54969
55364
  "--type": new Set(["name", "members"])
54970
55365
  };
@@ -55464,6 +55859,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
55464
55859
  const dataJsons = flags.data ?? [];
55465
55860
  const shapes = flags.shape ?? [];
55466
55861
  const abouts = flags.about ?? [];
55862
+ const affirms = flags.affirm ?? [];
55467
55863
  const reasons = flags.reason ?? [];
55468
55864
  const kinds = flags.kind ?? [];
55469
55865
  const expectedVersionExample = retractNames.length > 0 ? "wh commit submit --retract Player/alice --expected-version 3" : "wh commit submit --revise Player/alice --data '{...}' --expected-version 3";
@@ -55481,17 +55877,19 @@ var handleSubmit = async (ctx, { flags, args }) => {
55481
55877
  "shape",
55482
55878
  "collection"
55483
55879
  ];
55484
- for (const k of kinds) {
55485
- if (!validKinds.includes(k)) {
55880
+ const operationKinds = kinds.map((k) => {
55881
+ const parsed = validKinds.find((candidate) => candidate === k);
55882
+ if (!parsed) {
55486
55883
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind "${k}". Must be one of: ${validKinds.join(", ")}`);
55487
55884
  }
55488
- }
55885
+ return parsed;
55886
+ });
55489
55887
  const validCollectionTypes = ["arc", "bond", "set", "list", "pair"];
55490
55888
  const canonicalCollectionTypes2 = ["arc", "bond", "set", "list"];
55491
- if (flags.type && !validCollectionTypes.includes(flags.type)) {
55889
+ const collectionType = validCollectionTypes.find((candidate) => candidate === flags.type);
55890
+ if (flags.type !== undefined && collectionType === undefined) {
55492
55891
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --type "${flags.type}". Use one of: ${canonicalCollectionTypes2.join(", ")}`, undefined, "wh commit submit --type arc --name route --members Location/a,Location/b");
55493
55892
  }
55494
- const collectionType = flags.type;
55495
55893
  const jsonlFile = opsFile?.endsWith(".jsonl") === true;
55496
55894
  const operationSource = resolveCommitOperationSource({
55497
55895
  stream: streamInput,
@@ -55509,8 +55907,9 @@ var handleSubmit = async (ctx, { flags, args }) => {
55509
55907
  data: dataJsons.length > 0,
55510
55908
  shape: shapes.length > 0,
55511
55909
  about: abouts.length > 0,
55910
+ affirm: affirms.length > 0,
55512
55911
  reason: reasons.length > 0,
55513
- kind: kinds.length > 0,
55912
+ kind: operationKinds.length > 0,
55514
55913
  name: flags.name !== undefined,
55515
55914
  members: flags.members !== undefined
55516
55915
  });
@@ -55586,12 +55985,13 @@ var handleSubmit = async (ctx, { flags, args }) => {
55586
55985
  dataJsons,
55587
55986
  shapes,
55588
55987
  abouts,
55589
- kinds
55988
+ affirms,
55989
+ kinds: operationKinds
55590
55990
  });
55591
55991
  } else if (operationSource === "--retract") {
55592
55992
  operations = buildRetractOperations({
55593
55993
  retractNames,
55594
- kinds,
55994
+ kinds: operationKinds,
55595
55995
  reasons,
55596
55996
  expectedVersion,
55597
55997
  leaseId: leaseIdFlag
@@ -55600,19 +56000,23 @@ var handleSubmit = async (ctx, { flags, args }) => {
55600
56000
  if (dataJsons.length > 1) {
55601
56001
  throw new CliError(2 /* UserInput */, "USER_INPUT", `--revise supports a single operation, but --data was repeated ${dataJsons.length} times.`, undefined, "Use --file <path.json> for multi-revision writes.");
55602
56002
  }
55603
- if (kinds.length > 1) {
55604
- throw new CliError(2 /* UserInput */, "USER_INPUT", `--revise supports a single operation, but --kind was repeated ${kinds.length} times.`, undefined, "Use --file <path.json> for multi-revision writes.");
56003
+ if (operationKinds.length > 1) {
56004
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `--revise supports a single operation, but --kind was repeated ${operationKinds.length} times.`, undefined, "Use --file <path.json> for multi-revision writes.");
55605
56005
  }
55606
56006
  const rawData = dataJsons[0];
55607
56007
  const data = rawData !== undefined ? parseJsonObject(rawData, "--data") : undefined;
55608
- const kindFlag = kinds[0];
56008
+ const kindFlag = operationKinds[0];
55609
56009
  const kind = kindFlag ?? "thing";
56010
+ if (affirms.length > 0 && kind !== "assertion") {
56011
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `--affirm applies only to assertion revises, but --revise resolved kind '${kind}'.`, undefined, `wh commit submit --revise ${reviseName} --kind assertion --data '{...}' --affirm Location/cave@v3`);
56012
+ }
55610
56013
  operations = [
55611
56014
  {
55612
56015
  operation: "revise",
55613
56016
  kind,
55614
56017
  name: reviseName,
55615
56018
  data,
56019
+ ...affirms.length > 0 ? { affirmedTargets: affirms } : {},
55616
56020
  ...expectedVersion !== undefined ? { expectedVersion } : {},
55617
56021
  ...leaseIdFlag ? { leaseId: leaseIdFlag } : {}
55618
56022
  }
@@ -56018,8 +56422,7 @@ function bindComponentMethodArgs(invocation, method) {
56018
56422
  }
56019
56423
  const coerced = coerceArg(arg, raw);
56020
56424
  if (!coerced.ok) {
56021
- if (coerced.error)
56022
- addError(record2.index, coerced.error);
56425
+ addError(record2.index, coerced.error);
56023
56426
  continue;
56024
56427
  }
56025
56428
  if (!Object.hasOwn(args, arg.name))
@@ -56037,7 +56440,7 @@ function bindComponentMethodArgs(invocation, method) {
56037
56440
  const coerced = coerceArg(arg, arg.default);
56038
56441
  if (coerced.ok) {
56039
56442
  args[arg.name] = coerced.value;
56040
- } else if (coerced.error) {
56443
+ } else {
56041
56444
  addError(Number.POSITIVE_INFINITY, coerced.error);
56042
56445
  }
56043
56446
  continue;
@@ -56397,63 +56800,62 @@ function formatReservedNameWarning(name) {
56397
56800
  // ../../packages/warmhub-cli/src/manifest/parser.ts
56398
56801
  import { existsSync as existsSync8, readFileSync as readFileSync9 } from "node:fs";
56399
56802
  import { resolve } from "node:path";
56400
- function parseComponentPackage(dirPath) {
56401
- const rootDir = resolve(dirPath);
56402
- const errors3 = [];
56403
- const warnings = [];
56404
- const componentJsonPath = resolve(rootDir, "warmhub", "component.json");
56405
- if (!existsSync8(componentJsonPath)) {
56406
- errors3.push(`Missing warmhub/component.json at ${componentJsonPath}`);
56407
- return { ok: false, errors: errors3, warnings };
56803
+ function loadDocument(rootDir, fileName, validate) {
56804
+ const path2 = resolve(rootDir, "warmhub", fileName);
56805
+ if (!existsSync8(path2)) {
56806
+ return {
56807
+ valid: false,
56808
+ errors: [`Missing warmhub/${fileName} at ${path2}`],
56809
+ warnings: []
56810
+ };
56408
56811
  }
56409
- let componentRaw;
56410
- try {
56411
- componentRaw = JSON.parse(readFileSync9(componentJsonPath, "utf-8"));
56412
- } catch (err) {
56413
- errors3.push(`Failed to parse warmhub/component.json: ${err instanceof Error ? err.message : String(err)}`);
56414
- return { ok: false, errors: errors3, warnings };
56415
- }
56416
- const componentResult = validateComponentJson(componentRaw);
56417
- errors3.push(...componentResult.errors);
56418
- warnings.push(...componentResult.warnings);
56419
- const manifestJsonPath = resolve(rootDir, "warmhub", "manifest.json");
56420
- if (!existsSync8(manifestJsonPath)) {
56421
- errors3.push(`Missing warmhub/manifest.json at ${manifestJsonPath}`);
56422
- return { ok: false, errors: errors3, warnings };
56423
- }
56424
- let manifestRaw;
56812
+ let raw;
56425
56813
  try {
56426
- manifestRaw = JSON.parse(readFileSync9(manifestJsonPath, "utf-8"));
56814
+ raw = JSON.parse(readFileSync9(path2, "utf-8"));
56427
56815
  } catch (err) {
56428
- errors3.push(`Failed to parse warmhub/manifest.json: ${err instanceof Error ? err.message : String(err)}`);
56429
- return { ok: false, errors: errors3, warnings };
56430
- }
56431
- const manifestResult = validateManifestJson(manifestRaw);
56432
- errors3.push(...manifestResult.errors);
56433
- warnings.push(...manifestResult.warnings);
56434
- if (errors3.length > 0) {
56435
- return { ok: false, errors: errors3, warnings };
56816
+ return {
56817
+ valid: false,
56818
+ errors: [
56819
+ `Failed to parse warmhub/${fileName}: ${err instanceof Error ? err.message : String(err)}`
56820
+ ],
56821
+ warnings: []
56822
+ };
56436
56823
  }
56437
- if (!componentResult.value || !manifestResult.value) {
56824
+ return validate(raw);
56825
+ }
56826
+ function parseComponentPackage(dirPath) {
56827
+ const rootDir = resolve(dirPath);
56828
+ const component = loadDocument(rootDir, "component.json", validateComponentJson);
56829
+ const manifest = loadDocument(rootDir, "manifest.json", validateManifestJson);
56830
+ const warnings = [...component.warnings, ...manifest.warnings];
56831
+ if (!component.valid && !manifest.valid) {
56438
56832
  return {
56439
56833
  ok: false,
56440
- errors: ["Validated component package is missing parsed values"],
56834
+ errors: [...component.errors, ...manifest.errors],
56441
56835
  warnings
56442
56836
  };
56443
56837
  }
56838
+ if (!component.valid) {
56839
+ return { ok: false, errors: component.errors, warnings };
56840
+ }
56841
+ if (!manifest.valid) {
56842
+ return { ok: false, errors: manifest.errors, warnings };
56843
+ }
56444
56844
  return {
56445
56845
  ok: true,
56446
- errors: [],
56447
56846
  warnings,
56448
56847
  package: {
56449
- meta: componentResult.value,
56450
- manifest: manifestResult.value,
56848
+ meta: component.value,
56849
+ manifest: manifest.value,
56451
56850
  rootDir
56452
56851
  }
56453
56852
  };
56454
56853
  }
56455
56854
 
56456
56855
  // ../../packages/warmhub-cli/src/manifest/validate.ts
56856
+ function hasBlockingFindings(findings) {
56857
+ return findings.some((finding) => finding.level === "error");
56858
+ }
56457
56859
  function crossValidate(pkg) {
56458
56860
  const findings = [];
56459
56861
  const { meta: meta3, manifest } = pkg;
@@ -56472,8 +56874,7 @@ function crossValidate(pkg) {
56472
56874
  });
56473
56875
  }
56474
56876
  findings.push(...validateManifestSemantics(manifest));
56475
- const hasErrors = findings.some((f) => f.level === "error");
56476
- return { valid: !hasErrors, findings };
56877
+ return { findings };
56477
56878
  }
56478
56879
  function validateComponentPackage(pkg) {
56479
56880
  return crossValidate(pkg);
@@ -56632,14 +57033,11 @@ function resolveRegisteredComponentRef(ref, usage, example) {
56632
57033
  if (!ref) {
56633
57034
  usageError(usage, example);
56634
57035
  }
56635
- const parts = ref.split("/");
56636
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
57036
+ const parsed = parseComponentRef(ref);
57037
+ if (!parsed) {
56637
57038
  usageError(`Invalid component reference '${ref}'. Expected '<org>/<name>' with no extra slashes and no empty parts.`, example);
56638
57039
  }
56639
- return {
56640
- orgName: parts[0],
56641
- componentName: parts[1]
56642
- };
57040
+ return { orgName: parsed.org, componentName: parsed.name };
56643
57041
  }
56644
57042
  function resolveRegistryVisibility(args) {
56645
57043
  if (args.isPrivate && args.isPublic) {
@@ -56845,13 +57243,9 @@ var handleValidate = async (ctx, { args }) => {
56845
57243
  writeOutput(ctx, result2, () => renderValidationResult(ctx, result2));
56846
57244
  throw new CliError(2 /* UserInput */, "USER_INPUT", "Component package validation failed");
56847
57245
  }
56848
- const parsedPackage = parseResult.package;
56849
- if (!parsedPackage) {
56850
- throw new CliError(1 /* Runtime */, "UNKNOWN", "Component package validation returned no package");
56851
- }
56852
- const crossResult = validateComponentPackage(parsedPackage);
57246
+ const crossResult = validateComponentPackage(parseResult.package);
56853
57247
  const result = {
56854
- valid: crossResult.valid,
57248
+ valid: !hasBlockingFindings(crossResult.findings),
56855
57249
  errors: [],
56856
57250
  warnings: parseResult.warnings,
56857
57251
  findings: crossResult.findings
@@ -58305,7 +58699,7 @@ async function collectChecks(ctx) {
58305
58699
  const repoFlag = getRepoRef(ctx);
58306
58700
  const hasRepoFlag = repoFlag !== undefined;
58307
58701
  const repo = repoFlag ?? ctx.config.defaultRepo;
58308
- const repoParts = repo !== undefined ? splitRepoSlug(repo) : null;
58702
+ const repoParts = repo !== undefined ? parseRepoSlug(repo) : null;
58309
58703
  const repoForDisplay = repo !== undefined ? escapeTerminalTextForDisplay(repo) : undefined;
58310
58704
  const repoSource = hasRepoFlag ? "flag" : ctx.config.configSource?.repo;
58311
58705
  const repoProvenance = repoSource === "env" ? " (from WARMHUB_REPO)" : repoSource === "wh-file" ? " (from .wh file)" : repoSource === "flag" ? " (from --repo flag)" : "";
@@ -58638,7 +59032,7 @@ var handleDoctor2 = async (ctx, { flags }) => {
58638
59032
  ctx.out(` ${c.dim}${line}${c.reset}`);
58639
59033
  }
58640
59034
  }
58641
- if (check2.fix && check2.status !== "ok") {
59035
+ if (check2.fix) {
58642
59036
  for (const line of check2.fix.split(`
58643
59037
  `)) {
58644
59038
  ctx.out(` ${c.dim}${line}${c.reset}`);
@@ -58684,6 +59078,143 @@ var DOCTOR_DOMAIN = defineDomain({
58684
59078
  handler: handleDoctor2
58685
59079
  });
58686
59080
 
59081
+ // ../../packages/warmhub-cli/src/domains/grant.ts
59082
+ var createFlags5 = {
59083
+ key: flag.string({ description: "issuer-scoped idempotency key" }),
59084
+ coverage: flag.string({
59085
+ description: "inline coverage JSON ({include, exclude?})"
59086
+ }),
59087
+ view: flag.string({
59088
+ description: "View backing coverage instead (View/NAME or View/NAME@vN)"
59089
+ }),
59090
+ op: flag.string({
59091
+ description: "operation to grant (repeatable)",
59092
+ multiple: true
59093
+ })
59094
+ };
59095
+ var listFlags3 = {
59096
+ limit: flag.number({ description: "max records (default: 50, max: 100)" }),
59097
+ cursor: flag.string({ description: "grant keyset cursor" })
59098
+ };
59099
+ var revokeFlags2 = {
59100
+ reason: flag.string({ description: "revocation audit reason" })
59101
+ };
59102
+ function repo(ctx) {
59103
+ return parseOrgRepo(getRepoRef(ctx), ctx.config);
59104
+ }
59105
+ var CREATE_USAGE = "Usage: wh grant create <member EMAIL | pat NAME | component ORG/NAME> --key KEY --op OP [--op OP] (--coverage JSON | --view View/NAME[@vN])";
59106
+ var CREATE_EXAMPLE = `wh grant create component acme/indexer --key provision --op things:read --coverage '{"include":["Lesson/**"]}'`;
59107
+ function parseRecipient(kind, name) {
59108
+ switch (kind) {
59109
+ case "member":
59110
+ return { kind: "member", email: name };
59111
+ case "pat":
59112
+ return { kind: "pat", name };
59113
+ case "component":
59114
+ return {
59115
+ kind: "component",
59116
+ ...resolveRegisteredComponentRef(name, CREATE_USAGE, CREATE_EXAMPLE)
59117
+ };
59118
+ default:
59119
+ usageError("Grant recipient kind must be member, pat, or component.", CREATE_EXAMPLE);
59120
+ }
59121
+ }
59122
+ function isPatternList(value) {
59123
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.length > 0);
59124
+ }
59125
+ function parseCoverage(raw) {
59126
+ const candidate = parseJsonObject(raw, "--coverage");
59127
+ if (!isPatternList(candidate.include) || candidate.include.length === 0) {
59128
+ usageError("--coverage must be an object with a non-empty include array of patterns ({include, exclude?}).", CREATE_EXAMPLE);
59129
+ }
59130
+ if (candidate.exclude !== undefined && !isPatternList(candidate.exclude)) {
59131
+ usageError("--coverage exclude must be an array of patterns when present.", CREATE_EXAMPLE);
59132
+ }
59133
+ return candidate;
59134
+ }
59135
+ var handleCreate4 = async (ctx, { args, flags }) => {
59136
+ const [recipientKind, recipientName] = args;
59137
+ if (!recipientKind || !recipientName || !flags.key || !flags.op?.length) {
59138
+ usageError(CREATE_USAGE, CREATE_EXAMPLE);
59139
+ }
59140
+ if (flags.coverage && flags.view) {
59141
+ usageError("Grant create takes --coverage or --view, not both.", CREATE_EXAMPLE);
59142
+ }
59143
+ const recipient = parseRecipient(recipientKind, recipientName);
59144
+ const { org, repo: repoName } = repo(ctx);
59145
+ const source = flags.coverage ? { coverage: parseCoverage(flags.coverage) } : flags.view ? { viewRef: flags.view } : usageError("Grant create requires --coverage or --view.", CREATE_EXAMPLE);
59146
+ const result = await ctx.client.grant.create(org, repoName, {
59147
+ idempotencyKey: flags.key,
59148
+ recipient,
59149
+ ...source,
59150
+ ops: flags.op
59151
+ });
59152
+ writeOutput(ctx, result, () => ctx.out(JSON.stringify(result, null, 2)));
59153
+ };
59154
+ var handleGet = async (ctx, { args }) => {
59155
+ const grantId = args[0];
59156
+ if (!grantId) {
59157
+ usageError("Usage: wh grant get <grant-id>", "wh grant get 019b57b6-7a42-7000-8000-000000000000");
59158
+ }
59159
+ const { org, repo: repoName } = repo(ctx);
59160
+ const result = await ctx.client.grant.get(org, repoName, grantId);
59161
+ writeOutput(ctx, result, () => ctx.out(JSON.stringify(result, null, 2)));
59162
+ };
59163
+ var handleList4 = async (ctx, { flags }) => {
59164
+ const { org, repo: repoName } = repo(ctx);
59165
+ const limit = Math.min(parsePositiveIntFlag(flags.limit, "--limit", "wh grant list --limit 25") ?? 50, 100);
59166
+ const result = await ctx.client.grant.list(org, repoName, {
59167
+ limit,
59168
+ cursor: flags.cursor
59169
+ });
59170
+ writePageOutput(ctx, result.items, { limit, nextCursor: result.nextCursor ?? null }, () => ctx.out(JSON.stringify(result.items, null, 2)));
59171
+ };
59172
+ var handleRevoke2 = async (ctx, { args, flags }) => {
59173
+ const grantId = args[0];
59174
+ if (!grantId) {
59175
+ usageError("Usage: wh grant revoke <grant-id> [--reason TEXT]", "wh grant revoke 019b57b6-7a42-7000-8000-000000000000 --reason superseded");
59176
+ }
59177
+ const { org, repo: repoName } = repo(ctx);
59178
+ const result = await ctx.client.grant.revoke(org, repoName, grantId, {
59179
+ reason: flags.reason
59180
+ });
59181
+ writeOutput(ctx, result, () => ctx.out(JSON.stringify(result, null, 2)));
59182
+ };
59183
+ var GRANT_DOMAIN = defineDomain({
59184
+ name: "grant",
59185
+ summary: "Immutable repository Grant administration",
59186
+ group: "resource",
59187
+ verbs: {
59188
+ create: {
59189
+ prime: true,
59190
+ summary: "Create or replay an issuer-scoped Grant request",
59191
+ args: "<member|pat|component> <email|token-name|org/name>",
59192
+ flags: createFlags5,
59193
+ handler: handleCreate4
59194
+ },
59195
+ get: {
59196
+ prime: true,
59197
+ summary: "Get one active or revoked Grant",
59198
+ args: "<grant-id>",
59199
+ handler: handleGet
59200
+ },
59201
+ list: {
59202
+ prime: true,
59203
+ summary: "List active and revoked Grants",
59204
+ args: "",
59205
+ flags: listFlags3,
59206
+ handler: handleList4
59207
+ },
59208
+ revoke: {
59209
+ prime: true,
59210
+ summary: "Revoke a Grant idempotently",
59211
+ args: "<grant-id>",
59212
+ flags: revokeFlags2,
59213
+ handler: handleRevoke2
59214
+ }
59215
+ }
59216
+ });
59217
+
58687
59218
  // ../../packages/warmhub-cli/src/domains/init.ts
58688
59219
  import { basename as basename4 } from "node:path";
58689
59220
 
@@ -58692,7 +59223,7 @@ async function onboardRepo(ctx, repoRef, description) {
58692
59223
  if (!repoRef?.includes("/")) {
58693
59224
  throw new CliError(2 /* UserInput */, "USER_INPUT", "Usage: wh init [org/repo] [--description <desc>]", undefined, "Example: wh init my-org/my-repo");
58694
59225
  }
58695
- const parsed = splitRepoSlug(repoRef);
59226
+ const parsed = parseRepoSlug(repoRef);
58696
59227
  if (!parsed) {
58697
59228
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid repo format "${repoRef}". Expected "org/repo".`, undefined, "Example: wh init my-org/my-repo");
58698
59229
  }
@@ -58890,8 +59421,8 @@ function parseSince(raw, usage, example) {
58890
59421
  var handleNotifications = async (ctx, { flags }) => {
58891
59422
  const usage = "Usage: wh notifications [--repo org/repo] [--limit n] [--since <epoch-ms|iso>]";
58892
59423
  const example = "wh notifications --repo myorg/myrepo --since 2026-03-30T12:00:00Z";
58893
- const { org, repo } = resolveRepoContext(ctx);
58894
- const result = await ctx.client.action.listNotifications(org, repo, {
59424
+ const { org, repo: repo2 } = resolveRepoContext(ctx);
59425
+ const result = await ctx.client.action.listNotifications(org, repo2, {
58895
59426
  since: parseSince(flags.since, usage, example),
58896
59427
  limit: flags.limit
58897
59428
  });
@@ -59321,11 +59852,11 @@ var handleUpdate2 = async (ctx, { args, flags }) => {
59321
59852
  };
59322
59853
 
59323
59854
  // ../../packages/warmhub-cli/src/domains/org.ts
59324
- var createFlags5 = {
59855
+ var createFlags6 = {
59325
59856
  "display-name": flag.string({ description: "Display name for the org" }),
59326
59857
  description: flag.string({ short: "d", description: "Org description" })
59327
59858
  };
59328
- var handleCreate4 = async (ctx, { flags, args }) => {
59859
+ var handleCreate5 = async (ctx, { flags, args }) => {
59329
59860
  const name = args[0];
59330
59861
  if (!name) {
59331
59862
  usageError('Usage: wh org create <name> [--display-name "..."] [--description "..."]', 'wh org create caryden --display-name "Carl Ryden" -d "A great org"');
@@ -59367,12 +59898,12 @@ var handleView5 = async (ctx, { args }) => {
59367
59898
  ctx.out(`${c.dim}Created: ${new Date(result.createdAt).toISOString().slice(0, 16)}${c.reset}`);
59368
59899
  });
59369
59900
  };
59370
- var listFlags3 = {
59901
+ var listFlags4 = {
59371
59902
  "include-archived": flag.boolean({
59372
59903
  description: "Include archived organizations"
59373
59904
  })
59374
59905
  };
59375
- var handleList4 = async (ctx, { flags }) => {
59906
+ var handleList5 = async (ctx, { flags }) => {
59376
59907
  const c = ctx.colors;
59377
59908
  const result = await ctx.client.org.list({
59378
59909
  includeArchived: flags["include-archived"]
@@ -59479,9 +60010,9 @@ var ORG_DOMAIN = defineDomain({
59479
60010
  prime: true,
59480
60011
  summary: "Create a new organization",
59481
60012
  args: "<name>",
59482
- flags: createFlags5,
60013
+ flags: createFlags6,
59483
60014
  examples: ['wh org create caryden --display-name "Carl Ryden"'],
59484
- handler: handleCreate4
60015
+ handler: handleCreate5
59485
60016
  },
59486
60017
  view: {
59487
60018
  prime: true,
@@ -59494,9 +60025,9 @@ var ORG_DOMAIN = defineDomain({
59494
60025
  prime: true,
59495
60026
  summary: "List all organizations",
59496
60027
  args: "",
59497
- flags: listFlags3,
60028
+ flags: listFlags4,
59498
60029
  examples: ["wh org list", "wh org list --include-archived"],
59499
- handler: handleList4
60030
+ handler: handleList5
59500
60031
  },
59501
60032
  update: {
59502
60033
  summary: "Update org settings",
@@ -59538,7 +60069,7 @@ var ORG_DOMAIN = defineDomain({
59538
60069
  });
59539
60070
 
59540
60071
  // ../../packages/warmhub-cli/src/domains/prime-content.md
59541
- var prime_content_default = "# WarmHub CLI Context\n> **Context Recovery**: Run `wh prime` after compaction or new session\n\n## Environment\n{{REPO_LINE}}\n\n## Core Concepts\n- **Thing**: A named entity versioned by writes. **Assertion**: A thing that makes a shape-validated claim about another thing.\n- **Shape**: A thing defining data structure; every other thing has one. **Write**: One or more add/revise/retract operations with per-operation results.\n- **wref**: A reference to a thing. Local: `Player` (the shape) or `Player/alice` (a thing with that shape). Cross-repo: `wh:org/repo/Shape` or `wh:org/repo/Shape/name`.\n\n## Versioned Wrefs\n- `Shape` addresses the shape itself; `Shape/name` addresses a thing with that shape. `@vN` pins either.\n- Floating write refs to retracted targets fail; existing pinned versions remain valid.\n- Rename invalidates old spellings, including `@vN`; the new name resolves history.\n- Untyped wrefs accept any thing. `wref<T>` requires the target's shape to be `T`; a shape has no shape, so never satisfies it. `wref?` coalesces only `thing_absent`, never a missing shape.\n\n## Key Workflows\n\n**Write data** (discover shapes → scaffold ops → submit):\n```bash\nwh shape list --repo org/repo # list available shapes\nwh shape view ShapeName --repo org/repo # inspect fields\nwh shape template ShapeName -o ops.json --repo org/repo # scaffold write ops (supports --kind assertion)\n# edit ops.json — fill FILL_IN placeholders — then:\nwh commit submit --file ops.json -m \"msg\" --repo org/repo # submit operations (bare `wh commit` also works)\n# or single assertion (no file needed):\nwh assertion create --shape ShapeName --about Target/name --name my-assertion --data '{\"field\":1}' --repo org/repo\n# Relay failed operation details when present. Never hand-guess ops JSON — use `wh shape template <Shape>`.\n```\n\n**Read data:**\n```bash\nwh thing list --repo org/repo # all things at HEAD\nwh thing view Shape/name --repo org/repo # inspect a thing\nwh thing query --shape MyShape --repo org/repo # find things by shape\nwh thing about Shape --repo org/repo # assertions about a shape\nwh assertion list --repo org/repo # all assertions at HEAD\nwh thing history Shape/name --repo org/repo # version history\n\n# Batch read — wh thing view is variadic (max 500 wrefs/call):\nwh thing view Player/alice Player/bob # variadic positionals\nwh thing view --file wrefs.txt --json # one wref per line\ncat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped* requested wref\n```\n\n## Wref Quick Reference\n\nWrites use explicit names and wrefs. Untyped fields, collection members,\nassertion `about`, and committers accept any thing. Create a deterministic\ntarget before referencing it in the same commit.\n\n## Command Reference\n\n**Global flags**: `--repo`, `--format`, `--json`, `--live`\n### thing — Thing operations\n- `wh thing list [--shape] [--kind] [--match] [--include-retracted]` — Current HEAD state\n- `wh thing view [<wref>...] [--file <path>] [--version] [--depth] [--include-retracted] [--data-mode auto|full]` — Thing details. Variadic (max 500). `--version` implies `--include-retracted`. Batch JSON returns `{ requested, items, missing }`; jsonl emits one row per deduped requested wref. Large Set/List bodies summarize by default; use `--data-mode full` for canonical collection JSON.\n- `wh thing history [wref] [--shape] [--about] [--include-retracted]` — Version history\n- `wh thing resolve <wref>` — Resolve a wref to its canonical thing identity\n- `wh thing create <name|Shape/name> (--data|--file) [--shape]` — Create\n- `wh thing revise <name> [--data] [--message] [--committer] [--expected-version]` — Revise (CONFLICT if HEAD≠n)\n- `wh thing retract <wref> -m <message> [--reason] [--kind] [--expected-version]` — Retract\n- `wh thing query [--shape] [--kind] [--about] [--match]` — Query by filters\n- `wh thing search <query> [--shape] [--kind] [--about] [--mode]` — Search text\n- `wh thing rename <Shape/oldName> <newName>` — Rename\n- `wh thing refs <wref> [--inbound] [--outbound] [--field]` — Show field references; use `wh thing about` for assertions about the target thing\n- `wh thing about <wref> [--shape] [--match] [--depth] [--resolve-collections] [--role from|to|ends] [--limit] [--include-retracted]` — Show assertions about the target identity; `--resolve-collections` expands bare/@HEAD/@ALL members, `--role` filters direction; not pinned @vN\n\n### commit — Write operations\n- `wh commit submit [--ops|--file|--add|--revise|--retract] [--kind] [--data] [--reason] [--expected-version] [--chunk-size] [--skip-existing] [--progress] [--stream-id]` — Submit operations (bare `wh commit` is equivalent). Use `--file ops.jsonl --stream-id <id> --chunk-size 5000 --skip-existing` for bulk ingest.\n- `wh shape template <shape> [shape2 ...] [--kind] [--operation add|revise|retract] [-o file]` — Generate sample ops\n\n### assertion — Assertion operations\n- `wh assertion list [--about wref] [--shape] [--match] [--include-retracted]` — Browse assertions\n- `wh assertion view <wref> [--version] [--include-retracted]` — Assertion details\n- `wh assertion create --shape <s> --name <n> --about <wref> [--data] [-m] [--committer]` — Create assertion\n- `wh assertion revise <wref> --data <json> [--message] [--committer]` — Revise assertion\n- `wh assertion retract <wref> -m <message> [--reason] [--committer] [--expected-version]` — Retract assertion\n- `wh assertion history <wref> [--include-retracted]` — Assertion history\n\n### shape — Shape management\n- `wh shape list [--match] [--include-retracted]` — List all shapes\n- `wh shape view <name> [--include-retracted]` — Shape details\n- `wh shape revise <name> (--fields|--file)`\n- `wh shape create <name> (--fields|--file)`\n- `wh shape retract <name> -m <message> [--reason] [--expected-version]` — Retract shape\n- `wh shape history <name> [--include-retracted]` — Shape history\n- `wh shape rename <oldName> <newName>` — Rename shape\n\n### repo — Repository management\n- `wh repo create <org/name> [--display-name] [--description] [--visibility]` — Create repo\n- `wh repo list [org]` — List repos\n- `wh repo view [org/repo]` — Repo details\n\n### org — Organization management\n- `wh org create <name> [--display-name]` — Create a new organization\n- `wh org view <name>` — View organization details (alias: info)\n- `wh org list` — List all organizations\n\n### sub — Subscription management\n- `wh sub create <name> [flags]` — Create a subscription\n- `wh sub view <name>` — View subscription details\n- `wh sub list` — List all subscriptions\n- `wh sub log <name>` — Tail subscription delivery feed\n- `wh sub attempts <runId>` — Show attempt history for a run\n- `wh sub pause <name>` — Pause a subscription\n- `wh sub resume <name>` — Resume a paused subscription\n- `wh sub bind <name> [--credentials]` — Bind a credential set to a subscription for webhook auth\n- `wh sub unbind <name>` — Remove credential binding from a subscription\n- `wh sub delete <name>` — Retire; name reserved\n\n### notifications — Action notification listing\n- `wh notifications [--limit] [--since]` — List repo-scoped action notifications\n\n### credential — Credential set management\n- `wh credential create <name> [--repo org/repo | --org org] [--scope] [--description]` — Create an empty credential set\n- `wh credential list [--repo org/repo | --org org]` — List credential sets accessible from a repo or org\n- `wh credential view <name> [--repo org/repo | --org org]` — View a credential set (key names only, no values)\n- `wh credential delete <name> [--repo org/repo | --org org]` — Delete a credential set and its Vault object\n- `wh credential set <setName> [<keyName>] [--repo org/repo | --org org] [--value]` — Set credential key(s). With `<keyName>`: single-key form (reads value from `--value` or stdin). Without `<keyName>`: batch form (reads JSON object from stdin, e.g. `{\"KEY\":\"val\"}`)\n- `wh credential unset <setName> <keyName> [--repo org/repo | --org org]` — Remove a key from a credential set\n- `wh credential audit <setName> [--repo org/repo | --org org]` — View audit log for a credential set\n- `wh credential revoke <setName> [--repo org/repo | --org org] [--reason]` — Revoke a credential set (blocks new binds and stops bound webhook deliveries)\n\n### component — Component management\n- `wh component validate <path>` — Validate package\n- `wh component install <org/name>` — Install a registered component\n- `wh component register <name> --org <org> --manifest <path> [flags]` — Register component identity\n- `wh component unregister <org/name>` — Remove a registered component identity\n- `wh component registry list --org <org>` — List registered components\n- `wh component registry view <org/name>` — View a registered component\n- `wh component registry update <org/name> [flags]` — Update a registered component\n- `wh component list` — List installed components\n- `wh component update <org/name>` — Update installed component\n- `wh component view <org/name>` — Show component details (alias: show)\n- `wh component doctor <org/name>` — Run component health checks\n- `wh component teardown <org/name>` — Pause component subscriptions\n\n### Getting More Info\n- `wh help` — help overview\n- `wh <domain>` — domain verbs\n- `wh <domain> <verb> --help` — verb flags and examples\n- `wh help --format json` — `CliSpecV2` (`schemaVersion: 2`): global/contextual/root tables and command overrides\n\n## Common Workflows\n\n**Explore a repo:**\n```bash\nwh thing list --repo org/repo # see all things in HEAD\nwh thing view Shape/name --repo org/repo # inspect a specific thing\nwh thing history Shape/name --repo org/repo # inspect version history\nwh thing about Shape/name # assertions about thing/shape\n```\n\n**Create an assertion** (most common write):\n```bash\n# --about takes an untyped target wref: Shape or Shape/name.\nwh assertion create --shape MyShape --about TargetShape/target-name \\\n --name my-assertion --data '{\"field_a\":1,\"field_b\":\"value\"}' --repo org/repo\n# Output includes per-operation status; relay failures when present.\n```\n\n**Create via write entrypoint** (alternative, supports batches and streams):\n```bash\nwh commit submit --add my-item --shape MyShape --kind assertion \\\n --about TargetShape/target-name --data '{\"field_a\":1}' --repo org/repo\n```\n\n**Batch write via file** (generate template → edit → submit):\n```bash\nwh shape template Hypothesis Evidence -o ops.json # add --kind assertion --about TargetShape/name for assertions\n# edit ops.json — fill FILL_IN placeholders\nwh commit submit --file ops.json -m \"batch update\" # submit all operations (bare `wh commit` is equivalent)\n# --file format: docs.warmhub.ai/cli-reference/commit-operations\n```\n\n**Bulk write (JSONL stream, >1k ops)** — one chunked stream beats per-record commits (~60× faster):\n```bash\nwh shape template MyShape -o ops.jsonl # one op per line (.jsonl)\nID=\"bulk-$(date +%s)\" # caller id for chunk correlation\nwh commit submit --file ops.jsonl --stream-id \"$ID\" --chunk-size 5000 \\\n --skip-existing --progress -m \"bulk ingest\" --repo org/repo\n# --chunk-size: ops per append chunk (default 1000, max 10000); chunk≈1 is ~60× slower\n# --skip-existing: skips already-written add ops (drops per-row read-before-write)\n# --stream-id identifies the submission but provides no receipt or resume.\n# After an outcome-unknown append, stop writes and reconcile attempted + unsent\n# work from a later verified checkpoint; never blindly replay revise/retract.\n```\n\n**Create collections:**\n```bash\nwh commit submit --type arc --name route --members Location/a,Location/b --repo org/repo\nwh assertion create --shape Supports --name route-support --about Arc/route --data '{\"confidence\":0.8}' --repo org/repo\n```\n\n**Modify data:**\n```bash\nwh thing revise Shape/name --data '{\"x\":5,\"y\":3}' -m \"update\" --repo org/repo\nwh thing retract Shape/old-item -m \"withdrawn\" --reason \"data feed contaminated\" --repo org/repo\n```\n\n**Query and filter:**\n```bash\nwh thing query --shape MyShape # by shape\nwh thing query --kind assertion --about Shape/name # by kind + target\nwh thing history Shape/name --limit 10 # version history\n```\n\n## Built-in Content shape\n\nWarmHub repos expose three well-known content wrefs:\n- `Content/Readme` — stored markdown for humans\n- `Content/Agents` — stored markdown guidance for AI agents\n- `Content/LlmsTxt` — synthesized per-request sitemap (read-only)\n\nFetch via `wh repo content get --kind readme|agents|llms-txt`,\n`client.repo.getReadme/getAgents/getLlmsTxt`, MCP `warmhub_repo_content_get`,\nor raw HTTP `GET /{org}/{repo}/readme.md|agents.md|llms.txt`.\nSee `wh repo describe` → `additionalInformation` for the discovery field.\n\n## Query Discipline\n- Plan the repo, shapes, and wrefs you need before the first query.\n- Gather the needed facts from one repo before switching to another.\n- Do the queries first, then write one complete answer.\n\n## Agent Tips\n- **Always run commands for live data** — this context describes the CLI, not repo contents\n- **Before writing, discover wrefs** — run `wh thing list` or `wh shape list`\n- **Shape field types**: `string`, `number`, `boolean`, `wref`, arrays, optionals, nested objects\n- **Write commands return per-operation results** — relay failures and affected wrefs to the user\n- **Pass data inline** with `--data '{...}'` — do NOT create temp files\n- Add `--json` to any command for machine-readable JSON output\n- **Aliases teach canonical commands** — executing aliases emit a status hint; misleading lifecycle aliases reject and point to `retract`\n- Writes go through `wh commit submit` (or bare `wh commit`) or wrappers (`create`, `revise`, `retract`, `assertion create`). `retract` irreversibly withdraws an identity and creates a history entry.\n- Use `wh doctor` to check environment health\n";
60072
+ var prime_content_default = "# WarmHub CLI Context\n> **Context Recovery**: Run `wh prime` after compaction or new session\n\n## Environment\n{{REPO_LINE}}\n\n## Core Concepts\n- **Thing**: A named entity versioned by writes. **Assertion**: A thing that makes a shape-validated claim about another thing.\n- **Shape**: A thing defining data structure; every other thing has one. **Write**: One or more add/revise/retract operations with per-operation results.\n- **wref**: A reference to a thing. Local: `Player` (the shape) or `Player/alice` (a thing with that shape). Cross-repo: `wh:org/repo/Shape` or `wh:org/repo/Shape/name`.\n\n## Versioned Wrefs\n- `Shape` addresses the shape itself; `Shape/name` addresses a thing with that shape. `@vN` pins either.\n- Floating write refs to retracted targets fail; existing pinned versions remain valid.\n- Rename invalidates old spellings, including `@vN`; the new name resolves history.\n- Untyped wrefs accept any thing. `wref<T>` requires the target's shape to be `T`; a shape has no shape, so never satisfies it. `wref?` coalesces only `thing_absent`, never a missing shape.\n\n## Key Workflows\n\n**Write data** (discover shapes → scaffold ops → submit):\n```bash\nwh shape list --repo org/repo # list available shapes\nwh shape view ShapeName --repo org/repo # inspect fields\nwh shape template ShapeName -o ops.json --repo org/repo # scaffold write ops (supports --kind assertion)\n# edit ops.json — fill FILL_IN placeholders — then:\nwh commit submit --file ops.json -m \"msg\" --repo org/repo # submit operations (bare `wh commit` also works)\n# or single assertion (no file needed):\nwh assertion create --shape ShapeName --about Target/name --name my-assertion --data '{\"field\":1}' --repo org/repo\n# Relay failed operation details when present. Never hand-guess ops JSON — use `wh shape template <Shape>`.\n```\n\n**Read data:**\n```bash\nwh thing list --repo org/repo # all things at HEAD\nwh thing view Shape/name --repo org/repo # inspect a thing\nwh thing query --shape MyShape --repo org/repo # find things by shape\nwh thing about Shape --repo org/repo # assertions about a shape\nwh assertion list --repo org/repo # all assertions at HEAD\nwh thing history Shape/name --repo org/repo # version history\n\n# Batch read — wh thing view is variadic (max 500 wrefs/call):\nwh thing view Player/alice Player/bob # variadic positionals\nwh thing view --file wrefs.txt --json # one wref per line\ncat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped* requested wref\n```\n\n## Wref Quick Reference\n\nWrites use explicit names and wrefs. Untyped fields, collection members,\nassertion `about`, and committers accept any thing. Create a deterministic\ntarget before referencing it in the same commit.\n\n## Command Reference\n\n**Global flags**: `--repo`, `--format`, `--json`, `--live`\n### thing — Things\n- `wh thing list [--shape] [--kind] [--match] [--include-retracted]` — Current HEAD state\n- `wh thing view [<wref>...] [--file <path>] [--version] [--depth] [--include-retracted] [--data-mode auto|full]` — Thing details. Variadic (max 500). `--version` implies `--include-retracted`. Batch JSON returns `{ requested, items, missing }`; jsonl emits one row per deduped requested wref. Large Set/List bodies summarize by default; use `--data-mode full` for canonical collection JSON.\n- `wh thing history [wref] [--shape] [--about] [--include-retracted]` — Version history\n- `wh thing resolve <wref>` — Resolve a wref to its canonical thing identity\n- `wh thing create <name|Shape/name> (--data|--file) [--shape]` — Create\n- `wh thing revise <name> [--data] [--message] [--committer] [--expected-version]` — Revise (CONFLICT if HEAD≠n)\n- `wh thing retract <wref> -m <message> [--reason] [--kind] [--expected-version]` — Retract\n- `wh thing query [--shape] [--kind] [--about] [--match]` — Query by filters\n- `wh thing search <query> [--shape] [--kind] [--about] [--mode]` — Search text\n- `wh thing rename <Shape/oldName> <newName>` — Rename\n- `wh thing refs <wref> [--inbound] [--outbound] [--field]` — Show field references; use `wh thing about` for assertions about the target thing\n- `wh thing about <wref> [--shape] [--match] [--depth] [--resolve-collections] [--role from|to|ends] [--limit] [--include-retracted]` — Show assertions about the target identity; `--resolve-collections` expands bare/@HEAD/@ALL members, `--role` filters direction; not pinned @vN\n\n- `wh view evaluate VIEW [--limit N] [--cursor TOK] [--all]`\n### commit — Write operations\n- `wh commit submit [--ops|--file|--add|--revise|--retract] [--kind] [--data] [--reason] [--expected-version] [--chunk-size] [--skip-existing] [--progress] [--stream-id]` — Submit operations (bare `wh commit` is equivalent). Use `--file ops.jsonl --stream-id <id> --chunk-size 5000 --skip-existing` for bulk ingest.\n- `wh shape template <shape> [shape2 ...] [--kind] [--operation add|revise|retract] [-o file]` — Generate sample ops\n\n### assertion — Assertion operations\n- `wh assertion list [--about wref] [--shape] [--match] [--include-retracted]` — Browse assertions\n- `wh assertion view <wref> [--version] [--include-retracted]` — Assertion details\n- `wh assertion create --shape <s> --name <n> --about <wref> [--data] [-m] [--committer]` — Create assertion\n- `wh assertion revise <wref> --data <json> [--message] [--committer]` — Revise assertion\n- `wh assertion retract <wref> -m <message> [--reason] [--committer] [--expected-version]` — Retract assertion\n- `wh assertion history <wref> [--include-retracted]` — Assertion history\n\n### shape — Shape management\n- `wh shape list [--match] [--include-retracted]` — List all shapes\n- `wh shape view <name> [--include-retracted]` — Shape details\n- `wh shape revise <name> (--fields|--file)`\n- `wh shape create <name> (--fields|--file)`\n- `wh shape retract <name> -m <message> [--reason] [--expected-version]` — Retract shape\n- `wh shape history <name> [--include-retracted]` — Shape history\n- `wh shape rename <oldName> <newName>` — Rename shape\n\n### repo — Repository management\n- `wh repo create <org/name> [--display-name] [--description] [--visibility]` — Create repo\n- `wh repo list [org]` — List repos\n- `wh repo view [org/repo]` — Repo details\n\n### org — Organization management\n- `wh org create <name> [--display-name]` — Create a new organization\n- `wh org view <name>` — View organization details (alias: info)\n- `wh org list` — List all organizations\n\n### sub — Subscription management\n- `wh sub create <name> [flags]` — Create a subscription\n- `wh sub view <name>` — View subscription details\n- `wh sub list` — List all subscriptions\n- `wh sub log <name>` — Tail subscription delivery feed\n- `wh sub attempts <runId>` — Show attempt history for a run\n- `wh sub pause <name>` — Pause a subscription\n- `wh sub resume <name>` — Resume a paused subscription\n- `wh sub bind <name> [--credentials]` — Bind a credential set to a subscription for webhook auth\n- `wh sub unbind <name>` — Remove credential binding from a subscription\n- `wh sub delete <name>` — Retire; name reserved\n\n### notifications — Action notification listing\n- `wh notifications [--limit] [--since]` — List repo-scoped action notifications\n\n### credential — Credential set management\n- `wh credential create <name> [--repo org/repo | --org org] [--scope] [--description]` — Create an empty credential set\n- `wh credential list [--repo org/repo | --org org]` — List credential sets accessible from a repo or org\n- `wh credential view <name> [--repo org/repo | --org org]` — View a credential set (key names only, no values)\n- `wh credential delete <name> [--repo org/repo | --org org]` — Delete a credential set and its Vault object\n- `wh credential set <setName> [<keyName>] [--repo org/repo | --org org] [--value]` — Set credential key(s). With `<keyName>`: single-key form (reads value from `--value` or stdin). Without `<keyName>`: batch form (reads JSON object from stdin, e.g. `{\"KEY\":\"val\"}`)\n- `wh credential unset <setName> <keyName> [--repo org/repo | --org org]` — Remove a key from a credential set\n- `wh credential audit <setName> [--repo org/repo | --org org]` — View audit log for a credential set\n- `wh credential revoke <setName> [--repo org/repo | --org org] [--reason]` — Revoke a credential set (blocks new binds and stops bound webhook deliveries)\n\n### component — Component management\n- `wh component validate <path>` — Validate package\n- `wh component install <org/name>` — Install a registered component\n- `wh component register <name> --org <org> --manifest <path> [flags]` — Register component identity\n- `wh component unregister <org/name>` — Remove a registered component identity\n- `wh component registry list --org <org>` — List registered components\n- `wh component registry view <org/name>` — View a registered component\n- `wh component registry update <org/name> [flags]` — Update a registered component\n- `wh component list` — List installed components\n- `wh component update <org/name>` — Update installed component\n- `wh component view <org/name>` — Show component details (alias: show)\n- `wh component doctor <org/name>` — Run component health checks\n- `wh component teardown <org/name>` — Pause component subscriptions\n\n### Getting More Info\n- `wh help` — help overview\n- `wh <domain>` — domain verbs\n- `wh <domain> <verb> --help` — verb flags and examples\n- `wh help --format json` — `CliSpecV2` (`schemaVersion: 2`): global/contextual/root tables and command overrides\n\n## Common Workflows\n\n**Explore a repo:**\n```bash\nwh thing list --repo org/repo # see all things in HEAD\nwh thing view Shape/name --repo org/repo # inspect a specific thing\nwh thing history Shape/name --repo org/repo # inspect version history\nwh thing about Shape/name # assertions about thing/shape\n```\n\n**Create an assertion** (most common write):\n```bash\n# --about takes an untyped target wref: Shape or Shape/name.\nwh assertion create --shape MyShape --about TargetShape/target-name \\\n --name my-assertion --data '{\"field_a\":1,\"field_b\":\"value\"}' --repo org/repo\n# Output includes per-operation status; relay failures when present.\n```\n\n**Create via write entrypoint** (alternative, supports batches and streams):\n```bash\nwh commit submit --add my-item --shape MyShape --kind assertion \\\n --about TargetShape/target-name --data '{\"field_a\":1}' --repo org/repo\n```\n\n**Batch write via file** (generate template → edit → submit):\n```bash\nwh shape template Hypothesis Evidence -o ops.json # add --kind assertion --about TargetShape/name for assertions\n# edit ops.json — fill FILL_IN placeholders\nwh commit submit --file ops.json -m \"batch update\" # submit all operations (bare `wh commit` is equivalent)\n# --file format: docs.warmhub.ai/cli-reference/commit-operations\n```\n\n**Bulk write (JSONL stream, >1k ops)** — one chunked stream beats per-record commits (~60× faster):\n```bash\nwh shape template MyShape -o ops.jsonl # one op per line (.jsonl)\nID=\"bulk-$(date +%s)\" # caller id for chunk correlation\nwh commit submit --file ops.jsonl --stream-id \"$ID\" --chunk-size 5000 \\\n --skip-existing --progress -m \"bulk ingest\" --repo org/repo\n# --chunk-size: ops per append chunk (default 1000, max 10000); chunk≈1 is ~60× slower\n# --skip-existing: skips already-written add ops (drops per-row read-before-write)\n# --stream-id identifies the submission but provides no receipt or resume.\n# After an outcome-unknown append, stop writes and reconcile attempted + unsent\n# work from a later verified checkpoint; never blindly replay revise/retract.\n```\n\n**Create collections:**\n```bash\nwh commit submit --type arc --name route --members Location/a,Location/b --repo org/repo\nwh assertion create --shape Supports --name route-support --about Arc/route --data '{\"confidence\":0.8}' --repo org/repo\n```\n\n**Modify data:**\n```bash\nwh thing revise Shape/name --data '{\"x\":5,\"y\":3}' -m \"update\" --repo org/repo\nwh thing retract Shape/old-item -m \"withdrawn\" --reason \"data feed contaminated\" --repo org/repo\n```\n\n**Query and filter:**\n```bash\nwh thing query --shape MyShape # by shape\nwh thing query --kind assertion --about Shape/name # by kind + target\nwh thing history Shape/name --limit 10 # version history\n```\n\n## Built-in Content shape\n\nWarmHub repos expose three well-known content wrefs:\n- `Content/Readme` — stored markdown for humans\n- `Content/Agents` — stored markdown guidance for AI agents\n- `Content/LlmsTxt` — synthesized per-request sitemap (read-only)\n\nFetch via `wh repo content get --kind readme|agents|llms-txt`,\n`client.repo.getReadme/getAgents/getLlmsTxt`, MCP `warmhub_repo_content_get`,\nor raw HTTP `GET /{org}/{repo}/readme.md|agents.md|llms.txt`.\nSee `wh repo describe` → `additionalInformation` for the discovery field.\n\n## Query Discipline\n- Plan the repo, shapes, and wrefs you need before the first query.\n- Gather the needed facts from one repo before switching to another.\n- Do the queries first, then write one complete answer.\n\n## Agent Tips\n- **Always run commands for live data** — this context describes the CLI, not repo contents\n- **Before writing, discover wrefs** — run `wh thing list` or `wh shape list`\n- **Shape field types**: `string`, `number`, `boolean`, `wref`, arrays, optionals, nested objects\n- **Write commands return per-operation results** — relay failures and affected wrefs to the user\n- **Pass data inline** with `--data '{...}'` — do NOT create temp files\n- Add `--json` to any command for machine-readable JSON output\n- **Aliases teach canonical commands** — executing aliases emit a status hint; misleading lifecycle aliases reject and point to `retract`\n- Writes go through `wh commit submit` (or bare `wh commit`) or wrappers (`create`, `revise`, `retract`, `assertion create`). `retract` irreversibly withdraws an identity and creates a history entry.\n- Use `wh doctor` to check environment health\n";
59542
60073
 
59543
60074
  // ../../packages/warmhub-cli/src/domains/prime.ts
59544
60075
  function buildMarkdown(config2) {
@@ -60819,13 +61350,13 @@ function printCheckpoint(ctx, result) {
60819
61350
  ctx.out(`Failure: ${result.failureCode}`);
60820
61351
  });
60821
61352
  }
60822
- async function waitForCompletion(ctx, org, repo, initial) {
61353
+ async function waitForCompletion(ctx, org, repo2, initial) {
60823
61354
  let result = initial;
60824
61355
  let delayMs = 200;
60825
61356
  while (result.state === "queued" || result.state === "running") {
60826
61357
  ctx.status(`Checkpoint ${result.checkpointId} is ${result.state}; waiting…`);
60827
61358
  await delay2(delayMs, ctx.signal);
60828
- result = await checkpointClient(ctx).status(org, repo, {
61359
+ result = await checkpointClient(ctx).status(org, repo2, {
60829
61360
  checkpointId: result.checkpointId
60830
61361
  });
60831
61362
  delayMs = Math.min(delayMs * 2, 5000);
@@ -60850,27 +61381,27 @@ function delay2(ms, signal) {
60850
61381
  });
60851
61382
  }
60852
61383
  var handleGenerate = async (ctx, { args, flags }) => {
60853
- const { org, repo } = repoFor(ctx, args);
60854
- const result = await checkpointClient(ctx).generate(org, repo, {
61384
+ const { org, repo: repo2 } = repoFor(ctx, args);
61385
+ const result = await checkpointClient(ctx).generate(org, repo2, {
60855
61386
  atLeastRepoSeq: requireSequence(flags["at-least-repo-seq"], "--at-least-repo-seq")
60856
61387
  });
60857
- printCheckpoint(ctx, flags.wait ? await waitForCompletion(ctx, org, repo, result) : result);
61388
+ printCheckpoint(ctx, flags.wait ? await waitForCompletion(ctx, org, repo2, result) : result);
60858
61389
  };
60859
61390
  var handleStatus2 = async (ctx, { args, flags }) => {
60860
- const { org, repo } = repoFor(ctx, args);
60861
- printCheckpoint(ctx, await checkpointClient(ctx).status(org, repo, selectCheckpoint(flags)));
61391
+ const { org, repo: repo2 } = repoFor(ctx, args);
61392
+ printCheckpoint(ctx, await checkpointClient(ctx).status(org, repo2, selectCheckpoint(flags)));
60862
61393
  };
60863
61394
  var handleLatest = async (ctx, { args }) => {
60864
- const { org, repo } = repoFor(ctx, args);
60865
- printCheckpoint(ctx, await checkpointClient(ctx).latest(org, repo));
61395
+ const { org, repo: repo2 } = repoFor(ctx, args);
61396
+ printCheckpoint(ctx, await checkpointClient(ctx).latest(org, repo2));
60866
61397
  };
60867
61398
  var handleRetry = async (ctx, { args, flags }) => {
60868
61399
  if (!flags.checkpoint) {
60869
61400
  usageError("--checkpoint is required for retry.", `wh repo checkpoint retry acme/widgets --checkpoint ${CHECKPOINT_ID_EXAMPLE}`);
60870
61401
  }
60871
- const { org, repo } = repoFor(ctx, args);
60872
- const result = await checkpointClient(ctx).retry(org, repo, flags.checkpoint);
60873
- printCheckpoint(ctx, flags.wait ? await waitForCompletion(ctx, org, repo, result) : result);
61402
+ const { org, repo: repo2 } = repoFor(ctx, args);
61403
+ const result = await checkpointClient(ctx).retry(org, repo2, flags.checkpoint);
61404
+ printCheckpoint(ctx, flags.wait ? await waitForCompletion(ctx, org, repo2, result) : result);
60874
61405
  };
60875
61406
  var handleDownload = async (ctx, { args, flags }) => {
60876
61407
  if (!flags.output) {
@@ -60879,8 +61410,8 @@ var handleDownload = async (ctx, { args, flags }) => {
60879
61410
  if (flags.output === "-" && ctx.format !== "pretty") {
60880
61411
  throw new CliError(2 /* UserInput */, "USER_INPUT", "Binary stdout requires --format pretty; JSON and JSONL cannot carry artifact bytes.");
60881
61412
  }
60882
- const { org, repo } = repoFor(ctx, args);
60883
- const access = await checkpointClient(ctx).getAccess(org, repo, {
61413
+ const { org, repo: repo2 } = repoFor(ctx, args);
61414
+ const access = await checkpointClient(ctx).getAccess(org, repo2, {
60884
61415
  checkpoint: selectArtifactCheckpoint(flags, CHECKPOINT_DOWNLOAD_EXAMPLE),
60885
61416
  artifact: selectArtifact(flags, CHECKPOINT_DOWNLOAD_EXAMPLE)
60886
61417
  });
@@ -60895,8 +61426,8 @@ var handleDownload = async (ctx, { args, flags }) => {
60895
61426
  ctx.status(`Downloaded checkpoint artifact to ${flags.output}`);
60896
61427
  };
60897
61428
  var handleAccess = async (ctx, { args, flags }) => {
60898
- const { org, repo } = repoFor(ctx, args);
60899
- printAccess(ctx, await checkpointClient(ctx).getAccess(org, repo, {
61429
+ const { org, repo: repo2 } = repoFor(ctx, args);
61430
+ printAccess(ctx, await checkpointClient(ctx).getAccess(org, repo2, {
60900
61431
  checkpoint: selectArtifactCheckpoint(flags, CHECKPOINT_ACCESS_EXAMPLE),
60901
61432
  artifact: selectArtifact(flags, CHECKPOINT_ACCESS_EXAMPLE)
60902
61433
  }));
@@ -61104,24 +61635,22 @@ function parseExplicitOrgRepoArg(ref, usage, example) {
61104
61635
  if (!ref?.includes("/")) {
61105
61636
  usageError(usage, example);
61106
61637
  }
61107
- const parts = ref.split("/");
61108
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
61638
+ const parsed = parseRepoSlug(ref);
61639
+ if (!parsed) {
61109
61640
  usageError(`Invalid repo format "${ref}". Expected "org/repo" with no extra slashes or empty segments.`, example);
61110
61641
  }
61111
- const [orgName, repoName] = parts;
61112
- return { orgName, repoName };
61642
+ return { orgName: parsed.org, repoName: parsed.repo };
61113
61643
  }
61114
61644
  function resolveOrgRepoArg(ref, orgFlag) {
61115
61645
  if (ref?.includes("/")) {
61116
- const parts = ref.split("/");
61117
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
61646
+ const parsed = parseRepoSlug(ref);
61647
+ if (!parsed) {
61118
61648
  usageError(`Invalid repo format '${ref}'. Expected '<org>/<name>' with no extra slashes and no empty parts.`, "wh repo create myorg/myrepo");
61119
61649
  }
61120
- const [orgName, repoName] = parts;
61121
- if (orgFlag && orgFlag !== orgName) {
61122
- usageError(`Conflicting org: positional '${orgName}' vs --org '${orgFlag}'`, "wh repo create myorg/myrepo");
61650
+ if (orgFlag && orgFlag !== parsed.org) {
61651
+ usageError(`Conflicting org: positional '${parsed.org}' vs --org '${orgFlag}'`, "wh repo create myorg/myrepo");
61123
61652
  }
61124
- return { orgName, repoName };
61653
+ return { orgName: parsed.org, repoName: parsed.repo };
61125
61654
  }
61126
61655
  if (ref && orgFlag) {
61127
61656
  return {
@@ -61137,10 +61666,11 @@ function nameStrings(items) {
61137
61666
  }
61138
61667
 
61139
61668
  // ../../packages/warmhub-cli/src/domains/repo/content.ts
61140
- var READ_ONLY_KINDS = new Set(["llms-txt"]);
61141
61669
  var CONTENT_KINDS = ["readme", "agents", "llms-txt"];
61670
+ var CONTENT_KIND_LIST = CONTENT_KINDS.join(", ");
61671
+ var READ_ONLY_KINDS = new Set(["llms-txt"]);
61142
61672
  var kindFlagDef = flag.string({
61143
- description: "Which content kind to operate on (readme, agents, llms-txt)"
61673
+ description: `Which content kind to operate on (${CONTENT_KIND_LIST})`
61144
61674
  });
61145
61675
  var contentGetFlags = {
61146
61676
  kind: kindFlagDef
@@ -61160,19 +61690,20 @@ var promptFlags = {
61160
61690
  };
61161
61691
  function requireKind(kind) {
61162
61692
  if (!kind) {
61163
- throw new CliError(2 /* UserInput */, "USER_INPUT", "--kind is required. Choose one of: readme, agents, llms-txt", undefined, "Example: wh repo content get myorg/myrepo --kind readme");
61693
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `--kind is required. Choose one of: ${CONTENT_KIND_LIST}`, undefined, "Example: wh repo content get myorg/myrepo --kind readme");
61164
61694
  }
61165
- if (!CONTENT_KINDS.includes(kind)) {
61166
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind '${kind}'. Choose one of: readme, agents, llms-txt`);
61695
+ const parsed = CONTENT_KINDS.find((candidate) => candidate === kind);
61696
+ if (!parsed) {
61697
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind '${kind}'. Choose one of: ${CONTENT_KIND_LIST}`);
61167
61698
  }
61168
- return kind;
61699
+ return parsed;
61169
61700
  }
61170
61701
  var handleContentGet = async (ctx, { args, flags }) => {
61171
61702
  const kind = requireKind(flags.kind);
61172
- const { org, repo } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
61703
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
61173
61704
  switch (kind) {
61174
61705
  case "readme": {
61175
- const result = await ctx.client.repo.getReadme(org, repo);
61706
+ const result = await ctx.client.repo.getReadme(org, repo2);
61176
61707
  const content = result?.data?.content;
61177
61708
  const text = typeof content === "string" ? content : "";
61178
61709
  writeOutput(ctx, result, () => {
@@ -61181,7 +61712,7 @@ var handleContentGet = async (ctx, { args, flags }) => {
61181
61712
  break;
61182
61713
  }
61183
61714
  case "agents": {
61184
- const result = await ctx.client.repo.getAgents(org, repo);
61715
+ const result = await ctx.client.repo.getAgents(org, repo2);
61185
61716
  const content = result?.data?.content;
61186
61717
  const text = typeof content === "string" ? content : "";
61187
61718
  writeOutput(ctx, result, () => {
@@ -61190,7 +61721,7 @@ var handleContentGet = async (ctx, { args, flags }) => {
61190
61721
  break;
61191
61722
  }
61192
61723
  case "llms-txt": {
61193
- const result = await ctx.client.repo.getLlmsTxt(org, repo);
61724
+ const result = await ctx.client.repo.getLlmsTxt(org, repo2);
61194
61725
  writeOutput(ctx, result, () => {
61195
61726
  ctx.out(result.data.content);
61196
61727
  });
@@ -61203,26 +61734,26 @@ var handleContentSet = async (ctx, { args, flags }) => {
61203
61734
  if (READ_ONLY_KINDS.has(kind)) {
61204
61735
  throw new CliError(2 /* UserInput */, "USER_INPUT", `--kind ${kind} is read-only; \`set\` is rejected.`, undefined, `Use \`wh repo content get [org/repo] --kind ${kind}\` (or set --repo)`);
61205
61736
  }
61206
- const { org, repo } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
61737
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
61207
61738
  const inputContent = await readContentInput(flags.file, flags.content, ctx.stdin);
61208
61739
  const eventRequestId = flags["event-request-id"] ?? createOperationEventRequestId();
61209
61740
  ctx.status(`Operation event request: ${eventRequestId}`);
61210
61741
  switch (kind) {
61211
61742
  case "readme": {
61212
- const result = await ctx.client.repo.setReadme(org, repo, inputContent, {
61743
+ const result = await ctx.client.repo.setReadme(org, repo2, inputContent, {
61213
61744
  eventRequestId
61214
61745
  });
61215
61746
  writeOutput(ctx, result, () => {
61216
- ctx.status(`Content/Readme updated in ${org}/${repo}`);
61747
+ ctx.status(`Content/Readme updated in ${org}/${repo2}`);
61217
61748
  });
61218
61749
  break;
61219
61750
  }
61220
61751
  case "agents": {
61221
- const result = await ctx.client.repo.setAgents(org, repo, inputContent, {
61752
+ const result = await ctx.client.repo.setAgents(org, repo2, inputContent, {
61222
61753
  eventRequestId
61223
61754
  });
61224
61755
  writeOutput(ctx, result, () => {
61225
- ctx.status(`Content/Agents updated in ${org}/${repo}`);
61756
+ ctx.status(`Content/Agents updated in ${org}/${repo2}`);
61226
61757
  });
61227
61758
  break;
61228
61759
  }
@@ -61236,24 +61767,24 @@ var handleContentPrompt = async (ctx, { args, flags }) => {
61236
61767
  throw new CliError(2 /* UserInput */, "USER_INPUT", `--kind ${kind} is read-only; \`prompt\` is rejected.`, undefined, `Use \`wh repo content get [org/repo] --kind ${kind}\` (or set --repo)`);
61237
61768
  }
61238
61769
  const promptKind = kind;
61239
- const { org, repo } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
61770
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
61240
61771
  const [repoInfo, shapesPage, stats, thingsPage] = await Promise.all([
61241
- ctx.client.repo.get(org, repo),
61242
- ctx.client.shape.list(org, repo),
61243
- ctx.client.repo.getStats(org, repo),
61244
- ctx.client.thing.query(org, repo, { limit: 30 })
61772
+ ctx.client.repo.get(org, repo2),
61773
+ ctx.client.shape.list(org, repo2),
61774
+ ctx.client.repo.getStats(org, repo2),
61775
+ ctx.client.thing.query(org, repo2, { limit: 30 })
61245
61776
  ]);
61246
61777
  const { prompt, saveCommand } = buildContentPrompt({
61247
61778
  kind: promptKind,
61248
61779
  org,
61249
- repo,
61780
+ repo: repo2,
61250
61781
  description: repoInfo.description ?? null,
61251
61782
  byKind: stats.byKind,
61252
61783
  byShape: stats.byShape,
61253
61784
  shapeNames: nameStrings(shapesPage.items),
61254
61785
  sampleThingNames: nameStrings(thingsPage.items)
61255
61786
  });
61256
- writeOutput(ctx, { kind: promptKind, org, repo, prompt, saveCommand }, () => {
61787
+ writeOutput(ctx, { kind: promptKind, org, repo: repo2, prompt, saveCommand }, () => {
61257
61788
  ctx.out(prompt);
61258
61789
  });
61259
61790
  ctx.status(`Next: draft the content, then run:
@@ -61309,7 +61840,7 @@ var CONTENT_SUBDOMAIN = defineDomain({
61309
61840
  });
61310
61841
 
61311
61842
  // ../../packages/warmhub-cli/src/domains/repo/create.ts
61312
- var createFlags6 = {
61843
+ var createFlags7 = {
61313
61844
  "display-name": flag.string({
61314
61845
  description: "Display name for the repo"
61315
61846
  }),
@@ -61322,7 +61853,7 @@ var createFlags6 = {
61322
61853
  description: "Org name (tolerance fallback; prefer the `<org/name>` positional form)"
61323
61854
  })
61324
61855
  };
61325
- var handleCreate5 = async (ctx, { flags, args }) => {
61856
+ var handleCreate6 = async (ctx, { flags, args }) => {
61326
61857
  const ref = args[0];
61327
61858
  const orgFlag = flags.org;
61328
61859
  const resolved = resolveOrgRepoArg(ref, orgFlag);
@@ -61426,7 +61957,7 @@ var repoListFlags = {
61426
61957
  };
61427
61958
  var DEFAULT_REPO_LIST_LIMIT = 50;
61428
61959
  var MAX_REPO_LIST_LIMIT = 200;
61429
- var handleList5 = async (ctx, { flags, args }) => {
61960
+ var handleList6 = async (ctx, { flags, args }) => {
61430
61961
  const orgName = args[0] ?? ctx.config.defaultOrg;
61431
61962
  if (!orgName) {
61432
61963
  usageError("Usage: wh repo list <org> (or set WARMHUB_ORG)", "wh repo list myorg");
@@ -61552,15 +62083,15 @@ var describeFlags = {
61552
62083
  };
61553
62084
  var handleDescribe = async (ctx, { args, flags }) => {
61554
62085
  const repoRef = args[0];
61555
- const { org, repo } = parseOrgRepo(repoRef, ctx.config);
62086
+ const { org, repo: repo2 } = parseOrgRepo(repoRef, ctx.config);
61556
62087
  const c = ctx.colors;
61557
62088
  const showIndexedFields = flags["indexed-fields"] === true;
61558
62089
  const [repoInfo, license, shapesPage, stats, indexedFields] = await Promise.all([
61559
- ctx.client.repo.get(org, repo),
61560
- ctx.client.repo.getLicense(org, repo),
61561
- ctx.client.shape.list(org, repo),
61562
- ctx.client.repo.getStats(org, repo),
61563
- showIndexedFields ? ctx.client.repo.index.describe(org, repo) : null
62090
+ ctx.client.repo.get(org, repo2),
62091
+ ctx.client.repo.getLicense(org, repo2),
62092
+ ctx.client.shape.list(org, repo2),
62093
+ ctx.client.repo.getStats(org, repo2),
62094
+ showIndexedFields ? ctx.client.repo.index.describe(org, repo2) : null
61564
62095
  ]);
61565
62096
  const shapes = shapesPage.items;
61566
62097
  const byShape = Object.fromEntries([
@@ -61578,7 +62109,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
61578
62109
  } : null;
61579
62110
  const payload = {
61580
62111
  org,
61581
- repo,
62112
+ repo: repo2,
61582
62113
  description: repoInfo.description ?? null,
61583
62114
  license,
61584
62115
  counts: {
@@ -61600,7 +62131,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
61600
62131
  ...indexedFieldsPublic ? { indexedFields: indexedFieldsPublic } : {}
61601
62132
  };
61602
62133
  writeOutput(ctx, payload, () => {
61603
- ctx.out(`${c.bold}${org}/${repo}${c.reset}`);
62134
+ ctx.out(`${c.bold}${org}/${repo2}${c.reset}`);
61604
62135
  if (repoInfo.description) {
61605
62136
  ctx.out(` ${escapeTerminalTextForDisplay(repoInfo.description)}`);
61606
62137
  }
@@ -61728,12 +62259,12 @@ var handleRepoSearch = async (ctx, { flags, args }) => {
61728
62259
  // ../../packages/warmhub-cli/src/domains/repo/view.ts
61729
62260
  var handleView6 = async (ctx, { args }) => {
61730
62261
  const repoRef = args[0];
61731
- const { org, repo } = parseOrgRepo(repoRef, ctx.config);
62262
+ const { org, repo: repo2 } = parseOrgRepo(repoRef, ctx.config);
61732
62263
  const c = ctx.colors;
61733
62264
  const [repoInfo, stats, configureStats] = await Promise.all([
61734
- ctx.client.repo.get(org, repo),
61735
- ctx.client.repo.getStats(org, repo),
61736
- ctx.client.repo.getConfigureStats(org, repo).catch((err) => {
62265
+ ctx.client.repo.get(org, repo2),
62266
+ ctx.client.repo.getStats(org, repo2),
62267
+ ctx.client.repo.getConfigureStats(org, repo2).catch((err) => {
61737
62268
  if (err instanceof WarmHubError && (err.kind === "FORBIDDEN" || err.kind === "UNAUTHENTICATED")) {
61738
62269
  return null;
61739
62270
  }
@@ -61741,7 +62272,7 @@ var handleView6 = async (ctx, { args }) => {
61741
62272
  })
61742
62273
  ]);
61743
62274
  writeOutput(ctx, { ...repoInfo, stats, configureStats }, () => {
61744
- ctx.out(`${c.bold}${org}/${repo}${c.reset}`);
62275
+ ctx.out(`${c.bold}${org}/${repo2}${c.reset}`);
61745
62276
  if (repoInfo.displayName && repoInfo.displayName !== repoInfo.name) {
61746
62277
  ctx.out(` ${escapeTerminalTextForDisplay(repoInfo.displayName)}`);
61747
62278
  }
@@ -61763,7 +62294,7 @@ var handleVisibility = async (ctx, { args }) => {
61763
62294
  if (!orgRepo || !newVisibility || !orgRepo.includes("/") || newVisibility !== "public" && newVisibility !== "private") {
61764
62295
  usageError("Usage: wh repo visibility <org/repo> <public|private>", "wh repo visibility myorg/myrepo public");
61765
62296
  }
61766
- const parsed = splitRepoSlug(orgRepo);
62297
+ const parsed = parseRepoSlug(orgRepo);
61767
62298
  if (!parsed) {
61768
62299
  usageError("Usage: wh repo visibility <org/repo> <public|private>", "wh repo visibility myorg/myrepo public");
61769
62300
  }
@@ -61785,14 +62316,14 @@ var REPO_DOMAIN = defineDomain({
61785
62316
  prime: true,
61786
62317
  summary: "Create a new repo",
61787
62318
  args: "<org/name>",
61788
- flags: createFlags6,
62319
+ flags: createFlags7,
61789
62320
  examples: [
61790
62321
  "wh repo create myorg/myrepo",
61791
62322
  'wh repo create myorg/myrepo -d "My repo"',
61792
62323
  'wh repo create myorg/myrepo --display-name "My Repo"',
61793
62324
  'wh repo create myorg/myrepo --visibility private -d "Private repo"'
61794
62325
  ],
61795
- handler: handleCreate5
62326
+ handler: handleCreate6
61796
62327
  },
61797
62328
  list: {
61798
62329
  prime: true,
@@ -61804,7 +62335,7 @@ var REPO_DOMAIN = defineDomain({
61804
62335
  "wh repo list myorg",
61805
62336
  "wh repo list myorg --include-archived"
61806
62337
  ],
61807
- handler: handleList5
62338
+ handler: handleList6
61808
62339
  },
61809
62340
  search: {
61810
62341
  prime: true,
@@ -61931,7 +62462,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
61931
62462
  if (!shapeName) {
61932
62463
  usageError("Usage: wh shape history <name>", "wh shape history Location");
61933
62464
  }
61934
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62465
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
61935
62466
  const limit = flags.limit;
61936
62467
  const cursor = flags.cursor;
61937
62468
  const all = flags.all;
@@ -61947,7 +62478,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
61947
62478
  if (ctx.liveMode) {
61948
62479
  await runLive({
61949
62480
  apiUrl: ctx.config.apiUrl,
61950
- poll: (c) => c.shape.history(org, repo, bareName, {
62481
+ poll: (c) => c.shape.history(org, repo2, bareName, {
61951
62482
  includeRetracted,
61952
62483
  limit: pageLimit,
61953
62484
  cursor
@@ -61962,6 +62493,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
61962
62493
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
61963
62494
  functionLogs: ctx.functionLogMode,
61964
62495
  profile: ctx.profile,
62496
+ clientFlags: ctx.clientFlags,
61965
62497
  signal: ctx.signal
61966
62498
  });
61967
62499
  return;
@@ -61971,7 +62503,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
61971
62503
  let thing;
61972
62504
  let nextCursor;
61973
62505
  do {
61974
- const page = await ctx.client.shape.history(org, repo, bareName, {
62506
+ const page = await ctx.client.shape.history(org, repo2, bareName, {
61975
62507
  includeRetracted,
61976
62508
  limit: pageLimit,
61977
62509
  cursor: next
@@ -61993,7 +62525,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
61993
62525
  };
61994
62526
 
61995
62527
  // ../../packages/warmhub-cli/src/domains/shape/list.ts
61996
- var listFlags4 = {
62528
+ var listFlags5 = {
61997
62529
  match: flag.string({ description: "Filter by name glob pattern" }),
61998
62530
  component: flag.string({
61999
62531
  description: "Filter to shapes owned by this component (Org/Name ref)"
@@ -62005,15 +62537,15 @@ var listFlags4 = {
62005
62537
  description: "Include retracted shapes"
62006
62538
  })
62007
62539
  };
62008
- var handleList6 = async (ctx, { flags }) => {
62009
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62540
+ var handleList7 = async (ctx, { flags }) => {
62541
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62010
62542
  const c = ctx.colors;
62011
62543
  const match = flags.match;
62012
62544
  const componentRef = flags.component;
62013
62545
  const excludeComponents = !!flags["exclude-components"];
62014
62546
  const includeRetracted = flags["include-retracted"];
62015
62547
  validateComponentFilters(componentRef, excludeComponents, "wh shape list --component acme/veritas", "wh shape list --exclude-components");
62016
- const result = await ctx.client.shape.list(org, repo, {
62548
+ const result = await ctx.client.shape.list(org, repo2, {
62017
62549
  match,
62018
62550
  componentRef,
62019
62551
  excludeComponents,
@@ -62025,7 +62557,7 @@ var handleList6 = async (ctx, { flags }) => {
62025
62557
  ctx.status(`${c.dim}No shapes registered${c.reset}`);
62026
62558
  return;
62027
62559
  }
62028
- ctx.out(`${c.bold}Shapes${c.reset} ${c.cyan}${org}/${repo}${c.reset}`);
62560
+ ctx.out(`${c.bold}Shapes${c.reset} ${c.cyan}${org}/${repo2}${c.reset}`);
62029
62561
  for (const item of items) {
62030
62562
  const shape = item;
62031
62563
  const name = shape.name;
@@ -62069,9 +62601,9 @@ var handleView7 = async (ctx, { flags, args }) => {
62069
62601
  if (!shapeName) {
62070
62602
  usageError("Usage: wh shape view <name>", "wh shape view location");
62071
62603
  }
62072
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62604
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62073
62605
  const c = ctx.colors;
62074
- const result = await ctx.client.shape.get(org, repo, shapeName, {
62606
+ const result = await ctx.client.shape.get(org, repo2, shapeName, {
62075
62607
  includeRetracted: flags["include-retracted"]
62076
62608
  });
62077
62609
  writeOutput(ctx, result, () => {
@@ -62108,7 +62640,7 @@ var handleView7 = async (ctx, { flags, args }) => {
62108
62640
  var fieldsFileFlag = flag.string({
62109
62641
  description: "read fields from a JSON object file (portable alternative to inline --fields)"
62110
62642
  });
62111
- var createFlags7 = {
62643
+ var createFlags8 = {
62112
62644
  "event-request-id": operationEventRequestIdFlag,
62113
62645
  fields: flag.string({ description: FIELDS_FLAG_DESCRIPTION }),
62114
62646
  file: fieldsFileFlag,
@@ -62131,9 +62663,8 @@ var renameFlags3 = {
62131
62663
  "event-request-id": operationEventRequestIdFlag
62132
62664
  };
62133
62665
  function shapeChangeFromReceipt(receipt) {
62134
- assertSingleOpSuccess(receipt);
62135
- const entry = receipt.operations[0];
62136
- if (!entry || entry.operation === "rename" || !("version" in entry) || typeof entry.version !== "number" || !("dataHash" in entry) || typeof entry.dataHash !== "string") {
62666
+ const entry = requireSingleOpSuccess(receipt);
62667
+ if (entry.operation === "rename" || !("version" in entry) || typeof entry.version !== "number" || !("dataHash" in entry) || typeof entry.dataHash !== "string") {
62137
62668
  throw new Error("Shape mutation returned no version-bearing operation");
62138
62669
  }
62139
62670
  return {
@@ -62191,7 +62722,7 @@ var retractFlags3 = {
62191
62722
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
62192
62723
  })
62193
62724
  };
62194
- var handleCreate6 = async (ctx, { flags, args }) => {
62725
+ var handleCreate7 = async (ctx, { flags, args }) => {
62195
62726
  const shapeName = args[0];
62196
62727
  if (!shapeName) {
62197
62728
  usageError("Usage: wh shape create <name> (--fields '<json>' | --file <path>)", `wh shape create Location --fields '{"x":"number","y":"number"}'`, "wh shape create Location --file fields.json", `wh shape create Tags --fields '{"labels":["string"],"scores":["number"]}'`, `wh shape create Player --fields '{"name":"string","position":{"x":"number","y":"number"}}'`, `wh shape create Review --fields '{"score":"number","reason?":"string"}'`);
@@ -62203,14 +62734,14 @@ var handleCreate6 = async (ctx, { flags, args }) => {
62203
62734
  missingMessage: "Usage: wh shape create <name> (--fields '<json>' | --file <path>)",
62204
62735
  example: "wh shape create Location --file fields.json"
62205
62736
  });
62206
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62737
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62207
62738
  const c = ctx.colors;
62208
62739
  const eventRequestId = flags["event-request-id"] ?? createOperationEventRequestId();
62209
62740
  ctx.status(`Operation event request: ${eventRequestId}`);
62210
62741
  const opts = { eventRequestId };
62211
62742
  if (flags.description !== undefined)
62212
62743
  opts.description = flags.description;
62213
- const response = await ctx.client.shape.create(org, repo, shapeName, fields, opts);
62744
+ const response = await ctx.client.shape.create(org, repo2, shapeName, fields, opts);
62214
62745
  const result = shapeChangeFromReceipt(response.receipt);
62215
62746
  writeOutput(ctx, response, () => {
62216
62747
  if (result.operation === "noop") {
@@ -62232,9 +62763,9 @@ var handleRevise3 = async (ctx, { flags, args }) => {
62232
62763
  missingMessage: "Usage: wh shape revise <name> (--fields '<json>' | --file <path>)",
62233
62764
  example: "wh shape revise Location --file fields.json"
62234
62765
  });
62235
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62766
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62236
62767
  const c = ctx.colors;
62237
- const previousShape = flags["show-diff"] ? await ctx.client.shape.get(org, repo, shapeName) : undefined;
62768
+ const previousShape = flags["show-diff"] ? await ctx.client.shape.get(org, repo2, shapeName) : undefined;
62238
62769
  const previousVersion = previousShape?.version?.version;
62239
62770
  const previousFields = previousShape ? fieldsFromShapeData(previousShape.version?.data) : undefined;
62240
62771
  const eventRequestId = flags["event-request-id"] ?? createOperationEventRequestId();
@@ -62242,7 +62773,7 @@ var handleRevise3 = async (ctx, { flags, args }) => {
62242
62773
  const opts = { eventRequestId };
62243
62774
  if (flags.description !== undefined)
62244
62775
  opts.description = flags.description;
62245
- const response = await ctx.client.shape.revise(org, repo, shapeName, newFields, opts);
62776
+ const response = await ctx.client.shape.revise(org, repo2, shapeName, newFields, opts);
62246
62777
  const result = shapeChangeFromReceipt(response.receipt);
62247
62778
  let diff;
62248
62779
  if (previousFields) {
@@ -62250,7 +62781,7 @@ var handleRevise3 = async (ctx, { flags, args }) => {
62250
62781
  if (result.operation === "noop") {
62251
62782
  committedBaseFields = newFields;
62252
62783
  } else if (previousVersion !== result.version - 1) {
62253
- const committedBase = await ctx.client.thing.get(org, repo, shapeName, result.version - 1);
62784
+ const committedBase = await ctx.client.thing.get(org, repo2, shapeName, result.version - 1);
62254
62785
  committedBaseFields = fieldsFromShapeData(committedBase.data);
62255
62786
  }
62256
62787
  diff = diffShapeFields(committedBaseFields, newFields);
@@ -62270,10 +62801,10 @@ var handleRetract2 = async (ctx, { flags, args }) => {
62270
62801
  if (!shapeName) {
62271
62802
  usageError("Usage: wh shape retract <name> [--expected-version <n>]", "wh shape retract Location");
62272
62803
  }
62273
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62804
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62274
62805
  const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", "wh shape retract Location --expected-version 3");
62275
62806
  const c = ctx.colors;
62276
- const commitResult = await ctx.client.commit.apply(org, repo, flags.message ?? `retract shape ${shapeName}`, [
62807
+ const commitResult = await ctx.client.commit.apply(org, repo2, flags.message ?? `retract shape ${shapeName}`, [
62277
62808
  {
62278
62809
  operation: "retract",
62279
62810
  kind: "shape",
@@ -62282,10 +62813,7 @@ var handleRetract2 = async (ctx, { flags, args }) => {
62282
62813
  ...expectedVersion !== undefined ? { expectedVersion } : {}
62283
62814
  }
62284
62815
  ], { committer: flags.committer });
62285
- const result = commitResult.operations[0];
62286
- if (!result)
62287
- throw new Error("Commit returned no operation result");
62288
- assertSingleOpSuccess(commitResult);
62816
+ requireSingleOpSuccess(commitResult);
62289
62817
  writeOutput(ctx, commitResult, () => {
62290
62818
  renderCommitterEcho(ctx.out, c, flags.committer);
62291
62819
  ctx.out(`${c.red}Retracted${c.reset} ${c.magenta}${shapeName}${c.reset}`);
@@ -62297,11 +62825,11 @@ var handleShapeRename = async (ctx, { flags, args }) => {
62297
62825
  if (!oldName || !newName) {
62298
62826
  usageError("Usage: wh shape rename <oldName> <newName>", "wh shape rename Location Place");
62299
62827
  }
62300
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62828
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
62301
62829
  const c = ctx.colors;
62302
62830
  const eventRequestId = flags["event-request-id"] ?? createOperationEventRequestId();
62303
62831
  ctx.status(`Operation event request: ${eventRequestId}`);
62304
- const response = await ctx.client.shape.rename(org, repo, oldName, newName, {
62832
+ const response = await ctx.client.shape.rename(org, repo2, oldName, newName, {
62305
62833
  eventRequestId
62306
62834
  });
62307
62835
  writeOutput(ctx, response, () => {
@@ -62319,9 +62847,9 @@ var SHAPE_DOMAIN = defineDomain({
62319
62847
  prime: true,
62320
62848
  summary: "List all shapes",
62321
62849
  args: "",
62322
- flags: listFlags4,
62850
+ flags: listFlags5,
62323
62851
  examples: ["wh shape list", 'wh shape list --match "Game*"'],
62324
- handler: handleList6
62852
+ handler: handleList7
62325
62853
  },
62326
62854
  view: {
62327
62855
  prime: true,
@@ -62348,14 +62876,14 @@ var SHAPE_DOMAIN = defineDomain({
62348
62876
  prime: true,
62349
62877
  summary: "Create a new shape",
62350
62878
  args: "<name>",
62351
- flags: createFlags7,
62879
+ flags: createFlags8,
62352
62880
  examples: [
62353
62881
  `wh shape create GameConfig --repo org/repo --fields '{"x":"number"}'`,
62354
62882
  "wh shape create GameConfig --repo org/repo --file fields.json",
62355
62883
  `wh shape create Player --fields '{"name":{"type":"string","minLength":1,"maxLength":40},"role":{"type":"string","enum":["dm","player"]},"level":{"type":"number","minimum":1,"integer":true},"home":{"type":"wref","shape":"Location"},"tags":{"type":"array","items":"string","minItems":1}}'`
62356
62884
  ],
62357
62885
  notes: [...FIELD_CONSTRAINTS_NOTES],
62358
- handler: handleCreate6
62886
+ handler: handleCreate7
62359
62887
  },
62360
62888
  retract: {
62361
62889
  prime: true,
@@ -62403,7 +62931,7 @@ var SHAPE_DOMAIN = defineDomain({
62403
62931
  var orgScopeFlag = flag.string({
62404
62932
  description: `org slug for org-scoped events (${ORG_SCOPED_EVENT_TYPES.join(", ")}); use instead of --repo`
62405
62933
  });
62406
- var createFlags8 = {
62934
+ var createFlags9 = {
62407
62935
  on: flag.string({
62408
62936
  description: "Shape to subscribe to"
62409
62937
  }),
@@ -62441,27 +62969,27 @@ var createFlags8 = {
62441
62969
  })
62442
62970
  };
62443
62971
  var updateFlags4 = {
62444
- on: createFlags8.on,
62445
- kind: createFlags8.kind,
62446
- filter: createFlags8.filter,
62447
- cronspec: createFlags8.cronspec,
62448
- timezone: createFlags8.timezone,
62972
+ on: createFlags9.on,
62973
+ kind: createFlags9.kind,
62974
+ filter: createFlags9.filter,
62975
+ cronspec: createFlags9.cronspec,
62976
+ timezone: createFlags9.timezone,
62449
62977
  "webhook-url": flag.string({
62450
62978
  description: "Webhook destination URL"
62451
62979
  }),
62452
- url: createFlags8.url,
62453
- "fallback-webhook-url": createFlags8["fallback-webhook-url"],
62980
+ url: createFlags9.url,
62981
+ "fallback-webhook-url": createFlags9["fallback-webhook-url"],
62454
62982
  "clear-fallback-webhook-url": flag.boolean({
62455
62983
  description: "Clear the fallback webhook URL"
62456
62984
  }),
62457
- "allow-trace-reentry": createFlags8["allow-trace-reentry"],
62458
- name: createFlags8.name,
62985
+ "allow-trace-reentry": createFlags9["allow-trace-reentry"],
62986
+ name: createFlags9.name,
62459
62987
  org: orgScopeFlag
62460
62988
  };
62461
62989
  var logFlags = {
62462
62990
  limit: flag.number({ description: "Max deliveries to return" })
62463
62991
  };
62464
- var listFlags5 = {
62992
+ var listFlags6 = {
62465
62993
  limit: flag.number({ description: "Max subscriptions to return" }),
62466
62994
  org: orgScopeFlag
62467
62995
  };
@@ -62532,9 +63060,9 @@ function parseEventType(raw, _usage, example) {
62532
63060
  if (raw === undefined) {
62533
63061
  return COMMIT_EVENT_TYPE;
62534
63062
  }
62535
- if (SUBSCRIBABLE_EVENT_TYPES.includes(raw)) {
62536
- return raw;
62537
- }
63063
+ const parsed = SUBSCRIBABLE_EVENT_TYPES.find((candidate) => candidate === raw);
63064
+ if (parsed)
63065
+ return parsed;
62538
63066
  usageError(`--event must be one of: ${SUBSCRIBABLE_EVENT_TYPES.join(", ")}`, example);
62539
63067
  }
62540
63068
  function buildSubscriptionPatchArgs(flags, usage, example) {
@@ -62594,8 +63122,8 @@ function resolveSubScope(ctx, flags, correctiveExample) {
62594
63122
  if (typeof flags.org === "string" && flags.org) {
62595
63123
  return { orgName: flags.org };
62596
63124
  }
62597
- const { org, repo } = resolveRepoContext(ctx);
62598
- return { orgName: org, repoName: repo };
63125
+ const { org, repo: repo2 } = resolveRepoContext(ctx);
63126
+ return { orgName: org, repoName: repo2 };
62599
63127
  }
62600
63128
  function rejectConflictingSubScope(ctx, flags, correctiveExample) {
62601
63129
  if (flags.org !== undefined && ctx.invocation.flags.repo !== undefined) {
@@ -62607,7 +63135,7 @@ function scopeLabel(scope) {
62607
63135
  }
62608
63136
 
62609
63137
  // ../../packages/warmhub-cli/src/domains/sub/handlers-create.ts
62610
- var handleCreate7 = async (ctx, { flags, args }) => {
63138
+ var handleCreate8 = async (ctx, { flags, args }) => {
62611
63139
  const name = args[0] ?? flags.name;
62612
63140
  const usage = `Usage: wh sub create <name> (--repo org/repo | --org org) [--event ${SUBSCRIBABLE_EVENT_TYPES.join("|")}] [options]`;
62613
63141
  const example = `wh sub create signal-hook --repo myorg/myrepo --on Signal --filter '{"shape":"Signal"}' --webhook-url https://example.com/hook`;
@@ -62651,12 +63179,12 @@ var handleCreate7 = async (ctx, { flags, args }) => {
62651
63179
  if (flags.org !== undefined) {
62652
63180
  usageError(`Flag --org cannot be used with repo-scoped ${eventType} subscriptions`, `wh sub create repo-hook --repo myorg/myrepo --event ${eventType} --webhook-url https://example.com/hook`);
62653
63181
  }
62654
- const { org, repo } = resolveRepoContext(ctx);
63182
+ const { org, repo: repo2 } = resolveRepoContext(ctx);
62655
63183
  if (eventType !== "commit") {
62656
63184
  rejectCommitOnlyFlags(flags, eventType);
62657
63185
  const result2 = await ctx.client.subscription.create({
62658
63186
  orgName: org,
62659
- repoName: repo,
63187
+ repoName: repo2,
62660
63188
  name,
62661
63189
  eventType,
62662
63190
  kind,
@@ -62665,7 +63193,7 @@ var handleCreate7 = async (ctx, { flags, args }) => {
62665
63193
  });
62666
63194
  writeOutput(ctx, result2, () => {
62667
63195
  const c = ctx.colors;
62668
- ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset} (${eventType})`);
63196
+ ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo2}${c.reset} (${eventType})`);
62669
63197
  });
62670
63198
  return;
62671
63199
  }
@@ -62673,7 +63201,7 @@ var handleCreate7 = async (ctx, { flags, args }) => {
62673
63201
  const sourceRepoRef = typeof flags.source === "string" ? flags.source : undefined;
62674
63202
  const result = await ctx.client.subscription.create({
62675
63203
  orgName: org,
62676
- repoName: repo,
63204
+ repoName: repo2,
62677
63205
  name,
62678
63206
  webhookUrl,
62679
63207
  fallbackWebhookUrl: createArgs.fallbackWebhookUrl,
@@ -62685,7 +63213,7 @@ var handleCreate7 = async (ctx, { flags, args }) => {
62685
63213
  });
62686
63214
  writeOutput(ctx, result, () => {
62687
63215
  const c = ctx.colors;
62688
- ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset}`);
63216
+ ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo2}${c.reset}`);
62689
63217
  });
62690
63218
  };
62691
63219
  var handleUpdate4 = async (ctx, { flags, args }) => {
@@ -62861,7 +63389,7 @@ function renderSubscriptionLog(out, statusOut, c, subscriptionName, result) {
62861
63389
  }
62862
63390
 
62863
63391
  // ../../packages/warmhub-cli/src/domains/sub/handlers-management.ts
62864
- var handleList7 = async (ctx, { flags }) => {
63392
+ var handleList8 = async (ctx, { flags }) => {
62865
63393
  const scope = resolveSubScope(ctx, flags, "wh sub list --repo myorg/myrepo");
62866
63394
  const label = scopeLabel(scope);
62867
63395
  const all = await ctx.client.subscription.list(scope);
@@ -62961,11 +63489,11 @@ var handleLog = async (ctx, { flags, args }) => {
62961
63489
  usageError("Usage: wh sub log <name> [--repo org/repo]", "wh sub log my-sub --repo myorg/myrepo");
62962
63490
  }
62963
63491
  const org = scope.orgName;
62964
- const repo = scope.repoName;
63492
+ const repo2 = scope.repoName;
62965
63493
  if (ctx.liveMode) {
62966
63494
  await runLive({
62967
63495
  apiUrl: ctx.config.apiUrl,
62968
- poll: (c) => c.action.liveFeed(org, repo, name, { limit: flags.limit }),
63496
+ poll: (c) => c.action.liveFeed(org, repo2, name, { limit: flags.limit }),
62969
63497
  render: (result2) => renderSubscriptionLog(ctx.out, ctx.status, ctx.colors, name, result2),
62970
63498
  out: ctx.out,
62971
63499
  err: ctx.err,
@@ -62976,11 +63504,12 @@ var handleLog = async (ctx, { flags, args }) => {
62976
63504
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
62977
63505
  functionLogs: ctx.functionLogMode,
62978
63506
  profile: ctx.profile,
63507
+ clientFlags: ctx.clientFlags,
62979
63508
  signal: ctx.signal
62980
63509
  });
62981
63510
  return;
62982
63511
  }
62983
- const result = await ctx.client.action.liveFeed(org, repo, name, {
63512
+ const result = await ctx.client.action.liveFeed(org, repo2, name, {
62984
63513
  limit: flags.limit
62985
63514
  });
62986
63515
  writeOutput(ctx, result, () => renderSubscriptionLog(ctx.out, ctx.status, ctx.colors, name, result));
@@ -62990,8 +63519,8 @@ var handleAttempts = async (ctx, { args }) => {
62990
63519
  if (!runIdArg) {
62991
63520
  usageError("Usage: wh sub attempts <runId> [--repo org/repo]", "wh sub attempts 019d90f0-1111-7000-8000-000000000001 --repo myorg/myrepo");
62992
63521
  }
62993
- const { org, repo } = resolveRepoContext(ctx);
62994
- const result = await ctx.client.action.getRunAttempts(org, repo, runIdArg);
63522
+ const { org, repo: repo2 } = resolveRepoContext(ctx);
63523
+ const result = await ctx.client.action.getRunAttempts(org, repo2, runIdArg);
62995
63524
  writeOutput(ctx, result, () => {
62996
63525
  const c = ctx.colors;
62997
63526
  if (!result.length) {
@@ -63025,7 +63554,7 @@ var SUB_DOMAIN = defineDomain({
63025
63554
  prime: true,
63026
63555
  summary: "Create a subscription",
63027
63556
  args: "<name>",
63028
- flags: createFlags8,
63557
+ flags: createFlags9,
63029
63558
  examples: [
63030
63559
  "# Create a webhook subscription for things of a shape",
63031
63560
  ` $ wh sub create signal-hook --repo myorg/myrepo --on Signal --kind webhook --filter '{"shape":"Signal"}' --webhook-url https://example.com/hook`,
@@ -63051,7 +63580,7 @@ var SUB_DOMAIN = defineDomain({
63051
63580
  ' $ echo "tok_secret" | wh credential set webhook-keys WEBHOOK_BEARER_TOKEN --repo myorg/myrepo',
63052
63581
  " $ wh sub bind signal-hook --credentials webhook-keys --repo myorg/myrepo"
63053
63582
  ],
63054
- handler: handleCreate7
63583
+ handler: handleCreate8
63055
63584
  },
63056
63585
  update: {
63057
63586
  status: "live",
@@ -63086,14 +63615,14 @@ var SUB_DOMAIN = defineDomain({
63086
63615
  prime: true,
63087
63616
  summary: "List all subscriptions",
63088
63617
  args: "",
63089
- flags: listFlags5,
63618
+ flags: listFlags6,
63090
63619
  examples: [
63091
63620
  "wh sub list --repo myorg/myrepo",
63092
63621
  "wh sub list --limit 10",
63093
63622
  "# Org-scoped metadata subscriptions",
63094
63623
  " $ wh sub list --org myorg"
63095
63624
  ],
63096
- handler: handleList7
63625
+ handler: handleList8
63097
63626
  },
63098
63627
  log: {
63099
63628
  status: "live",
@@ -63272,7 +63801,7 @@ function tokenStatus(pat) {
63272
63801
  return "expired";
63273
63802
  return "active";
63274
63803
  }
63275
- var createFlags9 = {
63804
+ var createFlags10 = {
63276
63805
  name: flag.string({ short: "n", description: "Token name" }),
63277
63806
  scope: flag.string({
63278
63807
  short: "s",
@@ -63293,7 +63822,7 @@ var createFlags9 = {
63293
63822
  var nameFlags = {
63294
63823
  name: flag.string({ short: "n", description: "Token name" })
63295
63824
  };
63296
- var listFlags6 = {
63825
+ var listFlags7 = {
63297
63826
  all: flag.boolean({
63298
63827
  short: "a",
63299
63828
  description: "Include expired and revoked tokens (default: active only)"
@@ -63331,7 +63860,7 @@ function formatScopes(scopes) {
63331
63860
  return `${base}${formatAllowedMatches(e.allowedMatches)}`;
63332
63861
  }).join(" ");
63333
63862
  }
63334
- var handleCreate8 = async (ctx, { flags }) => {
63863
+ var handleCreate9 = async (ctx, { flags }) => {
63335
63864
  if (!flags.name) {
63336
63865
  usageError("Usage: wh token create --name <name> [flags]", "wh token create --name ci-bot --scope myorg/myrepo=role:editor --expires 90d");
63337
63866
  }
@@ -63380,7 +63909,7 @@ var handleCreate8 = async (ctx, { flags }) => {
63380
63909
  ctx.status(` expires: ${new Date(result.expiresAt).toISOString().slice(0, 16)}`);
63381
63910
  });
63382
63911
  };
63383
- var handleList8 = async (ctx, { flags }) => {
63912
+ var handleList9 = async (ctx, { flags }) => {
63384
63913
  const c = ctx.colors;
63385
63914
  const items = await ctx.client.token.list({ includeInactive: flags.all });
63386
63915
  writePageOutput(ctx, items, { limit: items.length, nextCursor: null }, () => {
@@ -63400,7 +63929,7 @@ var handleList8 = async (ctx, { flags }) => {
63400
63929
  }
63401
63930
  });
63402
63931
  };
63403
- var handleGet = async (ctx, { flags }) => {
63932
+ var handleGet2 = async (ctx, { flags }) => {
63404
63933
  if (!flags.name) {
63405
63934
  usageError("Usage: wh token get --name <name>", "wh token get --name ci-bot");
63406
63935
  }
@@ -63424,7 +63953,7 @@ var handleGet = async (ctx, { flags }) => {
63424
63953
  }
63425
63954
  });
63426
63955
  };
63427
- var handleRevoke2 = async (ctx, { flags }) => {
63956
+ var handleRevoke3 = async (ctx, { flags }) => {
63428
63957
  if (!flags.name) {
63429
63958
  usageError("Usage: wh token revoke --name <name>", "wh token revoke --name ci-bot");
63430
63959
  }
@@ -63442,7 +63971,7 @@ var TOKEN_DOMAIN = defineDomain({
63442
63971
  create: {
63443
63972
  summary: "Create a new personal access token",
63444
63973
  args: "",
63445
- flags: createFlags9,
63974
+ flags: createFlags10,
63446
63975
  examples: [
63447
63976
  "wh token create --name ci-bot --scope myorg/myrepo=repo:read,repo:write",
63448
63977
  "wh token create --name ci-bot --scope myorg/myrepo=role:editor",
@@ -63451,32 +63980,32 @@ var TOKEN_DOMAIN = defineDomain({
63451
63980
  `wh token create --name scoped --scopes-json '[{"resource":"myorg/myrepo","permissions":["repo:read"],"allowedMatches":["Signal/*"]}]'`,
63452
63981
  `wh token create --name global-reader --scopes-json '[{"permissions":["repo:read"]}]'`
63453
63982
  ],
63454
- handler: handleCreate8
63983
+ handler: handleCreate9
63455
63984
  },
63456
63985
  list: {
63457
63986
  summary: "List your personal access tokens (active by default)",
63458
63987
  args: "",
63459
- flags: listFlags6,
63988
+ flags: listFlags7,
63460
63989
  examples: [
63461
63990
  "wh token list",
63462
63991
  "wh token list --all",
63463
63992
  "wh token list --json"
63464
63993
  ],
63465
- handler: handleList8
63994
+ handler: handleList9
63466
63995
  },
63467
63996
  get: {
63468
63997
  summary: "View a token by name",
63469
63998
  args: "",
63470
63999
  flags: nameFlags,
63471
64000
  examples: ["wh token get --name ci-bot"],
63472
- handler: handleGet
64001
+ handler: handleGet2
63473
64002
  },
63474
64003
  revoke: {
63475
64004
  summary: "Revoke a token by name",
63476
64005
  args: "",
63477
64006
  flags: nameFlags,
63478
64007
  examples: ["wh token revoke --name ci-bot"],
63479
- handler: handleRevoke2
64008
+ handler: handleRevoke3
63480
64009
  }
63481
64010
  }
63482
64011
  });
@@ -64102,14 +64631,14 @@ var handleUse = async (ctx, { args, flags }) => {
64102
64631
  });
64103
64632
  return;
64104
64633
  }
64105
- const parts = repoArg.split("/");
64106
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
64634
+ const parsed = parseRepoSlug(repoArg);
64635
+ if (!parsed) {
64107
64636
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid repo format "${repoArg}". Expected "org/repo" (exactly one slash).`, undefined, "Example: wh use myorg/myrepo");
64108
64637
  }
64109
- const [org, repo] = parts;
64638
+ const { org, repo: repo2 } = parsed;
64110
64639
  const repoNotFoundMessage = `Repo "${repoArg}" not found`;
64111
64640
  try {
64112
- await ctx.client.repo.get(org, repo);
64641
+ await ctx.client.repo.get(org, repo2);
64113
64642
  } catch (e) {
64114
64643
  if (!(e instanceof WarmHubError) || e.kind !== "NOT_FOUND" || e.errorCode !== "NOT_FOUND" || e.message !== repoNotFoundMessage) {
64115
64644
  throw e;
@@ -64144,6 +64673,69 @@ var USE_DOMAIN = defineDomain({
64144
64673
  handler: handleUse
64145
64674
  });
64146
64675
 
64676
+ // ../../packages/warmhub-cli/src/domains/view.ts
64677
+ var evaluateFlags = {
64678
+ limit: flag.number({
64679
+ description: "Max results per page (default: 50, max: 500)"
64680
+ }),
64681
+ cursor: flag.string({ description: "Opaque pagination cursor" }),
64682
+ all: flag.boolean({ description: "Fetch all pages" })
64683
+ };
64684
+ var handleEvaluate = async (ctx, { args, flags }) => {
64685
+ const wref = args[0]?.trim();
64686
+ if (!wref) {
64687
+ usageError("Usage: wh view evaluate <wref> [--limit N] [--cursor TOKEN] [--all]", "wh view evaluate View/active-users --limit 50");
64688
+ }
64689
+ if (flags.cursor && !flags.limit) {
64690
+ usageError("Usage: wh view evaluate <wref> --limit N --cursor TOKEN", "wh view evaluate View/active-users --limit 50 --cursor <token>");
64691
+ }
64692
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
64693
+ const boundedLimit = Math.min(flags.limit ?? DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT);
64694
+ const pageLimit = flags.all ? Math.min(flags.limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedLimit;
64695
+ if (flags.all) {
64696
+ const items = await ctx.client.view.evaluateAll(org, repo2, wref, {
64697
+ limit: pageLimit,
64698
+ cursor: flags.cursor
64699
+ });
64700
+ writePageOutput(ctx, items, { limit: pageLimit, nextCursor: null }, () => {
64701
+ ctx.out(`${ctx.colors.bold}View ${escapeTerminalTextForDisplay(wref)}${ctx.colors.reset}`);
64702
+ renderQueryResults(ctx.out, ctx.colors, { items });
64703
+ });
64704
+ return;
64705
+ }
64706
+ const result = await ctx.client.view.evaluate(org, repo2, wref, {
64707
+ limit: boundedLimit,
64708
+ cursor: flags.cursor
64709
+ });
64710
+ if (result.nextCursor) {
64711
+ emitPartialPageHint(ctx, result.items.length, result.nextCursor, boundedLimit);
64712
+ }
64713
+ writePageOutput(ctx, result.items, { limit: boundedLimit, nextCursor: result.nextCursor ?? null }, () => {
64714
+ const selected = `${result.view.wref}@v${result.view.version}`;
64715
+ ctx.out(`${ctx.colors.bold}View ${escapeTerminalTextForDisplay(selected)}${ctx.colors.reset}`);
64716
+ renderQueryResults(ctx.out, ctx.colors, result);
64717
+ });
64718
+ };
64719
+ var VIEW_DOMAIN = defineDomain({
64720
+ name: "view",
64721
+ summary: "Stored View operations",
64722
+ group: "resource",
64723
+ verbs: {
64724
+ evaluate: {
64725
+ prime: true,
64726
+ summary: "Evaluate a stored View against live repository results",
64727
+ args: "<wref>",
64728
+ flags: evaluateFlags,
64729
+ examples: [
64730
+ "wh view evaluate View/active-users",
64731
+ "wh view evaluate View/active-users@v3 --limit 50",
64732
+ "wh view evaluate View/active-users --all"
64733
+ ],
64734
+ handler: handleEvaluate
64735
+ }
64736
+ }
64737
+ });
64738
+
64147
64739
  // ../../packages/warmhub-cli/src/domains/index.ts
64148
64740
  function registerAllDomains(registry3) {
64149
64741
  registry3.register(AUTH_DOMAIN);
@@ -64166,6 +64758,8 @@ function registerAllDomains(registry3) {
64166
64758
  registry3.register(TOKEN_DOMAIN);
64167
64759
  registry3.register(COMPONENT_DOMAIN);
64168
64760
  registry3.register(USE_DOMAIN);
64761
+ registry3.register(VIEW_DOMAIN);
64762
+ registry3.register(GRANT_DOMAIN);
64169
64763
  }
64170
64764
 
64171
64765
  // ../../packages/warmhub-cli/src/production-domain-registry.ts
@@ -64365,8 +64959,8 @@ async function printRootHelp(ctx) {
64365
64959
  }
64366
64960
  let repoSlug;
64367
64961
  try {
64368
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
64369
- repoSlug = `${org}/${repo}`;
64962
+ const { org, repo: repo2 } = parseOrgRepo(getRepoRef(ctx), ctx.config);
64963
+ repoSlug = `${org}/${repo2}`;
64370
64964
  } catch {
64371
64965
  repoSlug = undefined;
64372
64966
  }
@@ -65403,60 +65997,6 @@ var catalog = {
65403
65997
  function prepareCliInvocation(argv) {
65404
65998
  return prepare(argv, resolver, catalog);
65405
65999
  }
65406
- // ../../packages/warmhub-cli/src/cli-context.ts
65407
- function resolveCliContext(args) {
65408
- const { invocation, format } = args;
65409
- const config2 = args.config ?? loadConfig();
65410
- const apiUrlFlag = invocation.flags["api-url"];
65411
- const explicitApiUrl = typeof apiUrlFlag === "string" ? apiUrlFlag : undefined;
65412
- const profileFlag = invocation.flags.profile;
65413
- const apiUrl = explicitApiUrl ?? process.env.WARMHUB_API_URL ?? config2.apiUrl;
65414
- config2.apiUrl = apiUrl;
65415
- const explicitProfile = (typeof profileFlag === "string" ? profileFlag : undefined) ?? config2.profile;
65416
- const effectiveProfile = explicitProfile ?? "default";
65417
- const overridesBypassProfile = !explicitProfile && !!process.env.WH_TOKEN && (!!process.env.WARMHUB_API_URL || !!explicitApiUrl);
65418
- let profileData = null;
65419
- if (!overridesBypassProfile) {
65420
- try {
65421
- profileData = getProfile(effectiveProfile);
65422
- } catch (err) {
65423
- if (explicitProfile)
65424
- throw err;
65425
- const reason = err instanceof Error ? err.message : String(err);
65426
- if (format === "json" || format === "jsonl") {
65427
- process.stderr.write(`${JSON.stringify({
65428
- level: "warning",
65429
- kind: "auth-file-unreadable",
65430
- message: `could not read auth.json: ${reason}`
65431
- })}
65432
- `);
65433
- } else {
65434
- process.stderr.write(`warning: could not read auth.json (${reason})
65435
- `);
65436
- }
65437
- }
65438
- }
65439
- if (profileData) {
65440
- if (profileData.apiUrl && !explicitApiUrl) {
65441
- config2.apiUrl = profileData.apiUrl;
65442
- }
65443
- } else if (explicitProfile) {
65444
- const isAuthLogin = invocation.kind === "static" && invocation.commandPath[0] === "auth" && invocation.commandPath[1] === "login";
65445
- if (!isAuthLogin) {
65446
- const available = listProfiles();
65447
- const availableHint = available.length > 0 ? `Available profiles: ${available.join(", ")}.` : "No profiles found.";
65448
- throw new CliError(5 /* Auth */, "AUTH", `Auth profile "${explicitProfile}" does not exist.`, undefined, `${availableHint}
65449
- Run \`wh auth login --profile ${explicitProfile}\` to create it.`);
65450
- }
65451
- }
65452
- const client = args.client ?? createClient(config2, {
65453
- functionLogs: args.functionLogs,
65454
- profile: effectiveProfile,
65455
- signal: args.signal
65456
- });
65457
- return { config: config2, profile: effectiveProfile, client };
65458
- }
65459
-
65460
66000
  // ../../packages/warmhub-cli/src/confirm-prompt.ts
65461
66001
  function confirmPrompt(message, opts = {}) {
65462
66002
  const input = opts.input ?? process.stdin;
@@ -65504,8 +66044,8 @@ function selectedRepo(flags, config2) {
65504
66044
  }
65505
66045
  }
65506
66046
  try {
65507
- const { org, repo } = parseOrgRepo(repoRef, config2);
65508
- return `${org}/${repo}`;
66047
+ const { org, repo: repo2 } = parseOrgRepo(repoRef, config2);
66048
+ return `${org}/${repo2}`;
65509
66049
  } catch {
65510
66050
  return;
65511
66051
  }
@@ -65703,10 +66243,11 @@ async function runPreparedCli(rawArgv, prepared, opts) {
65703
66243
  requestedMode: requestedFunctionLogs
65704
66244
  });
65705
66245
  const localOnlyCommand = isLocalOnlyInvocation(invocation);
65706
- const { config: config2, client, profile } = localOnlyCommand ? {
66246
+ const { config: config2, client, profile, clientFlags } = localOnlyCommand ? {
65707
66247
  config: loadConfig(),
65708
66248
  client: createLocalOnlyClient(),
65709
- profile: "default"
66249
+ profile: "default",
66250
+ clientFlags: []
65710
66251
  } : resolveCliContext({
65711
66252
  invocation,
65712
66253
  format,
@@ -65726,6 +66267,7 @@ async function runPreparedCli(rawArgv, prepared, opts) {
65726
66267
  config: config2,
65727
66268
  invocation,
65728
66269
  profile,
66270
+ clientFlags,
65729
66271
  colors,
65730
66272
  chars,
65731
66273
  format,
@@ -65843,7 +66385,7 @@ function resolveLogLevel(flagLevel, env) {
65843
66385
  // package.json
65844
66386
  var package_default3 = {
65845
66387
  name: "@warmhub/cli",
65846
- version: "0.88.0",
66388
+ version: "0.90.0",
65847
66389
  private: false,
65848
66390
  type: "module",
65849
66391
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -65987,9 +66529,9 @@ async function performRegisteredInstall(args) {
65987
66529
  }
65988
66530
  function mapInstallError(error51, componentRef, verb) {
65989
66531
  if (isMissingRegistrationError(error51)) {
65990
- const [ownerOrg, name] = componentRef.split("/");
66532
+ const parsed = parseComponentRef(componentRef);
65991
66533
  const backendCode = warmHubErrorBackendCode(error51);
65992
- return new CliError(2 /* UserInput */, "USER_INPUT", `No component registered as ${componentRef}`, undefined, `Register it first with 'wh component register ${name ?? componentRef} --org ${ownerOrg ?? "<org>"} --manifest <path>'.`, undefined, backendCode ?? "NOT_FOUND");
66534
+ return new CliError(2 /* UserInput */, "USER_INPUT", `No component registered as ${componentRef}`, undefined, `Register it first with 'wh component register ${parsed?.name ?? componentRef} --org ${parsed?.org ?? "<org>"} --manifest <path>'.`, undefined, backendCode ?? "NOT_FOUND");
65993
66535
  }
65994
66536
  if (isMissingManifestPermissionError(error51)) {
65995
66537
  const backendCode = warmHubErrorBackendCode(error51) ?? warmHubErrorKind(error51);
@@ -66462,5 +67004,5 @@ process.exitCode = interceptedExitCode === undefined ? await runPreparedCli(laun
66462
67004
  version: package_default3.version
66463
67005
  }) : interceptedExitCode;
66464
67006
 
66465
- //# debugId=964BFCCE631EA49D64756E2164756E21
66466
- //# warmhub-cli-build-info {"cliVersion":"0.88.0","sdkVersion":"0.86.0"}
67007
+ //# debugId=0BE58A01FF9B9E5664756E2164756E21
67008
+ //# warmhub-cli-build-info {"cliVersion":"0.90.0","sdkVersion":"0.88.0"}