@warmhub/cli 0.85.0 → 0.86.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 +269 -139
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -27993,8 +27993,8 @@ function normalizeOptionalName(value) {
27993
27993
 
27994
27994
  // ../../packages/sdk-ts/src/operation-normalize.ts
27995
27995
  function toBackendStreamOperation(operation) {
27996
- if (operation.expectedVersion !== undefined && operation.operation !== "revise") {
27997
- throw new Error("expectedVersion is only valid on revise operations — set operation: 'revise'");
27996
+ if (operation.expectedVersion !== undefined && operation.operation !== "revise" && operation.operation !== "retract") {
27997
+ throw new Error("expectedVersion is only valid on revise or retract operations — set an explicit operation discriminator");
27998
27998
  }
27999
27999
  if (operation.operation === "retract") {
28000
28000
  return {
@@ -28002,6 +28002,7 @@ function toBackendStreamOperation(operation) {
28002
28002
  name: operation.name,
28003
28003
  ...operation.kind ? { kind: operation.kind } : {},
28004
28004
  ...operation.reason ? { reason: operation.reason } : {},
28005
+ ...operation.expectedVersion !== undefined ? { expectedVersion: operation.expectedVersion } : {},
28005
28006
  ...operation.leaseId ? { leaseId: operation.leaseId } : {}
28006
28007
  };
28007
28008
  }
@@ -28097,13 +28098,19 @@ class PartialStreamSubmissionError extends Error {
28097
28098
  code = "PARTIAL_STREAM_SUBMISSION";
28098
28099
  completedOperations;
28099
28100
  acknowledgedOperationCount;
28101
+ lastAcknowledgedRepoSeq;
28102
+ attemptedAppendOutcome;
28100
28103
  cause;
28101
28104
  constructor(input) {
28102
- super("Stream submission failed. A timed-out append may already have landed, so inspect repository state before sending any further operations.");
28105
+ super("Stream submission outcome is incomplete or unknown. Stop sending writes; once any outstanding append can no longer apply, obtain a later verified checkpoint and reconcile before replanning.");
28103
28106
  this.name = "WarmHubError";
28104
28107
  this.cause = input.cause;
28105
28108
  this.completedOperations = input.completedOperations;
28106
28109
  this.acknowledgedOperationCount = input.acknowledgedOperationCount ?? input.completedOperations.length;
28110
+ this.attemptedAppendOutcome = input.attemptedAppendOutcome;
28111
+ if (input.lastAcknowledgedRepoSeq !== undefined) {
28112
+ this.lastAcknowledgedRepoSeq = input.lastAcknowledgedRepoSeq;
28113
+ }
28107
28114
  }
28108
28115
  }
28109
28116
 
@@ -28260,6 +28267,9 @@ function isTransientStreamFailure(cause) {
28260
28267
  function isFetchNetworkTypeError(cause) {
28261
28268
  return cause instanceof TypeError && /fetch/i.test(cause.message);
28262
28269
  }
28270
+ function isReplaySafeOperation(operation) {
28271
+ return operation.operation !== "revise" || operation.expectedVersion !== undefined;
28272
+ }
28263
28273
  function computeBackoffDelayMs(attempt, policy) {
28264
28274
  const exponential = policy.baseDelayMs * 2 ** Math.max(0, attempt - 1);
28265
28275
  const jitter = Math.random() * policy.baseDelayMs;
@@ -28309,7 +28319,8 @@ async function submitOperationsViaStream(client, args) {
28309
28319
  for (const { operations: chunk, start: chunkStart } of chunkOperations(operations, chunkSize)) {
28310
28320
  let attempt = 1;
28311
28321
  let priorAttemptAmbiguous = false;
28312
- const chunkIsAtomic = chunk.length === 1;
28322
+ const chunkIsSingleOperation = chunk.length === 1;
28323
+ const chunkIsReplaySafe = chunk.every(isReplaySafeOperation);
28313
28324
  while (true) {
28314
28325
  try {
28315
28326
  const appendResult = await client.stream.append({
@@ -28337,7 +28348,7 @@ async function submitOperationsViaStream(client, args) {
28337
28348
  if (acknowledgedOperationCount === 0 && !priorAttemptAmbiguous && isDefiniteClientError(cause)) {
28338
28349
  throw cause;
28339
28350
  }
28340
- if (acknowledgedOperationCount === 0 && chunkIsAtomic && policy !== false && attempt < policy.maxAttempts && isTransientStreamFailure(cause)) {
28351
+ if (acknowledgedOperationCount === 0 && chunkIsSingleOperation && chunkIsReplaySafe && policy !== false && attempt < policy.maxAttempts && isTransientStreamFailure(cause)) {
28341
28352
  await sleep2(computeBackoffDelayMs(attempt, policy));
28342
28353
  attempt += 1;
28343
28354
  priorAttemptAmbiguous = true;
@@ -28352,7 +28363,9 @@ async function submitOperationsViaStream(client, args) {
28352
28363
  throw new PartialStreamSubmissionError({
28353
28364
  cause,
28354
28365
  completedOperations,
28355
- acknowledgedOperationCount
28366
+ acknowledgedOperationCount,
28367
+ lastAcknowledgedRepoSeq: repoSeq,
28368
+ attemptedAppendOutcome: !priorAttemptAmbiguous && isDefiniteClientError(cause) ? "not_applied" : "unknown"
28356
28369
  });
28357
28370
  }
28358
28371
  }
@@ -28366,7 +28379,9 @@ async function submitOperationsViaStream(client, args) {
28366
28379
  throw new PartialStreamSubmissionError({
28367
28380
  cause: failure,
28368
28381
  completedOperations: completedOperationsFrom(result),
28369
- acknowledgedOperationCount
28382
+ acknowledgedOperationCount,
28383
+ lastAcknowledgedRepoSeq: repoSeq,
28384
+ attemptedAppendOutcome: "unknown"
28370
28385
  });
28371
28386
  }
28372
28387
  throw failure;
@@ -28480,7 +28495,7 @@ function dedupeDeprecationsByShape(results) {
28480
28495
  // ../../packages/sdk-ts/package.json
28481
28496
  var package_default = {
28482
28497
  name: "@warmhub/sdk-ts",
28483
- version: "0.83.0",
28498
+ version: "0.84.0",
28484
28499
  private: false,
28485
28500
  type: "module",
28486
28501
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -28709,6 +28724,9 @@ function chunkArray(items, chunkSize) {
28709
28724
  }
28710
28725
  return chunks;
28711
28726
  }
28727
+ function narrowKind(kind) {
28728
+ return kind !== undefined && COMMIT_OPERATION_KINDS.includes(kind) ? kind : undefined;
28729
+ }
28712
28730
  function toSubscriptionRef(args) {
28713
28731
  const [first, repoName, name] = args;
28714
28732
  return typeof first === "string" ? { orgName: first, repoName, name } : first;
@@ -30047,6 +30065,7 @@ class WarmHubClient {
30047
30065
  return await this.trpc.action.listRuns.query({
30048
30066
  orgName,
30049
30067
  repoName,
30068
+ runId: opts?.runId,
30050
30069
  subscriptionName: opts?.subscriptionName,
30051
30070
  status: opts?.status,
30052
30071
  outcome: opts?.outcome,
@@ -30257,12 +30276,11 @@ class WarmHubClient {
30257
30276
  thing = {
30258
30277
  head: async (orgName, repoName, opts) => {
30259
30278
  try {
30260
- const kind = opts?.kind === "shape" || opts?.kind === "thing" || opts?.kind === "assertion" || opts?.kind === "collection" ? opts.kind : undefined;
30261
30279
  return await this.trpc.thing.head.query({
30262
30280
  orgName,
30263
30281
  repoName,
30264
30282
  shape: opts?.shape,
30265
- kind,
30283
+ kind: narrowKind(opts?.kind),
30266
30284
  match: opts?.match,
30267
30285
  dataMode: opts?.dataMode,
30268
30286
  includeRetracted: opts?.includeRetracted,
@@ -30496,13 +30514,12 @@ class WarmHubClient {
30496
30514
  },
30497
30515
  query: async (orgName, repoName, opts) => {
30498
30516
  try {
30499
- const kind = opts?.kind === "shape" || opts?.kind === "thing" || opts?.kind === "assertion" || opts?.kind === "collection" ? opts.kind : undefined;
30500
30517
  return await this.trpc.thing.query.query({
30501
30518
  orgName,
30502
30519
  repoName,
30503
30520
  shape: opts?.shape,
30504
30521
  about: opts?.about,
30505
- kind,
30522
+ kind: narrowKind(opts?.kind),
30506
30523
  match: opts?.match,
30507
30524
  includeRetracted: opts?.includeRetracted,
30508
30525
  resolveCollections: opts?.resolveCollections,
@@ -30536,14 +30553,13 @@ class WarmHubClient {
30536
30553
  },
30537
30554
  search: async (orgName, repoName, query, opts) => {
30538
30555
  try {
30539
- const kind = opts?.kind === "shape" || opts?.kind === "thing" || opts?.kind === "assertion" || opts?.kind === "collection" ? opts.kind : undefined;
30540
30556
  return await this.trpc.thing.search.query({
30541
30557
  orgName,
30542
30558
  repoName,
30543
30559
  query,
30544
30560
  shape: opts?.shape,
30545
30561
  about: opts?.about,
30546
- kind,
30562
+ kind: narrowKind(opts?.kind),
30547
30563
  match: opts?.match,
30548
30564
  includeRetracted: opts?.includeRetracted,
30549
30565
  resolveCollections: opts?.resolveCollections,
@@ -30571,13 +30587,12 @@ class WarmHubClient {
30571
30587
  },
30572
30588
  count: async (orgName, repoName, opts) => {
30573
30589
  try {
30574
- const kind = opts?.kind === "shape" || opts?.kind === "thing" || opts?.kind === "assertion" || opts?.kind === "collection" ? opts.kind : undefined;
30575
30590
  return await this.trpc.thing.count.query({
30576
30591
  orgName,
30577
30592
  repoName,
30578
30593
  shape: opts?.shape,
30579
30594
  about: opts?.about,
30580
- kind,
30595
+ kind: narrowKind(opts?.kind),
30581
30596
  match: opts?.match,
30582
30597
  includeRetracted: opts?.includeRetracted,
30583
30598
  resolveCollections: opts?.resolveCollections,
@@ -31215,20 +31230,101 @@ class CliError extends Error {
31215
31230
  cause;
31216
31231
  hint;
31217
31232
  backendCode;
31233
+ recovery;
31218
31234
  context;
31219
- constructor(code, kind, message, cause, hint, context, backendCode) {
31235
+ constructor(code, kind, message, cause, hint, context, backendCode, recovery) {
31220
31236
  super(message);
31221
31237
  this.code = code;
31222
31238
  this.kind = kind;
31223
31239
  this.cause = cause;
31224
31240
  this.hint = hint;
31225
31241
  this.backendCode = backendCode;
31242
+ this.recovery = recovery;
31226
31243
  this.context = context;
31227
31244
  }
31228
31245
  get errorCode() {
31229
31246
  return this.backendCode;
31230
31247
  }
31231
31248
  }
31249
+
31250
+ // ../../packages/warmhub-cli/src/stream-recovery.ts
31251
+ function failureCode(error) {
31252
+ if (typeof error !== "object" || error === null)
31253
+ return;
31254
+ const typed = error;
31255
+ if (typeof typed.errorCode === "string")
31256
+ return typed.errorCode;
31257
+ if (typeof typed.backendCode === "string")
31258
+ return typed.backendCode;
31259
+ if (typeof typed.data?.warmhub?.code === "string") {
31260
+ return typed.data.warmhub.code;
31261
+ }
31262
+ if (typeof typed.data?.code === "string")
31263
+ return typed.data.code;
31264
+ return failureCode(typed.cause);
31265
+ }
31266
+ function failureStatus(error) {
31267
+ if (typeof error !== "object" || error === null)
31268
+ return;
31269
+ const typed = error;
31270
+ if (typeof typed.status === "number")
31271
+ return typed.status;
31272
+ if (typeof typed.data?.warmhub?.status === "number") {
31273
+ return typed.data.warmhub.status;
31274
+ }
31275
+ if (typeof typed.data?.status === "number")
31276
+ return typed.data.status;
31277
+ if (typeof typed.data?.httpStatus === "number") {
31278
+ return typed.data.httpStatus;
31279
+ }
31280
+ return failureStatus(typed.cause);
31281
+ }
31282
+ function streamAppendWasExplicitlyRejected(cause) {
31283
+ const normalized = toWarmHubError(cause);
31284
+ const code = failureCode(cause) ?? normalized.errorCode ?? normalized.code;
31285
+ if (code === "COMMIT_OUTCOME_UNKNOWN")
31286
+ return false;
31287
+ const status = failureStatus(cause) ?? normalized.status;
31288
+ return status !== undefined && status >= 400 && status < 500 && status !== 408;
31289
+ }
31290
+ function streamFailureCode(cause) {
31291
+ const normalized = toWarmHubError(cause);
31292
+ const wireCode = failureCode(cause) ?? normalized.errorCode;
31293
+ if (wireCode !== undefined)
31294
+ return wireCode;
31295
+ return normalized.status !== undefined && normalized.code !== "BACKEND" ? normalized.code : undefined;
31296
+ }
31297
+ function buildStreamRecoveryReceipt(args) {
31298
+ const {
31299
+ acknowledgedOperationCount,
31300
+ lastAcknowledgedRepoSeq,
31301
+ cause,
31302
+ attemptedAppendOutcome
31303
+ } = args;
31304
+ const sequenceReceipt = lastAcknowledgedRepoSeq === undefined ? "" : ` Last acknowledged repo sequence: ${lastAcknowledgedRepoSeq}.`;
31305
+ const errorCode = streamFailureCode(cause);
31306
+ const backendSuffix = errorCode ? ` (backend: ${errorCode})` : "";
31307
+ const recovery = {
31308
+ acknowledgedOperationCount,
31309
+ ...lastAcknowledgedRepoSeq === undefined ? {} : { lastAcknowledgedRepoSeq },
31310
+ attemptedAppendOutcome
31311
+ };
31312
+ if (attemptedAppendOutcome === "unknown") {
31313
+ return {
31314
+ message: `Stream append outcome is unknown after ${acknowledgedOperationCount} acknowledged operation(s).${sequenceReceipt}${backendSuffix}`,
31315
+ hint: "Stop submitting writes. The attempted append may have landed after the last acknowledgement; once it can no longer apply, obtain and verify a later checkpoint, then reconcile the attempted append and unsent work.",
31316
+ errorCode,
31317
+ recovery
31318
+ };
31319
+ }
31320
+ const causeMessage = cause instanceof Error ? cause.message : String(cause);
31321
+ return {
31322
+ message: `${causeMessage} (${acknowledgedOperationCount} earlier operation(s) already acknowledged before this failure).${sequenceReceipt}${backendSuffix}`,
31323
+ hint: "The failed input or rejected append was not applied. Keep the acknowledged prefix receipt, then correct or replan the rejected and unsent operations.",
31324
+ errorCode,
31325
+ recovery
31326
+ };
31327
+ }
31232
31328
  // ../../packages/warmhub-cli/src/errors-logging.ts
31233
31329
  function shouldLogToErrorTier(err) {
31234
31330
  switch (err.kind) {
@@ -31453,7 +31549,8 @@ function printCliError(err, errWriter, opts = {}) {
31453
31549
  message: err.message,
31454
31550
  ...err.hint ? { hint: err.hint } : {},
31455
31551
  ...suggestions.length > 0 ? { suggestions } : {},
31456
- ...err.context ? { context: err.context } : {}
31552
+ ...err.context ? { context: err.context } : {},
31553
+ ...err.recovery ? { recovery: err.recovery } : {}
31457
31554
  }
31458
31555
  };
31459
31556
  errWriter(JSON.stringify(envelope));
@@ -31493,8 +31590,13 @@ function toCliError(err) {
31493
31590
  return cliErrorFromAllFailed(err.operations);
31494
31591
  }
31495
31592
  if (err instanceof PartialStreamSubmissionError) {
31496
- const hint = err.cause instanceof Error ? err.cause.message : err.cause === undefined ? undefined : String(err.cause);
31497
- return new CliError(4 /* Backend */, "BACKEND", err.message, err, hint);
31593
+ const receipt = buildStreamRecoveryReceipt({
31594
+ acknowledgedOperationCount: err.acknowledgedOperationCount,
31595
+ lastAcknowledgedRepoSeq: err.lastAcknowledgedRepoSeq,
31596
+ cause: err.cause,
31597
+ attemptedAppendOutcome: err.attemptedAppendOutcome
31598
+ });
31599
+ return new CliError(4 /* Backend */, "BACKEND", receipt.message, err, receipt.hint, undefined, receipt.errorCode, receipt.recovery);
31498
31600
  }
31499
31601
  if (err instanceof WarmHubError) {
31500
31602
  if (err.code === "CURSOR_EPOCH_INVALID" || err.errorCode === "CURSOR_EPOCH_INVALID") {
@@ -34966,6 +35068,7 @@ function pageEnvelope(items, opts) {
34966
35068
  const nextCursor = opts.nextCursor ?? null;
34967
35069
  return {
34968
35070
  items,
35071
+ ...opts.repoSeq === undefined ? {} : { repoSeq: opts.repoSeq },
34969
35072
  page: {
34970
35073
  limit: opts.limit,
34971
35074
  count: items.length,
@@ -35118,6 +35221,9 @@ var reviseFlags = {
35118
35221
  };
35119
35222
  var retractFlags = {
35120
35223
  reason: flag.string({ description: "Reason for retraction (<=500 chars)" }),
35224
+ "expected-version": flag.number({
35225
+ description: "only retract if the target is still at this version (optimistic concurrency)"
35226
+ }),
35121
35227
  message: flag.string({ short: "m", description: "Commit message" }),
35122
35228
  committer: flag.string({
35123
35229
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -35152,15 +35258,17 @@ var handleRevise = async (ctx, { flags, args }) => {
35152
35258
  var handleRetract = async (ctx, { flags, args }) => {
35153
35259
  const name = args[0];
35154
35260
  if (!name) {
35155
- usageError("Usage: wh assertion retract <wref> -m <message>", 'wh assertion retract Belief/cave-safe -m "withdraw claim"');
35261
+ usageError("Usage: wh assertion retract <wref> -m <message> [--expected-version <n>]", 'wh assertion retract Belief/cave-safe -m "withdraw claim"');
35156
35262
  }
35157
35263
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
35264
+ const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", "wh assertion retract Belief/cave-safe --expected-version 3");
35158
35265
  const result = await ctx.client.commit.apply(org, repo, flags.message ?? `retract ${name}`, [
35159
35266
  {
35160
35267
  operation: "retract",
35161
35268
  kind: "assertion",
35162
35269
  name,
35163
- ...flags.reason ? { reason: flags.reason } : {}
35270
+ ...flags.reason ? { reason: flags.reason } : {},
35271
+ ...expectedVersion !== undefined ? { expectedVersion } : {}
35164
35272
  }
35165
35273
  ], {
35166
35274
  committer: flags.committer
@@ -35235,6 +35343,47 @@ function parseCollectionRoleFlag(value, example) {
35235
35343
  return value;
35236
35344
  usageError("Invalid --role. Expected from, to, or ends.", example);
35237
35345
  }
35346
+ function parseSinceRepoSeqFlag(value) {
35347
+ if (value === undefined)
35348
+ return;
35349
+ if (Number.isSafeInteger(value) && value >= -1)
35350
+ return value;
35351
+ usageError("--since-repo-seq must be -1 or a nonnegative safe integer.", "wh thing list --since-repo-seq -1 --all --format json");
35352
+ }
35353
+ function requireIncrementalCheckpoint(repoSeq, required) {
35354
+ if (required && repoSeq === undefined) {
35355
+ throw new CliError(4 /* Backend */, "BACKEND", "Incremental read completed without repoSeq", undefined, "Retry the read. If the checkpoint remains absent, report a backend incremental-read contract violation.");
35356
+ }
35357
+ }
35358
+ async function collectThingPages(args) {
35359
+ const items = [];
35360
+ let cursor = args.initialCursor;
35361
+ const seenCursors = new Set(cursor ? [cursor] : []);
35362
+ while (true) {
35363
+ const page = await args.fetchPage(cursor);
35364
+ const pageItems = page.items ?? [];
35365
+ if (args.onPage) {
35366
+ if (!await args.onPage(pageItems)) {
35367
+ return { items, nextCursor: undefined };
35368
+ }
35369
+ } else {
35370
+ items.push(...pageItems);
35371
+ }
35372
+ if (!page.nextCursor) {
35373
+ requireIncrementalCheckpoint(page.repoSeq, args.requireRepoSeq);
35374
+ return {
35375
+ items,
35376
+ nextCursor: undefined,
35377
+ ...page.repoSeq === undefined ? {} : { repoSeq: page.repoSeq }
35378
+ };
35379
+ }
35380
+ if (seenCursors.has(page.nextCursor)) {
35381
+ throw new CliError(4 /* Backend */, "BACKEND", `${args.title} pagination cursor repeated; aborting --all to avoid an infinite loop.`, undefined, "Retry without --all to fetch one page and inspect page.nextCursor. If cursors repeat, report this as a backend pagination issue.");
35382
+ }
35383
+ seenCursors.add(page.nextCursor);
35384
+ cursor = page.nextCursor;
35385
+ }
35386
+ }
35238
35387
  async function handleCount(ctx, org, repo, opts) {
35239
35388
  const result = await ctx.client.thing.count(org, repo, opts);
35240
35389
  writeOutput(ctx, result, () => ctx.out(`${result.count}`));
@@ -36190,6 +36339,9 @@ var headFlags = {
36190
36339
  description: "Max items per page (default: 50, max: 500)"
36191
36340
  }),
36192
36341
  cursor: flag.string({ description: "Opaque pagination cursor" }),
36342
+ "since-repo-seq": flag.number({
36343
+ description: "Return identities changed after this repository sequence"
36344
+ }),
36193
36345
  all: flag.boolean({ description: "Fetch all pages" }),
36194
36346
  match: flag.string({ description: "Filter by wref glob pattern" }),
36195
36347
  count: flag.boolean({ description: "Return count of matching items" }),
@@ -36213,15 +36365,19 @@ var handleHead = async (ctx, { flags, args }) => {
36213
36365
  const kind = validateKind(flags.kind);
36214
36366
  const limit = flags.limit;
36215
36367
  const cursor = flags.cursor;
36368
+ const sinceRepoSeq = parseSinceRepoSeqFlag(flags["since-repo-seq"]);
36216
36369
  const all = flags.all;
36217
36370
  const match = flags.match;
36218
36371
  const count = flags.count;
36219
36372
  const includeRetracted = flags["include-retracted"];
36220
36373
  const whereRaw = flags.where ?? [];
36221
36374
  const where = whereRaw.map(parseWhereFlag);
36375
+ if (ctx.liveMode && sinceRepoSeq !== undefined) {
36376
+ usageError("--since-repo-seq cannot be used with --live.", "wh thing list --since-repo-seq 42 --all --format json");
36377
+ }
36222
36378
  if (count) {
36223
36379
  if (cursor || all || limit || ctx.liveMode) {
36224
- usageError("Usage: wh thing list --count [--shape SHAPE] [--kind KIND] [--match PATTERN]", "wh thing list --shape Player --count");
36380
+ usageError("Usage: wh thing list --count [--shape SHAPE] [--kind KIND] [--match PATTERN] [--since-repo-seq N]", "wh thing list --shape Player --count --since-repo-seq 42");
36225
36381
  }
36226
36382
  const componentRef2 = flags.component;
36227
36383
  const strictExclude2 = !!flags["exclude-components"];
@@ -36234,7 +36390,8 @@ var handleHead = async (ctx, { flags, args }) => {
36234
36390
  componentRef: componentRef2,
36235
36391
  excludeComponents: strictExclude2,
36236
36392
  excludeInfraShapes: !strictExclude2 && !shape,
36237
- where: where.length > 0 ? where : undefined
36393
+ where: where.length > 0 ? where : undefined,
36394
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36238
36395
  });
36239
36396
  }
36240
36397
  if (cursor && !limit) {
@@ -36261,7 +36418,8 @@ var handleHead = async (ctx, { flags, args }) => {
36261
36418
  componentRef,
36262
36419
  excludeComponents,
36263
36420
  excludeInfraShapes,
36264
- where: where.length > 0 ? where : undefined
36421
+ where: where.length > 0 ? where : undefined,
36422
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36265
36423
  };
36266
36424
  if (ctx.liveMode) {
36267
36425
  await runLive({
@@ -36294,7 +36452,8 @@ var handleHead = async (ctx, { flags, args }) => {
36294
36452
  componentRef,
36295
36453
  excludeComponents,
36296
36454
  excludeInfraShapes,
36297
- where: where.length > 0 ? where : undefined
36455
+ where: where.length > 0 ? where : undefined,
36456
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36298
36457
  }, streamJsonl ? async (items) => {
36299
36458
  writePageOutput(ctx, items, { limit: pageLimit }, () => {});
36300
36459
  return await ctx.flushOut?.() ?? true;
@@ -36308,23 +36467,25 @@ var handleHead = async (ctx, { flags, args }) => {
36308
36467
  componentRef,
36309
36468
  excludeComponents,
36310
36469
  excludeInfraShapes,
36311
- where: where.length > 0 ? where : undefined
36470
+ where: where.length > 0 ? where : undefined,
36471
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36312
36472
  });
36313
36473
  if (streamJsonl)
36314
36474
  return;
36475
+ requireIncrementalCheckpoint(result.repoSeq, sinceRepoSeq !== undefined && !result.nextCursor);
36315
36476
  if (!all && result.nextCursor) {
36316
36477
  emitPartialPageHint(ctx, (result.items ?? []).length, result.nextCursor, boundedLimit);
36317
36478
  }
36318
36479
  writePageOutput(ctx, result.items ?? [], {
36319
36480
  limit: all ? pageLimit : boundedLimit,
36320
- nextCursor: result.nextCursor ?? null
36481
+ nextCursor: result.nextCursor ?? null,
36482
+ ...result.repoSeq === undefined ? {} : { repoSeq: result.repoSeq }
36321
36483
  }, () => renderHead(ctx.out, ctx.colors, ctx.chars, result, org, repo, shape, kind));
36322
36484
  };
36323
36485
  async function fetchAllHeadPages(ctx, org, repo, opts, onPage) {
36324
- const items = [];
36325
- let cursor = opts.cursor;
36326
- while (true) {
36327
- const page = await ctx.client.thing.head(org, repo, {
36486
+ return collectThingPages({
36487
+ initialCursor: opts.cursor,
36488
+ fetchPage: (cursor) => ctx.client.thing.head(org, repo, {
36328
36489
  shape: opts.shape,
36329
36490
  kind: opts.kind,
36330
36491
  match: opts.match,
@@ -36334,20 +36495,13 @@ async function fetchAllHeadPages(ctx, org, repo, opts, onPage) {
36334
36495
  componentRef: opts.componentRef,
36335
36496
  excludeComponents: opts.excludeComponents,
36336
36497
  excludeInfraShapes: opts.excludeInfraShapes,
36337
- where: opts.where
36338
- });
36339
- const pageItems = page.items ?? [];
36340
- if (onPage) {
36341
- if (!await onPage(pageItems))
36342
- break;
36343
- } else {
36344
- items.push(...pageItems);
36345
- }
36346
- if (!page.nextCursor)
36347
- break;
36348
- cursor = page.nextCursor;
36349
- }
36350
- return { items, nextCursor: undefined };
36498
+ where: opts.where,
36499
+ ...opts.sinceRepoSeq === undefined ? {} : { sinceRepoSeq: opts.sinceRepoSeq }
36500
+ }),
36501
+ onPage,
36502
+ requireRepoSeq: opts.sinceRepoSeq !== undefined,
36503
+ title: "Thing list"
36504
+ });
36351
36505
  }
36352
36506
 
36353
36507
  // ../../packages/warmhub-cli/src/domains/thing/query.ts
@@ -36359,6 +36513,9 @@ var queryFlags = {
36359
36513
  description: "Max results per page (default: 50, max: 500)"
36360
36514
  }),
36361
36515
  cursor: flag.string({ description: "Opaque pagination cursor" }),
36516
+ "since-repo-seq": flag.number({
36517
+ description: "Return identities changed after this repository sequence"
36518
+ }),
36362
36519
  all: flag.boolean({ description: "Fetch all pages" }),
36363
36520
  match: flag.string({ description: "Filter by wref glob pattern" }),
36364
36521
  count: flag.boolean({ description: "Return count of matching items" }),
@@ -36389,6 +36546,7 @@ var handleQuery = async (ctx, { flags }) => {
36389
36546
  const kind = validateKind(flags.kind);
36390
36547
  const limit = flags.limit;
36391
36548
  const cursor = flags.cursor;
36549
+ const sinceRepoSeq = parseSinceRepoSeqFlag(flags["since-repo-seq"]);
36392
36550
  const all = flags.all;
36393
36551
  const match = flags.match;
36394
36552
  const count = flags.count;
@@ -36404,9 +36562,12 @@ var handleQuery = async (ctx, { flags }) => {
36404
36562
  const c = ctx.colors;
36405
36563
  const whereRaw = flags.where ?? [];
36406
36564
  const where = whereRaw.map(parseWhereFlag);
36565
+ if (ctx.liveMode && sinceRepoSeq !== undefined) {
36566
+ usageError("--since-repo-seq cannot be used with --live.", "wh thing query --since-repo-seq 42 --all --format json");
36567
+ }
36407
36568
  if (count) {
36408
36569
  if (cursor || all || limit || ctx.liveMode || role) {
36409
- usageError("Usage: wh thing query --count [--shape SHAPE] [--about WREF] [--kind KIND] [--match PATTERN]", "wh thing query --kind assertion --about Player/alice --count");
36570
+ 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");
36410
36571
  }
36411
36572
  return handleCount(ctx, org, repo, {
36412
36573
  shape,
@@ -36418,7 +36579,8 @@ var handleQuery = async (ctx, { flags }) => {
36418
36579
  componentRef,
36419
36580
  excludeComponents,
36420
36581
  excludeInfraShapes,
36421
- where: where.length > 0 ? where : undefined
36582
+ where: where.length > 0 ? where : undefined,
36583
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36422
36584
  });
36423
36585
  }
36424
36586
  if (role && (!about || !resolveCollections)) {
@@ -36445,7 +36607,8 @@ var handleQuery = async (ctx, { flags }) => {
36445
36607
  componentRef,
36446
36608
  excludeComponents,
36447
36609
  excludeInfraShapes,
36448
- where: where.length > 0 ? where : undefined
36610
+ where: where.length > 0 ? where : undefined,
36611
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36449
36612
  };
36450
36613
  if (ctx.liveMode) {
36451
36614
  await runLive({
@@ -36481,7 +36644,8 @@ var handleQuery = async (ctx, { flags }) => {
36481
36644
  componentRef,
36482
36645
  excludeComponents,
36483
36646
  excludeInfraShapes,
36484
- where: where.length > 0 ? where : undefined
36647
+ where: where.length > 0 ? where : undefined,
36648
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36485
36649
  }, streamJsonl ? async (items) => {
36486
36650
  writePageOutput(ctx, items, { limit: pageLimit }, () => {});
36487
36651
  return await ctx.flushOut?.() ?? true;
@@ -36498,23 +36662,25 @@ var handleQuery = async (ctx, { flags }) => {
36498
36662
  componentRef,
36499
36663
  excludeComponents,
36500
36664
  excludeInfraShapes,
36501
- where: where.length > 0 ? where : undefined
36665
+ where: where.length > 0 ? where : undefined,
36666
+ ...sinceRepoSeq === undefined ? {} : { sinceRepoSeq }
36502
36667
  });
36503
36668
  if (streamJsonl)
36504
36669
  return;
36670
+ requireIncrementalCheckpoint(result.repoSeq, sinceRepoSeq !== undefined && !result.nextCursor);
36505
36671
  if (!all && result.nextCursor) {
36506
36672
  emitPartialPageHint(ctx, (result.items ?? []).length, result.nextCursor, boundedLimit);
36507
36673
  }
36508
36674
  writePageOutput(ctx, result.items ?? [], {
36509
36675
  limit: all ? pageLimit : boundedLimit,
36510
- nextCursor: result.nextCursor ?? null
36676
+ nextCursor: result.nextCursor ?? null,
36677
+ ...result.repoSeq === undefined ? {} : { repoSeq: result.repoSeq }
36511
36678
  }, () => renderQueryResults(ctx.out, c, result));
36512
36679
  };
36513
36680
  async function fetchAllQueryPages(ctx, org, repo, opts, onPage) {
36514
- const items = [];
36515
- let cursor = opts.cursor;
36516
- while (true) {
36517
- const page = await ctx.client.thing.query(org, repo, {
36681
+ return collectThingPages({
36682
+ initialCursor: opts.cursor,
36683
+ fetchPage: (cursor) => ctx.client.thing.query(org, repo, {
36518
36684
  shape: opts.shape,
36519
36685
  about: opts.about,
36520
36686
  kind: opts.kind,
@@ -36527,20 +36693,13 @@ async function fetchAllQueryPages(ctx, org, repo, opts, onPage) {
36527
36693
  componentRef: opts.componentRef,
36528
36694
  excludeComponents: opts.excludeComponents,
36529
36695
  excludeInfraShapes: opts.excludeInfraShapes,
36530
- where: opts.where
36531
- });
36532
- const pageItems = page.items ?? [];
36533
- if (onPage) {
36534
- if (!await onPage(pageItems))
36535
- break;
36536
- } else {
36537
- items.push(...pageItems);
36538
- }
36539
- if (!page.nextCursor)
36540
- break;
36541
- cursor = page.nextCursor;
36542
- }
36543
- return { items, nextCursor: undefined };
36696
+ where: opts.where,
36697
+ ...opts.sinceRepoSeq === undefined ? {} : { sinceRepoSeq: opts.sinceRepoSeq }
36698
+ }),
36699
+ onPage,
36700
+ requireRepoSeq: opts.sinceRepoSeq !== undefined,
36701
+ title: "Thing query"
36702
+ });
36544
36703
  }
36545
36704
  function renderQueryResults(out, c, result) {
36546
36705
  const items = result.items ?? [];
@@ -36709,6 +36868,9 @@ var retractFlags2 = {
36709
36868
  description: "Optional safety check: thing|assertion|shape|collection (errors on mismatch)"
36710
36869
  }),
36711
36870
  reason: flag.string({ description: "Reason for retraction (<=500 chars)" }),
36871
+ "expected-version": flag.number({
36872
+ description: "only retract if the target is still at this version (optimistic concurrency)"
36873
+ }),
36712
36874
  message: flag.string({ short: "m", description: "Commit message" }),
36713
36875
  committer: flag.string({
36714
36876
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -36720,13 +36882,14 @@ var retractFlags2 = {
36720
36882
  var handleThingRetract = async (ctx, { flags, args }) => {
36721
36883
  const name = args[0];
36722
36884
  if (!name) {
36723
- usageError("Usage: wh thing retract <wref> -m <message> [--reason <text>] [--kind thing|assertion|shape|collection]", 'wh thing retract Measurement/m1 -m "cleanup" --reason "bad source"');
36885
+ usageError("Usage: wh thing retract <wref> -m <message> [--reason <text>] [--kind thing|assertion|shape|collection] [--expected-version <n>]", 'wh thing retract Measurement/m1 -m "cleanup" --reason "bad source"');
36724
36886
  }
36725
36887
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
36726
36888
  const committer = flags.committer;
36727
36889
  const message = flags.message;
36728
36890
  const kind = flags.kind;
36729
36891
  const reason = flags.reason;
36892
+ const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", "wh thing retract Player/alice --expected-version 3");
36730
36893
  const leaseId = requireLeaseIdFlag(flags["lease-id"], "wh thing retract Player/alice --lease-id <id>");
36731
36894
  const c = ctx.colors;
36732
36895
  const result = await ctx.client.commit.apply(org, repo, message ?? `retract ${name}`, [
@@ -36735,6 +36898,7 @@ var handleThingRetract = async (ctx, { flags, args }) => {
36735
36898
  name,
36736
36899
  ...kind ? { kind } : {},
36737
36900
  ...reason ? { reason } : {},
36901
+ ...expectedVersion !== undefined ? { expectedVersion } : {},
36738
36902
  ...leaseId ? { leaseId } : {}
36739
36903
  }
36740
36904
  ], { committer });
@@ -39319,7 +39483,7 @@ var createFlags3 = {
39319
39483
  description: "collection members (comma-separated wrefs)"
39320
39484
  }),
39321
39485
  "expected-version": flag.number({
39322
- description: "Only apply if the --revise target is still at this version (optimistic concurrency). Requires --revise."
39486
+ description: "only apply if the --revise or single --retract target is still at this version (optimistic concurrency)."
39323
39487
  }),
39324
39488
  "lease-id": flag.string({
39325
39489
  description: "read-lease token from `wh thing lease`, bound to --revise or one --retract target (auto-released on success)"
@@ -39582,7 +39746,7 @@ function buildAddOperations(input) {
39582
39746
  });
39583
39747
  }
39584
39748
  function buildRetractOperations(input) {
39585
- const { retractNames, kinds, reasons, leaseId } = input;
39749
+ const { retractNames, kinds, reasons, expectedVersion, leaseId } = input;
39586
39750
  if (leaseId !== undefined && retractNames.length !== 1) {
39587
39751
  throw new CliError(2 /* UserInput */, "USER_INPUT", `--lease-id requires exactly one --retract target; received ${retractNames.length}.`, undefined, "wh commit submit --retract Player/alice --lease-id lease-xyz --repo acme/world");
39588
39752
  }
@@ -39612,6 +39776,7 @@ function buildRetractOperations(input) {
39612
39776
  name,
39613
39777
  ...kind ? { kind } : {},
39614
39778
  ...reason ? { reason } : {},
39779
+ ...expectedVersion !== undefined ? { expectedVersion } : {},
39615
39780
  ...leaseId ? { leaseId } : {}
39616
39781
  };
39617
39782
  });
@@ -39711,15 +39876,14 @@ import { createInterface as createInterface2 } from "node:readline";
39711
39876
  class JsonlPartialSubmissionError extends CliError {
39712
39877
  }
39713
39878
  function jsonlPartialSubmissionError(args) {
39714
- const { acknowledgedOperationCount, cause } = args;
39715
- if (args.failedAppendMayHaveLanded === true) {
39716
- const backendCode = toWarmHubError(cause).backendCode;
39717
- const suffix = backendCode ? ` (backend: ${backendCode})` : "";
39718
- return new JsonlPartialSubmissionError(4 /* Backend */, "BACKEND", `Stream append failed after ${acknowledgedOperationCount} acknowledged operation(s).${suffix}`, cause, "The failed append may also have landed; inspect repository state before submitting any remaining JSONL operations.", undefined, backendCode);
39719
- }
39720
- const message = cause instanceof Error ? cause.message : String(cause);
39721
- const causeHint = cause instanceof CliError && cause.hint ? `${cause.hint} ` : "";
39722
- return new JsonlPartialSubmissionError(4 /* Backend */, "BACKEND", `${message} (${acknowledgedOperationCount} earlier operation(s) already acknowledged by the server before this input failure).`, cause, `${causeHint}Earlier chunks have landed; inspect repository state before submitting any remaining JSONL operations.`);
39879
+ const receipt = buildStreamRecoveryReceipt({
39880
+ acknowledgedOperationCount: args.acknowledgedOperationCount,
39881
+ lastAcknowledgedRepoSeq: args.lastAcknowledgedRepoSeq,
39882
+ cause: args.cause,
39883
+ attemptedAppendOutcome: args.failedAppendMayHaveLanded === true ? "unknown" : "not_applied"
39884
+ });
39885
+ const causeHint = args.cause instanceof CliError && args.cause.hint ? `${args.cause.hint} ` : "";
39886
+ return new JsonlPartialSubmissionError(4 /* Backend */, "BACKEND", receipt.message, args.cause, `${causeHint}${receipt.hint}`, undefined, receipt.errorCode, receipt.recovery);
39723
39887
  }
39724
39888
 
39725
39889
  // ../../packages/warmhub-cli/src/domains/commit-submit-utils.ts
@@ -39804,50 +39968,6 @@ function toCommitSubmitResult(args) {
39804
39968
  operations
39805
39969
  };
39806
39970
  }
39807
- function backendErrorCode(error) {
39808
- if (typeof error !== "object" || error === null) {
39809
- return;
39810
- }
39811
- const typed = error;
39812
- if (typeof typed.data === "object" && typed.data !== null) {
39813
- const data = typed.data;
39814
- if (typeof data.code === "string") {
39815
- return data.code;
39816
- }
39817
- }
39818
- const causeCode = backendErrorCode(typed.cause);
39819
- if (causeCode !== undefined) {
39820
- return causeCode;
39821
- }
39822
- return typeof typed.code === "string" ? typed.code : undefined;
39823
- }
39824
- function backendErrorStatus(error) {
39825
- if (typeof error !== "object" || error === null) {
39826
- return;
39827
- }
39828
- const typed = error;
39829
- if (typeof typed.status === "number") {
39830
- return typed.status;
39831
- }
39832
- if (typeof typed.data === "object" && typed.data !== null) {
39833
- const data = typed.data;
39834
- if (typeof data.status === "number") {
39835
- return data.status;
39836
- }
39837
- if (typeof data.httpStatus === "number") {
39838
- return data.httpStatus;
39839
- }
39840
- if (typeof data.warmhub?.status === "number") {
39841
- return data.warmhub.status;
39842
- }
39843
- }
39844
- return backendErrorStatus(typed.cause);
39845
- }
39846
- function firstJsonlAppendErrorMayHaveCommitted(error) {
39847
- const errorCode = backendErrorCode(error);
39848
- const errorStatus = backendErrorStatus(error);
39849
- return errorCode === undefined || errorCode === "COMMIT_OUTCOME_UNKNOWN" || errorCode === "INTERNAL_ERROR" || errorCode === "NETWORK" || errorCode === "SERVICE_UNAVAILABLE" || errorCode === "BACKEND" && errorStatus !== undefined && errorStatus >= 500;
39850
- }
39851
39971
 
39852
39972
  // ../../packages/warmhub-cli/src/domains/stream-progress.ts
39853
39973
  import { createReadStream } from "node:fs";
@@ -40032,12 +40152,12 @@ async function applyJsonlCommit(ctx, args) {
40032
40152
  const tAppendStart = performance.now();
40033
40153
  progress.start(t0);
40034
40154
  let opCount = 0;
40155
+ let repoSeq;
40035
40156
  try {
40036
40157
  const operations = [];
40037
40158
  const submittedOperations = [];
40038
40159
  let allocatedTokenRanges = [];
40039
40160
  let createdByEmail;
40040
- let repoSeq;
40041
40161
  let parsedOpCount = 0;
40042
40162
  let chunk = [];
40043
40163
  let lineNumber = 0;
@@ -40060,11 +40180,13 @@ async function applyJsonlCommit(ctx, args) {
40060
40180
  });
40061
40181
  } catch (cause) {
40062
40182
  const completed = opCount;
40063
- if (opCount > 0 || firstJsonlAppendErrorMayHaveCommitted(cause)) {
40183
+ const failedAppendMayHaveLanded = !streamAppendWasExplicitlyRejected(cause);
40184
+ if (opCount > 0 || failedAppendMayHaveLanded) {
40064
40185
  throw jsonlPartialSubmissionError({
40065
40186
  acknowledgedOperationCount: completed,
40066
40187
  cause,
40067
- failedAppendMayHaveLanded: true
40188
+ failedAppendMayHaveLanded,
40189
+ lastAcknowledgedRepoSeq: repoSeq
40068
40190
  });
40069
40191
  }
40070
40192
  throw cause;
@@ -40259,7 +40381,8 @@ async function applyJsonlCommit(ctx, args) {
40259
40381
  }
40260
40382
  throw jsonlPartialSubmissionError({
40261
40383
  acknowledgedOperationCount: opCount,
40262
- cause: error
40384
+ cause: error,
40385
+ lastAcknowledgedRepoSeq: repoSeq
40263
40386
  });
40264
40387
  }
40265
40388
  }
@@ -40329,9 +40452,10 @@ var handleSubmit = async (ctx, { flags, args }) => {
40329
40452
  const abouts = flags.about ?? [];
40330
40453
  const reasons = flags.reason ?? [];
40331
40454
  const kinds = flags.kind ?? [];
40332
- const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", "wh commit submit --revise Player/alice --data '{...}' --expected-version 3");
40333
- if (expectedVersion !== undefined && !reviseName) {
40334
- usageError("--expected-version requires --revise", "wh commit submit --revise Player/alice --data '{...}' --expected-version 3");
40455
+ const expectedVersionExample = retractNames.length > 0 ? "wh commit submit --retract Player/alice --expected-version 3" : "wh commit submit --revise Player/alice --data '{...}' --expected-version 3";
40456
+ const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", expectedVersionExample);
40457
+ if (expectedVersion !== undefined && reviseName === undefined && retractNames.length !== 1) {
40458
+ usageError("--expected-version requires --revise or exactly one --retract", "wh commit submit --retract Player/alice --expected-version 3");
40335
40459
  }
40336
40460
  const leaseIdFlag = requireLeaseIdFlag(flags["lease-id"], `wh commit submit --revise Player/alice --data '{"score":2}' --lease-id <id>`);
40337
40461
  if (leaseIdFlag !== undefined && reviseName === undefined && retractNames.length === 0) {
@@ -40455,6 +40579,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
40455
40579
  retractNames,
40456
40580
  kinds,
40457
40581
  reasons,
40582
+ expectedVersion,
40458
40583
  leaseId: leaseIdFlag
40459
40584
  });
40460
40585
  } else if (operationSource === "--revise") {
@@ -44376,7 +44501,7 @@ var ORG_DOMAIN = defineDomain({
44376
44501
  });
44377
44502
 
44378
44503
  // ../../packages/warmhub-cli/src/domains/prime-content.md
44379
- 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]` — 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]` — 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]` — 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>` — Delete a subscription\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# Add-only restart: rerun the WHOLE file. --skip-existing makes fixed-name adds\n# idempotent; --stream-id only identifies the submission. Mid-stream resume is\n# not a CLI mode. Revise/retract JSONL is not full-rerun safe after an ambiguous\n# append; inspect repo state and reconcile.\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";
44504
+ 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>` — Delete a subscription\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";
44380
44505
 
44381
44506
  // ../../packages/warmhub-cli/src/domains/prime.ts
44382
44507
  function buildMarkdown(config) {
@@ -45605,6 +45730,9 @@ function renderShapeFieldDiff(out, diff) {
45605
45730
  }
45606
45731
  var retractFlags3 = {
45607
45732
  reason: flag.string({ description: "Reason for retraction (<=500 chars)" }),
45733
+ "expected-version": flag.number({
45734
+ description: "only retract if the target is still at this version (optimistic concurrency)"
45735
+ }),
45608
45736
  message: flag.string({ short: "m", description: "Commit message" }),
45609
45737
  committer: flag.string({
45610
45738
  description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
@@ -45681,16 +45809,18 @@ var handleRevise3 = async (ctx, { flags, args }) => {
45681
45809
  var handleRetract2 = async (ctx, { flags, args }) => {
45682
45810
  const shapeName = args[0];
45683
45811
  if (!shapeName) {
45684
- usageError("Usage: wh shape retract <name>", "wh shape retract Location");
45812
+ usageError("Usage: wh shape retract <name> [--expected-version <n>]", "wh shape retract Location");
45685
45813
  }
45686
45814
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
45815
+ const expectedVersion = parsePositiveIntFlag(flags["expected-version"], "--expected-version", "wh shape retract Location --expected-version 3");
45687
45816
  const c = ctx.colors;
45688
45817
  const result = await ctx.client.commit.apply(org, repo, flags.message ?? `retract shape ${shapeName}`, [
45689
45818
  {
45690
45819
  operation: "retract",
45691
45820
  kind: "shape",
45692
45821
  name: shapeName,
45693
- ...flags.reason ? { reason: flags.reason } : {}
45822
+ ...flags.reason ? { reason: flags.reason } : {},
45823
+ ...expectedVersion !== undefined ? { expectedVersion } : {}
45694
45824
  }
45695
45825
  ], { committer: flags.committer });
45696
45826
  assertSingleOpSuccess(result);
@@ -49203,7 +49333,7 @@ function resolveLogLevel(flagLevel, env) {
49203
49333
  // package.json
49204
49334
  var package_default3 = {
49205
49335
  name: "@warmhub/cli",
49206
- version: "0.85.0",
49336
+ version: "0.86.0",
49207
49337
  private: false,
49208
49338
  type: "module",
49209
49339
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -49820,5 +49950,5 @@ process.exitCode = interceptedExitCode === undefined ? await runPreparedCli(laun
49820
49950
  version: package_default3.version
49821
49951
  }) : interceptedExitCode;
49822
49952
 
49823
- //# debugId=F50B28EECDCA074C64756E2164756E21
49824
- //# warmhub-cli-build-info {"cliVersion":"0.85.0","sdkVersion":"0.83.0"}
49953
+ //# debugId=864ACFE03DA5766664756E2164756E21
49954
+ //# warmhub-cli-build-info {"cliVersion":"0.86.0","sdkVersion":"0.84.0"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.85.0",
3
+ "version": "0.86.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.",