@warmhub/cli 0.52.0 → 0.53.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 +369 -248
  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.51.0",
21297
+ version: "0.52.1",
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,12 @@ class WarmHubClient {
22177
22184
  throw toWarmHubError(error);
22178
22185
  }
22179
22186
  },
22180
- get: async (orgName, repoName, componentId) => {
22187
+ get: async (orgName, repoName, componentRef) => {
22181
22188
  try {
22182
22189
  return await this.trpc.component.get.query({
22183
22190
  orgName,
22184
22191
  repoName,
22185
- componentId
22192
+ componentRef
22186
22193
  });
22187
22194
  } catch (error) {
22188
22195
  throw toWarmHubError(error);
@@ -22277,7 +22284,7 @@ class WarmHubClient {
22277
22284
  repoName,
22278
22285
  committer: opts?.committer,
22279
22286
  message,
22280
- componentId: opts?.componentId,
22287
+ componentRef: opts?.componentRef,
22281
22288
  chunkSize: opts?.chunkSize,
22282
22289
  skipExisting: opts?.skipExisting,
22283
22290
  streamId: opts?.streamId,
@@ -22715,7 +22722,7 @@ class WarmHubClient {
22715
22722
  orgName,
22716
22723
  repoName,
22717
22724
  match: opts?.match,
22718
- componentId: opts?.componentId,
22725
+ componentRef: opts?.componentRef,
22719
22726
  excludeComponents: opts?.excludeComponents,
22720
22727
  includeRetracted: opts?.includeRetracted
22721
22728
  });
@@ -22832,6 +22839,17 @@ class WarmHubClient {
22832
22839
  throw toWarmHubError(error);
22833
22840
  }
22834
22841
  },
22842
+ reveal: async (orgName, repoName, name) => {
22843
+ try {
22844
+ return await this.trpc.subscription.reveal.query({
22845
+ orgName,
22846
+ repoName,
22847
+ name
22848
+ });
22849
+ } catch (error) {
22850
+ throw toWarmHubError(error);
22851
+ }
22852
+ },
22835
22853
  list: async (orgName, repoName) => {
22836
22854
  try {
22837
22855
  const result = await this.trpc.subscription.list.query({
@@ -23050,7 +23068,7 @@ class WarmHubClient {
23050
23068
  includeRetracted: opts?.includeRetracted,
23051
23069
  limit: opts?.limit,
23052
23070
  cursor: opts?.cursor,
23053
- componentId: opts?.componentId,
23071
+ componentRef: opts?.componentRef,
23054
23072
  excludeComponents: opts?.excludeComponents,
23055
23073
  excludeInfraShapes: opts?.excludeInfraShapes,
23056
23074
  where: opts?.where
@@ -23271,7 +23289,7 @@ class WarmHubClient {
23271
23289
  resolveCollections: opts?.resolveCollections,
23272
23290
  limit: opts?.limit,
23273
23291
  cursor: opts?.cursor,
23274
- componentId: opts?.componentId,
23292
+ componentRef: opts?.componentRef,
23275
23293
  excludeComponents: opts?.excludeComponents,
23276
23294
  excludeInfraShapes: opts?.excludeInfraShapes,
23277
23295
  where: opts?.where
@@ -23302,7 +23320,7 @@ class WarmHubClient {
23302
23320
  resolveCollections: opts?.resolveCollections,
23303
23321
  limit: opts?.limit,
23304
23322
  cursor: opts?.cursor,
23305
- componentId: opts?.componentId,
23323
+ componentRef: opts?.componentRef,
23306
23324
  excludeComponents: opts?.excludeComponents,
23307
23325
  excludeInfraShapes: opts?.excludeInfraShapes,
23308
23326
  mode: opts?.mode
@@ -23323,7 +23341,7 @@ class WarmHubClient {
23323
23341
  match: opts?.match,
23324
23342
  includeRetracted: opts?.includeRetracted,
23325
23343
  resolveCollections: opts?.resolveCollections,
23326
- componentId: opts?.componentId,
23344
+ componentRef: opts?.componentRef,
23327
23345
  excludeComponents: opts?.excludeComponents,
23328
23346
  excludeInfraShapes: opts?.excludeInfraShapes,
23329
23347
  where: opts?.where
@@ -25165,7 +25183,7 @@ function loadProfileStore(path) {
25165
25183
  } catch (cause) {
25166
25184
  throw corruptedAuthError(p, cause);
25167
25185
  }
25168
- if (parsed === null || typeof parsed !== "object" || parsed.version !== 1 || parsed.profiles === null || typeof parsed.profiles !== "object") {
25186
+ if (parsed === null || typeof parsed !== "object" || parsed.version !== 1 || parsed.profiles === null || typeof parsed.profiles !== "object" || Array.isArray(parsed.profiles)) {
25169
25187
  throw corruptedAuthError(p);
25170
25188
  }
25171
25189
  return parsed;
@@ -25470,20 +25488,34 @@ function recordBenchmarkResponse(response, benchmarkId) {
25470
25488
  benchmarkTelemetry.requestDbQueryCountSum += requestDbQueryCount;
25471
25489
  }
25472
25490
  }
25473
- function createBenchmarkAwareFetch(benchmarkId) {
25474
- if (!benchmarkId)
25491
+ function createBenchmarkAwareFetch(benchmarkId, signal) {
25492
+ if (!benchmarkId && !signal)
25475
25493
  return;
25476
25494
  return async (input, init) => {
25477
25495
  const headers = new Headers(init?.headers);
25478
- headers.set(BENCHMARK_HEADER, benchmarkId);
25496
+ if (benchmarkId)
25497
+ headers.set(BENCHMARK_HEADER, benchmarkId);
25479
25498
  const response = await fetch(input, {
25480
25499
  ...init,
25481
- headers
25500
+ headers,
25501
+ signal: mergeAbortSignals(init?.signal, signal)
25482
25502
  });
25483
- recordBenchmarkResponse(response, benchmarkId);
25503
+ if (benchmarkId)
25504
+ recordBenchmarkResponse(response, benchmarkId);
25484
25505
  return response;
25485
25506
  };
25486
25507
  }
25508
+ function mergeAbortSignals(requestSignal, liveSignal) {
25509
+ if (!requestSignal)
25510
+ return liveSignal;
25511
+ if (!liveSignal)
25512
+ return requestSignal;
25513
+ if (requestSignal.aborted)
25514
+ return requestSignal;
25515
+ if (liveSignal.aborted)
25516
+ return liveSignal;
25517
+ return AbortSignal.any([requestSignal, liveSignal]);
25518
+ }
25487
25519
  function resetBenchmarkTelemetry() {
25488
25520
  benchmarkTelemetry = emptyBenchmarkTelemetry();
25489
25521
  }
@@ -25511,18 +25543,34 @@ function createClient(config, opts = {}) {
25511
25543
  function wantsStructuredLiveOutput(format) {
25512
25544
  return format === "json" || format === "jsonl";
25513
25545
  }
25546
+ var LIVE_ABORTED = Symbol("live-aborted");
25547
+ function pollUntilAbort(poll, signal) {
25548
+ if (signal.aborted)
25549
+ return Promise.resolve(LIVE_ABORTED);
25550
+ return new Promise((resolve, reject) => {
25551
+ const onAbort = () => resolve(LIVE_ABORTED);
25552
+ signal.addEventListener("abort", onAbort, { once: true });
25553
+ poll.then((result) => {
25554
+ signal.removeEventListener("abort", onAbort);
25555
+ resolve(result);
25556
+ }, (error) => {
25557
+ signal.removeEventListener("abort", onAbort);
25558
+ reject(error);
25559
+ });
25560
+ });
25561
+ }
25514
25562
  async function runLive(opts) {
25515
25563
  const auth = opts.auth ?? {
25516
- getToken: async () => await getValidToken() ?? undefined
25564
+ getToken: async () => await getValidToken(opts.profile) ?? undefined
25517
25565
  };
25518
25566
  const benchmarkId = process.env.WH_BENCHMARK_ID?.trim();
25567
+ const controller = new AbortController;
25519
25568
  const client = new WarmHubClient({
25520
25569
  apiUrl: opts.apiUrl,
25521
25570
  auth,
25522
- fetch: createBenchmarkAwareFetch(benchmarkId),
25571
+ fetch: createBenchmarkAwareFetch(benchmarkId, controller.signal),
25523
25572
  functionLogs: opts.functionLogs
25524
25573
  });
25525
- const controller = new AbortController;
25526
25574
  if (opts.signal) {
25527
25575
  if (opts.signal.aborted)
25528
25576
  controller.abort();
@@ -25546,7 +25594,12 @@ async function runLive(opts) {
25546
25594
  startTimer = setTimeout(() => controller.abort(), opts.startTimeoutMs);
25547
25595
  }
25548
25596
  while (!controller.signal.aborted) {
25549
- const result = await opts.poll(client);
25597
+ const poll = opts.poll(client, controller.signal);
25598
+ const result = await pollUntilAbort(poll, controller.signal);
25599
+ if (result === LIVE_ABORTED) {
25600
+ poll.catch(() => {});
25601
+ break;
25602
+ }
25550
25603
  updates += 1;
25551
25604
  if (startTimer) {
25552
25605
  clearTimeout(startTimer);
@@ -26207,6 +26260,7 @@ var handleAbout = async (ctx, { flags, args }) => {
26207
26260
  maxUpdates: ctx.maxUpdates,
26208
26261
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
26209
26262
  functionLogs: ctx.functionLogMode,
26263
+ profile: ctx.profile,
26210
26264
  signal: ctx.signal
26211
26265
  });
26212
26266
  return;
@@ -26558,14 +26612,14 @@ function renderBatchView(out, c, result, wrefs, flagsVersion) {
26558
26612
  // ../../packages/warmhub-cli/src/domains/thing/graph.ts
26559
26613
  var graphFlags = {
26560
26614
  depth: flag.number({
26561
- description: "Resolve embedded graph to this depth (default: 2, max: 5)"
26615
+ description: "Resolve outbound wref fields, assertion backlinks, and assertion about targets to this depth (default: 2, max: 5)"
26562
26616
  }),
26563
26617
  version: flag.number({ description: "Specific version number" })
26564
26618
  };
26565
26619
  var handleThingGraph = async (ctx, { flags, args }) => {
26566
26620
  const wref = args[0];
26567
26621
  if (!wref) {
26568
- usageError("Usage: wh thing graph <wref> [--depth N]", "wh thing graph Game/base");
26622
+ usageError("Usage: wh thing graph <wref> [--depth N]", "wh thing graph Game/base", "wh thing refs Game/base --inbound");
26569
26623
  }
26570
26624
  const depth = flags.depth;
26571
26625
  if (depth !== undefined && (depth < 1 || depth > 5)) {
@@ -26635,6 +26689,7 @@ var handleHistory = async (ctx, { flags, args }) => {
26635
26689
  maxUpdates: ctx.maxUpdates,
26636
26690
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
26637
26691
  functionLogs: ctx.functionLogMode,
26692
+ profile: ctx.profile,
26638
26693
  signal: ctx.signal
26639
26694
  });
26640
26695
  return;
@@ -26745,8 +26800,8 @@ function validateKind(value, flagName = "--kind") {
26745
26800
  function resolveRepoContext(ctx) {
26746
26801
  return parseOrgRepo(getRepoRef(ctx), ctx.config);
26747
26802
  }
26748
- function validateComponentFilters(componentId, excludeComponents, ...examples) {
26749
- if (componentId && excludeComponents) {
26803
+ function validateComponentFilters(componentRef, excludeComponents, ...examples) {
26804
+ if (componentRef && excludeComponents) {
26750
26805
  usageError("Cannot combine --component with --exclude-components.", ...examples);
26751
26806
  }
26752
26807
  }
@@ -26822,7 +26877,7 @@ var headFlags = {
26822
26877
  description: "Include retracted things"
26823
26878
  }),
26824
26879
  component: flag.string({
26825
- description: "Filter to things owned by this component ID"
26880
+ description: "Filter to things owned by this component (Org/Name ref)"
26826
26881
  }),
26827
26882
  "exclude-components": flag.boolean({
26828
26883
  description: "Exclude component-owned things from results"
@@ -26848,15 +26903,15 @@ var handleHead = async (ctx, { flags, args }) => {
26848
26903
  if (cursor || all || limit || ctx.liveMode) {
26849
26904
  usageError("Usage: wh thing list --count [--shape SHAPE] [--kind KIND] [--match PATTERN]", "wh thing list --shape Player --count");
26850
26905
  }
26851
- const componentId2 = flags.component;
26906
+ const componentRef2 = flags.component;
26852
26907
  const strictExclude2 = !!flags["exclude-components"];
26853
- validateComponentFilters(componentId2, strictExclude2, "wh thing list --component com.example.pkg");
26908
+ validateComponentFilters(componentRef2, strictExclude2, "wh thing list --component acme/veritas");
26854
26909
  return handleCount(ctx, org, repo, {
26855
26910
  shape,
26856
26911
  kind,
26857
26912
  match,
26858
26913
  includeRetracted,
26859
- componentId: componentId2,
26914
+ componentRef: componentRef2,
26860
26915
  excludeComponents: strictExclude2,
26861
26916
  excludeInfraShapes: !strictExclude2 && !shape,
26862
26917
  where: where.length > 0 ? where : undefined
@@ -26870,10 +26925,10 @@ var handleHead = async (ctx, { flags, args }) => {
26870
26925
  }
26871
26926
  const boundedLimit = Math.min(limit ?? DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT);
26872
26927
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedLimit;
26873
- const componentId = flags.component;
26928
+ const componentRef = flags.component;
26874
26929
  const hasShape = !!shape;
26875
26930
  const strictExclude = !!flags["exclude-components"];
26876
- validateComponentFilters(componentId, strictExclude, "wh thing list --component com.example.pkg");
26931
+ validateComponentFilters(componentRef, strictExclude, "wh thing list --component acme/veritas");
26877
26932
  const excludeComponents = strictExclude;
26878
26933
  const excludeInfraShapes = !strictExclude && !hasShape;
26879
26934
  const headOpts = {
@@ -26883,7 +26938,7 @@ var handleHead = async (ctx, { flags, args }) => {
26883
26938
  includeRetracted,
26884
26939
  limit: pageLimit,
26885
26940
  cursor,
26886
- componentId,
26941
+ componentRef,
26887
26942
  excludeComponents,
26888
26943
  excludeInfraShapes,
26889
26944
  where: where.length > 0 ? where : undefined
@@ -26903,6 +26958,7 @@ var handleHead = async (ctx, { flags, args }) => {
26903
26958
  maxUpdates: ctx.maxUpdates,
26904
26959
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
26905
26960
  functionLogs: ctx.functionLogMode,
26961
+ profile: ctx.profile,
26906
26962
  signal: ctx.signal
26907
26963
  });
26908
26964
  return;
@@ -26914,7 +26970,7 @@ var handleHead = async (ctx, { flags, args }) => {
26914
26970
  includeRetracted,
26915
26971
  limit: pageLimit,
26916
26972
  cursor,
26917
- componentId,
26973
+ componentRef,
26918
26974
  excludeComponents,
26919
26975
  excludeInfraShapes,
26920
26976
  where: where.length > 0 ? where : undefined
@@ -26925,7 +26981,7 @@ var handleHead = async (ctx, { flags, args }) => {
26925
26981
  includeRetracted,
26926
26982
  limit: boundedLimit,
26927
26983
  cursor,
26928
- componentId,
26984
+ componentRef,
26929
26985
  excludeComponents,
26930
26986
  excludeInfraShapes,
26931
26987
  where: where.length > 0 ? where : undefined
@@ -26946,7 +27002,7 @@ async function fetchAllHeadPages(ctx, org, repo, opts) {
26946
27002
  includeRetracted: opts.includeRetracted,
26947
27003
  limit: opts.limit,
26948
27004
  cursor,
26949
- componentId: opts.componentId,
27005
+ componentRef: opts.componentRef,
26950
27006
  excludeComponents: opts.excludeComponents,
26951
27007
  excludeInfraShapes: opts.excludeInfraShapes,
26952
27008
  where: opts.where
@@ -26978,7 +27034,7 @@ var queryFlags = {
26978
27034
  description: "Include assertions about collections (Pair/Triple/Set/List) containing the target. Only applies with --about."
26979
27035
  }),
26980
27036
  component: flag.string({
26981
- description: "Filter to things owned by this component ID"
27037
+ description: "Filter to things owned by this component (Org/Name ref)"
26982
27038
  }),
26983
27039
  "exclude-components": flag.boolean({
26984
27040
  description: "Exclude component-owned things from results"
@@ -27000,10 +27056,10 @@ var handleQuery = async (ctx, { flags }) => {
27000
27056
  const count = flags.count;
27001
27057
  const includeRetracted = flags["include-retracted"];
27002
27058
  const resolveCollections = flags["resolve-collections"];
27003
- const componentId = flags.component;
27059
+ const componentRef = flags.component;
27004
27060
  const hasShape = !!shape;
27005
27061
  const strictExclude = !!flags["exclude-components"];
27006
- validateComponentFilters(componentId, strictExclude, "wh thing query --component com.example.pkg");
27062
+ validateComponentFilters(componentRef, strictExclude, "wh thing query --component acme/veritas");
27007
27063
  const excludeComponents = strictExclude;
27008
27064
  const excludeInfraShapes = !strictExclude && !hasShape;
27009
27065
  const c = ctx.colors;
@@ -27020,7 +27076,7 @@ var handleQuery = async (ctx, { flags }) => {
27020
27076
  about,
27021
27077
  includeRetracted,
27022
27078
  resolveCollections,
27023
- componentId,
27079
+ componentRef,
27024
27080
  excludeComponents,
27025
27081
  excludeInfraShapes,
27026
27082
  where: where.length > 0 ? where : undefined
@@ -27043,7 +27099,7 @@ var handleQuery = async (ctx, { flags }) => {
27043
27099
  resolveCollections,
27044
27100
  limit: pageLimit,
27045
27101
  cursor,
27046
- componentId,
27102
+ componentRef,
27047
27103
  excludeComponents,
27048
27104
  excludeInfraShapes,
27049
27105
  where: where.length > 0 ? where : undefined
@@ -27063,6 +27119,7 @@ var handleQuery = async (ctx, { flags }) => {
27063
27119
  maxUpdates: ctx.maxUpdates,
27064
27120
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
27065
27121
  functionLogs: ctx.functionLogMode,
27122
+ profile: ctx.profile,
27066
27123
  signal: ctx.signal
27067
27124
  });
27068
27125
  return;
@@ -27076,7 +27133,7 @@ var handleQuery = async (ctx, { flags }) => {
27076
27133
  resolveCollections,
27077
27134
  limit: pageLimit,
27078
27135
  cursor,
27079
- componentId,
27136
+ componentRef,
27080
27137
  excludeComponents,
27081
27138
  excludeInfraShapes,
27082
27139
  where: where.length > 0 ? where : undefined
@@ -27089,7 +27146,7 @@ var handleQuery = async (ctx, { flags }) => {
27089
27146
  resolveCollections,
27090
27147
  limit: boundedLimit,
27091
27148
  cursor,
27092
- componentId,
27149
+ componentRef,
27093
27150
  excludeComponents,
27094
27151
  excludeInfraShapes,
27095
27152
  where: where.length > 0 ? where : undefined
@@ -27112,7 +27169,7 @@ async function fetchAllQueryPages(ctx, org, repo, opts) {
27112
27169
  resolveCollections: opts.resolveCollections,
27113
27170
  limit: opts.limit,
27114
27171
  cursor,
27115
- componentId: opts.componentId,
27172
+ componentRef: opts.componentRef,
27116
27173
  excludeComponents: opts.excludeComponents,
27117
27174
  excludeInfraShapes: opts.excludeInfraShapes,
27118
27175
  where: opts.where
@@ -27390,7 +27447,7 @@ var searchFlags = {
27390
27447
  cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
27391
27448
  all: flag.boolean({ description: "Fetch all pages (text mode)" }),
27392
27449
  component: flag.string({
27393
- description: "Filter to things owned by this component ID"
27450
+ description: "Filter to things owned by this component (Org/Name ref)"
27394
27451
  }),
27395
27452
  "exclude-components": flag.boolean({
27396
27453
  description: "Exclude component-owned things from results"
@@ -27427,10 +27484,10 @@ var handleSearch = async (ctx, { flags, args }) => {
27427
27484
  const pageLimit = all ? Math.min(limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedTextLimit;
27428
27485
  const resolveCollections = mode !== "hybrid" ? flags["resolve-collections"] : undefined;
27429
27486
  const supportsComponentFilters = !mode || mode === "text";
27430
- const componentId = supportsComponentFilters ? flags.component : undefined;
27487
+ const componentRef = supportsComponentFilters ? flags.component : undefined;
27431
27488
  const hasShape = !!flags.shape;
27432
27489
  const strictExclude = supportsComponentFilters ? !!flags["exclude-components"] : false;
27433
- validateComponentFilters(componentId, strictExclude, 'wh thing search "policy" --component com.example.pkg');
27490
+ validateComponentFilters(componentRef, strictExclude, 'wh thing search "policy" --component acme/veritas');
27434
27491
  const excludeComponents = supportsComponentFilters && strictExclude ? true : undefined;
27435
27492
  const excludeInfraShapes = supportsComponentFilters && !strictExclude && !hasShape ? true : undefined;
27436
27493
  const rawResult = all ? await fetchAllSearchPages(ctx, org, repo, queryText, {
@@ -27441,7 +27498,7 @@ var handleSearch = async (ctx, { flags, args }) => {
27441
27498
  resolveCollections,
27442
27499
  limit: pageLimit,
27443
27500
  cursor,
27444
- componentId,
27501
+ componentRef,
27445
27502
  excludeComponents,
27446
27503
  excludeInfraShapes
27447
27504
  }) : await ctx.client.thing.search(org, repo, queryText, {
@@ -27453,7 +27510,7 @@ var handleSearch = async (ctx, { flags, args }) => {
27453
27510
  limit: boundedTextLimit,
27454
27511
  cursor,
27455
27512
  mode,
27456
- componentId,
27513
+ componentRef,
27457
27514
  excludeComponents,
27458
27515
  excludeInfraShapes
27459
27516
  });
@@ -27479,7 +27536,7 @@ async function fetchAllSearchPages(ctx, org, repo, queryText, opts) {
27479
27536
  limit: opts.limit,
27480
27537
  cursor,
27481
27538
  mode: "text",
27482
- componentId: opts.componentId,
27539
+ componentRef: opts.componentRef,
27483
27540
  excludeComponents: opts.excludeComponents,
27484
27541
  excludeInfraShapes: opts.excludeInfraShapes
27485
27542
  });
@@ -27616,6 +27673,7 @@ async function runSingleView(ctx, wref, flags) {
27616
27673
  maxUpdates: ctx.maxUpdates,
27617
27674
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
27618
27675
  functionLogs: ctx.functionLogMode,
27676
+ profile: ctx.profile,
27619
27677
  signal: ctx.signal
27620
27678
  });
27621
27679
  return;
@@ -27831,13 +27889,16 @@ var THING_DOMAIN = defineDomain({
27831
27889
  },
27832
27890
  graph: {
27833
27891
  prime: true,
27834
- summary: "Fetch a thing's graph (forward + reverse references) at a given depth",
27892
+ summary: "Fetch a thing's graph (outbound wref fields, assertion backlinks, and assertion about targets)",
27835
27893
  args: "<wref>",
27836
27894
  flags: graphFlags,
27837
27895
  examples: [
27838
27896
  "wh thing graph Game/base",
27839
27897
  "wh thing graph Game/base --depth 2"
27840
27898
  ],
27899
+ notes: [
27900
+ "`graph` does not traverse inbound wref-field references; use `wh thing refs <wref> --inbound` to find things whose fields point at this thing."
27901
+ ],
27841
27902
  handler: handleThingGraph
27842
27903
  }
27843
27904
  }
@@ -27990,6 +28051,7 @@ var handleView2 = async (ctx, { flags, args }) => {
27990
28051
  maxUpdates: ctx.maxUpdates,
27991
28052
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
27992
28053
  functionLogs: ctx.functionLogMode,
28054
+ profile: ctx.profile,
27993
28055
  signal: ctx.signal
27994
28056
  });
27995
28057
  return;
@@ -28118,6 +28180,7 @@ var handleHistory2 = async (ctx, { flags, args }) => {
28118
28180
  maxUpdates: ctx.maxUpdates,
28119
28181
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
28120
28182
  functionLogs: ctx.functionLogMode,
28183
+ profile: ctx.profile,
28121
28184
  signal: ctx.signal
28122
28185
  });
28123
28186
  return;
@@ -28261,6 +28324,7 @@ var handleList = async (ctx, { flags, args }) => {
28261
28324
  maxUpdates: ctx.maxUpdates,
28262
28325
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
28263
28326
  functionLogs: ctx.functionLogMode,
28327
+ profile: ctx.profile,
28264
28328
  signal: ctx.signal
28265
28329
  });
28266
28330
  return;
@@ -28299,6 +28363,7 @@ var handleList = async (ctx, { flags, args }) => {
28299
28363
  maxUpdates: ctx.maxUpdates,
28300
28364
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
28301
28365
  functionLogs: ctx.functionLogMode,
28366
+ profile: ctx.profile,
28302
28367
  signal: ctx.signal
28303
28368
  });
28304
28369
  return;
@@ -29397,7 +29462,7 @@ function ndjsonMessage(msg) {
29397
29462
  return `${JSON.stringify(msg)}
29398
29463
  `;
29399
29464
  }
29400
- function createMessageReader(input, onMessage) {
29465
+ function createMessageReader(input, onMessage, onError = () => {}) {
29401
29466
  let buffer = "";
29402
29467
  let mode = null;
29403
29468
  function drain() {
@@ -29420,9 +29485,12 @@ function createMessageReader(input, onMessage) {
29420
29485
  continue;
29421
29486
  }
29422
29487
  } else {
29423
- const idx = buffer.indexOf(HEADER_DELIMITER);
29424
- if (idx !== -1) {
29425
- buffer = buffer.slice(idx + 4);
29488
+ const headerEnd = buffer.indexOf(HEADER_DELIMITER);
29489
+ if (headerEnd !== -1) {
29490
+ const resyncFrom = headerEnd + HEADER_DELIMITER.length;
29491
+ const nextHeaderMatch = /Content-Length:/i.exec(buffer.slice(resyncFrom));
29492
+ const nextHeader = nextHeaderMatch === null ? -1 : resyncFrom + nextHeaderMatch.index;
29493
+ buffer = nextHeader === -1 ? "" : buffer.slice(nextHeader);
29426
29494
  continue;
29427
29495
  }
29428
29496
  }
@@ -29442,12 +29510,14 @@ function createMessageReader(input, onMessage) {
29442
29510
  };
29443
29511
  input.setEncoding("utf8");
29444
29512
  input.on("data", onData);
29513
+ input.on("error", onError);
29445
29514
  if ("resume" in input && typeof input.resume === "function") {
29446
29515
  input.resume();
29447
29516
  }
29448
29517
  return {
29449
29518
  close() {
29450
29519
  input.removeListener("data", onData);
29520
+ input.removeListener("error", onError);
29451
29521
  }
29452
29522
  };
29453
29523
  }
@@ -29457,9 +29527,25 @@ var MCP_PROTOCOL_VERSION2 = "2025-11-25";
29457
29527
  function createChannelServer(opts) {
29458
29528
  let reader = null;
29459
29529
  let resolveReady;
29460
- const onReady = new Promise((resolve) => {
29530
+ let rejectReady;
29531
+ let readySettled = false;
29532
+ const onReady = new Promise((resolve, reject) => {
29461
29533
  resolveReady = resolve;
29534
+ rejectReady = reject;
29462
29535
  });
29536
+ function settleReady() {
29537
+ if (readySettled)
29538
+ return;
29539
+ readySettled = true;
29540
+ resolveReady();
29541
+ }
29542
+ function failReady(error) {
29543
+ if (readySettled)
29544
+ return;
29545
+ readySettled = true;
29546
+ reader?.close();
29547
+ rejectReady(error);
29548
+ }
29463
29549
  function send(msg) {
29464
29550
  opts.output.write(ndjsonMessage(msg));
29465
29551
  }
@@ -29482,7 +29568,7 @@ function createChannelServer(opts) {
29482
29568
  return;
29483
29569
  }
29484
29570
  if (method === "notifications/initialized") {
29485
- resolveReady();
29571
+ settleReady();
29486
29572
  return;
29487
29573
  }
29488
29574
  if (method === "ping") {
@@ -29499,7 +29585,7 @@ function createChannelServer(opts) {
29499
29585
  }
29500
29586
  return {
29501
29587
  start() {
29502
- reader = createMessageReader(opts.input, handleMessage);
29588
+ reader = createMessageReader(opts.input, handleMessage, failReady);
29503
29589
  },
29504
29590
  notify(content, meta) {
29505
29591
  send({
@@ -29511,6 +29597,7 @@ function createChannelServer(opts) {
29511
29597
  onReady,
29512
29598
  close() {
29513
29599
  reader?.close();
29600
+ settleReady();
29514
29601
  }
29515
29602
  };
29516
29603
  }
@@ -29573,7 +29660,16 @@ var handleChannel = async (ctx) => {
29573
29660
  else
29574
29661
  signal.addEventListener("abort", () => resolve("aborted"), { once: true });
29575
29662
  });
29576
- const ready = await Promise.race([server.onReady, aborted]);
29663
+ let ready;
29664
+ try {
29665
+ ready = await Promise.race([server.onReady.then(() => {
29666
+ return;
29667
+ }), aborted]);
29668
+ } catch (err) {
29669
+ server.close();
29670
+ const msg = err instanceof Error ? err.message : String(err);
29671
+ throw new CliError(4 /* Backend */, "BACKEND", `channel startup failed: ${msg}`);
29672
+ }
29577
29673
  if (ready === "aborted") {
29578
29674
  server.close();
29579
29675
  return;
@@ -30949,13 +31045,16 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
30949
31045
  const components = {};
30950
31046
  let detailReadFailures = 0;
30951
31047
  for (const item of activeItems) {
31048
+ if (!item.ref)
31049
+ continue;
31050
+ const itemRef = item.ref;
30952
31051
  let detail;
30953
31052
  try {
30954
- detail = await client.component.get(parsed.org, parsed.repo, item.componentId);
31053
+ detail = await client.component.get(parsed.org, parsed.repo, itemRef);
30955
31054
  } catch {
30956
31055
  detailReadFailures++;
30957
31056
  const previousEntry = previousCache?.components[item.componentName];
30958
- if (previousEntry?.componentId === item.componentId) {
31057
+ if (previousEntry?.ref === itemRef) {
30959
31058
  components[item.componentName] = previousEntry;
30960
31059
  }
30961
31060
  continue;
@@ -30970,7 +31069,7 @@ async function refreshFromSummaries(repoSlug, parsed, activeItems, client, now,
30970
31069
  if (!ref)
30971
31070
  continue;
30972
31071
  components[item.componentName] = {
30973
- componentId: item.componentId,
31072
+ ref: itemRef,
30974
31073
  ownerOrgName: ref.ownerOrgName,
30975
31074
  registeredComponentName: ref.registeredComponentName,
30976
31075
  version: manifest.component.version ?? item.version ?? "",
@@ -31330,7 +31429,7 @@ var handleComponentExec = async (ctx, { args, terminator }) => {
31330
31429
  }
31331
31430
  const method = entry.methods.find((m) => m.name === methodName);
31332
31431
  if (!method) {
31333
- 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.`);
31432
+ 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.`);
31334
31433
  }
31335
31434
  if (helpRequested) {
31336
31435
  renderMethodHelp(ctx, componentName, method);
@@ -31439,7 +31538,7 @@ async function ensureSharedInfra(client, org, repo) {
31439
31538
  name: shape.name,
31440
31539
  data: { fields: shape.fields }
31441
31540
  }
31442
- ], { componentId: SYSTEM_COMPONENT_ID });
31541
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31443
31542
  } catch (err) {
31444
31543
  if (!isAlreadyExistsError(err)) {
31445
31544
  throw err;
@@ -31452,7 +31551,7 @@ async function ensureSharedInfra(client, org, repo) {
31452
31551
  name: shape.name,
31453
31552
  data: { fields: shape.fields }
31454
31553
  }
31455
- ], { componentId: SYSTEM_COMPONENT_ID });
31554
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31456
31555
  } catch {}
31457
31556
  }
31458
31557
  }
@@ -31485,6 +31584,15 @@ async function doctorComponent(client, org, repo, componentId) {
31485
31584
  };
31486
31585
  }
31487
31586
  const componentName = typeof installData.name === "string" ? installData.name : componentId;
31587
+ const registeredComponentRef = typeof installData.registeredComponentRef === "string" && installData.registeredComponentRef.length > 0 ? installData.registeredComponentRef : undefined;
31588
+ if (!registeredComponentRef) {
31589
+ findings.push({
31590
+ resource: "ComponentInstall",
31591
+ status: "error",
31592
+ message: "Install record is missing registeredComponentRef"
31593
+ });
31594
+ return { componentId, componentName, state: "error", findings };
31595
+ }
31488
31596
  const existingState = typeof installData.state === "string" ? installData.state : undefined;
31489
31597
  if (existingState === "error") {
31490
31598
  findings.push({
@@ -31523,12 +31631,12 @@ async function doctorComponent(client, org, repo, componentId) {
31523
31631
  message: `Shape "${shape.name}" exists but is inactive`
31524
31632
  });
31525
31633
  } else {
31526
- const shapeComponentId = s && typeof s === "object" && "componentId" in s ? s.componentId : undefined;
31527
- if (shapeComponentId !== undefined && shapeComponentId !== componentId) {
31634
+ const shapeComponentRef = s && typeof s === "object" && "componentRef" in s ? s.componentRef : undefined;
31635
+ if (shapeComponentRef !== undefined && shapeComponentRef !== registeredComponentRef) {
31528
31636
  findings.push({
31529
31637
  resource: `shape:${shape.name}`,
31530
31638
  status: "warning",
31531
- message: `Shape "${shape.name}" exists but is owned by "${shapeComponentId}"`
31639
+ message: `Shape "${shape.name}" exists but is owned by "${shapeComponentRef}"`
31532
31640
  });
31533
31641
  } else {
31534
31642
  const expectedShapeData = manifestShapeData(shape);
@@ -31562,19 +31670,19 @@ async function doctorComponent(client, org, repo, componentId) {
31562
31670
  hasSubs = true;
31563
31671
  try {
31564
31672
  const s = await client.subscription.get(org, repo, sub.name);
31565
- const subComponentId = s && typeof s === "object" && "componentId" in s ? s.componentId : undefined;
31566
- if (!s.active) {
31673
+ const subComponentRef = s && typeof s === "object" && "componentRef" in s ? s.componentRef : undefined;
31674
+ if (subComponentRef !== undefined && subComponentRef !== registeredComponentRef) {
31675
+ allSubsPaused = false;
31567
31676
  findings.push({
31568
31677
  resource: `sub:${sub.name}`,
31569
- status: "inactive",
31570
- message: `Subscription "${sub.name}" is paused`
31678
+ status: "warning",
31679
+ message: `Subscription "${sub.name}" is owned by "${subComponentRef}"`
31571
31680
  });
31572
- } else if (subComponentId !== undefined && subComponentId !== componentId) {
31573
- allSubsPaused = false;
31681
+ } else if (!s.active) {
31574
31682
  findings.push({
31575
31683
  resource: `sub:${sub.name}`,
31576
- status: "warning",
31577
- message: `Subscription "${sub.name}" is owned by "${subComponentId}"`
31684
+ status: "inactive",
31685
+ message: `Subscription "${sub.name}" is paused`
31578
31686
  });
31579
31687
  } else {
31580
31688
  allSubsPaused = false;
@@ -31644,10 +31752,11 @@ async function doctorComponent(client, org, repo, componentId) {
31644
31752
  const hasMissing = findings.some((f) => f.status === "missing");
31645
31753
  const hasInactive = findings.some((f) => f.status === "inactive" && !f.resource.startsWith("sub:"));
31646
31754
  const hasShapeDrift = findings.some((f) => f.resource.startsWith("shape:") && f.status === "warning" && f.message.includes("differs from installed manifest"));
31755
+ const hasOwnershipConflict = findings.some((f) => (f.resource.startsWith("shape:") || f.resource.startsWith("sub:")) && f.status === "warning" && f.message.includes("owned by"));
31647
31756
  let state;
31648
- if (hasSubs && allSubsPaused && !hasMissing && !hasInactive && !hasShapeDrift) {
31757
+ if (hasSubs && allSubsPaused && !hasMissing && !hasInactive && !hasShapeDrift && !hasOwnershipConflict) {
31649
31758
  state = "paused";
31650
- } else if (hasMissing || hasInactive || hasShapeDrift) {
31759
+ } else if (hasMissing || hasInactive || hasShapeDrift || hasOwnershipConflict) {
31651
31760
  state = "degraded";
31652
31761
  } else {
31653
31762
  state = "ready";
@@ -31660,7 +31769,7 @@ async function doctorComponent(client, org, repo, componentId) {
31660
31769
  name: `ComponentInstall/${componentId}`,
31661
31770
  data: { ...installData, state, checkedAt: new Date().toISOString() }
31662
31771
  }
31663
- ], { componentId: SYSTEM_COMPONENT_ID });
31772
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31664
31773
  } catch {
31665
31774
  findings.push({
31666
31775
  resource: "state-update",
@@ -31754,6 +31863,22 @@ async function teardownComponent(client, org, repo, componentId) {
31754
31863
  };
31755
31864
  }
31756
31865
  const componentName = typeof installData.name === "string" ? installData.name : componentId;
31866
+ const registeredComponentRef = typeof installData.registeredComponentRef === "string" && installData.registeredComponentRef.length > 0 ? installData.registeredComponentRef : undefined;
31867
+ if (!registeredComponentRef) {
31868
+ return {
31869
+ componentId,
31870
+ componentName,
31871
+ state: "error",
31872
+ steps: [
31873
+ {
31874
+ step: "load-install",
31875
+ status: "error",
31876
+ message: "Install record is missing registeredComponentRef"
31877
+ }
31878
+ ],
31879
+ errors: ["Install record is missing registeredComponentRef"]
31880
+ };
31881
+ }
31757
31882
  let subscriptionNames = [];
31758
31883
  let teardownPolicy = {};
31759
31884
  try {
@@ -31776,9 +31901,9 @@ async function teardownComponent(client, org, repo, componentId) {
31776
31901
  for (const subName of subscriptionNames) {
31777
31902
  try {
31778
31903
  const sub = await client.subscription.get(org, repo, subName);
31779
- const ownerComponentId = sub && typeof sub === "object" && "componentId" in sub ? sub.componentId : undefined;
31780
- if (typeof ownerComponentId === "string" && ownerComponentId !== componentId) {
31781
- const msg = `Subscription "${subName}" is owned by "${ownerComponentId}", not "${componentId}"`;
31904
+ const ownerComponentRef = sub && typeof sub === "object" && "componentRef" in sub ? sub.componentRef : undefined;
31905
+ if (typeof ownerComponentRef === "string" && ownerComponentRef !== registeredComponentRef) {
31906
+ const msg = `Subscription "${subName}" is owned by "${ownerComponentRef}", not "${registeredComponentRef}"`;
31782
31907
  errors.push(msg);
31783
31908
  steps.push({
31784
31909
  step: `pause-${subName}`,
@@ -31827,7 +31952,7 @@ async function teardownComponent(client, org, repo, componentId) {
31827
31952
  updatedAt: new Date().toISOString()
31828
31953
  }
31829
31954
  }
31830
- ], { componentId: SYSTEM_COMPONENT_ID });
31955
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
31831
31956
  steps.push({ step: "update-state", status: "ok" });
31832
31957
  } catch (err) {
31833
31958
  const msg = err instanceof Error ? err.message : String(err);
@@ -32049,38 +32174,11 @@ function componentInstallCanonicalId(item) {
32049
32174
  const data = asRecord(item.data);
32050
32175
  return componentInstallIdFromWref(item.wref) ?? readString(data, "id") ?? readString(data, "componentId") ?? item.name;
32051
32176
  }
32052
- function uniqueStrings(values) {
32053
- return [...new Set(values.filter((value) => Boolean(value)))];
32177
+ function componentInstallHasRegisteredRef(item, ref) {
32178
+ return readString(asRecord(item.data), "registeredComponentRef") === ref;
32054
32179
  }
32055
- function componentInstallIdentityIds(item) {
32056
- const data = asRecord(item.data);
32057
- return uniqueStrings([
32058
- componentInstallCanonicalId(item),
32059
- readString(data, "id"),
32060
- readString(data, "componentId"),
32061
- item.name
32062
- ]);
32063
- }
32064
- function componentInstallHasExactId(item, name) {
32065
- return componentInstallIdentityIds(item).includes(name);
32066
- }
32067
- function componentInstallHasDisplayName(item, name) {
32068
- return readString(asRecord(item.data), "name") === name;
32069
- }
32070
- function formatComponentInstallAmbiguity(name, matches) {
32071
- const componentIds = uniqueStrings(matches.map((item) => componentInstallCanonicalId(item)));
32072
- const listedIds = componentIds.map((id) => `- ${id}`).join(`
32073
- `);
32074
- const exampleId = componentIds[0] ?? name;
32075
- return {
32076
- message: `Component name "${name}" is ambiguous. It matches multiple installed components:
32077
- ${listedIds}`,
32078
- hint: `Use a component id instead, for example: wh component doctor ${exampleId}`
32079
- };
32080
- }
32081
- async function resolveComponentDoctorId(client, org, repo, name) {
32180
+ async function resolveInstalledComponentRefId(client, org, repo, ref) {
32082
32181
  let cursor;
32083
- const displayNameMatches = [];
32084
32182
  do {
32085
32183
  const result = await client.thing.head(org, repo, {
32086
32184
  shape: "ComponentInstall",
@@ -32089,35 +32187,27 @@ async function resolveComponentDoctorId(client, org, repo, name) {
32089
32187
  cursor
32090
32188
  });
32091
32189
  const items = result.items ?? [];
32092
- const exactMatch = items.find((item) => componentInstallHasExactId(item, name));
32190
+ const exactMatch = items.find((item) => componentInstallHasRegisteredRef(item, ref));
32093
32191
  const resolved = exactMatch ? componentInstallCanonicalId(exactMatch) : undefined;
32094
32192
  if (resolved) {
32095
32193
  return resolved;
32096
32194
  }
32097
- displayNameMatches.push(...items.filter((item) => componentInstallHasDisplayName(item, name)));
32098
32195
  cursor = result.nextCursor;
32099
32196
  } while (cursor);
32100
- if (displayNameMatches.length === 1) {
32101
- return componentInstallCanonicalId(displayNameMatches[0]) ?? name;
32102
- }
32103
- if (displayNameMatches.length > 1) {
32104
- const { message, hint } = formatComponentInstallAmbiguity(name, displayNameMatches);
32105
- throw new CliError(2 /* UserInput */, "USER_INPUT", message, undefined, hint);
32106
- }
32107
- return name;
32197
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${ref}' is not installed. Run 'wh component install <org>/<name>' first.`);
32108
32198
  }
32109
32199
  var handleUpdate = async (ctx, { args }) => {
32110
- const name = args[0];
32111
- if (!name) {
32112
- usageError("Usage: wh component update <name> --repo org/repo", "wh component update research-knowledge --repo org/repo");
32200
+ const ref = args[0];
32201
+ const usage = "Usage: wh component update <org/name> --repo org/repo";
32202
+ const example = "wh component update warmhub/research-knowledge --repo org/repo";
32203
+ if (!ref) {
32204
+ usageError(usage, example);
32113
32205
  }
32114
- const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32115
- try {
32116
- await ctx.client.thing.get(org, repo, `ComponentInstall/${name}`);
32117
- } catch {
32118
- throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${name}' is not installed. Run 'wh component install <org>/<name>' first.`);
32206
+ resolveRegisteredComponentRef(ref, usage, example);
32207
+ if (ctx.liveMode === false) {
32208
+ usageError("Dry-run is not supported for component update.", "wh component update warmhub/research-knowledge --repo org/repo");
32119
32209
  }
32120
- 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>`.");
32210
+ 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.");
32121
32211
  };
32122
32212
  var handleRegister = async (ctx, { flags, args }) => {
32123
32213
  const componentName = args[0];
@@ -32210,8 +32300,7 @@ var handleRegistryUpdate = async (ctx, { flags, args }) => {
32210
32300
  };
32211
32301
  var handleInstall = async (ctx, { args }) => {
32212
32302
  const source = args[0];
32213
- const usage = `Usage: wh component install <source> --repo org/repo
32214
- source: <org>/<name> (registered component)`;
32303
+ const usage = "Usage: wh component install <org/name> --repo org/repo";
32215
32304
  const example = "wh component install warmhub/veritas --repo myorg/myrepo";
32216
32305
  if (!source) {
32217
32306
  usageError(usage, example);
@@ -32256,7 +32345,7 @@ var handleList2 = async (ctx, { flags }) => {
32256
32345
  const state = item.state ?? "unknown";
32257
32346
  const source = item.source ?? "-";
32258
32347
  const stateColor = stateToColor(c, state);
32259
- ctx.out(` ${c.cyan}${item.componentId}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32348
+ ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32260
32349
  }
32261
32350
  });
32262
32351
  };
@@ -32269,7 +32358,7 @@ var handleSearch2 = async (ctx, { flags, args }) => {
32269
32358
  const c = ctx.colors;
32270
32359
  const { items: allItems, nextCursor } = await fetchComponentPages(ctx.client, org, repo, { all: flags.all, limit: flags.limit, cursor: flags.cursor });
32271
32360
  const needle = query.toLowerCase();
32272
- const items = allItems.filter((item) => [item.componentId, item.componentName, item.source].filter((value) => typeof value === "string").some((value) => value.toLowerCase().includes(needle)));
32361
+ const items = allItems.filter((item) => [item.ref, item.componentName, item.source].filter((value) => typeof value === "string").some((value) => value.toLowerCase().includes(needle)));
32273
32362
  if (!flags.all && nextCursor) {
32274
32363
  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.`);
32275
32364
  }
@@ -32285,22 +32374,22 @@ var handleSearch2 = async (ctx, { flags, args }) => {
32285
32374
  const state = item.state ?? "unknown";
32286
32375
  const source = item.source ?? "-";
32287
32376
  const stateColor = stateToColor(c, state);
32288
- ctx.out(` ${c.cyan}${item.componentId}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32377
+ ctx.out(` ${c.cyan}${item.ref ?? item.componentName}${c.reset} ${stateColor}${state}${c.reset} ${c.dim}v${version}${c.reset} ${source}`);
32289
32378
  }
32290
32379
  });
32291
32380
  };
32292
32381
  var handleView3 = async (ctx, { args }) => {
32293
- const name = args[0];
32294
- const usage = "Usage: wh component view <name> --repo org/repo";
32295
- const example = "wh component view research-knowledge --repo myorg/myrepo";
32296
- if (!name) {
32382
+ const ref = args[0];
32383
+ const usage = "Usage: wh component view <org/name> --repo org/repo";
32384
+ const example = "wh component view myorg/research-knowledge --repo myorg/myrepo";
32385
+ if (!ref) {
32297
32386
  usageError(usage, example);
32298
32387
  }
32299
32388
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32300
- const viewData = await ctx.client.component.get(org, repo, name);
32389
+ const viewData = await ctx.client.component.get(org, repo, ref);
32301
32390
  writeOutput(ctx, viewData, () => {
32302
32391
  const c = ctx.colors;
32303
- ctx.out(`${c.bold}Component:${c.reset} ${c.cyan}${name}${c.reset}`);
32392
+ ctx.out(`${c.bold}Component:${c.reset} ${c.cyan}${viewData.ref ?? ref}${c.reset}`);
32304
32393
  ctx.out(`${c.bold}Version:${c.reset} ${viewData.version ?? "unknown"}`);
32305
32394
  ctx.out(`${c.bold}State:${c.reset} ${viewData.state ?? "-"}`);
32306
32395
  ctx.out(`${c.bold}Source:${c.reset} ${viewData.source ?? "-"}`);
@@ -32376,23 +32465,24 @@ function renderValidationResult(ctx, result) {
32376
32465
  var handleDoctor = async (ctx, { args }) => {
32377
32466
  const name = args[0];
32378
32467
  if (!name) {
32379
- usageError("Usage: wh component doctor <name> --repo org/repo", "wh component doctor research-knowledge --repo myorg/myrepo");
32468
+ usageError("Usage: wh component doctor <org/name> --repo org/repo", "wh component doctor warmhub/research-knowledge --repo myorg/myrepo");
32380
32469
  }
32381
32470
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32382
- const componentId = await resolveComponentDoctorId(ctx.client, org, repo, name);
32471
+ const componentId = await resolveInstalledComponentRefId(ctx.client, org, repo, name);
32383
32472
  const result = await doctorComponent(ctx.client, org, repo, componentId);
32384
32473
  writeOutput(ctx, result, () => renderDoctorResult(ctx, result));
32385
32474
  };
32386
32475
  var handleTeardown = async (ctx, { args }) => {
32387
32476
  const name = args[0];
32388
32477
  if (!name) {
32389
- usageError("Usage: wh component teardown <name> --repo org/repo", "wh component teardown research-knowledge --repo myorg/myrepo");
32478
+ usageError("Usage: wh component teardown <org/name> --repo org/repo", "wh component teardown warmhub/research-knowledge --repo myorg/myrepo");
32390
32479
  }
32391
32480
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
32392
32481
  const repoSlug = `${org}/${repo}`;
32482
+ const componentId = await resolveInstalledComponentRefId(ctx.client, org, repo, name);
32393
32483
  let result;
32394
32484
  try {
32395
- result = await teardownComponent(ctx.client, org, repo, name);
32485
+ result = await teardownComponent(ctx.client, org, repo, componentId);
32396
32486
  } catch (error) {
32397
32487
  invalidateInstallSnapshotCache(repoSlug);
32398
32488
  throw error;
@@ -32523,7 +32613,7 @@ var COMPONENT_DOMAIN = defineDomain({
32523
32613
  install: {
32524
32614
  prime: true,
32525
32615
  summary: "Install a registered component by its <org>/<name> ref",
32526
- args: "<source>",
32616
+ args: "<org/name>",
32527
32617
  flags: installFlags,
32528
32618
  examples: [
32529
32619
  "wh component install warmhub/identity --repo org/repo",
@@ -32533,9 +32623,9 @@ var COMPONENT_DOMAIN = defineDomain({
32533
32623
  },
32534
32624
  update: {
32535
32625
  summary: "Update an installed registered component to the latest manifest",
32536
- args: "<name>",
32626
+ args: "<org/name>",
32537
32627
  flags: updateFlags,
32538
- examples: ["wh component update research-knowledge --repo org/repo"],
32628
+ examples: ["wh component update warmhub/identity --repo org/repo"],
32539
32629
  handler: handleUpdate
32540
32630
  },
32541
32631
  list: {
@@ -32549,25 +32639,25 @@ var COMPONENT_DOMAIN = defineDomain({
32549
32639
  view: {
32550
32640
  prime: true,
32551
32641
  summary: "Show component details",
32552
- args: "<name>",
32642
+ args: "<org/name>",
32553
32643
  flags: viewFlags3,
32554
- examples: ["wh component view research-knowledge --repo org/repo"],
32644
+ examples: ["wh component view warmhub/identity --repo org/repo"],
32555
32645
  handler: handleView3
32556
32646
  },
32557
32647
  teardown: {
32558
32648
  prime: true,
32559
32649
  summary: "Pause component subscriptions",
32560
- args: "<name>",
32650
+ args: "<org/name>",
32561
32651
  flags: teardownFlags,
32562
- examples: ["wh component teardown research-knowledge --repo org/repo"],
32652
+ examples: ["wh component teardown warmhub/identity --repo org/repo"],
32563
32653
  handler: handleTeardown
32564
32654
  },
32565
32655
  doctor: {
32566
32656
  prime: true,
32567
32657
  summary: "Run component health checks",
32568
- args: "<name>",
32658
+ args: "<org/name>",
32569
32659
  flags: doctorFlags,
32570
- examples: ["wh component doctor research-knowledge --repo org/repo"],
32660
+ examples: ["wh component doctor warmhub/identity --repo org/repo"],
32571
32661
  handler: handleDoctor
32572
32662
  },
32573
32663
  init: {
@@ -33015,7 +33105,7 @@ import { basename } from "node:path";
33015
33105
  // ../../packages/warmhub-cli/src/harness.ts
33016
33106
  import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
33017
33107
  import { homedir as homedir4 } from "node:os";
33018
- import { dirname as dirname6, join as join6 } from "node:path";
33108
+ import { dirname as dirname6, join as join5 } from "node:path";
33019
33109
  var AGENTS_BEGIN_MARKER = "<!-- BEGIN WARMHUB CLI INTEGRATION -->";
33020
33110
  var AGENTS_END_MARKER = "<!-- END WARMHUB CLI INTEGRATION -->";
33021
33111
  var PRIME_COMMAND = "wh prime";
@@ -33035,10 +33125,10 @@ function getHarnessPaths(opts) {
33035
33125
  const userHome = opts?.homeDir ?? homedir4();
33036
33126
  return {
33037
33127
  repoDir,
33038
- agentsPath: join6(repoDir, "AGENTS.md"),
33039
- projectSettingsPath: join6(repoDir, ".claude", "settings.json"),
33040
- projectLocalSettingsPath: join6(repoDir, ".claude", "settings.local.json"),
33041
- globalSettingsPath: join6(userHome, ".claude", "settings.json")
33128
+ agentsPath: join5(repoDir, "AGENTS.md"),
33129
+ projectSettingsPath: join5(repoDir, ".claude", "settings.json"),
33130
+ projectLocalSettingsPath: join5(repoDir, ".claude", "settings.local.json"),
33131
+ globalSettingsPath: join5(userHome, ".claude", "settings.json")
33042
33132
  };
33043
33133
  }
33044
33134
  async function readJsonFile(path2) {
@@ -34439,17 +34529,18 @@ cat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped
34439
34529
  - \`wh credential revoke <setName> [--repo org/repo | --org org] [--reason]\` — Revoke a credential set (blocks new binds and strips auth from existing webhook deliveries)
34440
34530
 
34441
34531
  ### component — Component management
34442
- - \`wh component validate <path>\` — Validate a component package from disk
34443
- - \`wh component install <source>\` — Install a component from a bundled system id or a registered \`<org>/<name>\`
34444
- - \`wh component register <name> --org <org> --manifest <path> [flags]\` — Register a component identity (first manifest version) for \`install <org/name>\`
34532
+ - \`wh component validate <path>\` — Validate package
34533
+ - \`wh component install <org/name>\` — Install a registered component
34534
+ - \`wh component register <name> --org <org> --manifest <path> [flags]\` — Register component identity
34445
34535
  - \`wh component unregister <org/name>\` — Remove a registered component identity
34446
34536
  - \`wh component registry list --org <org>\` — List registered components
34447
34537
  - \`wh component registry view <org/name>\` — View a registered component
34448
34538
  - \`wh component registry update <org/name> [flags]\` — Update a registered component
34449
34539
  - \`wh component list\` — List installed components
34450
- - \`wh component view <name>\` — Show component details (alias: show)
34451
- - \`wh component doctor <name>\` — Run component health checks
34452
- - \`wh component teardown <name>\` — Pause component subscriptions
34540
+ - \`wh component update <org/name>\` — Update installed component
34541
+ - \`wh component view <org/name>\` — Show component details (alias: show)
34542
+ - \`wh component doctor <org/name>\` — Run component health checks
34543
+ - \`wh component teardown <org/name>\` — Pause component subscriptions
34453
34544
 
34454
34545
  ### Getting More Info
34455
34546
  - \`wh help\` — full help overview
@@ -35461,7 +35552,7 @@ var FIELD_CONSTRAINTS_NOTES = [
35461
35552
  var listFlags4 = {
35462
35553
  match: flag.string({ description: "Filter by name glob pattern" }),
35463
35554
  component: flag.string({
35464
- description: "Filter to shapes owned by this component ID"
35555
+ description: "Filter to shapes owned by this component (Org/Name ref)"
35465
35556
  }),
35466
35557
  "exclude-components": flag.boolean({
35467
35558
  description: "Exclude component-owned shapes from results"
@@ -35474,13 +35565,13 @@ var handleList6 = async (ctx, { flags }) => {
35474
35565
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
35475
35566
  const c = ctx.colors;
35476
35567
  const match = flags.match;
35477
- const componentId = flags.component;
35568
+ const componentRef = flags.component;
35478
35569
  const excludeComponents = !!flags["exclude-components"];
35479
35570
  const includeRetracted = flags["include-retracted"];
35480
- validateComponentFilters(componentId, excludeComponents, "wh shape list --component com.example.pkg", "wh shape list --exclude-components");
35571
+ validateComponentFilters(componentRef, excludeComponents, "wh shape list --component acme/veritas", "wh shape list --exclude-components");
35481
35572
  const result = await ctx.client.shape.list(org, repo, {
35482
35573
  match,
35483
- componentId,
35574
+ componentRef,
35484
35575
  excludeComponents,
35485
35576
  includeRetracted
35486
35577
  });
@@ -35547,9 +35638,9 @@ var handleView7 = async (ctx, { flags, args }) => {
35547
35638
  if (typeof shapeDescription === "string" && shapeDescription) {
35548
35639
  ctx.out(` ${c.dim}${shapeDescription}${c.reset}`);
35549
35640
  }
35550
- const cid = result.componentId;
35551
- if (cid) {
35552
- ctx.out(` ${c.dim}owner:${c.reset} ${c.yellow}${cid}${c.reset}`);
35641
+ const componentRef = result.componentRef;
35642
+ if (componentRef) {
35643
+ ctx.out(` ${c.dim}owner:${c.reset} ${c.yellow}${componentRef}${c.reset}`);
35553
35644
  }
35554
35645
  const fields = shapeData?.fields;
35555
35646
  if (fields) {
@@ -35694,6 +35785,7 @@ var handleHistory3 = async (ctx, { flags, args }) => {
35694
35785
  maxUpdates: ctx.maxUpdates,
35695
35786
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
35696
35787
  functionLogs: ctx.functionLogMode,
35788
+ profile: ctx.profile,
35697
35789
  signal: ctx.signal
35698
35790
  });
35699
35791
  return;
@@ -36008,6 +36100,11 @@ var logFlags = {
36008
36100
  var listFlags5 = {
36009
36101
  limit: flag.number({ description: "Max subscriptions to return" })
36010
36102
  };
36103
+ var viewFlags5 = {
36104
+ "show-secrets": flag.boolean({
36105
+ description: "Reveal the raw webhook URL(s) instead of the redacted origin (audit-logged)"
36106
+ })
36107
+ };
36011
36108
  function buildSubscriptionPatchArgs(flags, usage, example) {
36012
36109
  const args = {};
36013
36110
  if (typeof flags.on === "string" && flags.on) {
@@ -36121,14 +36218,15 @@ var handleUpdate4 = async (ctx, { flags, args }) => {
36121
36218
  ctx.status(`${c.green}Updated subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset}`);
36122
36219
  });
36123
36220
  };
36124
- var handleView8 = async (ctx, { args }) => {
36221
+ var handleView8 = async (ctx, { args, flags }) => {
36125
36222
  const name = args[0];
36126
36223
  if (!name) {
36127
- usageError("Usage: wh sub view <name> [--repo org/repo]", "wh sub view signal-hook --repo myorg/myrepo");
36224
+ usageError("Usage: wh sub view <name> [--show-secrets] [--repo org/repo]", "wh sub view signal-hook --repo myorg/myrepo");
36128
36225
  }
36129
36226
  const { org, repo } = resolveRepoContext(ctx);
36130
36227
  const sub = await ctx.client.subscription.get(org, repo, name);
36131
- writeOutput(ctx, sub, () => {
36228
+ const revealed = flags["show-secrets"] ? await ctx.client.subscription.reveal(org, repo, name) : undefined;
36229
+ writeOutput(ctx, revealed ? { ...sub, ...revealed } : sub, () => {
36132
36230
  const c = ctx.colors;
36133
36231
  ctx.out(`${c.bold}${sub.name}${c.reset}`);
36134
36232
  ctx.out(` kind: ${c.cyan}${sub.kind}${c.reset}`);
@@ -36139,12 +36237,15 @@ var handleView8 = async (ctx, { args }) => {
36139
36237
  if (sub.allowTraceReentry) {
36140
36238
  ctx.out(` allowTraceReentry: ${c.green}${sub.allowTraceReentry}${c.reset}`);
36141
36239
  }
36142
- if (sub.webhookUrl) {
36143
- ctx.out(` webhookUrl: ${sub.webhookUrl}`);
36144
- }
36145
- if (sub.fallbackWebhookUrl) {
36146
- ctx.out(` fallbackWebhookUrl: ${sub.fallbackWebhookUrl}`);
36147
- }
36240
+ const renderHook = (rawLabel, originLabel, raw, origin) => {
36241
+ if (raw) {
36242
+ ctx.out(` ${rawLabel}: ${raw}`);
36243
+ } else if (origin) {
36244
+ ctx.out(` ${originLabel}: ${origin}${c.dim}/***${c.reset}`);
36245
+ }
36246
+ };
36247
+ renderHook("webhookUrl", "webhookOrigin", revealed?.webhookUrl, sub.webhookOrigin);
36248
+ renderHook("fallbackWebhookUrl", "fallbackWebhookOrigin", revealed?.fallbackWebhookUrl, sub.fallbackWebhookOrigin);
36148
36249
  if (sub.actionContainer) {
36149
36250
  ctx.out(` action container: ${c.cyan}${sub.actionContainer}${c.reset}`);
36150
36251
  }
@@ -36256,6 +36357,7 @@ var handleLog = async (ctx, { flags, args }) => {
36256
36357
  maxUpdates: ctx.maxUpdates,
36257
36358
  inactivityTimeoutMs: ctx.inactivityTimeoutMs,
36258
36359
  functionLogs: ctx.functionLogMode,
36360
+ profile: ctx.profile,
36259
36361
  signal: ctx.signal
36260
36362
  });
36261
36363
  return;
@@ -36340,7 +36442,11 @@ var SUB_DOMAIN = defineDomain({
36340
36442
  prime: true,
36341
36443
  summary: "View subscription details",
36342
36444
  args: "<name>",
36343
- examples: ["wh sub view signal-hook --repo myorg/myrepo"],
36445
+ flags: viewFlags5,
36446
+ examples: [
36447
+ "wh sub view signal-hook --repo myorg/myrepo",
36448
+ "wh sub view signal-hook --show-secrets --repo myorg/myrepo"
36449
+ ],
36344
36450
  handler: handleView8
36345
36451
  },
36346
36452
  list: {
@@ -37834,10 +37940,6 @@ async function dispatch(ctx) {
37834
37940
  const { command } = ctx.invocation;
37835
37941
  if (!command || command === "help") {
37836
37942
  const helpTarget = command === "help" ? ctx.invocation.positional[0] : undefined;
37837
- if (ctx.format === "json") {
37838
- printJson(ctx.out, buildCliSpec());
37839
- return;
37840
- }
37841
37943
  if (helpTarget) {
37842
37944
  const domain = registry.getDomain(helpTarget);
37843
37945
  if (domain) {
@@ -37846,6 +37948,10 @@ async function dispatch(ctx) {
37846
37948
  throw new CliError(2 /* UserInput */, "USER_INPUT", `Unknown command: ${helpTarget}`, undefined, "Run 'wh help' for available commands.");
37847
37949
  }
37848
37950
  } else {
37951
+ if (ctx.format === "json") {
37952
+ printJson(ctx.out, buildCliSpec());
37953
+ return;
37954
+ }
37849
37955
  let repoSlug;
37850
37956
  try {
37851
37957
  const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
@@ -37897,6 +38003,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37897
38003
  const errors = [];
37898
38004
  const { meta, manifest } = pkg;
37899
38005
  const componentId = meta.id;
38006
+ const componentRef = source.registeredComponentRef;
37900
38007
  const validation = validateComponentPackage(pkg);
37901
38008
  if (!validation.valid) {
37902
38009
  const validationErrors = validation.findings.filter((f) => f.level === "error").map((f) => f.message);
@@ -37947,7 +38054,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37947
38054
  const oldCredNames = wasIncomplete ? new Set : new Set(oldManifest?.credentials?.map((c) => c.name) ?? []);
37948
38055
  const liveShapeNames = new Set;
37949
38056
  const liveShapeDataByName = new Map;
37950
- const liveShapeComponentIdByName = new Map;
38057
+ const liveShapeComponentRefByName = new Map;
37951
38058
  for (const shape of reconcileShapes) {
37952
38059
  if (isFailedInstallState || previousState !== "degraded" && !oldShapeNames.has(shape.name)) {
37953
38060
  continue;
@@ -37964,7 +38071,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37964
38071
  includeRetracted: true
37965
38072
  });
37966
38073
  liveShapeDataByName.set(shape.name, liveShape.version?.data);
37967
- liveShapeComponentIdByName.set(shape.name, liveShape.componentId);
38074
+ liveShapeComponentRefByName.set(shape.name, liveShape.componentRef);
37968
38075
  } catch {}
37969
38076
  } catch {}
37970
38077
  }
@@ -37999,7 +38106,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
37999
38106
  data: manifestShapeData(shape)
38000
38107
  }));
38001
38108
  try {
38002
- await client.commit.apply(org, repo, `Add new shapes for ${meta.name}`, shapeOps, { componentId });
38109
+ await client.commit.apply(org, repo, `Add new shapes for ${meta.name}`, shapeOps, { componentRef });
38003
38110
  steps.push({ step: "add-new-shapes", status: "ok" });
38004
38111
  } catch (err) {
38005
38112
  const msg = err instanceof Error ? err.message : String(err);
@@ -38015,8 +38122,8 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38015
38122
  if (!liveShapeNames.has(shape.name))
38016
38123
  return false;
38017
38124
  const liveData = liveShapeDataByName.get(shape.name);
38018
- const liveComponentId = liveShapeComponentIdByName.get(shape.name);
38019
- return liveComponentId !== componentId || !shapeDataEquals(manifestShapeData(shape), liveData);
38125
+ const liveComponentRef = liveShapeComponentRefByName.get(shape.name);
38126
+ return liveComponentRef !== componentRef || !shapeDataEquals(manifestShapeData(shape), liveData);
38020
38127
  });
38021
38128
  if (changedShapes.length > 0) {
38022
38129
  const shapeOps = changedShapes.map((shape) => ({
@@ -38026,7 +38133,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38026
38133
  data: manifestShapeData(shape)
38027
38134
  }));
38028
38135
  try {
38029
- await client.commit.apply(org, repo, `Reconcile shapes for ${meta.name}`, shapeOps, { componentId });
38136
+ await client.commit.apply(org, repo, `Reconcile shapes for ${meta.name}`, shapeOps, { componentRef });
38030
38137
  steps.push({ step: "claim-existing-shapes", status: "ok" });
38031
38138
  } catch (err) {
38032
38139
  const msg = err instanceof Error ? err.message : String(err);
@@ -38092,7 +38199,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38092
38199
  filterJson: compiled.filterJson,
38093
38200
  webhookUrl: compiled.webhookUrl,
38094
38201
  fallbackWebhookUrl: compiled.fallbackWebhookUrl,
38095
- componentId
38202
+ componentRef
38096
38203
  });
38097
38204
  steps.push({ step: `add-sub-${sub.name}`, status: "ok" });
38098
38205
  } catch (err) {
@@ -38131,8 +38238,8 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38131
38238
  }
38132
38239
  try {
38133
38240
  const liveSub = await client.subscription.get(org, repo, sub.name);
38134
- if (liveSub.componentId && liveSub.componentId !== componentId) {
38135
- const msg = `Subscription "${sub.name}" is owned by component "${liveSub.componentId}"`;
38241
+ if (liveSub.componentRef && liveSub.componentRef !== componentRef) {
38242
+ const msg = `Subscription "${sub.name}" is owned by component "${liveSub.componentRef}"`;
38136
38243
  errors.push(msg);
38137
38244
  steps.push({ step: stepName, status: "error", message: msg });
38138
38245
  continue;
@@ -38150,7 +38257,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38150
38257
  filterJson: compiled.filterJson,
38151
38258
  webhookUrl: compiled.webhookUrl,
38152
38259
  fallbackWebhookUrl: compiled.fallbackWebhookUrl,
38153
- componentId
38260
+ componentRef
38154
38261
  });
38155
38262
  } catch (createErr) {
38156
38263
  const createMsg = createErr instanceof Error ? createErr.message : String(createErr);
@@ -38207,7 +38314,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38207
38314
  name: `${seed.shape}/${seed.name}`,
38208
38315
  data: seed.data
38209
38316
  }
38210
- ], { componentId });
38317
+ ], { componentRef });
38211
38318
  } catch (reviseErr) {
38212
38319
  const reviseMsg = reviseErr instanceof Error ? reviseErr.message : String(reviseErr);
38213
38320
  const reviseLooksMissing = reviseMsg.includes("not found") || reviseMsg.includes("NOT_FOUND");
@@ -38223,7 +38330,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38223
38330
  name: `${seed.shape}/${seed.name}`,
38224
38331
  data: seed.data
38225
38332
  }
38226
- ], { componentId });
38333
+ ], { componentRef });
38227
38334
  } catch (addErr) {
38228
38335
  const msg = addErr instanceof Error ? addErr.message : String(addErr);
38229
38336
  if (!isAlreadyExistsError(addErr)) {
@@ -38248,8 +38355,8 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38248
38355
  componentId,
38249
38356
  name: meta.name,
38250
38357
  version: meta.version,
38251
- source: source.githubUrl ?? "local",
38252
- sourceKind: source.sourceKind ?? (source.githubUrl ? "github" : "local"),
38358
+ source: "registry",
38359
+ sourceKind: "registered",
38253
38360
  sourceRef: source.ref ?? "",
38254
38361
  resolvedSha: source.resolvedSha ?? "",
38255
38362
  ...source.registeredComponentRef ? { registeredComponentRef: source.registeredComponentRef } : {},
@@ -38261,7 +38368,7 @@ async function reconcileComponent(client, org, repo, pkg, source, existingInstal
38261
38368
  ...source.installId ?? persistedInstallId ? { installId: source.installId ?? persistedInstallId } : {}
38262
38369
  }
38263
38370
  }
38264
- ], { componentId: SYSTEM_COMPONENT_ID });
38371
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
38265
38372
  steps.push({ step: "update-install-record", status: "ok" });
38266
38373
  } catch (err) {
38267
38374
  const msg = err instanceof Error ? err.message : String(err);
@@ -38376,8 +38483,8 @@ async function installComponent(client, org, repo, pkg, source) {
38376
38483
  componentId,
38377
38484
  name: meta.name,
38378
38485
  version: meta.version,
38379
- source: source.githubUrl ?? "local",
38380
- sourceKind: source.sourceKind ?? (source.githubUrl ? "github" : "local"),
38486
+ source: "registry",
38487
+ sourceKind: "registered",
38381
38488
  sourceRef: source.ref ?? "",
38382
38489
  resolvedSha: source.resolvedSha ?? "",
38383
38490
  ...source.registeredComponentRef ? { registeredComponentRef: source.registeredComponentRef } : {},
@@ -38388,7 +38495,7 @@ async function installComponent(client, org, repo, pkg, source) {
38388
38495
  ...source.installId ? { installId: source.installId } : {}
38389
38496
  }
38390
38497
  }
38391
- ], { componentId: SYSTEM_COMPONENT_ID });
38498
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
38392
38499
  steps.push({ step: "create-install-record", status: "ok" });
38393
38500
  } catch (err) {
38394
38501
  const msg = err instanceof Error ? err.message : String(err);
@@ -38404,13 +38511,13 @@ async function installComponent(client, org, repo, pkg, source) {
38404
38511
  data: manifestShapeData(shape)
38405
38512
  }));
38406
38513
  try {
38407
- await client.commit.apply(org, repo, `Add shapes for ${meta.name}`, shapeOps, { componentId });
38514
+ await client.commit.apply(org, repo, `Add shapes for ${meta.name}`, shapeOps, { componentRef: source.registeredComponentRef });
38408
38515
  steps.push({ step: "create-shapes", status: "ok" });
38409
38516
  } catch (err) {
38410
38517
  const msg = err instanceof Error ? err.message : String(err);
38411
38518
  if (isAlreadyExistsError(err)) {
38412
38519
  try {
38413
- await reconcileShapesAfterCreateConflict(client, org, repo, pkg);
38520
+ await reconcileShapesAfterCreateConflict(client, org, repo, pkg, source);
38414
38521
  steps.push({
38415
38522
  step: "create-shapes",
38416
38523
  status: "ok",
@@ -38487,7 +38594,7 @@ async function installComponent(client, org, repo, pkg, source) {
38487
38594
  filterJson: compiled.filterJson,
38488
38595
  webhookUrl: compiled.webhookUrl,
38489
38596
  fallbackWebhookUrl: compiled.fallbackWebhookUrl,
38490
- componentId
38597
+ componentRef: source.registeredComponentRef
38491
38598
  });
38492
38599
  steps.push({ step: `create-sub-${sub.name}`, status: "ok" });
38493
38600
  } catch (err) {
@@ -38526,7 +38633,7 @@ async function installComponent(client, org, repo, pkg, source) {
38526
38633
  name: seedName,
38527
38634
  data: seed.data
38528
38635
  }
38529
- ], { componentId });
38636
+ ], { componentRef: source.registeredComponentRef });
38530
38637
  steps.push({ step: `seed-${seedName}`, status: "ok" });
38531
38638
  } catch (err) {
38532
38639
  const msg = err instanceof Error ? err.message : String(err);
@@ -38553,8 +38660,8 @@ async function installComponent(client, org, repo, pkg, source) {
38553
38660
  componentId,
38554
38661
  name: meta.name,
38555
38662
  version: meta.version,
38556
- source: source.githubUrl ?? "local",
38557
- sourceKind: source.sourceKind ?? (source.githubUrl ? "github" : "local"),
38663
+ source: "registry",
38664
+ sourceKind: "registered",
38558
38665
  sourceRef: source.ref ?? "",
38559
38666
  resolvedSha: source.resolvedSha ?? "",
38560
38667
  ...source.registeredComponentRef ? { registeredComponentRef: source.registeredComponentRef } : {},
@@ -38566,7 +38673,7 @@ async function installComponent(client, org, repo, pkg, source) {
38566
38673
  ...source.installId ? { installId: source.installId } : {}
38567
38674
  }
38568
38675
  }
38569
- ], { componentId: SYSTEM_COMPONENT_ID });
38676
+ ], { componentRef: SYSTEM_REGISTERED_COMPONENT_REF });
38570
38677
  steps.push({ step: "finalize", status: "ok" });
38571
38678
  } catch (err) {
38572
38679
  const msg = err instanceof Error ? err.message : String(err);
@@ -38584,12 +38691,12 @@ function assertCliMethodsAllowedForSource(pkg, source) {
38584
38691
  const hasCliMethods = (pkg.manifest.cli?.methods?.length ?? 0) > 0;
38585
38692
  if (!hasCliMethods)
38586
38693
  return;
38587
- if (source.sourceKind === "registered" && typeof source.registeredComponentRef === "string" && source.registeredComponentRef.length > 0) {
38694
+ if (typeof source.registeredComponentRef === "string" && source.registeredComponentRef.length > 0) {
38588
38695
  return;
38589
38696
  }
38590
38697
  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.");
38591
38698
  }
38592
- async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38699
+ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg, source) {
38593
38700
  const { meta, manifest } = pkg;
38594
38701
  const existingShapes = new Map;
38595
38702
  for (const shape of manifest.shapes) {
@@ -38597,8 +38704,8 @@ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38597
38704
  const existingShape = await client.shape.get(org, repo, shape.name, {
38598
38705
  includeRetracted: true
38599
38706
  });
38600
- if (existingShape.componentId !== meta.id) {
38601
- const owner = existingShape.componentId ? `owned by component "${existingShape.componentId}"` : "not owned by this component";
38707
+ if (existingShape.componentRef !== source.registeredComponentRef) {
38708
+ const owner = existingShape.componentRef ? `owned by component "${existingShape.componentRef}"` : "not owned by this component";
38602
38709
  throw new Error(`Shape "${shape.name}" already exists and is ${owner}; cannot reconcile during fresh install`);
38603
38710
  }
38604
38711
  existingShapes.set(shape.name, existingShape);
@@ -38620,7 +38727,7 @@ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38620
38727
  name: shape.name,
38621
38728
  data
38622
38729
  }
38623
- ], { componentId: meta.id });
38730
+ ], { componentRef: source.registeredComponentRef });
38624
38731
  continue;
38625
38732
  }
38626
38733
  try {
@@ -38631,7 +38738,7 @@ async function reconcileShapesAfterCreateConflict(client, org, repo, pkg) {
38631
38738
  name: shape.name,
38632
38739
  data
38633
38740
  }
38634
- ], { componentId: meta.id });
38741
+ ], { componentRef: source.registeredComponentRef });
38635
38742
  } catch (err) {
38636
38743
  if (isAlreadyExistsError(err)) {
38637
38744
  throw new Error(`Shape "${shape.name}" already exists but ownership could not be verified; cannot reconcile during fresh install`);
@@ -38906,9 +39013,10 @@ async function runCli(argv, opts) {
38906
39013
  requestedMode: requestedFunctionLogs
38907
39014
  });
38908
39015
  const localOnlyCommand = isLocalOnlyInvocation(invocation);
38909
- const { config, client } = localOnlyCommand ? {
39016
+ const { config, client, profile } = localOnlyCommand ? {
38910
39017
  config: loadConfig(),
38911
- client: createLocalOnlyClient()
39018
+ client: createLocalOnlyClient(),
39019
+ profile: "default"
38912
39020
  } : resolveCliContext({
38913
39021
  invocation,
38914
39022
  format,
@@ -38936,6 +39044,7 @@ async function runCli(argv, opts) {
38936
39044
  client,
38937
39045
  config,
38938
39046
  invocation,
39047
+ profile,
38939
39048
  colors,
38940
39049
  chars,
38941
39050
  format,
@@ -39044,7 +39153,7 @@ function resolveLogLevel(flags, env) {
39044
39153
  // package.json
39045
39154
  var package_default3 = {
39046
39155
  name: "@warmhub/cli",
39047
- version: "0.52.0",
39156
+ version: "0.53.0",
39048
39157
  private: false,
39049
39158
  type: "module",
39050
39159
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -39149,12 +39258,18 @@ async function maybeHandleComponentShellBoundary(argv, deps = {}) {
39149
39258
  const writeOut = deps.out ?? out;
39150
39259
  const writeErr = deps.err ?? err;
39151
39260
  const debug = getBoolFlag(invocation.flags, "debug") || process.env.WARMHUB_DEBUG === "1";
39152
- const formatFlag = getStringFlag(invocation.flags, "format");
39153
- const format = formatFlag === "json" || formatFlag === "jsonl" ? formatFlag : getBoolFlag(invocation.flags, "json") ? "json" : "pretty";
39261
+ let format = "pretty";
39154
39262
  const installFromManifestImpl = deps.installFromManifest ?? installFromManifest;
39155
39263
  const resolveRegisteredInstallImpl = deps.resolveRegisteredInstall ?? resolveRegisteredInstall;
39156
39264
  const callRegisteredSetupImpl = deps.callRegisteredSetup ?? callRegisteredSetup;
39157
39265
  try {
39266
+ canonicalizeGlobalFlags({ invocation });
39267
+ const formatFlag = getStringFlag(invocation.flags, "format");
39268
+ format = formatFlag === "json" || formatFlag === "jsonl" ? formatFlag : "pretty";
39269
+ applyGlobalFlags({ invocation });
39270
+ if (getBoolFlag(invocation.flags, "dry-run")) {
39271
+ return;
39272
+ }
39158
39273
  const { config, client } = resolveCliContext({
39159
39274
  invocation,
39160
39275
  format,
@@ -39185,14 +39300,17 @@ async function maybeHandleComponentShellBoundary(argv, deps = {}) {
39185
39300
  callRegisteredSetup: callRegisteredSetupImpl
39186
39301
  });
39187
39302
  }
39188
- const name = invocation.positional[1];
39189
- if (!name) {
39303
+ const componentRef = invocation.positional[1];
39304
+ if (!componentRef) {
39190
39305
  return;
39191
39306
  }
39307
+ if (!isRegisteredComponentSource(componentRef)) {
39308
+ 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");
39309
+ }
39192
39310
  const repoFlag = getStringFlag(invocation.flags, "repo") ?? config.defaultRepo;
39193
39311
  const refOverride = getStringFlag(invocation.flags, "ref");
39194
39312
  return await handleComponentUpdate({
39195
- name,
39313
+ componentRef,
39196
39314
  repoFlag,
39197
39315
  refOverride,
39198
39316
  client,
@@ -39263,7 +39381,6 @@ async function performRegisteredInstall(args) {
39263
39381
  invalidateInstallSnapshotCache(installRepo);
39264
39382
  const result = await args.installFromManifest(args.client, args.parsedRepo.org, args.parsedRepo.repo, resolved.manifest, {
39265
39383
  installId,
39266
- sourceKind: "registered",
39267
39384
  registeredComponentRef: args.componentRef
39268
39385
  });
39269
39386
  if (!result.ok) {
@@ -39328,11 +39445,15 @@ function warmHubErrorBackendCode(error) {
39328
39445
  async function handleComponentUpdate(args) {
39329
39446
  const parsedRepo = parseOrgRepo(args.repoFlag, args.config);
39330
39447
  const installRepo = `${parsedRepo.org}/${parsedRepo.repo}`;
39331
- const installThing = await args.client.thing.get(parsedRepo.org, parsedRepo.repo, `ComponentInstall/${args.name}`);
39448
+ const componentId = await resolveInstalledComponentRefId(args.client, parsedRepo.org, parsedRepo.repo, args.componentRef);
39449
+ const installThing = await args.client.thing.get(parsedRepo.org, parsedRepo.repo, `ComponentInstall/${componentId}`);
39332
39450
  const installData = installThing.data && typeof installThing.data === "object" ? installThing.data : {};
39333
39451
  const source = resolveComponentUpdateSource(installData);
39334
39452
  if (source.kind === "registered") {
39335
39453
  rejectRefForRegistered(source.componentRef, args.refOverride);
39454
+ if (source.componentRef !== args.componentRef) {
39455
+ throw new CliError(2 /* UserInput */, "USER_INPUT", `Component '${args.componentRef}' resolved to an install for '${source.componentRef}', which is inconsistent with the install record.`);
39456
+ }
39336
39457
  return performRegisteredInstall({
39337
39458
  componentRef: source.componentRef,
39338
39459
  persistedInstallData: installData,
@@ -39348,9 +39469,9 @@ async function handleComponentUpdate(args) {
39348
39469
  });
39349
39470
  }
39350
39471
  if (source.kind === "system") {
39351
- 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.`);
39472
+ 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.`);
39352
39473
  }
39353
- 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>`.");
39474
+ 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>`.");
39354
39475
  }
39355
39476
  async function writeInstallResult(writeOut, writeErr, format, verb, result, installRepo, client) {
39356
39477
  if (result.ok) {
@@ -39823,4 +39944,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
39823
39944
  var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
39824
39945
  process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
39825
39946
 
39826
- //# debugId=EA0B77423037747464756E2164756E21
39947
+ //# debugId=E69740B781D6D4C864756E2164756E21