@warmhub/cli 0.63.0 → 0.64.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 +248 -60
  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.63.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,6 +32693,54 @@ 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;
@@ -34269,10 +34348,10 @@ var searchFlags = {
34269
34348
  cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
34270
34349
  all: flag.boolean({ description: "Fetch all pages (text mode)" }),
34271
34350
  component: flag.string({
34272
- description: "Filter to things owned by this component (Org/Name ref)"
34351
+ description: "Filter to things owned by this component (Org/Name ref, text mode)"
34273
34352
  }),
34274
34353
  "exclude-components": flag.boolean({
34275
- description: "Exclude component-owned things from results"
34354
+ description: "Exclude component-owned things from results (text mode)"
34276
34355
  })
34277
34356
  };
34278
34357
  var handleSearch = async (ctx, { flags, args }) => {
@@ -34306,10 +34385,14 @@ var handleSearch = async (ctx, { flags, args }) => {
34306
34385
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedTextLimit;
34307
34386
  const resolveCollections = mode !== "hybrid" ? flags["resolve-collections"] : undefined;
34308
34387
  const supportsComponentFilters = !mode || mode === "text";
34309
- const componentRef = supportsComponentFilters ? flags.component : undefined;
34310
34388
  const hasShape = !!flags.shape;
34311
- const strictExclude = supportsComponentFilters ? !!flags["exclude-components"] : false;
34312
- validateComponentFilters(componentRef, strictExclude, 'wh thing search "policy" --component acme/veritas');
34389
+ const hasComponentFilter = flags.component !== undefined;
34390
+ const strictExclude = !!flags["exclude-components"];
34391
+ validateComponentFilters(flags.component, strictExclude, 'wh thing search "policy" --component acme/veritas');
34392
+ if (!supportsComponentFilters && (hasComponentFilter || strictExclude)) {
34393
+ usageError("--component/--exclude-components are only supported with text search mode.", 'wh thing search "policy" --mode text --component acme/veritas');
34394
+ }
34395
+ const componentRef = supportsComponentFilters ? flags.component : undefined;
34313
34396
  const excludeComponents = supportsComponentFilters && strictExclude ? true : undefined;
34314
34397
  const excludeInfraShapes = supportsComponentFilters && !strictExclude && !hasShape ? true : undefined;
34315
34398
  const rawResult = all ? await fetchAllSearchPages(ctx, org, repo, queryText, {
@@ -36060,7 +36143,7 @@ var HEADER_DELIMITER = `\r
36060
36143
  `;
36061
36144
  var CONTENT_LENGTH_RE = /^Content-Length:\s*(\d+)$/im;
36062
36145
  var MAX_MESSAGE_BYTES = 64 * 1024 * 1024;
36063
- function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES) {
36146
+ function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES, bufferByteLength) {
36064
36147
  const headerEnd = buffer.indexOf(HEADER_DELIMITER);
36065
36148
  if (headerEnd === -1)
36066
36149
  return null;
@@ -36073,11 +36156,36 @@ function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES) {
36073
36156
  throw new RangeError(`Content-Length ${contentLength} exceeds the maximum allowed ${maxContentLength} bytes`);
36074
36157
  }
36075
36158
  const bodyStart = headerEnd + HEADER_DELIMITER.length;
36076
- const remaining = Buffer.from(buffer.slice(bodyStart), "utf8");
36077
- if (remaining.length < contentLength)
36159
+ const bodyStartBytes = Buffer.byteLength(buffer.slice(0, bodyStart), "utf8");
36160
+ const totalBytes = bufferByteLength ?? Buffer.byteLength(buffer, "utf8");
36161
+ if (totalBytes - bodyStartBytes < contentLength)
36162
+ return null;
36163
+ const bodyEnd = findUtf8ByteBoundary(buffer, bodyStart, contentLength);
36164
+ if (bodyEnd === null)
36078
36165
  return null;
36079
- const body = remaining.subarray(0, contentLength).toString("utf8");
36080
- return { message: JSON.parse(body), consumed: bodyStart + body.length };
36166
+ const body = buffer.slice(bodyStart, bodyEnd);
36167
+ return { message: JSON.parse(body), consumed: bodyEnd };
36168
+ }
36169
+ function findUtf8ByteBoundary(value, start, targetBytes) {
36170
+ let bytes = 0;
36171
+ let index = start;
36172
+ while (index < value.length && bytes < targetBytes) {
36173
+ const codePoint = value.codePointAt(index);
36174
+ if (codePoint === undefined)
36175
+ return null;
36176
+ bytes += utf8CodePointByteLength(codePoint);
36177
+ index += codePoint > 65535 ? 2 : 1;
36178
+ }
36179
+ return bytes === targetBytes ? index : null;
36180
+ }
36181
+ function utf8CodePointByteLength(codePoint) {
36182
+ if (codePoint <= 127)
36183
+ return 1;
36184
+ if (codePoint <= 2047)
36185
+ return 2;
36186
+ if (codePoint <= 65535)
36187
+ return 3;
36188
+ return 4;
36081
36189
  }
36082
36190
  function parseNdjsonMessage(buffer) {
36083
36191
  const newlineIdx = buffer.indexOf(`
@@ -36125,7 +36233,7 @@ function createMessageReader(input, onMessage, onError = () => {}, maxMessageByt
36125
36233
  }
36126
36234
  let result;
36127
36235
  try {
36128
- result = mode === "ndjson" ? parseNdjsonMessage(buffer) : parseFramedMessage(buffer, maxMessageBytes);
36236
+ result = mode === "ndjson" ? parseNdjsonMessage(buffer) : parseFramedMessage(buffer, maxMessageBytes, bufferBytes);
36129
36237
  } catch (err) {
36130
36238
  if (err instanceof RangeError) {
36131
36239
  onError(err);
@@ -36187,27 +36295,47 @@ function createMessageReader(input, onMessage, onError = () => {}, maxMessageByt
36187
36295
  var MCP_PROTOCOL_VERSION2 = "2025-11-25";
36188
36296
  function createChannelServer(opts) {
36189
36297
  let reader = null;
36298
+ let removeInputCloseListeners = () => {};
36190
36299
  let resolveReady;
36191
36300
  let rejectReady;
36192
36301
  let readySettled = false;
36302
+ let resolveClosed;
36303
+ let closedSettled = false;
36193
36304
  const onReady = new Promise((resolve, reject) => {
36194
36305
  resolveReady = resolve;
36195
36306
  rejectReady = reject;
36196
36307
  });
36308
+ const onClosed = new Promise((resolve) => {
36309
+ resolveClosed = resolve;
36310
+ });
36197
36311
  function settleReady() {
36198
36312
  if (readySettled)
36199
36313
  return;
36200
36314
  readySettled = true;
36201
36315
  resolveReady();
36202
36316
  }
36203
- function failReady(error) {
36204
- if (readySettled)
36317
+ function settleClosed() {
36318
+ if (closedSettled)
36205
36319
  return;
36206
- readySettled = true;
36320
+ closedSettled = true;
36321
+ removeInputCloseListeners();
36207
36322
  reader?.close();
36208
- rejectReady(error);
36323
+ resolveClosed();
36324
+ }
36325
+ function closeServer() {
36326
+ settleClosed();
36327
+ settleReady();
36328
+ }
36329
+ function failReady(error) {
36330
+ if (!readySettled) {
36331
+ readySettled = true;
36332
+ rejectReady(error);
36333
+ }
36334
+ settleClosed();
36209
36335
  }
36210
36336
  function send(msg) {
36337
+ if (closedSettled)
36338
+ return;
36211
36339
  opts.output.write(ndjsonMessage(msg));
36212
36340
  }
36213
36341
  function handleMessage(msg) {
@@ -36246,6 +36374,13 @@ function createChannelServer(opts) {
36246
36374
  }
36247
36375
  return {
36248
36376
  start() {
36377
+ const handleInputClose = () => closeServer();
36378
+ opts.input.on("end", handleInputClose);
36379
+ opts.input.on("close", handleInputClose);
36380
+ removeInputCloseListeners = () => {
36381
+ opts.input.removeListener("end", handleInputClose);
36382
+ opts.input.removeListener("close", handleInputClose);
36383
+ };
36249
36384
  reader = createMessageReader(opts.input, handleMessage, failReady);
36250
36385
  },
36251
36386
  notify(content, meta) {
@@ -36256,14 +36391,15 @@ function createChannelServer(opts) {
36256
36391
  });
36257
36392
  },
36258
36393
  onReady,
36394
+ onClosed,
36259
36395
  close() {
36260
- reader?.close();
36261
- settleReady();
36396
+ closeServer();
36262
36397
  }
36263
36398
  };
36264
36399
  }
36265
36400
 
36266
36401
  // ../../packages/warmhub-cli/src/domains/channel.ts
36402
+ var RECONNECT_DELAY_MS = 2000;
36267
36403
  function formatChannelEvent(org, repo, event) {
36268
36404
  const things = event.affectedThings.join(", ");
36269
36405
  const shapes = event.affectedShapes.join(",");
@@ -36280,6 +36416,22 @@ function formatChannelEvent(org, repo, event) {
36280
36416
  };
36281
36417
  }
36282
36418
  async function subscribeLoop(client, org, repo, signal, server) {
36419
+ const pauseBeforeReconnect = () => new Promise((resolve) => {
36420
+ if (signal.aborted) {
36421
+ resolve();
36422
+ return;
36423
+ }
36424
+ let timeout;
36425
+ const onAbort = () => {
36426
+ clearTimeout(timeout);
36427
+ resolve();
36428
+ };
36429
+ timeout = setTimeout(() => {
36430
+ signal.removeEventListener("abort", onAbort);
36431
+ resolve();
36432
+ }, RECONNECT_DELAY_MS);
36433
+ signal.addEventListener("abort", onAbort, { once: true });
36434
+ });
36283
36435
  while (!signal.aborted) {
36284
36436
  try {
36285
36437
  const handle = await client.live.subscribe(org, repo, { signal }, (event) => {
@@ -36287,6 +36439,8 @@ async function subscribeLoop(client, org, repo, signal, server) {
36287
36439
  server.notify(content, meta);
36288
36440
  });
36289
36441
  await handle.closed;
36442
+ if (!signal.aborted)
36443
+ await pauseBeforeReconnect();
36290
36444
  } catch (err) {
36291
36445
  if (signal.aborted)
36292
36446
  break;
@@ -36294,7 +36448,7 @@ async function subscribeLoop(client, org, repo, signal, server) {
36294
36448
  if (msg.includes("401") || msg.includes("403") || msg.includes("404") || msg.includes("AUTH") || msg.includes("not found") || msg.includes("Session expired")) {
36295
36449
  throw new Error(`${org}/${repo}: ${msg}`);
36296
36450
  }
36297
- await new Promise((r) => setTimeout(r, 2000));
36451
+ await pauseBeforeReconnect();
36298
36452
  }
36299
36453
  }
36300
36454
  }
@@ -36313,7 +36467,6 @@ var handleChannel = async (ctx) => {
36313
36467
  input: process.stdin,
36314
36468
  output: process.stdout
36315
36469
  });
36316
- server.start();
36317
36470
  const signal = ctx.signal ?? new AbortController().signal;
36318
36471
  const aborted = new Promise((resolve) => {
36319
36472
  if (signal.aborted)
@@ -36323,15 +36476,19 @@ var handleChannel = async (ctx) => {
36323
36476
  });
36324
36477
  let ready;
36325
36478
  try {
36326
- ready = await Promise.race([server.onReady.then(() => {
36327
- return;
36328
- }), aborted]);
36479
+ const startup = Promise.race([
36480
+ server.onClosed.then(() => "closed"),
36481
+ server.onReady.then(() => "ready"),
36482
+ aborted
36483
+ ]);
36484
+ server.start();
36485
+ ready = await startup;
36329
36486
  } catch (err) {
36330
36487
  server.close();
36331
36488
  const msg = err instanceof Error ? err.message : String(err);
36332
36489
  throw new CliError(4 /* Backend */, "BACKEND", `channel startup failed: ${msg}`);
36333
36490
  }
36334
- if (ready === "aborted") {
36491
+ if (ready !== "ready") {
36335
36492
  server.close();
36336
36493
  return;
36337
36494
  }
@@ -36342,7 +36499,11 @@ var handleChannel = async (ctx) => {
36342
36499
  signal.addEventListener("abort", () => controller.abort(), { once: true });
36343
36500
  let fatal;
36344
36501
  try {
36345
- await Promise.all(repos.map(({ org, repo }) => subscribeLoop(ctx.client, org, repo, controller.signal, server)));
36502
+ const subscriptions = Promise.all(repos.map(({ org, repo }) => subscribeLoop(ctx.client, org, repo, controller.signal, server)));
36503
+ const closed = server.onClosed.then(() => {
36504
+ controller.abort();
36505
+ });
36506
+ await Promise.race([subscriptions, closed]);
36346
36507
  } catch (err) {
36347
36508
  controller.abort();
36348
36509
  fatal = err;
@@ -36373,7 +36534,7 @@ var CHANNEL_DOMAIN = defineDomain({
36373
36534
  // ../../packages/warmhub-cli/src/domains/commit-submit-flags.ts
36374
36535
  var createFlags3 = {
36375
36536
  ops: flag.string({
36376
- description: "Operations JSON (inline). For ops from a file, use -f/--file <path> instead; --ops accepts inline JSON only."
36537
+ description: "Operations JSON array (inline). For ops from a file, use -f/--file <path> instead; --ops accepts an inline JSON array only."
36377
36538
  }),
36378
36539
  file: flag.string({
36379
36540
  short: "f",
@@ -37461,7 +37622,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
37461
37622
  }
37462
37623
  ];
37463
37624
  } else if (opsJson) {
37464
- operations = safeParseJson(opsJson, "--ops", {
37625
+ operations = parseJsonArray(opsJson, "--ops", {
37465
37626
  fileFlagSibling: "-f/--file"
37466
37627
  });
37467
37628
  } else if (opsFile) {
@@ -37474,7 +37635,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
37474
37635
  } catch (e) {
37475
37636
  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
37637
  }
37477
- operations = safeParseJson(file, "--file contents");
37638
+ operations = parseJsonArray(file, "--file contents");
37478
37639
  }
37479
37640
  } else if (addNames.length > 0) {
37480
37641
  operations = buildAddOperations({
@@ -38112,7 +38273,7 @@ function coerceArg(arg, value) {
38112
38273
  if (arg.pattern) {
38113
38274
  let re;
38114
38275
  try {
38115
- re = new RegExp(arg.pattern);
38276
+ re = new RegExp(`^(?:${arg.pattern})$`);
38116
38277
  } catch {
38117
38278
  throw new CliError(2 /* UserInput */, "USER_INPUT", `invalid regex pattern for --${arg.name}: /${arg.pattern}/`);
38118
38279
  }
@@ -40666,8 +40827,9 @@ function renderActionNotifications(out, statusOut, c, notifications) {
40666
40827
  const subscriptionName = notification.subscriptionName ? `${c.cyan}${notification.subscriptionName}${c.reset}` : `${c.dim}(unknown subscription)${c.reset}`;
40667
40828
  out(` ${status} ${c.dim}${time}${c.reset} ${subscriptionName} attempt #${notification.attempt} ${c.dim}${notification.channel}${c.reset}`);
40668
40829
  if (notification.errorMessage) {
40669
- const code = notification.errorCode ? `${notification.errorCode}: ` : "";
40670
- out(` ${c.red}${code}${notification.errorMessage}${c.reset}`);
40830
+ const code = notification.errorCode ? `${escapeTerminalTextForDisplay(notification.errorCode)}: ` : "";
40831
+ const message = escapeTerminalTextForDisplay(notification.errorMessage);
40832
+ out(` ${c.red}${code}${message}${c.reset}`);
40671
40833
  }
40672
40834
  }
40673
40835
  }
@@ -42244,7 +42406,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
42244
42406
  const data = version?.data;
42245
42407
  const shapeDesc = data?.description;
42246
42408
  if (typeof shapeDesc === "string" && shapeDesc) {
42247
- ctx.out(` ${c.dim}${shapeDesc}${c.reset}`);
42409
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDesc)}${c.reset}`);
42248
42410
  }
42249
42411
  const fields = data?.fields;
42250
42412
  if (fields) {
@@ -42256,9 +42418,10 @@ var handleDescribe = async (ctx, { args, flags }) => {
42256
42418
  return Math.max(m, ts.length);
42257
42419
  }, 0);
42258
42420
  for (const [fieldName, fieldType] of entries) {
42421
+ const safeFieldName = escapeFieldNameForDisplay(fieldName);
42259
42422
  const typeStr = displayFieldType(fieldType);
42260
42423
  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}`;
42424
+ 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
42425
  ctx.out(line);
42263
42426
  }
42264
42427
  }
@@ -42647,7 +42810,7 @@ var handleList6 = async (ctx, { flags }) => {
42647
42810
  const shapeData = shape.version?.data;
42648
42811
  const shapeDescription = shapeData?.description;
42649
42812
  if (typeof shapeDescription === "string" && shapeDescription) {
42650
- ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
42813
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDescription)}${c.reset}`);
42651
42814
  }
42652
42815
  const fields = shapeData?.fields;
42653
42816
  if (fields) {
@@ -42662,7 +42825,7 @@ var handleList6 = async (ctx, { flags }) => {
42662
42825
  const typeStr = displayFieldType(fieldType);
42663
42826
  const padded = fieldName.padEnd(maxLen);
42664
42827
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42665
- const descSuffix = fieldDesc ? ` ${typeStr.padEnd(maxTypeLen)} ${fieldDesc}` : ` ${typeStr}`;
42828
+ const descSuffix = fieldDesc ? ` ${typeStr.padEnd(maxTypeLen)} ${escapeTerminalTextForDisplay(fieldDesc)}` : ` ${typeStr}`;
42666
42829
  ctx.out(` ${c.cyan}${padded}${c.reset} ${c.dim}${descSuffix}${c.reset}`);
42667
42830
  }
42668
42831
  }
@@ -42694,7 +42857,7 @@ var handleView7 = async (ctx, { flags, args }) => {
42694
42857
  const shapeData = shapeVersion?.data;
42695
42858
  const shapeDescription = shapeData?.description;
42696
42859
  if (typeof shapeDescription === "string" && shapeDescription) {
42697
- ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
42860
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDescription)}${c.reset}`);
42698
42861
  }
42699
42862
  const componentRef = result.componentRef;
42700
42863
  if (componentRef) {
@@ -42706,7 +42869,7 @@ var handleView7 = async (ctx, { flags, args }) => {
42706
42869
  for (const [fieldName, fieldType] of Object.entries(fields)) {
42707
42870
  const typeStr = displayFieldType(fieldType);
42708
42871
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42709
- const descSuffix = fieldDesc ? ` ${c.dim}${fieldDesc}${c.reset}` : "";
42872
+ const descSuffix = fieldDesc ? ` ${c.dim}${escapeTerminalTextForDisplay(fieldDesc)}${c.reset}` : "";
42710
42873
  const safeFieldName = escapeFieldNameForDisplay(fieldName);
42711
42874
  ctx.out(` ${c.cyan}${safeFieldName}${c.reset}: ${c.dim}${typeStr}${c.reset}${descSuffix}`);
42712
42875
  }
@@ -42807,8 +42970,10 @@ var handleShapeRename = async (ctx, { args }) => {
42807
42970
  }
42808
42971
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
42809
42972
  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}`);
42973
+ const result = await ctx.client.shape.rename(org, repo, oldName, newName);
42974
+ writeOutput(ctx, { ...result, oldName, newName }, () => {
42975
+ ctx.out(`${c.green}Renamed shape${c.reset} ${c.magenta}${oldName}${c.reset} → ${c.magenta}${newName}${c.reset}`);
42976
+ });
42812
42977
  };
42813
42978
 
42814
42979
  // ../../packages/warmhub-cli/src/domains/shape.ts
@@ -43265,6 +43430,11 @@ function renderResponseSnippet(out, c, snippet, baseIndent) {
43265
43430
  out(`${baseIndent} ${c.dim}${line}${c.reset}`);
43266
43431
  }
43267
43432
  }
43433
+ function renderErrorMessageLine(out, c, code, message, baseIndent) {
43434
+ const safeCode = code ? `${escapeTerminalTextForDisplay(code)}: ` : "";
43435
+ const safeMessage = escapeTerminalTextForDisplay(message);
43436
+ out(`${baseIndent}${c.red}${safeCode}${safeMessage}${c.reset}`);
43437
+ }
43268
43438
  function statusColor(c, status) {
43269
43439
  switch (status) {
43270
43440
  case "completed":
@@ -43305,11 +43475,10 @@ function renderSubscriptionLog(out, statusOut, c, subscriptionName, result) {
43305
43475
  const sourceLabel = (item.matchedOperationIndexes?.length ?? 0) > 0 ? `${c.cyan}write${c.reset}` : `${c.magenta}cron tick${c.reset}`;
43306
43476
  const matched = (item.matchedOperationIndexes ?? []).join(",") || "-";
43307
43477
  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}]`);
43478
+ const idSuffix = item.runId ? ` ${c.dim}run ${item.runId}${c.reset}` : item.deliveryId ? ` ${c.dim}delivery ${item.deliveryId}${c.reset}` : "";
43479
+ out(` ${status}${attemptSuffix} ${c.dim}${time}${c.reset}${idSuffix} ${sourceLabel} ops[${matched}]`);
43310
43480
  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}`);
43481
+ renderErrorMessageLine(out, c, item.lastErrorCode, item.lastErrorMessage, " ");
43313
43482
  }
43314
43483
  if ((displayStatus === "failed_terminal" || displayStatus === "dead_letter") && item.lastResponseSnippet) {
43315
43484
  renderResponseSnippet(out, c, item.lastResponseSnippet, " ");
@@ -43420,7 +43589,12 @@ var handleLog = async (ctx, { flags, args }) => {
43420
43589
  if (!name) {
43421
43590
  usageError("Usage: wh sub log <name> [--repo org/repo]", "wh sub log my-sub");
43422
43591
  }
43423
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
43592
+ const scope = resolveSubScope(ctx, flags);
43593
+ if (!scope.repoName) {
43594
+ usageError("Usage: wh sub log <name> [--repo org/repo]", "wh sub log my-sub --repo myorg/myrepo");
43595
+ }
43596
+ const org = scope.orgName;
43597
+ const repo = scope.repoName;
43424
43598
  if (ctx.liveMode) {
43425
43599
  await runLive({
43426
43600
  apiUrl: ctx.config.apiUrl,
@@ -43464,8 +43638,7 @@ var handleAttempts = async (ctx, { args }) => {
43464
43638
  const http = attempt.httpStatus ? ` ${c.dim}HTTP ${attempt.httpStatus}${c.reset}` : "";
43465
43639
  ctx.out(` #${attempt.attempt} ${sc}${attempt.status}${c.reset}${dur}${http}`);
43466
43640
  if (attempt.errorMessage) {
43467
- const code = attempt.errorCode ? `${attempt.errorCode}: ` : "";
43468
- ctx.out(` ${c.red}${code}${attempt.errorMessage}${c.reset}`);
43641
+ renderErrorMessageLine(ctx.out, c, attempt.errorCode, attempt.errorMessage, " ");
43469
43642
  }
43470
43643
  if (attempt.status === "failed" && attempt.responseSnippet) {
43471
43644
  renderResponseSnippet(ctx.out, c, attempt.responseSnippet, " ");
@@ -43558,6 +43731,9 @@ var SUB_DOMAIN = defineDomain({
43558
43731
  summary: "Tail subscription delivery feed with failed response snippets",
43559
43732
  args: "<name>",
43560
43733
  flags: logFlags,
43734
+ rejectedFlags: {
43735
+ org: "Use repo-scoped delivery logs: wh sub log my-sub --repo myorg/myrepo"
43736
+ },
43561
43737
  examples: [
43562
43738
  "# Show recent deliveries",
43563
43739
  " $ wh sub log signal-hook --repo org/repo",
@@ -43566,7 +43742,10 @@ var SUB_DOMAIN = defineDomain({
43566
43742
  " $ wh sub log daily-digest --repo org/repo",
43567
43743
  "",
43568
43744
  "# Follow deliveries in live mode",
43569
- " $ wh sub log signal-hook --repo org/repo --live"
43745
+ " $ wh sub log signal-hook --repo org/repo --live",
43746
+ "",
43747
+ "# Delivery logs currently require a repo-scoped subscription",
43748
+ " $ wh sub log signal-hook --repo org/repo"
43570
43749
  ],
43571
43750
  handler: handleLog
43572
43751
  },
@@ -44523,9 +44702,9 @@ function extractFlagsForVerb(flags, verbSpec) {
44523
44702
  }
44524
44703
  return flags;
44525
44704
  }
44526
- return extractFlags(flags, verbSpec.flags);
44705
+ return extractFlags(flags, verbSpec.flags, verbSpec.rejectedFlags);
44527
44706
  }
44528
- function extractFlags(flags, specs) {
44707
+ function extractFlags(flags, specs, rejectedFlags = {}) {
44529
44708
  const normalized = { ...flags };
44530
44709
  const result = {};
44531
44710
  const specLongs = specs.map((s) => s.long);
@@ -44560,11 +44739,19 @@ function extractFlags(flags, specs) {
44560
44739
  }
44561
44740
  for (const key of Object.keys(normalized)) {
44562
44741
  if (key.length === 1) {
44742
+ const rejectedHint2 = rejectedFlags[key];
44743
+ if (rejectedHint2) {
44744
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: -${key}`, undefined, rejectedHint2);
44745
+ }
44563
44746
  if (!allowedShorts.has(key) && !isGlobalFlag(key)) {
44564
44747
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: -${key}`);
44565
44748
  }
44566
44749
  continue;
44567
44750
  }
44751
+ const rejectedHint = rejectedFlags[key];
44752
+ if (rejectedHint) {
44753
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: --${key}`, undefined, rejectedHint);
44754
+ }
44568
44755
  if (!allowedLongs.has(key) && !isGlobalFlag(key)) {
44569
44756
  const hint = findClosest(key, [...allowedLongs]);
44570
44757
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: --${key}`, undefined, hint ? `Did you mean '--${hint}'?` : undefined);
@@ -45574,7 +45761,7 @@ function resolveLogLevel(flags, env) {
45574
45761
  // package.json
45575
45762
  var package_default3 = {
45576
45763
  name: "@warmhub/cli",
45577
- version: "0.63.0",
45764
+ version: "0.64.0",
45578
45765
  private: false,
45579
45766
  type: "module",
45580
45767
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -45615,6 +45802,7 @@ var package_default3 = {
45615
45802
  },
45616
45803
  scripts: {
45617
45804
  build: "bun run scripts/build.ts",
45805
+ prepack: "bun run build",
45618
45806
  "check:boundary": "node ../../scripts/lint/boundary-imports.mjs bin src scripts",
45619
45807
  "audit:bundle": "bun run scripts/audit-bundle.ts",
45620
45808
  "audit:pack": "bun run scripts/audit-pack.ts",
@@ -46228,4 +46416,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
46228
46416
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
46229
46417
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
46230
46418
 
46231
- //# debugId=AA99DB1239BF58B064756E2164756E21
46419
+ //# debugId=7FF3388CDD4F972C64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warmhub/cli",
3
- "version": "0.63.0",
3
+ "version": "0.64.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",