@warmhub/cli 0.52.1 → 0.54.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 +625 -318
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -18914,6 +18914,10 @@ var RUNTIME_ACCESS_BUILTINS = new Set([
18914
18914
  "ComponentConfig",
18915
18915
  ...BUILTIN_SHAPE_NAMES
18916
18916
  ]);
18917
+ var SUBSCRIPTION_TRIGGER_BUILTINS = new Set([
18918
+ "ComponentInstall",
18919
+ "ComponentConfig"
18920
+ ]);
18917
18921
  function validateProvisioning(obj, path, errors) {
18918
18922
  if (!("provisioning" in obj))
18919
18923
  return;
@@ -19206,8 +19210,19 @@ function validateManifestSemantics(manifest) {
19206
19210
  }
19207
19211
  const shapeNames = new Set(manifest.shapes.map((s) => s.name));
19208
19212
  const credentialNames = new Set(manifest.credentials.map((c) => c.name));
19209
- const knownShapes = new Set([...shapeNames, "ComponentConfig"]);
19213
+ const knownSubscriptionTriggerShapes = new Set([
19214
+ ...shapeNames,
19215
+ ...SUBSCRIPTION_TRIGGER_BUILTINS
19216
+ ]);
19217
+ const knownSeedShapes = new Set([...shapeNames, "ComponentConfig"]);
19210
19218
  for (const sub of manifest.subscriptions) {
19219
+ if (sub.trigger.kind === "event" && !knownSubscriptionTriggerShapes.has(sub.trigger.shape)) {
19220
+ findings.push({
19221
+ level: "error",
19222
+ code: "MISSING_SUBSCRIPTION_TRIGGER_SHAPE_REF",
19223
+ message: `subscription "${sub.name}" trigger references shape "${sub.trigger.shape}" which is not declared and is not a supported subscription trigger built-in`
19224
+ });
19225
+ }
19211
19226
  if (sub.credentials) {
19212
19227
  if (sub.credentials.length > 1) {
19213
19228
  findings.push({
@@ -19236,7 +19251,7 @@ function validateManifestSemantics(manifest) {
19236
19251
  }
19237
19252
  }
19238
19253
  for (const seed of manifest.seeds) {
19239
- if (!knownShapes.has(seed.shape)) {
19254
+ if (!knownSeedShapes.has(seed.shape)) {
19240
19255
  findings.push({
19241
19256
  level: "error",
19242
19257
  code: "MISSING_SHAPE_REF",
@@ -19381,6 +19396,11 @@ function joinFieldIdentityPath(...segments) {
19381
19396
  function joinFieldPathWithEscaper(escapeSegment, segments) {
19382
19397
  return segments.map((segment) => typeof segment === "number" ? `[${segment}]` : escapeSegment(segment)).join(".").replace(/\.\[/g, "[");
19383
19398
  }
19399
+ // ../../packages/rules/src/permission-scopes.ts
19400
+ var PUBLIC_ORG_PERMISSIONS = new Set([
19401
+ "org:read",
19402
+ "components:read"
19403
+ ]);
19384
19404
  // ../../packages/rules/src/platform-status.ts
19385
19405
  var PLATFORM_STATUS_CATALOG_SHAPE = "PlatformStatusCatalog";
19386
19406
  var PLATFORM_STATUS_CATALOG_NAME = "main";
@@ -21213,6 +21233,7 @@ function nestedObjectFields(typeDef) {
21213
21233
  }
21214
21234
  // ../../packages/rules/src/system-components/system.ts
21215
21235
  var SYSTEM_COMPONENT_ID = "com.warmhub.system";
21236
+ var SYSTEM_REGISTERED_COMPONENT_REF = "warmhub/system";
21216
21237
  var COMPONENT_INSTALL_FIELDS = {
21217
21238
  componentId: "string",
21218
21239
  name: "string",
@@ -21273,7 +21294,7 @@ function findSystemComponent(componentId) {
21273
21294
  // ../../packages/sdk-ts/package.json
21274
21295
  var package_default = {
21275
21296
  name: "@warmhub/sdk-ts",
21276
- version: "0.52.0",
21297
+ version: "0.53.0",
21277
21298
  private: false,
21278
21299
  type: "module",
21279
21300
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -21601,7 +21622,7 @@ async function submitOperationsViaStream(client, args) {
21601
21622
  orgName: args.orgName,
21602
21623
  repoName: args.repoName,
21603
21624
  streamId,
21604
- componentId: args.componentId,
21625
+ componentRef: args.componentRef,
21605
21626
  committer: args.committer,
21606
21627
  message: args.message,
21607
21628
  operations: chunk
@@ -22107,23 +22128,9 @@ class WarmHubClient {
22107
22128
  }
22108
22129
  };
22109
22130
  access = {
22110
- checkRepoPermission: async (orgName, repoName, permission) => {
22111
- try {
22112
- return await this.trpc.access.checkRepoPermission.query({
22113
- orgName,
22114
- repoName,
22115
- permission
22116
- });
22117
- } catch (error) {
22118
- throw toWarmHubError(error);
22119
- }
22120
- },
22121
- checkOrgPermission: async (orgName, permission) => {
22131
+ resolve: async (input) => {
22122
22132
  try {
22123
- return await this.trpc.access.checkOrgPermission.query({
22124
- orgName,
22125
- permission
22126
- });
22133
+ return await this.trpc.access.resolve.query(input);
22127
22134
  } catch (error) {
22128
22135
  throw toWarmHubError(error);
22129
22136
  }
@@ -22177,12 +22184,23 @@ class WarmHubClient {
22177
22184
  throw toWarmHubError(error);
22178
22185
  }
22179
22186
  },
22180
- get: async (orgName, repoName, componentId) => {
22187
+ search: async (query, opts) => {
22188
+ try {
22189
+ return await this.trpc.component.search.query({
22190
+ query,
22191
+ limit: opts?.limit,
22192
+ cursor: opts?.cursor
22193
+ });
22194
+ } catch (error) {
22195
+ throw toWarmHubError(error);
22196
+ }
22197
+ },
22198
+ get: async (orgName, repoName, componentRef) => {
22181
22199
  try {
22182
22200
  return await this.trpc.component.get.query({
22183
22201
  orgName,
22184
22202
  repoName,
22185
- componentId
22203
+ componentRef
22186
22204
  });
22187
22205
  } catch (error) {
22188
22206
  throw toWarmHubError(error);
@@ -22277,7 +22295,7 @@ class WarmHubClient {
22277
22295
  repoName,
22278
22296
  committer: opts?.committer,
22279
22297
  message,
22280
- componentId: opts?.componentId,
22298
+ componentRef: opts?.componentRef,
22281
22299
  chunkSize: opts?.chunkSize,
22282
22300
  skipExisting: opts?.skipExisting,
22283
22301
  streamId: opts?.streamId,
@@ -22512,6 +22530,17 @@ class WarmHubClient {
22512
22530
  throw toWarmHubError(error);
22513
22531
  }
22514
22532
  },
22533
+ search: async (query, opts) => {
22534
+ try {
22535
+ return await this.trpc.repo.search.query({
22536
+ query,
22537
+ limit: opts?.limit,
22538
+ cursor: opts?.cursor
22539
+ });
22540
+ } catch (error) {
22541
+ throw toWarmHubError(error);
22542
+ }
22543
+ },
22515
22544
  create: async (orgName, repoName, description, visibility, displayName) => {
22516
22545
  try {
22517
22546
  return await this.trpc.repo.create.mutate({
@@ -22715,7 +22744,7 @@ class WarmHubClient {
22715
22744
  orgName,
22716
22745
  repoName,
22717
22746
  match: opts?.match,
22718
- componentId: opts?.componentId,
22747
+ componentRef: opts?.componentRef,
22719
22748
  excludeComponents: opts?.excludeComponents,
22720
22749
  includeRetracted: opts?.includeRetracted
22721
22750
  });
@@ -23061,7 +23090,7 @@ class WarmHubClient {
23061
23090
  includeRetracted: opts?.includeRetracted,
23062
23091
  limit: opts?.limit,
23063
23092
  cursor: opts?.cursor,
23064
- componentId: opts?.componentId,
23093
+ componentRef: opts?.componentRef,
23065
23094
  excludeComponents: opts?.excludeComponents,
23066
23095
  excludeInfraShapes: opts?.excludeInfraShapes,
23067
23096
  where: opts?.where
@@ -23282,7 +23311,7 @@ class WarmHubClient {
23282
23311
  resolveCollections: opts?.resolveCollections,
23283
23312
  limit: opts?.limit,
23284
23313
  cursor: opts?.cursor,
23285
- componentId: opts?.componentId,
23314
+ componentRef: opts?.componentRef,
23286
23315
  excludeComponents: opts?.excludeComponents,
23287
23316
  excludeInfraShapes: opts?.excludeInfraShapes,
23288
23317
  where: opts?.where
@@ -23313,7 +23342,7 @@ class WarmHubClient {
23313
23342
  resolveCollections: opts?.resolveCollections,
23314
23343
  limit: opts?.limit,
23315
23344
  cursor: opts?.cursor,
23316
- componentId: opts?.componentId,
23345
+ componentRef: opts?.componentRef,
23317
23346
  excludeComponents: opts?.excludeComponents,
23318
23347
  excludeInfraShapes: opts?.excludeInfraShapes,
23319
23348
  mode: opts?.mode
@@ -23334,7 +23363,7 @@ class WarmHubClient {
23334
23363
  match: opts?.match,
23335
23364
  includeRetracted: opts?.includeRetracted,
23336
23365
  resolveCollections: opts?.resolveCollections,
23337
- componentId: opts?.componentId,
23366
+ componentRef: opts?.componentRef,
23338
23367
  excludeComponents: opts?.excludeComponents,
23339
23368
  excludeInfraShapes: opts?.excludeInfraShapes,
23340
23369
  where: opts?.where
@@ -24698,37 +24727,65 @@ function makeStderrSink(minLevel) {
24698
24727
  function enforceLineCap(record) {
24699
24728
  const initial = `${JSON.stringify(record)}
24700
24729
  `;
24701
- if (initial.length <= LINE_CAP + 1)
24730
+ if (lineByteLength(initial) <= LINE_CAP + 1)
24702
24731
  return initial;
24703
24732
  const trimmed = { ...record };
24704
24733
  for (let pass = 0;pass < 8; pass++) {
24705
24734
  const candidate = `${JSON.stringify(trimmed)}
24706
24735
  `;
24707
- if (candidate.length <= LINE_CAP + 1)
24736
+ if (lineByteLength(candidate) <= LINE_CAP + 1)
24708
24737
  return candidate;
24709
24738
  let largestKey = null;
24710
24739
  let largestLen = 0;
24711
24740
  for (const [key, val] of Object.entries(trimmed)) {
24712
- if (typeof val === "string" && val.length > largestLen) {
24741
+ if (typeof val === "string") {
24742
+ const byteLen = lineByteLength(val);
24743
+ if (byteLen <= largestLen)
24744
+ continue;
24713
24745
  largestKey = key;
24714
- largestLen = val.length;
24746
+ largestLen = byteLen;
24715
24747
  }
24716
24748
  }
24717
24749
  if (largestKey === null)
24718
24750
  break;
24719
- const overage = candidate.length - LINE_CAP - 1;
24751
+ const overage = lineByteLength(candidate) - LINE_CAP - 1;
24720
24752
  const current = trimmed[largestKey];
24721
- const allowed = Math.max(0, current.length - overage - TRUNCATED_MARKER.length);
24722
- trimmed[largestKey] = `${current.slice(0, allowed)}${TRUNCATED_MARKER}`;
24753
+ const allowedBytes = Math.max(0, lineByteLength(current) - overage - lineByteLength(TRUNCATED_MARKER));
24754
+ trimmed[largestKey] = `${sliceUtf8Bytes(current, allowedBytes)}${TRUNCATED_MARKER}`;
24723
24755
  }
24724
- return `${JSON.stringify({
24756
+ const fallback = {
24725
24757
  v: trimmed.v,
24726
24758
  ts: trimmed.ts,
24727
24759
  level: trimmed.level,
24728
24760
  msg: trimmed.msg,
24729
24761
  truncated: TRUNCATED_MARKER
24730
- })}
24762
+ };
24763
+ let line = `${JSON.stringify(fallback)}
24764
+ `;
24765
+ if (lineByteLength(line) <= LINE_CAP + 1)
24766
+ return line;
24767
+ const emptyMsgLine = `${JSON.stringify({ ...fallback, msg: "" })}
24768
+ `;
24769
+ const msgBudget = Math.max(0, LINE_CAP + 1 - lineByteLength(emptyMsgLine));
24770
+ fallback.msg = sliceUtf8Bytes(fallback.msg, msgBudget);
24771
+ line = `${JSON.stringify(fallback)}
24731
24772
  `;
24773
+ return line;
24774
+ }
24775
+ function lineByteLength(value) {
24776
+ return Buffer.byteLength(value, "utf8");
24777
+ }
24778
+ function sliceUtf8Bytes(value, maxBytes) {
24779
+ let bytes = 0;
24780
+ let result = "";
24781
+ for (const char of value) {
24782
+ const charBytes = lineByteLength(char);
24783
+ if (bytes + charBytes > maxBytes)
24784
+ break;
24785
+ result += char;
24786
+ bytes += charBytes;
24787
+ }
24788
+ return result;
24732
24789
  }
24733
24790
  function rotateIfNeeded(path, dir) {
24734
24791
  if (!existsSync(path))
@@ -25176,7 +25233,7 @@ function loadProfileStore(path) {
25176
25233
  } catch (cause) {
25177
25234
  throw corruptedAuthError(p, cause);
25178
25235
  }
25179
- if (parsed === null || typeof parsed !== "object" || parsed.version !== 1 || parsed.profiles === null || typeof parsed.profiles !== "object") {
25236
+ if (parsed === null || typeof parsed !== "object" || parsed.version !== 1 || parsed.profiles === null || typeof parsed.profiles !== "object" || Array.isArray(parsed.profiles)) {
25180
25237
  throw corruptedAuthError(p);
25181
25238
  }
25182
25239
  return parsed;
@@ -25403,10 +25460,11 @@ async function getValidToken(profile) {
25403
25460
  });
25404
25461
  await delay(1000);
25405
25462
  log.info("auth.refresh.retry", { profile: profileName, attempt: 2 });
25463
+ let retryStarted = Date.now();
25406
25464
  try {
25407
25465
  const retryProf = getProfile(profileName, authPath);
25408
25466
  const retryTokens = retryProf?.tokens ?? lockedTokens;
25409
- const retryStarted = Date.now();
25467
+ retryStarted = Date.now();
25410
25468
  const refreshed = await refreshAccessToken(retryTokens);
25411
25469
  saveProfileWhileLocked(profileName, { ...retryProf ?? lockedProf, tokens: refreshed }, authPath);
25412
25470
  log.info("auth.refresh.ok", {
@@ -25421,7 +25479,7 @@ async function getValidToken(profile) {
25421
25479
  const fields = {
25422
25480
  profile: profileName,
25423
25481
  classification,
25424
- duration_ms: Date.now() - refreshStarted,
25482
+ duration_ms: Date.now() - retryStarted,
25425
25483
  error_name: retryErr instanceof Error ? retryErr.name : "Unknown",
25426
25484
  on_retry: true
25427
25485
  };
@@ -25481,20 +25539,34 @@ function recordBenchmarkResponse(response, benchmarkId) {
25481
25539
  benchmarkTelemetry.requestDbQueryCountSum += requestDbQueryCount;
25482
25540
  }
25483
25541
  }
25484
- function createBenchmarkAwareFetch(benchmarkId) {
25485
- if (!benchmarkId)
25542
+ function createBenchmarkAwareFetch(benchmarkId, signal) {
25543
+ if (!benchmarkId && !signal)
25486
25544
  return;
25487
25545
  return async (input, init) => {
25488
25546
  const headers = new Headers(init?.headers);
25489
- headers.set(BENCHMARK_HEADER, benchmarkId);
25547
+ if (benchmarkId)
25548
+ headers.set(BENCHMARK_HEADER, benchmarkId);
25490
25549
  const response = await fetch(input, {
25491
25550
  ...init,
25492
- headers
25551
+ headers,
25552
+ signal: mergeAbortSignals(init?.signal, signal)
25493
25553
  });
25494
- recordBenchmarkResponse(response, benchmarkId);
25554
+ if (benchmarkId)
25555
+ recordBenchmarkResponse(response, benchmarkId);
25495
25556
  return response;
25496
25557
  };
25497
25558
  }
25559
+ function mergeAbortSignals(requestSignal, liveSignal) {
25560
+ if (!requestSignal)
25561
+ return liveSignal;
25562
+ if (!liveSignal)
25563
+ return requestSignal;
25564
+ if (requestSignal.aborted)
25565
+ return requestSignal;
25566
+ if (liveSignal.aborted)
25567
+ return liveSignal;
25568
+ return AbortSignal.any([requestSignal, liveSignal]);
25569
+ }
25498
25570
  function resetBenchmarkTelemetry() {
25499
25571
  benchmarkTelemetry = emptyBenchmarkTelemetry();
25500
25572
  }
@@ -25522,18 +25594,34 @@ function createClient(config, opts = {}) {
25522
25594
  function wantsStructuredLiveOutput(format) {
25523
25595
  return format === "json" || format === "jsonl";
25524
25596
  }
25597
+ var LIVE_ABORTED = Symbol("live-aborted");
25598
+ function pollUntilAbort(poll, signal) {
25599
+ if (signal.aborted)
25600
+ return Promise.resolve(LIVE_ABORTED);
25601
+ return new Promise((resolve, reject) => {
25602
+ const onAbort = () => resolve(LIVE_ABORTED);
25603
+ signal.addEventListener("abort", onAbort, { once: true });
25604
+ poll.then((result) => {
25605
+ signal.removeEventListener("abort", onAbort);
25606
+ resolve(result);
25607
+ }, (error) => {
25608
+ signal.removeEventListener("abort", onAbort);
25609
+ reject(error);
25610
+ });
25611
+ });
25612
+ }
25525
25613
  async function runLive(opts) {
25526
25614
  const auth = opts.auth ?? {
25527
25615
  getToken: async () => await getValidToken(opts.profile) ?? undefined
25528
25616
  };
25529
25617
  const benchmarkId = process.env.WH_BENCHMARK_ID?.trim();
25618
+ const controller = new AbortController;
25530
25619
  const client = new WarmHubClient({
25531
25620
  apiUrl: opts.apiUrl,
25532
25621
  auth,
25533
- fetch: createBenchmarkAwareFetch(benchmarkId),
25622
+ fetch: createBenchmarkAwareFetch(benchmarkId, controller.signal),
25534
25623
  functionLogs: opts.functionLogs
25535
25624
  });
25536
- const controller = new AbortController;
25537
25625
  if (opts.signal) {
25538
25626
  if (opts.signal.aborted)
25539
25627
  controller.abort();
@@ -25557,7 +25645,12 @@ async function runLive(opts) {
25557
25645
  startTimer = setTimeout(() => controller.abort(), opts.startTimeoutMs);
25558
25646
  }
25559
25647
  while (!controller.signal.aborted) {
25560
- const result = await opts.poll(client);
25648
+ const poll = opts.poll(client, controller.signal);
25649
+ const result = await pollUntilAbort(poll, controller.signal);
25650
+ if (result === LIVE_ABORTED) {
25651
+ poll.catch(() => {});
25652
+ break;
25653
+ }
25561
25654
  updates += 1;
25562
25655
  if (startTimer) {
25563
25656
  clearTimeout(startTimer);
@@ -26130,9 +26223,34 @@ function writeOutput(ctx, data, prettyFn) {
26130
26223
  }
26131
26224
  prettyFn();
26132
26225
  }
26133
- function emitPartialPageHint(ctx, count, nextCursor, limit) {
26226
+ function pageEnvelope(items, opts) {
26227
+ const nextCursor = opts.nextCursor ?? null;
26228
+ return {
26229
+ items,
26230
+ page: {
26231
+ limit: opts.limit,
26232
+ count: items.length,
26233
+ hasMore: nextCursor !== null,
26234
+ nextCursor
26235
+ }
26236
+ };
26237
+ }
26238
+ function writePageOutput(ctx, items, opts, prettyFn) {
26239
+ if (ctx.format === "json") {
26240
+ printJson(ctx.out, pageEnvelope(items, opts));
26241
+ return;
26242
+ }
26243
+ if (ctx.format === "jsonl") {
26244
+ printJsonl(ctx.out, items);
26245
+ return;
26246
+ }
26247
+ prettyFn();
26248
+ }
26249
+ function emitPartialPageHint(ctx, count, _nextCursor, _limit) {
26250
+ if (ctx.format === "json" || ctx.format === "jsonl")
26251
+ return;
26134
26252
  const c = ctx.colors;
26135
- ctx.status(`${c.yellow}${count} shown, more available${c.reset} use ${c.cyan}--all${c.reset} to fetch every page, ` + `or re-run the same command plus ${c.cyan}--limit=${limit} --cursor=${nextCursor}${c.reset} to resume from here.`);
26253
+ ctx.status(`${c.yellow}${count} shown; more available${c.reset}. Use ${c.cyan}--all${c.reset} to fetch every page.`);
26136
26254
  }
26137
26255
 
26138
26256
  // ../../packages/warmhub-cli/src/domains/thing/shared.ts
@@ -26208,7 +26326,7 @@ var handleAbout = async (ctx, { flags, args }) => {
26208
26326
  apiUrl: ctx.config.apiUrl,
26209
26327
  poll: (c) => c.thing.about(org, repo, wref, aboutOpts),
26210
26328
  render: (r) => {
26211
- renderAboutResult(ctx.out, ctx.colors, r, wref, boundedLimit);
26329
+ renderAboutResult(ctx.out, ctx.colors, r, wref);
26212
26330
  },
26213
26331
  out: ctx.out,
26214
26332
  err: ctx.err,
@@ -26236,22 +26354,21 @@ var handleAbout = async (ctx, { flags, args }) => {
26236
26354
  cur = page.nextCursor;
26237
26355
  }
26238
26356
  const result2 = { target, assertions, nextCursor: undefined };
26239
- writeOutput(ctx, result2, () => renderAboutResult(ctx.out, ctx.colors, result2, wref, boundedLimit));
26357
+ writePageOutput(ctx, assertions, { limit: pageLimit, nextCursor: null }, () => renderAboutResult(ctx.out, ctx.colors, result2, wref));
26240
26358
  return;
26241
26359
  }
26242
26360
  const result = await fetchPage(cursor);
26243
26361
  if (result.nextCursor) {
26244
26362
  emitPartialPageHint(ctx, result.assertions.length, result.nextCursor, boundedLimit);
26245
26363
  }
26246
- writeOutput(ctx, result, () => renderAboutResult(ctx.out, ctx.colors, result, wref, boundedLimit));
26364
+ writePageOutput(ctx, result.assertions, { limit: boundedLimit, nextCursor: result.nextCursor ?? null }, () => renderAboutResult(ctx.out, ctx.colors, result, wref));
26247
26365
  };
26248
- function renderAboutResult(out, c, result, wref, limit) {
26249
- const resumeHint = `${c.dim}Next: --limit=${limit} --cursor=${result.nextCursor}${c.reset}`;
26366
+ function renderAboutResult(out, c, result, wref) {
26250
26367
  out(`${c.bold}Assertions about${c.reset} ${pinnedWref(c, wref)} (${result.assertions.length}${result.nextCursor ? "+" : ""})`);
26251
26368
  if (result.assertions.length === 0) {
26252
26369
  out(` ${c.dim}(no assertions found)${c.reset}`);
26253
26370
  if (result.nextCursor) {
26254
- out(resumeHint);
26371
+ out(`${c.dim}More available. Use --all to fetch every page.${c.reset}`);
26255
26372
  }
26256
26373
  return;
26257
26374
  }
@@ -26259,7 +26376,7 @@ function renderAboutResult(out, c, result, wref, limit) {
26259
26376
  renderAboutAssertion(out, c, a, " ");
26260
26377
  }
26261
26378
  if (result.nextCursor) {
26262
- out(resumeHint);
26379
+ out(`${c.dim}More available. Use --all to fetch every page.${c.reset}`);
26263
26380
  }
26264
26381
  }
26265
26382
  function renderAboutAssertion(out, c, assertion, indent) {
@@ -26570,14 +26687,14 @@ function renderBatchView(out, c, result, wrefs, flagsVersion) {
26570
26687
  // ../../packages/warmhub-cli/src/domains/thing/graph.ts
26571
26688
  var graphFlags = {
26572
26689
  depth: flag.number({
26573
- description: "Resolve embedded graph to this depth (default: 2, max: 5)"
26690
+ description: "Resolve outbound wref fields, assertion backlinks, and assertion about targets to this depth (default: 2, max: 5)"
26574
26691
  }),
26575
26692
  version: flag.number({ description: "Specific version number" })
26576
26693
  };
26577
26694
  var handleThingGraph = async (ctx, { flags, args }) => {
26578
26695
  const wref = args[0];
26579
26696
  if (!wref) {
26580
- usageError("Usage: wh thing graph <wref> [--depth N]", "wh thing graph Game/base");
26697
+ usageError("Usage: wh thing graph <wref> [--depth N]", "wh thing graph Game/base", "wh thing refs Game/base --inbound");
26581
26698
  }
26582
26699
  const depth = flags.depth;
26583
26700
  if (depth !== undefined && (depth < 1 || depth > 5)) {
@@ -26672,7 +26789,10 @@ var handleHistory = async (ctx, { flags, args }) => {
26672
26789
  if (!all && result.nextCursor) {
26673
26790
  emitPartialPageHint(ctx, (result.versions ?? []).length, result.nextCursor, boundedLimit);
26674
26791
  }
26675
- writeOutput(ctx, result, () => renderHistory(ctx.out, ctx.colors, result));
26792
+ writePageOutput(ctx, result.versions ?? [], {
26793
+ limit: all ? pageLimit : boundedLimit,
26794
+ nextCursor: result.nextCursor ?? null
26795
+ }, () => renderHistory(ctx.out, ctx.colors, result));
26676
26796
  };
26677
26797
  async function fetchAllHistoryPages(ctx, org, repo, opts) {
26678
26798
  const versions = [];
@@ -26758,8 +26878,8 @@ function validateKind(value, flagName = "--kind") {
26758
26878
  function resolveRepoContext(ctx) {
26759
26879
  return parseOrgRepo(getRepoRef(ctx), ctx.config);
26760
26880
  }
26761
- function validateComponentFilters(componentId, excludeComponents, ...examples) {
26762
- if (componentId && excludeComponents) {
26881
+ function validateComponentFilters(componentRef, excludeComponents, ...examples) {
26882
+ if (componentRef && excludeComponents) {
26763
26883
  usageError("Cannot combine --component with --exclude-components.", ...examples);
26764
26884
  }
26765
26885
  }
@@ -26835,7 +26955,7 @@ var headFlags = {
26835
26955
  description: "Include retracted things"
26836
26956
  }),
26837
26957
  component: flag.string({
26838
- description: "Filter to things owned by this component ID"
26958
+ description: "Filter to things owned by this component (Org/Name ref)"
26839
26959
  }),
26840
26960
  "exclude-components": flag.boolean({
26841
26961
  description: "Exclude component-owned things from results"
@@ -26861,15 +26981,15 @@ var handleHead = async (ctx, { flags, args }) => {
26861
26981
  if (cursor || all || limit || ctx.liveMode) {
26862
26982
  usageError("Usage: wh thing list --count [--shape SHAPE] [--kind KIND] [--match PATTERN]", "wh thing list --shape Player --count");
26863
26983
  }
26864
- const componentId2 = flags.component;
26984
+ const componentRef2 = flags.component;
26865
26985
  const strictExclude2 = !!flags["exclude-components"];
26866
- validateComponentFilters(componentId2, strictExclude2, "wh thing list --component com.example.pkg");
26986
+ validateComponentFilters(componentRef2, strictExclude2, "wh thing list --component acme/veritas");
26867
26987
  return handleCount(ctx, org, repo, {
26868
26988
  shape,
26869
26989
  kind,
26870
26990
  match,
26871
26991
  includeRetracted,
26872
- componentId: componentId2,
26992
+ componentRef: componentRef2,
26873
26993
  excludeComponents: strictExclude2,
26874
26994
  excludeInfraShapes: !strictExclude2 && !shape,
26875
26995
  where: where.length > 0 ? where : undefined
@@ -26883,10 +27003,10 @@ var handleHead = async (ctx, { flags, args }) => {
26883
27003
  }
26884
27004
  const boundedLimit = Math.min(limit ?? DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT);
26885
27005
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedLimit;
26886
- const componentId = flags.component;
27006
+ const componentRef = flags.component;
26887
27007
  const hasShape = !!shape;
26888
27008
  const strictExclude = !!flags["exclude-components"];
26889
- validateComponentFilters(componentId, strictExclude, "wh thing list --component com.example.pkg");
27009
+ validateComponentFilters(componentRef, strictExclude, "wh thing list --component acme/veritas");
26890
27010
  const excludeComponents = strictExclude;
26891
27011
  const excludeInfraShapes = !strictExclude && !hasShape;
26892
27012
  const headOpts = {
@@ -26896,7 +27016,7 @@ var handleHead = async (ctx, { flags, args }) => {
26896
27016
  includeRetracted,
26897
27017
  limit: pageLimit,
26898
27018
  cursor,
26899
- componentId,
27019
+ componentRef,
26900
27020
  excludeComponents,
26901
27021
  excludeInfraShapes,
26902
27022
  where: where.length > 0 ? where : undefined
@@ -26928,7 +27048,7 @@ var handleHead = async (ctx, { flags, args }) => {
26928
27048
  includeRetracted,
26929
27049
  limit: pageLimit,
26930
27050
  cursor,
26931
- componentId,
27051
+ componentRef,
26932
27052
  excludeComponents,
26933
27053
  excludeInfraShapes,
26934
27054
  where: where.length > 0 ? where : undefined
@@ -26939,7 +27059,7 @@ var handleHead = async (ctx, { flags, args }) => {
26939
27059
  includeRetracted,
26940
27060
  limit: boundedLimit,
26941
27061
  cursor,
26942
- componentId,
27062
+ componentRef,
26943
27063
  excludeComponents,
26944
27064
  excludeInfraShapes,
26945
27065
  where: where.length > 0 ? where : undefined
@@ -26947,7 +27067,10 @@ var handleHead = async (ctx, { flags, args }) => {
26947
27067
  if (!all && result.nextCursor) {
26948
27068
  emitPartialPageHint(ctx, (result.items ?? []).length, result.nextCursor, boundedLimit);
26949
27069
  }
26950
- writeOutput(ctx, result, () => renderHead(ctx.out, ctx.colors, ctx.chars, result, org, repo, shape, kind));
27070
+ writePageOutput(ctx, result.items ?? [], {
27071
+ limit: all ? pageLimit : boundedLimit,
27072
+ nextCursor: result.nextCursor ?? null
27073
+ }, () => renderHead(ctx.out, ctx.colors, ctx.chars, result, org, repo, shape, kind));
26951
27074
  };
26952
27075
  async function fetchAllHeadPages(ctx, org, repo, opts) {
26953
27076
  const items = [];
@@ -26960,7 +27083,7 @@ async function fetchAllHeadPages(ctx, org, repo, opts) {
26960
27083
  includeRetracted: opts.includeRetracted,
26961
27084
  limit: opts.limit,
26962
27085
  cursor,
26963
- componentId: opts.componentId,
27086
+ componentRef: opts.componentRef,
26964
27087
  excludeComponents: opts.excludeComponents,
26965
27088
  excludeInfraShapes: opts.excludeInfraShapes,
26966
27089
  where: opts.where
@@ -26992,7 +27115,7 @@ var queryFlags = {
26992
27115
  description: "Include assertions about collections (Pair/Triple/Set/List) containing the target. Only applies with --about."
26993
27116
  }),
26994
27117
  component: flag.string({
26995
- description: "Filter to things owned by this component ID"
27118
+ description: "Filter to things owned by this component (Org/Name ref)"
26996
27119
  }),
26997
27120
  "exclude-components": flag.boolean({
26998
27121
  description: "Exclude component-owned things from results"
@@ -27014,10 +27137,10 @@ var handleQuery = async (ctx, { flags }) => {
27014
27137
  const count = flags.count;
27015
27138
  const includeRetracted = flags["include-retracted"];
27016
27139
  const resolveCollections = flags["resolve-collections"];
27017
- const componentId = flags.component;
27140
+ const componentRef = flags.component;
27018
27141
  const hasShape = !!shape;
27019
27142
  const strictExclude = !!flags["exclude-components"];
27020
- validateComponentFilters(componentId, strictExclude, "wh thing query --component com.example.pkg");
27143
+ validateComponentFilters(componentRef, strictExclude, "wh thing query --component acme/veritas");
27021
27144
  const excludeComponents = strictExclude;
27022
27145
  const excludeInfraShapes = !strictExclude && !hasShape;
27023
27146
  const c = ctx.colors;
@@ -27034,7 +27157,7 @@ var handleQuery = async (ctx, { flags }) => {
27034
27157
  about,
27035
27158
  includeRetracted,
27036
27159
  resolveCollections,
27037
- componentId,
27160
+ componentRef,
27038
27161
  excludeComponents,
27039
27162
  excludeInfraShapes,
27040
27163
  where: where.length > 0 ? where : undefined
@@ -27057,7 +27180,7 @@ var handleQuery = async (ctx, { flags }) => {
27057
27180
  resolveCollections,
27058
27181
  limit: pageLimit,
27059
27182
  cursor,
27060
- componentId,
27183
+ componentRef,
27061
27184
  excludeComponents,
27062
27185
  excludeInfraShapes,
27063
27186
  where: where.length > 0 ? where : undefined
@@ -27091,7 +27214,7 @@ var handleQuery = async (ctx, { flags }) => {
27091
27214
  resolveCollections,
27092
27215
  limit: pageLimit,
27093
27216
  cursor,
27094
- componentId,
27217
+ componentRef,
27095
27218
  excludeComponents,
27096
27219
  excludeInfraShapes,
27097
27220
  where: where.length > 0 ? where : undefined
@@ -27104,7 +27227,7 @@ var handleQuery = async (ctx, { flags }) => {
27104
27227
  resolveCollections,
27105
27228
  limit: boundedLimit,
27106
27229
  cursor,
27107
- componentId,
27230
+ componentRef,
27108
27231
  excludeComponents,
27109
27232
  excludeInfraShapes,
27110
27233
  where: where.length > 0 ? where : undefined
@@ -27112,7 +27235,10 @@ var handleQuery = async (ctx, { flags }) => {
27112
27235
  if (!all && result.nextCursor) {
27113
27236
  emitPartialPageHint(ctx, (result.items ?? []).length, result.nextCursor, boundedLimit);
27114
27237
  }
27115
- writeOutput(ctx, result, () => renderQueryResults(ctx.out, c, result));
27238
+ writePageOutput(ctx, result.items ?? [], {
27239
+ limit: all ? pageLimit : boundedLimit,
27240
+ nextCursor: result.nextCursor ?? null
27241
+ }, () => renderQueryResults(ctx.out, c, result));
27116
27242
  };
27117
27243
  async function fetchAllQueryPages(ctx, org, repo, opts) {
27118
27244
  const items = [];
@@ -27127,7 +27253,7 @@ async function fetchAllQueryPages(ctx, org, repo, opts) {
27127
27253
  resolveCollections: opts.resolveCollections,
27128
27254
  limit: opts.limit,
27129
27255
  cursor,
27130
- componentId: opts.componentId,
27256
+ componentRef: opts.componentRef,
27131
27257
  excludeComponents: opts.excludeComponents,
27132
27258
  excludeInfraShapes: opts.excludeInfraShapes,
27133
27259
  where: opts.where
@@ -27218,7 +27344,7 @@ var handleRefs = async (ctx, { flags, args }) => {
27218
27344
  cur = page.nextCursor;
27219
27345
  }
27220
27346
  const result2 = { items, nextCursor: undefined };
27221
- writeOutput(ctx, result2, () => renderRefs(ctx.out, ctx.colors, result2, wref, direction));
27347
+ writePageOutput(ctx, items, { limit: pageLimit, nextCursor: null }, () => renderRefs(ctx.out, ctx.colors, result2, wref, direction));
27222
27348
  maybeEmitAboutHint(ctx, direction, items.length, refsQueryIsNarrowed);
27223
27349
  return;
27224
27350
  }
@@ -27226,7 +27352,7 @@ var handleRefs = async (ctx, { flags, args }) => {
27226
27352
  if (result.nextCursor) {
27227
27353
  emitPartialPageHint(ctx, (result.items ?? []).length, result.nextCursor, boundedLimit);
27228
27354
  }
27229
- writeOutput(ctx, result, () => renderRefs(ctx.out, ctx.colors, result, wref, direction));
27355
+ writePageOutput(ctx, result.items ?? [], { limit: boundedLimit, nextCursor: result.nextCursor ?? null }, () => renderRefs(ctx.out, ctx.colors, result, wref, direction));
27230
27356
  maybeEmitAboutHint(ctx, direction, result.items?.length ?? 0, refsQueryIsNarrowed);
27231
27357
  };
27232
27358
  function maybeEmitAboutHint(ctx, direction, itemCount, refsQueryIsNarrowed) {
@@ -27405,7 +27531,7 @@ var searchFlags = {
27405
27531
  cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
27406
27532
  all: flag.boolean({ description: "Fetch all pages (text mode)" }),
27407
27533
  component: flag.string({
27408
- description: "Filter to things owned by this component ID"
27534
+ description: "Filter to things owned by this component (Org/Name ref)"
27409
27535
  }),
27410
27536
  "exclude-components": flag.boolean({
27411
27537
  description: "Exclude component-owned things from results"
@@ -27442,10 +27568,10 @@ var handleSearch = async (ctx, { flags, args }) => {
27442
27568
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedTextLimit;
27443
27569
  const resolveCollections = mode !== "hybrid" ? flags["resolve-collections"] : undefined;
27444
27570
  const supportsComponentFilters = !mode || mode === "text";
27445
- const componentId = supportsComponentFilters ? flags.component : undefined;
27571
+ const componentRef = supportsComponentFilters ? flags.component : undefined;
27446
27572
  const hasShape = !!flags.shape;
27447
27573
  const strictExclude = supportsComponentFilters ? !!flags["exclude-components"] : false;
27448
- validateComponentFilters(componentId, strictExclude, 'wh thing search "policy" --component com.example.pkg');
27574
+ validateComponentFilters(componentRef, strictExclude, 'wh thing search "policy" --component acme/veritas');
27449
27575
  const excludeComponents = supportsComponentFilters && strictExclude ? true : undefined;
27450
27576
  const excludeInfraShapes = supportsComponentFilters && !strictExclude && !hasShape ? true : undefined;
27451
27577
  const rawResult = all ? await fetchAllSearchPages(ctx, org, repo, queryText, {
@@ -27456,7 +27582,7 @@ var handleSearch = async (ctx, { flags, args }) => {
27456
27582
  resolveCollections,
27457
27583
  limit: pageLimit,
27458
27584
  cursor,
27459
- componentId,
27585
+ componentRef,
27460
27586
  excludeComponents,
27461
27587
  excludeInfraShapes
27462
27588
  }) : await ctx.client.thing.search(org, repo, queryText, {
@@ -27468,7 +27594,7 @@ var handleSearch = async (ctx, { flags, args }) => {
27468
27594
  limit: boundedTextLimit,
27469
27595
  cursor,
27470
27596
  mode,
27471
- componentId,
27597
+ componentRef,
27472
27598
  excludeComponents,
27473
27599
  excludeInfraShapes
27474
27600
  });
@@ -27479,7 +27605,10 @@ var handleSearch = async (ctx, { flags, args }) => {
27479
27605
  if (!all && result.nextCursor) {
27480
27606
  emitPartialPageHint(ctx, result.items.length, result.nextCursor, boundedTextLimit);
27481
27607
  }
27482
- writeOutput(ctx, result, () => renderQueryResults(ctx.out, c, result));
27608
+ writePageOutput(ctx, result.items, {
27609
+ limit: all ? pageLimit : boundedTextLimit,
27610
+ nextCursor: result.nextCursor ?? null
27611
+ }, () => renderQueryResults(ctx.out, c, result));
27483
27612
  };
27484
27613
  async function fetchAllSearchPages(ctx, org, repo, queryText, opts) {
27485
27614
  const items = [];
@@ -27494,7 +27623,7 @@ async function fetchAllSearchPages(ctx, org, repo, queryText, opts) {
27494
27623
  limit: opts.limit,
27495
27624
  cursor,
27496
27625
  mode: "text",
27497
- componentId: opts.componentId,
27626
+ componentRef: opts.componentRef,
27498
27627
  excludeComponents: opts.excludeComponents,
27499
27628
  excludeInfraShapes: opts.excludeInfraShapes
27500
27629
  });
@@ -27847,13 +27976,16 @@ var THING_DOMAIN = defineDomain({
27847
27976
  },
27848
27977
  graph: {
27849
27978
  prime: true,
27850
- summary: "Fetch a thing's graph (forward + reverse references) at a given depth",
27979
+ summary: "Fetch a thing's graph (outbound wref fields, assertion backlinks, and assertion about targets)",
27851
27980
  args: "<wref>",
27852
27981
  flags: graphFlags,
27853
27982
  examples: [
27854
27983
  "wh thing graph Game/base",
27855
27984
  "wh thing graph Game/base --depth 2"
27856
27985
  ],
27986
+ notes: [
27987
+ "`graph` does not traverse inbound wref-field references; use `wh thing refs <wref> --inbound` to find things whose fields point at this thing."
27988
+ ],
27857
27989
  handler: handleThingGraph
27858
27990
  }
27859
27991
  }
@@ -28161,7 +28293,10 @@ var handleHistory2 = async (ctx, { flags, args }) => {
28161
28293
  versions,
28162
28294
  nextCursor: flags.all ? undefined : nextCursor
28163
28295
  };
28164
- writeOutput(ctx, result, () => renderHistory(ctx.out, ctx.colors, result));
28296
+ if (!flags.all && result.nextCursor) {
28297
+ emitPartialPageHint(ctx, result.versions.length, result.nextCursor, limit);
28298
+ }
28299
+ writePageOutput(ctx, result.versions, { limit, nextCursor: result.nextCursor ?? null }, () => renderHistory(ctx.out, ctx.colors, result));
28165
28300
  };
28166
28301
  var handleCreate2 = async (ctx, { flags, args }) => {
28167
28302
  const { org, repo } = parseOrgRepo(getRepoRef(ctx) ?? args[0], ctx.config);
@@ -28291,7 +28426,10 @@ var handleList = async (ctx, { flags, args }) => {
28291
28426
  if (!all && result2.nextCursor) {
28292
28427
  emitPartialPageHint(ctx, (result2.items ?? []).length, result2.nextCursor, boundedLimit);
28293
28428
  }
28294
- writeOutput(ctx, result2, () => renderHead(ctx.out, ctx.colors, ctx.chars, result2, org, repo, shape, "assertion"));
28429
+ writePageOutput(ctx, result2.items ?? [], {
28430
+ limit: all ? pageLimit : boundedLimit,
28431
+ nextCursor: result2.nextCursor ?? null
28432
+ }, () => renderHead(ctx.out, ctx.colors, ctx.chars, result2, org, repo, shape, "assertion"));
28295
28433
  return;
28296
28434
  }
28297
28435
  const aboutOpts = {
@@ -28343,7 +28481,10 @@ var handleList = async (ctx, { flags, args }) => {
28343
28481
  if (!all && result.nextCursor) {
28344
28482
  emitPartialPageHint(ctx, (result.assertions ?? []).length, result.nextCursor, boundedLimit);
28345
28483
  }
28346
- writeOutput(ctx, result, () => renderAbout(ctx.out, ctx.colors, result));
28484
+ writePageOutput(ctx, result.assertions ?? [], {
28485
+ limit: all ? pageLimit : boundedLimit,
28486
+ nextCursor: result.nextCursor ?? null
28487
+ }, () => renderAbout(ctx.out, ctx.colors, result));
28347
28488
  };
28348
28489
  async function fetchAllAssertionAboutPages(ctx, org, repo, wref, opts) {
28349
28490
  const assertions = [];
@@ -29417,7 +29558,7 @@ function ndjsonMessage(msg) {
29417
29558
  return `${JSON.stringify(msg)}
29418
29559
  `;
29419
29560
  }
29420
- function createMessageReader(input, onMessage) {
29561
+ function createMessageReader(input, onMessage, onError = () => {}) {
29421
29562
  let buffer = "";
29422
29563
  let mode = null;
29423
29564
  function drain() {
@@ -29440,9 +29581,12 @@ function createMessageReader(input, onMessage) {
29440
29581
  continue;
29441
29582
  }
29442
29583
  } else {
29443
- const idx = buffer.indexOf(HEADER_DELIMITER);
29444
- if (idx !== -1) {
29445
- buffer = buffer.slice(idx + 4);
29584
+ const headerEnd = buffer.indexOf(HEADER_DELIMITER);
29585
+ if (headerEnd !== -1) {
29586
+ const resyncFrom = headerEnd + HEADER_DELIMITER.length;
29587
+ const nextHeaderMatch = /Content-Length:/i.exec(buffer.slice(resyncFrom));
29588
+ const nextHeader = nextHeaderMatch === null ? -1 : resyncFrom + nextHeaderMatch.index;
29589
+ buffer = nextHeader === -1 ? "" : buffer.slice(nextHeader);
29446
29590
  continue;
29447
29591
  }
29448
29592
  }
@@ -29462,12 +29606,14 @@ function createMessageReader(input, onMessage) {
29462
29606
  };
29463
29607
  input.setEncoding("utf8");
29464
29608
  input.on("data", onData);
29609
+ input.on("error", onError);
29465
29610
  if ("resume" in input && typeof input.resume === "function") {
29466
29611
  input.resume();
29467
29612
  }
29468
29613
  return {
29469
29614
  close() {
29470
29615
  input.removeListener("data", onData);
29616
+ input.removeListener("error", onError);
29471
29617
  }
29472
29618
  };
29473
29619
  }
@@ -29477,9 +29623,25 @@ var MCP_PROTOCOL_VERSION2 = "2025-11-25";
29477
29623
  function createChannelServer(opts) {
29478
29624
  let reader = null;
29479
29625
  let resolveReady;
29480
- const onReady = new Promise((resolve) => {
29626
+ let rejectReady;
29627
+ let readySettled = false;
29628
+ const onReady = new Promise((resolve, reject) => {
29481
29629
  resolveReady = resolve;
29630
+ rejectReady = reject;
29482
29631
  });
29632
+ function settleReady() {
29633
+ if (readySettled)
29634
+ return;
29635
+ readySettled = true;
29636
+ resolveReady();
29637
+ }
29638
+ function failReady(error) {
29639
+ if (readySettled)
29640
+ return;
29641
+ readySettled = true;
29642
+ reader?.close();
29643
+ rejectReady(error);
29644
+ }
29483
29645
  function send(msg) {
29484
29646
  opts.output.write(ndjsonMessage(msg));
29485
29647
  }
@@ -29502,7 +29664,7 @@ function createChannelServer(opts) {
29502
29664
  return;
29503
29665
  }
29504
29666
  if (method === "notifications/initialized") {
29505
- resolveReady();
29667
+ settleReady();
29506
29668
  return;
29507
29669
  }
29508
29670
  if (method === "ping") {
@@ -29519,7 +29681,7 @@ function createChannelServer(opts) {
29519
29681
  }
29520
29682
  return {
29521
29683
  start() {
29522
- reader = createMessageReader(opts.input, handleMessage);
29684
+ reader = createMessageReader(opts.input, handleMessage, failReady);
29523
29685
  },
29524
29686
  notify(content, meta) {
29525
29687
  send({
@@ -29531,6 +29693,7 @@ function createChannelServer(opts) {
29531
29693
  onReady,
29532
29694
  close() {
29533
29695
  reader?.close();
29696
+ settleReady();
29534
29697
  }
29535
29698
  };
29536
29699
  }
@@ -29593,7 +29756,16 @@ var handleChannel = async (ctx) => {
29593
29756
  else
29594
29757
  signal.addEventListener("abort", () => resolve("aborted"), { once: true });
29595
29758
  });
29596
- const ready = await Promise.race([server.onReady, aborted]);
29759
+ let ready;
29760
+ try {
29761
+ ready = await Promise.race([server.onReady.then(() => {
29762
+ return;
29763
+ }), aborted]);
29764
+ } catch (err) {
29765
+ server.close();
29766
+ const msg = err instanceof Error ? err.message : String(err);
29767
+ throw new CliError(4 /* Backend */, "BACKEND", `channel startup failed: ${msg}`);
29768
+ }
29597
29769
  if (ready === "aborted") {
29598
29770
  server.close();
29599
29771
  return;
@@ -30969,13 +31141,16 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
30969
31141
  const components = {};
30970
31142
  let detailReadFailures = 0;
30971
31143
  for (const item of activeItems) {
31144
+ if (!item.ref)
31145
+ continue;
31146
+ const itemRef = item.ref;
30972
31147
  let detail;
30973
31148
  try {
30974
- detail = await client.component.get(parsed.org, parsed.repo, item.componentId);
31149
+ detail = await client.component.get(parsed.org, parsed.repo, itemRef);
30975
31150
  } catch {
30976
31151
  detailReadFailures++;
30977
31152
  const previousEntry = previousCache?.components[item.componentName];
30978
- if (previousEntry?.componentId === item.componentId) {
31153
+ if (previousEntry?.ref === itemRef) {
30979
31154
  components[item.componentName] = previousEntry;
30980
31155
  }
30981
31156
  continue;
@@ -30990,7 +31165,7 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
30990
31165
  if (!ref)
30991
31166
  continue;
30992
31167
  components[item.componentName] = {
30993
- componentId: item.componentId,
31168
+ ref: itemRef,
30994
31169
  ownerOrgName: ref.ownerOrgName,
30995
31170
  registeredComponentName: ref.registeredComponentName,
30996
31171
  version: manifest.component.version ?? item.version ?? "",
@@ -31350,7 +31525,7 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
31350
31525
  }
31351
31526
  const method = entry.methods.find((m) => m.name === methodName);
31352
31527
  if (!method) {
31353
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Method '${methodName}' not found on component '${componentName}'.`, undefined, `Available: ${entry.methods.map((m) => m.name).join(", ")}. Run wh component update ${componentName} --repo ${installRepo} if you expect a newer method.`);
31528
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Method '${methodName}' not found on component '${componentName}'.`, undefined, `Available: ${entry.methods.map((m) => m.name).join(", ")}. Run wh component update ${entry.ref} --repo ${installRepo} if you expect a newer method.`);
31354
31529
  }
31355
31530
  if (helpRequested) {
31356
31531
  renderMethodHelp(ctx, componentName, method);
@@ -31402,6 +31577,40 @@ function formatReservedNameWarning(name) {
31402
31577
  return `warning: component name "${name}" shadows the builtin \`wh ${name}\` domain. Operators will need to invoke methods via \`wh component exec ${name} <method>\` — the shorthand \`wh ${name} <method>\` will route to the builtin instead.`;
31403
31578
  }
31404
31579
 
31580
+ // ../../packages/warmhub-cli/src/global-search-command.ts
31581
+ var DEFAULT_LIMIT = 25;
31582
+ async function runGlobalSearchCommand(ctx, args) {
31583
+ const c = ctx.colors;
31584
+ const first = await args.fetch({ limit: args.limit, cursor: args.cursor });
31585
+ const items = [...first.items];
31586
+ let nextCursor = first.nextCursor;
31587
+ if (args.all) {
31588
+ while (nextCursor) {
31589
+ const page = await args.fetch({ limit: args.limit, cursor: nextCursor });
31590
+ items.push(...page.items);
31591
+ nextCursor = page.nextCursor;
31592
+ }
31593
+ }
31594
+ if (!args.all && nextCursor) {
31595
+ emitPartialPageHint(ctx, items.length, nextCursor, args.limit ?? DEFAULT_LIMIT);
31596
+ }
31597
+ writePageOutput(ctx, items, {
31598
+ limit: args.limit ?? DEFAULT_LIMIT,
31599
+ nextCursor: args.all ? null : nextCursor ?? null
31600
+ }, () => {
31601
+ if (items.length === 0) {
31602
+ ctx.status(`${c.dim}No ${args.emptyLabel} matching "${args.query}"${c.reset}`);
31603
+ return;
31604
+ }
31605
+ ctx.out(`${c.bold}${args.title}${c.reset} ${c.dim}"${args.query}"${c.reset}`);
31606
+ ctx.out("");
31607
+ for (const item of items) {
31608
+ const desc = item.description ? ` ${c.dim}${item.description}${c.reset}` : "";
31609
+ ctx.out(` ${c.cyan}${item.orgName}/${item.name}${c.reset}${desc}`);
31610
+ }
31611
+ });
31612
+ }
31613
+
31405
31614
  // ../../packages/warmhub-cli/src/manifest/name-resolution.ts
31406
31615
  function resolveManifestCredentialName(name, ctx) {
31407
31616
  return resolveComponentTemplate(name, {
@@ -31459,7 +31668,7 @@ async function ensureSharedInfra(client, org, repo) {
31459
31668
  name: shape.name,
31460
31669
  data: { fields: shape.fields }
31461
31670
  }
31462
- ], { componentId: SYSTEM_COMPONENT_ID });
31671
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31463
31672
  } catch (err) {
31464
31673
  if (!isAlreadyExistsError(err)) {
31465
31674
  throw err;
@@ -31472,7 +31681,7 @@ async function ensureSharedInfra(client, org, repo) {
31472
31681
  name: shape.name,
31473
31682
  data: { fields: shape.fields }
31474
31683
  }
31475
- ], { componentId: SYSTEM_COMPONENT_ID });
31684
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31476
31685
  } catch {}
31477
31686
  }
31478
31687
  }
@@ -31505,6 +31714,15 @@ async function doctorComponent(client, org, repo, componentId) {
31505
31714
  };
31506
31715
  }
31507
31716
  const componentName = typeof installData.name === "string" ? installData.name : componentId;
31717
+ const registeredComponentRef = typeof installData.registeredComponentRef === "string" && installData.registeredComponentRef.length > 0 ? installData.registeredComponentRef : undefined;
31718
+ if (!registeredComponentRef) {
31719
+ findings.push({
31720
+ resource: "ComponentInstall",
31721
+ status: "error",
31722
+ message: "Install record is missing registeredComponentRef"
31723
+ });
31724
+ return { componentId, componentName, state: "error", findings };
31725
+ }
31508
31726
  const existingState = typeof installData.state === "string" ? installData.state : undefined;
31509
31727
  if (existingState === "error") {
31510
31728
  findings.push({
@@ -31543,12 +31761,12 @@ async function doctorComponent(client, org, repo, componentId) {
31543
31761
  message: `Shape "${shape.name}" exists but is inactive`
31544
31762
  });
31545
31763
  } else {
31546
- const shapeComponentId = s && typeof s === "object" && "componentId" in s ? s.componentId : undefined;
31547
- if (shapeComponentId !== undefined && shapeComponentId !== componentId) {
31764
+ const shapeComponentRef = s && typeof s === "object" && "componentRef" in s ? s.componentRef : undefined;
31765
+ if (shapeComponentRef !== undefined && shapeComponentRef !== registeredComponentRef) {
31548
31766
  findings.push({
31549
31767
  resource: `shape:${shape.name}`,
31550
31768
  status: "warning",
31551
- message: `Shape "${shape.name}" exists but is owned by "${shapeComponentId}"`
31769
+ message: `Shape "${shape.name}" exists but is owned by "${shapeComponentRef}"`
31552
31770
  });
31553
31771
  } else {
31554
31772
  const expectedShapeData = manifestShapeData(shape);
@@ -31582,19 +31800,19 @@ async function doctorComponent(client, org, repo, componentId) {
31582
31800
  hasSubs = true;
31583
31801
  try {
31584
31802
  const s = await client.subscription.get(org, repo, sub.name);
31585
- const subComponentId = s && typeof s === "object" && "componentId" in s ? s.componentId : undefined;
31586
- if (!s.active) {
31803
+ const subComponentRef = s && typeof s === "object" && "componentRef" in s ? s.componentRef : undefined;
31804
+ if (subComponentRef !== undefined && subComponentRef !== registeredComponentRef) {
31805
+ allSubsPaused = false;
31587
31806
  findings.push({
31588
31807
  resource: `sub:${sub.name}`,
31589
- status: "inactive",
31590
- message: `Subscription "${sub.name}" is paused`
31808
+ status: "warning",
31809
+ message: `Subscription "${sub.name}" is owned by "${subComponentRef}"`
31591
31810
  });
31592
- } else if (subComponentId !== undefined && subComponentId !== componentId) {
31593
- allSubsPaused = false;
31811
+ } else if (!s.active) {
31594
31812
  findings.push({
31595
31813
  resource: `sub:${sub.name}`,
31596
- status: "warning",
31597
- message: `Subscription "${sub.name}" is owned by "${subComponentId}"`
31814
+ status: "inactive",
31815
+ message: `Subscription "${sub.name}" is paused`
31598
31816
  });
31599
31817
  } else {
31600
31818
  allSubsPaused = false;
@@ -31664,10 +31882,11 @@ async function doctorComponent(client, org, repo, componentId) {
31664
31882
  const hasMissing = findings.some((f) => f.status === "missing");
31665
31883
  const hasInactive = findings.some((f) => f.status === "inactive" && !f.resource.startsWith("sub:"));
31666
31884
  const hasShapeDrift = findings.some((f) => f.resource.startsWith("shape:") && f.status === "warning" && f.message.includes("differs from installed manifest"));
31885
+ const hasOwnershipConflict = findings.some((f) => (f.resource.startsWith("shape:") || f.resource.startsWith("sub:")) && f.status === "warning" && f.message.includes("owned by"));
31667
31886
  let state;
31668
- if (hasSubs && allSubsPaused && !hasMissing && !hasInactive && !hasShapeDrift) {
31887
+ if (hasSubs && allSubsPaused && !hasMissing && !hasInactive && !hasShapeDrift && !hasOwnershipConflict) {
31669
31888
  state = "paused";
31670
- } else if (hasMissing || hasInactive || hasShapeDrift) {
31889
+ } else if (hasMissing || hasInactive || hasShapeDrift || hasOwnershipConflict) {
31671
31890
  state = "degraded";
31672
31891
  } else {
31673
31892
  state = "ready";
@@ -31680,7 +31899,7 @@ async function doctorComponent(client, org, repo, componentId) {
31680
31899
  name: `ComponentInstall/${componentId}`,
31681
31900
  data: { ...installData, state, checkedAt: new Date().toISOString() }
31682
31901
  }
31683
- ], { componentId: SYSTEM_COMPONENT_ID });
31902
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31684
31903
  } catch {
31685
31904
  findings.push({
31686
31905
  resource: "state-update",
@@ -31774,6 +31993,22 @@ async function teardownComponent(client, org, repo, componentId) {
31774
31993
  };
31775
31994
  }
31776
31995
  const componentName = typeof installData.name === "string" ? installData.name : componentId;
31996
+ const registeredComponentRef = typeof installData.registeredComponentRef === "string" && installData.registeredComponentRef.length > 0 ? installData.registeredComponentRef : undefined;
31997
+ if (!registeredComponentRef) {
31998
+ return {
31999
+ componentId,
32000
+ componentName,
32001
+ state: "error",
32002
+ steps: [
32003
+ {
32004
+ step: "load-install",
32005
+ status: "error",
32006
+ message: "Install record is missing registeredComponentRef"
32007
+ }
32008
+ ],
32009
+ errors: ["Install record is missing registeredComponentRef"]
32010
+ };
32011
+ }
31777
32012
  let subscriptionNames = [];
31778
32013
  let teardownPolicy = {};
31779
32014
  try {
@@ -31796,9 +32031,9 @@ async function teardownComponent(client, org, repo, componentId) {
31796
32031
  for (const subName of subscriptionNames) {
31797
32032
  try {
31798
32033
  const sub = await client.subscription.get(org, repo, subName);
31799
- const ownerComponentId = sub && typeof sub === "object" && "componentId" in sub ? sub.componentId : undefined;
31800
- if (typeof ownerComponentId === "string" && ownerComponentId !== componentId) {
31801
- const msg = `Subscription "${subName}" is owned by "${ownerComponentId}", not "${componentId}"`;
32034
+ const ownerComponentRef = sub && typeof sub === "object" && "componentRef" in sub ? sub.componentRef : undefined;
32035
+ if (typeof ownerComponentRef === "string" && ownerComponentRef !== registeredComponentRef) {
32036
+ const msg = `Subscription "${subName}" is owned by "${ownerComponentRef}", not "${registeredComponentRef}"`;
31802
32037
  errors.push(msg);
31803
32038
  steps.push({
31804
32039
  step: `pause-${subName}`,
@@ -31847,7 +32082,7 @@ async function teardownComponent(client, org, repo, componentId) {
31847
32082
  updatedAt: new Date().toISOString()
31848
32083
  }
31849
32084
  }
31850
- ], { componentId: SYSTEM_COMPONENT_ID });
32085
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31851
32086
  steps.push({ step: "update-state", status: "ok" });
31852
32087
  } catch (err) {
31853
32088
  const msg = err instanceof Error ? err.message : String(err);
@@ -31920,6 +32155,12 @@ function resolveMintedTokensFlag(args) {
31920
32155
  return false;
31921
32156
  return;
31922
32157
  }
32158
+ var showSecretsFlag = flag.boolean({
32159
+ description: "Reveal raw lifecycle URLs in command output"
32160
+ });
32161
+ var showSecretsStructuredOutputFlag = flag.boolean({
32162
+ description: "Reveal raw lifecycle URLs in JSON/JSONL output"
32163
+ });
31923
32164
  var installFlags = {};
31924
32165
  var updateFlags = {};
31925
32166
  var validateFlags = {};
@@ -31932,13 +32173,15 @@ var listFlags2 = {
31932
32173
  description: "Fetch all pages (auto-paginate until exhausted)"
31933
32174
  })
31934
32175
  };
32176
+ var DEFAULT_COMPONENT_LIST_LIMIT = 50;
32177
+ var MAX_COMPONENT_LIST_LIMIT = 500;
31935
32178
  var viewFlags3 = {};
31936
32179
  var teardownFlags = {};
31937
32180
  var doctorFlags = {};
31938
32181
  var initFlags = {};
31939
32182
  var searchFlags2 = {
31940
32183
  limit: flag.number({
31941
- description: "Maximum components per page (default: 50, max: 500)"
32184
+ description: "Maximum results per page"
31942
32185
  }),
31943
32186
  cursor: flag.string({ description: "Opaque pagination cursor" }),
31944
32187
  all: flag.boolean({
@@ -31984,7 +32227,8 @@ var registerFlags = {
31984
32227
  }),
31985
32228
  "no-minted-tokens": flag.boolean({
31986
32229
  description: "Disable minted tokens (default)"
31987
- })
32230
+ }),
32231
+ "show-secrets": showSecretsFlag
31988
32232
  };
31989
32233
  function readManifestArg(path2) {
31990
32234
  let raw;
@@ -32008,9 +32252,12 @@ var unregisterFlags = {};
32008
32252
  var registryListFlags = {
32009
32253
  org: flag.string({
32010
32254
  description: "Owner org to list registrations for"
32011
- })
32255
+ }),
32256
+ "show-secrets": showSecretsStructuredOutputFlag
32257
+ };
32258
+ var registryViewFlags = {
32259
+ "show-secrets": showSecretsFlag
32012
32260
  };
32013
- var registryViewFlags = {};
32014
32261
  var registryUpdateFlags = {
32015
32262
  manifest: flag.string({
32016
32263
  description: "Path to a manifest.json to publish as a new version (optional; must have a strictly-greater semver)"
@@ -32049,7 +32296,8 @@ var registryUpdateFlags = {
32049
32296
  }),
32050
32297
  "no-minted-tokens": flag.boolean({
32051
32298
  description: "Disable minted tokens"
32052
- })
32299
+ }),
32300
+ "show-secrets": showSecretsFlag
32053
32301
  };
32054
32302
  function asRecord(value) {
32055
32303
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -32069,38 +32317,11 @@ function componentInstallCanonicalId(item) {
32069
32317
  const data = asRecord(item.data);
32070
32318
  return componentInstallIdFromWref(item.wref) ?? readString(data, "id") ?? readString(data, "componentId") ?? item.name;
32071
32319
  }
32072
- function uniqueStrings(values) {
32073
- return [...new Set(values.filter((value) => Boolean(value)))];
32074
- }
32075
- function componentInstallIdentityIds(item) {
32076
- const data = asRecord(item.data);
32077
- return uniqueStrings([
32078
- componentInstallCanonicalId(item),
32079
- readString(data, "id"),
32080
- readString(data, "componentId"),
32081
- item.name
32082
- ]);
32083
- }
32084
- function componentInstallHasExactId(item, name) {
32085
- return componentInstallIdentityIds(item).includes(name);
32320
+ function componentInstallHasRegisteredRef(item, ref) {
32321
+ return readString(asRecord(item.data), "registeredComponentRef") === ref;
32086
32322
  }
32087
- function componentInstallHasDisplayName(item, name) {
32088
- return readString(asRecord(item.data), "name") === name;
32089
- }
32090
- function formatComponentInstallAmbiguity(name, matches) {
32091
- const componentIds = uniqueStrings(matches.map((item) => componentInstallCanonicalId(item)));
32092
- const listedIds = componentIds.map((id) => `- ${id}`).join(`
32093
- `);
32094
- const exampleId = componentIds[0] ?? name;
32095
- return {
32096
- message: `Component name "${name}" is ambiguous. It matches multiple installed components:
32097
- ${listedIds}`,
32098
- hint: `Use a component id instead, for example: wh component doctor ${exampleId}`
32099
- };
32100
- }
32101
- async function resolveComponentDoctorId(client, org, repo, name) {
32323
+ async function resolveInstalledComponentRefId(client, org, repo, ref) {
32102
32324
  let cursor;
32103
- const displayNameMatches = [];
32104
32325
  do {
32105
32326
  const result = await client.thing.head(org, repo, {
32106
32327
  shape: "ComponentInstall",
@@ -32109,35 +32330,27 @@ async function resolveComponentDoctorId(client, org, repo, name) {
32109
32330
  cursor
32110
32331
  });
32111
32332
  const items = result.items ?? [];
32112
- const exactMatch = items.find((item) => componentInstallHasExactId(item, name));
32333
+ const exactMatch = items.find((item) => componentInstallHasRegisteredRef(item, ref));
32113
32334
  const resolved = exactMatch ? componentInstallCanonicalId(exactMatch) : undefined;
32114
32335
  if (resolved) {
32115
32336
  return resolved;
32116
32337
  }
32117
- displayNameMatches.push(...items.filter((item) => componentInstallHasDisplayName(item, name)));
32118
32338
  cursor = result.nextCursor;
32119
32339
  } while (cursor);
32120
- if (displayNameMatches.length === 1) {
32121
- return componentInstallCanonicalId(displayNameMatches[0]) ?? name;
32122
- }
32123
- if (displayNameMatches.length > 1) {
32124
- const { message, hint } = formatComponentInstallAmbiguity(name, displayNameMatches);
32125
- throw new CliError(2 /* UserInput */, "USER_INPUT", message, undefined, hint);
32126
- }
32127
- return name;
32340
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${ref}' is not installed. Run 'wh component install <org>/<name>' first.`);
32128
32341
  }
32129
32342
  var handleUpdate = async (ctx, { args }) => {
32130
- const name = args[0];
32131
- if (!name) {
32132
- usageError("Usage: wh component update <name> --repo org/repo", "wh component update research-knowledge --repo org/repo");
32343
+ const ref = args[0];
32344
+ const usage = "Usage: wh component update <org/name> --repo org/repo";
32345
+ const example = "wh component update warmhub/research-knowledge --repo org/repo";
32346
+ if (!ref) {
32347
+ usageError(usage, example);
32133
32348
  }
32134
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32135
- try {
32136
- await ctx.client.thing.get(org, repo, `ComponentInstall/${name}`);
32137
- } catch {
32138
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${name}' is not installed. Run 'wh component install <org>/<name>' first.`);
32349
+ resolveRegisteredComponentRef(ref, usage, example);
32350
+ if (ctx.liveMode === false) {
32351
+ usageError("Dry-run is not supported for component update.", "wh component update warmhub/research-knowledge --repo org/repo");
32139
32352
  }
32140
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${name}' was not installed from a registered component and can no longer be updated in place.`, undefined, "Register the component (`wh component register <name> --org <org> --manifest <path>`) and reinstall it with `wh component install <org>/<name>`.");
32353
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${ref}' could not be updated through the component shell boundary.`, undefined, "Run `wh component update <org/name> --repo org/repo` without --dry-run.");
32141
32354
  };
32142
32355
  var handleRegister = async (ctx, { flags, args }) => {
32143
32356
  const componentName = args[0];
@@ -32178,7 +32391,8 @@ var handleRegister = async (ctx, { flags, args }) => {
32178
32391
  if (reservedWarning) {
32179
32392
  ctx.err(reservedWarning);
32180
32393
  }
32181
- writeOutput(ctx, result, () => renderRegistryEntry(ctx, result));
32394
+ const output = redactRegistryEntryLifecycleUrls(result, flags["show-secrets"]);
32395
+ writeOutput(ctx, output, () => renderRegistryEntry(ctx, output));
32182
32396
  };
32183
32397
  var handleUnregister = async (ctx, { args }) => {
32184
32398
  const { orgName, componentName } = resolveRegisteredComponentRef(args[0], "Usage: wh component unregister <org/name>", "wh component unregister warmhub/veritas");
@@ -32193,12 +32407,14 @@ var handleRegistryList = async (ctx, { flags, args }) => {
32193
32407
  usageError("Usage: wh component registry list --org <org>", "wh component registry list --org warmhub");
32194
32408
  }
32195
32409
  const result = await ctx.client.component.registry.list(orgName);
32196
- writeOutput(ctx, result.items, () => renderRegistryList(ctx, orgName, result));
32410
+ const items = redactRegistryEntryListLifecycleUrls(result.items, flags["show-secrets"]);
32411
+ writePageOutput(ctx, items, { limit: items.length, nextCursor: null }, () => renderRegistryList(ctx, orgName, { ...result, items }));
32197
32412
  };
32198
- var handleRegistryView = async (ctx, { args }) => {
32413
+ var handleRegistryView = async (ctx, { flags, args }) => {
32199
32414
  const { orgName, componentName } = resolveRegisteredComponentRef(args[0], "Usage: wh component registry view <org/name>", "wh component registry view warmhub/veritas");
32200
32415
  const result = await ctx.client.component.registry.view(orgName, componentName);
32201
- writeOutput(ctx, result, () => renderRegistryEntry(ctx, result));
32416
+ const output = redactRegistryEntryLifecycleUrls(result, flags["show-secrets"]);
32417
+ writeOutput(ctx, output, () => renderRegistryEntry(ctx, output));
32202
32418
  };
32203
32419
  var handleRegistryUpdate = async (ctx, { flags, args }) => {
32204
32420
  const { orgName, componentName } = resolveRegisteredComponentRef(args[0], "Usage: wh component registry update <org/name> [flags]", "wh component registry update warmhub/veritas --public");
@@ -32226,12 +32442,12 @@ var handleRegistryUpdate = async (ctx, { flags, args }) => {
32226
32442
  description: flags.description,
32227
32443
  mintedTokens
32228
32444
  });
32229
- writeOutput(ctx, result, () => renderRegistryEntry(ctx, result));
32445
+ const output = redactRegistryEntryLifecycleUrls(result, flags["show-secrets"]);
32446
+ writeOutput(ctx, output, () => renderRegistryEntry(ctx, output));
32230
32447
  };
32231
- var handleInstall = async (ctx, { args }) => {
32448
+ var handleInstall = async (_ctx, { args }) => {
32232
32449
  const source = args[0];
32233
- const usage = `Usage: wh component install <source> --repo org/repo
32234
- source: <org>/<name> (registered component)`;
32450
+ const usage = "Usage: wh component install <org/name> --repo org/repo";
32235
32451
  const example = "wh component install warmhub/veritas --repo myorg/myrepo";
32236
32452
  if (!source) {
32237
32453
  usageError(usage, example);
@@ -32262,9 +32478,12 @@ var handleList2 = async (ctx, { flags }) => {
32262
32478
  const c = ctx.colors;
32263
32479
  const { items, nextCursor } = await fetchComponentPages(ctx.client, org, repo, { all: flags.all, limit: flags.limit, cursor: flags.cursor });
32264
32480
  if (!flags.all && nextCursor) {
32265
- ctx.status(`${c.yellow}${items.length} shown, more available${c.reset} — use ${c.cyan}--all${c.reset} to fetch every page, ` + `or re-run the same command plus ${c.cyan}--cursor=${nextCursor}${c.reset} to resume from here.`);
32481
+ emitPartialPageHint(ctx, items.length, nextCursor, Math.min(flags.limit ?? DEFAULT_COMPONENT_LIST_LIMIT, MAX_COMPONENT_LIST_LIMIT));
32266
32482
  }
32267
- writeOutput(ctx, items, () => {
32483
+ writePageOutput(ctx, items, {
32484
+ limit: Math.min(flags.limit ?? DEFAULT_COMPONENT_LIST_LIMIT, MAX_COMPONENT_LIST_LIMIT),
32485
+ nextCursor: flags.all ? null : nextCursor ?? null
32486
+ }, () => {
32268
32487
  if (!items.length) {
32269
32488
  ctx.status(`${c.dim}No components installed${c.reset}`);
32270
32489
  return;
@@ -32276,51 +32495,41 @@ var handleList2 = async (ctx, { flags }) => {
32276
32495
  const state = item.state ?? "unknown";
32277
32496
  const source = item.source ?? "-";
32278
32497
  const stateColor = stateToColor(c, state);
32279
- ctx.out(` ${c.cyan}${item.componentId}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32498
+ ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32280
32499
  }
32281
32500
  });
32282
32501
  };
32283
32502
  var handleSearch2 = async (ctx, { flags, args }) => {
32284
32503
  const query = args[0]?.trim();
32285
32504
  if (!query) {
32286
- usageError("Usage: wh component search <query> --repo org/repo", "wh component search research --repo myorg/myrepo");
32505
+ usageError("Usage: wh component search <query>", 'wh component search "subjective logic"');
32287
32506
  }
32288
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32289
- const c = ctx.colors;
32290
- const { items: allItems, nextCursor } = await fetchComponentPages(ctx.client, org, repo, { all: flags.all, limit: flags.limit, cursor: flags.cursor });
32291
- const needle = query.toLowerCase();
32292
- const items = allItems.filter((item) => [item.componentId, item.componentName, item.source].filter((value) => typeof value === "string").some((value) => value.toLowerCase().includes(needle)));
32293
- if (!flags.all && nextCursor) {
32294
- ctx.status(`${c.yellow}${allItems.length} component(s) searched, more pages available${c.reset} — matches beyond this page were not searched. ` + `Use ${c.cyan}--all${c.reset} to search every page, ` + `or re-run the same command plus ${c.cyan}--cursor=${nextCursor}${c.reset} to continue from here.`);
32507
+ if (getRepoRef(ctx)) {
32508
+ const c = ctx.colors;
32509
+ ctx.status(`${c.dim}--repo is ignored: \`wh component search\` searches the cross-org registry. ` + `Use \`wh component list --repo <org/repo>\` to see installed components.${c.reset}`);
32295
32510
  }
32296
- writeOutput(ctx, items, () => {
32297
- if (!items.length) {
32298
- ctx.status(`${c.dim}No components matching "${query}" in ${org}/${repo}${c.reset}`);
32299
- return;
32300
- }
32301
- ctx.out(`${c.bold}Matching Components${c.reset} ${c.cyan}${org}/${repo}${c.reset}`);
32302
- ctx.out("");
32303
- for (const item of items) {
32304
- const version = item.version ?? "unknown";
32305
- const state = item.state ?? "unknown";
32306
- const source = item.source ?? "-";
32307
- const stateColor = stateToColor(c, state);
32308
- ctx.out(` ${c.cyan}${item.componentId}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32309
- }
32511
+ await runGlobalSearchCommand(ctx, {
32512
+ query,
32513
+ all: flags.all,
32514
+ limit: flags.limit,
32515
+ cursor: flags.cursor,
32516
+ fetch: (opts) => ctx.client.component.search(query, opts),
32517
+ title: "Component search",
32518
+ emptyLabel: "public components"
32310
32519
  });
32311
32520
  };
32312
32521
  var handleView3 = async (ctx, { args }) => {
32313
- const name = args[0];
32314
- const usage = "Usage: wh component view <name> --repo org/repo";
32315
- const example = "wh component view research-knowledge --repo myorg/myrepo";
32316
- if (!name) {
32522
+ const ref = args[0];
32523
+ const usage = "Usage: wh component view <org/name> --repo org/repo";
32524
+ const example = "wh component view myorg/research-knowledge --repo myorg/myrepo";
32525
+ if (!ref) {
32317
32526
  usageError(usage, example);
32318
32527
  }
32319
32528
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32320
- const viewData = await ctx.client.component.get(org, repo, name);
32529
+ const viewData = await ctx.client.component.get(org, repo, ref);
32321
32530
  writeOutput(ctx, viewData, () => {
32322
32531
  const c = ctx.colors;
32323
- ctx.out(`${c.bold}Component:${c.reset} ${c.cyan}${name}${c.reset}`);
32532
+ ctx.out(`${c.bold}Component:${c.reset} ${c.cyan}${viewData.ref ?? ref}${c.reset}`);
32324
32533
  ctx.out(`${c.bold}Version:${c.reset} ${viewData.version ?? "unknown"}`);
32325
32534
  ctx.out(`${c.bold}State:${c.reset} ${viewData.state ?? "-"}`);
32326
32535
  ctx.out(`${c.bold}Source:${c.reset} ${viewData.source ?? "-"}`);
@@ -32396,23 +32605,24 @@ function renderValidationResult(ctx, result) {
32396
32605
  var handleDoctor = async (ctx, { args }) => {
32397
32606
  const name = args[0];
32398
32607
  if (!name) {
32399
- usageError("Usage: wh component doctor <name> --repo org/repo", "wh component doctor research-knowledge --repo myorg/myrepo");
32608
+ usageError("Usage: wh component doctor <org/name> --repo org/repo", "wh component doctor warmhub/research-knowledge --repo myorg/myrepo");
32400
32609
  }
32401
32610
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32402
- const componentId = await resolveComponentDoctorId(ctx.client, org, repo, name);
32611
+ const componentId = await resolveInstalledComponentRefId(ctx.client, org, repo, name);
32403
32612
  const result = await doctorComponent(ctx.client, org, repo, componentId);
32404
32613
  writeOutput(ctx, result, () => renderDoctorResult(ctx, result));
32405
32614
  };
32406
32615
  var handleTeardown = async (ctx, { args }) => {
32407
32616
  const name = args[0];
32408
32617
  if (!name) {
32409
- usageError("Usage: wh component teardown <name> --repo org/repo", "wh component teardown research-knowledge --repo myorg/myrepo");
32618
+ usageError("Usage: wh component teardown <org/name> --repo org/repo", "wh component teardown warmhub/research-knowledge --repo myorg/myrepo");
32410
32619
  }
32411
32620
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32412
32621
  const repoSlug = `${org}/${repo}`;
32622
+ const componentId = await resolveInstalledComponentRefId(ctx.client, org, repo, name);
32413
32623
  let result;
32414
32624
  try {
32415
- result = await teardownComponent(ctx.client, org, repo, name);
32625
+ result = await teardownComponent(ctx.client, org, repo, componentId);
32416
32626
  } catch (error) {
32417
32627
  invalidateInstallSnapshotCache(repoSlug);
32418
32628
  throw error;
@@ -32480,10 +32690,10 @@ function renderRegistryEntry(ctx, entry) {
32480
32690
  ctx.out(` Source: ${c.dim}(not installable — no source URL)${c.reset}`);
32481
32691
  }
32482
32692
  if (entry.setupUrl) {
32483
- ctx.out(` Setup: ${entry.setupUrl}`);
32693
+ ctx.out(` Setup: ${formatLifecycleUrl(entry.setupUrl, c)}`);
32484
32694
  }
32485
32695
  if (entry.uninstallUrl) {
32486
- ctx.out(` Uninstall: ${entry.uninstallUrl}`);
32696
+ ctx.out(` Uninstall: ${formatLifecycleUrl(entry.uninstallUrl, c)}`);
32487
32697
  }
32488
32698
  if (entry.credentialSetName || entry.credentialSetId) {
32489
32699
  ctx.out(` Credential set: ${entry.credentialSetName ?? entry.credentialSetId}`);
@@ -32493,6 +32703,43 @@ function renderRegistryEntry(ctx, entry) {
32493
32703
  }
32494
32704
  ctx.out(` ${c.dim}Updated: ${new Date(entry.updatedAt).toISOString().slice(0, 16)}${c.reset}`);
32495
32705
  }
32706
+ function redactRegistryEntryLifecycleUrls(entry, showSecrets) {
32707
+ if (showSecrets)
32708
+ return entry;
32709
+ return {
32710
+ ...entry,
32711
+ ...entry.setupUrl ? { setupUrl: redactSecretBearingUrl(entry.setupUrl) } : {},
32712
+ ...entry.uninstallUrl ? { uninstallUrl: redactSecretBearingUrl(entry.uninstallUrl) } : {}
32713
+ };
32714
+ }
32715
+ function redactRegistryEntryListLifecycleUrls(entries, showSecrets) {
32716
+ if (showSecrets)
32717
+ return entries;
32718
+ return entries.map((entry) => redactRegistryEntryLifecycleUrls(entry, showSecrets));
32719
+ }
32720
+ var REDACTED_LIFECYCLE_URL = "[redacted-url]";
32721
+ var REDACTED_LIFECYCLE_PATH_SUFFIX = "/***";
32722
+ function redactSecretBearingUrl(rawUrl) {
32723
+ try {
32724
+ const origin = new URL(rawUrl).origin;
32725
+ if (origin === "null") {
32726
+ return REDACTED_LIFECYCLE_URL;
32727
+ }
32728
+ return `${origin}${REDACTED_LIFECYCLE_PATH_SUFFIX}`;
32729
+ } catch {
32730
+ return REDACTED_LIFECYCLE_URL;
32731
+ }
32732
+ }
32733
+ function formatLifecycleUrl(url, colors) {
32734
+ if (url === REDACTED_LIFECYCLE_URL) {
32735
+ return `${colors.dim}${url}${colors.reset}`;
32736
+ }
32737
+ if (url.endsWith(REDACTED_LIFECYCLE_PATH_SUFFIX)) {
32738
+ const visiblePrefix = url.slice(0, -REDACTED_LIFECYCLE_PATH_SUFFIX.length);
32739
+ return `${visiblePrefix}${colors.dim}${REDACTED_LIFECYCLE_PATH_SUFFIX}${colors.reset}`;
32740
+ }
32741
+ return url;
32742
+ }
32496
32743
  function renderRegistryList(ctx, orgName, result) {
32497
32744
  const c = ctx.colors;
32498
32745
  if (!result.items.length) {
@@ -32543,7 +32790,7 @@ var COMPONENT_DOMAIN = defineDomain({
32543
32790
  install: {
32544
32791
  prime: true,
32545
32792
  summary: "Install a registered component by its <org>/<name> ref",
32546
- args: "<source>",
32793
+ args: "<org/name>",
32547
32794
  flags: installFlags,
32548
32795
  examples: [
32549
32796
  "wh component install warmhub/identity --repo org/repo",
@@ -32553,9 +32800,9 @@ var COMPONENT_DOMAIN = defineDomain({
32553
32800
  },
32554
32801
  update: {
32555
32802
  summary: "Update an installed registered component to the latest manifest",
32556
- args: "<name>",
32803
+ args: "<org/name>",
32557
32804
  flags: updateFlags,
32558
- examples: ["wh component update research-knowledge --repo org/repo"],
32805
+ examples: ["wh component update warmhub/identity --repo org/repo"],
32559
32806
  handler: handleUpdate
32560
32807
  },
32561
32808
  list: {
@@ -32569,25 +32816,25 @@ var COMPONENT_DOMAIN = defineDomain({
32569
32816
  view: {
32570
32817
  prime: true,
32571
32818
  summary: "Show component details",
32572
- args: "<name>",
32819
+ args: "<org/name>",
32573
32820
  flags: viewFlags3,
32574
- examples: ["wh component view research-knowledge --repo org/repo"],
32821
+ examples: ["wh component view warmhub/identity --repo org/repo"],
32575
32822
  handler: handleView3
32576
32823
  },
32577
32824
  teardown: {
32578
32825
  prime: true,
32579
32826
  summary: "Pause component subscriptions",
32580
- args: "<name>",
32827
+ args: "<org/name>",
32581
32828
  flags: teardownFlags,
32582
- examples: ["wh component teardown research-knowledge --repo org/repo"],
32829
+ examples: ["wh component teardown warmhub/identity --repo org/repo"],
32583
32830
  handler: handleTeardown
32584
32831
  },
32585
32832
  doctor: {
32586
32833
  prime: true,
32587
32834
  summary: "Run component health checks",
32588
- args: "<name>",
32835
+ args: "<org/name>",
32589
32836
  flags: doctorFlags,
32590
- examples: ["wh component doctor research-knowledge --repo org/repo"],
32837
+ examples: ["wh component doctor warmhub/identity --repo org/repo"],
32591
32838
  handler: handleDoctor
32592
32839
  },
32593
32840
  init: {
@@ -32616,10 +32863,13 @@ var COMPONENT_DOMAIN = defineDomain({
32616
32863
  handler: handleComponentExec
32617
32864
  },
32618
32865
  search: {
32619
- summary: "Search for components on GitHub",
32866
+ summary: "Search public components across all orgs (the registry). To list components installed in a repo, use `wh component list --repo`.",
32620
32867
  args: "<query>",
32621
32868
  flags: searchFlags2,
32622
- examples: ["wh component search research"],
32869
+ examples: [
32870
+ 'wh component search "subjective logic"',
32871
+ "wh component search reputation"
32872
+ ],
32623
32873
  handler: handleSearch2
32624
32874
  }
32625
32875
  },
@@ -32742,7 +32992,7 @@ var handleCreate3 = async (ctx, { flags, args }) => {
32742
32992
  var handleList3 = async (ctx, { flags }) => {
32743
32993
  const context = resolveCredentialContext({ ctx, orgFlag: flags.org });
32744
32994
  const items = await ctx.client.credential.listSets(context.org, context.repo);
32745
- writeOutput(ctx, items, () => {
32995
+ writePageOutput(ctx, items, { limit: items.length, nextCursor: null }, () => {
32746
32996
  const c = ctx.colors;
32747
32997
  if (!items.length) {
32748
32998
  ctx.status(`${c.dim}No credential sets in ${formatCredentialContextTarget(context)}${c.reset}`);
@@ -32893,7 +33143,7 @@ var handleAudit = async (ctx, { flags, args }) => {
32893
33143
  limit: flags.limit
32894
33144
  })
32895
33145
  });
32896
- writeOutput(ctx, entries, () => {
33146
+ writePageOutput(ctx, entries, { limit: flags.limit ?? entries.length, nextCursor: null }, () => {
32897
33147
  const c = ctx.colors;
32898
33148
  if (!entries.length) {
32899
33149
  ctx.status(`${c.dim}No audit entries for ${setName}${c.reset}`);
@@ -33035,7 +33285,7 @@ import { basename } from "node:path";
33035
33285
  // ../../packages/warmhub-cli/src/harness.ts
33036
33286
  import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
33037
33287
  import { homedir as homedir4 } from "node:os";
33038
- import { dirname as dirname6, join as join6 } from "node:path";
33288
+ import { dirname as dirname6, join as join5 } from "node:path";
33039
33289
  var AGENTS_BEGIN_MARKER = "<!-- BEGIN WARMHUB CLI INTEGRATION -->";
33040
33290
  var AGENTS_END_MARKER = "<!-- END WARMHUB CLI INTEGRATION -->";
33041
33291
  var PRIME_COMMAND = "wh prime";
@@ -33055,10 +33305,10 @@ function getHarnessPaths(opts) {
33055
33305
  const userHome = opts?.homeDir ?? homedir4();
33056
33306
  return {
33057
33307
  repoDir,
33058
- agentsPath: join6(repoDir, "AGENTS.md"),
33059
- projectSettingsPath: join6(repoDir, ".claude", "settings.json"),
33060
- projectLocalSettingsPath: join6(repoDir, ".claude", "settings.local.json"),
33061
- globalSettingsPath: join6(userHome, ".claude", "settings.json")
33308
+ agentsPath: join5(repoDir, "AGENTS.md"),
33309
+ projectSettingsPath: join5(repoDir, ".claude", "settings.json"),
33310
+ projectLocalSettingsPath: join5(repoDir, ".claude", "settings.local.json"),
33311
+ globalSettingsPath: join5(userHome, ".claude", "settings.json")
33062
33312
  };
33063
33313
  }
33064
33314
  async function readJsonFile(path2) {
@@ -33302,7 +33552,7 @@ function comparePrereleaseIdentifiers2(a, b) {
33302
33552
  return -1;
33303
33553
  if (!aNum && bNum)
33304
33554
  return 1;
33305
- return a.localeCompare(b);
33555
+ return a < b ? -1 : a > b ? 1 : 0;
33306
33556
  }
33307
33557
  function compareVersions(candidate, current) {
33308
33558
  if (candidate.major !== current.major)
@@ -33965,7 +34215,7 @@ var handleNotifications = async (ctx, { flags }) => {
33965
34215
  since: parseSince(flags.since, usage, example),
33966
34216
  limit: flags.limit
33967
34217
  });
33968
- writeOutput(ctx, result, () => renderActionNotifications(ctx.out, ctx.status, ctx.colors, result));
34218
+ writePageOutput(ctx, result, { limit: flags.limit ?? result.length, nextCursor: null }, () => renderActionNotifications(ctx.out, ctx.status, ctx.colors, result));
33969
34219
  };
33970
34220
  var NOTIFICATIONS_DOMAIN = defineDomain({
33971
34221
  kind: "flat",
@@ -34038,7 +34288,7 @@ var handleList4 = async (ctx, { flags }) => {
34038
34288
  const result = await ctx.client.org.list({
34039
34289
  includeArchived: flags["include-archived"]
34040
34290
  });
34041
- writeOutput(ctx, result.items, () => {
34291
+ writePageOutput(ctx, result.items, { limit: result.items.length, nextCursor: null }, () => {
34042
34292
  if (!result.items.length) {
34043
34293
  ctx.status(`${c.dim}No organizations${c.reset}`);
34044
34294
  return;
@@ -34459,17 +34709,18 @@ cat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped
34459
34709
  - \`wh credential revoke <setName> [--repo org/repo | --org org] [--reason]\` — Revoke a credential set (blocks new binds and strips auth from existing webhook deliveries)
34460
34710
 
34461
34711
  ### component — Component management
34462
- - \`wh component validate <path>\` — Validate a component package from disk
34463
- - \`wh component install <source>\` — Install a component from a bundled system id or a registered \`<org>/<name>\`
34464
- - \`wh component register <name> --org <org> --manifest <path> [flags]\` — Register a component identity (first manifest version) for \`install <org/name>\`
34712
+ - \`wh component validate <path>\` — Validate package
34713
+ - \`wh component install <org/name>\` — Install a registered component
34714
+ - \`wh component register <name> --org <org> --manifest <path> [flags]\` — Register component identity
34465
34715
  - \`wh component unregister <org/name>\` — Remove a registered component identity
34466
34716
  - \`wh component registry list --org <org>\` — List registered components
34467
34717
  - \`wh component registry view <org/name>\` — View a registered component
34468
34718
  - \`wh component registry update <org/name> [flags]\` — Update a registered component
34469
34719
  - \`wh component list\` — List installed components
34470
- - \`wh component view <name>\` — Show component details (alias: show)
34471
- - \`wh component doctor <name>\` — Run component health checks
34472
- - \`wh component teardown <name>\` — Pause component subscriptions
34720
+ - \`wh component update <org/name>\` — Update installed component
34721
+ - \`wh component view <org/name>\` — Show component details (alias: show)
34722
+ - \`wh component doctor <org/name>\` — Run component health checks
34723
+ - \`wh component teardown <org/name>\` — Pause component subscriptions
34473
34724
 
34474
34725
  ### Getting More Info
34475
34726
  - \`wh help\` — full help overview
@@ -34799,6 +35050,8 @@ var repoListFlags = {
34799
35050
  description: "Fetch all pages (auto-paginate until exhausted)"
34800
35051
  })
34801
35052
  };
35053
+ var DEFAULT_REPO_LIST_LIMIT = 50;
35054
+ var MAX_REPO_LIST_LIMIT = 200;
34802
35055
  var handleList5 = async (ctx, { flags, args }) => {
34803
35056
  const orgName = args[0] ?? ctx.config.defaultOrg;
34804
35057
  if (!orgName) {
@@ -34826,9 +35079,12 @@ var handleList5 = async (ctx, { flags, args }) => {
34826
35079
  }
34827
35080
  }
34828
35081
  if (!all && nextCursor) {
34829
- ctx.status(`${c.yellow}${items.length} shown, more available${c.reset} — use ${c.cyan}--all${c.reset} to fetch every page, ` + `or re-run the same command plus ${c.cyan}--cursor=${nextCursor}${c.reset} to resume from here.`);
35082
+ emitPartialPageHint(ctx, items.length, nextCursor, Math.min(flags.limit ?? DEFAULT_REPO_LIST_LIMIT, MAX_REPO_LIST_LIMIT));
34830
35083
  }
34831
- writeOutput(ctx, items, () => {
35084
+ writePageOutput(ctx, items, {
35085
+ limit: Math.min(flags.limit ?? DEFAULT_REPO_LIST_LIMIT, MAX_REPO_LIST_LIMIT),
35086
+ nextCursor: all ? null : nextCursor ?? null
35087
+ }, () => {
34832
35088
  if (!items.length) {
34833
35089
  ctx.status(`${c.dim}No repos in ${orgName}${c.reset}`);
34834
35090
  return;
@@ -35349,6 +35605,30 @@ var CONTENT_SUBDOMAIN = defineDomain({
35349
35605
  }
35350
35606
  }
35351
35607
  });
35608
+ var repoSearchFlags = {
35609
+ limit: flag.number({
35610
+ description: "Maximum results per page (default: 25, max: 100)"
35611
+ }),
35612
+ cursor: flag.string({ description: "Opaque pagination cursor" }),
35613
+ all: flag.boolean({
35614
+ description: "Fetch all pages (auto-paginate until exhausted)"
35615
+ })
35616
+ };
35617
+ var handleRepoSearch = async (ctx, { flags, args }) => {
35618
+ const query = args[0]?.trim();
35619
+ if (!query) {
35620
+ usageError("Usage: wh repo search <query>", 'wh repo search "payment processing"');
35621
+ }
35622
+ await runGlobalSearchCommand(ctx, {
35623
+ query,
35624
+ all: flags.all,
35625
+ limit: flags.limit,
35626
+ cursor: flags.cursor,
35627
+ fetch: (opts) => ctx.client.repo.search(query, opts),
35628
+ title: "Repo search",
35629
+ emptyLabel: "public repos"
35630
+ });
35631
+ };
35352
35632
  var REPO_DOMAIN = defineDomain({
35353
35633
  name: "repo",
35354
35634
  summary: "Repository management",
@@ -35379,6 +35659,14 @@ var REPO_DOMAIN = defineDomain({
35379
35659
  ],
35380
35660
  handler: handleList5
35381
35661
  },
35662
+ search: {
35663
+ prime: true,
35664
+ summary: "Search public repos across all orgs",
35665
+ args: "<query>",
35666
+ flags: repoSearchFlags,
35667
+ examples: ["wh repo search users", "wh repo search users --limit 10"],
35668
+ handler: handleRepoSearch
35669
+ },
35382
35670
  view: {
35383
35671
  prime: true,
35384
35672
  summary: "Show repo details",
@@ -35481,7 +35769,7 @@ var FIELD_CONSTRAINTS_NOTES = [
35481
35769
  var listFlags4 = {
35482
35770
  match: flag.string({ description: "Filter by name glob pattern" }),
35483
35771
  component: flag.string({
35484
- description: "Filter to shapes owned by this component ID"
35772
+ description: "Filter to shapes owned by this component (Org/Name ref)"
35485
35773
  }),
35486
35774
  "exclude-components": flag.boolean({
35487
35775
  description: "Exclude component-owned shapes from results"
@@ -35494,18 +35782,18 @@ var handleList6 = async (ctx, { flags }) => {
35494
35782
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
35495
35783
  const c = ctx.colors;
35496
35784
  const match = flags.match;
35497
- const componentId = flags.component;
35785
+ const componentRef = flags.component;
35498
35786
  const excludeComponents = !!flags["exclude-components"];
35499
35787
  const includeRetracted = flags["include-retracted"];
35500
- validateComponentFilters(componentId, excludeComponents, "wh shape list --component com.example.pkg", "wh shape list --exclude-components");
35788
+ validateComponentFilters(componentRef, excludeComponents, "wh shape list --component acme/veritas", "wh shape list --exclude-components");
35501
35789
  const result = await ctx.client.shape.list(org, repo, {
35502
35790
  match,
35503
- componentId,
35791
+ componentRef,
35504
35792
  excludeComponents,
35505
35793
  includeRetracted
35506
35794
  });
35507
35795
  const items = result.items;
35508
- writeOutput(ctx, items, () => {
35796
+ writePageOutput(ctx, items, { limit: items.length, nextCursor: null }, () => {
35509
35797
  if (!items.length) {
35510
35798
  ctx.status(`${c.dim}No shapes registered${c.reset}`);
35511
35799
  return;
@@ -35567,9 +35855,9 @@ var handleView7 = async (ctx, { flags, args }) => {
35567
35855
  if (typeof shapeDescription === "string" && shapeDescription) {
35568
35856
  ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
35569
35857
  }
35570
- const cid = result.componentId;
35571
- if (cid) {
35572
- ctx.out(` ${c.dim}owner:${c.reset} ${c.yellow}${cid}${c.reset}`);
35858
+ const componentRef = result.componentRef;
35859
+ if (componentRef) {
35860
+ ctx.out(` ${c.dim}owner:${c.reset} ${c.yellow}${componentRef}${c.reset}`);
35573
35861
  }
35574
35862
  const fields = shapeData?.fields;
35575
35863
  if (fields) {
@@ -35742,7 +36030,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
35742
36030
  if (!all && result.nextCursor) {
35743
36031
  emitPartialPageHint(ctx, (result.versions ?? []).length, result.nextCursor, pageLimit);
35744
36032
  }
35745
- writeOutput(ctx, result, () => renderHistory(ctx.out, ctx.colors, result));
36033
+ writePageOutput(ctx, result.versions ?? [], { limit: pageLimit, nextCursor: result.nextCursor ?? null }, () => renderHistory(ctx.out, ctx.colors, result));
35746
36034
  };
35747
36035
  var handleShapeRename = async (ctx, { args }) => {
35748
36036
  const oldName = args[0];
@@ -36184,7 +36472,7 @@ var handleList7 = async (ctx, { flags }) => {
36184
36472
  const { org, repo } = resolveRepoContext(ctx);
36185
36473
  const all = await ctx.client.subscription.list(org, repo);
36186
36474
  const items = all.slice(0, flags.limit ?? all.length);
36187
- writeOutput(ctx, items, () => {
36475
+ writePageOutput(ctx, items, { limit: flags.limit ?? all.length, nextCursor: null }, () => {
36188
36476
  const c = ctx.colors;
36189
36477
  if (!items.length) {
36190
36478
  ctx.status(`${c.dim}No subscriptions in ${org}/${repo}${c.reset}`);
@@ -36651,7 +36939,7 @@ var handleCreate8 = async (ctx, { flags }) => {
36651
36939
  var handleList8 = async (ctx, { flags }) => {
36652
36940
  const c = ctx.colors;
36653
36941
  const items = await ctx.client.token.list({ includeInactive: flags.all });
36654
- writeOutput(ctx, items, () => {
36942
+ writePageOutput(ctx, items, { limit: items.length, nextCursor: null }, () => {
36655
36943
  if (!items.length) {
36656
36944
  ctx.status(`${c.dim}No tokens${c.reset}`);
36657
36945
  return;
@@ -37869,10 +38157,6 @@ async function dispatch(ctx) {
37869
38157
  const { command } = ctx.invocation;
37870
38158
  if (!command || command === "help") {
37871
38159
  const helpTarget = command === "help" ? ctx.invocation.positional[0] : undefined;
37872
- if (ctx.format === "json") {
37873
- printJson(ctx.out, buildCliSpec());
37874
- return;
37875
- }
37876
38160
  if (helpTarget) {
37877
38161
  const domain = registry.getDomain(helpTarget);
37878
38162
  if (domain) {
@@ -37881,6 +38165,10 @@ async function dispatch(ctx) {
37881
38165
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown command: ${helpTarget}`, undefined, "Run 'wh help' for available commands.");
37882
38166
  }
37883
38167
  } else {
38168
+ if (ctx.format === "json") {
38169
+ printJson(ctx.out, buildCliSpec());
38170
+ return;
38171
+ }
37884
38172
  let repoSlug;
37885
38173
  try {
37886
38174
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
@@ -37932,6 +38220,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37932
38220
  const errors = [];
37933
38221
  const { meta, manifest } = pkg;
37934
38222
  const componentId = meta.id;
38223
+ const componentRef = source.registeredComponentRef;
37935
38224
  const validation = validateComponentPackage(pkg);
37936
38225
  if (!validation.valid) {
37937
38226
  const validationErrors = validation.findings.filter((f) => f.level === "error").map((f) => f.message);
@@ -37982,7 +38271,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37982
38271
  const oldCredNames = wasIncomplete ? new Set : new Set(oldManifest?.credentials?.map((c) => c.name) ?? []);
37983
38272
  const liveShapeNames = new Set;
37984
38273
  const liveShapeDataByName = new Map;
37985
- const liveShapeComponentIdByName = new Map;
38274
+ const liveShapeComponentRefByName = new Map;
37986
38275
  for (const shape of reconcileShapes) {
37987
38276
  if (isFailedInstallState || previousState !== "degraded" && !oldShapeNames.has(shape.name)) {
37988
38277
  continue;
@@ -37999,7 +38288,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37999
38288
  includeRetracted: true
38000
38289
  });
38001
38290
  liveShapeDataByName.set(shape.name, liveShape.version?.data);
38002
- liveShapeComponentIdByName.set(shape.name, liveShape.componentId);
38291
+ liveShapeComponentRefByName.set(shape.name, liveShape.componentRef);
38003
38292
  } catch {}
38004
38293
  } catch {}
38005
38294
  }
@@ -38034,7 +38323,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38034
38323
  data: manifestShapeData(shape)
38035
38324
  }));
38036
38325
  try {
38037
- await client.commit.apply(org, repo, `Add new shapes for ${meta.name}`, shapeOps, { componentId });
38326
+ await client.commit.apply(org, repo, `Add new shapes for ${meta.name}`, shapeOps, { componentRef });
38038
38327
  steps.push({ step: "add-new-shapes", status: "ok" });
38039
38328
  } catch (err) {
38040
38329
  const msg = err instanceof Error ? err.message : String(err);
@@ -38050,8 +38339,8 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38050
38339
  if (!liveShapeNames.has(shape.name))
38051
38340
  return false;
38052
38341
  const liveData = liveShapeDataByName.get(shape.name);
38053
- const liveComponentId = liveShapeComponentIdByName.get(shape.name);
38054
- return liveComponentId !== componentId || !shapeDataEquals(manifestShapeData(shape), liveData);
38342
+ const liveComponentRef = liveShapeComponentRefByName.get(shape.name);
38343
+ return liveComponentRef !== componentRef || !shapeDataEquals(manifestShapeData(shape), liveData);
38055
38344
  });
38056
38345
  if (changedShapes.length > 0) {
38057
38346
  const shapeOps = changedShapes.map((shape) => ({
@@ -38061,7 +38350,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38061
38350
  data: manifestShapeData(shape)
38062
38351
  }));
38063
38352
  try {
38064
- await client.commit.apply(org, repo, `Reconcile shapes for ${meta.name}`, shapeOps, { componentId });
38353
+ await client.commit.apply(org, repo, `Reconcile shapes for ${meta.name}`, shapeOps, { componentRef });
38065
38354
  steps.push({ step: "claim-existing-shapes", status: "ok" });
38066
38355
  } catch (err) {
38067
38356
  const msg = err instanceof Error ? err.message : String(err);
@@ -38127,7 +38416,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38127
38416
  filterJson: compiled.filterJson,
38128
38417
  webhookUrl: compiled.webhookUrl,
38129
38418
  fallbackWebhookUrl: compiled.fallbackWebhookUrl,
38130
- componentId
38419
+ componentRef
38131
38420
  });
38132
38421
  steps.push({ step: `add-sub-${sub.name}`, status: "ok" });
38133
38422
  } catch (err) {
@@ -38166,8 +38455,8 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38166
38455
  }
38167
38456
  try {
38168
38457
  const liveSub = await client.subscription.get(org, repo, sub.name);
38169
- if (liveSub.componentId && liveSub.componentId !== componentId) {
38170
- const msg = `Subscription "${sub.name}" is owned by component "${liveSub.componentId}"`;
38458
+ if (liveSub.componentRef && liveSub.componentRef !== componentRef) {
38459
+ const msg = `Subscription "${sub.name}" is owned by component "${liveSub.componentRef}"`;
38171
38460
  errors.push(msg);
38172
38461
  steps.push({ step: stepName, status: "error", message: msg });
38173
38462
  continue;
@@ -38185,7 +38474,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38185
38474
  filterJson: compiled.filterJson,
38186
38475
  webhookUrl: compiled.webhookUrl,
38187
38476
  fallbackWebhookUrl: compiled.fallbackWebhookUrl,
38188
- componentId
38477
+ componentRef
38189
38478
  });
38190
38479
  } catch (createErr) {
38191
38480
  const createMsg = createErr instanceof Error ? createErr.message : String(createErr);
@@ -38242,7 +38531,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38242
38531
  name: `${seed.shape}/${seed.name}`,
38243
38532
  data: seed.data
38244
38533
  }
38245
- ], { componentId });
38534
+ ], { componentRef });
38246
38535
  } catch (reviseErr) {
38247
38536
  const reviseMsg = reviseErr instanceof Error ? reviseErr.message : String(reviseErr);
38248
38537
  const reviseLooksMissing = reviseMsg.includes("not found") || reviseMsg.includes("NOT_FOUND");
@@ -38258,7 +38547,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38258
38547
  name: `${seed.shape}/${seed.name}`,
38259
38548
  data: seed.data
38260
38549
  }
38261
- ], { componentId });
38550
+ ], { componentRef });
38262
38551
  } catch (addErr) {
38263
38552
  const msg = addErr instanceof Error ? addErr.message : String(addErr);
38264
38553
  if (!isAlreadyExistsError(addErr)) {
@@ -38283,8 +38572,8 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38283
38572
  componentId,
38284
38573
  name: meta.name,
38285
38574
  version: meta.version,
38286
- source: source.githubUrl ?? "local",
38287
- sourceKind: source.sourceKind ?? (source.githubUrl ? "github" : "local"),
38575
+ source: "registry",
38576
+ sourceKind: "registered",
38288
38577
  sourceRef: source.ref ?? "",
38289
38578
  resolvedSha: source.resolvedSha ?? "",
38290
38579
  ...source.registeredComponentRef ? { registeredComponentRef: source.registeredComponentRef } : {},
@@ -38296,7 +38585,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38296
38585
  ...source.installId ?? persistedInstallId ? { installId: source.installId ?? persistedInstallId } : {}
38297
38586
  }
38298
38587
  }
38299
- ], { componentId: SYSTEM_COMPONENT_ID });
38588
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
38300
38589
  steps.push({ step: "update-install-record", status: "ok" });
38301
38590
  } catch (err) {
38302
38591
  const msg = err instanceof Error ? err.message : String(err);
@@ -38411,8 +38700,8 @@ async function installComponent(client, org, repo, pkg, source) {
38411
38700
  componentId,
38412
38701
  name: meta.name,
38413
38702
  version: meta.version,
38414
- source: source.githubUrl ?? "local",
38415
- sourceKind: source.sourceKind ?? (source.githubUrl ? "github" : "local"),
38703
+ source: "registry",
38704
+ sourceKind: "registered",
38416
38705
  sourceRef: source.ref ?? "",
38417
38706
  resolvedSha: source.resolvedSha ?? "",
38418
38707
  ...source.registeredComponentRef ? { registeredComponentRef: source.registeredComponentRef } : {},
@@ -38423,7 +38712,7 @@ async function installComponent(client, org, repo, pkg, source) {
38423
38712
  ...source.installId ? { installId: source.installId } : {}
38424
38713
  }
38425
38714
  }
38426
- ], { componentId: SYSTEM_COMPONENT_ID });
38715
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
38427
38716
  steps.push({ step: "create-install-record", status: "ok" });
38428
38717
  } catch (err) {
38429
38718
  const msg = err instanceof Error ? err.message : String(err);
@@ -38439,13 +38728,13 @@ async function installComponent(client, org, repo, pkg, source) {
38439
38728
  data: manifestShapeData(shape)
38440
38729
  }));
38441
38730
  try {
38442
- await client.commit.apply(org, repo, `Add shapes for ${meta.name}`, shapeOps, { componentId });
38731
+ await client.commit.apply(org, repo, `Add shapes for ${meta.name}`, shapeOps, { componentRef: source.registeredComponentRef });
38443
38732
  steps.push({ step: "create-shapes", status: "ok" });
38444
38733
  } catch (err) {
38445
38734
  const msg = err instanceof Error ? err.message : String(err);
38446
38735
  if (isAlreadyExistsError(err)) {
38447
38736
  try {
38448
- await reconcileShapesAfterCreateConflict(client, org, repo, pkg);
38737
+ await reconcileShapesAfterCreateConflict(client, org, repo, pkg, source);
38449
38738
  steps.push({
38450
38739
  step: "create-shapes",
38451
38740
  status: "ok",
@@ -38522,7 +38811,7 @@ async function installComponent(client, org, repo, pkg, source) {
38522
38811
  filterJson: compiled.filterJson,
38523
38812
  webhookUrl: compiled.webhookUrl,
38524
38813
  fallbackWebhookUrl: compiled.fallbackWebhookUrl,
38525
- componentId
38814
+ componentRef: source.registeredComponentRef
38526
38815
  });
38527
38816
  steps.push({ step: `create-sub-${sub.name}`, status: "ok" });
38528
38817
  } catch (err) {
@@ -38561,7 +38850,7 @@ async function installComponent(client, org, repo, pkg, source) {
38561
38850
  name: seedName,
38562
38851
  data: seed.data
38563
38852
  }
38564
- ], { componentId });
38853
+ ], { componentRef: source.registeredComponentRef });
38565
38854
  steps.push({ step: `seed-${seedName}`, status: "ok" });
38566
38855
  } catch (err) {
38567
38856
  const msg = err instanceof Error ? err.message : String(err);
@@ -38588,8 +38877,8 @@ async function installComponent(client, org, repo, pkg, source) {
38588
38877
  componentId,
38589
38878
  name: meta.name,
38590
38879
  version: meta.version,
38591
- source: source.githubUrl ?? "local",
38592
- sourceKind: source.sourceKind ?? (source.githubUrl ? "github" : "local"),
38880
+ source: "registry",
38881
+ sourceKind: "registered",
38593
38882
  sourceRef: source.ref ?? "",
38594
38883
  resolvedSha: source.resolvedSha ?? "",
38595
38884
  ...source.registeredComponentRef ? { registeredComponentRef: source.registeredComponentRef } : {},
@@ -38601,7 +38890,7 @@ async function installComponent(client, org, repo, pkg, source) {
38601
38890
  ...source.installId ? { installId: source.installId } : {}
38602
38891
  }
38603
38892
  }
38604
- ], { componentId: SYSTEM_COMPONENT_ID });
38893
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
38605
38894
  steps.push({ step: "finalize", status: "ok" });
38606
38895
  } catch (err) {
38607
38896
  const msg = err instanceof Error ? err.message : String(err);
@@ -38619,12 +38908,12 @@ function assertCliMethodsAllowedForSource(pkg, source) {
38619
38908
  const hasCliMethods = (pkg.manifest.cli?.methods?.length ?? 0) > 0;
38620
38909
  if (!hasCliMethods)
38621
38910
  return;
38622
- if (source.sourceKind === "registered" && typeof source.registeredComponentRef === "string" && source.registeredComponentRef.length > 0) {
38911
+ if (typeof source.registeredComponentRef === "string" && source.registeredComponentRef.length > 0) {
38623
38912
  return;
38624
38913
  }
38625
38914
  throw new CliError(2 /* UserInput */, "USER_INPUT", "Components that declare manifest.cli.methods must be installed from the registry.", undefined, "Register the component, then install it as <org>/<name>. Local path and GitHub URL installs cannot expose CLI methods.");
38626
38915
  }
38627
- async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38916
+ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg, source) {
38628
38917
  const { meta, manifest } = pkg;
38629
38918
  const existingShapes = new Map;
38630
38919
  for (const shape of manifest.shapes) {
@@ -38632,8 +38921,8 @@ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38632
38921
  const existingShape = await client.shape.get(org, repo, shape.name, {
38633
38922
  includeRetracted: true
38634
38923
  });
38635
- if (existingShape.componentId !== meta.id) {
38636
- const owner = existingShape.componentId ? `owned by component "${existingShape.componentId}"` : "not owned by this component";
38924
+ if (existingShape.componentRef !== source.registeredComponentRef) {
38925
+ const owner = existingShape.componentRef ? `owned by component "${existingShape.componentRef}"` : "not owned by this component";
38637
38926
  throw new Error(`Shape "${shape.name}" already exists and is ${owner}; cannot reconcile during fresh install`);
38638
38927
  }
38639
38928
  existingShapes.set(shape.name, existingShape);
@@ -38655,7 +38944,7 @@ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38655
38944
  name: shape.name,
38656
38945
  data
38657
38946
  }
38658
- ], { componentId: meta.id });
38947
+ ], { componentRef: source.registeredComponentRef });
38659
38948
  continue;
38660
38949
  }
38661
38950
  try {
@@ -38666,7 +38955,7 @@ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38666
38955
  name: shape.name,
38667
38956
  data
38668
38957
  }
38669
- ], { componentId: meta.id });
38958
+ ], { componentRef: source.registeredComponentRef });
38670
38959
  } catch (err) {
38671
38960
  if (isAlreadyExistsError(err)) {
38672
38961
  throw new Error(`Shape "${shape.name}" already exists but ownership could not be verified; cannot reconcile during fresh install`);
@@ -38888,14 +39177,16 @@ async function runCli(argv, opts) {
38888
39177
  teeStderr: debugMode,
38889
39178
  whVersion: version
38890
39179
  });
38891
- process.once("uncaughtException", (e) => {
39180
+ const handleUncaughtException = (e) => {
38892
39181
  logger.crash(e, "uncaughtException");
38893
39182
  process.exit(1);
38894
- });
38895
- process.once("unhandledRejection", (reason) => {
39183
+ };
39184
+ const handleUnhandledRejection = (reason) => {
38896
39185
  logger.crash(reason, "unhandledRejection");
38897
39186
  process.exit(1);
38898
- });
39187
+ };
39188
+ process.once("uncaughtException", handleUncaughtException);
39189
+ process.once("unhandledRejection", handleUnhandledRejection);
38899
39190
  logger.info("cli.start", {
38900
39191
  argv: redactArgv(argv),
38901
39192
  version,
@@ -38905,6 +39196,7 @@ async function runCli(argv, opts) {
38905
39196
  profile: getStringFlag(invocation.flags, "profile", "P") ?? undefined
38906
39197
  });
38907
39198
  let exitCode = 0 /* Ok */;
39199
+ let removeSignalListeners;
38908
39200
  try {
38909
39201
  canonicalizeGlobalFlags({ invocation });
38910
39202
  const retirementHint = lookupInvocationRenameHint(invocation);
@@ -38957,17 +39249,23 @@ async function runCli(argv, opts) {
38957
39249
  const chars = makeChars();
38958
39250
  const ac = new AbortController;
38959
39251
  const liveMode = getBoolFlag(invocation.flags, "live");
38960
- process.on("SIGINT", () => {
39252
+ const handleSigint = () => {
38961
39253
  ac.abort();
38962
39254
  logger.info("cli.cancelled", { signal: "SIGINT" });
38963
39255
  if (!liveMode)
38964
39256
  process.exitCode = 130 /* Cancelled */;
38965
- });
38966
- process.on("SIGTERM", () => {
39257
+ };
39258
+ const handleSigterm = () => {
38967
39259
  ac.abort();
38968
39260
  logger.info("cli.cancelled", { signal: "SIGTERM" });
38969
39261
  process.exitCode = 143;
38970
- });
39262
+ };
39263
+ process.on("SIGINT", handleSigint);
39264
+ process.on("SIGTERM", handleSigterm);
39265
+ removeSignalListeners = () => {
39266
+ process.removeListener("SIGINT", handleSigint);
39267
+ process.removeListener("SIGTERM", handleSigterm);
39268
+ };
38971
39269
  await dispatch({
38972
39270
  client,
38973
39271
  config,
@@ -39026,6 +39324,9 @@ async function runCli(argv, opts) {
39026
39324
  });
39027
39325
  return exitCode;
39028
39326
  } finally {
39327
+ process.removeListener("uncaughtException", handleUncaughtException);
39328
+ process.removeListener("unhandledRejection", handleUnhandledRejection);
39329
+ removeSignalListeners?.();
39029
39330
  logger.info("cli.end", {
39030
39331
  exit_code: exitCode,
39031
39332
  duration_ms: Date.now() - startedAt
@@ -39081,7 +39382,7 @@ function resolveLogLevel(flags, env) {
39081
39382
  // package.json
39082
39383
  var package_default3 = {
39083
39384
  name: "@warmhub/cli",
39084
- version: "0.52.1",
39385
+ version: "0.54.0",
39085
39386
  private: false,
39086
39387
  type: "module",
39087
39388
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -39228,14 +39529,17 @@ async function maybeHandleComponentShellBoundary(argv, deps = {}) {
39228
39529
  callRegisteredSetup: callRegisteredSetupImpl
39229
39530
  });
39230
39531
  }
39231
- const name = invocation.positional[1];
39232
- if (!name) {
39532
+ const componentRef = invocation.positional[1];
39533
+ if (!componentRef) {
39233
39534
  return;
39234
39535
  }
39536
+ if (!isRegisteredComponentSource(componentRef)) {
39537
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid component reference '${componentRef}'. Expected '<org>/<name>' with no extra slashes and no empty parts.`, undefined, "Usage: wh component update <org/name> --repo org/repo");
39538
+ }
39235
39539
  const repoFlag = getStringFlag(invocation.flags, "repo") ?? config.defaultRepo;
39236
39540
  const refOverride = getStringFlag(invocation.flags, "ref");
39237
39541
  return await handleComponentUpdate({
39238
- name,
39542
+ componentRef,
39239
39543
  repoFlag,
39240
39544
  refOverride,
39241
39545
  client,
@@ -39306,7 +39610,6 @@ async function performRegisteredInstall(args) {
39306
39610
  invalidateInstallSnapshotCache(installRepo);
39307
39611
  const result = await args.installFromManifest(args.client, args.parsedRepo.org, args.parsedRepo.repo, resolved.manifest, {
39308
39612
  installId,
39309
- sourceKind: "registered",
39310
39613
  registeredComponentRef: args.componentRef
39311
39614
  });
39312
39615
  if (!result.ok) {
@@ -39371,11 +39674,15 @@ function warmHubErrorBackendCode(error) {
39371
39674
  async function handleComponentUpdate(args) {
39372
39675
  const parsedRepo = parseOrgRepo(args.repoFlag, args.config);
39373
39676
  const installRepo = `${parsedRepo.org}/${parsedRepo.repo}`;
39374
- const installThing = await args.client.thing.get(parsedRepo.org, parsedRepo.repo, `ComponentInstall/${args.name}`);
39677
+ const componentId = await resolveInstalledComponentRefId(args.client, parsedRepo.org, parsedRepo.repo, args.componentRef);
39678
+ const installThing = await args.client.thing.get(parsedRepo.org, parsedRepo.repo, `ComponentInstall/${componentId}`);
39375
39679
  const installData = installThing.data && typeof installThing.data === "object" ? installThing.data : {};
39376
39680
  const source = resolveComponentUpdateSource(installData);
39377
39681
  if (source.kind === "registered") {
39378
39682
  rejectRefForRegistered(source.componentRef, args.refOverride);
39683
+ if (source.componentRef !== args.componentRef) {
39684
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${args.componentRef}' resolved to an install for '${source.componentRef}', which is inconsistent with the install record.`);
39685
+ }
39379
39686
  return performRegisteredInstall({
39380
39687
  componentRef: source.componentRef,
39381
39688
  persistedInstallData: installData,
@@ -39391,9 +39698,9 @@ async function handleComponentUpdate(args) {
39391
39698
  });
39392
39699
  }
39393
39700
  if (source.kind === "system") {
39394
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${args.name}' is a platform-managed system install and cannot be updated via the CLI; it is reconciled automatically by the WarmHub backend.`);
39701
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${args.componentRef}' is a platform-managed system install and cannot be updated via the CLI; it is reconciled automatically by the WarmHub backend.`);
39395
39702
  }
39396
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${args.name}' was not installed from a registered component and can no longer be updated in place.`, undefined, "Register the component (`wh component register <name> --org <org> --manifest <path>`) and reinstall it with `wh component install <org>/<name>`.");
39703
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${args.componentRef}' was not installed from a registered component and can no longer be updated in place.`, undefined, "Register the component (`wh component register <name> --org <org> --manifest <path>`) and reinstall it with `wh component install <org>/<name>`.");
39397
39704
  }
39398
39705
  async function writeInstallResult(writeOut, writeErr, format, verb, result, installRepo, client) {
39399
39706
  if (result.ok) {
@@ -39866,4 +40173,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
39866
40173
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
39867
40174
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
39868
40175
 
39869
- //# debugId=4117FD49D270041C64756E2164756E21
40176
+ //# debugId=194B08F51AA9569F64756E2164756E21