@warmhub/cli 0.89.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 (2) hide show
  1. package/dist/wh.js +221 -36
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -42940,8 +42940,8 @@ function normalizeOptionalName(value) {
42940
42940
 
42941
42941
  // ../../packages/sdk-ts/src/operation-normalize.ts
42942
42942
  function toBackendStreamOperation(operation) {
42943
- if (operation.expectedVersion !== undefined && operation.operation !== "revise" && operation.operation !== "retract") {
42944
- 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");
42945
42945
  }
42946
42946
  if (operation.operation === "retract") {
42947
42947
  return {
@@ -42953,6 +42953,17 @@ function toBackendStreamOperation(operation) {
42953
42953
  ...operation.leaseId ? { leaseId: operation.leaseId } : {}
42954
42954
  };
42955
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
+ }
42956
42967
  if (operation.operation === "rename") {
42957
42968
  return {
42958
42969
  operation: "rename",
@@ -42970,6 +42981,9 @@ function toBackendStreamOperation(operation) {
42970
42981
  if (Object.hasOwn(operation, "active")) {
42971
42982
  throw new Error(`${kind2} revise operation no longer supports 'active' — use retract('${name}') instead`);
42972
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
+ }
42973
42987
  if (kind2 === "collection") {
42974
42988
  return normalizeBackendCollectionRevise(operation, "commit.apply");
42975
42989
  }
@@ -42982,6 +42996,7 @@ function toBackendStreamOperation(operation) {
42982
42996
  kind: "assertion",
42983
42997
  name,
42984
42998
  data: operation.data,
42999
+ ...operation.affirmedTargets ? { affirmedTargets: operation.affirmedTargets } : {},
42985
43000
  ...operation.expectedVersion !== undefined ? { expectedVersion: operation.expectedVersion } : {},
42986
43001
  ...operation.leaseId ? { leaseId: operation.leaseId } : {}
42987
43002
  };
@@ -43000,6 +43015,9 @@ function toBackendStreamOperation(operation) {
43000
43015
  if (kind !== "collection" && (("type" in operation) && operation.type !== undefined || ("members" in operation) && operation.members !== undefined)) {
43001
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'`);
43002
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
+ }
43003
43021
  if (kind === "collection") {
43004
43022
  return normalizeBackendCollectionAdd({ ...operation, skipExisting }, "commit.apply");
43005
43023
  }
@@ -43022,6 +43040,7 @@ function toBackendStreamOperation(operation) {
43022
43040
  name: operation.name,
43023
43041
  about: operation.about,
43024
43042
  data: operation.data,
43043
+ ...operation.affirmedTargets ? { affirmedTargets: operation.affirmedTargets } : {},
43025
43044
  ...skipExisting === true ? { skipExisting } : {}
43026
43045
  };
43027
43046
  }
@@ -43406,11 +43425,12 @@ function aggregateSubmittedStreamResult(input) {
43406
43425
  operations: input.results.map((result) => ({
43407
43426
  ...result.opIndex !== undefined ? { opIndex: result.opIndex } : {},
43408
43427
  name: result.name ?? "",
43409
- 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",
43410
43429
  dataHash: result.dataHash ?? "",
43411
43430
  version: result.version ?? 0,
43412
43431
  status: streamAppendResultStatus(result),
43413
43432
  error: result.error,
43433
+ ...result.affirmations ? { affirmations: result.affirmations } : {},
43414
43434
  ...result.status === "failed" && result.opIndex !== undefined && input.operations[result.opIndex]?.name !== undefined ? { submittedName: input.operations[result.opIndex]?.name } : {},
43415
43435
  ...result.resolvedName !== undefined ? { resolvedName: result.resolvedName } : {},
43416
43436
  ...result.retryable !== undefined ? { retryable: result.retryable } : {},
@@ -43425,7 +43445,7 @@ function completedOperationsFrom(result) {
43425
43445
  // ../../packages/sdk-ts/package.json
43426
43446
  var package_default = {
43427
43447
  name: "@warmhub/sdk-ts",
43428
- version: "0.87.0",
43448
+ version: "0.88.0",
43429
43449
  private: false,
43430
43450
  type: "module",
43431
43451
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -45571,6 +45591,7 @@ class WarmHubClient {
45571
45591
  repoName,
45572
45592
  shape: opts?.shape,
45573
45593
  about: opts?.about,
45594
+ affirmedAbout: opts?.affirmedAbout,
45574
45595
  kind: narrowKind(opts?.kind),
45575
45596
  match: opts?.match,
45576
45597
  includeRetracted: opts?.includeRetracted,
@@ -49968,6 +49989,9 @@ function pinnedWref(c, wref, version2) {
49968
49989
  const base = wref.replace(/@v\d+$/, "");
49969
49990
  return `${c.cyan}${escapeTerminalTextForDisplay(base)}@v${version2}${c.reset}`;
49970
49991
  }
49992
+ function formatAffirmedWrefs(c, wrefs) {
49993
+ return wrefs.map((wref) => pinnedWref(c, wref)).join(`${c.dim},${c.reset} `);
49994
+ }
49971
49995
  function kindLabel(c, kind) {
49972
49996
  return `${c.dim}${kind}${c.reset}`;
49973
49997
  }
@@ -50201,6 +50225,9 @@ function renderAbout(out, c, result) {
50201
50225
  const a = item;
50202
50226
  const wref = a.wref ?? a.name;
50203
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
+ }
50204
50231
  if (a.data && typeof a.data === "object") {
50205
50232
  out(` ${c.dim}data:${c.reset}`);
50206
50233
  const lines = JSON.stringify(a.data, null, 2).split(`
@@ -50284,6 +50311,10 @@ var createFlags = {
50284
50311
  shape: flag.string({ description: "Shape for assertion (required)" }),
50285
50312
  data: flag.string({ description: "Data payload (JSON)" }),
50286
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
+ }),
50287
50318
  message: flag.string({ short: "m", description: "Commit message" }),
50288
50319
  committer: flag.string({
50289
50320
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -50291,6 +50322,27 @@ var createFlags = {
50291
50322
  };
50292
50323
  var reviseFlags = {
50293
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
+ }),
50294
50346
  message: flag.string({ short: "m", description: "Commit message" }),
50295
50347
  committer: flag.string({
50296
50348
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -50322,7 +50374,8 @@ var handleRevise = async (ctx, { flags, args }) => {
50322
50374
  operation: "revise",
50323
50375
  kind: "assertion",
50324
50376
  name,
50325
- data
50377
+ data,
50378
+ ...flags.affirm && flags.affirm.length > 0 ? { affirmedTargets: flags.affirm } : {}
50326
50379
  }
50327
50380
  ], { committer: flags.committer });
50328
50381
  const result = requireSingleOpSuccess(commitResult);
@@ -50356,6 +50409,47 @@ var handleRetract = async (ctx, { flags, args }) => {
50356
50409
  ctx.out(`${ctx.colors.red}-${ctx.colors.reset} ${displayName(ctx.colors, result.name)}`);
50357
50410
  });
50358
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
+ }
50451
+ });
50452
+ };
50359
50453
  var handleCreate = async (ctx, { flags, args }) => {
50360
50454
  const { org, repo } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
50361
50455
  const shape = flags.shape;
@@ -50370,13 +50464,15 @@ var handleCreate = async (ctx, { flags, args }) => {
50370
50464
  }
50371
50465
  const about = parseAbout(aboutRaw);
50372
50466
  const localName = `${shape}/${name}`;
50467
+ const affirmedTargets = flags.affirm ?? [];
50373
50468
  const operations = [
50374
50469
  {
50375
50470
  operation: "add",
50376
50471
  kind: "assertion",
50377
50472
  name: localName,
50378
50473
  about,
50379
- data
50474
+ data,
50475
+ ...affirmedTargets.length > 0 ? { affirmedTargets } : {}
50380
50476
  }
50381
50477
  ];
50382
50478
  const commitResult = await ctx.client.commit.apply(org, repo, message ?? `assert ${shape}`, operations, { committer });
@@ -50891,6 +50987,9 @@ function renderHead(out, c, chars, result, org, repo, shape, kind) {
50891
50987
  if (item.kind === "assertion" && item.aboutWref) {
50892
50988
  out(` ${c.dim}about:${c.reset} ${pinnedWref(c, item.aboutWref)}`);
50893
50989
  }
50990
+ if (item.affirmedWrefs?.length) {
50991
+ out(` ${c.dim}affirms:${c.reset} ${formatAffirmedWrefs(c, item.affirmedWrefs)}`);
50992
+ }
50894
50993
  const fields = shapeName && (item.kind === "thing" || item.kind === "collection") && item.data ? collectionFields(shapeName, item.data) : null;
50895
50994
  if (fields) {
50896
50995
  const allWrefs = fields.flatMap((f) => f.wrefs);
@@ -50923,6 +51022,9 @@ function renderThing(out, c, result) {
50923
51022
  if (aboutWref) {
50924
51023
  out(` ${c.dim}about:${c.reset} ${escapeTerminalTextForDisplay(String(aboutWref))}`);
50925
51024
  }
51025
+ if (result.affirmedWrefs?.length) {
51026
+ out(` ${c.dim}affirms:${c.reset} ${formatAffirmedWrefs(c, result.affirmedWrefs)}`);
51027
+ }
50926
51028
  const meta3 = result.metadata;
50927
51029
  if (meta3?.durableId || meta3?.createdOn || meta3?.revisedOn) {
50928
51030
  const now = Date.now();
@@ -51057,6 +51159,8 @@ function renderHistory(out, c, result) {
51057
51159
  } else if (ver.operation === "retract") {
51058
51160
  const reason = ver.retractReason ? ` ${c.dim}'${escapeTerminalTextForDisplay(ver.retractReason.length > 80 ? `${ver.retractReason.slice(0, 77)}...` : ver.retractReason)}'${c.reset}` : "";
51059
51161
  op = `${c.red}retract${c.reset}${reason}`;
51162
+ } else if (ver.operation === "reaffirm") {
51163
+ op = `${c.cyan}reaffirm${c.reset}`;
51060
51164
  } else {
51061
51165
  op = `${c.yellow}revise${c.reset}`;
51062
51166
  }
@@ -51067,6 +51171,10 @@ function renderHistory(out, c, result) {
51067
51171
  const createdOn = ver.metadata?.createdOn;
51068
51172
  const thingCreatedStr = createdOn ? ` ${c.dim}born:${formatTime(createdOn, now)}${c.reset}` : "";
51069
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
+ }
51070
51178
  }
51071
51179
  }
51072
51180
  function renderRefs(out, c, result, wref, direction) {
@@ -51592,6 +51700,9 @@ var queryFlags = {
51592
51700
  shape: flag.string({ description: "Filter by shape" }),
51593
51701
  kind: flag.string({ description: "Filter by kind" }),
51594
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
+ }),
51595
51706
  limit: flag.number({
51596
51707
  description: "Max results per page (default: 50, max: 500)"
51597
51708
  }),
@@ -51626,6 +51737,7 @@ var handleQuery = async (ctx, { flags }) => {
51626
51737
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
51627
51738
  const shape = flags.shape;
51628
51739
  const about = flags.about;
51740
+ const affirmedAbout = flags["affirmed-about"];
51629
51741
  const kind = validateKind(flags.kind);
51630
51742
  const limit = flags.limit;
51631
51743
  const cursor = flags.cursor;
@@ -51648,6 +51760,9 @@ var handleQuery = async (ctx, { flags }) => {
51648
51760
  if (ctx.liveMode && sinceRepoSeq !== undefined) {
51649
51761
  usageError("--since-repo-seq cannot be used with --live.", "wh thing query --since-repo-seq 42 --all --format json");
51650
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
+ }
51651
51766
  if (count) {
51652
51767
  if (cursor || all || limit || ctx.liveMode || role) {
51653
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");
@@ -51680,6 +51795,7 @@ var handleQuery = async (ctx, { flags }) => {
51680
51795
  const queryOpts = {
51681
51796
  shape,
51682
51797
  about,
51798
+ affirmedAbout,
51683
51799
  kind,
51684
51800
  match,
51685
51801
  includeRetracted,
@@ -51718,6 +51834,7 @@ var handleQuery = async (ctx, { flags }) => {
51718
51834
  const result = all ? await fetchAllQueryPages(ctx, org, repo, {
51719
51835
  shape,
51720
51836
  about,
51837
+ affirmedAbout,
51721
51838
  kind,
51722
51839
  match,
51723
51840
  includeRetracted,
@@ -51736,6 +51853,7 @@ var handleQuery = async (ctx, { flags }) => {
51736
51853
  } : undefined) : await ctx.client.thing.query(org, repo, {
51737
51854
  shape,
51738
51855
  about,
51856
+ affirmedAbout,
51739
51857
  kind,
51740
51858
  match,
51741
51859
  includeRetracted,
@@ -51767,6 +51885,7 @@ async function fetchAllQueryPages(ctx, org, repo, opts, onPage) {
51767
51885
  fetchPage: (cursor) => ctx.client.thing.query(org, repo, {
51768
51886
  shape: opts.shape,
51769
51887
  about: opts.about,
51888
+ affirmedAbout: opts.affirmedAbout,
51770
51889
  kind: opts.kind,
51771
51890
  match: opts.match,
51772
51891
  includeRetracted: opts.includeRetracted,
@@ -53007,6 +53126,17 @@ var ASSERTION_DOMAIN = defineDomain({
53007
53126
  ],
53008
53127
  handler: handleRevise
53009
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
+ },
53010
53140
  retract: {
53011
53141
  prime: true,
53012
53142
  summary: "Retract an assertion",
@@ -54740,7 +54870,7 @@ function renderPrettyReceipt(ctx, receipt, committer) {
54740
54870
  const record2 = operation;
54741
54871
  const operationKind = String(record2.operation ?? "operation");
54742
54872
  const failed = isFailedOpStatus(record2.status);
54743
- const marker = failed ? "!" : operationKind === "add" ? "+" : operationKind === "revise" ? "~" : "-";
54873
+ const marker = failed ? "!" : operationKind === "add" ? "+" : operationKind === "revise" ? "~" : operationKind === "reaffirm" ? "±" : "-";
54744
54874
  const error51 = typeof record2.error === "object" && record2.error !== null ? record2.error : undefined;
54745
54875
  const errorSummary = failed ? ` ${error51?.message ?? error51?.code ?? "failed"}` : "";
54746
54876
  ctx.out(` ${marker} ${displayName(c, String(record2.name ?? record2.resolvedName ?? "(unnamed)"))}${errorSummary}`);
@@ -54842,6 +54972,10 @@ var createFlags3 = {
54842
54972
  description: "Target shape or shaped thing for assertions. Repeatable; one per --add, or a single value broadcast to all.",
54843
54973
  multiple: true
54844
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
+ }),
54845
54979
  reason: flag.string({
54846
54980
  description: "Reason for retraction. Repeatable; one per --retract, or a single value broadcast to all.",
54847
54981
  multiple: true
@@ -55042,18 +55176,21 @@ var handleTemplate = async (ctx, { flags, args }) => {
55042
55176
  }
55043
55177
  const data = buildTemplateData(fields);
55044
55178
  const nameSuffix = count > 1 ? (i) => `my-${shapeName.toLowerCase()}-${i + 1}` : () => `my-${shapeName.toLowerCase()}`;
55179
+ const affirmedTargetsPlaceholder = templateKind === "assertion" ? { affirmedTargets: [] } : {};
55045
55180
  for (let i = 0;i < count; i++) {
55046
55181
  const op = operationType === "add" ? {
55047
55182
  operation: "add",
55048
55183
  kind: templateKind,
55049
55184
  name: `${shapeName}/${nameSuffix(i)}`,
55050
55185
  ...aboutPlaceholder ? { about: aboutPlaceholder } : {},
55051
- data
55186
+ data,
55187
+ ...affirmedTargetsPlaceholder
55052
55188
  } : {
55053
55189
  operation: "revise",
55054
55190
  kind: templateKind,
55055
55191
  name: `${shapeName}/FILL_IN`,
55056
- data
55192
+ data,
55193
+ ...affirmedTargetsPlaceholder
55057
55194
  };
55058
55195
  operations.push(op);
55059
55196
  }
@@ -55078,7 +55215,7 @@ var handleTemplate = async (ctx, { flags, args }) => {
55078
55215
  // ../../packages/warmhub-cli/src/domains/commit-submit-ops.ts
55079
55216
  var SHORT_FORM_MAX_ADDS = 20;
55080
55217
  function buildAddOperations(input) {
55081
- const { addNames, dataJsons, shapes, abouts, kinds } = input;
55218
+ const { addNames, dataJsons, shapes, abouts, affirms, kinds } = input;
55082
55219
  if (addNames.length > SHORT_FORM_MAX_ADDS) {
55083
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.");
55084
55221
  }
@@ -55096,6 +55233,9 @@ function buildAddOperations(input) {
55096
55233
  assertCardinality("--shape", shapes, { allowBroadcast: true });
55097
55234
  assertCardinality("--about", abouts, { allowBroadcast: true });
55098
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
+ }
55099
55239
  const pick2 = (values, i, { allowBroadcast }) => {
55100
55240
  if (values.length === 0)
55101
55241
  return;
@@ -55116,7 +55256,17 @@ function buildAddOperations(input) {
55116
55256
  }
55117
55257
  const localName = shape ? `${shape}/${addName}` : addName;
55118
55258
  const kind = kindFlag ?? (about ? "assertion" : "thing");
55119
- 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
+ };
55120
55270
  });
55121
55271
  }
55122
55272
  function buildRetractOperations(input) {
@@ -55171,6 +55321,8 @@ function synthesizeCommitMessage(operations) {
55171
55321
  if (operations.length > 1)
55172
55322
  return `batch: ${operations.length} operations`;
55173
55323
  const op = operations[0];
55324
+ if (!op)
55325
+ return;
55174
55326
  const name = op.name ?? "";
55175
55327
  if (op.operation === "revise") {
55176
55328
  return name ? `revise ${name}` : "revise";
@@ -55180,6 +55332,9 @@ function synthesizeCommitMessage(operations) {
55180
55332
  return `retract shape ${name}`;
55181
55333
  return name ? `retract ${name}` : "retract";
55182
55334
  }
55335
+ if (op.operation === "reaffirm") {
55336
+ return name ? `reaffirm ${name}` : "reaffirm";
55337
+ }
55183
55338
  const add = op;
55184
55339
  if (add.kind === "collection") {
55185
55340
  const type = add.type ?? "collection";
@@ -55203,8 +55358,8 @@ var ALLOWED_FLAGS = {
55203
55358
  "--stream": new Set,
55204
55359
  "--ops": new Set,
55205
55360
  "--file": new Set,
55206
- "--add": new Set(["data", "shape", "about", "kind"]),
55207
- "--revise": new Set(["data", "kind"]),
55361
+ "--add": new Set(["data", "shape", "about", "affirm", "kind"]),
55362
+ "--revise": new Set(["data", "affirm", "kind"]),
55208
55363
  "--retract": new Set(["reason", "kind"]),
55209
55364
  "--type": new Set(["name", "members"])
55210
55365
  };
@@ -55704,6 +55859,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
55704
55859
  const dataJsons = flags.data ?? [];
55705
55860
  const shapes = flags.shape ?? [];
55706
55861
  const abouts = flags.about ?? [];
55862
+ const affirms = flags.affirm ?? [];
55707
55863
  const reasons = flags.reason ?? [];
55708
55864
  const kinds = flags.kind ?? [];
55709
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";
@@ -55751,6 +55907,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
55751
55907
  data: dataJsons.length > 0,
55752
55908
  shape: shapes.length > 0,
55753
55909
  about: abouts.length > 0,
55910
+ affirm: affirms.length > 0,
55754
55911
  reason: reasons.length > 0,
55755
55912
  kind: operationKinds.length > 0,
55756
55913
  name: flags.name !== undefined,
@@ -55828,6 +55985,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
55828
55985
  dataJsons,
55829
55986
  shapes,
55830
55987
  abouts,
55988
+ affirms,
55831
55989
  kinds: operationKinds
55832
55990
  });
55833
55991
  } else if (operationSource === "--retract") {
@@ -55849,12 +56007,16 @@ var handleSubmit = async (ctx, { flags, args }) => {
55849
56007
  const data = rawData !== undefined ? parseJsonObject(rawData, "--data") : undefined;
55850
56008
  const kindFlag = operationKinds[0];
55851
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
+ }
55852
56013
  operations = [
55853
56014
  {
55854
56015
  operation: "revise",
55855
56016
  kind,
55856
56017
  name: reviseName,
55857
56018
  data,
56019
+ ...affirms.length > 0 ? { affirmedTargets: affirms } : {},
55858
56020
  ...expectedVersion !== undefined ? { expectedVersion } : {},
55859
56021
  ...leaseIdFlag ? { leaseId: leaseIdFlag } : {}
55860
56022
  }
@@ -58922,6 +59084,9 @@ var createFlags5 = {
58922
59084
  coverage: flag.string({
58923
59085
  description: "inline coverage JSON ({include, exclude?})"
58924
59086
  }),
59087
+ view: flag.string({
59088
+ description: "View backing coverage instead (View/NAME or View/NAME@vN)"
59089
+ }),
58925
59090
  op: flag.string({
58926
59091
  description: "operation to grant (repeatable)",
58927
59092
  multiple: true
@@ -58937,31 +59102,51 @@ var revokeFlags2 = {
58937
59102
  function repo(ctx) {
58938
59103
  return parseOrgRepo(getRepoRef(ctx), ctx.config);
58939
59104
  }
58940
- var handleCreate4 = async (ctx, { args, flags }) => {
58941
- const [principalKind, principalId] = args;
58942
- if (!principalKind || !principalId || !flags.key || !flags.op?.length) {
58943
- usageError("Usage: wh grant create <member|pat|component> <principal-id> --key KEY --op OP [--op OP] --coverage JSON", `wh grant create component install-1:7 --key provision --op things:read --coverage '{"include":["Lesson/**"]}'`);
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);
58944
59120
  }
58945
- if (!flags.coverage) {
58946
- usageError("Grant create requires --coverage.", `wh grant create component install-1:7 --key provision --op things:read --coverage '{"include":["Lesson/**"]}'`);
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);
58947
59129
  }
58948
- if (!["member", "pat", "component"].includes(principalKind)) {
58949
- usageError("Grant grantee kind must be member, pat, or component.", `wh grant create component install-1:7 --key provision --op things:read --coverage '{"include":["Lesson/**"]}'`);
59130
+ if (candidate.exclude !== undefined && !isPatternList(candidate.exclude)) {
59131
+ usageError("--coverage exclude must be an array of patterns when present.", CREATE_EXAMPLE);
58950
59132
  }
58951
- let coverage;
58952
- try {
58953
- coverage = JSON.parse(flags.coverage);
58954
- } catch {
58955
- usageError("--coverage must be valid JSON.", `wh grant create component install-1:7 --key provision --op things:read --coverage '{"include":["Lesson/**"]}'`);
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);
58956
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);
58957
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);
58958
59146
  const result = await ctx.client.grant.create(org, repoName, {
58959
59147
  idempotencyKey: flags.key,
58960
- grantee: {
58961
- principalId,
58962
- principalKind
58963
- },
58964
- coverage,
59148
+ recipient,
59149
+ ...source,
58965
59150
  ops: flags.op
58966
59151
  });
58967
59152
  writeOutput(ctx, result, () => ctx.out(JSON.stringify(result, null, 2)));
@@ -58977,7 +59162,7 @@ var handleGet = async (ctx, { args }) => {
58977
59162
  };
58978
59163
  var handleList4 = async (ctx, { flags }) => {
58979
59164
  const { org, repo: repoName } = repo(ctx);
58980
- const limit = Math.min(flags.limit ?? 50, 100);
59165
+ const limit = Math.min(parsePositiveIntFlag(flags.limit, "--limit", "wh grant list --limit 25") ?? 50, 100);
58981
59166
  const result = await ctx.client.grant.list(org, repoName, {
58982
59167
  limit,
58983
59168
  cursor: flags.cursor
@@ -59003,7 +59188,7 @@ var GRANT_DOMAIN = defineDomain({
59003
59188
  create: {
59004
59189
  prime: true,
59005
59190
  summary: "Create or replay an issuer-scoped Grant request",
59006
- args: "<member|pat|component> <principal-id>",
59191
+ args: "<member|pat|component> <email|token-name|org/name>",
59007
59192
  flags: createFlags5,
59008
59193
  handler: handleCreate4
59009
59194
  },
@@ -66200,7 +66385,7 @@ function resolveLogLevel(flagLevel, env) {
66200
66385
  // package.json
66201
66386
  var package_default3 = {
66202
66387
  name: "@warmhub/cli",
66203
- version: "0.89.0",
66388
+ version: "0.90.0",
66204
66389
  private: false,
66205
66390
  type: "module",
66206
66391
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -66819,5 +67004,5 @@ process.exitCode = interceptedExitCode === undefined ? await runPreparedCli(laun
66819
67004
  version: package_default3.version
66820
67005
  }) : interceptedExitCode;
66821
67006
 
66822
- //# debugId=0D9B1F5B8E62352264756E2164756E21
66823
- //# warmhub-cli-build-info {"cliVersion":"0.89.0","sdkVersion":"0.87.0"}
67007
+ //# debugId=0BE58A01FF9B9E5664756E2164756E21
67008
+ //# warmhub-cli-build-info {"cliVersion":"0.90.0","sdkVersion":"0.88.0"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.89.0",
3
+ "version": "0.90.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",