@warmhub/cli 0.63.0 → 0.65.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 +350 -85
  2. package/package.json +2 -1
package/dist/wh.js CHANGED
@@ -18731,7 +18731,7 @@ function defaultMatchesCliArgType(type, value) {
18731
18731
  }
18732
18732
  function compileCliArgPattern(pattern) {
18733
18733
  try {
18734
- return new RegExp(pattern);
18734
+ return new RegExp(`^(?:${pattern})$`);
18735
18735
  } catch {
18736
18736
  return;
18737
18737
  }
@@ -27353,7 +27353,7 @@ function findSystemComponent(componentId) {
27353
27353
  // ../../packages/sdk-ts/package.json
27354
27354
  var package_default = {
27355
27355
  name: "@warmhub/sdk-ts",
27356
- version: "0.62.1",
27356
+ version: "0.64.0",
27357
27357
  private: false,
27358
27358
  type: "module",
27359
27359
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -27403,8 +27403,7 @@ var package_default = {
27403
27403
  }
27404
27404
  },
27405
27405
  scripts: {
27406
- prebuild: "tsc --noEmit",
27407
- build: "tsup && bun run scripts/inject-doc-links.ts",
27406
+ build: "tsc --noEmit && tsup && bun run scripts/inject-doc-links.ts",
27408
27407
  "generate:api-contract": "bun run scripts/generate-api-contract.ts",
27409
27408
  "generate:backend-types": "bun run scripts/generate-backend-types.ts",
27410
27409
  "audit:api-contract": "bun run scripts/audit-api-contract.ts",
@@ -28352,6 +28351,15 @@ class WarmHubClient {
28352
28351
  }
28353
28352
  }
28354
28353
  };
28354
+ homepage = {
28355
+ featuredLists: async () => {
28356
+ try {
28357
+ return await this.trpc.homepage.featuredLists.query();
28358
+ } catch (error) {
28359
+ throw toWarmHubError(error);
28360
+ }
28361
+ }
28362
+ };
28355
28363
  access = {
28356
28364
  resolve: async (input) => {
28357
28365
  try {
@@ -29194,24 +29202,26 @@ class WarmHubClient {
29194
29202
  throw toWarmHubError(error);
29195
29203
  }
29196
29204
  },
29197
- claimDelivery: async (orgName, repoName, runId, holderId) => {
29205
+ claimDelivery: async (orgName, repoName, target, holderId) => {
29206
+ const deliveryTarget = typeof target === "string" ? { runId: target } : target;
29198
29207
  try {
29199
29208
  return await this.trpc.action.claimDelivery.mutate({
29200
29209
  orgName,
29201
29210
  repoName,
29202
- runId,
29211
+ ...deliveryTarget,
29203
29212
  holderId
29204
29213
  });
29205
29214
  } catch (error) {
29206
29215
  throw toWarmHubError(error);
29207
29216
  }
29208
29217
  },
29209
- completeDelivery: async (orgName, repoName, runId, holderId) => {
29218
+ completeDelivery: async (orgName, repoName, target, holderId) => {
29219
+ const deliveryTarget = typeof target === "string" ? { runId: target } : target;
29210
29220
  try {
29211
29221
  return await this.trpc.action.completeDelivery.mutate({
29212
29222
  orgName,
29213
29223
  repoName,
29214
- runId,
29224
+ ...deliveryTarget,
29215
29225
  holderId
29216
29226
  });
29217
29227
  } catch (error) {
@@ -30572,11 +30582,25 @@ function safeParseJson(input, label, options) {
30572
30582
  function parseJsonObject(input, label, options) {
30573
30583
  const parsed = safeParseJson(input, label, options);
30574
30584
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
30575
- const got = Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed;
30585
+ const got = describeJsonType(parsed);
30576
30586
  throw new CliError(2 /* UserInput */, "USER_INPUT", `${label} must be a JSON object, got ${got}`, undefined, `Pass an object, e.g. '{"key":"value"}'.`);
30577
30587
  }
30578
30588
  return parsed;
30579
30589
  }
30590
+ function parseJsonArray(input, label, options) {
30591
+ const parsed = safeParseJson(input, label, options);
30592
+ if (!Array.isArray(parsed)) {
30593
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `${label} must be a JSON array, got ${describeJsonType(parsed)}`, undefined, `Pass an array of operations, e.g. '[{"operation":"add","kind":"thing","name":"Shape/item","data":{}}]'.`);
30594
+ }
30595
+ return parsed;
30596
+ }
30597
+ function describeJsonType(value) {
30598
+ if (Array.isArray(value))
30599
+ return "array";
30600
+ if (value === null)
30601
+ return "null";
30602
+ return typeof value;
30603
+ }
30580
30604
  function parsePositiveIntFlag(value, label, example) {
30581
30605
  if (value !== undefined && (!Number.isInteger(value) || value < 1)) {
30582
30606
  usageError(`${label} must be a positive integer`, example);
@@ -32352,7 +32376,7 @@ class DomainRegistry {
32352
32376
  }
32353
32377
  const verbs = {};
32354
32378
  for (const [verbName, v] of Object.entries(def.verbs)) {
32355
- verbs[verbName] = {
32379
+ const verbSpec = {
32356
32380
  status: v.status ?? "live",
32357
32381
  prime: v.prime ?? false,
32358
32382
  summary: v.summary,
@@ -32363,6 +32387,13 @@ class DomainRegistry {
32363
32387
  verbAliases: v.verbAliases,
32364
32388
  passthroughFlags: v.passthroughFlags
32365
32389
  };
32390
+ if (v.rejectedFlags) {
32391
+ Object.defineProperty(verbSpec, "rejectedFlags", {
32392
+ value: v.rejectedFlags,
32393
+ enumerable: false
32394
+ });
32395
+ }
32396
+ verbs[verbName] = verbSpec;
32366
32397
  }
32367
32398
  const subdomains = def.subdomains ? Object.fromEntries(Object.entries(def.subdomains).map(([k, sd]) => [
32368
32399
  k,
@@ -32662,20 +32693,88 @@ function extractShapeName(name) {
32662
32693
  const slash = name.indexOf("/");
32663
32694
  return slash > 0 ? name.slice(0, slash) : "";
32664
32695
  }
32696
+ var DANGEROUS_TERMINAL_FORMAT_CODEPOINTS = new Set([
32697
+ 8203,
32698
+ 8204,
32699
+ 8205,
32700
+ 8288,
32701
+ 8294,
32702
+ 8295,
32703
+ 8296,
32704
+ 8297,
32705
+ 8234,
32706
+ 8235,
32707
+ 8236,
32708
+ 8237,
32709
+ 8238,
32710
+ 8232,
32711
+ 8233
32712
+ ]);
32713
+ function isTerminalControlCodePoint(codePoint) {
32714
+ return codePoint <= 31 || codePoint === 127 || codePoint >= 128 && codePoint <= 159;
32715
+ }
32716
+ function escapeTerminalCodePoint(codePoint) {
32717
+ return codePoint <= 65535 ? `\\u${codePoint.toString(16).padStart(4, "0")}` : `\\u{${codePoint.toString(16)}}`;
32718
+ }
32719
+ function terminalTextNeedsEscape(value) {
32720
+ for (const char of value) {
32721
+ const codePoint = char.codePointAt(0);
32722
+ if (codePoint === undefined)
32723
+ continue;
32724
+ if (isTerminalControlCodePoint(codePoint))
32725
+ return true;
32726
+ if (DANGEROUS_TERMINAL_FORMAT_CODEPOINTS.has(codePoint))
32727
+ return true;
32728
+ }
32729
+ return false;
32730
+ }
32731
+ function escapeTerminalTextForDisplay(value) {
32732
+ if (!terminalTextNeedsEscape(value))
32733
+ return value;
32734
+ const jsonEscaped = JSON.stringify(value).slice(1, -1);
32735
+ let output = "";
32736
+ for (const char of jsonEscaped) {
32737
+ const codePoint = char.codePointAt(0);
32738
+ if (codePoint === undefined)
32739
+ continue;
32740
+ output += isTerminalControlCodePoint(codePoint) || DANGEROUS_TERMINAL_FORMAT_CODEPOINTS.has(codePoint) ? escapeTerminalCodePoint(codePoint) : char;
32741
+ }
32742
+ return output;
32743
+ }
32665
32744
  var escapeInlineTerminalText = escapeFieldNameForDisplay;
32666
32745
  function renderWarningLine(out, c, chars, op) {
32667
32746
  const warnings = op.warnings;
32668
- if (!warnings || warnings.undeclaredFields.length === 0)
32747
+ if (!warnings)
32669
32748
  return;
32670
- const shapeName = extractShapeName(op.name);
32671
- const total = warnings.totalUndeclared ?? warnings.undeclaredFields.length;
32749
+ renderUndeclaredFieldsWarning(out, c, chars, op.name, warnings);
32750
+ renderCoalescedWrefsWarning(out, c, chars, warnings);
32751
+ }
32752
+ function renderUndeclaredFieldsWarning(out, c, chars, opName, warnings) {
32753
+ const undeclaredFields = warnings.undeclaredFields;
32754
+ if (!undeclaredFields || undeclaredFields.length === 0)
32755
+ return;
32756
+ const shapeName = extractShapeName(opName);
32757
+ const total = warnings.totalUndeclared ?? undeclaredFields.length;
32672
32758
  const noun = total === 1 ? "field" : "fields";
32673
32759
  const shapeLabel = shapeName ? ` ${shapeName}` : "";
32674
- const remaining = warnings.undeclaredFieldsTruncated ? total - warnings.undeclaredFields.length : 0;
32675
- const fieldsList = warnings.undeclaredFields.map(escapeInlineTerminalText).join(", ");
32760
+ const remaining = warnings.undeclaredFieldsTruncated ? total - undeclaredFields.length : 0;
32761
+ const fieldsList = undeclaredFields.map(escapeInlineTerminalText).join(", ");
32676
32762
  const moreSuffix = remaining > 0 ? ` ${c.dim}(+${remaining} more)${c.reset}` : "";
32677
32763
  out(` ${c.yellow}${chars.warn}${c.reset} ${total} ${noun} not declared in shape${shapeLabel}: ${c.dim}${fieldsList}${c.reset}${moreSuffix}`);
32678
32764
  }
32765
+ function renderCoalescedWrefsWarning(out, c, chars, warnings) {
32766
+ const coalescedWrefs = warnings.coalescedWrefs;
32767
+ if (!coalescedWrefs || coalescedWrefs.length === 0)
32768
+ return;
32769
+ for (const entry of coalescedWrefs) {
32770
+ out(` ${c.yellow}${chars.warn}${c.reset} coalesced wref ${escapeInlineTerminalText(entry.fieldPath)}: ${c.dim}${escapeInlineTerminalText(entry.wref)}${c.reset} (${escapeInlineTerminalText(entry.reason)})`);
32771
+ }
32772
+ const total = warnings.totalCoalescedWrefs ?? coalescedWrefs.length;
32773
+ const remaining = warnings.coalescedWrefsTruncated ? total - coalescedWrefs.length : 0;
32774
+ if (remaining > 0) {
32775
+ out(` ${c.dim}(+${remaining} more coalesced wrefs)${c.reset}`);
32776
+ }
32777
+ }
32679
32778
  function renderCommitterEcho(out, c, committer) {
32680
32779
  if (!committer)
32681
32780
  return;
@@ -34269,10 +34368,10 @@ var searchFlags = {
34269
34368
  cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
34270
34369
  all: flag.boolean({ description: "Fetch all pages (text mode)" }),
34271
34370
  component: flag.string({
34272
- description: "Filter to things owned by this component (Org/Name ref)"
34371
+ description: "Filter to things owned by this component (Org/Name ref, text mode)"
34273
34372
  }),
34274
34373
  "exclude-components": flag.boolean({
34275
- description: "Exclude component-owned things from results"
34374
+ description: "Exclude component-owned things from results (text mode)"
34276
34375
  })
34277
34376
  };
34278
34377
  var handleSearch = async (ctx, { flags, args }) => {
@@ -34306,10 +34405,14 @@ var handleSearch = async (ctx, { flags, args }) => {
34306
34405
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedTextLimit;
34307
34406
  const resolveCollections = mode !== "hybrid" ? flags["resolve-collections"] : undefined;
34308
34407
  const supportsComponentFilters = !mode || mode === "text";
34309
- const componentRef = supportsComponentFilters ? flags.component : undefined;
34310
34408
  const hasShape = !!flags.shape;
34311
- const strictExclude = supportsComponentFilters ? !!flags["exclude-components"] : false;
34312
- validateComponentFilters(componentRef, strictExclude, 'wh thing search "policy" --component acme/veritas');
34409
+ const hasComponentFilter = flags.component !== undefined;
34410
+ const strictExclude = !!flags["exclude-components"];
34411
+ validateComponentFilters(flags.component, strictExclude, 'wh thing search "policy" --component acme/veritas');
34412
+ if (!supportsComponentFilters && (hasComponentFilter || strictExclude)) {
34413
+ usageError("--component/--exclude-components are only supported with text search mode.", 'wh thing search "policy" --mode text --component acme/veritas');
34414
+ }
34415
+ const componentRef = supportsComponentFilters ? flags.component : undefined;
34313
34416
  const excludeComponents = supportsComponentFilters && strictExclude ? true : undefined;
34314
34417
  const excludeInfraShapes = supportsComponentFilters && !strictExclude && !hasShape ? true : undefined;
34315
34418
  const rawResult = all ? await fetchAllSearchPages(ctx, org, repo, queryText, {
@@ -36060,7 +36163,7 @@ var HEADER_DELIMITER = `\r
36060
36163
  `;
36061
36164
  var CONTENT_LENGTH_RE = /^Content-Length:\s*(\d+)$/im;
36062
36165
  var MAX_MESSAGE_BYTES = 64 * 1024 * 1024;
36063
- function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES) {
36166
+ function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES, bufferByteLength) {
36064
36167
  const headerEnd = buffer.indexOf(HEADER_DELIMITER);
36065
36168
  if (headerEnd === -1)
36066
36169
  return null;
@@ -36073,11 +36176,36 @@ function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES) {
36073
36176
  throw new RangeError(`Content-Length ${contentLength} exceeds the maximum allowed ${maxContentLength} bytes`);
36074
36177
  }
36075
36178
  const bodyStart = headerEnd + HEADER_DELIMITER.length;
36076
- const remaining = Buffer.from(buffer.slice(bodyStart), "utf8");
36077
- if (remaining.length < contentLength)
36179
+ const bodyStartBytes = Buffer.byteLength(buffer.slice(0, bodyStart), "utf8");
36180
+ const totalBytes = bufferByteLength ?? Buffer.byteLength(buffer, "utf8");
36181
+ if (totalBytes - bodyStartBytes < contentLength)
36078
36182
  return null;
36079
- const body = remaining.subarray(0, contentLength).toString("utf8");
36080
- return { message: JSON.parse(body), consumed: bodyStart + body.length };
36183
+ const bodyEnd = findUtf8ByteBoundary(buffer, bodyStart, contentLength);
36184
+ if (bodyEnd === null)
36185
+ return null;
36186
+ const body = buffer.slice(bodyStart, bodyEnd);
36187
+ return { message: JSON.parse(body), consumed: bodyEnd };
36188
+ }
36189
+ function findUtf8ByteBoundary(value, start, targetBytes) {
36190
+ let bytes = 0;
36191
+ let index = start;
36192
+ while (index < value.length && bytes < targetBytes) {
36193
+ const codePoint = value.codePointAt(index);
36194
+ if (codePoint === undefined)
36195
+ return null;
36196
+ bytes += utf8CodePointByteLength(codePoint);
36197
+ index += codePoint > 65535 ? 2 : 1;
36198
+ }
36199
+ return bytes === targetBytes ? index : null;
36200
+ }
36201
+ function utf8CodePointByteLength(codePoint) {
36202
+ if (codePoint <= 127)
36203
+ return 1;
36204
+ if (codePoint <= 2047)
36205
+ return 2;
36206
+ if (codePoint <= 65535)
36207
+ return 3;
36208
+ return 4;
36081
36209
  }
36082
36210
  function parseNdjsonMessage(buffer) {
36083
36211
  const newlineIdx = buffer.indexOf(`
@@ -36125,7 +36253,7 @@ function createMessageReader(input, onMessage, onError = () => {}, maxMessageByt
36125
36253
  }
36126
36254
  let result;
36127
36255
  try {
36128
- result = mode === "ndjson" ? parseNdjsonMessage(buffer) : parseFramedMessage(buffer, maxMessageBytes);
36256
+ result = mode === "ndjson" ? parseNdjsonMessage(buffer) : parseFramedMessage(buffer, maxMessageBytes, bufferBytes);
36129
36257
  } catch (err) {
36130
36258
  if (err instanceof RangeError) {
36131
36259
  onError(err);
@@ -36187,27 +36315,47 @@ function createMessageReader(input, onMessage, onError = () => {}, maxMessageByt
36187
36315
  var MCP_PROTOCOL_VERSION2 = "2025-11-25";
36188
36316
  function createChannelServer(opts) {
36189
36317
  let reader = null;
36318
+ let removeInputCloseListeners = () => {};
36190
36319
  let resolveReady;
36191
36320
  let rejectReady;
36192
36321
  let readySettled = false;
36322
+ let resolveClosed;
36323
+ let closedSettled = false;
36193
36324
  const onReady = new Promise((resolve, reject) => {
36194
36325
  resolveReady = resolve;
36195
36326
  rejectReady = reject;
36196
36327
  });
36328
+ const onClosed = new Promise((resolve) => {
36329
+ resolveClosed = resolve;
36330
+ });
36197
36331
  function settleReady() {
36198
36332
  if (readySettled)
36199
36333
  return;
36200
36334
  readySettled = true;
36201
36335
  resolveReady();
36202
36336
  }
36203
- function failReady(error) {
36204
- if (readySettled)
36337
+ function settleClosed() {
36338
+ if (closedSettled)
36205
36339
  return;
36206
- readySettled = true;
36340
+ closedSettled = true;
36341
+ removeInputCloseListeners();
36207
36342
  reader?.close();
36208
- rejectReady(error);
36343
+ resolveClosed();
36344
+ }
36345
+ function closeServer() {
36346
+ settleClosed();
36347
+ settleReady();
36348
+ }
36349
+ function failReady(error) {
36350
+ if (!readySettled) {
36351
+ readySettled = true;
36352
+ rejectReady(error);
36353
+ }
36354
+ settleClosed();
36209
36355
  }
36210
36356
  function send(msg) {
36357
+ if (closedSettled)
36358
+ return;
36211
36359
  opts.output.write(ndjsonMessage(msg));
36212
36360
  }
36213
36361
  function handleMessage(msg) {
@@ -36246,6 +36394,13 @@ function createChannelServer(opts) {
36246
36394
  }
36247
36395
  return {
36248
36396
  start() {
36397
+ const handleInputClose = () => closeServer();
36398
+ opts.input.on("end", handleInputClose);
36399
+ opts.input.on("close", handleInputClose);
36400
+ removeInputCloseListeners = () => {
36401
+ opts.input.removeListener("end", handleInputClose);
36402
+ opts.input.removeListener("close", handleInputClose);
36403
+ };
36249
36404
  reader = createMessageReader(opts.input, handleMessage, failReady);
36250
36405
  },
36251
36406
  notify(content, meta) {
@@ -36256,14 +36411,15 @@ function createChannelServer(opts) {
36256
36411
  });
36257
36412
  },
36258
36413
  onReady,
36414
+ onClosed,
36259
36415
  close() {
36260
- reader?.close();
36261
- settleReady();
36416
+ closeServer();
36262
36417
  }
36263
36418
  };
36264
36419
  }
36265
36420
 
36266
36421
  // ../../packages/warmhub-cli/src/domains/channel.ts
36422
+ var RECONNECT_DELAY_MS = 2000;
36267
36423
  function formatChannelEvent(org, repo, event) {
36268
36424
  const things = event.affectedThings.join(", ");
36269
36425
  const shapes = event.affectedShapes.join(",");
@@ -36280,6 +36436,22 @@ function formatChannelEvent(org, repo, event) {
36280
36436
  };
36281
36437
  }
36282
36438
  async function subscribeLoop(client, org, repo, signal, server) {
36439
+ const pauseBeforeReconnect = () => new Promise((resolve) => {
36440
+ if (signal.aborted) {
36441
+ resolve();
36442
+ return;
36443
+ }
36444
+ let timeout;
36445
+ const onAbort = () => {
36446
+ clearTimeout(timeout);
36447
+ resolve();
36448
+ };
36449
+ timeout = setTimeout(() => {
36450
+ signal.removeEventListener("abort", onAbort);
36451
+ resolve();
36452
+ }, RECONNECT_DELAY_MS);
36453
+ signal.addEventListener("abort", onAbort, { once: true });
36454
+ });
36283
36455
  while (!signal.aborted) {
36284
36456
  try {
36285
36457
  const handle = await client.live.subscribe(org, repo, { signal }, (event) => {
@@ -36287,6 +36459,8 @@ async function subscribeLoop(client, org, repo, signal, server) {
36287
36459
  server.notify(content, meta);
36288
36460
  });
36289
36461
  await handle.closed;
36462
+ if (!signal.aborted)
36463
+ await pauseBeforeReconnect();
36290
36464
  } catch (err) {
36291
36465
  if (signal.aborted)
36292
36466
  break;
@@ -36294,7 +36468,7 @@ async function subscribeLoop(client, org, repo, signal, server) {
36294
36468
  if (msg.includes("401") || msg.includes("403") || msg.includes("404") || msg.includes("AUTH") || msg.includes("not found") || msg.includes("Session expired")) {
36295
36469
  throw new Error(`${org}/${repo}: ${msg}`);
36296
36470
  }
36297
- await new Promise((r) => setTimeout(r, 2000));
36471
+ await pauseBeforeReconnect();
36298
36472
  }
36299
36473
  }
36300
36474
  }
@@ -36313,7 +36487,6 @@ var handleChannel = async (ctx) => {
36313
36487
  input: process.stdin,
36314
36488
  output: process.stdout
36315
36489
  });
36316
- server.start();
36317
36490
  const signal = ctx.signal ?? new AbortController().signal;
36318
36491
  const aborted = new Promise((resolve) => {
36319
36492
  if (signal.aborted)
@@ -36323,15 +36496,19 @@ var handleChannel = async (ctx) => {
36323
36496
  });
36324
36497
  let ready;
36325
36498
  try {
36326
- ready = await Promise.race([server.onReady.then(() => {
36327
- return;
36328
- }), aborted]);
36499
+ const startup = Promise.race([
36500
+ server.onClosed.then(() => "closed"),
36501
+ server.onReady.then(() => "ready"),
36502
+ aborted
36503
+ ]);
36504
+ server.start();
36505
+ ready = await startup;
36329
36506
  } catch (err) {
36330
36507
  server.close();
36331
36508
  const msg = err instanceof Error ? err.message : String(err);
36332
36509
  throw new CliError(4 /* Backend */, "BACKEND", `channel startup failed: ${msg}`);
36333
36510
  }
36334
- if (ready === "aborted") {
36511
+ if (ready !== "ready") {
36335
36512
  server.close();
36336
36513
  return;
36337
36514
  }
@@ -36342,7 +36519,11 @@ var handleChannel = async (ctx) => {
36342
36519
  signal.addEventListener("abort", () => controller.abort(), { once: true });
36343
36520
  let fatal;
36344
36521
  try {
36345
- await Promise.all(repos.map(({ org, repo }) => subscribeLoop(ctx.client, org, repo, controller.signal, server)));
36522
+ const subscriptions = Promise.all(repos.map(({ org, repo }) => subscribeLoop(ctx.client, org, repo, controller.signal, server)));
36523
+ const closed = server.onClosed.then(() => {
36524
+ controller.abort();
36525
+ });
36526
+ await Promise.race([subscriptions, closed]);
36346
36527
  } catch (err) {
36347
36528
  controller.abort();
36348
36529
  fatal = err;
@@ -36373,7 +36554,7 @@ var CHANNEL_DOMAIN = defineDomain({
36373
36554
  // ../../packages/warmhub-cli/src/domains/commit-submit-flags.ts
36374
36555
  var createFlags3 = {
36375
36556
  ops: flag.string({
36376
- description: "Operations JSON (inline). For ops from a file, use -f/--file <path> instead; --ops accepts inline JSON only."
36557
+ description: "Operations JSON array (inline). For ops from a file, use -f/--file <path> instead; --ops accepts an inline JSON array only."
36377
36558
  }),
36378
36559
  file: flag.string({
36379
36560
  short: "f",
@@ -37461,7 +37642,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
37461
37642
  }
37462
37643
  ];
37463
37644
  } else if (opsJson) {
37464
- operations = safeParseJson(opsJson, "--ops", {
37645
+ operations = parseJsonArray(opsJson, "--ops", {
37465
37646
  fileFlagSibling: "-f/--file"
37466
37647
  });
37467
37648
  } else if (opsFile) {
@@ -37474,7 +37655,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
37474
37655
  } catch (e) {
37475
37656
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Cannot read file '${opsFile}': ${e instanceof Error ? e.message : String(e)}`, undefined, "Check that the file path is correct and the file exists.");
37476
37657
  }
37477
- operations = safeParseJson(file, "--file contents");
37658
+ operations = parseJsonArray(file, "--file contents");
37478
37659
  }
37479
37660
  } else if (addNames.length > 0) {
37480
37661
  operations = buildAddOperations({
@@ -37721,6 +37902,24 @@ function isInstallSnapshotCacheShape(value) {
37721
37902
  if (!Array.isArray(component.methods))
37722
37903
  return false;
37723
37904
  }
37905
+ if (!isPlainObject2(value.installs))
37906
+ return false;
37907
+ const installs = value.installs;
37908
+ for (const entry of Object.values(installs)) {
37909
+ if (!isPlainObject2(entry))
37910
+ return false;
37911
+ const install = entry;
37912
+ if (typeof install.ref !== "string")
37913
+ return false;
37914
+ if (typeof install.version !== "string")
37915
+ return false;
37916
+ if (install.latestVersion !== undefined && typeof install.latestVersion !== "string") {
37917
+ return false;
37918
+ }
37919
+ if (install.updateAvailable !== undefined && typeof install.updateAvailable !== "boolean") {
37920
+ return false;
37921
+ }
37922
+ }
37724
37923
  return true;
37725
37924
  }
37726
37925
 
@@ -37794,6 +37993,7 @@ async function refreshInstallSnapshotCache(repoSlug, client, opts) {
37794
37993
  }
37795
37994
  async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now, previousCache) {
37796
37995
  const components = {};
37996
+ const installs = {};
37797
37997
  let detailReadFailures = 0;
37798
37998
  for (const item of activeItems) {
37799
37999
  if (!item.ref)
@@ -37813,6 +38013,12 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
37813
38013
  const manifest = extractInstalledManifest(detail.install.data);
37814
38014
  if (!manifest)
37815
38015
  continue;
38016
+ installs[item.componentName] = {
38017
+ ref: itemRef,
38018
+ version: manifest.component.version ?? item.version ?? "",
38019
+ latestVersion: item.latestVersion,
38020
+ updateAvailable: item.updateAvailable
38021
+ };
37816
38022
  const methods = manifest.cli?.methods ?? [];
37817
38023
  if (methods.length === 0)
37818
38024
  continue;
@@ -37826,7 +38032,9 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
37826
38032
  version: manifest.component.version ?? item.version ?? "",
37827
38033
  description: manifest.cli?.description,
37828
38034
  manifestHash: item.manifestHash ?? "",
37829
- methods
38035
+ methods,
38036
+ latestVersion: item.latestVersion,
38037
+ updateAvailable: item.updateAvailable
37830
38038
  };
37831
38039
  }
37832
38040
  if (activeItems.length > 0 && detailReadFailures === activeItems.length) {
@@ -37838,7 +38046,8 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
37838
38046
  const cache = {
37839
38047
  cachedAt: now,
37840
38048
  repoSlug,
37841
- components
38049
+ components,
38050
+ installs
37842
38051
  };
37843
38052
  writeInstallSnapshotCache(repoSlug, cache);
37844
38053
  return cache;
@@ -38112,7 +38321,7 @@ function coerceArg(arg, value) {
38112
38321
  if (arg.pattern) {
38113
38322
  let re;
38114
38323
  try {
38115
- re = new RegExp(arg.pattern);
38324
+ re = new RegExp(`^(?:${arg.pattern})$`);
38116
38325
  } catch {
38117
38326
  throw new CliError(2 /* UserInput */, "USER_INPUT", `invalid regex pattern for --${arg.name}: /${arg.pattern}/`);
38118
38327
  }
@@ -38204,6 +38413,13 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
38204
38413
  const cache = await ensureFreshInstallSnapshotCache(installRepo, ctx.client);
38205
38414
  const entry = cache.components[componentName];
38206
38415
  if (!entry) {
38416
+ const install = cache.installs[componentName];
38417
+ if (install?.updateAvailable && install.latestVersion) {
38418
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${componentName}' is installed at ${install.version || "an older version"} in ${installRepo}, which exposes no CLI method${methodName ? ` '${methodName}'` : "s"}.`, undefined, `Version ${install.latestVersion} is available — run 'wh component update ${install.ref} --repo ${installRepo}', then 'wh component exec ${componentName} --help' to see its methods.`);
38419
+ }
38420
+ if (install) {
38421
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${componentName}' is installed in ${installRepo} but exposes no CLI methods.`);
38422
+ }
38207
38423
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${componentName}' is not installed in ${installRepo}.`, undefined, `Run 'wh component install <ref> --repo ${installRepo}' first.`);
38208
38424
  }
38209
38425
  if (!methodName) {
@@ -38215,7 +38431,9 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
38215
38431
  }
38216
38432
  const method = entry.methods.find((m) => m.name === methodName);
38217
38433
  if (!method) {
38218
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Method '${methodName}' not found on component '${componentName}'.`, undefined, `Available: ${entry.methods.map((m) => m.name).join(", ")}. Run wh component update ${entry.ref} --repo ${installRepo} if you expect a newer method.`);
38434
+ const available = entry.methods.map((m) => m.name).join(", ");
38435
+ const updateHint = entry.updateAvailable && entry.latestVersion ? `Version ${entry.latestVersion} is available — run wh component update ${entry.ref} --repo ${installRepo} for newer methods.` : `Run wh component update ${entry.ref} --repo ${installRepo} if you expect a newer method.`;
38436
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Method '${methodName}' not found on component '${componentName}'.`, undefined, `Available: ${available}. ${updateHint}`);
38219
38437
  }
38220
38438
  if (helpRequested) {
38221
38439
  renderMethodHelp(ctx, componentName, method);
@@ -38864,7 +39082,8 @@ var handleView3 = async (ctx, { args }) => {
38864
39082
  writeOutput(ctx, viewData, () => {
38865
39083
  const c = ctx.colors;
38866
39084
  ctx.out(`${c.bold}Component:${c.reset} ${c.cyan}${viewData.ref ?? ref}${c.reset}`);
38867
- ctx.out(`${c.bold}Version:${c.reset} ${viewData.version ?? "unknown"}`);
39085
+ const update = viewData.updateAvailable && viewData.latestVersion ? ` ${c.yellow}(${viewData.latestVersion} available — run wh component update ${viewData.ref ?? ref} --repo ${org}/${repo})${c.reset}` : "";
39086
+ ctx.out(`${c.bold}Version:${c.reset} ${viewData.version ?? "unknown"}${update}`);
38868
39087
  ctx.out(`${c.bold}State:${c.reset} ${viewData.state ?? "-"}`);
38869
39088
  ctx.out(`${c.bold}Source:${c.reset} ${viewData.source ?? "-"}`);
38870
39089
  if (viewData.ownedShapes.length > 0) {
@@ -39121,6 +39340,22 @@ async function doctorComponent(client, org, repo, componentId) {
39121
39340
  });
39122
39341
  }
39123
39342
  }
39343
+ try {
39344
+ const detail = await client.component.get(org, repo, registeredComponentRef);
39345
+ if (detail.updateAvailable === true && detail.latestVersion) {
39346
+ findings.push({
39347
+ resource: "version",
39348
+ status: "warning",
39349
+ message: `Installed ${detail.version ?? "version"}; ${detail.latestVersion} available — run wh component update ${registeredComponentRef} --repo ${org}/${repo}`
39350
+ });
39351
+ } else if (detail.updateAvailable === false && detail.version) {
39352
+ findings.push({
39353
+ resource: "version",
39354
+ status: "ok",
39355
+ message: `Up to date (${detail.version})`
39356
+ });
39357
+ }
39358
+ } catch {}
39124
39359
  const hasMissing = findings.some((f) => f.status === "missing");
39125
39360
  const hasInactive = findings.some((f) => f.status === "inactive" && !f.resource.startsWith("sub:"));
39126
39361
  const hasShapeDrift = findings.some((f) => f.resource.startsWith("shape:") && f.status === "warning" && f.message.includes("differs from installed manifest"));
@@ -39133,21 +39368,23 @@ async function doctorComponent(client, org, repo, componentId) {
39133
39368
  } else {
39134
39369
  state = "ready";
39135
39370
  }
39136
- try {
39137
- await client.commit.apply(org, repo, `Doctor: update ${componentName} state to ${state}`, [
39138
- {
39139
- operation: "revise",
39140
- kind: "thing",
39141
- name: `ComponentInstall/${componentId}`,
39142
- data: { ...installData, state, checkedAt: new Date().toISOString() }
39143
- }
39144
- ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
39145
- } catch {
39146
- findings.push({
39147
- resource: "state-update",
39148
- status: "warning",
39149
- message: "Failed to persist computed state"
39150
- });
39371
+ if (state !== existingState) {
39372
+ try {
39373
+ await client.commit.apply(org, repo, `Doctor: update ${componentName} state to ${state}`, [
39374
+ {
39375
+ operation: "revise",
39376
+ kind: "thing",
39377
+ name: `ComponentInstall/${componentId}`,
39378
+ data: { ...installData, state }
39379
+ }
39380
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
39381
+ } catch {
39382
+ findings.push({
39383
+ resource: "state-update",
39384
+ status: "warning",
39385
+ message: "Failed to persist computed state"
39386
+ });
39387
+ }
39151
39388
  }
39152
39389
  return { componentId, componentName, state, findings };
39153
39390
  }
@@ -39265,7 +39502,8 @@ var handleList2 = async (ctx, { flags }) => {
39265
39502
  const state = item.state ?? "unknown";
39266
39503
  const source = item.source ?? "-";
39267
39504
  const stateColor = stateToColor2(c, state);
39268
- ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
39505
+ const update = item.updateAvailable && item.latestVersion ? ` ${c.yellow}(${item.latestVersion} available)${c.reset}` : "";
39506
+ ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset}${update} ${source}`);
39269
39507
  }
39270
39508
  });
39271
39509
  };
@@ -40666,8 +40904,9 @@ function renderActionNotifications(out, statusOut, c, notifications) {
40666
40904
  const subscriptionName = notification.subscriptionName ? `${c.cyan}${notification.subscriptionName}${c.reset}` : `${c.dim}(unknown subscription)${c.reset}`;
40667
40905
  out(` ${status} ${c.dim}${time}${c.reset} ${subscriptionName} attempt #${notification.attempt} ${c.dim}${notification.channel}${c.reset}`);
40668
40906
  if (notification.errorMessage) {
40669
- const code = notification.errorCode ? `${notification.errorCode}: ` : "";
40670
- out(` ${c.red}${code}${notification.errorMessage}${c.reset}`);
40907
+ const code = notification.errorCode ? `${escapeTerminalTextForDisplay(notification.errorCode)}: ` : "";
40908
+ const message = escapeTerminalTextForDisplay(notification.errorMessage);
40909
+ out(` ${c.red}${code}${message}${c.reset}`);
40671
40910
  }
40672
40911
  }
40673
40912
  }
@@ -42244,7 +42483,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
42244
42483
  const data = version?.data;
42245
42484
  const shapeDesc = data?.description;
42246
42485
  if (typeof shapeDesc === "string" && shapeDesc) {
42247
- ctx.out(` ${c.dim}${shapeDesc}${c.reset}`);
42486
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDesc)}${c.reset}`);
42248
42487
  }
42249
42488
  const fields = data?.fields;
42250
42489
  if (fields) {
@@ -42256,9 +42495,10 @@ var handleDescribe = async (ctx, { args, flags }) => {
42256
42495
  return Math.max(m, ts.length);
42257
42496
  }, 0);
42258
42497
  for (const [fieldName, fieldType] of entries) {
42498
+ const safeFieldName = escapeFieldNameForDisplay(fieldName);
42259
42499
  const typeStr = displayFieldType(fieldType);
42260
42500
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42261
- const line = fieldDesc ? ` ${c.cyan}${fieldName.padEnd(maxName)}${c.reset} ${c.dim}${typeStr.padEnd(maxType)}${c.reset} ${fieldDesc}` : ` ${c.cyan}${fieldName.padEnd(maxName)}${c.reset} ${c.dim}${typeStr}${c.reset}`;
42501
+ const line = fieldDesc ? ` ${c.cyan}${safeFieldName.padEnd(maxName)}${c.reset} ${c.dim}${typeStr.padEnd(maxType)}${c.reset} ${escapeTerminalTextForDisplay(fieldDesc)}` : ` ${c.cyan}${safeFieldName.padEnd(maxName)}${c.reset} ${c.dim}${typeStr}${c.reset}`;
42262
42502
  ctx.out(line);
42263
42503
  }
42264
42504
  }
@@ -42647,7 +42887,7 @@ var handleList6 = async (ctx, { flags }) => {
42647
42887
  const shapeData = shape.version?.data;
42648
42888
  const shapeDescription = shapeData?.description;
42649
42889
  if (typeof shapeDescription === "string" && shapeDescription) {
42650
- ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
42890
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDescription)}${c.reset}`);
42651
42891
  }
42652
42892
  const fields = shapeData?.fields;
42653
42893
  if (fields) {
@@ -42662,7 +42902,7 @@ var handleList6 = async (ctx, { flags }) => {
42662
42902
  const typeStr = displayFieldType(fieldType);
42663
42903
  const padded = fieldName.padEnd(maxLen);
42664
42904
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42665
- const descSuffix = fieldDesc ? ` ${typeStr.padEnd(maxTypeLen)} ${fieldDesc}` : ` ${typeStr}`;
42905
+ const descSuffix = fieldDesc ? ` ${typeStr.padEnd(maxTypeLen)} ${escapeTerminalTextForDisplay(fieldDesc)}` : ` ${typeStr}`;
42666
42906
  ctx.out(` ${c.cyan}${padded}${c.reset} ${c.dim}${descSuffix}${c.reset}`);
42667
42907
  }
42668
42908
  }
@@ -42694,7 +42934,7 @@ var handleView7 = async (ctx, { flags, args }) => {
42694
42934
  const shapeData = shapeVersion?.data;
42695
42935
  const shapeDescription = shapeData?.description;
42696
42936
  if (typeof shapeDescription === "string" && shapeDescription) {
42697
- ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
42937
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDescription)}${c.reset}`);
42698
42938
  }
42699
42939
  const componentRef = result.componentRef;
42700
42940
  if (componentRef) {
@@ -42706,7 +42946,7 @@ var handleView7 = async (ctx, { flags, args }) => {
42706
42946
  for (const [fieldName, fieldType] of Object.entries(fields)) {
42707
42947
  const typeStr = displayFieldType(fieldType);
42708
42948
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42709
- const descSuffix = fieldDesc ? ` ${c.dim}${fieldDesc}${c.reset}` : "";
42949
+ const descSuffix = fieldDesc ? ` ${c.dim}${escapeTerminalTextForDisplay(fieldDesc)}${c.reset}` : "";
42710
42950
  const safeFieldName = escapeFieldNameForDisplay(fieldName);
42711
42951
  ctx.out(` ${c.cyan}${safeFieldName}${c.reset}: ${c.dim}${typeStr}${c.reset}${descSuffix}`);
42712
42952
  }
@@ -42807,8 +43047,10 @@ var handleShapeRename = async (ctx, { args }) => {
42807
43047
  }
42808
43048
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
42809
43049
  const c = ctx.colors;
42810
- await ctx.client.shape.rename(org, repo, oldName, newName);
42811
- ctx.out(`${c.green}Renamed shape${c.reset} ${c.magenta}${oldName}${c.reset} ${c.magenta}${newName}${c.reset}`);
43050
+ const result = await ctx.client.shape.rename(org, repo, oldName, newName);
43051
+ writeOutput(ctx, { ...result, oldName, newName }, () => {
43052
+ ctx.out(`${c.green}Renamed shape${c.reset} ${c.magenta}${oldName}${c.reset} → ${c.magenta}${newName}${c.reset}`);
43053
+ });
42812
43054
  };
42813
43055
 
42814
43056
  // ../../packages/warmhub-cli/src/domains/shape.ts
@@ -43265,6 +43507,11 @@ function renderResponseSnippet(out, c, snippet, baseIndent) {
43265
43507
  out(`${baseIndent} ${c.dim}${line}${c.reset}`);
43266
43508
  }
43267
43509
  }
43510
+ function renderErrorMessageLine(out, c, code, message, baseIndent) {
43511
+ const safeCode = code ? `${escapeTerminalTextForDisplay(code)}: ` : "";
43512
+ const safeMessage = escapeTerminalTextForDisplay(message);
43513
+ out(`${baseIndent}${c.red}${safeCode}${safeMessage}${c.reset}`);
43514
+ }
43268
43515
  function statusColor(c, status) {
43269
43516
  switch (status) {
43270
43517
  case "completed":
@@ -43305,11 +43552,10 @@ function renderSubscriptionLog(out, statusOut, c, subscriptionName, result) {
43305
43552
  const sourceLabel = (item.matchedOperationIndexes?.length ?? 0) > 0 ? `${c.cyan}write${c.reset}` : `${c.magenta}cron tick${c.reset}`;
43306
43553
  const matched = (item.matchedOperationIndexes ?? []).join(",") || "-";
43307
43554
  const attemptSuffix = item.attemptCount != null && item.maxAttempts != null ? ` ${c.dim}${item.attemptCount}/${item.maxAttempts}${c.reset}` : "";
43308
- const runSuffix = item.runId ? ` ${c.dim}run ${item.runId}${c.reset}` : "";
43309
- out(` ${status}${attemptSuffix} ${c.dim}${time}${c.reset}${runSuffix} ${sourceLabel} ops[${matched}]`);
43555
+ const idSuffix = item.runId ? ` ${c.dim}run ${item.runId}${c.reset}` : item.deliveryId ? ` ${c.dim}delivery ${item.deliveryId}${c.reset}` : "";
43556
+ out(` ${status}${attemptSuffix} ${c.dim}${time}${c.reset}${idSuffix} ${sourceLabel} ops[${matched}]`);
43310
43557
  if ((displayStatus === "failed_terminal" || displayStatus === "dead_letter") && item.lastErrorMessage) {
43311
- const code = item.lastErrorCode ? `${item.lastErrorCode}: ` : "";
43312
- out(` ${c.red}${code}${item.lastErrorMessage}${c.reset}`);
43558
+ renderErrorMessageLine(out, c, item.lastErrorCode, item.lastErrorMessage, " ");
43313
43559
  }
43314
43560
  if ((displayStatus === "failed_terminal" || displayStatus === "dead_letter") && item.lastResponseSnippet) {
43315
43561
  renderResponseSnippet(out, c, item.lastResponseSnippet, " ");
@@ -43420,7 +43666,12 @@ var handleLog = async (ctx, { flags, args }) => {
43420
43666
  if (!name) {
43421
43667
  usageError("Usage: wh sub log <name> [--repo org/repo]", "wh sub log my-sub");
43422
43668
  }
43423
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
43669
+ const scope = resolveSubScope(ctx, flags);
43670
+ if (!scope.repoName) {
43671
+ usageError("Usage: wh sub log <name> [--repo org/repo]", "wh sub log my-sub --repo myorg/myrepo");
43672
+ }
43673
+ const org = scope.orgName;
43674
+ const repo = scope.repoName;
43424
43675
  if (ctx.liveMode) {
43425
43676
  await runLive({
43426
43677
  apiUrl: ctx.config.apiUrl,
@@ -43464,8 +43715,7 @@ var handleAttempts = async (ctx, { args }) => {
43464
43715
  const http = attempt.httpStatus ? ` ${c.dim}HTTP ${attempt.httpStatus}${c.reset}` : "";
43465
43716
  ctx.out(` #${attempt.attempt} ${sc}${attempt.status}${c.reset}${dur}${http}`);
43466
43717
  if (attempt.errorMessage) {
43467
- const code = attempt.errorCode ? `${attempt.errorCode}: ` : "";
43468
- ctx.out(` ${c.red}${code}${attempt.errorMessage}${c.reset}`);
43718
+ renderErrorMessageLine(ctx.out, c, attempt.errorCode, attempt.errorMessage, " ");
43469
43719
  }
43470
43720
  if (attempt.status === "failed" && attempt.responseSnippet) {
43471
43721
  renderResponseSnippet(ctx.out, c, attempt.responseSnippet, " ");
@@ -43558,6 +43808,9 @@ var SUB_DOMAIN = defineDomain({
43558
43808
  summary: "Tail subscription delivery feed with failed response snippets",
43559
43809
  args: "<name>",
43560
43810
  flags: logFlags,
43811
+ rejectedFlags: {
43812
+ org: "Use repo-scoped delivery logs: wh sub log my-sub --repo myorg/myrepo"
43813
+ },
43561
43814
  examples: [
43562
43815
  "# Show recent deliveries",
43563
43816
  " $ wh sub log signal-hook --repo org/repo",
@@ -43566,7 +43819,10 @@ var SUB_DOMAIN = defineDomain({
43566
43819
  " $ wh sub log daily-digest --repo org/repo",
43567
43820
  "",
43568
43821
  "# Follow deliveries in live mode",
43569
- " $ wh sub log signal-hook --repo org/repo --live"
43822
+ " $ wh sub log signal-hook --repo org/repo --live",
43823
+ "",
43824
+ "# Delivery logs currently require a repo-scoped subscription",
43825
+ " $ wh sub log signal-hook --repo org/repo"
43570
43826
  ],
43571
43827
  handler: handleLog
43572
43828
  },
@@ -44523,9 +44779,9 @@ function extractFlagsForVerb(flags, verbSpec) {
44523
44779
  }
44524
44780
  return flags;
44525
44781
  }
44526
- return extractFlags(flags, verbSpec.flags);
44782
+ return extractFlags(flags, verbSpec.flags, verbSpec.rejectedFlags);
44527
44783
  }
44528
- function extractFlags(flags, specs) {
44784
+ function extractFlags(flags, specs, rejectedFlags = {}) {
44529
44785
  const normalized = { ...flags };
44530
44786
  const result = {};
44531
44787
  const specLongs = specs.map((s) => s.long);
@@ -44560,11 +44816,19 @@ function extractFlags(flags, specs) {
44560
44816
  }
44561
44817
  for (const key of Object.keys(normalized)) {
44562
44818
  if (key.length === 1) {
44819
+ const rejectedHint2 = rejectedFlags[key];
44820
+ if (rejectedHint2) {
44821
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: -${key}`, undefined, rejectedHint2);
44822
+ }
44563
44823
  if (!allowedShorts.has(key) && !isGlobalFlag(key)) {
44564
44824
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: -${key}`);
44565
44825
  }
44566
44826
  continue;
44567
44827
  }
44828
+ const rejectedHint = rejectedFlags[key];
44829
+ if (rejectedHint) {
44830
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: --${key}`, undefined, rejectedHint);
44831
+ }
44568
44832
  if (!allowedLongs.has(key) && !isGlobalFlag(key)) {
44569
44833
  const hint = findClosest(key, [...allowedLongs]);
44570
44834
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: --${key}`, undefined, hint ? `Did you mean '--${hint}'?` : undefined);
@@ -45574,7 +45838,7 @@ function resolveLogLevel(flags, env) {
45574
45838
  // package.json
45575
45839
  var package_default3 = {
45576
45840
  name: "@warmhub/cli",
45577
- version: "0.63.0",
45841
+ version: "0.65.0",
45578
45842
  private: false,
45579
45843
  type: "module",
45580
45844
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -45615,6 +45879,7 @@ var package_default3 = {
45615
45879
  },
45616
45880
  scripts: {
45617
45881
  build: "bun run scripts/build.ts",
45882
+ prepack: "bun run build",
45618
45883
  "check:boundary": "node ../../scripts/lint/boundary-imports.mjs bin src scripts",
45619
45884
  "audit:bundle": "bun run scripts/audit-bundle.ts",
45620
45885
  "audit:pack": "bun run scripts/audit-pack.ts",
@@ -46228,4 +46493,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
46228
46493
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
46229
46494
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
46230
46495
 
46231
- //# debugId=AA99DB1239BF58B064756E2164756E21
46496
+ //# debugId=B70D5B946B8CF0E364756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.63.0",
3
+ "version": "0.65.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.",
@@ -41,6 +41,7 @@
41
41
  },
42
42
  "scripts": {
43
43
  "build": "bun run scripts/build.ts",
44
+ "prepack": "bun run build",
44
45
  "check:boundary": "node ../../scripts/lint/boundary-imports.mjs bin src scripts",
45
46
  "audit:bundle": "bun run scripts/audit-bundle.ts",
46
47
  "audit:pack": "bun run scripts/audit-pack.ts",