@warmhub/cli 0.62.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 +593 -133
  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.0",
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",
@@ -27439,6 +27438,7 @@ var package_default = {
27439
27438
  "@trpc/client": "11.17.0"
27440
27439
  },
27441
27440
  devDependencies: {
27441
+ "@trpc/server": "11.17.0",
27442
27442
  "@vitest/coverage-v8": "catalog:",
27443
27443
  "@warmhub/backend": "workspace:*",
27444
27444
  "@warmhub/rules": "workspace:*",
@@ -27697,6 +27697,14 @@ function resolveRetryPolicy(retry) {
27697
27697
  };
27698
27698
  }
27699
27699
  var DEFINITE_CLIENT_REJECT_CODES = new Set([
27700
+ "BAD_REQUEST",
27701
+ "METHOD_NOT_SUPPORTED",
27702
+ "PARSE_ERROR",
27703
+ "PAYLOAD_TOO_LARGE",
27704
+ "PRECONDITION_FAILED",
27705
+ "UNAUTHORIZED",
27706
+ "UNPROCESSABLE_CONTENT",
27707
+ "UNSUPPORTED_MEDIA_TYPE",
27700
27708
  "UNAUTHENTICATED",
27701
27709
  "FORBIDDEN",
27702
27710
  "VALIDATION_ERROR",
@@ -27709,6 +27717,7 @@ var DEFINITE_CLIENT_REJECT_CODES = new Set([
27709
27717
  "ALREADY_RETRACTED",
27710
27718
  "ARCHIVED",
27711
27719
  "RATE_LIMITED",
27720
+ "TOO_MANY_REQUESTS",
27712
27721
  "UNRESOLVED_TOKEN"
27713
27722
  ]);
27714
27723
  function extractErrorCode(cause) {
@@ -27726,9 +27735,24 @@ function extractErrorCode(cause) {
27726
27735
  return dc;
27727
27736
  return;
27728
27737
  }
27738
+ function extractHttpStatus(cause) {
27739
+ if (!cause || typeof cause !== "object")
27740
+ return;
27741
+ const status = cause.data?.httpStatus;
27742
+ if (typeof status === "number")
27743
+ return status;
27744
+ const warmhubStatus = cause.data?.warmhub?.status;
27745
+ if (typeof warmhubStatus === "number")
27746
+ return warmhubStatus;
27747
+ const direct = cause.status;
27748
+ return typeof direct === "number" ? direct : undefined;
27749
+ }
27750
+ function isDefiniteClientRejectionStatus(status) {
27751
+ return status !== undefined && status >= 400 && status < 500 && status !== 408;
27752
+ }
27729
27753
  function isDefiniteClientError(cause) {
27730
27754
  const code = extractErrorCode(cause);
27731
- return code !== undefined && DEFINITE_CLIENT_REJECT_CODES.has(code);
27755
+ return code !== undefined && DEFINITE_CLIENT_REJECT_CODES.has(code) || isDefiniteClientRejectionStatus(extractHttpStatus(cause));
27732
27756
  }
27733
27757
  function isTransientStreamFailure(cause) {
27734
27758
  if (isDefiniteClientError(cause))
@@ -28075,6 +28099,48 @@ function sanitizeSubscriptionUpdateInput(input) {
28075
28099
  } = input;
28076
28100
  return supported;
28077
28101
  }
28102
+ function trpcClientCodeToWarmHubCode(code) {
28103
+ switch (code) {
28104
+ case "BAD_REQUEST":
28105
+ case "PARSE_ERROR":
28106
+ case "PAYLOAD_TOO_LARGE":
28107
+ case "UNPROCESSABLE_CONTENT":
28108
+ case "UNSUPPORTED_MEDIA_TYPE":
28109
+ return "VALIDATION_ERROR";
28110
+ case "METHOD_NOT_SUPPORTED":
28111
+ return "NOT_FOUND";
28112
+ case "UNAUTHORIZED":
28113
+ return "UNAUTHENTICATED";
28114
+ case "FORBIDDEN":
28115
+ return "FORBIDDEN";
28116
+ case "NOT_FOUND":
28117
+ return "NOT_FOUND";
28118
+ case "CONFLICT":
28119
+ return "CONFLICT";
28120
+ case "PRECONDITION_FAILED":
28121
+ return "PRECONDITION_FAILED";
28122
+ case "TOO_MANY_REQUESTS":
28123
+ return "RATE_LIMITED";
28124
+ default:
28125
+ return;
28126
+ }
28127
+ }
28128
+ function trpcHttpStatusToWarmHubCode(status) {
28129
+ if (status === undefined || status === 408)
28130
+ return;
28131
+ if (status === 405)
28132
+ return "NOT_FOUND";
28133
+ if (status === 412)
28134
+ return "PRECONDITION_FAILED";
28135
+ if (status === 422)
28136
+ return "VALIDATION_ERROR";
28137
+ const mapped = httpStatusToWarmHubCode(status);
28138
+ if (mapped !== "BACKEND")
28139
+ return mapped;
28140
+ if (status >= 400 && status < 500)
28141
+ return "VALIDATION_ERROR";
28142
+ return mapped;
28143
+ }
28078
28144
  var INTERNAL_PATTERNS = [
28079
28145
  /\bselect\b.+?\bfrom\b/i,
28080
28146
  /\binsert\b.+?\binto\b/i,
@@ -28136,8 +28202,10 @@ function toWarmHubError(error) {
28136
28202
  }
28137
28203
  const data = error.data;
28138
28204
  const wireCode = data?.warmhub?.code;
28205
+ const trpcCode = typeof data?.code === "string" ? trpcClientCodeToWarmHubCode(data.code) : undefined;
28206
+ const trpcStatus = trpcHttpStatusToWarmHubCode(data?.httpStatus);
28139
28207
  const message = data?.warmhub?.message ?? sanitizeErrorMessage(error.message);
28140
- return new WarmHubError(wireCode ?? "BACKEND", message, data?.warmhub?.status, data?.warmhub?.hint, data?.warmhub?.retryAfter, wireCode, data?.warmhub?.details);
28208
+ return new WarmHubError(wireCode ?? trpcCode ?? trpcStatus ?? "BACKEND", message, data?.warmhub?.status ?? data?.httpStatus, data?.warmhub?.hint, data?.warmhub?.retryAfter ?? data?.retryAfter, wireCode, data?.warmhub?.details);
28141
28209
  }
28142
28210
  if (error instanceof Error) {
28143
28211
  const warmhubLike = error;
@@ -28283,6 +28351,15 @@ class WarmHubClient {
28283
28351
  }
28284
28352
  }
28285
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
+ };
28286
28363
  access = {
28287
28364
  resolve: async (input) => {
28288
28365
  try {
@@ -29125,24 +29202,26 @@ class WarmHubClient {
29125
29202
  throw toWarmHubError(error);
29126
29203
  }
29127
29204
  },
29128
- claimDelivery: async (orgName, repoName, runId, holderId) => {
29205
+ claimDelivery: async (orgName, repoName, target, holderId) => {
29206
+ const deliveryTarget = typeof target === "string" ? { runId: target } : target;
29129
29207
  try {
29130
29208
  return await this.trpc.action.claimDelivery.mutate({
29131
29209
  orgName,
29132
29210
  repoName,
29133
- runId,
29211
+ ...deliveryTarget,
29134
29212
  holderId
29135
29213
  });
29136
29214
  } catch (error) {
29137
29215
  throw toWarmHubError(error);
29138
29216
  }
29139
29217
  },
29140
- completeDelivery: async (orgName, repoName, runId, holderId) => {
29218
+ completeDelivery: async (orgName, repoName, target, holderId) => {
29219
+ const deliveryTarget = typeof target === "string" ? { runId: target } : target;
29141
29220
  try {
29142
29221
  return await this.trpc.action.completeDelivery.mutate({
29143
29222
  orgName,
29144
29223
  repoName,
29145
- runId,
29224
+ ...deliveryTarget,
29146
29225
  holderId
29147
29226
  });
29148
29227
  } catch (error) {
@@ -30503,11 +30582,25 @@ function safeParseJson(input, label, options) {
30503
30582
  function parseJsonObject(input, label, options) {
30504
30583
  const parsed = safeParseJson(input, label, options);
30505
30584
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
30506
- const got = Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed;
30585
+ const got = describeJsonType(parsed);
30507
30586
  throw new CliError(2 /* UserInput */, "USER_INPUT", `${label} must be a JSON object, got ${got}`, undefined, `Pass an object, e.g. '{"key":"value"}'.`);
30508
30587
  }
30509
30588
  return parsed;
30510
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
+ }
30511
30604
  function parsePositiveIntFlag(value, label, example) {
30512
30605
  if (value !== undefined && (!Number.isInteger(value) || value < 1)) {
30513
30606
  usageError(`${label} must be a positive integer`, example);
@@ -30576,7 +30669,12 @@ function parseArgs(argv) {
30576
30669
  positionals.push(arg);
30577
30670
  i += 1;
30578
30671
  }
30579
- return { positionals, flags, ...terminator ? { terminator } : {} };
30672
+ return {
30673
+ positionals,
30674
+ flags,
30675
+ ...terminator ? { terminator } : {},
30676
+ rawArgv: [...argv]
30677
+ };
30580
30678
  }
30581
30679
  function getStringFlag(flags, ...keys) {
30582
30680
  for (const key of keys) {
@@ -30598,8 +30696,9 @@ function getBoolFlag(flags, ...keys) {
30598
30696
  function getNumberFlag(flags, ...keys) {
30599
30697
  for (const key of keys) {
30600
30698
  const val = flags[key];
30601
- if (typeof val === "string") {
30602
- const num = Number(val);
30699
+ const scalar = Array.isArray(val) ? val[val.length - 1] : val;
30700
+ if (typeof scalar === "string") {
30701
+ const num = Number(scalar);
30603
30702
  if (!Number.isNaN(num))
30604
30703
  return num;
30605
30704
  }
@@ -31448,10 +31547,21 @@ function writeStore(store, path) {
31448
31547
  }
31449
31548
  }
31450
31549
  }
31550
+ function hasProfile(store, name) {
31551
+ return Object.hasOwn(store.profiles, name);
31552
+ }
31553
+ function setProfile(store, name, profile) {
31554
+ Object.defineProperty(store.profiles, name, {
31555
+ value: profile,
31556
+ enumerable: true,
31557
+ configurable: true,
31558
+ writable: true
31559
+ });
31560
+ }
31451
31561
  function saveProfile(name, profile, path) {
31452
31562
  const p = path ?? getAuthPath();
31453
31563
  const store = loadProfileStore(p);
31454
- store.profiles[name] = profile;
31564
+ setProfile(store, name, profile);
31455
31565
  writeStore(store, p);
31456
31566
  }
31457
31567
  function saveProfileWhileLocked(name, profile, path) {
@@ -31460,7 +31570,7 @@ function saveProfileWhileLocked(name, profile, path) {
31460
31570
  function getProfile(name, path) {
31461
31571
  const p = path ?? getAuthPath();
31462
31572
  const store = loadProfileStore(p);
31463
- return store.profiles[name] ?? null;
31573
+ return hasProfile(store, name) ? store.profiles[name] : null;
31464
31574
  }
31465
31575
  async function modifyStore(mutator, path) {
31466
31576
  const p = path ?? getAuthPath();
@@ -31473,12 +31583,12 @@ async function modifyStore(mutator, path) {
31473
31583
  }
31474
31584
  async function saveProfileLocked(name, profile, path) {
31475
31585
  await modifyStore((store) => {
31476
- store.profiles[name] = profile;
31586
+ setProfile(store, name, profile);
31477
31587
  }, path);
31478
31588
  }
31479
31589
  async function deleteProfileLocked(name, path) {
31480
31590
  await modifyStore((store) => {
31481
- if (!(name in store.profiles))
31591
+ if (!hasProfile(store, name))
31482
31592
  return;
31483
31593
  delete store.profiles[name];
31484
31594
  }, path);
@@ -31714,8 +31824,52 @@ var package_default2 = {
31714
31824
  }
31715
31825
  };
31716
31826
 
31827
+ // ../../packages/warmhub-cli/src/cli-trace-context.ts
31828
+ import { randomBytes } from "node:crypto";
31829
+ var TRACE_VERSION = "00";
31830
+ var TRACE_FLAGS_SAMPLED = "01";
31831
+ var activeTrace;
31832
+ function randomHex(byteLength) {
31833
+ let value = "";
31834
+ do {
31835
+ value = randomBytes(byteLength).toString("hex");
31836
+ } while (/^0+$/.test(value));
31837
+ return value;
31838
+ }
31839
+ function createTraceContext() {
31840
+ return {
31841
+ traceId: randomHex(16),
31842
+ rootSpanId: randomHex(8)
31843
+ };
31844
+ }
31845
+ function startCliTraceContext() {
31846
+ activeTrace = createTraceContext();
31847
+ return activeTrace;
31848
+ }
31849
+ function getCliTraceContext() {
31850
+ activeTrace ??= createTraceContext();
31851
+ return activeTrace;
31852
+ }
31853
+ function cliTraceLogFields() {
31854
+ const trace = getCliTraceContext();
31855
+ return {
31856
+ traceId: trace.traceId,
31857
+ spanId: trace.rootSpanId
31858
+ };
31859
+ }
31860
+ function createCliTraceparent() {
31861
+ const trace = getCliTraceContext();
31862
+ return [
31863
+ TRACE_VERSION,
31864
+ trace.traceId,
31865
+ trace.rootSpanId,
31866
+ TRACE_FLAGS_SAMPLED
31867
+ ].join("-");
31868
+ }
31869
+
31717
31870
  // ../../packages/warmhub-cli/src/client.ts
31718
31871
  var BENCHMARK_HEADER = "x-warmhub-benchmark-id";
31872
+ var TRACEPARENT_HEADER = "traceparent";
31719
31873
  var REQUEST_TOTAL_MS_HEADER = "x-warmhub-request-total-ms";
31720
31874
  var REQUEST_DB_QUERY_COUNT_HEADER = "x-warmhub-request-db-query-count";
31721
31875
  var benchmarkTelemetry = emptyBenchmarkTelemetry();
@@ -31753,10 +31907,9 @@ function recordBenchmarkResponse(response, benchmarkId) {
31753
31907
  }
31754
31908
  }
31755
31909
  function createBenchmarkAwareFetch(benchmarkId, signal) {
31756
- if (!benchmarkId && !signal)
31757
- return;
31758
31910
  return async (input, init) => {
31759
31911
  const headers = new Headers(init?.headers);
31912
+ headers.set(TRACEPARENT_HEADER, createCliTraceparent());
31760
31913
  if (benchmarkId)
31761
31914
  headers.set(BENCHMARK_HEADER, benchmarkId);
31762
31915
  const response = await fetch(input, {
@@ -31812,6 +31965,15 @@ function createClient(config, opts = {}) {
31812
31965
  client: cliClientIdentity()
31813
31966
  });
31814
31967
  }
31968
+ function createUnauthenticatedClient(config, opts = {}) {
31969
+ const benchmarkId = process.env.WH_BENCHMARK_ID?.trim();
31970
+ return new WarmHubClient({
31971
+ apiUrl: config.apiUrl,
31972
+ fetch: createBenchmarkAwareFetch(benchmarkId),
31973
+ functionLogs: opts.functionLogs,
31974
+ client: cliClientIdentity()
31975
+ });
31976
+ }
31815
31977
  function wantsStructuredLiveOutput(format) {
31816
31978
  return format === "json" || format === "jsonl";
31817
31979
  }
@@ -32186,9 +32348,18 @@ class DomainRegistry {
32186
32348
  throw new Error(`Domain '${def.name}' already registered`);
32187
32349
  }
32188
32350
  const spec = this.buildSpec(def);
32189
- this.domains.set(def.name, spec);
32190
- this.registerHandlers(def);
32191
32351
  this.validateDomain(spec, def);
32352
+ const handlers = new Map;
32353
+ this.collectHandlers(def, handlers);
32354
+ for (const key of handlers.keys()) {
32355
+ if (this.handlers.has(key)) {
32356
+ throw new Error(`Handler '${key}' already registered`);
32357
+ }
32358
+ }
32359
+ this.domains.set(def.name, spec);
32360
+ for (const [key, handler] of handlers) {
32361
+ this.handlers.set(key, handler);
32362
+ }
32192
32363
  }
32193
32364
  buildSpec(def) {
32194
32365
  if (def.kind === "flat") {
@@ -32205,7 +32376,7 @@ class DomainRegistry {
32205
32376
  }
32206
32377
  const verbs = {};
32207
32378
  for (const [verbName, v] of Object.entries(def.verbs)) {
32208
- verbs[verbName] = {
32379
+ const verbSpec = {
32209
32380
  status: v.status ?? "live",
32210
32381
  prime: v.prime ?? false,
32211
32382
  summary: v.summary,
@@ -32216,6 +32387,13 @@ class DomainRegistry {
32216
32387
  verbAliases: v.verbAliases,
32217
32388
  passthroughFlags: v.passthroughFlags
32218
32389
  };
32390
+ if (v.rejectedFlags) {
32391
+ Object.defineProperty(verbSpec, "rejectedFlags", {
32392
+ value: v.rejectedFlags,
32393
+ enumerable: false
32394
+ });
32395
+ }
32396
+ verbs[verbName] = verbSpec;
32219
32397
  }
32220
32398
  const subdomains = def.subdomains ? Object.fromEntries(Object.entries(def.subdomains).map(([k, sd]) => [
32221
32399
  k,
@@ -32241,39 +32419,48 @@ class DomainRegistry {
32241
32419
  aliases: f.aliases
32242
32420
  }));
32243
32421
  }
32244
- registerHandlers(def, path = [def.name]) {
32422
+ collectHandlers(def, handlers, path = [def.name]) {
32245
32423
  if (def.kind === "flat") {
32246
32424
  const key = [...path, ""].join(":");
32247
- if (this.handlers.has(key)) {
32425
+ if (handlers.has(key)) {
32248
32426
  throw new Error(`Handler '${key}' already registered`);
32249
32427
  }
32250
- this.handlers.set(key, def.handler);
32428
+ handlers.set(key, def.handler);
32251
32429
  return;
32252
32430
  }
32253
32431
  for (const [verbName, v] of Object.entries(def.verbs)) {
32254
32432
  const key = [...path, verbName].join(":");
32255
- if (this.handlers.has(key)) {
32433
+ if (handlers.has(key)) {
32256
32434
  throw new Error(`Handler '${key}' already registered`);
32257
32435
  }
32258
- this.handlers.set(key, v.handler);
32436
+ handlers.set(key, v.handler);
32259
32437
  }
32260
32438
  if (def.subdomains) {
32261
32439
  for (const [subName, subDef] of Object.entries(def.subdomains)) {
32262
- this.registerHandlers(subDef, [...path, subName]);
32440
+ this.collectHandlers(subDef, handlers, [...path, subName]);
32263
32441
  }
32264
32442
  }
32265
32443
  }
32266
- validateDomain(spec, def) {
32444
+ validateDomain(spec, def, path = [def.name]) {
32267
32445
  if (spec.kind === "noun") {
32446
+ const displayPath = path.join(".");
32268
32447
  for (const [verbName, v] of Object.entries(spec.verbs)) {
32269
32448
  for (const alias of v.verbAliases ?? []) {
32270
32449
  if (spec.verbs[alias]) {
32271
- throw new Error(`Alias '${alias}' for ${spec.name}.${verbName} conflicts with verb '${alias}'`);
32450
+ throw new Error(`Alias '${alias}' for ${displayPath}.${verbName} conflicts with verb '${alias}'`);
32272
32451
  }
32273
32452
  }
32274
32453
  }
32275
32454
  if (def.kind !== "flat" && def.defaultVerb && !def.verbs[def.defaultVerb]) {
32276
- throw new Error(`Domain '${def.name}': defaultVerb '${def.defaultVerb}' does not name a canonical verb`);
32455
+ throw new Error(`Domain '${displayPath}': defaultVerb '${def.defaultVerb}' does not name a canonical verb`);
32456
+ }
32457
+ if (def.kind !== "flat" && def.subdomains) {
32458
+ for (const [subName, subDef] of Object.entries(def.subdomains)) {
32459
+ const subSpec = spec.subdomains?.[subName];
32460
+ if (subSpec) {
32461
+ this.validateDomain(subSpec, subDef, [...path, subName]);
32462
+ }
32463
+ }
32277
32464
  }
32278
32465
  }
32279
32466
  }
@@ -32299,6 +32486,14 @@ class DomainRegistry {
32299
32486
  path.push(tokens[i]);
32300
32487
  i++;
32301
32488
  }
32489
+ if (cursor.kind === "flat") {
32490
+ return {
32491
+ domain,
32492
+ domainPath: path,
32493
+ verb: undefined,
32494
+ remaining: tokens.slice(i)
32495
+ };
32496
+ }
32302
32497
  const verb = tokens[i];
32303
32498
  const remaining = tokens.slice(i + 1);
32304
32499
  return { domain, domainPath: path, verb, remaining };
@@ -32498,6 +32693,54 @@ function extractShapeName(name) {
32498
32693
  const slash = name.indexOf("/");
32499
32694
  return slash > 0 ? name.slice(0, slash) : "";
32500
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
+ }
32501
32744
  var escapeInlineTerminalText = escapeFieldNameForDisplay;
32502
32745
  function renderWarningLine(out, c, chars, op) {
32503
32746
  const warnings = op.warnings;
@@ -34105,10 +34348,10 @@ var searchFlags = {
34105
34348
  cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
34106
34349
  all: flag.boolean({ description: "Fetch all pages (text mode)" }),
34107
34350
  component: flag.string({
34108
- 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)"
34109
34352
  }),
34110
34353
  "exclude-components": flag.boolean({
34111
- description: "Exclude component-owned things from results"
34354
+ description: "Exclude component-owned things from results (text mode)"
34112
34355
  })
34113
34356
  };
34114
34357
  var handleSearch = async (ctx, { flags, args }) => {
@@ -34142,10 +34385,14 @@ var handleSearch = async (ctx, { flags, args }) => {
34142
34385
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedTextLimit;
34143
34386
  const resolveCollections = mode !== "hybrid" ? flags["resolve-collections"] : undefined;
34144
34387
  const supportsComponentFilters = !mode || mode === "text";
34145
- const componentRef = supportsComponentFilters ? flags.component : undefined;
34146
34388
  const hasShape = !!flags.shape;
34147
- const strictExclude = supportsComponentFilters ? !!flags["exclude-components"] : false;
34148
- 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;
34149
34396
  const excludeComponents = supportsComponentFilters && strictExclude ? true : undefined;
34150
34397
  const excludeInfraShapes = supportsComponentFilters && !strictExclude && !hasShape ? true : undefined;
34151
34398
  const rawResult = all ? await fetchAllSearchPages(ctx, org, repo, queryText, {
@@ -35720,8 +35967,9 @@ var handleLogin = async (ctx, { flags }) => {
35720
35967
  try {
35721
35968
  clientId = await ctx.client.auth.getClientId();
35722
35969
  } catch {
35723
- await deleteProfileLocked(profile);
35724
- clientId = await ctx.client.auth.getClientId();
35970
+ clientId = await createUnauthenticatedClient(ctx.config, {
35971
+ functionLogs: ctx.functionLogMode
35972
+ }).auth.getClientId();
35725
35973
  }
35726
35974
  if (!clientId) {
35727
35975
  throw new CliError(5 /* Auth */, "AUTH", "Backend has no WORKOS_CLIENT_ID configured.");
@@ -35895,7 +36143,7 @@ var HEADER_DELIMITER = `\r
35895
36143
  `;
35896
36144
  var CONTENT_LENGTH_RE = /^Content-Length:\s*(\d+)$/im;
35897
36145
  var MAX_MESSAGE_BYTES = 64 * 1024 * 1024;
35898
- function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES) {
36146
+ function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES, bufferByteLength) {
35899
36147
  const headerEnd = buffer.indexOf(HEADER_DELIMITER);
35900
36148
  if (headerEnd === -1)
35901
36149
  return null;
@@ -35908,11 +36156,36 @@ function parseFramedMessage(buffer, maxContentLength = MAX_MESSAGE_BYTES) {
35908
36156
  throw new RangeError(`Content-Length ${contentLength} exceeds the maximum allowed ${maxContentLength} bytes`);
35909
36157
  }
35910
36158
  const bodyStart = headerEnd + HEADER_DELIMITER.length;
35911
- const remaining = Buffer.from(buffer.slice(bodyStart), "utf8");
35912
- 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)
35913
36162
  return null;
35914
- const body = remaining.subarray(0, contentLength).toString("utf8");
35915
- return { message: JSON.parse(body), consumed: bodyStart + body.length };
36163
+ const bodyEnd = findUtf8ByteBoundary(buffer, bodyStart, contentLength);
36164
+ if (bodyEnd === null)
36165
+ return null;
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;
35916
36189
  }
35917
36190
  function parseNdjsonMessage(buffer) {
35918
36191
  const newlineIdx = buffer.indexOf(`
@@ -35960,7 +36233,7 @@ function createMessageReader(input, onMessage, onError = () => {}, maxMessageByt
35960
36233
  }
35961
36234
  let result;
35962
36235
  try {
35963
- result = mode === "ndjson" ? parseNdjsonMessage(buffer) : parseFramedMessage(buffer, maxMessageBytes);
36236
+ result = mode === "ndjson" ? parseNdjsonMessage(buffer) : parseFramedMessage(buffer, maxMessageBytes, bufferBytes);
35964
36237
  } catch (err) {
35965
36238
  if (err instanceof RangeError) {
35966
36239
  onError(err);
@@ -36022,27 +36295,47 @@ function createMessageReader(input, onMessage, onError = () => {}, maxMessageByt
36022
36295
  var MCP_PROTOCOL_VERSION2 = "2025-11-25";
36023
36296
  function createChannelServer(opts) {
36024
36297
  let reader = null;
36298
+ let removeInputCloseListeners = () => {};
36025
36299
  let resolveReady;
36026
36300
  let rejectReady;
36027
36301
  let readySettled = false;
36302
+ let resolveClosed;
36303
+ let closedSettled = false;
36028
36304
  const onReady = new Promise((resolve, reject) => {
36029
36305
  resolveReady = resolve;
36030
36306
  rejectReady = reject;
36031
36307
  });
36308
+ const onClosed = new Promise((resolve) => {
36309
+ resolveClosed = resolve;
36310
+ });
36032
36311
  function settleReady() {
36033
36312
  if (readySettled)
36034
36313
  return;
36035
36314
  readySettled = true;
36036
36315
  resolveReady();
36037
36316
  }
36038
- function failReady(error) {
36039
- if (readySettled)
36317
+ function settleClosed() {
36318
+ if (closedSettled)
36040
36319
  return;
36041
- readySettled = true;
36320
+ closedSettled = true;
36321
+ removeInputCloseListeners();
36042
36322
  reader?.close();
36043
- 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();
36044
36335
  }
36045
36336
  function send(msg) {
36337
+ if (closedSettled)
36338
+ return;
36046
36339
  opts.output.write(ndjsonMessage(msg));
36047
36340
  }
36048
36341
  function handleMessage(msg) {
@@ -36081,6 +36374,13 @@ function createChannelServer(opts) {
36081
36374
  }
36082
36375
  return {
36083
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
+ };
36084
36384
  reader = createMessageReader(opts.input, handleMessage, failReady);
36085
36385
  },
36086
36386
  notify(content, meta) {
@@ -36091,14 +36391,15 @@ function createChannelServer(opts) {
36091
36391
  });
36092
36392
  },
36093
36393
  onReady,
36394
+ onClosed,
36094
36395
  close() {
36095
- reader?.close();
36096
- settleReady();
36396
+ closeServer();
36097
36397
  }
36098
36398
  };
36099
36399
  }
36100
36400
 
36101
36401
  // ../../packages/warmhub-cli/src/domains/channel.ts
36402
+ var RECONNECT_DELAY_MS = 2000;
36102
36403
  function formatChannelEvent(org, repo, event) {
36103
36404
  const things = event.affectedThings.join(", ");
36104
36405
  const shapes = event.affectedShapes.join(",");
@@ -36115,6 +36416,22 @@ function formatChannelEvent(org, repo, event) {
36115
36416
  };
36116
36417
  }
36117
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
+ });
36118
36435
  while (!signal.aborted) {
36119
36436
  try {
36120
36437
  const handle = await client.live.subscribe(org, repo, { signal }, (event) => {
@@ -36122,6 +36439,8 @@ async function subscribeLoop(client, org, repo, signal, server) {
36122
36439
  server.notify(content, meta);
36123
36440
  });
36124
36441
  await handle.closed;
36442
+ if (!signal.aborted)
36443
+ await pauseBeforeReconnect();
36125
36444
  } catch (err) {
36126
36445
  if (signal.aborted)
36127
36446
  break;
@@ -36129,7 +36448,7 @@ async function subscribeLoop(client, org, repo, signal, server) {
36129
36448
  if (msg.includes("401") || msg.includes("403") || msg.includes("404") || msg.includes("AUTH") || msg.includes("not found") || msg.includes("Session expired")) {
36130
36449
  throw new Error(`${org}/${repo}: ${msg}`);
36131
36450
  }
36132
- await new Promise((r) => setTimeout(r, 2000));
36451
+ await pauseBeforeReconnect();
36133
36452
  }
36134
36453
  }
36135
36454
  }
@@ -36148,7 +36467,6 @@ var handleChannel = async (ctx) => {
36148
36467
  input: process.stdin,
36149
36468
  output: process.stdout
36150
36469
  });
36151
- server.start();
36152
36470
  const signal = ctx.signal ?? new AbortController().signal;
36153
36471
  const aborted = new Promise((resolve) => {
36154
36472
  if (signal.aborted)
@@ -36158,15 +36476,19 @@ var handleChannel = async (ctx) => {
36158
36476
  });
36159
36477
  let ready;
36160
36478
  try {
36161
- ready = await Promise.race([server.onReady.then(() => {
36162
- return;
36163
- }), 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;
36164
36486
  } catch (err) {
36165
36487
  server.close();
36166
36488
  const msg = err instanceof Error ? err.message : String(err);
36167
36489
  throw new CliError(4 /* Backend */, "BACKEND", `channel startup failed: ${msg}`);
36168
36490
  }
36169
- if (ready === "aborted") {
36491
+ if (ready !== "ready") {
36170
36492
  server.close();
36171
36493
  return;
36172
36494
  }
@@ -36177,7 +36499,11 @@ var handleChannel = async (ctx) => {
36177
36499
  signal.addEventListener("abort", () => controller.abort(), { once: true });
36178
36500
  let fatal;
36179
36501
  try {
36180
- 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]);
36181
36507
  } catch (err) {
36182
36508
  controller.abort();
36183
36509
  fatal = err;
@@ -36208,7 +36534,7 @@ var CHANNEL_DOMAIN = defineDomain({
36208
36534
  // ../../packages/warmhub-cli/src/domains/commit-submit-flags.ts
36209
36535
  var createFlags3 = {
36210
36536
  ops: flag.string({
36211
- 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."
36212
36538
  }),
36213
36539
  file: flag.string({
36214
36540
  short: "f",
@@ -37296,7 +37622,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
37296
37622
  }
37297
37623
  ];
37298
37624
  } else if (opsJson) {
37299
- operations = safeParseJson(opsJson, "--ops", {
37625
+ operations = parseJsonArray(opsJson, "--ops", {
37300
37626
  fileFlagSibling: "-f/--file"
37301
37627
  });
37302
37628
  } else if (opsFile) {
@@ -37309,7 +37635,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
37309
37635
  } catch (e) {
37310
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.");
37311
37637
  }
37312
- operations = safeParseJson(file, "--file contents");
37638
+ operations = parseJsonArray(file, "--file contents");
37313
37639
  }
37314
37640
  } else if (addNames.length > 0) {
37315
37641
  operations = buildAddOperations({
@@ -37818,7 +38144,8 @@ function resolveInvocation(parsed) {
37818
38144
  subcommand,
37819
38145
  positional: positionals,
37820
38146
  flags,
37821
- ...parsed.terminator ? { terminator: parsed.terminator } : {}
38147
+ ...parsed.terminator ? { terminator: parsed.terminator } : {},
38148
+ ...parsed.rawArgv ? { rawArgv: [...parsed.rawArgv] } : {}
37822
38149
  };
37823
38150
  }
37824
38151
 
@@ -37829,6 +38156,68 @@ function isRawGlobalFlagForComponentExec(key) {
37829
38156
  return true;
37830
38157
  return isGlobalShortFlag(key) && key !== key.toLowerCase();
37831
38158
  }
38159
+ function isNegativeNumericToken(token) {
38160
+ if (!token.startsWith("-") || token === "-")
38161
+ return false;
38162
+ return Number.isFinite(Number(token));
38163
+ }
38164
+ function isNumericMethodArg(method, name) {
38165
+ return method.args.some((arg) => arg.name === name && (arg.type === "number" || arg.type === "integer"));
38166
+ }
38167
+ function normalizeNegativeNumericMethodArgs(method, argv) {
38168
+ const normalized = [];
38169
+ for (let i = 0;i < argv.length; i += 1) {
38170
+ const token = argv[i];
38171
+ if (token.startsWith("--") && !token.includes("=") && isNumericMethodArg(method, token.slice(2)) && argv[i + 1] !== undefined && isNegativeNumericToken(argv[i + 1])) {
38172
+ normalized.push(`${token}=${argv[i + 1]}`);
38173
+ i += 1;
38174
+ continue;
38175
+ }
38176
+ normalized.push(token);
38177
+ }
38178
+ return normalized;
38179
+ }
38180
+ function flagValueTokenLength(argv, index) {
38181
+ const token = argv[index];
38182
+ if (token === undefined)
38183
+ return 0;
38184
+ if (token.startsWith("--")) {
38185
+ if (token.includes("="))
38186
+ return 1;
38187
+ const next = argv[index + 1];
38188
+ return next !== undefined && !next.startsWith("-") ? 2 : 1;
38189
+ }
38190
+ if (token.startsWith("-") && token !== "-") {
38191
+ const next = argv[index + 1];
38192
+ return next !== undefined && !next.startsWith("-") ? 2 : 1;
38193
+ }
38194
+ return 0;
38195
+ }
38196
+ function findComponentMethodArgStart(rawArgv, componentName, methodName) {
38197
+ const terminatorIndex = rawArgv.indexOf("--");
38198
+ const scanEnd = terminatorIndex === -1 ? rawArgv.length : terminatorIndex;
38199
+ const positionalIndexes = [];
38200
+ for (let i = 0;i < scanEnd; ) {
38201
+ const consumedFlagTokens = flagValueTokenLength(rawArgv, i);
38202
+ if (consumedFlagTokens > 0) {
38203
+ i += consumedFlagTokens;
38204
+ continue;
38205
+ }
38206
+ positionalIndexes.push(i);
38207
+ i += 1;
38208
+ }
38209
+ const positionals = positionalIndexes.map((index) => rawArgv[index]);
38210
+ if (positionals[0] === "component" && positionals[1] === "exec" && positionals[2] === componentName && positionals[3] === methodName) {
38211
+ return positionalIndexes[3] + 1;
38212
+ }
38213
+ if (positionals[0] === componentName && positionals[1] === methodName) {
38214
+ return positionalIndexes[1] + 1;
38215
+ }
38216
+ return;
38217
+ }
38218
+ function parseComponentMethodTokenStream(method, argv) {
38219
+ return parseArgs(normalizeNegativeNumericMethodArgs(method, argv));
38220
+ }
37832
38221
  function parseMethodArgs(method, rawFlags, terminatorFlags = {}) {
37833
38222
  const argsByName = new Map;
37834
38223
  for (const a of method.args)
@@ -37884,7 +38273,7 @@ function coerceArg(arg, value) {
37884
38273
  if (arg.pattern) {
37885
38274
  let re;
37886
38275
  try {
37887
- re = new RegExp(arg.pattern);
38276
+ re = new RegExp(`^(?:${arg.pattern})$`);
37888
38277
  } catch {
37889
38278
  throw new CliError(2 /* UserInput */, "USER_INPUT", `invalid regex pattern for --${arg.name}: /${arg.pattern}/`);
37890
38279
  }
@@ -37971,9 +38360,6 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
37971
38360
  }
37972
38361
  const componentName = args[0];
37973
38362
  const methodName = args[1];
37974
- if (args.length > 2) {
37975
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Unexpected argument: '${args[2]}'`, undefined, "'wh component exec' accepts at most 2 positional arguments (<component> <method>); pass method inputs as flags");
37976
- }
37977
38363
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
37978
38364
  const installRepo = `${org}/${repo}`;
37979
38365
  const cache = await ensureFreshInstallSnapshotCache(installRepo, ctx.client);
@@ -37996,14 +38382,29 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
37996
38382
  renderMethodHelp(ctx, componentName, method);
37997
38383
  return;
37998
38384
  }
37999
- const terminatorArgs = terminator && terminator.length > 0 ? parseArgs([...terminator]) : undefined;
38385
+ const rawArgv = ctx.invocation.rawArgv;
38386
+ const methodArgStart = rawArgv === undefined ? undefined : findComponentMethodArgStart(rawArgv, componentName, methodName);
38387
+ const terminatorIndex = rawArgv?.indexOf("--") ?? -1;
38388
+ const preTerminatorEnd = rawArgv === undefined ? undefined : terminatorIndex === -1 ? rawArgv.length : terminatorIndex;
38389
+ const preMethodArgs = rawArgv !== undefined && methodArgStart !== undefined ? parseComponentMethodTokenStream(method, rawArgv.slice(0, methodArgStart)) : undefined;
38390
+ const methodArgs = rawArgv !== undefined && methodArgStart !== undefined && preTerminatorEnd !== undefined ? parseComponentMethodTokenStream(method, rawArgv.slice(methodArgStart, preTerminatorEnd)) : undefined;
38391
+ const unexpectedMethodPositional = methodArgs?.positionals[0] ?? (methodArgStart === undefined ? args[2] : undefined);
38392
+ if (unexpectedMethodPositional !== undefined) {
38393
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unexpected argument: '${unexpectedMethodPositional}'`, undefined, "'wh component exec' accepts at most 2 positional arguments (<component> <method>); pass method inputs as flags");
38394
+ }
38395
+ const terminatorArgs = terminator && terminator.length > 0 ? parseComponentMethodTokenStream(method, terminator) : undefined;
38000
38396
  if (terminatorArgs?.positionals.length) {
38001
38397
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unexpected argument: '${terminatorArgs.positionals[0]}'`, undefined, "Component CLI method inputs must be passed as named flags, even after --");
38002
38398
  }
38003
38399
  const terminatorFlags = terminatorArgs?.flags ?? {};
38004
38400
  let parsedArgs;
38401
+ const rawFlags = {
38402
+ ...methodArgStart === undefined ? ctx.invocation.flags : {},
38403
+ ...preMethodArgs?.flags,
38404
+ ...methodArgs?.flags
38405
+ };
38005
38406
  try {
38006
- parsedArgs = parseMethodArgs(method, ctx.invocation.flags, terminatorFlags);
38407
+ parsedArgs = parseMethodArgs(method, rawFlags, terminatorFlags);
38007
38408
  } catch (error) {
38008
38409
  withMethodHelpHint(error, methodHelpHint(componentName, methodName, installRepo));
38009
38410
  }
@@ -40426,8 +40827,9 @@ function renderActionNotifications(out, statusOut, c, notifications) {
40426
40827
  const subscriptionName = notification.subscriptionName ? `${c.cyan}${notification.subscriptionName}${c.reset}` : `${c.dim}(unknown subscription)${c.reset}`;
40427
40828
  out(` ${status} ${c.dim}${time}${c.reset} ${subscriptionName} attempt #${notification.attempt} ${c.dim}${notification.channel}${c.reset}`);
40428
40829
  if (notification.errorMessage) {
40429
- const code = notification.errorCode ? `${notification.errorCode}: ` : "";
40430
- 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}`);
40431
40833
  }
40432
40834
  }
40433
40835
  }
@@ -41479,6 +41881,17 @@ function buildContentPrompt(ctx) {
41479
41881
  }
41480
41882
 
41481
41883
  // ../../packages/warmhub-cli/src/domains/repo/helpers.ts
41884
+ function parseExplicitOrgRepoArg(ref, usage, example) {
41885
+ if (!ref?.includes("/")) {
41886
+ usageError(usage, example);
41887
+ }
41888
+ const parts = ref.split("/");
41889
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
41890
+ usageError(`Invalid repo format "${ref}". Expected "org/repo" with no extra slashes or empty segments.`, example);
41891
+ }
41892
+ const [orgName, repoName] = parts;
41893
+ return { orgName, repoName };
41894
+ }
41482
41895
  function ensureNonEmptyDisplayName(value, exampleCommand) {
41483
41896
  if (value !== undefined && value.trim() === "") {
41484
41897
  usageError("--display-name requires a non-empty value", exampleCommand);
@@ -41730,11 +42143,7 @@ var confirmFlags2 = {
41730
42143
  yes: flag.boolean({ short: "y", description: "Skip confirmation prompt" })
41731
42144
  };
41732
42145
  var handleArchive2 = async (ctx, { flags, args }) => {
41733
- const orgRepo = args[0];
41734
- if (!orgRepo?.includes("/")) {
41735
- usageError("Usage: wh repo archive <org/repo> [--yes]", "wh repo archive myorg/old-repo");
41736
- }
41737
- const [orgName, repoName] = orgRepo.split("/", 2);
42146
+ const { orgName, repoName } = parseExplicitOrgRepoArg(args[0], "Usage: wh repo archive <org/repo> [--yes]", "wh repo archive myorg/old-repo");
41738
42147
  if (!flags.yes) {
41739
42148
  const confirmed = await ctx.confirm?.(`Archive repo "${orgName}/${repoName}"? This will block new commits.`);
41740
42149
  if (!confirmed) {
@@ -41749,11 +42158,7 @@ var handleArchive2 = async (ctx, { flags, args }) => {
41749
42158
  });
41750
42159
  };
41751
42160
  var handleUnarchive2 = async (ctx, { args }) => {
41752
- const orgRepo = args[0];
41753
- if (!orgRepo?.includes("/")) {
41754
- usageError("Usage: wh repo unarchive <org/repo>", "wh repo unarchive myorg/old-repo");
41755
- }
41756
- const [orgName, repoName] = orgRepo.split("/", 2);
42161
+ const { orgName, repoName } = parseExplicitOrgRepoArg(args[0], "Usage: wh repo unarchive <org/repo>", "wh repo unarchive myorg/old-repo");
41757
42162
  const c = ctx.colors;
41758
42163
  const result = await ctx.client.repo.unarchive(orgName, repoName);
41759
42164
  writeOutput(ctx, result, () => {
@@ -41764,11 +42169,7 @@ var deleteFlags = {
41764
42169
  yes: flag.boolean({ short: "y", description: "Skip confirmation prompt" })
41765
42170
  };
41766
42171
  var handleDelete2 = async (ctx, { flags, args }) => {
41767
- const orgRepo = args[0];
41768
- if (!orgRepo?.includes("/")) {
41769
- usageError("Usage: wh repo delete <org/repo> [--yes]", "wh repo delete myorg/old-repo");
41770
- }
41771
- const [orgName, repoName] = orgRepo.split("/", 2);
42172
+ const { orgName, repoName } = parseExplicitOrgRepoArg(args[0], "Usage: wh repo delete <org/repo> [--yes]", "wh repo delete myorg/old-repo");
41772
42173
  const c = ctx.colors;
41773
42174
  if (!flags.yes) {
41774
42175
  const prompt = `Delete "${orgName}/${repoName}"? The repo will be hidden immediately and permanently deleted after a 30-day grace window.`;
@@ -41866,21 +42267,23 @@ var handleRepoRename = async (ctx, { args, flags }) => {
41866
42267
  const flagSlug = flags.slug;
41867
42268
  const displayName2 = flags["display-name"];
41868
42269
  const rawSlugFromInvocation = ctx.invocation.positional[2];
42270
+ const usage = 'Usage: wh repo rename <org/repoName> [<newName>] [--slug <slug>] [--display-name "..."]';
42271
+ const example = 'wh repo rename myorg/oldrepo newrepo --display-name "New Repo"';
41869
42272
  if (!orgRepo?.includes("/")) {
41870
- usageError('Usage: wh repo rename <org/repoName> [<newName>] [--slug <slug>] [--display-name "..."]', 'wh repo rename myorg/oldrepo newrepo --display-name "New Repo"');
42273
+ usageError(usage, example);
41871
42274
  }
41872
42275
  if (positionalSlug && flagSlug !== undefined && positionalSlug !== flagSlug) {
41873
42276
  usageError("Specify the new slug as either a positional or --slug, not both", "wh repo rename myorg/foo bar # or: wh repo rename myorg/foo --slug bar");
41874
42277
  }
41875
42278
  const newSlug = positionalSlug !== undefined ? positionalSlug : flagSlug;
41876
42279
  if (newSlug === undefined && displayName2 === undefined) {
41877
- usageError('Usage: wh repo rename <org/repoName> [<newName>] [--slug <slug>] [--display-name "..."]', 'wh repo rename myorg/oldrepo newrepo --display-name "New Repo"');
42280
+ usageError(usage, example);
41878
42281
  }
41879
42282
  if (newSlug !== undefined && newSlug.length === 0 || rawSlugFromInvocation === "" || flagSlug === "") {
41880
42283
  usageError("New slug must be a non-empty string", "wh repo rename myorg/oldrepo newrepo");
41881
42284
  }
41882
42285
  ensureNonEmptyDisplayName(displayName2, 'wh repo rename myorg/oldrepo --display-name "New Repo"');
41883
- const [orgName, oldName] = orgRepo.split("/", 2);
42286
+ const { orgName, repoName: oldName } = parseExplicitOrgRepoArg(orgRepo, usage, example);
41884
42287
  const c = ctx.colors;
41885
42288
  const slugChange = newSlug && newSlug !== oldName ? newSlug : undefined;
41886
42289
  if (displayName2 !== undefined && slugChange) {
@@ -41909,14 +42312,12 @@ var updateFlags3 = {
41909
42312
  description: flag.string({ short: "d", description: "New repo description" })
41910
42313
  };
41911
42314
  var handleUpdate3 = async (ctx, { args, flags }) => {
41912
- const orgRepo = args[0];
41913
- if (!orgRepo?.includes("/")) {
41914
- usageError('Usage: wh repo update <org/repo> --description "..."', 'wh repo update myorg/myrepo -d "My repo description"');
41915
- }
42315
+ const usage = 'Usage: wh repo update <org/repo> --description "..."';
42316
+ const example = 'wh repo update myorg/myrepo -d "My repo description"';
42317
+ const { orgName, repoName } = parseExplicitOrgRepoArg(args[0], usage, example);
41916
42318
  if (flags.description === undefined) {
41917
42319
  usageError("At least one field must be specified to update", 'wh repo update myorg/myrepo --description "New description"');
41918
42320
  }
41919
- const [orgName, repoName] = orgRepo.split("/", 2);
41920
42321
  const c = ctx.colors;
41921
42322
  const description = flags.description === "" ? undefined : flags.description;
41922
42323
  const result = await ctx.client.repo.setDescription(orgName, repoName, description);
@@ -42005,7 +42406,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
42005
42406
  const data = version?.data;
42006
42407
  const shapeDesc = data?.description;
42007
42408
  if (typeof shapeDesc === "string" && shapeDesc) {
42008
- ctx.out(` ${c.dim}${shapeDesc}${c.reset}`);
42409
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDesc)}${c.reset}`);
42009
42410
  }
42010
42411
  const fields = data?.fields;
42011
42412
  if (fields) {
@@ -42017,9 +42418,10 @@ var handleDescribe = async (ctx, { args, flags }) => {
42017
42418
  return Math.max(m, ts.length);
42018
42419
  }, 0);
42019
42420
  for (const [fieldName, fieldType] of entries) {
42421
+ const safeFieldName = escapeFieldNameForDisplay(fieldName);
42020
42422
  const typeStr = displayFieldType(fieldType);
42021
42423
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42022
- 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}`;
42023
42425
  ctx.out(line);
42024
42426
  }
42025
42427
  }
@@ -42408,7 +42810,7 @@ var handleList6 = async (ctx, { flags }) => {
42408
42810
  const shapeData = shape.version?.data;
42409
42811
  const shapeDescription = shapeData?.description;
42410
42812
  if (typeof shapeDescription === "string" && shapeDescription) {
42411
- ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
42813
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDescription)}${c.reset}`);
42412
42814
  }
42413
42815
  const fields = shapeData?.fields;
42414
42816
  if (fields) {
@@ -42423,7 +42825,7 @@ var handleList6 = async (ctx, { flags }) => {
42423
42825
  const typeStr = displayFieldType(fieldType);
42424
42826
  const padded = fieldName.padEnd(maxLen);
42425
42827
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42426
- const descSuffix = fieldDesc ? ` ${typeStr.padEnd(maxTypeLen)} ${fieldDesc}` : ` ${typeStr}`;
42828
+ const descSuffix = fieldDesc ? ` ${typeStr.padEnd(maxTypeLen)} ${escapeTerminalTextForDisplay(fieldDesc)}` : ` ${typeStr}`;
42427
42829
  ctx.out(` ${c.cyan}${padded}${c.reset} ${c.dim}${descSuffix}${c.reset}`);
42428
42830
  }
42429
42831
  }
@@ -42455,7 +42857,7 @@ var handleView7 = async (ctx, { flags, args }) => {
42455
42857
  const shapeData = shapeVersion?.data;
42456
42858
  const shapeDescription = shapeData?.description;
42457
42859
  if (typeof shapeDescription === "string" && shapeDescription) {
42458
- ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
42860
+ ctx.out(` ${c.dim}${escapeTerminalTextForDisplay(shapeDescription)}${c.reset}`);
42459
42861
  }
42460
42862
  const componentRef = result.componentRef;
42461
42863
  if (componentRef) {
@@ -42467,7 +42869,7 @@ var handleView7 = async (ctx, { flags, args }) => {
42467
42869
  for (const [fieldName, fieldType] of Object.entries(fields)) {
42468
42870
  const typeStr = displayFieldType(fieldType);
42469
42871
  const fieldDesc = fieldDescriptionFromSpec(fieldType);
42470
- const descSuffix = fieldDesc ? ` ${c.dim}${fieldDesc}${c.reset}` : "";
42872
+ const descSuffix = fieldDesc ? ` ${c.dim}${escapeTerminalTextForDisplay(fieldDesc)}${c.reset}` : "";
42471
42873
  const safeFieldName = escapeFieldNameForDisplay(fieldName);
42472
42874
  ctx.out(` ${c.cyan}${safeFieldName}${c.reset}: ${c.dim}${typeStr}${c.reset}${descSuffix}`);
42473
42875
  }
@@ -42568,8 +42970,10 @@ var handleShapeRename = async (ctx, { args }) => {
42568
42970
  }
42569
42971
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
42570
42972
  const c = ctx.colors;
42571
- await ctx.client.shape.rename(org, repo, oldName, newName);
42572
- 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
+ });
42573
42977
  };
42574
42978
 
42575
42979
  // ../../packages/warmhub-cli/src/domains/shape.ts
@@ -43026,6 +43430,11 @@ function renderResponseSnippet(out, c, snippet, baseIndent) {
43026
43430
  out(`${baseIndent} ${c.dim}${line}${c.reset}`);
43027
43431
  }
43028
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
+ }
43029
43438
  function statusColor(c, status) {
43030
43439
  switch (status) {
43031
43440
  case "completed":
@@ -43066,11 +43475,10 @@ function renderSubscriptionLog(out, statusOut, c, subscriptionName, result) {
43066
43475
  const sourceLabel = (item.matchedOperationIndexes?.length ?? 0) > 0 ? `${c.cyan}write${c.reset}` : `${c.magenta}cron tick${c.reset}`;
43067
43476
  const matched = (item.matchedOperationIndexes ?? []).join(",") || "-";
43068
43477
  const attemptSuffix = item.attemptCount != null && item.maxAttempts != null ? ` ${c.dim}${item.attemptCount}/${item.maxAttempts}${c.reset}` : "";
43069
- const runSuffix = item.runId ? ` ${c.dim}run ${item.runId}${c.reset}` : "";
43070
- 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}]`);
43071
43480
  if ((displayStatus === "failed_terminal" || displayStatus === "dead_letter") && item.lastErrorMessage) {
43072
- const code = item.lastErrorCode ? `${item.lastErrorCode}: ` : "";
43073
- out(` ${c.red}${code}${item.lastErrorMessage}${c.reset}`);
43481
+ renderErrorMessageLine(out, c, item.lastErrorCode, item.lastErrorMessage, " ");
43074
43482
  }
43075
43483
  if ((displayStatus === "failed_terminal" || displayStatus === "dead_letter") && item.lastResponseSnippet) {
43076
43484
  renderResponseSnippet(out, c, item.lastResponseSnippet, " ");
@@ -43181,7 +43589,12 @@ var handleLog = async (ctx, { flags, args }) => {
43181
43589
  if (!name) {
43182
43590
  usageError("Usage: wh sub log <name> [--repo org/repo]", "wh sub log my-sub");
43183
43591
  }
43184
- 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;
43185
43598
  if (ctx.liveMode) {
43186
43599
  await runLive({
43187
43600
  apiUrl: ctx.config.apiUrl,
@@ -43225,8 +43638,7 @@ var handleAttempts = async (ctx, { args }) => {
43225
43638
  const http = attempt.httpStatus ? ` ${c.dim}HTTP ${attempt.httpStatus}${c.reset}` : "";
43226
43639
  ctx.out(` #${attempt.attempt} ${sc}${attempt.status}${c.reset}${dur}${http}`);
43227
43640
  if (attempt.errorMessage) {
43228
- const code = attempt.errorCode ? `${attempt.errorCode}: ` : "";
43229
- ctx.out(` ${c.red}${code}${attempt.errorMessage}${c.reset}`);
43641
+ renderErrorMessageLine(ctx.out, c, attempt.errorCode, attempt.errorMessage, " ");
43230
43642
  }
43231
43643
  if (attempt.status === "failed" && attempt.responseSnippet) {
43232
43644
  renderResponseSnippet(ctx.out, c, attempt.responseSnippet, " ");
@@ -43319,6 +43731,9 @@ var SUB_DOMAIN = defineDomain({
43319
43731
  summary: "Tail subscription delivery feed with failed response snippets",
43320
43732
  args: "<name>",
43321
43733
  flags: logFlags,
43734
+ rejectedFlags: {
43735
+ org: "Use repo-scoped delivery logs: wh sub log my-sub --repo myorg/myrepo"
43736
+ },
43322
43737
  examples: [
43323
43738
  "# Show recent deliveries",
43324
43739
  " $ wh sub log signal-hook --repo org/repo",
@@ -43327,7 +43742,10 @@ var SUB_DOMAIN = defineDomain({
43327
43742
  " $ wh sub log daily-digest --repo org/repo",
43328
43743
  "",
43329
43744
  "# Follow deliveries in live mode",
43330
- " $ 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"
43331
43749
  ],
43332
43750
  handler: handleLog
43333
43751
  },
@@ -44284,9 +44702,9 @@ function extractFlagsForVerb(flags, verbSpec) {
44284
44702
  }
44285
44703
  return flags;
44286
44704
  }
44287
- return extractFlags(flags, verbSpec.flags);
44705
+ return extractFlags(flags, verbSpec.flags, verbSpec.rejectedFlags);
44288
44706
  }
44289
- function extractFlags(flags, specs) {
44707
+ function extractFlags(flags, specs, rejectedFlags = {}) {
44290
44708
  const normalized = { ...flags };
44291
44709
  const result = {};
44292
44710
  const specLongs = specs.map((s) => s.long);
@@ -44321,11 +44739,19 @@ function extractFlags(flags, specs) {
44321
44739
  }
44322
44740
  for (const key of Object.keys(normalized)) {
44323
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
+ }
44324
44746
  if (!allowedShorts.has(key) && !isGlobalFlag(key)) {
44325
44747
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: -${key}`);
44326
44748
  }
44327
44749
  continue;
44328
44750
  }
44751
+ const rejectedHint = rejectedFlags[key];
44752
+ if (rejectedHint) {
44753
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: --${key}`, undefined, rejectedHint);
44754
+ }
44329
44755
  if (!allowedLongs.has(key) && !isGlobalFlag(key)) {
44330
44756
  const hint = findClosest(key, [...allowedLongs]);
44331
44757
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown flag: --${key}`, undefined, hint ? `Did you mean '--${hint}'?` : undefined);
@@ -44345,12 +44771,13 @@ function extractFlags(flags, specs) {
44345
44771
  result[spec.long] = Boolean(value);
44346
44772
  break;
44347
44773
  case "number": {
44348
- if (typeof value === "boolean") {
44774
+ const scalarValue = Array.isArray(value) ? value[value.length - 1] : value;
44775
+ if (typeof scalarValue === "boolean") {
44349
44776
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Flag --${spec.long} requires a numeric value`, undefined, `Usage: --${spec.long} <number>`);
44350
44777
  }
44351
- const n = Number(value);
44778
+ const n = Number(scalarValue);
44352
44779
  if (!Number.isFinite(n)) {
44353
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid number for --${spec.long}: '${value}'`, undefined, `Expected a number, e.g. --${spec.long} 10`);
44780
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid number for --${spec.long}: '${scalarValue}'`, undefined, `Expected a number, e.g. --${spec.long} 10`);
44354
44781
  }
44355
44782
  result[spec.long] = n;
44356
44783
  break;
@@ -44558,6 +44985,11 @@ function walkSubdomainsForHelpAll(out) {
44558
44985
  for (const [verbName, verb] of Object.entries(sub.verbs)) {
44559
44986
  out(` ${domain.name} ${subName} ${verbName.padEnd(12)} ${verb.summary}`);
44560
44987
  }
44988
+ } else {
44989
+ out(` ${domain.name} ${subName.padEnd(12)} ${sub.summary}`);
44990
+ if (sub.args) {
44991
+ out(` Usage: wh ${domain.name} ${subName} ${sub.args}`);
44992
+ }
44561
44993
  }
44562
44994
  }
44563
44995
  }
@@ -44725,6 +45157,20 @@ function printVerbHelp(out, domain, verbName, verb, format, domainPath) {
44725
45157
  }
44726
45158
 
44727
45159
  // ../../packages/warmhub-cli/src/domain-dispatch-core.ts
45160
+ function resolveDomainPathSpec(domain, domainPath) {
45161
+ let cursor = domain;
45162
+ for (const seg of domainPath.slice(1)) {
45163
+ if (cursor.kind !== "noun") {
45164
+ throw new CliError(1 /* Runtime */, "UNKNOWN", `Invalid subdomain path: ${seg}`);
45165
+ }
45166
+ const next = cursor.subdomains?.[seg];
45167
+ if (!next) {
45168
+ throw new CliError(1 /* Runtime */, "UNKNOWN", `Invalid subdomain path: ${seg}`);
45169
+ }
45170
+ cursor = next;
45171
+ }
45172
+ return cursor;
45173
+ }
44728
45174
  async function dispatchDomain(ctx, depth = 0) {
44729
45175
  const tokens = [
44730
45176
  ctx.invocation.command ?? "",
@@ -44752,9 +45198,10 @@ async function dispatchDomain(ctx, depth = 0) {
44752
45198
  }
44753
45199
  const { domain, domainPath, verb, remaining } = resolved;
44754
45200
  const helpRequested = ctx.invocation.flags.help === true || ctx.invocation.flags.h === true;
44755
- if (domain.kind === "flat") {
45201
+ const pathSpec = resolveDomainPathSpec(domain, domainPath);
45202
+ if (pathSpec.kind === "flat") {
44756
45203
  if (helpRequested) {
44757
- printDomainVerbHelp(ctx.out, domain, ctx.format, domainPath);
45204
+ printDomainVerbHelp(ctx.out, pathSpec, ctx.format, domainPath);
44758
45205
  return true;
44759
45206
  }
44760
45207
  if (remaining.length > 0) {
@@ -44764,13 +45211,13 @@ async function dispatchDomain(ctx, depth = 0) {
44764
45211
  throwRenameHint(flatRenameHint);
44765
45212
  }
44766
45213
  }
44767
- const maxPositional = countMaxPositional(domain.args);
45214
+ const maxPositional = countMaxPositional(pathSpec.args);
44768
45215
  if (remaining.length > maxPositional) {
44769
45216
  const extra = remaining[maxPositional];
44770
- const usageHint = maxPositional === 0 ? `'wh ${domainPath.join(" ")}' takes no positional arguments` : `'wh ${domainPath.join(" ")}' accepts at most ${maxPositional} positional argument${maxPositional === 1 ? "" : "s"} (${domain.args})`;
45217
+ const usageHint = maxPositional === 0 ? `'wh ${domainPath.join(" ")}' takes no positional arguments` : `'wh ${domainPath.join(" ")}' accepts at most ${maxPositional} positional argument${maxPositional === 1 ? "" : "s"} (${pathSpec.args})`;
44771
45218
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unexpected argument: '${extra}'`, undefined, usageHint);
44772
45219
  }
44773
- const typedFlags2 = extractFlags(ctx.invocation.flags, domain.flags);
45220
+ const typedFlags2 = extractFlags(ctx.invocation.flags, pathSpec.flags);
44774
45221
  const allArgs = verb ? [verb, ...remaining] : remaining;
44775
45222
  if (ctx.dryRun) {
44776
45223
  ctx.out(JSON.stringify({
@@ -44793,12 +45240,7 @@ async function dispatchDomain(ctx, depth = 0) {
44793
45240
  });
44794
45241
  return true;
44795
45242
  }
44796
- const specCursor = domainPath.slice(1).reduce((d, seg) => {
44797
- const next = d.subdomains?.[seg];
44798
- if (!next || next.kind === "flat")
44799
- throw new CliError(1 /* Runtime */, "UNKNOWN", `Invalid subdomain path: ${seg}`);
44800
- return next;
44801
- }, domain);
45243
+ const specCursor = pathSpec;
44802
45244
  const verbs = Object.keys(specCursor.verbs);
44803
45245
  const invokeSingleVerb = async (args) => {
44804
45246
  if (verbs.length !== 1 || helpRequested)
@@ -45108,6 +45550,8 @@ function parseFunctionLogMode(flags, env) {
45108
45550
  async function runCli(argv, opts) {
45109
45551
  const version = opts?.version ?? package_default2.version;
45110
45552
  setCliClientVersion(version);
45553
+ startCliTraceContext();
45554
+ const traceFields = cliTraceLogFields();
45111
45555
  const startedAt = Date.now();
45112
45556
  const { out, err } = stdioWriter();
45113
45557
  const parsed = parseArgs(argv);
@@ -45135,7 +45579,8 @@ async function runCli(argv, opts) {
45135
45579
  cwd: process.cwd(),
45136
45580
  node: process.version,
45137
45581
  pid: process.pid,
45138
- profile: getStringFlag(invocation.flags, "profile", "P") ?? undefined
45582
+ profile: getStringFlag(invocation.flags, "profile", "P") ?? undefined,
45583
+ ...traceFields
45139
45584
  });
45140
45585
  let exitCode = 0 /* Ok */;
45141
45586
  let removeSignalListeners;
@@ -45194,14 +45639,14 @@ async function runCli(argv, opts) {
45194
45639
  let cancelledExitCode;
45195
45640
  const handleSigint = () => {
45196
45641
  ac.abort();
45197
- logger.info("cli.cancelled", { signal: "SIGINT" });
45642
+ logger.info("cli.cancelled", { signal: "SIGINT", ...traceFields });
45198
45643
  cancelledExitCode = cancellationExitCode("SIGINT", liveMode);
45199
45644
  if (!liveMode)
45200
45645
  process.exitCode = 130 /* Cancelled */;
45201
45646
  };
45202
45647
  const handleSigterm = () => {
45203
45648
  ac.abort();
45204
- logger.info("cli.cancelled", { signal: "SIGTERM" });
45649
+ logger.info("cli.cancelled", { signal: "SIGTERM", ...traceFields });
45205
45650
  cancelledExitCode = cancellationExitCode("SIGTERM", liveMode);
45206
45651
  process.exitCode = 143;
45207
45652
  };
@@ -45241,7 +45686,8 @@ async function runCli(argv, opts) {
45241
45686
  const cliError = toCliError2(error);
45242
45687
  const fields = {
45243
45688
  kind: cliError.kind,
45244
- exit_code: cliError.code
45689
+ exit_code: cliError.code,
45690
+ ...traceFields
45245
45691
  };
45246
45692
  if (cliError.kind !== "USER_INPUT" && cliError.kind !== "CONFIG") {
45247
45693
  fields.message = cliError.message;
@@ -45261,7 +45707,8 @@ async function runCli(argv, opts) {
45261
45707
  removeSignalListeners?.();
45262
45708
  logger.info("cli.end", {
45263
45709
  exit_code: exitCode,
45264
- duration_ms: Date.now() - startedAt
45710
+ duration_ms: Date.now() - startedAt,
45711
+ ...traceFields
45265
45712
  });
45266
45713
  await logger.shutdown();
45267
45714
  }
@@ -45314,7 +45761,7 @@ function resolveLogLevel(flags, env) {
45314
45761
  // package.json
45315
45762
  var package_default3 = {
45316
45763
  name: "@warmhub/cli",
45317
- version: "0.62.0",
45764
+ version: "0.64.0",
45318
45765
  private: false,
45319
45766
  type: "module",
45320
45767
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -45355,6 +45802,7 @@ var package_default3 = {
45355
45802
  },
45356
45803
  scripts: {
45357
45804
  build: "bun run scripts/build.ts",
45805
+ prepack: "bun run build",
45358
45806
  "check:boundary": "node ../../scripts/lint/boundary-imports.mjs bin src scripts",
45359
45807
  "audit:bundle": "bun run scripts/audit-bundle.ts",
45360
45808
  "audit:pack": "bun run scripts/audit-pack.ts",
@@ -45374,6 +45822,14 @@ var package_default3 = {
45374
45822
  };
45375
45823
 
45376
45824
  // ../../packages/warmhub-cli/src/component-shell.ts
45825
+ function registeredComponentUsageHint(verb) {
45826
+ const example = verb === "install" ? "wh component install warmhub/veritas --repo myorg/myrepo" : "wh component update warmhub/identity --repo org/repo";
45827
+ return [
45828
+ `Usage: wh component ${verb} <org/name> --repo org/repo`,
45829
+ `Example: ${example}`
45830
+ ].join(`
45831
+ `);
45832
+ }
45377
45833
  async function maybeHandleComponentShellBoundary(argv, deps = {}) {
45378
45834
  const parsed = parseArgs(argv);
45379
45835
  const invocation = resolveInvocation(parsed);
@@ -45397,6 +45853,11 @@ async function maybeHandleComponentShellBoundary(argv, deps = {}) {
45397
45853
  if (getBoolFlag(invocation.flags, "dry-run")) {
45398
45854
  return;
45399
45855
  }
45856
+ const source = invocation.positional[1];
45857
+ if (source && invocation.positional.length > 2) {
45858
+ const unexpected = invocation.positional[2];
45859
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Unexpected argument '${unexpected}' for wh component ${componentShellVerb}.`, undefined, registeredComponentUsageHint(componentShellVerb));
45860
+ }
45400
45861
  const { config, client } = resolveCliContext({
45401
45862
  invocation,
45402
45863
  format,
@@ -45404,7 +45865,6 @@ async function maybeHandleComponentShellBoundary(argv, deps = {}) {
45404
45865
  config: deps.config,
45405
45866
  client: deps.client
45406
45867
  });
45407
- const source = invocation.positional[1];
45408
45868
  if (!source) {
45409
45869
  return;
45410
45870
  }
@@ -45956,4 +46416,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
45956
46416
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
45957
46417
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
45958
46418
 
45959
- //# debugId=FB7C860F078FFF2164756E2164756E21
46419
+ //# debugId=7FF3388CDD4F972C64756E2164756E21